Skip to content

Commit da8f177

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm, gc] Allocate card tables up front.
This avoids data races when multiple mutators compete to install the card table, and allows removing the initialization check from the write barrier. TEST=ci, tsan Bug: #56895 Change-Id: I30fe4687d3ca771f6c00dfa59e8dadec23d557a3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/390023 Reviewed-by: Siva Annamalai <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 40c039a commit da8f177

12 files changed

+1054
-1143
lines changed

runtime/vm/app_snapshot.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,7 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster {
14141414
if ((SetType::Storage::ArrayCid == kArrayCid) &&
14151415
Array::UseCardMarkingForAllocation(length)) {
14161416
table->untag()->SetCardRememberedBitUnsynchronized();
1417+
Page::Of(table)->AllocateCardTable();
14171418
}
14181419
InitTypeArgsOrNext(table);
14191420
table->untag()->length_ = Smi::New(length);
@@ -6508,6 +6509,7 @@ class ArrayDeserializationCluster
65086509
stamp_canonical);
65096510
if (Array::UseCardMarkingForAllocation(length)) {
65106511
array->untag()->SetCardRememberedBitUnsynchronized();
6512+
Page::Of(array)->AllocateCardTable();
65116513
}
65126514
array->untag()->type_arguments_ =
65136515
static_cast<TypeArgumentsPtr>(d.ReadRef());

runtime/vm/compiler/runtime_offsets_extracted.h

Lines changed: 1034 additions & 1034 deletions
Large diffs are not rendered by default.

runtime/vm/compiler/stub_code_compiler_arm.cc

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,15 +1859,13 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
18591859
__ Ret();
18601860
}
18611861
if (cards) {
1862-
Label remember_card_slow, retry;
1862+
Label retry;
18631863

18641864
// Get card table.
18651865
__ Bind(&remember_card);
18661866
__ AndImmediate(TMP, R1, target::kPageMask); // Page.
18671867
__ ldr(TMP,
18681868
Address(TMP, target::Page::card_table_offset())); // Card table.
1869-
__ cmp(TMP, Operand(0));
1870-
__ b(&remember_card_slow, EQ);
18711869

18721870
// Atomically dirty the card.
18731871
__ PushList((1 << R0) | (1 << R1) | (1 << R2));
@@ -1890,17 +1888,6 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
18901888
__ b(&retry, EQ);
18911889
__ PopList((1 << R0) | (1 << R1) | (1 << R2));
18921890
__ Ret();
1893-
1894-
// Card table not yet allocated.
1895-
__ Bind(&remember_card_slow);
1896-
{
1897-
LeafRuntimeScope rt(assembler, /*frame_size=*/0,
1898-
/*preserve_registers=*/true);
1899-
__ mov(R0, Operand(R1)); // Arg0 = Object
1900-
__ mov(R1, Operand(R9)); // Arg1 = Slot
1901-
rt.Call(kRememberCardRuntimeEntry, 2);
1902-
}
1903-
__ Ret();
19041891
}
19051892
}
19061893

runtime/vm/compiler/stub_code_compiler_arm64.cc

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2242,14 +2242,13 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
22422242
__ ret();
22432243
}
22442244
if (cards) {
2245-
Label remember_card_slow, retry;
2245+
Label retry;
22462246

22472247
// Get card table.
22482248
__ Bind(&remember_card);
22492249
__ AndImmediate(TMP, R1, target::kPageMask); // Page.
22502250
__ ldr(TMP2,
22512251
Address(TMP, target::Page::card_table_offset())); // Card table.
2252-
__ cbz(&remember_card_slow, TMP2);
22532252

22542253
// Atomically dirty the card.
22552254
__ sub(R25, R25, Operand(TMP)); // Offset in page.
@@ -2271,18 +2270,6 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
22712270
__ PopRegister(R0);
22722271
}
22732272
__ ret();
2274-
2275-
// Card table not yet allocated.
2276-
__ Bind(&remember_card_slow);
2277-
{
2278-
LeafRuntimeScope rt(assembler,
2279-
/*frame_size=*/0,
2280-
/*preserve_registers=*/true);
2281-
__ mov(R0, R1); // Arg0 = Object
2282-
__ mov(R1, R25); // Arg1 = Slot
2283-
rt.Call(kRememberCardRuntimeEntry, /*argument_count=*/2);
2284-
}
2285-
__ ret();
22862273
}
22872274
}
22882275

