Skip to content

Commit 949eb44

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm, gc] Add write-write fence after initializing object headers, or defer marking new-space objects in an active TLAB.
On architectures with a weak memory model, there is the possibility that the concurrent marker can see the publishing store of a new object before it sees the initializing store of that object's header. On an M1, the barrier to prevent reordering these stores is fairly cheap, so we emit this barrier on Mac/iOS ARM64. Otherwise, this barrier is very expensive (or at least expensive for some hardware within the ABI), so instead we avoid the race by deferring marking of objects inside an active TLAB. Disable TSAN instrumentation on the marker setting the mark bit, as TSAN does not understand fences. TEST=ooo arm64 machines Bug: #56845 Change-Id: I0676661a7cf941fdc6b451e516d890c26826bb3b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/389265 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Siva Annamalai <[email protected]>
1 parent 1e69ae8 commit 949eb44

31 files changed

+171
-65
lines changed

runtime/vm/bitfield.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ class AtomicBitFieldContainer {
113113
return TargetBitField::decode(old_field);
114114
}
115115

116+
template <class TargetBitField>
117+
NO_SANITIZE_THREAD bool TryClearIgnoreRace() {
118+
T mask = ~TargetBitField::encode(true);
119+
T old_field = field_.fetch_and(mask, std::memory_order_relaxed);
120+
return TargetBitField::decode(old_field);
121+
}
122+
116123
private:
117124
std::atomic<T> field_;
118125
};

runtime/vm/compiler/asm_intrinsifier_arm.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ static void TryAllocateString(Assembler* assembler,
15581558
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
15591559
__ LoadImmediate(TMP, tags);
15601560
__ orr(R3, R3, Operand(TMP));
1561-
__ str(R3, FieldAddress(R0, target::Object::tags_offset())); // Store tags.
1561+
__ InitializeHeader(R3, R0);
15621562
}
15631563

15641564
// Set the length field using the saved length (R8).

runtime/vm/compiler/asm_intrinsifier_arm64.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1778,7 +1778,7 @@ static void TryAllocateString(Assembler* assembler,
17781778
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
17791779
__ LoadImmediate(TMP, tags);
17801780
__ orr(R2, R2, Operand(TMP));
1781-
__ str(R2, FieldAddress(R0, target::Object::tags_offset())); // Store tags.
1781+
__ InitializeHeader(R2, R0);
17821782
}
17831783

17841784
#if DART_COMPRESSED_POINTERS

runtime/vm/compiler/asm_intrinsifier_ia32.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1602,7 +1602,7 @@ static void TryAllocateString(Assembler* assembler,
16021602
const uword tags =
16031603
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
16041604
__ orl(EDI, Immediate(tags));
1605-
__ movl(FieldAddress(EAX, target::Object::tags_offset()), EDI); // Tags.
1605+
__ InitializeHeader(EDI, EAX);
16061606
}
16071607

16081608
// Set the length field.

runtime/vm/compiler/asm_intrinsifier_riscv.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ static void TryAllocateString(Assembler* assembler,
18161816
const uword tags =
18171817
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
18181818
__ OrImmediate(A1, A1, tags);
1819-
__ sx(A1, FieldAddress(A0, target::Object::tags_offset())); // Store tags.
1819+
__ InitializeHeader(A1, A0);
18201820
}
18211821

18221822
// Set the length field using the saved length (T0).

runtime/vm/compiler/asm_intrinsifier_x64.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,7 @@ static void TryAllocateString(Assembler* assembler,
16771677
const uword tags =
16781678
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
16791679
__ orq(RDI, Immediate(tags));
1680-
__ movq(FieldAddress(RAX, target::Object::tags_offset()), RDI); // Tags.
1680+
__ InitializeHeader(RDI, RAX);
16811681
}
16821682

16831683
// Set the length field.

