Index: trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 100265)
+++ trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 100266)
@@ -288,4 +288,7 @@
     pVCpu->iem.s.offInstrNextByte   = 0;
     pVCpu->iem.s.offCurInstrStart   = 0;
+# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    pVCpu->iem.s.offOpcode          = 0;
+# endif
 # ifdef VBOX_STRICT
     pVCpu->iem.s.GCPhysInstrBuf     = NIL_RTGCPHYS;
@@ -401,8 +404,11 @@
 # endif
     }
-#else
+# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    pVCpu->iem.s.offOpcode          = 0;
+# endif
+#else  /* !IEM_WITH_CODE_TLB */
     pVCpu->iem.s.cbOpcode           = 0;
     pVCpu->iem.s.offOpcode          = 0;
-#endif
+#endif /* !IEM_WITH_CODE_TLB */
     pVCpu->iem.s.offModRm           = 0;
     Assert(pVCpu->iem.s.cActiveMappings == 0);
@@ -1091,5 +1097,5 @@
 }
 
-#else
+#else /* !IEM_WITH_CODE_TLB */
 
 /**
@@ -9742,323 +9748,4 @@
 }
 
-
-#ifdef IEM_WITH_SETJMP
-/**
- * Calculates the effective address of a ModR/M memory operand, extended version
- * for use in the recompilers.
- *
- * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
- *
- * May longjmp on internal error.
- *
- * @return  The effective address.
- * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
- * @param   bRm                 The ModRM byte.
- * @param   cbImmAndRspOffset   - First byte: The size of any immediate
- *                                following the effective address opcode bytes
- *                                (only for RIP relative addressing).
- *                              - Second byte: RSP displacement (for POP [ESP]).
- * @param   puInfo              Extra info: 32-bit displacement (bits 31:0) and
- *                              SIB byte (bits 39:32).
- */
-RTGCPTR iemOpHlpCalcRmEffAddrJmpEx(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, uint64_t *puInfo) IEM_NOEXCEPT_MAY_LONGJMP
-{
-    Log5(("iemOpHlpCalcRmEffAddrJmp: bRm=%#x\n", bRm));
-# define SET_SS_DEF() \
-    do \
-    { \
-        if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
-            pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
-    } while (0)
-
-    if (!IEM_IS_64BIT_CODE(pVCpu))
-    {
-/** @todo Check the effective address size crap! */
-        if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
-        {
-            uint16_t u16EffAddr;
-
-            /* Handle the disp16 form with no registers first. */
-            if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
-            {
-                IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
-                *puInfo = u16EffAddr;
-            }
-            else
-            {
-                /* Get the displacment. */
-                switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
-                {
-                    case 0:  u16EffAddr = 0;                             break;
-                    case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
-                    case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
-                    default: AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_1)); /* (caller checked for these) */
-                }
-                *puInfo = u16EffAddr;
-
-                /* Add the base and index registers to the disp. */
-                switch (bRm & X86_MODRM_RM_MASK)
-                {
-                    case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
-                    case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
-                    case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
-                    case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
-                    case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
-                    case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
-                    case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
-                    case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
-                }
-            }
-
-            Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#06RX16 uInfo=%#RX64\n", u16EffAddr, *puInfo));
-            return u16EffAddr;
-        }
-
-        Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
-        uint32_t u32EffAddr;
-        uint64_t uInfo;
-
-        /* Handle the disp32 form with no registers first. */
-        if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
-        {
-            IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
-            uInfo = u32EffAddr;
-        }
-        else
-        {
-            /* Get the register (or SIB) value. */
-            uInfo = 0;
-            switch ((bRm & X86_MODRM_RM_MASK))
-            {
-                case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
-                case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
-                case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
-                case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
-                case 4: /* SIB */
-                {
-                    uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
-                    uInfo = (uint64_t)bSib << 32;
-
-                    /* Get the index and scale it. */
-                    switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
-                    {
-                        case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
-                        case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
-                        case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
-                        case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
-                        case 4: u32EffAddr = 0; /*none */ break;
-                        case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
-                        case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
-                        case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
-                        IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
-                    }
-                    u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
-
-                    /* add base */
-                    switch (bSib & X86_SIB_BASE_MASK)
-                    {
-                        case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
-                        case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
-                        case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
-                        case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
-                        case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
-                        case 5:
-                            if ((bRm & X86_MODRM_MOD_MASK) != 0)
-                            {
-                                u32EffAddr += pVCpu->cpum.GstCtx.ebp;
-                                SET_SS_DEF();
-                            }
-                            else
-                            {
-                                uint32_t u32Disp;
-                                IEM_OPCODE_GET_NEXT_U32(&u32Disp);
-                                u32EffAddr += u32Disp;
-                                uInfo      |= u32Disp;
-                            }
-                            break;
-                        case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
-                        case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
-                        IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
-                    }
-                    break;
-                }
-                case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
-                case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
-                case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
-                IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
-            }
-
-            /* Get and add the displacement. */
-            switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
-            {
-                case 0:
-                    break;
-                case 1:
-                {
-                    int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
-                    u32EffAddr += i8Disp;
-                    uInfo      |= (uint32_t)(int32_t)i8Disp;
-                    break;
-                }
-                case 2:
-                {
-                    uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
-                    u32EffAddr += u32Disp;
-                    uInfo      |= u32Disp;
-                    break;
-                }
-                default:
-                    AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_2)); /* (caller checked for these) */
-            }
-        }
-
-        *puInfo = uInfo;
-        Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RX32 uInfo=%#RX64\n", u32EffAddr, uInfo));
-        return u32EffAddr;
-    }
-
-    uint64_t u64EffAddr;
-    uint64_t uInfo;
-
-    /* Handle the rip+disp32 form with no registers first. */
-    if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
-    {
-        IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
-        uInfo = (uint32_t)u64EffAddr;
-        u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
-    }
-    else
-    {
-        /* Get the register (or SIB) value. */
-        uInfo = 0;
-        switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
-        {
-            case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
-            case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
-            case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
-            case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
-            case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
-            case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
-            case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
-            case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
-            case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
-            case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
-            case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
-            case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
-            case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
-            case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
-            /* SIB */
-            case 4:
-            case 12:
-            {
-                uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
-                uInfo = (uint64_t)bSib << 32;
-
-                /* Get the index and scale it. */
-                switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
-                {
-                    case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
-                    case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
-                    case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
-                    case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
-                    case  4: u64EffAddr = 0; /*none */ break;
-                    case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
-                    case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
-                    case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
-                    case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
-                    case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
-                    case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
-                    case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
-                    case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
-                    case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
-                    case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
-                    case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
-                    IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
-                }
-                u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
-
-                /* add base */
-                switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
-                {
-                    case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
-                    case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
-                    case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
-                    case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
-                    case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
-                    case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
-                    case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
-                    case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
-                    case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
-                    case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
-                    case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
-                    case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
-                    case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
-                    case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
-                    /* complicated encodings */
-                    case 5:
-                    case 13:
-                        if ((bRm & X86_MODRM_MOD_MASK) != 0)
-                        {
-                            if (!pVCpu->iem.s.uRexB)
-                            {
-                                u64EffAddr += pVCpu->cpum.GstCtx.rbp;
-                                SET_SS_DEF();
-                            }
-                            else
-                                u64EffAddr += pVCpu->cpum.GstCtx.r13;
-                        }
-                        else
-                        {
-                            uint32_t u32Disp;
-                            IEM_OPCODE_GET_NEXT_U32(&u32Disp);
-                            u64EffAddr += (int32_t)u32Disp;
-                            uInfo      |= u32Disp;
-                        }
-                        break;
-                    IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
-                }
-                break;
-            }
-            IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
-        }
-
-        /* Get and add the displacement. */
-        switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
-        {
-            case 0:
-                break;
-            case 1:
-            {
-                int8_t i8Disp;
-                IEM_OPCODE_GET_NEXT_S8(&i8Disp);
-                u64EffAddr += i8Disp;
-                uInfo      |= (uint32_t)(int32_t)i8Disp;
-                break;
-            }
-            case 2:
-            {
-                uint32_t u32Disp;
-                IEM_OPCODE_GET_NEXT_U32(&u32Disp);
-                u64EffAddr += (int32_t)u32Disp;
-                uInfo      |= u32Disp;
-                break;
-            }
-            IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX); /* (caller checked for these) */
-        }
-
-    }
-
-    *puInfo = uInfo;
-    if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
-    {
-        Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv uInfo=%#RX64\n", u64EffAddr, uInfo));
-        return u64EffAddr;
-    }
-    Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
-    Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv uInfo=%#RX64\n", u64EffAddr & UINT32_MAX, uInfo));
-    return u64EffAddr & UINT32_MAX;
-}
-#endif /* IEM_WITH_SETJMP */
-
 /** @}  */
 
