Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 3952b64

Browse files
committed
Move Software Write Watch's write barrier updates to use the new
GCToEEInterface::StompWriteBarrier to stomp the EE's write barrier.
1 parent 98798b7 commit 3952b64

17 files changed

+195
-89
lines changed

src/gc/gc.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,9 +1402,6 @@ int mark_time, plan_time, sweep_time, reloc_time, compact_time;
14021402

14031403
#ifndef MULTIPLE_HEAPS
14041404

1405-
#define ephemeral_low g_gc_ephemeral_low
1406-
#define ephemeral_high g_gc_ephemeral_high
1407-
14081405
#endif // MULTIPLE_HEAPS
14091406

14101407
#ifdef TRACE_GC
@@ -2187,26 +2184,32 @@ void stomp_write_barrier_resize(bool is_runtime_suspended, bool requires_upper_b
21872184
args.card_table = g_gc_card_table;
21882185
args.lowest_address = g_gc_lowest_address;
21892186
args.highest_address = g_gc_highest_address;
2187+
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
2188+
if (SoftwareWriteWatch::IsEnabledForGCHeap())
2189+
{
2190+
args.write_watch_table = g_gc_sw_ww_table;
2191+
}
2192+
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
21902193
GCToEEInterface::StompWriteBarrier(&args);
21912194
}
21922195

2193-
void stomp_write_barrier_ephemeral(bool is_runtime_suspended, uint8_t* ephemeral_lo, uint8_t* ephemeral_hi)
2196+
void stomp_write_barrier_ephemeral(bool is_runtime_suspended, uint8_t* ephemeral_low, uint8_t* ephemeral_high)
21942197
{
21952198
WriteBarrierParameters args = {};
21962199
args.operation = WriteBarrierOp::StompEphemeral;
21972200
args.is_runtime_suspended = is_runtime_suspended;
2198-
args.ephemeral_lo = g_gc_ephemeral_low;
2199-
args.ephemeral_hi = g_gc_ephemeral_high;
2201+
args.ephemeral_low = ephemeral_low;
2202+
args.ephemeral_high = ephemeral_high;
22002203
#ifdef MULTIPLE_HEAPS
22012204
// It is not correct to update the EE's g_ephemeral_low and g_ephemeral_high
22022205
// to anything other than their default values when using Server GC, since
22032206
// there is no single ephemeral generation across all of the heaps.
22042207
// Server GC write barriers do not reference these two globals, but ErectWriteBarrier does.
22052208
//
2206-
// When MULTIPLE_HEAPS is defined, g_gc_ephemeral_low and g_gc_ephemeral_high should
2209+
// When MULTIPLE_HEAPS is defined, the EE's g_ephemeral_low and g_ephemeral_high should
22072210
// always have their default values.
2208-
assert(args.ephemeral_lo == (uint8_t*)1);
2209-
assert(args.ephemeral_hi == (uint8_t*)~0);
2211+
args.ephemeral_low = (uint8_t*)1;
2212+
args.ephemeral_high = (uint8_t*)~0;
22102213
#endif // MULTIPLE_HEAPS
22112214
GCToEEInterface::StompWriteBarrier(&args);
22122215
}
@@ -2430,6 +2433,10 @@ BOOL gc_heap::ro_segments_in_range;
24302433

24312434
size_t gc_heap::gen0_big_free_spaces = 0;
24322435

2436+
uint8_t* gc_heap::ephemeral_low;
2437+
2438+
uint8_t* gc_heap::ephemeral_high;
2439+
24332440
uint8_t* gc_heap::lowest_address;
24342441

24352442
uint8_t* gc_heap::highest_address;
@@ -7277,9 +7284,6 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
72777284
}
72787285

72797286
g_gc_card_table = translated_ct;
7280-
g_gc_lowest_address = saved_g_lowest_address;
7281-
g_gc_highest_address = saved_g_highest_address;
7282-
72837287
SoftwareWriteWatch::SetResizedUntranslatedTable(
72847288
mem + sw_ww_table_offset,
72857289
saved_g_lowest_address,
@@ -7290,6 +7294,8 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
72907294
// grow version of the write barrier. This test tells us if the new
72917295
// segment was allocated at a lower address than the old, requiring
72927296
// that we start doing an upper bounds check in the write barrier.
7297+
g_gc_lowest_address = saved_g_lowest_address;
7298+
g_gc_highest_address = saved_g_highest_address;
72937299
stomp_write_barrier_resize(true, la != saved_g_lowest_address);
72947300
write_barrier_updated = true;
72957301

@@ -32778,8 +32784,8 @@ gc_heap::verify_heap (BOOL begin_gc_p)
3277832784
#endif //BACKGROUND_GC
3277932785

3278032786
#ifndef MULTIPLE_HEAPS
32781-
if ((g_gc_ephemeral_low != generation_allocation_start (generation_of (max_generation - 1))) ||
32782-
(g_gc_ephemeral_high != heap_segment_reserved (ephemeral_heap_segment)))
32787+
if ((ephemeral_low != generation_allocation_start (generation_of (max_generation - 1))) ||
32788+
(ephemeral_high != heap_segment_reserved (ephemeral_heap_segment)))
3278332789
{
3278432790
FATAL_GC_ERROR();
3278532791
}
@@ -35739,7 +35745,13 @@ GCHeap::SetCardsAfterBulkCopy( Object **StartPoint, size_t len )
3573935745
end = StartPoint + (len/sizeof(Object*));
3574035746
while (rover < end)
3574135747
{
35742-
if ( (((uint8_t*)*rover) >= g_gc_ephemeral_low) && (((uint8_t*)*rover) < g_gc_ephemeral_high) )
35748+
// For Workstation GC, where there is exactly one ephemeral region, we can avoid touching the
35749+
// card table if the rover is currently pointing into a region outside of the ephemeral generation.
35750+
//
35751+
// For Server GC, where there are multiple ephemeral regions, we must always touch the card table.
35752+
#ifndef MULTIPLE_HEAPS
35753+
if ( (((uint8_t*)*rover) >= gc_heap::ephemeral_low) && (((uint8_t*)*rover) < gc_heap::ephemeral_high) )
35754+
#endif // MULTIPLE_HEAPS
3574335755
{
3574435756
// Set Bit For Card and advance to next card
3574535757
size_t card = gcard_of ((uint8_t*)rover);
@@ -35748,10 +35760,12 @@ GCHeap::SetCardsAfterBulkCopy( Object **StartPoint, size_t len )
3574835760
// Skip to next card for the object
3574935761
rover = (Object**)align_on_card ((uint8_t*)(rover+1));
3575035762
}
35763+
#ifndef MULTIPLE_HEAPS
3575135764
else
3575235765
{
3575335766
rover++;
3575435767
}
35768+
#endif // MULTIPLE_HEAPS
3575535769
}
3575635770
}
3575735771

src/gc/gc.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ class DacHeapWalker;
140140
extern "C" uint32_t* g_gc_card_table;
141141
extern "C" uint8_t* g_gc_lowest_address;
142142
extern "C" uint8_t* g_gc_highest_address;
143-
extern "C" uint8_t* g_gc_ephemeral_low;
144-
extern "C" uint8_t* g_gc_ephemeral_high;
145143

146144
namespace WKS {
147145
::IGCHeapInternal* CreateGCHeap();

src/gc/gccommon.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ uint8_t* g_shadow_lowest_address = NULL;
4141
uint32_t* g_gc_card_table;
4242
uint8_t* g_gc_lowest_address = 0;
4343
uint8_t* g_gc_highest_address = 0;
44-
uint8_t* g_gc_ephemeral_low = (uint8_t*)1;
45-
uint8_t* g_gc_ephemeral_high = (uint8_t*)~0;
4644

4745
VOLATILE(int32_t) m_GCLock = -1;
4846

src/gc/gcinterface.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ enum class WriteBarrierOp
4646
{
4747
StompResize,
4848
StompEphemeral,
49-
Initialize
49+
Initialize,
50+
SwitchToWriteWatch,
51+
SwitchToNonWriteWatch
5052
};
5153

5254
// Arguments to GCToEEInterface::StompWriteBarrier
@@ -85,11 +87,15 @@ struct WriteBarrierParameters
8587

8688
// The new start of the ephemeral generation.
8789
// Used for WriteBarrierOp::StompEphemeral.
88-
uint8_t* ephemeral_lo;
90+
uint8_t* ephemeral_low;
8991

9092
// The new end of the ephemeral generation.
9193
// Used for WriteBarrierOp::StompEphemeral.
92-
uint8_t* ephemeral_hi;
94+
uint8_t* ephemeral_high;
95+
96+
// The new write watch table, if we are using our own write watch
97+
// implementation. Used for WriteBarrierOp::SwitchToWriteWatch only.
98+
uint8_t* write_watch_table;
9399
};
94100

95101
#include "gcinterface.ee.h"
@@ -148,6 +154,10 @@ struct segment_info
148154

149155
#define max_generation 2
150156

157+
// The bit shift used to convert a memory address into an index into the
158+
// Software Write Watch table.
159+
#define SOFTWARE_WRITE_WATCH_AddressToTableByteIndexShift 0xc
160+
151161
class Object;
152162
class IGCHeap;
153163

src/gc/gcpriv.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,13 +2802,11 @@ class gc_heap
28022802
PER_HEAP
28032803
void exit_gc_done_event_lock();
28042804

2805-
#ifdef MULTIPLE_HEAPS
28062805
PER_HEAP
28072806
uint8_t* ephemeral_low; //lowest ephemeral address
28082807

28092808
PER_HEAP
28102809
uint8_t* ephemeral_high; //highest ephemeral address
2811-
#endif //MULTIPLE_HEAPS
28122810

28132811
PER_HEAP
28142812
uint32_t* card_table;

src/gc/gcsvr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "gc.h"
1414
#include "gcscan.h"
1515
#include "gcdesc.h"
16+
#include "softwarewritewatch.h"
1617

1718
#define SERVER_GC 1
1819

src/gc/gcwks.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "gc.h"
1212
#include "gcscan.h"
1313
#include "gcdesc.h"
14+
#include "softwarewritewatch.h"
1415

1516
#ifdef SERVER_GC
1617
#undef SERVER_GC

src/gc/sample/GCSample.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,11 @@ inline void ErectWriteBarrier(Object ** dst, Object * ref)
9494
if (((uint8_t*)dst < g_gc_lowest_address) || ((uint8_t*)dst >= g_gc_highest_address))
9595
return;
9696

97-
if((uint8_t*)ref >= g_gc_ephemeral_low && (uint8_t*)ref < g_gc_ephemeral_high)
98-
{
99-
// volatile is used here to prevent fetch of g_card_table from being reordered
100-
// with g_lowest/highest_address check above. See comment in code:gc_heap::grow_brick_card_tables.
101-
uint8_t* pCardByte = (uint8_t *)*(volatile uint8_t **)(&g_gc_card_table) + card_byte((uint8_t *)dst);
102-
if(*pCardByte != 0xFF)
103-
*pCardByte = 0xFF;
104-
}
97+
// volatile is used here to prevent fetch of g_card_table from being reordered
98+
// with g_lowest/highest_address check above. See comment in code:gc_heap::grow_brick_card_tables.
99+
uint8_t* pCardByte = (uint8_t *)*(volatile uint8_t **)(&g_gc_card_table) + card_byte((uint8_t *)dst);
100+
if(*pCardByte != 0xFF)
101+
*pCardByte = 0xFF;
105102
}
106103

107104
void WriteBarrier(Object ** dst, Object * ref)

src/gc/softwarewritewatch.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
// See the LICENSE file in the project root for more information.
44

55
#include "common.h"
6-
#include "softwarewritewatch.h"
7-
86
#include "gcenv.h"
97
#include "env/gcenv.os.h"
8+
#include "softwarewritewatch.h"
109

1110
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
1211
#ifndef DACCESS_COMPILE
@@ -15,8 +14,8 @@ static_assert((static_cast<size_t>(1) << SOFTWARE_WRITE_WATCH_AddressToTableByte
1514

1615
extern "C"
1716
{
18-
uint8_t *g_sw_ww_table = nullptr;
19-
bool g_sw_ww_enabled_for_gc_heap = false;
17+
uint8_t *g_gc_sw_ww_table = nullptr;
18+
bool g_gc_sw_ww_enabled_for_gc_heap = false;
2019
}
2120

2221
void SoftwareWriteWatch::StaticClose()
@@ -26,8 +25,8 @@ void SoftwareWriteWatch::StaticClose()
2625
return;
2726
}
2827

29-
g_sw_ww_enabled_for_gc_heap = false;
30-
g_sw_ww_table = nullptr;
28+
g_gc_sw_ww_enabled_for_gc_heap = false;
29+
g_gc_sw_ww_table = nullptr;
3130
}
3231

