imperative to emit position-independent code. */
Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i,
- Bool mode64, void* dispatch )
+ Bool mode64,
+ void* dispatch_unassisted,
+ void* dispatch_assisted )
{
UInt /*irno,*/ opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
UInt xtra;
goto done;
}
- case Ain_Goto:
+ case Ain_Goto: {
+ void* dispatch_to_use = NULL;
+ vassert(dispatch_unassisted != NULL);
+ vassert(dispatch_assisted != NULL);
+
/* Use ptmp for backpatching conditional jumps. */
ptmp = NULL;
/* If a non-boring, set %rbp (the guest state pointer)
appropriately. Since these numbers are all small positive
integers, we can get away with "movl $N, %ebp" rather than
- the longer "movq $N, %rbp". */
+ the longer "movq $N, %rbp". Also, decide which dispatcher we
+ need to use. */
+ dispatch_to_use = dispatch_assisted;
+
/* movl $magic_number, %ebp */
switch (i->Ain.Goto.jk) {
case Ijk_ClientReq:
case Ijk_Ret:
case Ijk_Call:
case Ijk_Boring:
+ dispatch_to_use = dispatch_unassisted;
break;
default:
ppIRJumpKind(i->Ain.Goto.jk);
after the load of %rax since %rdx might be carrying the value
destined for %rax immediately prior to this Ain_Goto. */
vassert(sizeof(ULong) == sizeof(void*));
- vassert(dispatch != NULL);
- if (fitsIn32Bits(Ptr_to_ULong(dispatch))) {
+ if (fitsIn32Bits(Ptr_to_ULong(dispatch_to_use))) {
/* movl sign-extend(imm32), %rdx */
*p++ = 0x48;
*p++ = 0xC7;
*p++ = 0xC2;
- p = emit32(p, (UInt)Ptr_to_ULong(dispatch));
+ p = emit32(p, (UInt)Ptr_to_ULong(dispatch_to_use));
} else {
/* movabsq $imm64, %rdx */
*p++ = 0x48;
*p++ = 0xBA;
- p = emit64(p, Ptr_to_ULong(dispatch));
+ p = emit64(p, Ptr_to_ULong(dispatch_to_use));
}
/* jmp *%rdx */
*p++ = 0xFF;
*ptmp = toUChar(delta-1);
}
goto done;
+ }
case Ain_CMov64:
vassert(i->Ain.CMov64.cond != Acc_ALWAYS);
extern void mapRegs_AMD64Instr ( HRegRemap*, AMD64Instr*, Bool );
extern Bool isMove_AMD64Instr ( AMD64Instr*, HReg*, HReg* );
extern Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr*,
- Bool, void* dispatch );
+ Bool,
+ void* dispatch_unassisted,
+ void* dispatch_assisted );
extern void genSpill_AMD64 ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offset, Bool );
Int emit_ARMInstr ( UChar* buf, Int nbuf, ARMInstr* i,
- Bool mode64, void* dispatch )
+ Bool mode64,
+ void* dispatch_unassisted, void* dispatch_assisted )
{
UInt* p = (UInt*)buf;
vassert(nbuf >= 32);
vassert(mode64 == False);
vassert(0 == (((HWord)buf) & 3));
- /* since we branch to lr(r13) to get back to dispatch: */
- vassert(dispatch == NULL);
switch (i->tag) {
case ARMin_Alu: {
ARMCondCode cond = i->ARMin.Goto.cond;
UInt rnext = iregNo(i->ARMin.Goto.gnext);
Int trc = -1;
+ /* since we branch to lr(r13) to get back to dispatch: */
+ vassert(dispatch_unassisted == NULL);
+ vassert(dispatch_assisted == NULL);
switch (jk) {
case Ijk_Ret: case Ijk_Call: case Ijk_Boring:
break; /* no need to set GST in these common cases */
extern void mapRegs_ARMInstr ( HRegRemap*, ARMInstr*, Bool );
extern Bool isMove_ARMInstr ( ARMInstr*, HReg*, HReg* );
extern Int emit_ARMInstr ( UChar* buf, Int nbuf, ARMInstr*,
- Bool, void* dispatch );
+ Bool,
+ void* dispatch_unassisted,
+ void* dispatch_assisted );
extern void genSpill_ARM ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offset, Bool );
code and back.
*/
Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i,
- Bool mode64, void* dispatch )
+ Bool mode64,
+ void* dispatch_unassisted, void* dispatch_assisted )
{
UChar* p = &buf[0];
UChar* ptmp = p;
UInt r_dst;
ULong imm_dst;
- vassert(dispatch == NULL);
+ vassert(dispatch_unassisted == NULL);
+ vassert(dispatch_assisted == NULL);
/* First off, if this is conditional, create a conditional
jump over the rest of it. */
extern void mapRegs_PPCInstr ( HRegRemap*, PPCInstr* , Bool mode64);
extern Bool isMove_PPCInstr ( PPCInstr*, HReg*, HReg* );
extern Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr*,
- Bool mode64, void* dispatch );
+ Bool mode64,
+ void* dispatch_unassisted,
+ void* dispatch_assisted );
extern void genSpill_PPC ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offsetB, Bool mode64 );
Int
emit_S390Instr(UChar *buf, Int nbuf, struct s390_insn *insn,
- Bool mode64, void *dispatch)
+ Bool mode64,
+ void *dispatch_unassisted, void *dispatch_assisted)
{
UChar *end;
break;
case S390_INSN_BRANCH:
+ vassert(dispatch_unassisted == NULL);
+ vassert(dispatch_assisted == NULL);
end = s390_insn_branch_emit(buf, insn);
break;
void getRegUsage_S390Instr( HRegUsage *, struct s390_insn *, Bool );
void mapRegs_S390Instr ( HRegRemap *, struct s390_insn *, Bool );
Bool isMove_S390Instr ( struct s390_insn *, HReg *, HReg * );
-Int emit_S390Instr ( UChar *, Int, struct s390_insn *, Bool, void * );
+Int emit_S390Instr ( UChar *, Int, struct s390_insn *, Bool,
+ void *, void * );
void getAllocableRegs_S390( Int *, HReg **, Bool );
void genSpill_S390 ( HInstr **, HInstr **, HReg , Int , Bool );
void genReload_S390 ( HInstr **, HInstr **, HReg , Int , Bool );
imperative to emit position-independent code. */
Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i,
- Bool mode64, void* dispatch )
+ Bool mode64,
+ void* dispatch_unassisted,
+ void* dispatch_assisted )
{
UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
*p++ = toUChar(0xD0 + irno);
goto done;
- case Xin_Goto:
+ case Xin_Goto: {
+ void* dispatch_to_use = NULL;
+ vassert(dispatch_unassisted != NULL);
+ vassert(dispatch_assisted != NULL);
+
/* Use ptmp for backpatching conditional jumps. */
ptmp = NULL;
}
/* If a non-boring, set %ebp (the guest state pointer)
- appropriately. */
+ appropriately. Also, decide which dispatcher we need to
+ use. */
+ dispatch_to_use = dispatch_assisted;
+
/* movl $magic_number, %ebp */
switch (i->Xin.Goto.jk) {
case Ijk_ClientReq:
case Ijk_Ret:
case Ijk_Call:
case Ijk_Boring:
+ dispatch_to_use = dispatch_unassisted;
break;
default:
ppIRJumpKind(i->Xin.Goto.jk);
after the load of %eax since %edx might be carrying the value
destined for %eax immediately prior to this Xin_Goto. */
vassert(sizeof(UInt) == sizeof(void*));
- vassert(dispatch != NULL);
+ vassert(dispatch_to_use != NULL);
/* movl $imm32, %edx */
*p++ = 0xBA;
- p = emit32(p, (UInt)Ptr_to_ULong(dispatch));
+ p = emit32(p, (UInt)Ptr_to_ULong(dispatch_to_use));
/* jmp *%edx */
*p++ = 0xFF;
*ptmp = toUChar(delta-1);
}
goto done;
+ }
case Xin_CMov32:
vassert(i->Xin.CMov32.cond != Xcc_ALWAYS);
extern void mapRegs_X86Instr ( HRegRemap*, X86Instr*, Bool );
extern Bool isMove_X86Instr ( X86Instr*, HReg*, HReg* );
extern Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr*,
- Bool, void* dispatch );
+ Bool,
+ void* dispatch_unassisted,
+ void* dispatch_assisted );
extern void genSpill_X86 ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offset, Bool );
void (*ppReg) ( HReg );
HInstrArray* (*iselSB) ( IRSB*, VexArch, VexArchInfo*,
VexAbiInfo* );
- Int (*emit) ( UChar*, Int, HInstr*, Bool, void* );
+ Int (*emit) ( UChar*, Int, HInstr*, Bool, void*, void* );
IRExpr* (*specHelper) ( HChar*, IRExpr**, IRStmt**, Int );
Bool (*preciseMemExnsFn) ( Int, Int );
ppInstr = (void(*)(HInstr*, Bool)) ppX86Instr;
ppReg = (void(*)(HReg)) ppHRegX86;
iselSB = iselSB_X86;
- emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_X86Instr;
+ emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*))
+ emit_X86Instr;
host_is_bigendian = False;
host_word_type = Ity_I32;
vassert(are_valid_hwcaps(VexArchX86, vta->archinfo_host.hwcaps));
- vassert(vta->dispatch != NULL); /* jump-to-dispatcher scheme */
+ /* jump-to-dispatcher scheme */
+ vassert(vta->dispatch_unassisted != NULL);
+ vassert(vta->dispatch_assisted != NULL);
break;
case VexArchAMD64:
ppInstr = (void(*)(HInstr*, Bool)) ppAMD64Instr;
ppReg = (void(*)(HReg)) ppHRegAMD64;
iselSB = iselSB_AMD64;
- emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_AMD64Instr;
+ emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*))
+ emit_AMD64Instr;
host_is_bigendian = False;
host_word_type = Ity_I64;
vassert(are_valid_hwcaps(VexArchAMD64, vta->archinfo_host.hwcaps));
- vassert(vta->dispatch != NULL); /* jump-to-dispatcher scheme */
+ /* jump-to-dispatcher scheme */
+ vassert(vta->dispatch_unassisted != NULL);
+ vassert(vta->dispatch_assisted != NULL);
break;
case VexArchPPC32:
ppInstr = (void(*)(HInstr*,Bool)) ppPPCInstr;
ppReg = (void(*)(HReg)) ppHRegPPC;
iselSB = iselSB_PPC;
- emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_PPCInstr;
+ emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*))
+ emit_PPCInstr;
host_is_bigendian = True;
host_word_type = Ity_I32;
vassert(are_valid_hwcaps(VexArchPPC32, vta->archinfo_host.hwcaps));
- vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
+ /* return-to-dispatcher scheme */
+ vassert(vta->dispatch_unassisted == NULL);
+ vassert(vta->dispatch_assisted == NULL);
break;
case VexArchPPC64:
ppInstr = (void(*)(HInstr*, Bool)) ppPPCInstr;
ppReg = (void(*)(HReg)) ppHRegPPC;
iselSB = iselSB_PPC;
- emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_PPCInstr;
+ emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*))
+ emit_PPCInstr;
host_is_bigendian = True;
host_word_type = Ity_I64;
vassert(are_valid_hwcaps(VexArchPPC64, vta->archinfo_host.hwcaps));
- vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
+ /* return-to-dispatcher scheme */
+ vassert(vta->dispatch_unassisted == NULL);
+ vassert(vta->dispatch_assisted == NULL);
break;
case VexArchS390X:
ppInstr = (void(*)(HInstr*, Bool)) ppS390Instr;
ppReg = (void(*)(HReg)) ppHRegS390;
iselSB = iselSB_S390;
- emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_S390Instr;
+ emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*))
+ emit_S390Instr;
host_is_bigendian = True;
host_word_type = Ity_I64;
vassert(are_valid_hwcaps(VexArchS390X, vta->archinfo_host.hwcaps));
- vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
+ /* return-to-dispatcher scheme */
+ vassert(vta->dispatch_unassisted == NULL);
+ vassert(vta->dispatch_assisted == NULL);
break;
case VexArchARM:
ppInstr = (void(*)(HInstr*, Bool)) ppARMInstr;
ppReg = (void(*)(HReg)) ppHRegARM;
iselSB = iselSB_ARM;
- emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_ARMInstr;
+ emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*,void*))
+ emit_ARMInstr;
host_is_bigendian = False;
host_word_type = Ity_I32;
vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_host.hwcaps));
- vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
+ vassert(vta->dispatch_unassisted == NULL);
+ vassert(vta->dispatch_assisted == NULL);
+ /* return-to-dispatcher scheme */
break;
default:
vex_printf("\n");
}
j = (*emit)( insn_bytes, sizeof insn_bytes, rcode->arr[i], mode64,
- vta->dispatch );
+ vta->dispatch_unassisted, vta->dispatch_assisted );
if (vex_traceflags & VEX_TRACE_ASM) {
for (k = 0; k < j; k++)
if (insn_bytes[k] < 16)
/* IN: debug: trace vex activity at various points */
Int traceflags;
- /* IN: address of the dispatcher entry point. Describes the
- place where generated code should jump to at the end of each
+ /* IN: address of the dispatcher entry points. Describes the
+ places where generated code should jump to at the end of each
bb.
At the end of each translation, the next guest address is
control; caller supplies this) in the following way:
- On host archs which lack a link register (x86, amd64), by a
- jump to the host address specified in 'dispatcher', which
- must be non-NULL.
+ jump to the host address specified in
+ 'dispatcher_assisted', if the guest state pointer has been
+ changed so as to request some action before the next block
+ is run, or 'dispatcher_unassisted' (the fast path), in
+ which it is assumed that the guest state pointer is
+ unchanged and we wish to continue directly with the next
+ translation. Both of these must be non-NULL.
- On host archs which have a link register (ppc32, ppc64), by
a branch to the link register (which is guaranteed to be
unchanged from whatever it was at entry to the
- translation). 'dispatch' must be NULL.
+ translation). 'dispatch_assisted' and
+ 'dispatch_unassisted' must be NULL.
The aim is to get back and forth between translations and the
dispatcher without creating memory traffic to store return
addresses.
*/
- void* dispatch;
+ void* dispatch_unassisted;
+ void* dispatch_assisted;
}
VexTranslateArgs;