Index: trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h	(revision 100265)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h	(revision 100266)
@@ -12544,5 +12544,5 @@
 FNIEMOP_DEF(iemOp_Grp9)
 {
-    uint8_t bRm; IEM_OPCODE_GET_NEXT_RM(&bRm);
+    uint8_t bRm; IEM_OPCODE_GET_NEXT_U8(&bRm);
     if (IEM_IS_MODRM_REG_MODE(bRm))
         /* register, register */
Index: trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py	(revision 100265)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py	(revision 100266)
@@ -877,5 +877,9 @@
             sCode += ', ' + ' | '.join(asFrags);
         sCode += ');';
-        aoStmts = [ iai.McCppGeneric(sCode, cchIndent = cchIndent), ];
+
+        aoStmts = [
+            iai.McCppGeneric('IEM_MC2_PRE_EMIT_CALLS();', cchIndent = cchIndent), # Serves as a hook for various stuff.
+            iai.McCppGeneric(sCode, cchIndent = cchIndent),
+        ];
 
         # For CIMPL stuff, we need to consult the associated IEM_CIMPL_F_XXX
Index: trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp	(revision 100265)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllThreadedRecompiler.cpp	(revision 100266)
@@ -48,4 +48,5 @@
 # define LOG_GROUP LOG_GROUP_IEM_RE_THREADED
 #endif
+#define IEM_WITH_CODE_TLB_AND_OPCODE_BUF  /* A bit hackish, but its all in IEMInline.h. */
 #define VMCPU_INCL_CPUM_GST_CTX
 #include <VBox/vmm/iem.h>
@@ -161,45 +162,9 @@
         struct
         {
-            /** @todo we actually need BASE, LIM and CS?  If we don't tie a TB to a RIP
-             * range, because that's bad for PIC/PIE code on unix with address space
-             * randomization enabled, the assumption is that anything involving PC
-             * (RIP/EIP/IP, maybe + CS.BASE) will be done by reading current register
-             * values and not embedding presumed values into the code. Thus the uCsBase
-             * member here shouldn't be needed.  For the same reason, uCsLimit isn't helpful
-             * either as RIP/EIP/IP may differ between address spaces.  So, before TB
-             * execution we'd need to check CS.LIM against RIP+cbPC (ditto for 64-bit
-             * canonicallity).
-             *
-             * We could bake instruction limit / canonicallity checks into the generated
-             * code if we find ourselves close to the limit and should expect to run into
-             * it by the end of the translation block. That would just be using a very
-             * simple threshold distance and be a special IEMTB_F_XXX flag so we figure out
-             * it out when picking the TB.
-             *
-             * The CS value is likewise useless as we'll always be using the actual CS
-             * register value whenever it is relevant (mainly pushing to the stack in a
-             * call, trap, whatever).
-             *
-             * The segment attributes should be handled via the IEM_F_MODE_XXX and
-             * IEM_F_X86_CPL_MASK portions of fFlags, so we could skip those too, I think.
-             * All the places where they matter, we would be in CIMPL code which would
-             * consult the actual CS.ATTR and not depend on the recompiled code block.
-             */
-            /** The CS base. */
-            uint32_t uCsBase;
-            /** The CS limit (UINT32_MAX for 64-bit code). */
-            uint32_t uCsLimit;
-            /** The CS selector value. */
-            uint16_t CS;
             /**< Relevant CS X86DESCATTR_XXX bits. */
-            uint16_t fAttr;
+            uint16_t    fAttr;
         } x86;
     };
     /** @} */
-
-    /** Number of bytes of opcodes covered by this block.
-     * @todo Support discontiguous chunks of opcodes in same block, though maybe
-     *       restrict to the initial page or smth. */
-    uint32_t    cbPC;
 
     union
@@ -215,4 +180,12 @@
         } Thrd;
     };
+
+
+    /** Number of bytes of opcodes stored in pabOpcodes. */
+    uint16_t            cbOpcodes;
+    /** The max storage available in the pabOpcodes block. */
+    uint16_t            cbOpcodesAllocated;
+    /** Pointer to the opcode bytes this block was recompiled from. */
+    uint8_t            *pabOpcodes;
 } IEMTB;
 
@@ -241,4 +214,9 @@
 #endif
 
