summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gc/gc.cpp21
-rw-r--r--src/vm/amd64/jitinterfaceamd64.cpp92
-rw-r--r--src/vm/arm/stubs.cpp28
-rw-r--r--src/vm/arm64/stubs.cpp17
-rw-r--r--src/vm/gcenv.ee.cpp59
-rw-r--r--src/vm/gchelpers.h9
-rw-r--r--src/vm/i386/jitinterfacex86.cpp45
-rw-r--r--src/vm/jitinterface.h20
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: