Index: trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompFuncs.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompFuncs.h	(revision 105854)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompFuncs.h	(revision 105855)
@@ -579,5 +579,5 @@
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
     pReNative->Core.offPc += cbInstr;
-    Log4(("offPc=%x cbInstr=%#x off=%#x\n", pReNative->Core.offPc, cbInstr, off));
+    Log4(("offPc=%#RX64 cbInstr=%#x off=%#x\n", pReNative->Core.offPc, cbInstr, off));
 # ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
     off = iemNativeEmitPcDebugAdd(pReNative, off, cbInstr, 64);
@@ -586,8 +586,5 @@
     off = iemNativePcAdjustCheck(pReNative, off);
 # endif
-# if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
     STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativePcUpdateTotal);
-    pReNative->Core.cInstrPcUpdateSkipped++;
-# endif
 #endif
 
@@ -628,5 +625,5 @@
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
     pReNative->Core.offPc += cbInstr;
-    Log4(("offPc=%x cbInstr=%#x off=%#x\n", pReNative->Core.offPc, cbInstr, off));
+    Log4(("offPc=%#RX64 cbInstr=%#x off=%#x\n", pReNative->Core.offPc, cbInstr, off));
 # ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
     off = iemNativeEmitPcDebugAdd(pReNative, off, cbInstr, 32);
@@ -635,8 +632,5 @@
     off = iemNativePcAdjustCheck(pReNative, off);
 # endif
-# if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
     STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativePcUpdateTotal);
-    pReNative->Core.cInstrPcUpdateSkipped++;
-# endif
 #endif
 
@@ -678,5 +672,5 @@
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
     pReNative->Core.offPc += cbInstr;
-    Log4(("offPc=%x cbInstr=%#x off=%#x\n", pReNative->Core.offPc, cbInstr, off));
+    Log4(("offPc=%#RX64 cbInstr=%#x off=%#x\n", pReNative->Core.offPc, cbInstr, off));
 # ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
     off = iemNativeEmitPcDebugAdd(pReNative, off, cbInstr, 16);
@@ -685,8 +679,5 @@
     off = iemNativePcAdjustCheck(pReNative, off);
 # endif
-# if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
     STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativePcUpdateTotal);
-    pReNative->Core.cInstrPcUpdateSkipped++;
-# endif
 #endif
 
@@ -776,43 +767,50 @@
 {
     Assert(enmEffOpSize == IEMMODE_64BIT || enmEffOpSize == IEMMODE_16BIT);
-
-    /* We speculatively modify PC and may raise #GP(0), so make sure the right values are in CPUMCTX. */
-/** @todo relax this one, we won't raise \#GP when a_fWithinPage is true. */
-    off = iemNativeRegFlushPendingWrites(pReNative, off);
-
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
-    Assert(pReNative->Core.offPc == 0);
     STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativePcUpdateTotal);