+#define IEM_MC2_PRE_EMIT_CALLS() do { \
+        AssertMsg(pVCpu->iem.s.offOpcode == IEM_GET_INSTR_LEN(pVCpu), \
+                  ("%u vs %u (%04x:%08RX64)\n", pVCpu->iem.s.offOpcode, IEM_GET_INSTR_LEN(pVCpu), \
+                  pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip)); \
+    } while (0)
 #define IEM_MC2_EMIT_CALL_0(a_enmFunction) do { \
         IEMTHREADEDFUNCS const enmFunctionCheck = a_enmFunction; RT_NOREF(enmFunctionCheck); \
@@ -310,4 +288,324 @@
 }
 
+/**
+ * Calculates the effective address of a ModR/M memory operand, extended version
+ * for use in the recompilers.
+ *
+ * Meant to be used via IEM_MC_CALC_RM_EFF_ADDR.
+ *
+ * May longjmp on internal error.
+ *
+ * @return  The effective address.
+ * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
+ * @param   bRm                 The ModRM byte.
+ * @param   cbImmAndRspOffset   - First byte: The size of any immediate
+ *                                following the effective address opcode bytes
+ *                                (only for RIP relative addressing).
+ *                              - Second byte: RSP displacement (for POP [ESP]).
+ * @param   puInfo              Extra info: 32-bit displacement (bits 31:0) and
+ *                              SIB byte (bits 39:32).
+ *
+ * @note This must be defined in a source file with matching
+ *       IEM_WITH_CODE_TLB_AND_OPCODE_BUF define till the define is made default
+ *       or implemented differently...
+ */
+RTGCPTR iemOpHlpCalcRmEffAddrJmpEx(PVMCPUCC pVCpu, uint8_t bRm, uint32_t cbImmAndRspOffset, uint64_t *puInfo) IEM_NOEXCEPT_MAY_LONGJMP
+{
+    Log5(("iemOpHlpCalcRmEffAddrJmp: bRm=%#x\n", bRm));
+# define SET_SS_DEF() \
+    do \
+    { \
+        if (!(pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SEG_MASK)) \
+            pVCpu->iem.s.iEffSeg = X86_SREG_SS; \
+    } while (0)
+
+    if (!IEM_IS_64BIT_CODE(pVCpu))
+    {
+/** @todo Check the effective address size crap! */
+        if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_16BIT)
+        {
+            uint16_t u16EffAddr;
+
+            /* Handle the disp16 form with no registers first. */
+            if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 6)
+            {
+                IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);
+                *puInfo = u16EffAddr;
+            }
+            else
+            {
+                /* Get the displacment. */
+                switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
+                {
+                    case 0:  u16EffAddr = 0;                             break;
+                    case 1:  IEM_OPCODE_GET_NEXT_S8_SX_U16(&u16EffAddr); break;
+                    case 2:  IEM_OPCODE_GET_NEXT_U16(&u16EffAddr);       break;
+                    default: AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_1)); /* (caller checked for these) */
+                }
+                *puInfo = u16EffAddr;
+
+                /* Add the base and index registers to the disp. */
+                switch (bRm & X86_MODRM_RM_MASK)
+                {
+                    case 0: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.si; break;
+                    case 1: u16EffAddr += pVCpu->cpum.GstCtx.bx + pVCpu->cpum.GstCtx.di; break;
+                    case 2: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.si; SET_SS_DEF(); break;
+                    case 3: u16EffAddr += pVCpu->cpum.GstCtx.bp + pVCpu->cpum.GstCtx.di; SET_SS_DEF(); break;
+                    case 4: u16EffAddr += pVCpu->cpum.GstCtx.si;            break;
+                    case 5: u16EffAddr += pVCpu->cpum.GstCtx.di;            break;
+                    case 6: u16EffAddr += pVCpu->cpum.GstCtx.bp;            SET_SS_DEF(); break;
+                    case 7: u16EffAddr += pVCpu->cpum.GstCtx.bx;            break;
+                }
+            }
+
+            Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#06RX16 uInfo=%#RX64\n", u16EffAddr, *puInfo));
+            return u16EffAddr;
+        }
+
+        Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
+        uint32_t u32EffAddr;
+        uint64_t uInfo;
+
+        /* Handle the disp32 form with no registers first. */
+        if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
+        {
+            IEM_OPCODE_GET_NEXT_U32(&u32EffAddr);
+            uInfo = u32EffAddr;
+        }
+        else
+        {
+            /* Get the register (or SIB) value. */
+            uInfo = 0;
+            switch ((bRm & X86_MODRM_RM_MASK))
+            {
+                case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
+                case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
+                case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
+                case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
+                case 4: /* SIB */
+                {
+                    uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
+                    uInfo = (uint64_t)bSib << 32;
+
+                    /* Get the index and scale it. */
+                    switch ((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK)
+                    {
+                        case 0: u32EffAddr = pVCpu->cpum.GstCtx.eax; break;
+                        case 1: u32EffAddr = pVCpu->cpum.GstCtx.ecx; break;
+                        case 2: u32EffAddr = pVCpu->cpum.GstCtx.edx; break;
+                        case 3: u32EffAddr = pVCpu->cpum.GstCtx.ebx; break;
+                        case 4: u32EffAddr = 0; /*none */ break;
+                        case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; break;
+                        case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
+                        case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
+                        IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
+                    }
+                    u32EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
+
+                    /* add base */
+                    switch (bSib & X86_SIB_BASE_MASK)
+                    {
+                        case 0: u32EffAddr += pVCpu->cpum.GstCtx.eax; break;
+                        case 1: u32EffAddr += pVCpu->cpum.GstCtx.ecx; break;
+                        case 2: u32EffAddr += pVCpu->cpum.GstCtx.edx; break;
+                        case 3: u32EffAddr += pVCpu->cpum.GstCtx.ebx; break;
+                        case 4: u32EffAddr += pVCpu->cpum.GstCtx.esp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
+                        case 5:
+                            if ((bRm & X86_MODRM_MOD_MASK) != 0)
+                            {
+                                u32EffAddr += pVCpu->cpum.GstCtx.ebp;
+                                SET_SS_DEF();
+                            }
+                            else
+                            {
+                                uint32_t u32Disp;
+                                IEM_OPCODE_GET_NEXT_U32(&u32Disp);
+                                u32EffAddr += u32Disp;
+                                uInfo      |= u32Disp;
+                            }
+                            break;
+                        case 6: u32EffAddr += pVCpu->cpum.GstCtx.esi; break;
+                        case 7: u32EffAddr += pVCpu->cpum.GstCtx.edi; break;
+                        IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
+                    }
+                    break;
+                }
+                case 5: u32EffAddr = pVCpu->cpum.GstCtx.ebp; SET_SS_DEF(); break;
+                case 6: u32EffAddr = pVCpu->cpum.GstCtx.esi; break;
+                case 7: u32EffAddr = pVCpu->cpum.GstCtx.edi; break;
+                IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
+            }
+
+            /* Get and add the displacement. */
+            switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
+            {
+                case 0:
+                    break;
+                case 1:
+                {
+                    int8_t i8Disp; IEM_OPCODE_GET_NEXT_S8(&i8Disp);
+                    u32EffAddr += i8Disp;
+                    uInfo      |= (uint32_t)(int32_t)i8Disp;
+                    break;
+                }
+                case 2:
+                {
+                    uint32_t u32Disp; IEM_OPCODE_GET_NEXT_U32(&u32Disp);
+                    u32EffAddr += u32Disp;
+                    uInfo      |= u32Disp;
+                    break;
+                }
+                default:
+                    AssertFailedStmt(IEM_DO_LONGJMP(pVCpu, VERR_IEM_IPE_2)); /* (caller checked for these) */
+            }
+        }
+
+        *puInfo = uInfo;
+        Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RX32 uInfo=%#RX64\n", u32EffAddr, uInfo));
+        return u32EffAddr;
+    }
+
+    uint64_t u64EffAddr;
+    uint64_t uInfo;
+
+    /* Handle the rip+disp32 form with no registers first. */
+    if ((bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
+    {
+        IEM_OPCODE_GET_NEXT_S32_SX_U64(&u64EffAddr);
+        uInfo = (uint32_t)u64EffAddr;
+        u64EffAddr += pVCpu->cpum.GstCtx.rip + IEM_GET_INSTR_LEN(pVCpu) + (cbImmAndRspOffset & UINT32_C(0xff));
+    }
+    else
+    {
+        /* Get the register (or SIB) value. */
+        uInfo = 0;
+        switch ((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB)
+        {
+            case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
+            case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
+            case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
+            case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
+            case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; SET_SS_DEF(); break;
+            case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
+            case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
+            case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
+            case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
+            case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
+            case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
+            case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
+            case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
+            case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
+            /* SIB */
+            case 4:
+            case 12:
+            {
+                uint8_t bSib; IEM_OPCODE_GET_NEXT_U8(&bSib);
+                uInfo = (uint64_t)bSib << 32;
+
+                /* Get the index and scale it. */
+                switch (((bSib >> X86_SIB_INDEX_SHIFT) & X86_SIB_INDEX_SMASK) | pVCpu->iem.s.uRexIndex)
+                {
+                    case  0: u64EffAddr = pVCpu->cpum.GstCtx.rax; break;
+                    case  1: u64EffAddr = pVCpu->cpum.GstCtx.rcx; break;
+                    case  2: u64EffAddr = pVCpu->cpum.GstCtx.rdx; break;
+                    case  3: u64EffAddr = pVCpu->cpum.GstCtx.rbx; break;
+                    case  4: u64EffAddr = 0; /*none */ break;
+                    case  5: u64EffAddr = pVCpu->cpum.GstCtx.rbp; break;
+                    case  6: u64EffAddr = pVCpu->cpum.GstCtx.rsi; break;
+                    case  7: u64EffAddr = pVCpu->cpum.GstCtx.rdi; break;
+                    case  8: u64EffAddr = pVCpu->cpum.GstCtx.r8;  break;
+                    case  9: u64EffAddr = pVCpu->cpum.GstCtx.r9;  break;
+                    case 10: u64EffAddr = pVCpu->cpum.GstCtx.r10; break;
+                    case 11: u64EffAddr = pVCpu->cpum.GstCtx.r11; break;
+                    case 12: u64EffAddr = pVCpu->cpum.GstCtx.r12; break;
+                    case 13: u64EffAddr = pVCpu->cpum.GstCtx.r13; break;
+                    case 14: u64EffAddr = pVCpu->cpum.GstCtx.r14; break;
+                    case 15: u64EffAddr = pVCpu->cpum.GstCtx.r15; break;
+                    IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
+                }
+                u64EffAddr <<= (bSib >> X86_SIB_SCALE_SHIFT) & X86_SIB_SCALE_SMASK;
+
+                /* add base */
+                switch ((bSib & X86_SIB_BASE_MASK) | pVCpu->iem.s.uRexB)
+                {
+                    case  0: u64EffAddr += pVCpu->cpum.GstCtx.rax; break;
+                    case  1: u64EffAddr += pVCpu->cpum.GstCtx.rcx; break;
+                    case  2: u64EffAddr += pVCpu->cpum.GstCtx.rdx; break;
+                    case  3: u64EffAddr += pVCpu->cpum.GstCtx.rbx; break;
+                    case  4: u64EffAddr += pVCpu->cpum.GstCtx.rsp + (cbImmAndRspOffset >> 8); SET_SS_DEF(); break;
+                    case  6: u64EffAddr += pVCpu->cpum.GstCtx.rsi; break;
+                    case  7: u64EffAddr += pVCpu->cpum.GstCtx.rdi; break;
+                    case  8: u64EffAddr += pVCpu->cpum.GstCtx.r8;  break;
+                    case  9: u64EffAddr += pVCpu->cpum.GstCtx.r9;  break;
+                    case 10: u64EffAddr += pVCpu->cpum.GstCtx.r10; break;
+                    case 11: u64EffAddr += pVCpu->cpum.GstCtx.r11; break;
+                    case 12: u64EffAddr += pVCpu->cpum.GstCtx.r12; break;
+                    case 14: u64EffAddr += pVCpu->cpum.GstCtx.r14; break;
+                    case 15: u64EffAddr += pVCpu->cpum.GstCtx.r15; break;
+                    /* complicated encodings */
+                    case 5:
+                    case 13:
+                        if ((bRm & X86_MODRM_MOD_MASK) != 0)
+                        {
+                            if (!pVCpu->iem.s.uRexB)
+                            {
+                                u64EffAddr += pVCpu->cpum.GstCtx.rbp;
+                                SET_SS_DEF();
+                            }
+                            else
+                                u64EffAddr += pVCpu->cpum.GstCtx.r13;
+                        }
+                        else
+                        {
+                            uint32_t u32Disp;
+                            IEM_OPCODE_GET_NEXT_U32(&u32Disp);
+                            u64EffAddr += (int32_t)u32Disp;
+                            uInfo      |= u32Disp;
+                        }
+                        break;
+                    IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
+                }
+                break;
+            }
+            IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX);
+        }
+
+        /* Get and add the displacement. */
+        switch ((bRm >> X86_MODRM_MOD_SHIFT) & X86_MODRM_MOD_SMASK)
+        {
+            case 0:
+                break;
+            case 1:
+            {
+                int8_t i8Disp;
+                IEM_OPCODE_GET_NEXT_S8(&i8Disp);
+                u64EffAddr += i8Disp;
+                uInfo      |= (uint32_t)(int32_t)i8Disp;
+                break;
+            }
+            case 2:
+            {
+                uint32_t u32Disp;
+                IEM_OPCODE_GET_NEXT_U32(&u32Disp);
+                u64EffAddr += (int32_t)u32Disp;
+                uInfo      |= u32Disp;
+                break;
+            }
+            IEM_NOT_REACHED_DEFAULT_CASE_RET2(RTGCPTR_MAX); /* (caller checked for these) */
+        }
+
+    }
+
+    *puInfo = uInfo;
+    if (pVCpu->iem.s.enmEffAddrMode == IEMMODE_64BIT)
+    {
+        Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv uInfo=%#RX64\n", u64EffAddr, uInfo));
+        return u64EffAddr;
+    }
+    Assert(pVCpu->iem.s.enmEffAddrMode == IEMMODE_32BIT);
+    Log5(("iemOpHlpCalcRmEffAddrJmp: EffAddr=%#010RGv uInfo=%#RX64\n", u64EffAddr & UINT32_MAX, uInfo));
+    return u64EffAddr & UINT32_MAX;
+}
+
 
 /*
@@ -351,20 +649,24 @@
     if (pTb)
     {
-        pTb->Thrd.paCalls = (PIEMTHRDEDCALLENTRY)RTMemAlloc(sizeof(IEMTHRDEDCALLENTRY) * 128);
+        unsigned const cCalls = 128;
+        pTb->Thrd.paCalls = (PIEMTHRDEDCALLENTRY)RTMemAlloc(sizeof(IEMTHRDEDCALLENTRY) * cCalls);
         if (pTb->Thrd.paCalls)
         {
-            pTb->Thrd.cAllocated = 128;
-            pTb->Thrd.cCalls     = 0;
-            pTb->pNext           = NULL;
-            RTListInit(&pTb->LocalList);
-            pTb->cbPC            = 0;
-            pTb->GCPhysPc        = GCPhysPc;
-            pTb->x86.uCsBase     = (uint32_t)pVCpu->cpum.GstCtx.cs.u64Base;
-            pTb->x86.uCsLimit    = (uint32_t)pVCpu->cpum.GstCtx.cs.u32Limit;
-            pTb->x86.CS          = (uint32_t)pVCpu->cpum.GstCtx.cs.Sel;
-            pTb->x86.fAttr       = (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u;
-            pTb->fFlags          = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags;
-            pVCpu->iem.s.cTbAllocs++;
-            return pTb;
+            pTb->pabOpcodes = (uint8_t *)RTMemAlloc(cCalls * 16); /* This will be reallocated later. */
+            if (pTb->pabOpcodes)
+            {
+                pTb->Thrd.cAllocated    = cCalls;
+                pTb->cbOpcodesAllocated = cCalls * 16;
+                pTb->Thrd.cCalls        = 0;
+                pTb->cbOpcodes          = 0;
+                pTb->pNext              = NULL;
+                RTListInit(&pTb->LocalList);
+                pTb->GCPhysPc           = GCPhysPc;
+                pTb->x86.fAttr          = (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u;
+                pTb->fFlags             = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags;
+                pVCpu->iem.s.cTbAllocs++;
+                return pTb;
+            }
+            RTMemFree(pTb->Thrd.paCalls);
         }
         RTMemFree(pTb);
@@ -388,9 +690,30 @@
     AssertPtr(pTb);
 
-    AssertCompile((IEMTB_F_STATE_OBSOLETE >> IEMTB_F_STATE_SHIFT) == (IEMTB_F_STATE_MASK >> IEMTB_F_STATE_SHIFT));
+    AssertCompile(IEMTB_F_STATE_OBSOLETE == IEMTB_F_STATE_MASK);
     pTb->fFlags |= IEMTB_F_STATE_OBSOLETE; /* works, both bits set */
 
+    /* Unlink it from the hash table: */
+    uint32_t const idxHash = IEMTBCACHE_HASH(&g_TbCache, pTb->fFlags, pTb->GCPhysPc);
+    PIEMTB pTbCur = g_TbCache.apHash[idxHash];
+    if (pTbCur == pTb)
+        g_TbCache.apHash[idxHash] = pTb->pNext;
+    else
+        while (pTbCur)
+        {
+            PIEMTB const pNextTb = pTbCur->pNext;
+            if (pNextTb == pTb)
+            {
+                pTbCur->pNext = pTb->pNext;
+                break;
+            }
+            pTbCur = pNextTb;
+        }
+
+    /* Free it. */
     RTMemFree(pTb->Thrd.paCalls);
     pTb->Thrd.paCalls = NULL;
+
+    RTMemFree(pTb->pabOpcodes);
+    pTb->pabOpcodes = NULL;
 
     RTMemFree(pTb);
@@ -415,6 +738,6 @@
 #ifdef VBOX_WITH_STATISTICS
                     pVCpu->iem.s.cTbLookupHits++;
+#endif
                     return pTb;
-#endif
                 }
                 Log11(("TB miss: CS: %#x, wanted %#x\n", pTb->x86.fAttr, (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u));
@@ -439,5 +762,5 @@
     pTb->pNext = g_TbCache.apHash[idxHash];
     g_TbCache.apHash[idxHash] = pTb;
-    Log12(("TB added: %p %RGp LB %#x fl=%#x idxHash=%#x\n", pTb, pTb->GCPhysPc, pTb->cbPC, pTb->fFlags, idxHash));
+    Log12(("TB added: %p %RGp LB %#x fl=%#x idxHash=%#x\n", pTb, pTb->GCPhysPc, pTb->cbOpcodes, pTb->fFlags, idxHash));
     RT_NOREF(pVM, pVCpu);
 }
