From 49a135ab7e01107cad0920b350171af2be711b07 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Wed, 18 Jan 2023 20:16:11 +0000 Subject: [PATCH] [vm] Extend the hash_table.h templates to support weak sets. Make the canonical string table weak. Remove incorrect assumption that a symbol not already existing implies there is no target. This would be true but for all the call-through-field/method-extractor nonsense. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/50648 Bug: b/265897936 Change-Id: I463807a5d8c064888abbdc3dc75e916c2bdc8fa5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279273 Reviewed-by: Siva Annamalai Commit-Queue: Ryan Macnak --- runtime/vm/app_snapshot.cc | 154 +++++++++++++++--- runtime/vm/app_snapshot.h | 1 + runtime/vm/canonical_tables.h | 3 +- .../vm/compiler/aot/aot_call_specializer.cc | 7 +- runtime/vm/compiler/aot/precompiler.cc | 8 +- runtime/vm/compiler/runtime_api.h | 5 +- .../vm/compiler/runtime_offsets_extracted.h | 90 ++++++++++ runtime/vm/compiler/runtime_offsets_list.h | 2 + runtime/vm/hash_table.h | 103 ++++++++++-- runtime/vm/message_snapshot.cc | 1 + runtime/vm/object_store.h | 2 +- runtime/vm/reusable_handles.h | 2 + runtime/vm/symbols.cc | 6 +- runtime/vm/thread.h | 3 +- 14 files changed, 333 insertions(+), 54 deletions(-) diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc index 4d0f3e4ed2c..24e8b9bd632 100644 --- a/runtime/vm/app_snapshot.cc +++ b/runtime/vm/app_snapshot.cc @@ -624,7 +624,7 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster { const char* name) : DeserializationCluster(name, is_canonical), is_root_unit_(is_root_unit), - table_(Array::Handle()) {} + table_(SetType::ArrayHandle::Handle()) {} void BuildCanonicalSetFromLayout(Deserializer* d) { if (!is_root_unit_ || !is_canonical()) { @@ -645,11 +645,11 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster { protected: const bool is_root_unit_; intptr_t first_element_; - Array& table_; + typename SetType::ArrayHandle& table_; void VerifyCanonicalSet(Deserializer* d, const Array& refs, - const Array& current_table) { + const typename SetType::ArrayHandle& current_table) { #if defined(DEBUG) // First check that we are not overwriting a table and loosing information. if (!current_table.IsNull()) { @@ -672,7 +672,7 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster { private: struct DeserializationFinger { - ArrayPtr table; + typename SetType::ArrayPtr table; intptr_t current_index; ObjectPtr gap_element; @@ -687,12 +687,12 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster { table->untag()->data()[current_index++] = object; } - ArrayPtr Finish() { - if (table != Array::null()) { + typename SetType::ArrayPtr Finish() { + if (table != SetType::ArrayHandle::null()) { FillGap(Smi::Value(table->untag()->length()) - current_index); } auto result = table; - table = Array::null(); + table = SetType::ArrayHandle::null(); return result; } }; @@ -700,11 +700,12 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster { static DeserializationFinger StartDeserialization(Deserializer* d, intptr_t length, intptr_t count) { - const intptr_t instance_size = Array::InstanceSize(length); - ArrayPtr table = static_cast( + const intptr_t instance_size = SetType::ArrayHandle::InstanceSize(length); + typename SetType::ArrayPtr table = static_cast( d->heap()->old_space()->AllocateSnapshot(instance_size)); - Deserializer::InitializeHeader(table, kArrayCid, instance_size); - table->untag()->type_arguments_ = TypeArguments::null(); + Deserializer::InitializeHeader(table, SetType::Storage::ArrayCid, + instance_size); + InitTypeArgsOrNext(table); table->untag()->length_ = Smi::New(length); for (intptr_t i = 0; i < SetType::kFirstKeyIndex; i++) { table->untag()->data()[i] = Smi::New(0); @@ -712,6 +713,13 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster { table->untag()->data()[SetType::kOccupiedEntriesIndex] = Smi::New(count); return {table, SetType::kFirstKeyIndex, SetType::UnusedMarker().ptr()}; } + + static void InitTypeArgsOrNext(ArrayPtr table) { + table->untag()->type_arguments_ = TypeArguments::null(); + } + static void InitTypeArgsOrNext(WeakArrayPtr table) { + table->untag()->next_seen_by_gc_ = WeakArray::null(); + } }; #if !defined(DART_PRECOMPILED_RUNTIME) @@ -3065,7 +3073,8 @@ class RODataDeserializationCluster void PostLoad(Deserializer* d, const Array& refs, bool primary) { if (!table_.IsNull()) { auto object_store = d->isolate_group()->object_store(); - VerifyCanonicalSet(d, refs, Array::Handle(object_store->symbol_table())); + VerifyCanonicalSet(d, refs, + WeakArray::Handle(object_store->symbol_table())); object_store->set_symbol_table(table_); if (d->isolate_group() == Dart::vm_isolate_group()) { Symbols::InitFromSnapshot(d->isolate_group()); @@ -5501,6 +5510,8 @@ class WeakPropertySerializationCluster : public SerializationCluster { void Trace(Serializer* s, ObjectPtr object) { WeakPropertyPtr property = WeakProperty::RawCast(object); objects_.Add(property); + + s->PushWeak(property->untag()->key()); } void RetraceEphemerons(Serializer* s) { @@ -5857,6 +5868,92 @@ class ArrayDeserializationCluster const intptr_t cid_; }; +#if !defined(DART_PRECOMPILED_RUNTIME) +class WeakArraySerializationCluster : public SerializationCluster { + public: + WeakArraySerializationCluster() + : SerializationCluster("WeakArray", kWeakArrayCid, kSizeVaries) {} + ~WeakArraySerializationCluster() {} + + void Trace(Serializer* s, ObjectPtr object) { + WeakArrayPtr array = WeakArray::RawCast(object); + objects_.Add(array); + + const intptr_t length = Smi::Value(array->untag()->length()); + for (intptr_t i = 0; i < length; i++) { + s->PushWeak(array->untag()->element(i)); + } + } + + void WriteAlloc(Serializer* s) { + const intptr_t count = objects_.length(); + s->WriteUnsigned(count); + for (intptr_t i = 0; i < count; i++) { + WeakArrayPtr array = objects_[i]; + s->AssignRef(array); + AutoTraceObject(array); + const intptr_t length = Smi::Value(array->untag()->length()); + s->WriteUnsigned(length); + target_memory_size_ += compiler::target::WeakArray::InstanceSize(length); + } + } + + void WriteFill(Serializer* s) { + const intptr_t count = objects_.length(); + for (intptr_t i = 0; i < count; i++) { + WeakArrayPtr array = objects_[i]; + AutoTraceObject(array); + const intptr_t length = Smi::Value(array->untag()->length()); + s->WriteUnsigned(length); + for (intptr_t j = 0; j < length; j++) { + if (s->HasRef(array->untag()->element(j))) { + s->WriteElementRef(array->untag()->element(j), j); + } else { + s->WriteElementRef(Object::null(), j); + } + } + } + } + + private: + GrowableArray objects_; +}; +#endif // !DART_PRECOMPILED_RUNTIME + +class WeakArrayDeserializationCluster : public DeserializationCluster { + public: + WeakArrayDeserializationCluster() : DeserializationCluster("WeakArray") {} + ~WeakArrayDeserializationCluster() {} + + void ReadAlloc(Deserializer* d) { + start_index_ = d->next_index(); + PageSpace* old_space = d->heap()->old_space(); + const intptr_t count = d->ReadUnsigned(); + for (intptr_t i = 0; i < count; i++) { + const intptr_t length = d->ReadUnsigned(); + d->AssignRef( + old_space->AllocateSnapshot(WeakArray::InstanceSize(length))); + } + stop_index_ = d->next_index(); + } + + void ReadFill(Deserializer* d_, bool primary) { + Deserializer::Local d(d_); + + for (intptr_t id = start_index_, n = stop_index_; id < n; id++) { + WeakArrayPtr array = static_cast(d.Ref(id)); + const intptr_t length = d.ReadUnsigned(); + Deserializer::InitializeHeader(array, kWeakArrayCid, + WeakArray::InstanceSize(length), false); + array->untag()->next_seen_by_gc_ = WeakArray::null(); + array->untag()->length_ = Smi::New(length); + for (intptr_t j = 0; j < length; j++) { + array->untag()->data()[j] = d.ReadRef(); + } + } + } +}; + #if !defined(DART_PRECOMPILED_RUNTIME) class StringSerializationCluster : public CanonicalSetSerializationClusterisolate_group()->object_store(); - VerifyCanonicalSet(d, refs, Array::Handle(object_store->symbol_table())); + VerifyCanonicalSet(d, refs, + WeakArray::Handle(object_store->symbol_table())); object_store->set_symbol_table(table_); if (d->isolate_group() == Dart::vm_isolate_group()) { Symbols::InitFromSnapshot(d->isolate_group()); @@ -6055,7 +6153,8 @@ class FakeSerializationCluster : public SerializationCluster { #if !defined(DART_PRECOMPILED_RUNTIME) class VMSerializationRoots : public SerializationRoots { public: - explicit VMSerializationRoots(const Array& symbols, bool should_write_symbols) + explicit VMSerializationRoots(const WeakArray& symbols, + bool should_write_symbols) : symbols_(symbols), should_write_symbols_(should_write_symbols), zone_(Thread::Current()->zone()) {} @@ -6174,7 +6273,7 @@ class VMSerializationRoots : public SerializationRoots { } private: - const Array& symbols_; + const WeakArray& symbols_; const bool should_write_symbols_; Zone* zone_; }; @@ -6182,7 +6281,7 @@ class VMSerializationRoots : public SerializationRoots { class VMDeserializationRoots : public DeserializationRoots { public: - VMDeserializationRoots() : symbol_table_(Array::Handle()) {} + VMDeserializationRoots() : symbol_table_(WeakArray::Handle()) {} bool AddBaseObjects(Deserializer* d) { // These objects are always allocated by Object::InitOnce, so they are not @@ -6267,7 +6366,7 @@ class VMDeserializationRoots : public DeserializationRoots { } private: - Array& symbol_table_; + WeakArray& symbol_table_; }; #if !defined(DART_PRECOMPILED_RUNTIME) @@ -6288,7 +6387,7 @@ static const char* const kObjectStoreFieldNames[] = { class ProgramSerializationRoots : public SerializationRoots { public: #define RESET_ROOT_LIST(V) \ - V(symbol_table, Array, HashTables::New(4)) \ + V(symbol_table, WeakArray, HashTables::New(4)) \ V(canonical_types, Array, HashTables::New(4)) \ V(canonical_function_types, Array, \ HashTables::New(4)) \ @@ -7196,6 +7295,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid, case kImmutableArrayCid: return new (Z) ArraySerializationCluster(is_canonical, kImmutableArrayCid); + case kWeakArrayCid: + return new (Z) WeakArraySerializationCluster(); case kStringCid: return new (Z) StringSerializationCluster( is_canonical, cluster_represents_canonical_set && !vm_); @@ -7641,6 +7742,18 @@ void Serializer::Push(ObjectPtr object, intptr_t cid_override) { } } +void Serializer::PushWeak(ObjectPtr object) { + // The GC considers immediate objects to always be alive. This doesn't happen + // automatically in the serializer because the serializer does not have + // immediate objects: it handles Smis as ref indices like all other objects. + // This visit causes the serializer to reproduce the GC's semantics for + // weakness, which in particular allows the templates in hash_table.h to work + // with weak arrays because the metadata Smis always survive. + if (!object->IsHeapObject() || vm_) { + Push(object); + } +} + void Serializer::Trace(ObjectPtr object, intptr_t cid_override) { intptr_t cid; bool is_canonical; @@ -8366,6 +8479,8 @@ DeserializationCluster* Deserializer::ReadCluster() { case kImmutableArrayCid: return new (Z) ArrayDeserializationCluster(is_canonical, kImmutableArrayCid); + case kWeakArrayCid: + return new (Z) WeakArrayDeserializationCluster(); case kStringCid: return new (Z) StringDeserializationCluster( is_canonical, @@ -8857,7 +8972,8 @@ ZoneGrowableArray* FullSnapshotWriter::WriteVMSnapshot() { serializer.ReserveHeader(); serializer.WriteVersionAndFeatures(true); VMSerializationRoots roots( - Array::Handle(Dart::vm_isolate_group()->object_store()->symbol_table()), + WeakArray::Handle( + Dart::vm_isolate_group()->object_store()->symbol_table()), /*should_write_symbols=*/!Snapshot::IncludesStringsInROData(kind_)); ZoneGrowableArray* objects = serializer.Serialize(&roots); serializer.FillHeader(serializer.kind()); diff --git a/runtime/vm/app_snapshot.h b/runtime/vm/app_snapshot.h index 6359b276507..6f4d537d7a7 100644 --- a/runtime/vm/app_snapshot.h +++ b/runtime/vm/app_snapshot.h @@ -233,6 +233,7 @@ class Serializer : public ThreadStackResource { intptr_t GetCodeIndex(CodePtr code); void Push(ObjectPtr object, intptr_t cid_override = kIllegalCid); + void PushWeak(ObjectPtr object); void AddUntracedRef() { num_written_objects_++; } diff --git a/runtime/vm/canonical_tables.h b/runtime/vm/canonical_tables.h index be90131758b..29c35368743 100644 --- a/runtime/vm/canonical_tables.h +++ b/runtime/vm/canonical_tables.h @@ -132,7 +132,8 @@ class SymbolTraits { } }; -typedef UnorderedHashSet CanonicalStringSet; +typedef UnorderedHashSet + CanonicalStringSet; class CanonicalTypeKey { public: diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc index 4329be44345..548ae63e54b 100644 --- a/runtime/vm/compiler/aot/aot_call_specializer.cc +++ b/runtime/vm/compiler/aot/aot_call_specializer.cc @@ -972,11 +972,8 @@ bool AotCallSpecializer::TryExpandCallThroughGetter(const Class& receiver_class, Function& target = Function::Handle(Z); - const String& getter_name = String::ZoneHandle( - Z, Symbols::LookupFromGet(thread(), call->function_name())); - if (getter_name.IsNull()) { - return false; - } + const String& getter_name = + String::ZoneHandle(Z, Symbols::FromGet(thread(), call->function_name())); const Array& args_desc_array = Array::Handle( Z, diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index 57a5a6bc8bf..012b0da6d09 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc @@ -1719,12 +1719,8 @@ void Precompiler::CheckForNewDynamicFunctions() { functions_called_dynamically_.Insert(function2); } } else if (function.kind() == UntaggedFunction::kRegularFunction) { - selector2 = Field::LookupGetterSymbol(selector); - selector3 = String::null(); - if (!selector2.IsNull()) { - selector3 = - Function::CreateDynamicInvocationForwarderName(selector2); - } + selector2 = Field::GetterSymbol(selector); + selector3 = Function::CreateDynamicInvocationForwarderName(selector2); if (IsSent(selector2) || IsSent(selector3)) { metadata = kernel::ProcedureAttributesOf(function, Z); found_metadata = true; diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index ad9f9f71280..e57cd81354a 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -1425,7 +1425,10 @@ class WeakSerializationReference : public AllStatic { class WeakArray : public AllStatic { public: - static word InstanceSize() { return 0; } + static word length_offset(); + static word element_offset(intptr_t index); + static word InstanceSize(intptr_t length); + static word InstanceSize(); FINAL_CLASS(); }; diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 28393418f79..1cbaa63738d 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -57,6 +57,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 12; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65533; @@ -730,6 +733,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 8; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 24; +static constexpr dart::compiler::target::word WeakArray_element_size = 8; static constexpr dart::compiler::target::word Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = @@ -1414,6 +1420,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 12; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65533; @@ -2087,6 +2096,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 8; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 24; +static constexpr dart::compiler::target::word WeakArray_element_size = 8; static constexpr dart::compiler::target::word Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = @@ -2772,6 +2784,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 16; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65532; @@ -3454,6 +3469,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 16; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65532; @@ -4137,6 +4155,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 12; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65533; @@ -4812,6 +4833,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 8; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 24; +static constexpr dart::compiler::target::word WeakArray_element_size = 8; static constexpr dart::compiler::target::word Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = @@ -5496,6 +5520,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 12; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65533; @@ -6161,6 +6188,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 8; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 24; +static constexpr dart::compiler::target::word WeakArray_element_size = 8; static constexpr dart::compiler::target::word Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = @@ -6837,6 +6867,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 12; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65533; @@ -7502,6 +7535,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 8; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 24; +static constexpr dart::compiler::target::word WeakArray_element_size = 8; static constexpr dart::compiler::target::word Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = @@ -8179,6 +8215,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 16; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65532; @@ -8853,6 +8892,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 16; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65532; @@ -9528,6 +9570,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 4; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 12; +static constexpr dart::compiler::target::word WeakArray_element_size = 4; static constexpr dart::compiler::target::word Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = 65533; @@ -10195,6 +10240,9 @@ static constexpr dart::compiler::target::word TypeArguments_element_size = 8; static constexpr dart::compiler::target::word TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word WeakArray_elements_start_offset = + 24; +static constexpr dart::compiler::target::word WeakArray_element_size = 8; static constexpr dart::compiler::target::word Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word Array_kMaxNewSpaceElements = @@ -10880,6 +10928,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 12; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -11629,6 +11680,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 24; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 8; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -12386,6 +12440,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 24; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 8; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -13141,6 +13198,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 16; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -13896,6 +13956,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 16; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -14652,6 +14715,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 12; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -15403,6 +15469,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 24; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 8; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -16157,6 +16226,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 12; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -16897,6 +16969,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 24; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 8; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -17645,6 +17720,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 24; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 8; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -18391,6 +18469,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 16; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -19137,6 +19218,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 16; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -19884,6 +19968,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 12; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 12; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 4; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 268435455; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = @@ -20626,6 +20713,9 @@ static constexpr dart::compiler::target::word AOT_TwoByteString_elements_start_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_element_size = 2; +static constexpr dart::compiler::target::word + AOT_WeakArray_elements_start_offset = 24; +static constexpr dart::compiler::target::word AOT_WeakArray_element_size = 8; static constexpr dart::compiler::target::word AOT_Array_kMaxElements = 576460752303423487; static constexpr dart::compiler::target::word AOT_Array_kMaxNewSpaceElements = diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h index 3ad422d9d8d..1f51c5845f9 100644 --- a/runtime/vm/compiler/runtime_offsets_list.h +++ b/runtime/vm/compiler/runtime_offsets_list.h @@ -62,6 +62,7 @@ ARRAY(Record, field_offset) \ ARRAY(TypeArguments, type_at_offset) \ ARRAY(TwoByteString, element_offset) \ + ARRAY(WeakArray, element_offset) \ ARRAY_SIZEOF(Array, InstanceSize, element_offset) \ ARRAY_SIZEOF(Code, InstanceSize, element_offset) \ ARRAY_SIZEOF(Context, InstanceSize, variable_offset) \ @@ -72,6 +73,7 @@ ARRAY_SIZEOF(Record, InstanceSize, field_offset) \ ARRAY_SIZEOF(TypeArguments, InstanceSize, type_at_offset) \ ARRAY_SIZEOF(TwoByteString, InstanceSize, element_offset) \ + ARRAY_SIZEOF(WeakArray, InstanceSize, element_offset) \ CONSTANT(Array, kMaxElements) \ CONSTANT(Array, kMaxNewSpaceElements) \ CONSTANT(Context, kMaxElements) \ diff --git a/runtime/vm/hash_table.h b/runtime/vm/hash_table.h index d917aae6842..a8fc29f8b5a 100644 --- a/runtime/vm/hash_table.h +++ b/runtime/vm/hash_table.h @@ -15,6 +15,7 @@ namespace dart { struct ArrayStorageTraits { using ArrayHandle = Array; using ArrayPtr = dart::ArrayPtr; + static const intptr_t ArrayCid = kArrayCid; static ArrayHandle& PtrToHandle(ArrayPtr ptr) { return Array::Handle(ptr); } @@ -43,6 +44,40 @@ struct ArrayStorageTraits { } }; +struct WeakArrayStorageTraits { + using ArrayHandle = WeakArray; + using ArrayPtr = dart::WeakArrayPtr; + static const intptr_t ArrayCid = kWeakArrayCid; + + static ArrayHandle& PtrToHandle(ArrayPtr ptr) { + return WeakArray::Handle(ptr); + } + + static void SetHandle(ArrayHandle& dst, const ArrayHandle& src) { // NOLINT + dst = src.ptr(); + } + + static void ClearHandle(ArrayHandle& handle) { // NOLINT + handle = WeakArray::null(); + } + + static ArrayPtr New(Zone* zone, intptr_t length, Heap::Space space) { + return WeakArray::New(length, space); + } + + static bool IsImmutable(const ArrayHandle& handle) { + return handle.ptr()->untag()->InVMIsolateHeap(); + } + + static ObjectPtr At(ArrayHandle* array, intptr_t index) { + return array->At(index); + } + + static void SetAt(ArrayHandle* array, intptr_t index, const Object& value) { + array->SetAt(index, value); + } +}; + struct AcqRelStorageTraits : ArrayStorageTraits { static ObjectPtr At(ArrayHandle* array, intptr_t index) { return array->AtAcquire(index); @@ -53,10 +88,20 @@ struct AcqRelStorageTraits : ArrayStorageTraits { } }; +struct WeakAcqRelStorageTraits : WeakArrayStorageTraits { + static ObjectPtr At(ArrayHandle* array, intptr_t index) { + return array->AtAcquire(index); + } + + static void SetAt(ArrayHandle* array, intptr_t index, const Object& value) { + array->SetAtRelease(index, value); + } +}; + class HashTableBase : public ValueObject { public: static const Object& UnusedMarker() { return Object::transition_sentinel(); } - static const Object& DeletedMarker() { return Object::sentinel(); } + static const Object& DeletedMarker() { return Object::null_object(); } }; // OVERVIEW: @@ -206,9 +251,6 @@ class HashTable : public HashTableBase { template intptr_t FindKey(const Key& key) const { const intptr_t num_entries = NumEntries(); - // Deleted may undercount due to weak references used during AOT - // snapshotting. - NOT_IN_PRECOMPILED(ASSERT(NumOccupied() < num_entries)); // TODO(koda): Add salt. NOT_IN_PRODUCT(intptr_t collisions = 0;) uword hash = KeyTraits::Hash(key); @@ -244,9 +286,6 @@ class HashTable : public HashTableBase { bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const { const intptr_t num_entries = NumEntries(); ASSERT(entry != NULL); - // Deleted may undercount due to weak references used during AOT - // snapshotting. - NOT_IN_PRECOMPILED(ASSERT(NumOccupied() < num_entries)); NOT_IN_PRODUCT(intptr_t collisions = 0;) uword hash = KeyTraits::Hash(key); ASSERT(Utils::IsPowerOfTwo(num_entries)); @@ -294,9 +333,6 @@ class HashTable : public HashTableBase { } InternalSetKey(entry, key); ASSERT(IsOccupied(entry)); - // Deleted may undercount due to weak references used during AOT - // snapshotting. - NOT_IN_PRECOMPILED(ASSERT(NumOccupied() < NumEntries())); } bool IsUnused(intptr_t entry) const { @@ -401,6 +437,26 @@ class HashTable : public HashTableBase { } #endif // !PRODUCT + void UpdateWeakDeleted() const { + if (StorageTraits::ArrayCid != kWeakArrayCid) return; + + // As entries are deleted by GC, NumOccupied and NumDeleted become stale. + // Re-count before growing/rehashing to prevent table growth when the + // number of live entries is not increasing. + intptr_t num_occupied = 0; + intptr_t num_deleted = 0; + for (intptr_t i = 0, n = NumEntries(); i < n; i++) { + if (IsDeleted(i)) { + num_deleted++; + } + if (IsOccupied(i)) { + num_occupied++; + } + } + SetSmiValueAt(kOccupiedEntriesIndex, num_occupied); + SetSmiValueAt(kDeletedEntriesIndex, num_deleted); + } + protected: static const intptr_t kOccupiedEntriesIndex = 0; static const intptr_t kDeletedEntriesIndex = 1; @@ -439,6 +495,9 @@ class HashTable : public HashTableBase { intptr_t GetSmiValueAt(intptr_t index) const { ASSERT(!data_->IsNull()); + if (StorageTraits::At(data_, index)->IsHeapObject()) { + Object::Handle(StorageTraits::At(data_, index)).Print(); + } ASSERT(!StorageTraits::At(data_, index)->IsHeapObject()); return Smi::Value(Smi::RawCast(StorageTraits::At(data_, index))); } @@ -476,11 +535,13 @@ class UnorderedHashTable : public HashTable { public: typedef HashTable BaseTable; + typedef typename StorageTraits::ArrayPtr ArrayPtr; + typedef typename StorageTraits::ArrayHandle ArrayHandle; static const intptr_t kPayloadSize = kUserPayloadSize; explicit UnorderedHashTable(ArrayPtr data) : BaseTable(Thread::Current()->zone(), data) {} UnorderedHashTable(Zone* zone, ArrayPtr data) : BaseTable(zone, data) {} - UnorderedHashTable(Object* key, Smi* value, Array* data) + UnorderedHashTable(Object* key, Smi* value, ArrayHandle* data) : BaseTable(key, value, data) {} // Note: Does not check for concurrent modification. class Iterator { @@ -565,6 +626,9 @@ class HashTables : public AllStatic { if (current < high && !too_many_deleted) { return; } + + table.UpdateWeakDeleted(); + // Normally we double the size here, but if less than half are occupied // then it won't grow (this would imply that there were quite a lot of // deleted slots). We don't want to constantly rehash if we are adding @@ -724,13 +788,15 @@ class UnorderedHashMap : public HashMap > { : BaseMap(key, value, data) {} }; -template +template class HashSet : public BaseIterTable { public: + typedef typename StorageTraits::ArrayPtr ArrayPtr; + typedef typename StorageTraits::ArrayHandle ArrayHandle; explicit HashSet(ArrayPtr data) : BaseIterTable(Thread::Current()->zone(), data) {} HashSet(Zone* zone, ArrayPtr data) : BaseIterTable(zone, data) {} - HashSet(Object* key, Smi* value, Array* data) + HashSet(Object* key, Smi* value, ArrayHandle* data) : BaseIterTable(key, value, data) {} bool Insert(const Object& key) { EnsureCapacity(); @@ -800,17 +866,20 @@ class HashSet : public BaseIterTable { template class UnorderedHashSet - : public HashSet> { + : public HashSet, + TableStorageTraits> { using UnderlyingTable = UnorderedHashTable; public: - typedef HashSet BaseSet; + typedef HashSet BaseSet; + typedef typename TableStorageTraits::ArrayPtr ArrayPtr; + typedef typename TableStorageTraits::ArrayHandle ArrayHandle; explicit UnorderedHashSet(ArrayPtr data) : BaseSet(Thread::Current()->zone(), data) { - ASSERT(data != Array::null()); + ASSERT(data != Object::null()); } UnorderedHashSet(Zone* zone, ArrayPtr data) : BaseSet(zone, data) {} - UnorderedHashSet(Object* key, Smi* value, Array* data) + UnorderedHashSet(Object* key, Smi* value, ArrayHandle* data) : BaseSet(key, value, data) {} void Dump() const { diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc index c2357e92d44..29bc5eac36c 100644 --- a/runtime/vm/message_snapshot.cc +++ b/runtime/vm/message_snapshot.cc @@ -2847,6 +2847,7 @@ void MessageSerializer::Trace(Object* object) { ILLEGAL(UserTag) ILLEGAL(WeakProperty) ILLEGAL(WeakReference) + ILLEGAL(WeakArray) // From "dart:ffi" we handle only Pointer/DynamicLibrary specially, since // those are the only non-abstract classes (so we avoid checking more cids diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index 6851f3abc56..8ba40b782f7 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -139,7 +139,7 @@ class ObjectPointerVisitor; RW(Class, finalizer_class) \ RW(Class, finalizer_entry_class) \ RW(Class, native_finalizer_class) \ - ARW_AR(Array, symbol_table) \ + ARW_AR(WeakArray, symbol_table) \ RW(Array, canonical_types) \ RW(Array, canonical_function_types) \ RW(Array, canonical_record_types) \ diff --git a/runtime/vm/reusable_handles.h b/runtime/vm/reusable_handles.h index c13955276c6..7d4a09e9c64 100644 --- a/runtime/vm/reusable_handles.h +++ b/runtime/vm/reusable_handles.h @@ -112,6 +112,8 @@ REUSABLE_HANDLE_LIST(REUSABLE_SCOPE) ReusableTypeArgumentsHandleScope reused_type_arguments_handle(thread); #define REUSABLE_TYPE_PARAMETER_HANDLESCOPE(thread) \ ReusableTypeParameterHandleScope reused_type_parameter(thread); +#define REUSABLE_WEAK_ARRAY_HANDLESCOPE(thread) \ + ReusableWeakArrayHandleScope reused_weak_array(thread); } // namespace dart diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc index a60edfaa3fb..7cde8883aeb 100644 --- a/runtime/vm/symbols.cc +++ b/runtime/vm/symbols.cc @@ -173,7 +173,7 @@ void Symbols::SetupSymbolTable(IsolateGroup* isolate_group) { const intptr_t initial_size = (isolate_group == Dart::vm_isolate_group()) ? kInitialVMIsolateSymtabSize : kInitialSymtabSize; - Array& array = Array::Handle( + class WeakArray& array = WeakArray::Handle( HashTables::New(initial_size, Heap::kOld)); isolate_group->object_store()->set_symbol_table(array); } @@ -341,7 +341,7 @@ StringPtr Symbols::NewSymbol(Thread* thread, const StringType& str) { String& symbol = String::Handle(thread->zone()); dart::Object& key = thread->ObjectHandle(); Smi& value = thread->SmiHandle(); - Array& data = thread->ArrayHandle(); + class WeakArray& data = thread->WeakArrayHandle(); { auto vm_isolate_group = Dart::vm_isolate_group(); data = vm_isolate_group->object_store()->symbol_table(); @@ -386,7 +386,7 @@ StringPtr Symbols::Lookup(Thread* thread, const StringType& str) { String& symbol = String::Handle(thread->zone()); dart::Object& key = thread->ObjectHandle(); Smi& value = thread->SmiHandle(); - Array& data = thread->ArrayHandle(); + class WeakArray& data = thread->WeakArrayHandle(); { auto vm_isolate_group = Dart::vm_isolate_group(); data = vm_isolate_group->object_store()->symbol_table(); diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h index 2e15b9c35c0..5530cfaf07e 100644 --- a/runtime/vm/thread.h +++ b/runtime/vm/thread.h @@ -93,7 +93,8 @@ class Thread; V(String) \ V(TypeParameters) \ V(TypeArguments) \ - V(TypeParameter) + V(TypeParameter) \ + V(WeakArray) #define CACHED_VM_STUBS_LIST(V) \ V(CodePtr, fix_callers_target_code_, StubCode::FixCallersTarget().ptr(), \