runtime/vm/compiler/stub_code_compiler_ia32.cc

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,14 +1675,10 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
16751675
__ ret();
16761676
}
16771677
if (cards) {
1678-
Label remember_card_slow;
1679-
16801678
// Get card table.
16811679
__ Bind(&remember_card);
16821680
__ movl(EAX, EDX); // Object.
16831681
__ andl(EAX, Immediate(target::kPageMask)); // Page.
1684-
__ cmpl(Address(EAX, target::Page::card_table_offset()), Immediate(0));
1685-
__ j(EQUAL, &remember_card_slow, Assembler::kNearJump);
16861682

16871683
// Atomically dirty the card.
16881684
__ pushl(EBX);
@@ -1702,21 +1698,6 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
17021698
__ popl(ECX);
17031699
__ popl(EAX);
17041700
__ ret();
1705-
1706-
// Card table not yet allocated.
1707-
__ Bind(&remember_card_slow);
1708-
1709-
{
1710-
LeafRuntimeScope rt(assembler,
1711-
/*frame_size=*/2 * target::kWordSize,
1712-
/*preserve_registers=*/true);
1713-
__ movl(Address(ESP, 0 * target::kWordSize), EDX); // Object
1714-
__ movl(Address(ESP, 1 * target::kWordSize), EDI); // Slot
1715-
rt.Call(kRememberCardRuntimeEntry, 2);
1716-
}
1717-
__ popl(ECX);
1718-
__ popl(EAX);
1719-
__ ret();
17201701
}
17211702
}
17221703

runtime/vm/compiler/stub_code_compiler_riscv.cc

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,14 +1841,11 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
18411841
__ ret();
18421842
}
18431843
if (cards) {
1844-
Label remember_card_slow;
1845-
18461844
// Get card table.
18471845
__ Bind(&remember_card);
18481846
__ AndImmediate(TMP, A0, target::kPageMask); // Page.
18491847
__ lx(TMP2,
18501848
Address(TMP, target::Page::card_table_offset())); // Card table.
1851-
__ beqz(TMP2, &remember_card_slow);
18521849

18531850
// Atomically dirty the card.
18541851
__ sub(A6, A6, TMP); // Offset in page.
@@ -1864,17 +1861,6 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
18641861
__ amoord(ZR, TMP, Address(TMP2, 0));
18651862
#endif
18661863
__ ret();
1867-
1868-
// Card table not yet allocated.
1869-
__ Bind(&remember_card_slow);
1870-
{
1871-
LeafRuntimeScope rt(assembler, /*frame_size=*/0,
1872-
/*preserve_registers=*/true);
1873-
__ mv(A0, A0); // Arg0 = Object
1874-
__ mv(A1, A6); // Arg1 = Slot
1875-
rt.Call(kRememberCardRuntimeEntry, /*argument_count=*/2);
1876-
}
1877-
__ ret();
18781864
}
18791865
}
18801866

runtime/vm/compiler/stub_code_compiler_x64.cc

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,14 +2158,10 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
21582158
}
21592159

21602160
if (cards) {
2161-
Label remember_card_slow;
2162-
21632161
// Get card table.
21642162
__ Bind(&remember_card);
21652163
__ movq(TMP, RDX); // Object.
21662164
__ andq(TMP, Immediate(target::kPageMask)); // Page.
2167-
__ cmpq(Address(TMP, target::Page::card_table_offset()), Immediate(0));
2168-
__ j(EQUAL, &remember_card_slow, Assembler::kNearJump);
21692165

21702166
// Atomically dirty the card.
21712167
__ pushq(RAX);
@@ -2183,18 +2179,6 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler, bool cards) {
21832179
__ popq(RCX);
21842180
__ popq(RAX);
21852181
__ ret();
2186-
2187-
// Card table not yet allocated.
2188-
__ Bind(&remember_card_slow);
2189-
{
2190-
LeafRuntimeScope rt(assembler,
2191-
/*frame_size=*/0,
2192-
/*preserve_registers=*/true);
2193-
__ movq(CallingConventions::kArg1Reg, RDX);
2194-
__ movq(CallingConventions::kArg2Reg, R13);
2195-
rt.Call(kRememberCardRuntimeEntry, 2);
2196-
}
2197-
__ ret();
21982182
}
21992183
}
22002184