@@ -588,4 +911,7 @@
     pVCpu->iem.s.offInstrNextByte   = 0;
     pVCpu->iem.s.offCurInstrStart   = 0;
+#ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    pVCpu->iem.s.offOpcode          = 0;
+#endif
 #ifdef VBOX_STRICT
     pVCpu->iem.s.GCPhysInstrBuf     = NIL_RTGCPHYS;
@@ -641,4 +967,7 @@
 #endif
     }
+#ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    pVCpu->iem.s.offOpcode          = 0;
+#endif
 }
 
@@ -698,4 +1027,5 @@
         uint8_t b; IEM_OPCODE_GET_FIRST_U8(&b);
         uint16_t const cCallsPrev = pTb->Thrd.cCalls;
+
         rcStrict = FNIEMOP_CALL(g_apfnIemThreadedRecompilerOneByteMap[b]);
         if (   rcStrict == VINF_SUCCESS
@@ -704,8 +1034,19 @@
             Assert(pTb->Thrd.cCalls > cCallsPrev);
             Assert(cCallsPrev - pTb->Thrd.cCalls < 5);
+
+            memcpy(&pTb->pabOpcodes[pTb->cbOpcodes], pVCpu->iem.s.abOpcode, pVCpu->iem.s.offOpcode);
+            pTb->cbOpcodes += pVCpu->iem.s.offOpcode;
+            Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated);
         }
         else if (pTb->Thrd.cCalls > 0)
         {
             Log8(("%04x:%08RX64: End TB - %u calls, rc=%d\n", uCsLog, uRipLog, pTb->Thrd.cCalls, VBOXSTRICTRC_VAL(rcStrict)));
+
+            if (cCallsPrev != pTb->Thrd.cCalls)
+            {
+                memcpy(&pTb->pabOpcodes[pTb->cbOpcodes], pVCpu->iem.s.abOpcode, pVCpu->iem.s.offOpcode);
+                pTb->cbOpcodes += pVCpu->iem.s.offOpcode;
+                Assert(pTb->cbOpcodes <= pTb->cbOpcodesAllocated);
+            }
             break;
         }