3332
bool SoftwareWriteWatch::GetDirtyFromBlock(

src/gc/softwarewritewatch.h

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,20 @@
55
#ifndef __SOFTWARE_WRITE_WATCH_H__
66
#define __SOFTWARE_WRITE_WATCH_H__
77

8+
#include "gcinterface.h"
9+
#include "gc.h"
10+
811
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
912
#ifndef DACCESS_COMPILE
1013

11-
extern void SwitchToWriteWatchBarrier(bool isRuntimeSuspended);
12-
extern void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended);
13-
14-
#define SOFTWARE_WRITE_WATCH_AddressToTableByteIndexShift 0xc
15-
1614
extern "C"
1715
{
1816
// Table containing the dirty state. This table is translated to exclude the lowest address it represents, see
1917
// TranslateTableToExcludeHeapStartAddress.
20-
extern uint8_t *g_sw_ww_table;
18+
extern uint8_t *g_gc_sw_ww_table;
2119

2220
// Write watch may be disabled when it is not needed (between GCs for instance). This indicates whether it is enabled.
23-
extern bool g_sw_ww_enabled_for_gc_heap;
24-
25-
extern uint8_t *g_lowest_address; // start address of the GC heap
26-
extern uint8_t *g_highest_address; // end address of the GC heap
21+
extern bool g_gc_sw_ww_enabled_for_gc_heap;
2722
}
2823

2924
class SoftwareWriteWatch
@@ -116,7 +111,7 @@ inline void SoftwareWriteWatch::VerifyMemoryRegion(
116111

117112
inline uint8_t *SoftwareWriteWatch::GetTable()
118113
{
119-
return g_sw_ww_table;
114+
return g_gc_sw_ww_table;
120115
}
121116

122117
inline uint8_t *SoftwareWriteWatch::GetUntranslatedTable()
@@ -163,7 +158,7 @@ inline void SoftwareWriteWatch::SetUntranslatedTable(uint8_t *untranslatedTable,
163158
assert(ALIGN_DOWN(untranslatedTable, sizeof(size_t)) == untranslatedTable);
164159
assert(heapStartAddress != nullptr);
165160

166-
g_sw_ww_table = TranslateTableToExcludeHeapStartAddress(untranslatedTable, heapStartAddress);
161+
g_gc_sw_ww_table = TranslateTableToExcludeHeapStartAddress(untranslatedTable, heapStartAddress);
167162
}
168163

169164
inline void SoftwareWriteWatch::SetResizedUntranslatedTable(
@@ -194,7 +189,7 @@ inline void SoftwareWriteWatch::SetResizedUntranslatedTable(
194189

195190
inline bool SoftwareWriteWatch::IsEnabledForGCHeap()
196191
{
197-
return g_sw_ww_enabled_for_gc_heap;
192+
return g_gc_sw_ww_enabled_for_gc_heap;
198193
}
199194

200195
inline void SoftwareWriteWatch::EnableForGCHeap()
@@ -204,9 +199,13 @@ inline void SoftwareWriteWatch::EnableForGCHeap()
204199

205200
VerifyCreated();
206201
assert(!IsEnabledForGCHeap());
202+
g_gc_sw_ww_enabled_for_gc_heap = true;
207203

208-
g_sw_ww_enabled_for_gc_heap = true;
209-
SwitchToWriteWatchBarrier(true);
204+
WriteBarrierParameters args = {};
205+
args.operation = WriteBarrierOp::SwitchToWriteWatch;
206+
args.write_watch_table = g_gc_sw_ww_table;
207+
args.is_runtime_suspended = true;
208+
GCToEEInterface::StompWriteBarrier(&args);
210209
}
211210

212211
inline void SoftwareWriteWatch::DisableForGCHeap()
@@ -216,19 +215,22 @@ inline void SoftwareWriteWatch::DisableForGCHeap()
216215

217216
VerifyCreated();
218217
assert(IsEnabledForGCHeap());
218+
g_gc_sw_ww_enabled_for_gc_heap = false;
219219

220-
g_sw_ww_enabled_for_gc_heap = false;
221-
SwitchToNonWriteWatchBarrier(true);
220+
WriteBarrierParameters args = {};
221+
args.operation = WriteBarrierOp::SwitchToNonWriteWatch;
222+
args.is_runtime_suspended = true;
223+
GCToEEInterface::StompWriteBarrier(&args);
222224
}
223225

224226
inline void *SoftwareWriteWatch::GetHeapStartAddress()
225227
{
226-
return g_lowest_address;
228+
return g_gc_lowest_address;
227229
}
228230

229231
inline void *SoftwareWriteWatch::GetHeapEndAddress()
230232
{
231-
return g_highest_address;
233+
return g_gc_highest_address;
232234
}
233235

234236
inline size_t SoftwareWriteWatch::GetTableByteIndex(void *address)

0 commit comments

Comments
 (0)