Skip to content

Commit 9e39986

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] Don't stop mutators when inserting into a megamorphic cache.
TEST=rr --chaos Change-Id: I4501d10b09691907e88f92aacbd3e4071d05e107 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/440065 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 77b90f5 commit 9e39986

File tree

8 files changed

+8090
-49
lines changed

8 files changed

+8090
-49
lines changed

runtime/tests/vm/dart/isolates/concurrent_megamorphic_call_test.dart

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

runtime/vm/compiler/stub_code_compiler_arm.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3288,12 +3288,12 @@ void StubCodeCompiler::GenerateOptimizedIdenticalWithNumberCheckStub() {
32883288
void StubCodeCompiler::GenerateMegamorphicCallStub() {
32893289
__ LoadTaggedClassIdMayBeSmi(R8, R0);
32903290
// R8: receiver cid as Smi.
3291-
__ ldr(R2,
3292-
FieldAddress(IC_DATA_REG, target::MegamorphicCache::buckets_offset()));
32933291
__ ldr(R1,
32943292
FieldAddress(IC_DATA_REG, target::MegamorphicCache::mask_offset()));
3293+
__ ldr(R2,
3294+
FieldAddress(IC_DATA_REG, target::MegamorphicCache::buckets_offset()));
3295+
// R1: mask as a smi - load first to support insertion w/o stopping Dart code.
32953296
// R2: cache buckets array.
3296-
// R1: mask as a smi.
32973297

32983298
// Compute the table index.
32993299
ASSERT(target::MegamorphicCache::kSpreadFactor == 7);

runtime/vm/compiler/stub_code_compiler_arm64.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3683,12 +3683,12 @@ void StubCodeCompiler::GenerateMegamorphicCallStub() {
36833683

36843684
Label cid_loaded;
36853685
__ Bind(&cid_loaded);
3686-
__ ldr(R2,
3687-
FieldAddress(IC_DATA_REG, target::MegamorphicCache::buckets_offset()));
36883686
__ ldr(R1,
36893687
FieldAddress(IC_DATA_REG, target::MegamorphicCache::mask_offset()));
3688+
__ ldr(R2,
3689+
FieldAddress(IC_DATA_REG, target::MegamorphicCache::buckets_offset()));
3690+
// R1: mask as a smi - load first to support insertion w/o stopping Dart code.
36903691
// R2: cache buckets array.
3691-
// R1: mask as a smi.
36923692

36933693
// Make the cid into a smi.
36943694
__ SmiTag(R8);

runtime/vm/compiler/stub_code_compiler_ia32.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3177,8 +3177,8 @@ void StubCodeCompiler::GenerateMegamorphicCallStub() {
31773177
FieldAddress(IC_DATA_REG, target::MegamorphicCache::mask_offset()));
31783178
__ movl(EDI, FieldAddress(IC_DATA_REG,
31793179
target::MegamorphicCache::buckets_offset()));
3180+
// EBX: mask as a smi - load first to support insert w/o stopping Dart code.
31803181
// EDI: cache buckets array.
3181-
// EBX: mask as a smi.
31823182

31833183
// Tag cid as a smi.
31843184
__ addl(EAX, EAX);

runtime/vm/compiler/stub_code_compiler_riscv.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3194,11 +3194,11 @@ void StubCodeCompiler::GenerateMegamorphicCallStub() {
31943194

31953195
Label cid_loaded;
31963196
__ Bind(&cid_loaded);
3197+
__ lx(T1, FieldAddress(IC_DATA_REG, target::MegamorphicCache::mask_offset()));
31973198
__ lx(T2,
31983199
FieldAddress(IC_DATA_REG, target::MegamorphicCache::buckets_offset()));
3199-
__ lx(T1, FieldAddress(IC_DATA_REG, target::MegamorphicCache::mask_offset()));
3200+
// T1: mask as a smi - load first to support insertion w/o stopping Dart code.
32003201
// T2: cache buckets array.
3201-
// T1: mask as a smi.
32023202

32033203
// Make the cid into a smi.
32043204
__ SmiTag(T5);

runtime/vm/compiler/stub_code_compiler_x64.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3587,7 +3587,7 @@ void StubCodeCompiler::GenerateMegamorphicCallStub() {
35873587
FieldAddress(IC_DATA_REG, target::MegamorphicCache::mask_offset()));
35883588
__ movq(RDI, FieldAddress(IC_DATA_REG,
35893589
target::MegamorphicCache::buckets_offset()));
3590-
// R9: mask as a smi.
3590+
// R9: mask as a smi - load first to support insertion w/o stopping Dart code.
35913591
// RDI: cache buckets array.
35923592

35933593
// Tag cid as a smi.

runtime/vm/object.cc

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19759,24 +19759,9 @@ ObjectPtr MegamorphicCache::LookupLocked(const Smi& class_id) const {
1975919759
UNREACHABLE();
1976019760
}
1976119761

19762+
// Note this may run with Dart execution reading this cache.
1976219763
void MegamorphicCache::InsertLocked(const Smi& class_id,
1976319764
const Object& target) const {
19764-
auto isolate_group = IsolateGroup::Current();
19765-
ASSERT(isolate_group->type_feedback_mutex()->IsOwnedByCurrentThread());
19766-
19767-
// As opposed to ICData we are stopping mutator threads from other isolates
19768-
// while modifying the megamorphic cache, since updates are not atomic.
19769-
//
19770-
// NOTE: In the future we might change the megamorphic cache insertions to
19771-
// carefully use store-release barriers on the writer as well as
19772-
// load-acquire barriers on the reader, ...
19773-
isolate_group->RunWithStoppedMutators([&]() {
19774-
EnsureCapacityLocked();
19775-
InsertEntryLocked(class_id, target);
19776-
});
19777-
}
19778-
19779-
void MegamorphicCache::EnsureCapacityLocked() const {
1978019765
auto thread = Thread::Current();
1978119766
auto zone = thread->zone();
1978219767
auto isolate_group = thread->isolate_group();
@@ -19787,50 +19772,54 @@ void MegamorphicCache::EnsureCapacityLocked() const {
1978719772
if (static_cast<double>(filled_entry_count() + 1) > load_limit) {
1978819773
const Array& old_buckets = Array::Handle(zone, buckets());
1978919774
intptr_t new_capacity = old_capacity * 2;
19775+
intptr_t new_mask = new_capacity - 1;
1979019776
const Array& new_buckets =
1979119777
Array::Handle(zone, Array::New(kEntryLength * new_capacity));
1979219778

1979319779
auto& target = Object::Handle(zone);
1979419780
for (intptr_t i = 0; i < new_capacity; ++i) {
1979519781
SetEntry(new_buckets, i, smi_illegal_cid(), target);
1979619782
}
19797-
set_buckets(new_buckets);
19798-
set_mask(new_capacity - 1);
19799-
set_filled_entry_count(0);
1980019783

1980119784
// Rehash the valid entries.
1980219785
Smi& class_id = Smi::Handle(zone);
1980319786
for (intptr_t i = 0; i < old_capacity; ++i) {
1980419787
class_id ^= GetClassId(old_buckets, i);
1980519788
if (class_id.Value() != kIllegalCid) {
1980619789
target = GetTargetFunction(old_buckets, i);
19807-
InsertEntryLocked(class_id, target);
19790+
InsertEntryLocked<std::memory_order_relaxed>(new_buckets, new_mask,
19791+
class_id, target);
1980819792
}
1980919793
}
19794+
19795+
// Publish buckets first. Old mask with new buckets is just a spurious miss.
19796+
untag()->set_buckets<std::memory_order_release>(new_buckets.ptr());
19797+
untag()->set_mask<std::memory_order_release>(Smi::New(new_mask));
1981019798
}
19811-
}
1981219799

19813-
void MegamorphicCache::InsertEntryLocked(const Smi& class_id,
19814-
const Object& target) const {
19815-
auto thread = Thread::Current();
19816-
auto isolate_group = thread->isolate_group();
19817-
ASSERT(isolate_group->type_feedback_mutex()->IsOwnedByCurrentThread());
19800+
const Array& new_buckets = Array::Handle(zone, buckets());
19801+
InsertEntryLocked<std::memory_order_release>(new_buckets, mask(), class_id,
19802+
target);
19803+
set_filled_entry_count(filled_entry_count() + 1);
19804+
}
1981819805

19819-
ASSERT(Thread::Current()->IsDartMutatorThread());
19820-
ASSERT(static_cast<double>(filled_entry_count() + 1) <=
19821-
(kLoadFactor * static_cast<double>(mask() + 1)));
19822-
const Array& backing_array = Array::Handle(buckets());
19823-
intptr_t id_mask = mask();
19824-
intptr_t index = (class_id.Value() * kSpreadFactor) & id_mask;
19825-
intptr_t i = index;
19806+
template <std::memory_order order>
19807+
void MegamorphicCache::InsertEntryLocked(const Array& backing_array,
19808+
intptr_t mask,
19809+
const Smi& class_id,
19810+
const Object& target) {
19811+
const intptr_t start = (class_id.Value() * kSpreadFactor) & mask;
19812+
intptr_t i = start;
1982619813
do {
1982719814
if (Smi::Value(Smi::RawCast(GetClassId(backing_array, i))) == kIllegalCid) {
19828-
SetEntry(backing_array, i, class_id, target);
19829-
set_filled_entry_count(filled_entry_count() + 1);
19815+
// Publish target first. Old class id with new target is just a spurious
19816+
// miss.
19817+
SetTargetFunction<order>(backing_array, i, target);
19818+
SetClassId<order>(backing_array, i, class_id);
1983019819
return;
1983119820
}
19832-
i = (i + 1) & id_mask;
19833-
} while (i != index);
19821+
i = (i + 1) & mask;
19822+
} while (i != start);
1983419823
UNREACHABLE();
1983519824
}
1983619825

runtime/vm/object.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7838,18 +7838,29 @@ class MegamorphicCache : public CallSiteData {
78387838

78397839
// The caller must hold IsolateGroup::type_feedback_mutex().
78407840
void InsertLocked(const Smi& class_id, const Object& target) const;
7841-
void EnsureCapacityLocked() const;
78427841
ObjectPtr LookupLocked(const Smi& class_id) const;
78437842

7844-
void InsertEntryLocked(const Smi& class_id, const Object& target) const;
7843+
template <std::memory_order order>
7844+
static void InsertEntryLocked(const Array& array,
7845+
intptr_t mask,
7846+
const Smi& class_id,
7847+
const Object& target);
78457848

78467849
static inline void SetEntry(const Array& array,
78477850
intptr_t index,
78487851
const Smi& class_id,
78497852
const Object& target);
78507853

78517854
static inline ObjectPtr GetClassId(const Array& array, intptr_t index);
7855+
template <std::memory_order order>
7856+
static inline void SetClassId(const Array& array,
7857+
intptr_t index,
7858+
const Smi& class_id);
78527859
static inline ObjectPtr GetTargetFunction(const Array& array, intptr_t index);
7860+
template <std::memory_order order>
7861+
static inline void SetTargetFunction(const Array& array,
7862+
intptr_t index,
7863+
const Object& target);
78537864

78547865
FINAL_HEAP_OBJECT_IMPLEMENTATION(MegamorphicCache, CallSiteData);
78557866
};
@@ -13549,11 +13560,25 @@ ObjectPtr MegamorphicCache::GetClassId(const Array& array, intptr_t index) {
1354913560
return array.At((index * kEntryLength) + kClassIdIndex);
1355013561
}
1355113562

13563+
template <std::memory_order order>
13564+
void MegamorphicCache::SetClassId(const Array& array,
13565+
intptr_t index,
13566+
const Smi& class_id) {
13567+
array.SetAt<order>((index * kEntryLength) + kClassIdIndex, class_id);
13568+
}
13569+
1355213570
ObjectPtr MegamorphicCache::GetTargetFunction(const Array& array,
1355313571
intptr_t index) {
1355413572
return array.At((index * kEntryLength) + kTargetFunctionIndex);
1355513573
}
1355613574

13575+
template <std::memory_order order>
13576+
void MegamorphicCache::SetTargetFunction(const Array& array,
13577+
intptr_t index,
13578+
const Object& target) {
13579+
array.SetAt<order>((index * kEntryLength) + kTargetFunctionIndex, target);
13580+
}
13581+
1355713582
inline uword AbstractType::Hash() const {
1355813583
ASSERT(IsFinalized());
1355913584
intptr_t result = Smi::Value(untag()->hash());

0 commit comments

Comments
 (0)