@@ -755,4 +1096,14 @@
 static VBOXSTRICTRC iemThreadedTbExec(PVMCPUCC pVCpu, PIEMTB pTb)
 {
+    if (memcmp(pTb->pabOpcodes, &pVCpu->iem.s.pbInstrBuf[pVCpu->iem.s.offInstrNextByte],
+               RT_MIN(pTb->cbOpcodes, pVCpu->iem.s.cbInstrBuf - pVCpu->iem.s.offInstrNextByte)) == 0)
+    { /* likely */ }
+    else
+    {
+        Log11(("TB obsolete: %p GCPhys=%RGp\n", pTb, pTb->GCPhysPc));
+        iemThreadedTbFree(pVCpu->pVMR3, pVCpu, pTb);
+        return VINF_SUCCESS;
+    }
+
     /* Set the current TB so CIMPL function may get at it. */
     pVCpu->iem.s.pCurTbR3 = pTb;
Index: trunk/src/VBox/VMM/include/IEMInline.h
===================================================================
--- trunk/src/VBox/VMM/include/IEMInline.h	(revision 100265)
+++ trunk/src/VBox/VMM/include/IEMInline.h	(revision 100266)
@@ -434,4 +434,7 @@
     pVCpu->iem.s.offCurInstrStart   = INT16_MAX;
     pVCpu->iem.s.uInstrBufPc        = UINT64_C(0xc0ffc0ffcff0c0ff);
+#    ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    pVCpu->iem.s.offOpcode          = 127;
+#    endif
 #   else
     pVCpu->iem.s.offOpcode          = 127;
@@ -587,4 +590,5 @@
      */
 #  ifdef IEM_WITH_CODE_TLB
+    uint8_t         bRet;
     uintptr_t       offBuf = pVCpu->iem.s.offInstrNextByte;
     uint8_t const  *pbBuf  = pVCpu->iem.s.pbInstrBuf;
@@ -593,7 +597,15 @@
     {
         pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 1;
-        return pbBuf[offBuf];
-    }
-#  else
+        bRet = pbBuf[offBuf];
+    }
+    else
+        bRet = iemOpcodeGetNextU8SlowJmp(pVCpu);
+#   ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    Assert(pVCpu->iem.s.offOpcode == 0);
+    pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++] = bRet;
+#   endif
+    return bRet;
+
+#  else /* !IEM_WITH_CODE_TLB */
     uintptr_t offOpcode = pVCpu->iem.s.offOpcode;
     if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