runtime/vm/compiler/assembler/assembler_arm.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3628,7 +3628,7 @@ void Assembler::TryAllocateObject(intptr_t cid,
36283628

36293629
const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size);
36303630
LoadImmediate(temp_reg, tags);
3631-
str(temp_reg, FieldAddress(instance_reg, target::Object::tags_offset()));
3631+
InitializeHeader(temp_reg, instance_reg);
36323632
} else {
36333633
b(failure);
36343634
}
@@ -3671,8 +3671,7 @@ void Assembler::TryAllocateArray(intptr_t cid,
36713671
// instance: new object start as a tagged pointer.
36723672
const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size);
36733673
LoadImmediate(temp2, tags);
3674-
str(temp2,
3675-
FieldAddress(instance, target::Object::tags_offset())); // Store tags.
3674+
InitializeHeader(temp2, instance);
36763675
} else {
36773676
b(failure);
36783677
}

runtime/vm/compiler/assembler/assembler_arm.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,19 @@ class Assembler : public AssemblerBase {
10341034
}
10351035
void CompareObject(Register rn, const Object& object);
10361036

1037+
void InitializeHeader(Register tags, Register object) {
1038+
str(tags, FieldAddress(object, target::Object::tags_offset()));
1039+
#if defined(TARGET_HAS_FAST_WRITE_WRITE_FENCE)
1040+
dmb();
1041+
#endif
1042+
}
1043+
void InitializeHeaderUntagged(Register tags, Register object) {
1044+
str(tags, Address(object, target::Object::tags_offset()));
1045+
#if defined(TARGET_HAS_FAST_WRITE_WRITE_FENCE)
1046+
dmb();
1047+
#endif
1048+
}
1049+
10371050
void StoreObjectIntoObjectNoBarrier(
10381051
Register object,
10391052
const Address& dest,

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,7 @@ void Assembler::TryAllocateObject(intptr_t cid,
19691969

19701970
const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size);
19711971
LoadImmediate(temp_reg, tags);
1972-
Store(temp_reg, FieldAddress(instance_reg, target::Object::tags_offset()));
1972+
InitializeHeader(temp_reg, instance_reg);
19731973
} else {
19741974
b(failure);
19751975
}
@@ -2011,7 +2011,7 @@ void Assembler::TryAllocateArray(intptr_t cid,
20112011
// instance: new object start as a tagged pointer.
20122012
const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size);
20132013
LoadImmediate(temp2, tags);
2014-
str(temp2, FieldAddress(instance, target::Object::tags_offset()));
2014+
InitializeHeader(temp2, instance);
20152015
} else {
20162016
b(failure);
20172017
}

runtime/vm/compiler/assembler/assembler_arm64.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,8 @@ class Assembler : public AssemblerBase {
12321232
// Breakpoint.
12331233
void brk(uint16_t imm) { EmitExceptionGenOp(BRK, imm); }
12341234

1235+
void dmb() { Emit(kDataMemoryBarrier); }
1236+
12351237
// Double floating point.
12361238
bool fmovdi(VRegister vd, double immd) {
12371239
int64_t imm64 = bit_cast<int64_t, double>(immd);
@@ -1948,6 +1950,19 @@ class Assembler : public AssemblerBase {
19481950
void LoadCompressed(Register dest, const Address& slot) override;
19491951
#endif
19501952

1953+
void InitializeHeader(Register header, Register object) {
1954+
str(header, FieldAddress(object, target::Object::tags_offset()));
1955+
#if defined(TARGET_HAS_FAST_WRITE_WRITE_FENCE)
1956+
dmb();
1957+
#endif
1958+
}
1959+
void InitializeHeaderUntagged(Register header, Register object) {
1960+
str(header, Address(object, target::Object::tags_offset()));
1961+
#if defined(TARGET_HAS_FAST_WRITE_WRITE_FENCE)
1962+
dmb();
1963+
#endif
1964+
}
1965+
19511966
void StoreBarrier(Register object,
19521967
Register value,
19531968
CanBeSmi can_value_be_smi,

0 commit comments

Comments
 (0)