diff options
-rw-r--r-- | src/gc/gc.cpp | 21 | ||||
-rw-r--r-- | src/vm/amd64/jitinterfaceamd64.cpp | 92 | ||||
-rw-r--r-- | src/vm/arm/stubs.cpp | 28 | ||||
-rw-r--r-- | src/vm/arm64/stubs.cpp | 17 | ||||
-rw-r--r-- | src/vm/gcenv.ee.cpp | 59 | ||||
-rw-r--r-- | src/vm/gchelpers.h | 9 | ||||
-rw-r--r-- | src/vm/i386/jitinterfacex86.cpp | 45 | ||||
-rw-r--r-- | src/vm/jitinterface.h | 20 |
8 files changed, 169 insertions, 122 deletions
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index cb5e7d098e..ce8540939f 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -2327,7 +2327,7 @@ void stomp_write_barrier_ephemeral(uint8_t* ephemeral_low, uint8_t* ephemeral_hi GCToEEInterface::StompWriteBarrier(&args); } -void stomp_write_barrier_initialize() +void stomp_write_barrier_initialize(uint8_t* ephemeral_low, uint8_t* ephemeral_high) { WriteBarrierParameters args = {}; args.operation = WriteBarrierOp::Initialize; @@ -2341,8 +2341,8 @@ void stomp_write_barrier_initialize() args.lowest_address = g_gc_lowest_address; args.highest_address = g_gc_highest_address; - args.ephemeral_low = reinterpret_cast<uint8_t*>(1); - args.ephemeral_high = reinterpret_cast<uint8_t*>(~0); + args.ephemeral_low = ephemeral_low; + args.ephemeral_high = ephemeral_high; GCToEEInterface::StompWriteBarrier(&args); } @@ -10602,7 +10602,18 @@ gc_heap::init_gc_heap (int h_number) make_background_mark_stack (b_arr); #endif //BACKGROUND_GC - adjust_ephemeral_limits(); + ephemeral_low = generation_allocation_start(generation_of(max_generation - 1)); + ephemeral_high = heap_segment_reserved(ephemeral_heap_segment); + if (heap_number == 0) + { + stomp_write_barrier_initialize( +#ifdef MULTIPLE_HEAPS + reinterpret_cast<uint8_t*>(1), reinterpret_cast<uint8_t*>(~0) +#else + ephemeral_low, ephemeral_high +#endif //!MULTIPLE_HEAPS + ); + } #ifdef MARK_ARRAY // why would we clear the mark array for this page? it should be cleared.. @@ -33575,8 +33586,6 @@ HRESULT GCHeap::Initialize () return E_FAIL; } - stomp_write_barrier_initialize(); - #ifndef FEATURE_REDHAWK // Redhawk forces relocation a different way #if defined (STRESS_HEAP) && !defined (MULTIPLE_HEAPS) if (GCStress<cfg_any>::IsEnabled()) { diff --git a/src/vm/amd64/jitinterfaceamd64.cpp b/src/vm/amd64/jitinterfaceamd64.cpp index 6a19e274e0..bffec814b1 100644 --- a/src/vm/amd64/jitinterfaceamd64.cpp +++ b/src/vm/amd64/jitinterfaceamd64.cpp @@ -278,14 +278,14 @@ PBYTE WriteBarrierManager::CalculatePatchLocation(LPVOID base, LPVOID label, int return ((LPBYTE)GetEEFuncEntryPoint(JIT_WriteBarrier) + ((LPBYTE)GetEEFuncEntryPoint(label) - (LPBYTE)GetEEFuncEntryPoint(base) + offset)); } -void WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended) +int WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended) { GCX_MAYBE_COOP_NO_THREAD_BROKEN((!isRuntimeSuspended && GetThread() != NULL)); - BOOL bEESuspendedHere = FALSE; - if(!isRuntimeSuspended && m_currentWriteBarrier != WRITE_BARRIER_UNINITIALIZED) + int stompWBCompleteActions = SWB_PASS; + if (!isRuntimeSuspended && m_currentWriteBarrier != WRITE_BARRIER_UNINITIALIZED) { ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_GC_PREP); - bEESuspendedHere = TRUE; + stompWBCompleteActions |= SWB_EE_RESTART; } _ASSERTE(m_currentWriteBarrier != newWriteBarrier); @@ -409,13 +409,10 @@ void WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, UNREACHABLE_MSG("unexpected write barrier type!"); } - UpdateEphemeralBounds(true); - UpdateWriteWatchAndCardTableLocations(true, false); + stompWBCompleteActions |= UpdateEphemeralBounds(true); + stompWBCompleteActions |= UpdateWriteWatchAndCardTableLocations(true, false); - if(bEESuspendedHere) - { - ThreadSuspend::RestartEE(FALSE, TRUE); - } + return stompWBCompleteActions; } #undef CALC_PATCH_LOCATION @@ -521,21 +518,20 @@ bool WriteBarrierManager::NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, W return m_currentWriteBarrier != writeBarrierType; } -void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) +int WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) { - bool needToFlushCache = false; - WriteBarrierType newType; if (NeedDifferentWriteBarrier(false, &newType)) { - ChangeWriteBarrierTo(newType, isRuntimeSuspended); - return; + return ChangeWriteBarrierTo(newType, isRuntimeSuspended); } + int stompWBCompleteActions = SWB_PASS; + #ifdef _DEBUG // Using debug-only write barrier? if (m_currentWriteBarrier == WRITE_BARRIER_UNINITIALIZED) - return; + return stompWBCompleteActions; #endif switch (m_currentWriteBarrier) @@ -549,7 +545,7 @@ void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) if (*(UINT64*)m_pUpperBoundImmediate != (size_t)g_ephemeral_high) { *(UINT64*)m_pUpperBoundImmediate = (size_t)g_ephemeral_high; - needToFlushCache = true; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; } } // @@ -564,7 +560,7 @@ void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) if (*(UINT64*)m_pLowerBoundImmediate != (size_t)g_ephemeral_low) { *(UINT64*)m_pLowerBoundImmediate = (size_t)g_ephemeral_low; - needToFlushCache = true; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; } break; } @@ -583,13 +579,10 @@ void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) UNREACHABLE_MSG("unexpected m_currentWriteBarrier in UpdateEphemeralBounds"); } - if (needToFlushCache) - { - FlushInstructionCache(GetCurrentProcess(), (PVOID)JIT_WriteBarrier, GetCurrentWriteBarrierSize()); - } + return stompWBCompleteActions; } -void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) +int WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) { // If we are told that we require an upper bounds check (GC did some heap reshuffling), // we need to switch to the WriteBarrier_PostGrow function for good. @@ -597,17 +590,16 @@ void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSu WriteBarrierType newType; if (NeedDifferentWriteBarrier(bReqUpperBoundsCheck, &newType)) { - ChangeWriteBarrierTo(newType, isRuntimeSuspended); - return; + return ChangeWriteBarrierTo(newType, isRuntimeSuspended); } + + int stompWBCompleteActions = SWB_PASS; #ifdef _DEBUG // Using debug-only write barrier? if (m_currentWriteBarrier == WRITE_BARRIER_UNINITIALIZED) - return; + return stompWBCompleteActions; #endif - - bool fFlushCache = false; #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP switch (m_currentWriteBarrier) @@ -620,7 +612,7 @@ void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSu if (*(UINT64*)m_pWriteWatchTableImmediate != (size_t)g_sw_ww_table) { *(UINT64*)m_pWriteWatchTableImmediate = (size_t)g_sw_ww_table; - fFlushCache = true; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; } break; @@ -632,32 +624,29 @@ void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSu if (*(UINT64*)m_pCardTableImmediate != (size_t)g_card_table) { *(UINT64*)m_pCardTableImmediate = (size_t)g_card_table; - fFlushCache = true; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; } #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES if (*(UINT64*)m_pCardBundleTableImmediate != (size_t)g_card_bundle_table) { *(UINT64*)m_pCardBundleTableImmediate = (size_t)g_card_bundle_table; - fFlushCache = true; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; } #endif - if (fFlushCache) - { - FlushInstructionCache(GetCurrentProcess(), (LPVOID)JIT_WriteBarrier, GetCurrentWriteBarrierSize()); - } + return stompWBCompleteActions; } #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -void WriteBarrierManager::SwitchToWriteWatchBarrier(bool isRuntimeSuspended) +int WriteBarrierManager::SwitchToWriteWatchBarrier(bool isRuntimeSuspended) { WriteBarrierType newWriteBarrierType; switch (m_currentWriteBarrier) { case WRITE_BARRIER_UNINITIALIZED: // Using the debug-only write barrier - return; + return SWB_PASS; case WRITE_BARRIER_PREGROW64: newWriteBarrierType = WRITE_BARRIER_WRITE_WATCH_PREGROW64; @@ -677,17 +666,17 @@ void WriteBarrierManager::SwitchToWriteWatchBarrier(bool isRuntimeSuspended) UNREACHABLE(); } - ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended); + return ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended); } -void WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) +int WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) { WriteBarrierType newWriteBarrierType; switch (m_currentWriteBarrier) { case WRITE_BARRIER_UNINITIALIZED: // Using the debug-only write barrier - return; + return SWB_PASS; case WRITE_BARRIER_WRITE_WATCH_PREGROW64: newWriteBarrierType = WRITE_BARRIER_PREGROW64; @@ -707,42 +696,47 @@ void WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) UNREACHABLE(); } - ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended); + return ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended); } #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP // This function bashes the super fast amd64 version of the JIT_WriteBarrier // helper. It should be called by the GC whenever the ephermeral region // bounds get changed, but still remain on the top of the GC Heap. -void StompWriteBarrierEphemeral(bool isRuntimeSuspended) +int StompWriteBarrierEphemeral(bool isRuntimeSuspended) { WRAPPER_NO_CONTRACT; - g_WriteBarrierManager.UpdateEphemeralBounds(isRuntimeSuspended); + return g_WriteBarrierManager.UpdateEphemeralBounds(isRuntimeSuspended); } // This function bashes the super fast amd64 versions of the JIT_WriteBarrier // helpers. It should be called by the GC whenever the ephermeral region gets moved // from being at the top of the GC Heap, and/or when the cards table gets moved. -void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) +int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) { WRAPPER_NO_CONTRACT; - g_WriteBarrierManager.UpdateWriteWatchAndCardTableLocations(isRuntimeSuspended, bReqUpperBoundsCheck); + return g_WriteBarrierManager.UpdateWriteWatchAndCardTableLocations(isRuntimeSuspended, bReqUpperBoundsCheck); +} + +void FlushWriteBarrierInstructionCache() +{ + FlushInstructionCache(GetCurrentProcess(), (PVOID)JIT_WriteBarrier, g_WriteBarrierManager.GetCurrentWriteBarrierSize()); } #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -void SwitchToWriteWatchBarrier(bool isRuntimeSuspended) +int SwitchToWriteWatchBarrier(bool isRuntimeSuspended) { WRAPPER_NO_CONTRACT; - g_WriteBarrierManager.SwitchToWriteWatchBarrier(isRuntimeSuspended); + return g_WriteBarrierManager.SwitchToWriteWatchBarrier(isRuntimeSuspended); } -void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) +int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) { WRAPPER_NO_CONTRACT; - g_WriteBarrierManager.SwitchToNonWriteWatchBarrier(isRuntimeSuspended); + return g_WriteBarrierManager.SwitchToNonWriteWatchBarrier(isRuntimeSuspended); } #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp index 4bc1b2c1ea..6d9b3d0dca 100644 --- a/src/vm/arm/stubs.cpp +++ b/src/vm/arm/stubs.cpp @@ -442,15 +442,9 @@ void UpdateGCWriteBarriers(bool postGrow = false) pDesc++; } - - // We've changed code so we must flush the instruction cache. - BYTE *pbAlteredRange; - DWORD cbAlteredRange; - ComputeWriteBarrierRange(&pbAlteredRange, &cbAlteredRange); - FlushInstructionCache(GetCurrentProcess(), pbAlteredRange, cbAlteredRange); } -void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) +int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) { // The runtime is not always suspended when this is called (unlike StompWriteBarrierEphemeral) but we have // no way to update the barrier code atomically on ARM since each 32-bit value we change is loaded over @@ -462,26 +456,36 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) // suspend/resuming the EE under GC stress will trigger a GC and if we're holding the // GC lock due to allocating a LOH segment it will cause a deadlock so disable it here. GCStressPolicy::InhibitHolder iholder; + int stompWBCompleteActions = SWB_ICACHE_FLUSH; - bool fSuspended = false; if (!isRuntimeSuspended) { ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER); - fSuspended = true; + stompWBCompleteActions |= SWB_EE_RESTART; } UpdateGCWriteBarriers(bReqUpperBoundsCheck); - if (fSuspended) - ThreadSuspend::RestartEE(FALSE, TRUE); + return stompWBCompleteActions; } -void StompWriteBarrierEphemeral(bool isRuntimeSuspended) +int StompWriteBarrierEphemeral(bool isRuntimeSuspended) { UNREFERENCED_PARAMETER(isRuntimeSuspended); _ASSERTE(isRuntimeSuspended); UpdateGCWriteBarriers(); + return SWB_ICACHE_FLUSH; } + +void FlushWriteBarrierInstructionCache() +{ + // We've changed code so we must flush the instruction cache. + BYTE *pbAlteredRange; + DWORD cbAlteredRange; + ComputeWriteBarrierRange(&pbAlteredRange, &cbAlteredRange); + FlushInstructionCache(GetCurrentProcess(), pbAlteredRange, cbAlteredRange); +} + #endif // CROSSGEN_COMPILE #endif // !DACCESS_COMPILE diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp index 7e7c2e8088..c57fca94b1 100644 --- a/src/vm/arm64/stubs.cpp +++ b/src/vm/arm64/stubs.cpp @@ -1348,26 +1348,35 @@ LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv) return EXCEPTION_CONTINUE_SEARCH; } +void FlushWriteBarrierInstructionCache() +{ + // this wouldn't be called in arm64, just to comply with gchelpers.h +} + #ifndef CROSSGEN_COMPILE -void StompWriteBarrierEphemeral(bool isRuntimeSuspended) +int StompWriteBarrierEphemeral(bool isRuntimeSuspended) { JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); + return SWB_PASS; } -void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) +int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) { JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); + return SWB_PASS; } #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -void SwitchToWriteWatchBarrier(bool isRuntimeSuspended) +int SwitchToWriteWatchBarrier(bool isRuntimeSuspended) { JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); + return SWB_PASS; } -void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) +int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) { JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); + return SWB_PASS; } #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP #endif // CROSSGEN_COMPILE diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index b135173c0f..29c75e2577 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -843,6 +843,8 @@ void GCToEEInterface::DiagWalkBGCSurvivors(void* gcContext) void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) { + int stompWBCompleteActions = SWB_PASS; + assert(args != nullptr); switch (args->operation) { @@ -868,7 +870,7 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) } #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - ::StompWriteBarrierResize(args->is_runtime_suspended, args->requires_upper_bounds_check); + stompWBCompleteActions |= ::StompWriteBarrierResize(args->is_runtime_suspended, args->requires_upper_bounds_check); // We need to make sure that other threads executing checked write barriers // will see the g_card_table update before g_lowest/highest_address updates. @@ -884,30 +886,45 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) // "cross-modifying code": We need all _executing_ threads to invalidate // their instruction cache, which FlushProcessWriteBuffers achieves by sending // an IPI (inter-process interrupt). - FlushProcessWriteBuffers(); + + if (stompWBCompleteActions & SWB_ICACHE_FLUSH) + { + // flushing icache on current processor (thread) + ::FlushWriteBarrierInstructionCache(); + // asking other processors (threads) to invalidate their icache + FlushProcessWriteBuffers(); + } g_lowest_address = args->lowest_address; VolatileStore(&g_highest_address, args->highest_address); #if defined(_ARM64_) // Need to reupdate for changes to g_highest_address g_lowest_address - ::StompWriteBarrierResize(args->is_runtime_suspended, args->requires_upper_bounds_check); + bool is_runtime_suspended = (stompWBCompleteActions & SWB_EE_RESTART) || args->is_runtime_suspended; + stompWBCompleteActions |= ::StompWriteBarrierResize(is_runtime_suspended, args->requires_upper_bounds_check); - if(!args->is_runtime_suspended) + is_runtime_suspended = (stompWBCompleteActions & SWB_EE_RESTART) || args->is_runtime_suspended; + if(!is_runtime_suspended) { // If runtime is not suspended, force updated state to be visible to all threads MemoryBarrier(); } #endif - return; + if (stompWBCompleteActions & SWB_EE_RESTART) + { + assert(!args->is_runtime_suspended && + "if runtime was suspended in patching routines then it was in running state at begining"); + ThreadSuspend::RestartEE(FALSE, TRUE); + } + return; // unlike other branches we have already done cleanup so bailing out here case WriteBarrierOp::StompEphemeral: // StompEphemeral requires a new ephemeral low and a new ephemeral high assert(args->ephemeral_low != nullptr); assert(args->ephemeral_high != nullptr); g_ephemeral_low = args->ephemeral_low; g_ephemeral_high = args->ephemeral_high; - ::StompWriteBarrierEphemeral(args->is_runtime_suspended); - return; + stompWBCompleteActions |= ::StompWriteBarrierEphemeral(args->is_runtime_suspended); + break; case WriteBarrierOp::Initialize: // This operation should only be invoked once, upon initialization. assert(g_card_table == nullptr); @@ -927,12 +944,10 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) assert(g_card_bundle_table == nullptr); g_card_bundle_table = args->card_bundle_table; #endif - - FlushProcessWriteBuffers(); g_lowest_address = args->lowest_address; - VolatileStore(&g_highest_address, args->highest_address); - ::StompWriteBarrierResize(true, false); + g_highest_address = args->highest_address; + stompWBCompleteActions |= ::StompWriteBarrierResize(true, false); // StompWriteBarrierResize does not necessarily bash g_ephemeral_low // usages, so we must do so here. This is particularly true on x86, @@ -940,32 +955,42 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) // called with the parameters (true, false), as it is above. g_ephemeral_low = args->ephemeral_low; g_ephemeral_high = args->ephemeral_high; - ::StompWriteBarrierEphemeral(true); - return; + stompWBCompleteActions |= ::StompWriteBarrierEphemeral(true); + break; case WriteBarrierOp::SwitchToWriteWatch: #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP assert(args->write_watch_table != nullptr); assert(args->is_runtime_suspended && "the runtime must be suspended here!"); g_sw_ww_table = args->write_watch_table; g_sw_ww_enabled_for_gc_heap = true; - ::SwitchToWriteWatchBarrier(true); + stompWBCompleteActions |= ::SwitchToWriteWatchBarrier(true); #else assert(!"should never be called without FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP"); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - return; + break; case WriteBarrierOp::SwitchToNonWriteWatch: #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP assert(args->is_runtime_suspended && "the runtime must be suspended here!"); g_sw_ww_table = 0; g_sw_ww_enabled_for_gc_heap = false; - ::SwitchToNonWriteWatchBarrier(true); + stompWBCompleteActions |= ::SwitchToNonWriteWatchBarrier(true); #else assert(!"should never be called without FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP"); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - return; + break; default: assert(!"unknown WriteBarrierOp enum"); } + if (stompWBCompleteActions & SWB_ICACHE_FLUSH) + { + ::FlushWriteBarrierInstructionCache(); + } + if (stompWBCompleteActions & SWB_EE_RESTART) + { + assert(!args->is_runtime_suspended && + "if runtime was suspended in patching routines then it was in running state at begining"); + ThreadSuspend::RestartEE(FALSE, TRUE); + } } void GCToEEInterface::EnableFinalization(bool foundFinalizers) diff --git a/src/vm/gchelpers.h b/src/vm/gchelpers.h index 73933f691f..0e407c6e61 100644 --- a/src/vm/gchelpers.h +++ b/src/vm/gchelpers.h @@ -107,10 +107,11 @@ OBJECTREF AllocateObject(MethodTable *pMT #endif ); -extern void StompWriteBarrierEphemeral(bool isRuntimeSuspended); -extern void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck); -extern void SwitchToWriteWatchBarrier(bool isRuntimeSuspended); -extern void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended); +extern int StompWriteBarrierEphemeral(bool isRuntimeSuspended); +extern int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck); +extern int SwitchToWriteWatchBarrier(bool isRuntimeSuspended); +extern int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended); +extern void FlushWriteBarrierInstructionCache(); extern void ThrowOutOfMemoryDimensionsExceeded(); diff --git a/src/vm/i386/jitinterfacex86.cpp b/src/vm/i386/jitinterfacex86.cpp index 66911e87f5..8463b084ac 100644 --- a/src/vm/i386/jitinterfacex86.cpp +++ b/src/vm/i386/jitinterfacex86.cpp @@ -1675,21 +1675,21 @@ void ValidateWriteBarrierHelpers() // When a GC happens, the upper and lower bounds of the ephemeral // generation change. This routine updates the WriteBarrier thunks // with the new values. -void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */) +int StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */) { CONTRACTL { NOTHROW; GC_NOTRIGGER; } CONTRACTL_END; + int stompWBCompleteActions = SWB_PASS; + #ifdef WRITE_BARRIER_CHECK // Don't do the fancy optimization if we are checking write barrier if (((BYTE *)JIT_WriteBarrierEAX)[0] == 0xE9) // we are using slow write barrier - return; + return stompWBCompleteActions; #endif // WRITE_BARRIER_CHECK - BOOL flushICache = FALSE; - // Update the lower bound. for (int iBarrier = 0; iBarrier < NUM_WRITE_BARRIERS; iBarrier++) { @@ -1703,7 +1703,7 @@ void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */) //avoid trivial self modifying code if (*pfunc != (size_t) g_ephemeral_low) { - flushICache = TRUE; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; *pfunc = (size_t) g_ephemeral_low; } if (!WriteBarrierIsPreGrow()) @@ -1716,15 +1716,13 @@ void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */) //avoid trivial self modifying code if (*pfunc != (size_t) g_ephemeral_high) { - flushICache = TRUE; + stompWBCompleteActions |= SWB_ICACHE_FLUSH; *pfunc = (size_t) g_ephemeral_high; } } } - if (flushICache) - FlushInstructionCache(GetCurrentProcess(), (void *)JIT_PatchedWriteBarrierGroup, - (BYTE*)JIT_PatchedWriteBarrierGroup_End - (BYTE*)JIT_PatchedWriteBarrierGroup); + return stompWBCompleteActions; } /*********************************************************************/ @@ -1733,24 +1731,24 @@ void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */) // to the PostGrow thunk that checks both upper and lower bounds. // regardless we need to update the thunk with the // card_table - lowest_address. -void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) +int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) { CONTRACTL { NOTHROW; if (GetThread()) {GC_TRIGGERS;} else {GC_NOTRIGGER;} } CONTRACTL_END; + int stompWBCompleteActions = SWB_PASS; + #ifdef WRITE_BARRIER_CHECK // Don't do the fancy optimization if we are checking write barrier if (((BYTE *)JIT_WriteBarrierEAX)[0] == 0xE9) // we are using slow write barrier - return; + return stompWBCompleteActions; #endif // WRITE_BARRIER_CHECK bool bWriteBarrierIsPreGrow = WriteBarrierIsPreGrow(); bool bStompWriteBarrierEphemeral = false; - BOOL bEESuspendedHere = FALSE; - for (int iBarrier = 0; iBarrier < NUM_WRITE_BARRIERS; iBarrier++) { BYTE * pBuf = (BYTE *)c_rgWriteBarriers[iBarrier]; @@ -1765,9 +1763,9 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) if (bReqUpperBoundsCheck) { GCX_MAYBE_COOP_NO_THREAD_BROKEN((GetThread()!=NULL)); - if( !isRuntimeSuspended && !bEESuspendedHere) { + if( !isRuntimeSuspended && !(stompWBCompleteActions & SWB_EE_RESTART) ) { ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_GC_PREP); - bEESuspendedHere = TRUE; + stompWBCompleteActions |= SWB_EE_RESTART; } pfunc = (size_t *) JIT_WriteBarrierReg_PostGrow; @@ -1855,16 +1853,15 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) if (bStompWriteBarrierEphemeral) { - _ASSERTE(isRuntimeSuspended || bEESuspendedHere); - StompWriteBarrierEphemeral(true); - } - else - { - FlushInstructionCache(GetCurrentProcess(), (void *)JIT_PatchedWriteBarrierGroup, - (BYTE*)JIT_PatchedWriteBarrierGroup_End - (BYTE*)JIT_PatchedWriteBarrierGroup); + _ASSERTE(isRuntimeSuspended || (stompWBCompleteActions & SWB_EE_RESTART)); + stompWBCompleteActions |= StompWriteBarrierEphemeral(true); } + return stompWBCompleteActions; +} - if(bEESuspendedHere) - ThreadSuspend::RestartEE(FALSE, TRUE); +void FlushWriteBarrierInstructionCache() +{ + FlushInstructionCache(GetCurrentProcess(), (void *)JIT_PatchedWriteBarrierGroup, + (BYTE*)JIT_PatchedWriteBarrierGroup_End - (BYTE*)JIT_PatchedWriteBarrierGroup); } diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h index b27e160e80..56394e3016 100644 --- a/src/vm/jitinterface.h +++ b/src/vm/jitinterface.h @@ -22,6 +22,14 @@ #define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((GetOsPageSize() / 2) - 1) #endif // !FEATURE_PAL + +enum StompWriteBarrierCompletionAction +{ + SWB_PASS = 0x0, + SWB_ICACHE_FLUSH = 0x1, + SWB_EE_RESTART = 0x2 +}; + class Stub; class MethodDesc; class FieldDesc; @@ -294,20 +302,20 @@ public: WriteBarrierManager(); void Initialize(); - void UpdateEphemeralBounds(bool isRuntimeSuspended); - void UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck); + int UpdateEphemeralBounds(bool isRuntimeSuspended); + int UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck); #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - void SwitchToWriteWatchBarrier(bool isRuntimeSuspended); - void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended); + int SwitchToWriteWatchBarrier(bool isRuntimeSuspended); + int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + size_t GetCurrentWriteBarrierSize(); protected: - size_t GetCurrentWriteBarrierSize(); size_t GetSpecificWriteBarrierSize(WriteBarrierType writeBarrier); PBYTE CalculatePatchLocation(LPVOID base, LPVOID label, int offset); PCODE GetCurrentWriteBarrierCode(); - void ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended); + int ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended); bool NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, WriteBarrierType* pNewWriteBarrierType); private: |