@@ -602,6 +614,6 @@
         return pVCpu->iem.s.abOpcode[offOpcode];
     }
+    return iemOpcodeGetNextU8SlowJmp(pVCpu);
 #  endif
-    return iemOpcodeGetNextU8SlowJmp(pVCpu);
 }
 
@@ -662,4 +674,5 @@
 {
 #  ifdef IEM_WITH_CODE_TLB
+    uint8_t         bRet;
     uintptr_t       offBuf = pVCpu->iem.s.offInstrNextByte;
     uint8_t const  *pbBuf  = pVCpu->iem.s.pbInstrBuf;
@@ -668,7 +681,15 @@
     {
         pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 1;
-        return pbBuf[offBuf];
-    }
-#  else
+        bRet = pbBuf[offBuf];
+    }
+    else
+        bRet = iemOpcodeGetNextU8SlowJmp(pVCpu);
+#   ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    Assert(pVCpu->iem.s.offOpcode < sizeof(pVCpu->iem.s.abOpcode));
+    pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++] = bRet;
+#   endif
+    return bRet;
+
+#  else /* !IEM_WITH_CODE_TLB */
     uintptr_t offOpcode = pVCpu->iem.s.offOpcode;
     if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
@@ -677,6 +698,6 @@
         return pVCpu->iem.s.abOpcode[offOpcode];
     }
+    return iemOpcodeGetNextU8SlowJmp(pVCpu);
 #  endif
-    return iemOpcodeGetNextU8SlowJmp(pVCpu);
 }
 
@@ -863,81 +884,4 @@
 
 # ifndef IEM_WITH_SETJMP