-#endif
-
-    /* Allocate a temporary PC register. */
-    uint8_t const idxPcReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_Pc, kIemNativeGstRegUse_ForUpdate);
-
-    /* Perform the addition. */
-    off = iemNativeEmitAddGprImm(pReNative, off, idxPcReg, (int64_t)offDisp + cbInstr);
-
-    if (RT_LIKELY(enmEffOpSize == IEMMODE_64BIT))
-    {
-        /* Check that the address is canonical, raising #GP(0) + exit TB if it isn't.
-           We can skip this if the target is within the same page. */
-        if (!a_fWithinPage)
-            off = iemNativeEmitCheckGprCanonicalMaybeRaiseGp0(pReNative, off, idxPcReg, idxInstr);
+    if (a_fWithinPage && enmEffOpSize == IEMMODE_64BIT)
+    {
+        pReNative->Core.offPc += (int64_t)offDisp + cbInstr;
+# ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
+        off = iemNativeEmitPcDebugAdd(pReNative, off, (int64_t)offDisp + cbInstr, enmEffOpSize == IEMMODE_64BIT ? 64 : 16);
+# endif
     }
     else
-    {
-        /* Just truncate the result to 16-bit IP. */
-        Assert(enmEffOpSize == IEMMODE_16BIT);
-        off = iemNativeEmitClear16UpGpr(pReNative, off, idxPcReg);
-    }
+#endif
+    {
+        /* We speculatively modify PC and may raise #GP(0), so make sure the right values are in CPUMCTX. */
+        off = iemNativeRegFlushPendingWrites(pReNative, off);
+#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+        Assert(pReNative->Core.offPc == 0);
+#endif
+        /* Allocate a temporary PC register. */
+        uint8_t const idxPcReg = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_Pc, kIemNativeGstRegUse_ForUpdate);
+
+        /* Perform the addition. */
+        off = iemNativeEmitAddGprImm(pReNative, off, idxPcReg, (int64_t)offDisp + cbInstr + pReNative->Core.offPc);
+
+        if (RT_LIKELY(enmEffOpSize == IEMMODE_64BIT))
+        {
+            /* Check that the address is canonical, raising #GP(0) + exit TB if it isn't.
+               We can skip this if the target is within the same page. */
+            if (!a_fWithinPage)
+                off = iemNativeEmitCheckGprCanonicalMaybeRaiseGp0(pReNative, off, idxPcReg, idxInstr);
+        }
+        else
+        {
+            /* Just truncate the result to 16-bit IP. */
+            Assert(enmEffOpSize == IEMMODE_16BIT);
+            off = iemNativeEmitClear16UpGpr(pReNative, off, idxPcReg);
+        }
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
-    off = iemNativeEmitPcDebugAdd(pReNative, off, (int64_t)offDisp + cbInstr, enmEffOpSize == IEMMODE_64BIT ? 64 : 16);
-    off = iemNativeEmitPcDebugCheckWithReg(pReNative, off, idxPcReg);
-#endif
-
-    off = iemNativeEmitStoreGprToVCpuU64(pReNative, off, idxPcReg, RT_UOFFSETOF(VMCPU, cpum.GstCtx.rip));
-
-    /* Free but don't flush the PC register. */
-    iemNativeRegFreeTmp(pReNative, idxPcReg);
-
+        off = iemNativeEmitPcDebugAdd(pReNative, off, (int64_t)offDisp + cbInstr, enmEffOpSize == IEMMODE_64BIT ? 64 : 16);
+        off = iemNativeEmitPcDebugCheckWithReg(pReNative, off, idxPcReg);
+#endif
+
+        off = iemNativeEmitStoreGprToVCpuU64(pReNative, off, idxPcReg, RT_UOFFSETOF(VMCPU, cpum.GstCtx.rip));
+
+        /* Free but don't flush the PC register. */
+        iemNativeRegFreeTmp(pReNative, idxPcReg);
+    }
     return off;
 }
