@@ -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.
1976219763void 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
0 commit comments