-/**
- * Fetches the next opcode byte.
- *
- * @returns Strict VBox status code.
- * @param   pVCpu               The cross context virtual CPU structure of the
- *                              calling thread.
- * @param   pu8                 Where to return the opcode byte.
- */
-DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextRm(PVMCPUCC pVCpu, uint8_t *pu8) RT_NOEXCEPT
-{
-    uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
-    pVCpu->iem.s.offModRm = offOpcode;
-    if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
-    {
-        pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 1;
-        *pu8 = pVCpu->iem.s.abOpcode[offOpcode];
-        return VINF_SUCCESS;
-    }
-    return iemOpcodeGetNextU8Slow(pVCpu, pu8);
-}
-# else  /* IEM_WITH_SETJMP */
-/**
- * Fetches the next opcode byte, longjmp on error.
- *
- * @returns The opcode byte.
- * @param   pVCpu               The cross context virtual CPU structure of the calling thread.
- */
-DECL_INLINE_THROW(uint8_t) iemOpcodeGetNextRmJmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
-{
-#  ifdef IEM_WITH_CODE_TLB
-    uintptr_t       offBuf = pVCpu->iem.s.offInstrNextByte;
-    pVCpu->iem.s.offModRm  = offBuf;
-    uint8_t const  *pbBuf  = pVCpu->iem.s.pbInstrBuf;
-    if (RT_LIKELY(   pbBuf != NULL
-                  && offBuf < pVCpu->iem.s.cbInstrBuf))
-    {
-        pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 1;
-        return pbBuf[offBuf];
-    }
-#  else
-    uintptr_t offOpcode   = pVCpu->iem.s.offOpcode;
-    pVCpu->iem.s.offModRm = offOpcode;
-    if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
-    {
-        pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 1;
-        return pVCpu->iem.s.abOpcode[offOpcode];
-    }
-#  endif
-    return iemOpcodeGetNextU8SlowJmp(pVCpu);
-}
-# endif /* IEM_WITH_SETJMP */
-
-/**
- * Fetches the next opcode byte, which is a ModR/M byte, returns automatically
- * on failure.
- *
- * Will note down the position of the ModR/M byte for VT-x exits.
- *
- * @param   a_pbRm              Where to return the RM opcode byte.
- * @remark Implicitly references pVCpu.
- */
-# ifndef IEM_WITH_SETJMP
-#  define IEM_OPCODE_GET_NEXT_RM(a_pbRm) \
-    do \
-    { \
-        VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextRm(pVCpu, (a_pbRm)); \
-        if (rcStrict2 == VINF_SUCCESS) \
-        { /* likely */ } \
-        else \
-            return rcStrict2; \
-    } while (0)
-# else
-#  define IEM_OPCODE_GET_NEXT_RM(a_pbRm) (*(a_pbRm) = iemOpcodeGetNextRmJmp(pVCpu))
-# endif /* IEM_WITH_SETJMP */
-
-
-# ifndef IEM_WITH_SETJMP
 
 /**
@@ -975,4 +919,5 @@
 {
 #  ifdef IEM_WITH_CODE_TLB
+    uint16_t        u16Ret;
     uintptr_t       offBuf = pVCpu->iem.s.offInstrNextByte;
     uint8_t const  *pbBuf  = pVCpu->iem.s.pbInstrBuf;
@@ -982,9 +927,26 @@
         pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 2;
 #   ifdef IEM_USE_UNALIGNED_DATA_ACCESS
-        return *(uint16_t const *)&pbBuf[offBuf];
+        u16Ret = *(uint16_t const *)&pbBuf[offBuf];
 #   else
-        return RT_MAKE_U16(pbBuf[offBuf], pbBuf[offBuf + 1]);
+        u16Ret = RT_MAKE_U16(pbBuf[offBuf], pbBuf[offBuf + 1]);
 #   endif
     }
+    else
+        u16Ret = iemOpcodeGetNextU16SlowJmp(pVCpu);
+
+#   ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
+    Assert(offOpcode + 1 < sizeof(pVCpu->iem.s.abOpcode));
+#    ifdef IEM_USE_UNALIGNED_DATA_ACCESS
+    *(uint16_t *)&pVCpu->iem.s.abOpcode[offOpcode] = u16Ret;
+#    else
+    pVCpu->iem.s.abOpcode[offOpcode]     = RT_LO_U8(u16Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 1] = RT_HI_U8(u16Ret);
+#    endif
+    pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + (uint8_t)2;
+#   endif
+
+    return u16Ret;
+
 #  else /* !IEM_WITH_CODE_TLB */
     uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
@@ -998,6 +960,6 @@
 #   endif
     }
+    return iemOpcodeGetNextU16SlowJmp(pVCpu);
 #  endif /* !IEM_WITH_CODE_TLB */
-    return iemOpcodeGetNextU16SlowJmp(pVCpu);
 }
 
@@ -1174,4 +1136,5 @@
 {
 #  ifdef IEM_WITH_CODE_TLB
+    uint32_t u32Ret;
     uintptr_t       offBuf = pVCpu->iem.s.offInstrNextByte;
     uint8_t const  *pbBuf  = pVCpu->iem.s.pbInstrBuf;
@@ -1181,13 +1144,32 @@
         pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 4;
 #   ifdef IEM_USE_UNALIGNED_DATA_ACCESS
-        return *(uint32_t const *)&pbBuf[offBuf];
+        u32Ret = *(uint32_t const *)&pbBuf[offBuf];
 #   else
-        return RT_MAKE_U32_FROM_U8(pbBuf[offBuf],
-                                   pbBuf[offBuf + 1],
-                                   pbBuf[offBuf + 2],
-                                   pbBuf[offBuf + 3]);
+        u32Ret = RT_MAKE_U32_FROM_U8(pbBuf[offBuf],
+                                     pbBuf[offBuf + 1],
+                                     pbBuf[offBuf + 2],
+                                     pbBuf[offBuf + 3]);
 #   endif
     }
-#  else
+    else
+        u32Ret = iemOpcodeGetNextU32SlowJmp(pVCpu);
+
+#   ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
+    Assert(offOpcode + 3 < sizeof(pVCpu->iem.s.abOpcode));
+#    ifdef IEM_USE_UNALIGNED_DATA_ACCESS
+    *(uint32_t *)&pVCpu->iem.s.abOpcode[offOpcode] = u32Ret;
+#    else
+    pVCpu->iem.s.abOpcode[offOpcode]     = RT_BYTE1(u32Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 1] = RT_BYTE2(u32Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 2] = RT_BYTE3(u32Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 3] = RT_BYTE4(u32Ret);
+#    endif
+    pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + (uint8_t)4;
+#   endif /* IEM_WITH_CODE_TLB_AND_OPCODE_BUF */
+
+    return u32Ret;
+
+#  else  /* !IEM_WITH_CODE_TLB */
     uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
     if (RT_LIKELY((uint8_t)offOpcode + 4 <= pVCpu->iem.s.cbOpcode))
@@ -1203,6 +1185,6 @@
 #   endif
     }
+    return iemOpcodeGetNextU32SlowJmp(pVCpu);
 #  endif
-    return iemOpcodeGetNextU32SlowJmp(pVCpu);
 }
 