@@ -895,12 +893,16 @@
 {
     Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
+#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+    STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativePcUpdateTotal);
+#endif
 
     /* We speculatively modify PC and may raise #GP(0), so make sure the right values are in CPUMCTX. */
-    off = iemNativeRegFlushPendingWrites(pReNative, off);
-
+    if (!a_fFlat || enmEffOpSize == IEMMODE_16BIT)
+    {
+        off = iemNativeRegFlushPendingWrites(pReNative, off);
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
-    Assert(pReNative->Core.offPc == 0);
-    STAM_COUNTER_INC(&pReNative->pVCpu->iem.s.StatNativePcUpdateTotal);
-#endif
+        Assert(pReNative->Core.offPc == 0);
+#endif
+    }
 
     /* Allocate a temporary PC register. */
@@ -908,5 +910,9 @@
 
     /* Perform the addition. */
-    off = iemNativeEmitAddGpr32Imm(pReNative, off, idxPcReg, offDisp + cbInstr);
+#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+    off = iemNativeEmitAddGpr32Imm(pReNative, off, idxPcReg, offDisp + cbInstr + (int32_t)pReNative->Core.offPc);
+#else
+    off = iemNativeEmitAddGpr32Imm(pReNative, off, idxPcReg, offDisp + cbInstr + (int32_t)pReNative->Core.offPc);
+#endif
 
     /* Truncate the result to 16-bit IP if the operand size is 16-bit. */
@@ -918,4 +924,5 @@
         off = iemNativeEmitCheckGpr32AgainstCsSegLimitMaybeRaiseGp0(pReNative, off, idxPcReg, idxInstr);
 
+    /* Commit it. */
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
     off = iemNativeEmitPcDebugAdd(pReNative, off, offDisp + cbInstr, enmEffOpSize == IEMMODE_32BIT ? 32 : 16);
@@ -924,4 +931,7 @@
 
     off = iemNativeEmitStoreGprToVCpuU64(pReNative, off, idxPcReg, RT_UOFFSETOF(VMCPU, cpum.GstCtx.rip));
+#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+    pReNative->Core.offPc = 0;
+#endif
 
     /* Free but don't flush the PC register. */
@@ -2727,5 +2737,5 @@
 #ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
         AssertMsgStmt(pReNative->Core.offPc == pOther->offPc,
-                      ("Core.offPc=%#x pOther->offPc=%#x\n", pReNative->Core.offPc, pOther->offPc),
+                      ("Core.offPc=%#RX64 pOther->offPc=%#RX64\n", pReNative->Core.offPc, pOther->offPc),
                       IEMNATIVE_DO_LONGJMP(pReNative, VERR_IEM_COND_ENDIF_RECONCILIATION_FAILED));
 #endif
@@ -6301,17 +6311,15 @@
     if ((bRmEx & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
     {
-#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
-        /* Need to take the current PC offset into account for the displacement, no need to flush here
-         * as the PC is only accessed readonly and there is no branching or calling helpers involved. */
-        u32Disp += pReNative->Core.offPc;
-#endif
-
         uint8_t const idxRegRet = iemNativeVarRegisterAcquire(pReNative, idxVarRet, &off);
         uint8_t const idxRegPc  = iemNativeRegAllocTmpForGuestReg(pReNative, &off, kIemNativeGstReg_Pc,
                                                                   kIemNativeGstRegUse_ReadOnly);
-#ifdef RT_ARCH_AMD64
         if (f64Bit)
         {
+#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+            int64_t const offFinalDisp = (int64_t)(int32_t)u32Disp + cbInstr + (int64_t)pReNative->Core.offPc;
+#else
             int64_t const offFinalDisp = (int64_t)(int32_t)u32Disp + cbInstr;
+#endif
+#ifdef RT_ARCH_AMD64
             if ((int32_t)offFinalDisp == offFinalDisp)
                 off = iemNativeEmitLoadGprFromGprWithAddendMaybeZero(pReNative, off, idxRegRet, idxRegPc, (int32_t)offFinalDisp);
@@ -6321,19 +6329,17 @@
                 off = iemNativeEmitAddGprImm8(pReNative, off, idxRegRet, cbInstr);
             }
+#else
+            off = iemNativeEmitLoadGprFromGprWithAddendMaybeZero(pReNative, off, idxRegRet, idxRegPc, offFinalDisp);
+#endif
         }
         else
-            off = iemNativeEmitLoadGprFromGpr32WithAddendMaybeZero(pReNative, off, idxRegRet, idxRegPc, (int32_t)u32Disp + cbInstr);
-
-#elif defined(RT_ARCH_ARM64)
-        if (f64Bit)
-            off = iemNativeEmitLoadGprFromGprWithAddendMaybeZero(pReNative, off, idxRegRet, idxRegPc,
-                                                                 (int64_t)(int32_t)u32Disp + cbInstr);
-        else
-            off = iemNativeEmitLoadGprFromGpr32WithAddendMaybeZero(pReNative, off, idxRegRet, idxRegPc,
-                                                                   (int32_t)u32Disp + cbInstr);
-
-#else
-# error "Port me!"
-#endif
+        {
+# ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+            int32_t const offFinalDisp = (int32_t)u32Disp + cbInstr + (int32_t)pReNative->Core.offPc;
+# else
+            int32_t const offFinalDisp = (int32_t)u32Disp + cbInstr;
+# endif
+            off = iemNativeEmitLoadGprFromGpr32WithAddendMaybeZero(pReNative, off, idxRegRet, idxRegPc, offFinalDisp);
+        }
         iemNativeRegFreeTmp(pReNative, idxRegPc);
         iemNativeVarRegisterRelease(pReNative, idxVarRet);
Index: trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp	(revision 105854)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp	(revision 105855)
@@ -2072,5 +2072,5 @@
     pReNative->Core.offPc                  = 0;
 # if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
-    pReNative->Core.cInstrPcUpdateSkipped  = 0;
+    pReNative->Core.idxInstrPlusOneOfLastPcUpdate = 0;
 # endif
 # ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
@@ -2718,9 +2718,9 @@
  * Debug Info: Record info about delayed RIP updates.
  */
-DECL_HIDDEN_THROW(void) iemNativeDbgInfoAddDelayedPcUpdate(PIEMRECOMPILERSTATE pReNative, uint32_t offPc, uint32_t cInstrSkipped)
+DECL_HIDDEN_THROW(void) iemNativeDbgInfoAddDelayedPcUpdate(PIEMRECOMPILERSTATE pReNative, uint64_t offPc, uint32_t cInstrSkipped)
 {
     PIEMTBDBGENTRY const pEntry = iemNativeDbgInfoAddNewEntry(pReNative, pReNative->pDbgInfo);
     pEntry->DelayedPcUpdate.uType         = kIemTbDbgEntryType_DelayedPcUpdate;
-    pEntry->DelayedPcUpdate.offPc         = offPc;
+    pEntry->DelayedPcUpdate.offPc         = offPc; /** @todo support larger values */
     pEntry->DelayedPcUpdate.cInstrSkipped = cInstrSkipped;
 }
@@ -5765,8 +5765,24 @@
 {
     Assert(pReNative->Core.offPc);
-    Log4(("offPc=%#x -> 0; off=%#x\n", pReNative->Core.offPc, off));
-# ifdef IEMNATIVE_WITH_TB_DEBUG_INFO
+# if !defined(IEMNATIVE_WITH_TB_DEBUG_INFO) && !defined(VBOX_WITH_STATISTICS)
+    Log4(("iemNativeEmitPcWritebackSlow: offPc=%#RX64 -> 0; off=%#x\n", pReNative->Core.offPc, off));
+# else
+    uint8_t const idxOldInstrPlusOne = pReNative->Core.idxInstrPlusOneOfLastPcUpdate;
+    uint8_t       idxCurCall         = pReNative->idxCurCall;
+    uint8_t       idxInstr           = pReNative->pTbOrg->Thrd.paCalls[idxCurCall].idxInstr; /* unreliable*/
+    while (idxInstr == 0 && idxInstr + 1 < idxOldInstrPlusOne && idxCurCall > 0)
+        idxInstr = pReNative->pTbOrg->Thrd.paCalls[--idxCurCall].idxInstr;
+    uint8_t const cInstrsSkipped     = idxInstr <= pReNative->Core.idxInstrPlusOneOfLastPcUpdate ? 0
+                                     : idxInstr - pReNative->Core.idxInstrPlusOneOfLastPcUpdate;
+    Log4(("iemNativeEmitPcWritebackSlow: offPc=%#RX64 -> 0; off=%#x; idxInstr=%u cInstrsSkipped=%u\n",
+          pReNative->Core.offPc, off, idxInstr, cInstrsSkipped));
+
+    pReNative->Core.idxInstrPlusOneOfLastPcUpdate = RT_MAX(idxInstr + 1, pReNative->Core.idxInstrPlusOneOfLastPcUpdate);
+    STAM_COUNTER_ADD(&pReNative->pVCpu->iem.s.StatNativePcUpdateDelayed, cInstrsSkipped);
+
+#  ifdef IEMNATIVE_WITH_TB_DEBUG_INFO
     iemNativeDbgInfoAddNativeOffset(pReNative, off);
-    iemNativeDbgInfoAddDelayedPcUpdate(pReNative, pReNative->Core.offPc, pReNative->Core.cInstrPcUpdateSkipped);
+    iemNativeDbgInfoAddDelayedPcUpdate(pReNative, pReNative->Core.offPc, cInstrsSkipped);
+#  endif
 # endif
 
@@ -5790,9 +5806,5 @@
 # endif
 
-    pReNative->Core.offPc                 = 0;
-# if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
-    STAM_COUNTER_ADD(&pReNative->pVCpu->iem.s.StatNativePcUpdateDelayed, pReNative->Core.cInstrPcUpdateSkipped);
-    pReNative->Core.cInstrPcUpdateSkipped = 0;
-# endif
+    pReNative->Core.offPc = 0;
 
     return off;
@@ -10136,5 +10148,5 @@
         uint32_t             cRecompiledCalls = 0;
 #endif
-#if defined(IEMNATIVE_WITH_LIVENESS_ANALYSIS) || defined(IEM_WITH_INTRA_TB_JUMPS) || defined(VBOX_STRICT) || defined(LOG_ENABLED)
+#if defined(IEMNATIVE_WITH_LIVENESS_ANALYSIS) || defined(IEM_WITH_INTRA_TB_JUMPS) || defined(VBOX_STRICT) || defined(LOG_ENABLED) || defined(VBOX_WITH_STATISTICS) || defined(IEMNATIVE_WITH_DELAYED_PC_UPDATING)
         uint32_t             idxCurCall       = 0;
 #endif
@@ -10144,5 +10156,5 @@
         {
             PFNIEMNATIVERECOMPFUNC const pfnRecom = g_apfnIemNativeRecompileFunctions[pCallEntry->enmFunction];
-#ifdef IEMNATIVE_WITH_LIVENESS_ANALYSIS
+#if defined(IEMNATIVE_WITH_LIVENESS_ANALYSIS) || defined(VBOX_WITH_STATISTICS) || defined(IEMNATIVE_WITH_DELAYED_PC_UPDATING)
             pReNative->idxCurCall                 = idxCurCall;
 #endif
@@ -10258,5 +10270,5 @@
              */
             pCallEntry++;
-#if defined(IEMNATIVE_WITH_LIVENESS_ANALYSIS) || defined(IEM_WITH_INTRA_TB_JUMPS) || defined(VBOX_STRICT) || defined(LOG_ENABLED)
+#if defined(IEMNATIVE_WITH_LIVENESS_ANALYSIS) || defined(IEM_WITH_INTRA_TB_JUMPS) || defined(VBOX_STRICT) || defined(LOG_ENABLED) || defined(VBOX_WITH_STATISTICS) || defined(IEMNATIVE_WITH_DELAYED_PC_UPDATING)
             idxCurCall++;
 #endif
Index: trunk/src/VBox/VMM/include/IEMN8veRecompiler.h
===================================================================
--- trunk/src/VBox/VMM/include/IEMN8veRecompiler.h	(revision 105854)
+++ trunk/src/VBox/VMM/include/IEMN8veRecompiler.h	(revision 105855)
@@ -1240,21 +1240,4 @@
 typedef struct IEMNATIVECORESTATE
 {
-#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
-    /** The current instruction offset in bytes from when the guest program counter
-     * was updated last. Used for delaying the write to the guest context program counter
-     * as long as possible. */
-    uint32_t                    offPc;
-# if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
-    /** Number of instructions where we could skip the updating. */
-    uint8_t                     cInstrPcUpdateSkipped;
-# endif
-# ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
-    /** Set after we've loaded PC into uPcUpdatingDebug at the first update. */
-    bool                        fDebugPcInitialized;
-    uint8_t                     abPadding[2];
-# else
-    uint8_t                     abPadding[3];
-# endif
-#endif
     /** Allocation bitmap for aHstRegs. */
     uint32_t                    bmHstRegs;
@@ -1268,4 +1251,19 @@
     /** Bitmap marking the shadowed guest register as dirty and needing writeback when flushing. */
     uint64_t                    bmGstRegShadowDirty;
+#endif
+
+#ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING
+    /** The current instruction offset in bytes from when the guest program counter
+     * was updated last. Used for delaying the write to the guest context program counter
+     * as long as possible. */
+    int64_t                     offPc;
+# if defined(IEMNATIVE_WITH_TB_DEBUG_INFO) || defined(VBOX_WITH_STATISTICS)
+    /** Statistics: The idxInstr+1 value at the last PC update. */
+    uint8_t                     idxInstrPlusOneOfLastPcUpdate;
+# endif
+# ifdef IEMNATIVE_WITH_DELAYED_PC_UPDATING_DEBUG
+    /** Set after we've loaded PC into uPcUpdatingDebug at the first update. */
+    bool                        fDebugPcInitialized;
+# endif
 #endif
 
@@ -1669,5 +1667,5 @@
 # endif
 DECL_HIDDEN_THROW(void)     iemNativeDbgInfoAddDelayedPcUpdate(PIEMRECOMPILERSTATE pReNative,
-                                                               uint32_t offPc, uint32_t cInstrSkipped);
+                                                               uint64_t offPc, uint32_t cInstrSkipped);
 #endif /* IEMNATIVE_WITH_TB_DEBUG_INFO */
 
