[vm] Update Megamorphic::filled_entry_count_ under the megamorphic lock.
Otherwise the background compiler may see 0 when the mutator grows the megamorphic cache.
Bug: https://github.com/dart-lang/sdk/issues/37257
Change-Id: I64a31937391ad6c0f086f8f175501ca4ef06c305
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105969
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 932b94e..17e1b33 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -776,7 +776,7 @@
if (ic_data.is_megamorphic()) {
const MegamorphicCache& cache =
MegamorphicCache::Handle(zone, ic_data.AsMegamorphicCache());
- SafepointMutexLocker ml(Isolate::Current()->megamorphic_lookup_mutex());
+ SafepointMutexLocker ml(Isolate::Current()->megamorphic_mutex());
MegamorphicCacheEntries entries(Array::Handle(zone, cache.buckets()));
for (intptr_t i = 0; i < entries.Length(); i++) {
const intptr_t id =
@@ -787,8 +787,10 @@
if (include_targets) {
Function& function = Function::ZoneHandle(zone);
function ^= entries[i].Get<MegamorphicCache::kTargetFunctionIndex>();
+ const intptr_t filled_entry_count = cache.filled_entry_count();
+ ASSERT(filled_entry_count > 0);
cid_ranges_.Add(new (zone) TargetInfo(
- id, id, &function, Usage(function) / cache.filled_entry_count(),
+ id, id, &function, Usage(function) / filled_entry_count,
StaticTypeExactnessState::NotTracking()));
} else {
cid_ranges_.Add(new (zone) CidRange(id, id));
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index e68d40c..544424a 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -892,8 +892,7 @@
NOT_IN_PRODUCT("Isolate::type_canonicalization_mutex_")),
constant_canonicalization_mutex_(
NOT_IN_PRODUCT("Isolate::constant_canonicalization_mutex_")),
- megamorphic_lookup_mutex_(
- NOT_IN_PRODUCT("Isolate::megamorphic_lookup_mutex_")),
+ megamorphic_mutex_(NOT_IN_PRODUCT("Isolate::megamorphic_mutex_")),
kernel_data_lib_cache_mutex_(
NOT_IN_PRODUCT("Isolate::kernel_data_lib_cache_mutex_")),
kernel_data_class_cache_mutex_(
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 4813d27..6e8cb9e 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -355,7 +355,7 @@
Mutex* constant_canonicalization_mutex() {
return &constant_canonicalization_mutex_;
}
- Mutex* megamorphic_lookup_mutex() { return &megamorphic_lookup_mutex_; }
+ Mutex* megamorphic_mutex() { return &megamorphic_mutex_; }
Mutex* kernel_data_lib_cache_mutex() { return &kernel_data_lib_cache_mutex_; }
Mutex* kernel_data_class_cache_mutex() {
@@ -1027,7 +1027,8 @@
Mutex symbols_mutex_; // Protects concurrent access to the symbol table.
Mutex type_canonicalization_mutex_; // Protects type canonicalization.
Mutex constant_canonicalization_mutex_; // Protects const canonicalization.
- Mutex megamorphic_lookup_mutex_; // Protects megamorphic table lookup.
+ Mutex megamorphic_mutex_; // Protects the table of megamorphic caches and
+ // their entries.
Mutex kernel_data_lib_cache_mutex_;
Mutex kernel_data_class_cache_mutex_;
Mutex kernel_constants_mutex_;
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index c07452f..8b9bf6a 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -16,7 +16,7 @@
const String& name,
const Array& descriptor) {
// Multiple compilation threads could access this lookup.
- SafepointMutexLocker ml(isolate->megamorphic_lookup_mutex());
+ SafepointMutexLocker ml(isolate->megamorphic_mutex());
ASSERT(name.IsSymbol());
// TODO(rmacnak): ASSERT(descriptor.IsCanonical());
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index ffea8e7..4294af9 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -14175,7 +14175,7 @@
if (is_megamorphic()) {
const MegamorphicCache& cache =
MegamorphicCache::Handle(AsMegamorphicCache());
- SafepointMutexLocker ml(Isolate::Current()->megamorphic_lookup_mutex());
+ SafepointMutexLocker ml(Isolate::Current()->megamorphic_mutex());
MegamorphicCacheEntries entries(Array::Handle(cache.buckets()));
for (intptr_t i = 0; i < entries.Length(); i++) {
const intptr_t id =
@@ -15672,7 +15672,14 @@
return result.raw();
}
-void MegamorphicCache::EnsureCapacity() const {
+void MegamorphicCache::Insert(const Smi& class_id, const Object& target) const {
+ SafepointMutexLocker ml(Isolate::Current()->megamorphic_mutex());
+ EnsureCapacityLocked();
+ InsertLocked(class_id, target);
+}
+
+void MegamorphicCache::EnsureCapacityLocked() const {
+ ASSERT(Isolate::Current()->megamorphic_mutex()->IsOwnedByCurrentThread());
intptr_t old_capacity = mask() + 1;
double load_limit = kLoadFactor * static_cast<double>(old_capacity);
if (static_cast<double>(filled_entry_count() + 1) > load_limit) {
@@ -15696,16 +15703,18 @@
class_id ^= GetClassId(old_buckets, i);
if (class_id.Value() != kIllegalCid) {
target = GetTargetFunction(old_buckets, i);
- Insert(class_id, target);
+ InsertLocked(class_id, target);
}
}
}
}
-void MegamorphicCache::Insert(const Smi& class_id, const Object& target) const {
+void MegamorphicCache::InsertLocked(const Smi& class_id,
+ const Object& target) const {
+ ASSERT(Isolate::Current()->megamorphic_mutex()->IsOwnedByCurrentThread());
+ ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(static_cast<double>(filled_entry_count() + 1) <=
(kLoadFactor * static_cast<double>(mask() + 1)));
- SafepointMutexLocker ml(Isolate::Current()->megamorphic_lookup_mutex());
const Array& backing_array = Array::Handle(buckets());
intptr_t id_mask = mask();
intptr_t index = (class_id.Value() * kSpreadFactor) & id_mask;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c1cc1a4..a5a5731 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5836,8 +5836,6 @@
static RawMegamorphicCache* New(const String& target_name,
const Array& arguments_descriptor);
- void EnsureCapacity() const;
-
void Insert(const Smi& class_id, const Object& target) const;
void SwitchToBareInstructions();
@@ -5856,6 +5854,10 @@
void set_target_name(const String& value) const;
void set_arguments_descriptor(const Array& value) const;
+ // The caller must hold Isolate::megamorphic_mutex().
+ void EnsureCapacityLocked() const;
+ void InsertLocked(const Smi& class_id, const Object& target) const;
+
static inline void SetEntry(const Array& array,
intptr_t index,
const Smi& class_id,
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index c2257d0..f13950a 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1786,7 +1786,6 @@
} else {
const MegamorphicCache& cache = MegamorphicCache::Cast(ic_data_or_cache);
// Insert function found into cache and return it.
- cache.EnsureCapacity();
const Smi& class_id = Smi::Handle(zone, Smi::New(cls.id()));
cache.Insert(class_id, target_function);
}