@@ -1389,4 +1371,5 @@
 {
 #  ifdef IEM_WITH_CODE_TLB
+    uint64_t        u64Ret;
     uintptr_t       offBuf = pVCpu->iem.s.offInstrNextByte;
     uint8_t const  *pbBuf  = pVCpu->iem.s.pbInstrBuf;
@@ -1396,17 +1379,40 @@
         pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 8;
 #   ifdef IEM_USE_UNALIGNED_DATA_ACCESS
-        return *(uint64_t const *)&pbBuf[offBuf];
+        u64Ret = *(uint64_t const *)&pbBuf[offBuf];
 #   else
-        return RT_MAKE_U64_FROM_U8(pbBuf[offBuf],
-                                   pbBuf[offBuf + 1],
-                                   pbBuf[offBuf + 2],
-                                   pbBuf[offBuf + 3],
-                                   pbBuf[offBuf + 4],
-                                   pbBuf[offBuf + 5],
-                                   pbBuf[offBuf + 6],
-                                   pbBuf[offBuf + 7]);
+        u64Ret = RT_MAKE_U64_FROM_U8(pbBuf[offBuf],
+                                     pbBuf[offBuf + 1],
+                                     pbBuf[offBuf + 2],
+                                     pbBuf[offBuf + 3],
+                                     pbBuf[offBuf + 4],
+                                     pbBuf[offBuf + 5],
+                                     pbBuf[offBuf + 6],
+                                     pbBuf[offBuf + 7]);
 #   endif
     }
-#  else
+    else
+        u64Ret = iemOpcodeGetNextU64SlowJmp(pVCpu);
+
+#   ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
+    Assert(offOpcode + 7 < sizeof(pVCpu->iem.s.abOpcode));
+#    ifdef IEM_USE_UNALIGNED_DATA_ACCESS
+    *(uint64_t *)&pVCpu->iem.s.abOpcode[offOpcode] = u64Ret;
+#    else
+    pVCpu->iem.s.abOpcode[offOpcode]     = RT_BYTE1(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 1] = RT_BYTE2(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 2] = RT_BYTE3(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 3] = RT_BYTE4(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 4] = RT_BYTE5(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 5] = RT_BYTE6(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 6] = RT_BYTE7(u64Ret);
+    pVCpu->iem.s.abOpcode[offOpcode + 7] = RT_BYTE8(u64Ret);
+#    endif
+    pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + (uint8_t)8;
+#   endif /* IEM_WITH_CODE_TLB_AND_OPCODE_BUF */
+
+    return u64Ret;
+
+#  else /* !IEM_WITH_CODE_TLB */
     uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
     if (RT_LIKELY((uint8_t)offOpcode + 8 <= pVCpu->iem.s.cbOpcode))
@@ -1426,6 +1432,6 @@
 #   endif
     }
-#  endif
     return iemOpcodeGetNextU64SlowJmp(pVCpu);
+#  endif /* !IEM_WITH_CODE_TLB */
 }
 
Index: trunk/src/VBox/VMM/include/IEMInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/IEMInternal.h	(revision 100265)
+++ trunk/src/VBox/VMM/include/IEMInternal.h	(revision 100266)
@@ -789,4 +789,11 @@
     /** The offset of the ModR/M byte relative to the start of the instruction. */
     uint8_t                 offModRm;                                                                       /* 0x34 */
+
+#  ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
+    /** The current offset into abOpcode. */
+    uint8_t                 offOpcode;                                                                      /* 0x35 */
+#  else
+    uint8_t                 bUnused;                                                                        /* 0x35 */
+#  endif
 # else  /* !IEM_WITH_CODE_TLB */
     /** The size of what has currently been fetched into abOpcode. */
@@ -813,24 +820,26 @@
 
     /** The effective operand mode. */
-    IEMMODE                 enmEffOpSize;                                                                   /* 0x35, 0x13 */
+    IEMMODE                 enmEffOpSize;                                                                   /* 0x36, 0x13 */
     /** The default addressing mode. */
-    IEMMODE                 enmDefAddrMode;                                                                 /* 0x36, 0x14 */
+    IEMMODE                 enmDefAddrMode;                                                                 /* 0x37, 0x14 */
     /** The effective addressing mode. */
-    IEMMODE                 enmEffAddrMode;                                                                 /* 0x37, 0x15 */
+    IEMMODE                 enmEffAddrMode;                                                                 /* 0x38, 0x15 */
     /** The default operand mode. */
-    IEMMODE                 enmDefOpSize;                                                                   /* 0x38, 0x16 */
+    IEMMODE                 enmDefOpSize;                                                                   /* 0x39, 0x16 */
 
     /** Prefix index (VEX.pp) for two byte and three byte tables. */
-    uint8_t                 idxPrefix;                                                                      /* 0x39, 0x17 */
+    uint8_t                 idxPrefix;                                                                      /* 0x3a, 0x17 */
     /** 3rd VEX/EVEX/XOP register.
      * Please use IEM_GET_EFFECTIVE_VVVV to access.  */
-    uint8_t                 uVex3rdReg;                                                                     /* 0x3a, 0x18 */
+    uint8_t                 uVex3rdReg;                                                                     /* 0x3b, 0x18 */
     /** The VEX/EVEX/XOP length field. */
-    uint8_t                 uVexLength;                                                                     /* 0x3b, 0x19 */
+    uint8_t                 uVexLength;                                                                     /* 0x3c, 0x19 */
     /** Additional EVEX stuff. */
-    uint8_t                 fEvexStuff;                                                                     /* 0x3c, 0x1a */
-
+    uint8_t                 fEvexStuff;                                                                     /* 0x3d, 0x1a */
+
+# ifndef IEM_WITH_CODE_TLB
     /** Explicit alignment padding. */
-    uint8_t                 abAlignment2a[1];                                                               /* 0x3d, 0x1b */
+    uint8_t                 abAlignment2a[1];                                                               /*       0x1b */
+# endif
     /** The FPU opcode (FOP). */
     uint16_t                uFpuOpcode;                                                                     /* 0x3e, 0x1c */
Index: trunk/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
===================================================================
--- trunk/src/VBox/VMM/testcase/tstIEMCheckMc.cpp	(revision 100265)
+++ trunk/src/VBox/VMM/testcase/tstIEMCheckMc.cpp	(revision 100266)
@@ -130,5 +130,4 @@
 
 
-#define IEM_OPCODE_GET_NEXT_RM(a_pu8)                       do { *(a_pu8)  = g_bRandom; CHK_PTYPE(uint8_t  *, a_pu8);  } while (0)
 #define IEM_OPCODE_GET_NEXT_U8(a_pu8)                       do { *(a_pu8)  = g_bRandom; CHK_PTYPE(uint8_t  *, a_pu8);  } while (0)
 #define IEM_OPCODE_GET_NEXT_S8(a_pi8)                       do { *(a_pi8)  = g_bRandom; CHK_PTYPE(int8_t   *, a_pi8);  } while (0)
