From: Julian Seward Date: Wed, 29 Mar 2017 16:13:35 +0000 (+0000) Subject: Add a mechanism for hinting to the core disassembler loop, that the X-Git-Tag: svn/VALGRIND_3_13_0^2~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94d63e388b5455a68d3965b0d233e82a1b669988;p=thirdparty%2Fvalgrind.git Add a mechanism for hinting to the core disassembler loop, that the just-disassembled instruction is very verbose. This allows dynamic changes to the maximum number of guest instructions allowed in the current IRSB. Fixes #375839. git-svn-id: svn://svn.valgrind.org/vex/trunk@3337 --- diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c index da06a87218..46dd460180 100644 --- a/VEX/priv/guest_amd64_toIR.c +++ b/VEX/priv/guest_amd64_toIR.c @@ -29616,6 +29616,7 @@ Long dis_ESC_0F38__VEX ( if (have66noF2noF3(pfx)) { delta = dis_FMA( vbi, pfx, delta, opc ); *uses_vvvv = True; + dres->hint = Dis_HintVerbose; goto decode_success; } break; @@ -31744,13 +31745,18 @@ Long dis_ESC_0F3A__VEX ( /* else fall though; dis_PCMPxSTRx failed to decode it */ } break; + case 0x5C ... 0x5F: case 0x68 ... 0x6F: case 0x78 ... 0x7F: + /* FIXME: list the instructions decoded here */ if (have66noF2noF3(pfx) && 0==getVexL(pfx)/*128*/) { Long delta0 = delta; delta = dis_FMA4( pfx, delta, opc, uses_vvvv, vbi ); - if (delta > delta0) goto decode_success; + if (delta > delta0) { + dres->hint = Dis_HintVerbose; + goto decode_success; + } /* else fall though; dis_FMA4 failed to decode it */ } break; @@ -31863,6 +31869,7 @@ DisResult disInstr_AMD64_WRK ( dres.len = 0; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; *expect_CAS = False; vassert(guest_RIP_next_assumed == 0); diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index 8e91291ddb..088af554d4 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -14305,6 +14305,7 @@ Bool disInstr_ARM64_WRK ( dres->len = 4; dres->continueAt = 0; dres->jk_StopHere = Ijk_INVALID; + dres->hint = Dis_HintNone; /* At least this is simple on ARM64: insns are all 4 bytes long, and 4-aligned. So just fish the whole thing out of memory right now diff --git a/VEX/priv/guest_arm_toIR.c b/VEX/priv/guest_arm_toIR.c index 2cb3ac3a7e..b9e1be27fb 100644 --- a/VEX/priv/guest_arm_toIR.c +++ b/VEX/priv/guest_arm_toIR.c @@ -16099,6 +16099,7 @@ DisResult disInstr_ARM_WRK ( dres.len = 4; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; /* Set default actions for post-insn handling of writes to r15, if required. */ @@ -18986,6 +18987,7 @@ DisResult disInstr_THUMB_WRK ( dres.len = 2; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; /* Set default actions for post-insn handling of writes to r15, if required. */ diff --git a/VEX/priv/guest_generic_bb_to_IR.c b/VEX/priv/guest_generic_bb_to_IR.c index 779f8ae451..fb3ffb5136 100644 --- a/VEX/priv/guest_generic_bb_to_IR.c +++ b/VEX/priv/guest_generic_bb_to_IR.c @@ -237,6 +237,13 @@ IRSB* bb_to_IR ( vassert((offB_GUEST_IP % 8) == 0); } + /* Although we will try to disassemble up to vex_control.guest_max_insns + insns into the block, the individual insn assemblers may hint to us that a + disassembled instruction is verbose. In that case we will lower the limit + so as to ensure that the JIT doesn't run out of space. See bug 375839 for + the motivating example. */ + Int guest_max_insns_really = vex_control.guest_max_insns; + /* Start a new, empty extent. */ vge->n_used = 1; vge->base[0] = guest_IP_bbstart; @@ -284,7 +291,7 @@ IRSB* bb_to_IR ( /* Process instructions. */ while (True) { - vassert(n_instrs < vex_control.guest_max_insns); + vassert(n_instrs < guest_max_insns_really); /* Regardless of what chase_into_ok says, is chasing permissible at all right now? Set resteerOKfn accordingly. */ @@ -383,6 +390,23 @@ IRSB* bb_to_IR ( if (n_cond_resteers_allowed == 0) vassert(dres.whatNext != Dis_ResteerC); + /* If the disassembly function passed us a hint, take note of it. */ + if (LIKELY(dres.hint == Dis_HintNone)) { + /* Do nothing */ + } else { + vassert(dres.hint == Dis_HintVerbose); + /* The current insn is known to be verbose. Lower the max insns limit + if necessary so as to avoid running the JIT out of space in the + event that we've encountered the start of a long sequence of them. + This is expected to be a very rare event. In any case the remaining + limit (30 insns) is still so high that most blocks will terminate + anyway before then. So this is very unlikely to give a perf hit in + practice. See bug 375839 for the motivating example. */ + if (guest_max_insns_really > 30) { + guest_max_insns_really = 30; + } + } + /* Fill in the insn-mark length field. */ vassert(first_stmt_idx >= 0 && first_stmt_idx < irsb->stmts_used); imark = irsb->stmts[first_stmt_idx]; @@ -435,7 +459,7 @@ IRSB* bb_to_IR ( case Dis_Continue: vassert(dres.continueAt == 0); vassert(dres.jk_StopHere == Ijk_INVALID); - if (n_instrs < vex_control.guest_max_insns) { + if (n_instrs < guest_max_insns_really) { /* keep going */ } else { /* We have to stop. See comment above re irsb field diff --git a/VEX/priv/guest_generic_bb_to_IR.h b/VEX/priv/guest_generic_bb_to_IR.h index 78a5a870dd..2c90db3d2b 100644 --- a/VEX/priv/guest_generic_bb_to_IR.h +++ b/VEX/priv/guest_generic_bb_to_IR.h @@ -76,10 +76,16 @@ typedef Dis_ResteerC: (speculatively, of course) followed a conditional branch; continue at 'continueAt' */ - enum { Dis_StopHere, Dis_Continue, + enum { Dis_StopHere=0x10, Dis_Continue, Dis_ResteerU, Dis_ResteerC } whatNext; - /* For Dis_StopHere, we need to end the block and create a + /* Any other hints that we should feed back to the disassembler? + Dis_HintNone: no hint + Dis_HintVerbose: this insn potentially generates a lot of code + */ + enum { Dis_HintNone=0x20, Dis_HintVerbose } hint; + + /* For whatNext==Dis_StopHere, we need to end the block and create a transfer to whatever the NIA is. That will have presumably been set by the IR generated for this insn. So we need to know the jump kind to use. Should Ijk_INVALID in other Dis_ @@ -89,7 +95,6 @@ typedef /* For Dis_Resteer, this is the guest address we should continue at. Otherwise ignored (should be zero). */ Addr continueAt; - } DisResult; diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index 77cd1f29e4..38f375e6fc 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -12132,6 +12132,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, dres.len = 0; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; delay_slot_branch = likely_delay_slot = delay_slot_jump = False; diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c index 6fede61aec..d9d9255d4f 100644 --- a/VEX/priv/guest_ppc_toIR.c +++ b/VEX/priv/guest_ppc_toIR.c @@ -27406,6 +27406,7 @@ DisResult disInstr_PPC_WRK ( dres.len = 0; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; /* At least this is simple on PPC32: insns are all 4 bytes long, and 4-aligned. So just fish the whole thing out of memory right now @@ -29112,6 +29113,7 @@ DisResult disInstr_PPC ( IRSB* irsb_IN, dres.whatNext = Dis_StopHere; dres.jk_StopHere = Ijk_NoDecode; dres.continueAt = 0; + dres.hint = Dis_HintNone; return dres; } diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index c5b97b406f..a7bcacc5af 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -16832,6 +16832,7 @@ disInstr_S390_WRK(const UChar *insn) dres.len = insn_length; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; /* fixs390: consider chasing of conditional jumps */ diff --git a/VEX/priv/guest_tilegx_toIR.c b/VEX/priv/guest_tilegx_toIR.c index f13c7ad71f..93e1297cbb 100644 --- a/VEX/priv/guest_tilegx_toIR.c +++ b/VEX/priv/guest_tilegx_toIR.c @@ -323,6 +323,7 @@ static DisResult disInstr_TILEGX_WRK ( Bool(*resteerOkFn) (void *, Addr), dres.len = 0; dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; /* Verify the code addr is 8-byte aligned. */ vassert((((Addr)code) & 7) == 0); diff --git a/VEX/priv/guest_x86_toIR.c b/VEX/priv/guest_x86_toIR.c index d2cdb6a024..23ed055d7e 100644 --- a/VEX/priv/guest_x86_toIR.c +++ b/VEX/priv/guest_x86_toIR.c @@ -8114,6 +8114,7 @@ DisResult disInstr_X86_WRK ( dres.whatNext = Dis_Continue; dres.len = 0; dres.continueAt = 0; + dres.hint = Dis_HintNone; dres.jk_StopHere = Ijk_INVALID; *expect_CAS = False; diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 855bc64f77..fdb772fee0 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -475,7 +475,7 @@ typedef Default=120. A setting of zero disables unrolling. */ Int iropt_unroll_thresh; /* What's the maximum basic block length the front end(s) allow? - BBs longer than this are split up. Default=50 (guest + BBs longer than this are split up. Default=60 (guest insns). */ Int guest_max_insns; /* How aggressive should front ends be in following