runtime/vm/heap/page.h

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -271,32 +271,27 @@ class Page {
271271
bool IsSurvivor(uword raw_addr) const { return raw_addr < survivor_end_; }
272272
bool IsResolved() const { return top_ == resolved_top_; }
273273

274+
void AllocateCardTable() {
275+
ASSERT(card_table_ == nullptr);
276+
ASSERT(is_large());
277+
size_t size_in_bits = card_table_size();
278+
size_t size_in_bytes =
279+
Utils::RoundUp(size_in_bits, kBitsPerWord) >> kBitsPerByteLog2;
280+
card_table_ = reinterpret_cast<RelaxedAtomic<uword>*>(
281+
calloc(size_in_bytes, sizeof(uint8_t)));
282+
}
283+
274284
private:
275285
void RememberCard(uword slot) {
276286
ASSERT(Contains(slot));
277-
uword* card_table = card_table_.load();
278-
if (card_table == nullptr) {
279-
size_t size_in_bits = card_table_size();
280-
size_t size_in_bytes =
281-
Utils::RoundUp(size_in_bits, kBitsPerWord) >> kBitsPerByteLog2;
282-
uword* new_card_table =
283-
reinterpret_cast<uword*>(calloc(size_in_bytes, sizeof(uint8_t)));
284-
if (card_table_.compare_exchange_strong(card_table, new_card_table)) {
285-
card_table = new_card_table;
286-
} else {
287-
// Lost race.
288-
ASSERT(card_table != nullptr);
289-
free(new_card_table);
290-
}
291-
}
287+
ASSERT(card_table_ != nullptr);
292288
intptr_t offset = slot - reinterpret_cast<uword>(this);
293289
intptr_t index = offset >> kBytesPerCardLog2;
294290
ASSERT((index >= 0) && (index < card_table_size()));
295291
intptr_t word_offset = index >> kBitsPerWordLog2;
296292
intptr_t bit_offset = index & (kBitsPerWord - 1);
297293
uword bit_mask = static_cast<uword>(1) << bit_offset;
298-
reinterpret_cast<std::atomic<uword>*>(&card_table[word_offset])
299-
->fetch_or(bit_mask, std::memory_order_relaxed);
294+
card_table_[word_offset].fetch_or(bit_mask);
300295
}
301296
bool IsCardRemembered(uword slot) {
302297
ASSERT(Contains(slot));
@@ -309,7 +304,7 @@ class Page {
309304
intptr_t word_offset = index >> kBitsPerWordLog2;
310305
intptr_t bit_offset = index & (kBitsPerWord - 1);
311306
uword bit_mask = static_cast<uword>(1) << bit_offset;
312-
return (card_table_[word_offset] & bit_mask) != 0;
307+
return (card_table_[word_offset].load() & bit_mask) != 0;
313308
}
314309

315310
void set_object_end(uword value) {
@@ -328,7 +323,7 @@ class Page {
328323
VirtualMemory* memory_;
329324
Page* next_;
330325
ForwardingPage* forwarding_page_;
331-
RelaxedAtomic<uword*> card_table_; // Remembered set, not marking.
326+
RelaxedAtomic<uword>* card_table_; // Remembered set, not marking.
332327
RelaxedAtomic<intptr_t> progress_bar_;
333328

334329
// The thread using this page for allocation, otherwise nullptr.

runtime/vm/object.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25248,6 +25248,7 @@ ArrayPtr Array::NewUninitialized(intptr_t class_id,
2524825248
if (UseCardMarkingForAllocation(len)) {
2524925249
ASSERT(raw->IsOldObject());
2525025250
raw->untag()->SetCardRememberedBitUnsynchronized();
25251+
Page::Of(raw)->AllocateCardTable();
2525125252
}
2525225253
return raw;
2525325254
}

runtime/vm/object_graph_copy.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,7 @@ class SlowObjectCopyBase : public ObjectCopyBase {
16071607
if ((cid == kArrayCid || cid == kImmutableArrayCid) &&
16081608
!IsAllocatableInNewSpace(size)) {
16091609
to.untag()->SetCardRememberedBitUnsynchronized();
1610+
Page::Of(to)->AllocateCardTable();
16101611
}
16111612
if (IsExternalTypedDataClassId(cid)) {
16121613
const auto& external_to = slow_forward_map_.AddExternalTypedData(

0 commit comments

Comments
 (0)