From 85e396a1de20bd0c017707cc9680962652a9ed6f Mon Sep 17 00:00:00 2001 From: Alexander Aprelev Date: Mon, 6 Jan 2020 18:58:11 +0000 Subject: [PATCH] [vm/fieldtable] Move current field values out of Field object into separate table. This is to support sharing of Field objects between isolate group's isolates. Each isolate will have it's own field table with static instances/values. field_table is stored on isolate, copied over to thread for easier access. This also removes the write barrier from static field assignments; the field table is a GC root. Bug: https://github.com/dart-lang/sdk/issues/37835 Bug: https://github.com/dart-lang/sdk/issues/36097 Change-Id: I232a86f059ac4cacc3e9f54bcc31d1d0524f9496 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127582 Commit-Queue: Alexander Aprelev Reviewed-by: Martin Kustermann Reviewed-by: Ryan Macnak --- .../service/get_retaining_path_rpc_test.dart | 34 +- ...et_user_level_retaining_path_rpc_test.dart | 6 +- .../service/inbound_references_test.dart | 2 - runtime/vm/clustered_snapshot.cc | 93 +++-- runtime/vm/clustered_snapshot.h | 6 + runtime/vm/compiler/aot/precompiler.cc | 46 +++ runtime/vm/compiler/aot/precompiler.h | 3 + .../vm/compiler/backend/flow_graph_compiler.h | 7 + runtime/vm/compiler/backend/il.cc | 4 - runtime/vm/compiler/backend/il.h | 19 +- runtime/vm/compiler/backend/il_arm.cc | 59 +-- runtime/vm/compiler/backend/il_arm64.cc | 54 ++- runtime/vm/compiler/backend/il_ia32.cc | 55 +-- runtime/vm/compiler/backend/il_printer.cc | 2 +- runtime/vm/compiler/backend/il_x64.cc | 63 +-- .../compiler/backend/type_propagator_test.cc | 3 +- .../frontend/base_flow_graph_builder.cc | 4 +- .../frontend/base_flow_graph_builder.h | 2 +- .../frontend/bytecode_flow_graph_builder.cc | 3 +- .../frontend/kernel_binary_flowgraph.cc | 7 +- .../frontend/kernel_binary_flowgraph.h | 2 +- runtime/vm/compiler/frontend/kernel_to_il.cc | 14 +- runtime/vm/compiler/runtime_api.cc | 5 + runtime/vm/compiler/runtime_api.h | 6 + .../vm/compiler/runtime_offsets_extracted.h | 390 +++++++++--------- runtime/vm/compiler/runtime_offsets_list.h | 2 +- runtime/vm/field_table.cc | 106 +++++ runtime/vm/field_table.h | 88 ++++ runtime/vm/heap/pages.cc | 1 + runtime/vm/interpreter.cc | 22 +- runtime/vm/isolate.cc | 12 + runtime/vm/isolate.h | 6 + runtime/vm/isolate_reload_test.cc | 124 ++++++ runtime/vm/object.cc | 25 +- runtime/vm/object.h | 35 +- runtime/vm/object_reload.cc | 7 +- runtime/vm/raw_object.h | 12 +- runtime/vm/raw_object_fields.cc | 4 +- runtime/vm/thread.h | 9 + runtime/vm/vm_sources.gni | 2 + 40 files changed, 910 insertions(+), 434 deletions(-) create mode 100644 runtime/vm/field_table.cc create mode 100644 runtime/vm/field_table.h diff --git a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart index 0421eab8fe841..fcb20a7035390 100644 --- a/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart +++ b/runtime/observatory/tests/service/get_retaining_path_rpc_test.dart @@ -48,9 +48,9 @@ var tests = [ 'limit': 100, }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); - expect(result['gcRootType'], 'user global'); - expect(result['elements'].length, equals(2)); - expect(result['elements'][1]['value']['name'], equals('globalObject')); + expect(result['gcRootType'], 'static fields table'); + expect(result['elements'].length, equals(1)); + expect(result['elements'][0]['value']['type'], equals('@Instance')); }, // missing limit. @@ -81,10 +81,10 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['gcRootType'], 'user global'); - expect(result['elements'].length, equals(3)); + expect(result['gcRootType'], 'static fields table'); + expect(result['elements'].length, equals(2)); + expect(result['elements'][0]['value']['type'], equals('@Instance')); expect(result['elements'][1]['parentField'], equals('x')); - expect(result['elements'][2]['value']['name'], equals('globalObject')); }, (Isolate isolate) async { @@ -96,10 +96,10 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['gcRootType'], 'user global'); - expect(result['elements'].length, equals(3)); + expect(result['gcRootType'], 'static fields table'); + expect(result['elements'].length, equals(2)); expect(result['elements'][1]['parentField'], equals('y')); - expect(result['elements'][2]['value']['name'], equals('globalObject')); + expect(result['elements'][1]['value']['type'], equals('@Instance')); }, (Isolate isolate) async { @@ -111,10 +111,10 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['gcRootType'], 'user global'); - expect(result['elements'].length, equals(3)); + expect(result['gcRootType'], 'static fields table'); + expect(result['elements'].length, equals(2)); expect(result['elements'][1]['parentListIndex'], equals(12)); - expect(result['elements'][2]['value']['name'], equals('globalList')); + expect(result['elements'][1]['value']['type'], equals('@Instance')); }, (Isolate isolate) async { @@ -126,11 +126,11 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['gcRootType'], 'user global'); - expect(result['elements'].length, equals(3)); + expect(result['gcRootType'], 'static fields table'); + expect(result['elements'].length, equals(2)); expect( result['elements'][1]['parentMapKey']['valueAsString'], equals('key')); - expect(result['elements'][2]['value']['name'], equals('globalMap1')); + expect(result['elements'][1]['value']['type'], equals('@Instance')); }, (Isolate isolate) async { @@ -142,10 +142,10 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['elements'].length, equals(3)); + expect(result['elements'].length, equals(2)); expect(result['elements'][1]['parentMapKey']['class']['name'], equals('_TestClass')); - expect(result['elements'][2]['value']['name'], equals('globalMap2')); + expect(result['elements'][1]['value']['type'], equals('@Instance')); }, // object store diff --git a/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart b/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart index 12f17655454c0..698ab567b65f9 100644 --- a/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart +++ b/runtime/observatory/tests/service/get_user_level_retaining_path_rpc_test.dart @@ -46,10 +46,9 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['elements'].length, equals(2)); + expect(result['elements'].length, equals(1)); expect( result['elements'][0]['value']['class']['name'], equals('_TestConst')); - expect(result['elements'][1]['value']['name'], equals('x')); }, // Expect a simple path through variable fn instead of long path filled @@ -62,9 +61,8 @@ var tests = [ }; var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params); expect(result['type'], equals('RetainingPath')); - expect(result['elements'].length, equals(2)); + expect(result['elements'].length, equals(1)); expect(result['elements'][0]['value']['class']['name'], equals('_Closure')); - expect(result['elements'][1]['value']['name'], equals('fn')); } ]; diff --git a/runtime/observatory/tests/service/inbound_references_test.dart b/runtime/observatory/tests/service/inbound_references_test.dart index 6309f1f7b9b62..fddc8ba7aaf82 100644 --- a/runtime/observatory/tests/service/inbound_references_test.dart +++ b/runtime/observatory/tests/service/inbound_references_test.dart @@ -46,8 +46,6 @@ var tests = [ r['source'].clazz.name == 'Node'); hasReferenceSuchThat( (r) => r['parentListIndex'] == 1 && r['source'].isList); - hasReferenceSuchThat( - (r) => r['source'] is Field && r['source'].name == 'e'); } ]; diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc index 11548c0a1ebaa..49ee8cc511e20 100644 --- a/runtime/vm/clustered_snapshot.cc +++ b/runtime/vm/clustered_snapshot.cc @@ -913,26 +913,11 @@ class FieldSerializationCluster : public SerializationCluster { s->Push(field->ptr()->name_); s->Push(field->ptr()->owner_); s->Push(field->ptr()->type_); - // Write out the initial static value or field offset. - if (Field::StaticBit::decode(field->ptr()->kind_bits_)) { - if (kind == Snapshot::kFullAOT) { - // For precompiled static fields, the value was already reset and - // initializer_ now contains a Function. - s->Push(field->ptr()->value_.static_value_); - } else if (Field::ConstBit::decode(field->ptr()->kind_bits_)) { - // Do not reset const fields. - s->Push(field->ptr()->value_.static_value_); - } else { - // Otherwise, for static fields we write out the initial static value. - s->Push(field->ptr()->saved_initial_value_); - } - } else { - s->Push(field->ptr()->value_.offset_); - } // Write out the initializer function s->Push(field->ptr()->initializer_function_); + if (kind != Snapshot::kFullAOT) { - // Write out the saved initial value + // Write out the saved initial values s->Push(field->ptr()->saved_initial_value_); } if (kind != Snapshot::kFullAOT) { @@ -942,6 +927,22 @@ class FieldSerializationCluster : public SerializationCluster { if (kind == Snapshot::kFullJIT) { s->Push(field->ptr()->dependent_code_); } + // Write out either static value, initial value or field offset. + if (Field::StaticBit::decode(field->ptr()->kind_bits_)) { + if ( + // For precompiled static fields, the value was already reset and + // initializer_ now contains a Function. + kind == Snapshot::kFullAOT || + // Do not reset const fields. + Field::ConstBit::decode(field->ptr()->kind_bits_)) { + s->Push(s->field_table()->At(field->ptr()->offset_or_field_id_)); + } else { + // Otherwise, for static fields we write out the initial static value. + s->Push(field->ptr()->saved_initial_value_); + } + } else { + s->Push(Smi::New(field->ptr()->offset_or_field_id_)); + } } void WriteAlloc(Serializer* s) { @@ -964,22 +965,6 @@ class FieldSerializationCluster : public SerializationCluster { WriteField(field, name_); WriteField(field, owner_); WriteField(field, type_); - // Write out the initial static value or field offset. - if (Field::StaticBit::decode(field->ptr()->kind_bits_)) { - if (kind == Snapshot::kFullAOT) { - // For precompiled static fields, the value was already reset and - // initializer_ now contains a Function. - WriteField(field, value_.static_value_); - } else if (Field::ConstBit::decode(field->ptr()->kind_bits_)) { - // Do not reset const fields. - WriteField(field, value_.static_value_); - } else { - // Otherwise, for static fields we write out the initial static value. - WriteField(field, saved_initial_value_); - } - } else { - WriteField(field, value_.offset_); - } // Write out the initializer function and initial value if not in AOT. WriteField(field, initializer_function_); if (kind != Snapshot::kFullAOT) { @@ -1004,6 +989,27 @@ class FieldSerializationCluster : public SerializationCluster { #endif } s->Write(field->ptr()->kind_bits_); + + // Write out the initial static value or field offset. + if (Field::StaticBit::decode(field->ptr()->kind_bits_)) { + if ( + // For precompiled static fields, the value was already reset and + // initializer_ now contains a Function. + // WriteField(field, value_.static_value_); + kind == Snapshot::kFullAOT || + // Do not reset const fields. + Field::ConstBit::decode(field->ptr()->kind_bits_)) { + WriteFieldValue( + "static value", + s->field_table()->At(field->ptr()->offset_or_field_id_)); + } else { + // Otherwise, for static fields we write out the initial static value. + WriteFieldValue("static value", field->ptr()->saved_initial_value_); + } + s->WriteUnsigned(field->ptr()->offset_or_field_id_); + } else { + WriteFieldValue("offset", Smi::New(field->ptr()->offset_or_field_id_)); + } } } @@ -1045,6 +1051,17 @@ class FieldDeserializationCluster : public DeserializationCluster { #endif } field->ptr()->kind_bits_ = d->Read(); + + RawObject* value_or_offset = d->ReadRef(); + if (Field::StaticBit::decode(field->ptr()->kind_bits_)) { + intptr_t field_id = d->ReadUnsigned(); + d->field_table()->SetAt( + field_id, reinterpret_cast(value_or_offset)); + field->ptr()->offset_or_field_id_ = field_id; + } else { + field->ptr()->offset_or_field_id_ = + Smi::Value(Smi::RawCast(value_or_offset)); + } } } @@ -4342,6 +4359,7 @@ Serializer::Serializer(Thread* thread, num_base_objects_(0), num_written_objects_(0), next_ref_index_(1), + field_table_(thread->isolate()->field_table()), vm_(vm), profile_writer_(profile_writer) #if defined(SNAPSHOT_BACKTRACE) @@ -4796,6 +4814,7 @@ void Serializer::Serialize() { WriteUnsigned(num_objects); WriteUnsigned(num_clusters); WriteUnsigned(code_order_length); + WriteUnsigned(field_table_->NumFieldIds()); for (intptr_t cid = 1; cid < num_cids_; cid++) { SerializationCluster* cluster = clusters_by_cid_[cid]; @@ -5012,7 +5031,8 @@ Deserializer::Deserializer(Thread* thread, image_reader_(NULL), refs_(NULL), next_ref_index_(1), - clusters_(NULL) { + clusters_(NULL), + field_table_(thread->isolate()->field_table()) { if (Snapshot::IncludesCode(kind)) { ASSERT(instructions_buffer != NULL); ASSERT(data_buffer != NULL); @@ -5280,9 +5300,14 @@ void Deserializer::Prepare() { num_objects_ = ReadUnsigned(); num_clusters_ = ReadUnsigned(); code_order_length_ = ReadUnsigned(); + const intptr_t field_table_len = ReadUnsigned(); clusters_ = new DeserializationCluster*[num_clusters_]; refs_ = Array::New(num_objects_ + 1, Heap::kOld); + if (field_table_len > 0) { + field_table_->AllocateIndex(field_table_len - 1); + } + ASSERT(field_table_->NumFieldIds() == field_table_len); } void Deserializer::Deserialize() { diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h index d65569c6f0a51..7be84ef2d046e 100644 --- a/runtime/vm/clustered_snapshot.h +++ b/runtime/vm/clustered_snapshot.h @@ -216,6 +216,9 @@ class Serializer : public ThreadStackResource { void WriteVersionAndFeatures(bool is_vm_snapshot); void Serialize(); + + FieldTable* field_table() { return field_table_; } + WriteStream* stream() { return &stream_; } intptr_t bytes_written() { return stream_.bytes_written(); } @@ -372,6 +375,7 @@ class Serializer : public ThreadStackResource { intptr_t num_written_objects_; intptr_t next_ref_index_; SmiObjectIdMap smi_ids_; + FieldTable* field_table_; // True if writing VM snapshot, false for Isolate snapshot. bool vm_; @@ -556,6 +560,7 @@ class Deserializer : public ThreadStackResource { intptr_t next_index() const { return next_ref_index_; } Heap* heap() const { return heap_; } Snapshot::Kind kind() const { return kind_; } + FieldTable* field_table() const { return field_table_; } // The number of code objects which were relocated during AOT snapshot // writing. @@ -585,6 +590,7 @@ class Deserializer : public ThreadStackResource { RawArray* refs_; intptr_t next_ref_index_; DeserializationCluster** clusters_; + FieldTable* field_table_; }; #define ReadFromTo(obj, ...) d->ReadFromTo(obj, ##__VA_ARGS__); diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index e4f60dbc99c6f..3abf7b362194a 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc @@ -166,6 +166,7 @@ Precompiler::Precompiler(Thread* thread) libraries_(GrowableObjectArray::Handle(I->object_store()->libraries())), pending_functions_( GrowableObjectArray::Handle(GrowableObjectArray::New())), + pending_static_fields_to_retain_(), sent_selectors_(), enqueued_functions_( HashTables::New(/*initial_capacity=*/1024)), @@ -530,6 +531,13 @@ void Precompiler::AddRoots() { } } +void Precompiler::AddRetainedStaticField(const Field& field) { + if (pending_static_fields_to_retain_.HasKey(&field)) { + return; + } + pending_static_fields_to_retain_.Insert(&Field::ZoneHandle(Z, field.raw())); +} + void Precompiler::Iterate() { Function& function = Function::Handle(Z); @@ -541,6 +549,12 @@ void Precompiler::Iterate() { ProcessFunction(function); } + FieldSet::Iterator it = pending_static_fields_to_retain_.GetIterator(); + for (const Field** field = it.Next(); field != nullptr; field = it.Next()) { + AddField(**field); + } + pending_static_fields_to_retain_.Clear(); + CheckForNewDynamicFunctions(); CollectCallbackFields(); } @@ -1551,6 +1565,12 @@ void Precompiler::DropFields() { if (FLAG_trace_precompiler) { THR_Print("Dropping field %s\n", field.ToCString()); } + + // This cleans up references to field current and initial values. + if (field.is_static()) { + field.SetStaticValue(Object::null_instance(), + /*save_initial_value=*/true); + } } } @@ -1794,9 +1814,25 @@ void Precompiler::DropMetadata() { Array& dependencies = Array::Handle(Z); Namespace& ns = Namespace::Handle(Z); const Field& null_field = Field::Handle(Z); + GrowableObjectArray& metadata = GrowableObjectArray::Handle(Z); + Field& metadata_field = Field::Handle(Z); for (intptr_t i = 0; i < libraries_.Length(); i++) { lib ^= libraries_.At(i); + metadata ^= lib.metadata(); + for (intptr_t j = 0; j < metadata.Length(); j++) { + metadata_field ^= metadata.At(j); + if (metadata_field.is_static()) { + // Although this field will become garbage after clearing the list + // below, we also need to clear its value from the field table. + // The value may be an instance of an otherwise dead class, and if + // it remains in the field table we can get an instance on the heap + // with a deleted class. + metadata_field.SetStaticValue(Object::null_instance(), + /*save_initial_value=*/true); + } + } + lib.set_metadata(null_growable_list); dependencies = lib.imports(); @@ -2455,6 +2491,16 @@ bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) { function_stats); } + for (intptr_t i = 0; i < graph_compiler.used_static_fields().length(); + i++) { + // We can't use precompiler_->AddField() directly here because they + // need to be added later as part of Iterate(). If they are added + // before that, initializer functions will get their code cleared by + // Precompiler::ClearAllCode(). + precompiler_->AddRetainedStaticField( + *graph_compiler.used_static_fields().At(i)); + } + // In bare instructions mode try adding all entries from the object // pool into the global object pool. This might fail if we have // nested code generation (i.e. we generated some stubs) whichs means diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h index 9cb24d247e555..ba1e3521c7ad4 100644 --- a/runtime/vm/compiler/aot/precompiler.h +++ b/runtime/vm/compiler/aot/precompiler.h @@ -217,6 +217,8 @@ class Precompiler : public ValueObject { static Precompiler* Instance() { return singleton_; } + void AddRetainedStaticField(const Field& field); + private: static Precompiler* singleton_; @@ -305,6 +307,7 @@ class Precompiler : public ValueObject { compiler::ObjectPoolBuilder global_object_pool_builder_; GrowableObjectArray& libraries_; const GrowableObjectArray& pending_functions_; + FieldSet pending_static_fields_to_retain_; SymbolSet sent_selectors_; FunctionSet enqueued_functions_; FieldSet fields_to_retain_; diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h index ae2e9c033b4d1..38d30c014baf6 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler.h +++ b/runtime/vm/compiler/backend/flow_graph_compiler.h @@ -478,6 +478,10 @@ class FlowGraphCompiler : public ValueObject { if (stats_ != NULL) stats_->SpecialEnd(tag); } + GrowableArray& used_static_fields() { + return used_static_fields_; + } + // Constructor is lighweight, major initialization work should occur here. // This makes it easier to measure time spent in the compiler. void InitCompiler(); @@ -1090,6 +1094,9 @@ class FlowGraphCompiler : public ValueObject { GrowableArray block_info_; GrowableArray deopt_infos_; GrowableArray slow_path_code_; + // Fields that were referenced by generated code. + // This list is needed by precompiler to ensure they are retained. + GrowableArray used_static_fields_; // Stores static call targets as well as stub targets. // TODO(srdjan): Evaluate if we should store allocation stub targets into a // separate table? diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index bbf1c878f4e5f..bf05108a27628 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -1086,10 +1086,6 @@ bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { return StaticField().raw() == other_load->StaticField().raw(); } -const Field& LoadStaticFieldInstr::StaticField() const { - return Field::Cast(field_value()->BoundConstant()); -} - bool LoadStaticFieldInstr::IsFieldInitialized() const { const Field& field = StaticField(); return (field.StaticValue() != Object::sentinel().raw()) && diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h index 520b6aa4f39d0..9dc9d4219d095 100644 --- a/runtime/vm/compiler/backend/il.h +++ b/runtime/vm/compiler/backend/il.h @@ -4929,22 +4929,17 @@ class GuardFieldTypeInstr : public GuardFieldInstr { DISALLOW_COPY_AND_ASSIGN(GuardFieldTypeInstr); }; -class LoadStaticFieldInstr : public TemplateDefinition<1, NoThrow> { +class LoadStaticFieldInstr : public TemplateDefinition<0, NoThrow> { public: - LoadStaticFieldInstr(Value* field_value, TokenPosition token_pos) - : token_pos_(token_pos) { - ASSERT(field_value->BindsToConstant()); - SetInputAt(0, field_value); - } + LoadStaticFieldInstr(const Field& field, TokenPosition token_pos) + : field_(field), token_pos_(token_pos) {} DECLARE_INSTRUCTION(LoadStaticField) virtual CompileType ComputeType() const; - const Field& StaticField() const; + const Field& StaticField() const { return field_; } bool IsFieldInitialized() const; - Value* field_value() const { return inputs_[0]; } - virtual bool ComputeCanDeoptimize() const { return false; } virtual bool AllowsCSE() const { @@ -4959,6 +4954,7 @@ class LoadStaticFieldInstr : public TemplateDefinition<1, NoThrow> { PRINT_OPERANDS_TO_SUPPORT private: + const Field& field_; const TokenPosition token_pos_; DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldInstr); @@ -5972,11 +5968,10 @@ class InitInstanceFieldInstr : public TemplateInstruction<1, Throws> { DISALLOW_COPY_AND_ASSIGN(InitInstanceFieldInstr); }; -class InitStaticFieldInstr : public TemplateInstruction<1, Throws> { +class InitStaticFieldInstr : public TemplateInstruction<0, Throws> { public: - InitStaticFieldInstr(Value* input, const Field& field, intptr_t deopt_id) + InitStaticFieldInstr(const Field& field, intptr_t deopt_id) : TemplateInstruction(deopt_id), field_(field) { - SetInputAt(0, input); CheckField(field); } diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index 950e48e8ee728..72dfe9f06cedc 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -2659,12 +2659,12 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; + const intptr_t kNumInputs = 0; + const intptr_t kNumTemps = 1; LocationSummary* summary = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - summary->set_in(0, Location::RequiresRegister()); summary->set_out(0, Location::RequiresRegister()); + summary->set_temp(0, Location::RequiresRegister()); return summary; } @@ -2674,10 +2674,19 @@ LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, // // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - const Register field = locs()->in(0).reg(); const Register result = locs()->out(0).reg(); - __ LoadFieldFromOffset(kWord, result, field, - compiler::target::Field::static_value_offset()); + const Register temp = locs()->temp(0).reg(); + + compiler->used_static_fields().Add(&StaticField()); + + __ LoadFromOffset(kWord, temp, THR, + compiler::target::Thread::field_table_values_offset()); + // Hot-reload has to guarantee that static fields will never change their + // "id", so we can embed the offset directly in the unoptimized code. + // The hot-reload code seems to maintain this guarantee only for non-enum + // classes. + __ LoadFromOffset(kWord, result, temp, + compiler::target::FieldTable::OffsetOf(StaticField())); } LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, @@ -2686,7 +2695,7 @@ LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, const intptr_t kNumTemps = 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - locs->set_in(0, Location::RegisterLocation(kWriteBarrierValueReg)); + locs->set_in(0, Location::RequiresRegister()); locs->set_temp(0, Location::RequiresRegister()); return locs; } @@ -2695,21 +2704,13 @@ void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const Register value = locs()->in(0).reg(); const Register temp = locs()->temp(0).reg(); - __ LoadObject(temp, Field::ZoneHandle(Z, field().Original())); - if (this->value()->NeedsWriteBarrier()) { - __ StoreIntoObject( - temp, - compiler::FieldAddress(temp, - compiler::target::Field::static_value_offset()), - value, CanValueBeSmi(), - /*lr_reserved=*/!compiler->intrinsic_mode()); - } else { - __ StoreIntoObjectNoBarrier( - temp, - compiler::FieldAddress(temp, - compiler::target::Field::static_value_offset()), - value); - } + compiler->used_static_fields().Add(&field()); + + __ LoadFromOffset(kWord, temp, THR, + compiler::target::Thread::field_table_values_offset()); + // Note: static fields ids won't be changed by hot-reload. + __ StoreToOffset(kWord, value, temp, + compiler::target::FieldTable::OffsetOf(field())); } LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone, @@ -3221,22 +3222,24 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* InitStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; + const intptr_t kNumInputs = 0; const intptr_t kNumTemps = 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(R0)); locs->set_temp(0, Location::RegisterLocation(R1)); return locs; } void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - Register field = locs()->in(0).reg(); Register temp = locs()->temp(0).reg(); compiler::Label call_runtime, no_call; - __ ldr(temp, compiler::FieldAddress( - field, compiler::target::Field::static_value_offset())); + __ LoadFromOffset(kWord, temp, THR, + compiler::target::Thread::field_table_values_offset()); + // Note: static fields ids won't be changed by hot-reload. + __ LoadFromOffset(kWord, temp, temp, + compiler::target::FieldTable::OffsetOf(field())); + __ CompareObject(temp, Object::sentinel()); __ b(&call_runtime, EQ); @@ -3245,7 +3248,7 @@ void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ Bind(&call_runtime); __ PushObject(Object::null_object()); // Make room for (unused) result. - __ Push(field); + __ PushObject(Field::ZoneHandle(field().Original())); compiler->GenerateRuntimeCall(token_pos(), deopt_id(), kInitStaticFieldRuntimeEntry, 1, locs()); __ Drop(2); // Remove argument and result placeholder. diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc index 8ed4ea91ac513..c9af45bfba843 100644 --- a/runtime/vm/compiler/backend/il_arm64.cc +++ b/runtime/vm/compiler/backend/il_arm64.cc @@ -2246,12 +2246,12 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; + const intptr_t kNumInputs = 0; + const intptr_t kNumTemps = 1; LocationSummary* summary = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - summary->set_in(0, Location::RequiresRegister()); summary->set_out(0, Location::RequiresRegister()); + summary->set_temp(0, Location::RequiresRegister()); return summary; } @@ -2261,16 +2261,25 @@ LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, // // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - const Register field = locs()->in(0).reg(); const Register result = locs()->out(0).reg(); - __ LoadFieldFromOffset(result, field, Field::static_value_offset()); + const Register temp = locs()->temp(0).reg(); + + compiler->used_static_fields().Add(&StaticField()); + + __ LoadFromOffset(temp, THR, + compiler::target::Thread::field_table_values_offset()); + // Note: static fields ids won't be changed by hot-reload. + __ LoadFromOffset(result, temp, + compiler::target::FieldTable::OffsetOf(StaticField())); } LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - LocationSummary* locs = - new (zone) LocationSummary(zone, 1, 1, LocationSummary::kNoCall); - locs->set_in(0, Location::RegisterLocation(kWriteBarrierValueReg)); + const intptr_t kNumInputs = 1; + const intptr_t kNumTemps = 1; + LocationSummary* locs = new (zone) + LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); + locs->set_in(0, Location::RequiresRegister()); locs->set_temp(0, Location::RequiresRegister()); return locs; } @@ -2279,15 +2288,13 @@ void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const Register value = locs()->in(0).reg(); const Register temp = locs()->temp(0).reg(); - __ LoadObject(temp, Field::ZoneHandle(Z, field().Original())); - if (this->value()->NeedsWriteBarrier()) { - __ StoreIntoObjectOffset(temp, Field::static_value_offset(), value, - CanValueBeSmi(), - /*lr_reserved=*/!compiler->intrinsic_mode()); - } else { - __ StoreIntoObjectOffsetNoBarrier(temp, Field::static_value_offset(), - value); - } + compiler->used_static_fields().Add(&field()); + + __ LoadFromOffset(temp, THR, + compiler::target::Thread::field_table_values_offset()); + // Note: static fields ids won't be changed by hot-reload. + __ StoreToOffset(value, temp, + compiler::target::FieldTable::OffsetOf(field())); } LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone, @@ -2780,21 +2787,23 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* InitStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; + const intptr_t kNumInputs = 0; const intptr_t kNumTemps = 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(R0)); locs->set_temp(0, Location::RegisterLocation(R1)); return locs; } void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - Register field = locs()->in(0).reg(); Register temp = locs()->temp(0).reg(); compiler::Label call_runtime, no_call; - __ ldr(temp, compiler::FieldAddress(field, Field::static_value_offset())); + __ LoadFromOffset(temp, THR, + compiler::target::Thread::field_table_values_offset()); + // Note: static fields ids won't be changed by hot-reload. + __ LoadFromOffset(temp, temp, + compiler::target::FieldTable::OffsetOf(field())); __ CompareObject(temp, Object::sentinel()); __ b(&call_runtime, EQ); @@ -2802,7 +2811,8 @@ void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ b(&no_call, NE); __ Bind(&call_runtime); - __ PushPair(field, NULL_REG); + __ Push(NULL_REG); + __ PushObject(Field::ZoneHandle(field().Original())); compiler->GenerateRuntimeCall(token_pos(), deopt_id(), kInitStaticFieldRuntimeEntry, 1, locs()); __ Drop(2); // Remove argument and result placeholder. diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc index 1cf298b4e537a..651ffb53008e0 100644 --- a/runtime/vm/compiler/backend/il_ia32.cc +++ b/runtime/vm/compiler/backend/il_ia32.cc @@ -2208,14 +2208,12 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; + const intptr_t kNumInputs = 0; + const intptr_t kNumTemps = 1; LocationSummary* summary = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - summary->set_in(0, Location::RequiresRegister()); - // By specifying same register as input, our simple register allocator can - // generate better code. - summary->set_out(0, Location::SameAsFirstInput()); + summary->set_temp(0, Location::RequiresRegister()); + summary->set_out(0, Location::RequiresRegister()); return summary; } @@ -2225,9 +2223,18 @@ LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, // // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - Register field = locs()->in(0).reg(); Register result = locs()->out(0).reg(); - __ movl(result, compiler::FieldAddress(field, Field::static_value_offset())); + Register temp = locs()->temp(0).reg(); + + compiler->used_static_fields().Add(&StaticField()); + + __ movl(temp, + compiler::Address( + THR, compiler::target::Thread::field_table_values_offset())); + // Note: static fields ids won't be changed by hot-reload. + __ movl(result, + compiler::Address( + temp, compiler::target::FieldTable::OffsetOf(StaticField()))); } LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, @@ -2244,16 +2251,15 @@ void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { Register value = locs()->in(0).reg(); Register temp = locs()->temp(0).reg(); - __ LoadObject(temp, Field::ZoneHandle(Z, field().Original())); - if (this->value()->NeedsWriteBarrier()) { - __ StoreIntoObject( - temp, compiler::FieldAddress(temp, Field::static_value_offset()), value, - CanValueBeSmi()); - } else { - __ StoreIntoObjectNoBarrier( - temp, compiler::FieldAddress(temp, Field::static_value_offset()), - value); - } + compiler->used_static_fields().Add(&field()); + + __ movl(temp, + compiler::Address( + THR, compiler::target::Thread::field_table_values_offset())); + // Note: static fields ids won't be changed by hot-reload. + __ movl( + compiler::Address(temp, compiler::target::FieldTable::OffsetOf(field())), + value); } LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone, @@ -2766,22 +2772,25 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* InitStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; + const intptr_t kNumInputs = 0; const intptr_t kNumTemps = 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(EAX)); locs->set_temp(0, Location::RegisterLocation(ECX)); return locs; } void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - Register field = locs()->in(0).reg(); Register temp = locs()->temp(0).reg(); compiler::Label call_runtime, no_call; - __ movl(temp, compiler::FieldAddress(field, Field::static_value_offset())); + __ movl(temp, + compiler::Address( + THR, compiler::target::Thread::field_table_values_offset())); + // Note: static fields ids won't be changed by hot-reload. + __ movl(temp, compiler::Address( + temp, compiler::target::FieldTable::OffsetOf(field()))); __ CompareObject(temp, Object::sentinel()); __ j(EQUAL, &call_runtime); @@ -2790,7 +2799,7 @@ void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ Bind(&call_runtime); __ PushObject(Object::null_object()); // Make room for (unused) result. - __ pushl(field); + __ PushObject(Field::ZoneHandle(field().Original())); compiler->GenerateRuntimeCall(token_pos(), deopt_id(), kInitStaticFieldRuntimeEntry, 1, locs()); __ Drop(2); // Remove argument and unused result. diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc index eb9c1b44ce08b..2769729afd09b 100644 --- a/runtime/vm/compiler/backend/il_printer.cc +++ b/runtime/vm/compiler/backend/il_printer.cc @@ -638,7 +638,7 @@ void IfThenElseInstr::PrintOperandsTo(BufferFormatter* f) const { } void LoadStaticFieldInstr::PrintOperandsTo(BufferFormatter* f) const { - field_value()->PrintTo(f); + f->Print("%s", String::Handle(StaticField().name()).ToCString()); } void StoreStaticFieldInstr::PrintOperandsTo(BufferFormatter* f) const { diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc index 836403674992e..3a3045f5906e2 100644 --- a/runtime/vm/compiler/backend/il_x64.cc +++ b/runtime/vm/compiler/backend/il_x64.cc @@ -2343,13 +2343,13 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; - LocationSummary* summary = new (zone) + const intptr_t kNumInputs = 0; + const intptr_t kNumTemps = 1; + LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - summary->set_in(0, Location::RequiresRegister()); - summary->set_out(0, Location::RequiresRegister()); - return summary; + locs->set_out(0, Location::RequiresRegister()); + locs->set_temp(0, Location::RequiresRegister()); + return locs; } // When the parser is building an implicit static getter for optimization, @@ -2358,15 +2358,26 @@ LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, // // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - Register field = locs()->in(0).reg(); Register result = locs()->out(0).reg(); - __ movq(result, compiler::FieldAddress(field, Field::static_value_offset())); + Register temp = locs()->temp(0).reg(); + + compiler->used_static_fields().Add(&StaticField()); + + __ movq(temp, + compiler::Address( + THR, compiler::target::Thread::field_table_values_offset())); + // Note: static fields ids won't be changed by hot-reload. + __ movq(result, + compiler::Address( + temp, compiler::target::FieldTable::OffsetOf(StaticField()))); } LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - LocationSummary* locs = - new (zone) LocationSummary(zone, 1, 1, LocationSummary::kNoCall); + const intptr_t kNumInputs = 1; + const intptr_t kNumTemps = 1; + LocationSummary* locs = new (zone) + LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); locs->set_in(0, Location::RegisterLocation(kWriteBarrierValueReg)); locs->set_temp(0, Location::RequiresRegister()); return locs; @@ -2376,16 +2387,15 @@ void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { Register value = locs()->in(0).reg(); Register temp = locs()->temp(0).reg(); - __ LoadObject(temp, Field::ZoneHandle(Z, field().Original())); - if (this->value()->NeedsWriteBarrier()) { - __ StoreIntoObject( - temp, compiler::FieldAddress(temp, Field::static_value_offset()), value, - CanValueBeSmi()); - } else { - __ StoreIntoObjectNoBarrier( - temp, compiler::FieldAddress(temp, Field::static_value_offset()), - value); - } + compiler->used_static_fields().Add(&field()); + + __ movq(temp, + compiler::Address( + THR, compiler::target::Thread::field_table_values_offset())); + // Note: static fields ids won't be changed by hot-reload. + __ movq( + compiler::Address(temp, compiler::target::FieldTable::OffsetOf(field())), + value); } LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone, @@ -2899,22 +2909,25 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* InitStaticFieldInstr::MakeLocationSummary(Zone* zone, bool opt) const { - const intptr_t kNumInputs = 1; + const intptr_t kNumInputs = 0; const intptr_t kNumTemps = 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(RAX)); locs->set_temp(0, Location::RegisterLocation(RCX)); return locs; } void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - Register field = locs()->in(0).reg(); Register temp = locs()->temp(0).reg(); compiler::Label call_runtime, no_call; - __ movq(temp, compiler::FieldAddress(field, Field::static_value_offset())); + __ movq(temp, + compiler::Address( + THR, compiler::target::Thread::field_table_values_offset())); + // Note: static fields ids won't be changed by hot-reload. + __ movq(temp, compiler::Address( + temp, compiler::target::FieldTable::OffsetOf(field()))); __ CompareObject(temp, Object::sentinel()); __ j(EQUAL, &call_runtime); @@ -2923,7 +2936,7 @@ void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ Bind(&call_runtime); __ PushObject(Object::null_object()); // Make room for (unused) result. - __ pushq(field); + __ PushObject(Field::ZoneHandle(field().Original())); compiler->GenerateRuntimeCall(token_pos(), deopt_id(), kInitStaticFieldRuntimeEntry, 1, locs()); __ Drop(2); // Remove argument and unused result. diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc index 796d977fb5059..77272f1c3bfb4 100644 --- a/runtime/vm/compiler/backend/type_propagator_test.cc +++ b/runtime/vm/compiler/backend/type_propagator_test.cc @@ -253,8 +253,7 @@ ISOLATE_UNIT_TEST_CASE(TypePropagator_Refinement) { EXPECT_PROPERTY(v2->Type(), it.IsNullableInt()); EXPECT_PROPERTY(v3->Type(), it.IsNullableInt()); - auto v4 = new LoadStaticFieldInstr( - new Value(H.flow_graph()->GetConstant(field)), TokenPosition::kNoSource); + auto v4 = new LoadStaticFieldInstr(field, TokenPosition::kNoSource); H.flow_graph()->InsertBefore(v2, v4, nullptr, FlowGraph::kValue); v2->ReplaceUsesWith(v4); v2->RemoveFromGraph(); diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc index c19f38e9d6a22..37d991b13e7ea 100644 --- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc @@ -530,9 +530,9 @@ Fragment BaseFlowGraphBuilder::StoreInstanceFieldGuarded( return instructions; } -Fragment BaseFlowGraphBuilder::LoadStaticField() { +Fragment BaseFlowGraphBuilder::LoadStaticField(const Field& field) { LoadStaticFieldInstr* load = - new (Z) LoadStaticFieldInstr(Pop(), TokenPosition::kNoSource); + new (Z) LoadStaticFieldInstr(field, TokenPosition::kNoSource); Push(load); return Fragment(load); } diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h index c565459e10fcf..17554e9666e2a 100644 --- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h +++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h @@ -197,7 +197,7 @@ class BaseFlowGraphBuilder { Fragment StoreInstanceFieldGuarded(const Field& field, StoreInstanceFieldInstr::Kind kind = StoreInstanceFieldInstr::Kind::kOther); - Fragment LoadStaticField(); + Fragment LoadStaticField(const Field& field); Fragment RedefinitionWithType(const AbstractType& type); Fragment StoreStaticField(TokenPosition position, const Field& field); Fragment StoreIndexed(classid_t class_id); diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc index b4af4dc8a123a..740197d93a978 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc @@ -1351,8 +1351,7 @@ void BytecodeFlowGraphBuilder::BuildLoadStatic() { code_ += B->Constant(value); return; } - PushConstant(operand); - code_ += B->LoadStaticField(); + code_ += B->LoadStaticField(field); } void BytecodeFlowGraphBuilder::BuildStoreIndexedTOS() { diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index 62dc147207bc3..c68dfbbbb6fa6 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -1652,8 +1652,8 @@ Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) { return flow_graph_builder_->IntConstant(value); } -Fragment StreamingFlowGraphBuilder::LoadStaticField() { - return flow_graph_builder_->LoadStaticField(); +Fragment StreamingFlowGraphBuilder::LoadStaticField(const Field& field) { + return flow_graph_builder_->LoadStaticField(field); } Fragment StreamingFlowGraphBuilder::RedefinitionWithType( @@ -2745,8 +2745,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) { if (result_type.IsConstant()) { return Constant(result_type.constant_value); } - Fragment instructions = Constant(field); - return instructions + LoadStaticField(); + return LoadStaticField(field); } } } else { diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h index 62666df347afc..99aeaa024fd34 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h @@ -164,7 +164,7 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper { Fragment ThrowNoSuchMethodError(); Fragment Constant(const Object& value); Fragment IntConstant(int64_t value); - Fragment LoadStaticField(); + Fragment LoadStaticField(const Field& field); Fragment RedefinitionWithType(const AbstractType& type); Fragment CheckNull(TokenPosition position, LocalVariable* receiver, diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index d9af89482cf32..d2ff1e0db4aef 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -443,8 +443,7 @@ Fragment FlowGraphBuilder::LoadLateField(const Field& field, // Check whether the field has been initialized already. if (is_static) { - instructions += Constant(field); - instructions += LoadStaticField(); + instructions += LoadStaticField(field); } else { instructions += LoadLocal(instance); instructions += LoadField(field); @@ -532,8 +531,7 @@ Fragment FlowGraphBuilder::StoreLateField(const Field& field, if (is_final) { // Check whether the field has been initialized already. if (is_static) { - instructions += Constant(field); - instructions += LoadStaticField(); + instructions += LoadStaticField(field); } else { instructions += LoadLocal(instance); instructions += LoadField(field); @@ -582,8 +580,8 @@ Fragment FlowGraphBuilder::InitInstanceField(const Field& field) { } Fragment FlowGraphBuilder::InitStaticField(const Field& field) { - InitStaticFieldInstr* init = new (Z) - InitStaticFieldInstr(Pop(), MayCloneField(field), GetNextDeoptId()); + InitStaticFieldInstr* init = + new (Z) InitStaticFieldInstr(MayCloneField(field), GetNextDeoptId()); return Fragment(init); } @@ -2724,10 +2722,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor( body += LoadLateField(field, /* instance = */ nullptr); } else { ASSERT(field.has_nontrivial_initializer()); - body += Constant(field); body += InitStaticField(field); - body += Constant(field); - body += LoadStaticField(); + body += LoadStaticField(field); } if (field.needs_load_guard()) { #if defined(PRODUCT) diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc index 67efe20fd9bc7..63299eec0ecaf 100644 --- a/runtime/vm/compiler/runtime_api.cc +++ b/runtime/vm/compiler/runtime_api.cc @@ -635,6 +635,11 @@ word Field::OffsetOf(const dart::Field& field) { return TranslateOffsetInWords(field.Offset()); } +word FieldTable::OffsetOf(const dart::Field& field) { + return TranslateOffsetInWords( + dart::FieldTable::FieldOffsetFor(field.field_id())); +} + } // namespace target } // namespace compiler } // namespace dart diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index c4fc3e085f248..b1d1bd3be1052 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -651,6 +651,7 @@ class Thread : public AllStatic { static word top_offset(); static word end_offset(); static word isolate_offset(); + static word field_table_values_offset(); static word store_buffer_block_offset(); static word call_to_runtime_entry_point_offset(); static word null_error_shared_with_fpu_regs_entry_point_offset(); @@ -908,6 +909,11 @@ class TypeArguments : public AllStatic { static word type_at_offset(intptr_t i); }; +class FieldTable : public AllStatic { + public: + static word OffsetOf(const dart::Field& field); +}; + } // namespace target } // namespace compiler } // namespace dart diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index c93b19686d14e..22595eac00afe 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -103,14 +103,13 @@ static constexpr dart::compiler::target::word ExternalTwoByteString_external_data_offset = 12; static constexpr dart::compiler::target::word Float32x4_value_offset = 8; static constexpr dart::compiler::target::word Float64x2_value_offset = 8; -static constexpr dart::compiler::target::word Field_guarded_cid_offset = 48; +static constexpr dart::compiler::target::word Field_guarded_cid_offset = 44; static constexpr dart::compiler::target::word - Field_guarded_list_length_in_object_offset_offset = 56; + Field_guarded_list_length_in_object_offset_offset = 52; static constexpr dart::compiler::target::word Field_guarded_list_length_offset = - 28; -static constexpr dart::compiler::target::word Field_is_nullable_offset = 50; -static constexpr dart::compiler::target::word Field_static_value_offset = 16; -static constexpr dart::compiler::target::word Field_kind_bits_offset = 58; + 24; +static constexpr dart::compiler::target::word Field_is_nullable_offset = 46; +static constexpr dart::compiler::target::word Field_kind_bits_offset = 60; static constexpr dart::compiler::target::word Function_code_offset = 44; static constexpr dart::compiler::target::word Function_entry_point_offset = 4; static constexpr dart::compiler::target::word @@ -138,7 +137,7 @@ static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word Isolate_object_store_offset = 36; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 60; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 64; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16; static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16; static constexpr dart::compiler::target::word @@ -204,7 +203,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_allocate_mint_without_fpu_regs_stub_offset = 164; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = - 88; + 92; static constexpr dart::compiler::target::word Thread_auto_scope_native_wrapper_entry_point_offset = 288; static constexpr dart::compiler::target::word Thread_bool_false_offset = 112; @@ -227,7 +226,7 @@ static constexpr dart::compiler::target::word Thread_double_abs_address_offset = 308; static constexpr dart::compiler::target::word Thread_double_negate_address_offset = 304; -static constexpr dart::compiler::target::word Thread_end_offset = 64; +static constexpr dart::compiler::target::word Thread_end_offset = 68; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 204; static constexpr dart::compiler::target::word Thread_execution_state_offset = @@ -259,6 +258,8 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 132; static constexpr dart::compiler::target::word Thread_isolate_offset = 52; +static constexpr dart::compiler::target::word Thread_field_table_values_offset = + 56; static constexpr dart::compiler::target::word Thread_lazy_deopt_from_return_stub_offset = 188; static constexpr dart::compiler::target::word @@ -266,7 +267,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_lazy_specialize_type_test_stub_offset = 200; static constexpr dart::compiler::target::word - Thread_marking_stack_block_offset = 76; + Thread_marking_stack_block_offset = 80; static constexpr dart::compiler::target::word Thread_megamorphic_call_checked_entry_offset = 260; static constexpr dart::compiler::target::word @@ -315,14 +316,14 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168; static constexpr dart::compiler::target::word Thread_store_buffer_block_offset = - 72; + 76; static constexpr dart::compiler::target::word - Thread_top_exit_frame_info_offset = 68; -static constexpr dart::compiler::target::word Thread_top_offset = 60; + Thread_top_exit_frame_info_offset = 72; +static constexpr dart::compiler::target::word Thread_top_offset = 64; static constexpr dart::compiler::target::word Thread_top_resource_offset = 24; static constexpr dart::compiler::target::word Thread_unboxed_int64_runtime_arg_offset = 96; -static constexpr dart::compiler::target::word Thread_vm_tag_offset = 84; +static constexpr dart::compiler::target::word Thread_vm_tag_offset = 88; static constexpr dart::compiler::target::word Thread_write_barrier_code_offset = 116; static constexpr dart::compiler::target::word @@ -476,14 +477,13 @@ static constexpr dart::compiler::target::word ExternalTwoByteString_external_data_offset = 16; static constexpr dart::compiler::target::word Float32x4_value_offset = 8; static constexpr dart::compiler::target::word Float64x2_value_offset = 8; -static constexpr dart::compiler::target::word Field_guarded_cid_offset = 88; +static constexpr dart::compiler::target::word Field_guarded_cid_offset = 80; static constexpr dart::compiler::target::word - Field_guarded_list_length_in_object_offset_offset = 96; + Field_guarded_list_length_in_object_offset_offset = 88; static constexpr dart::compiler::target::word Field_guarded_list_length_offset = - 56; -static constexpr dart::compiler::target::word Field_is_nullable_offset = 90; -static constexpr dart::compiler::target::word Field_static_value_offset = 32; -static constexpr dart::compiler::target::word Field_kind_bits_offset = 98; + 48; +static constexpr dart::compiler::target::word Field_is_nullable_offset = 82; +static constexpr dart::compiler::target::word Field_kind_bits_offset = 104; static constexpr dart::compiler::target::word Function_code_offset = 88; static constexpr dart::compiler::target::word Function_entry_point_offset = 8; static constexpr dart::compiler::target::word @@ -511,7 +511,7 @@ static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word Isolate_object_store_offset = 72; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 120; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 128; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32; static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32; static constexpr dart::compiler::target::word @@ -559,151 +559,153 @@ static constexpr dart::compiler::target::word String_hash_offset = 4; static constexpr dart::compiler::target::word String_length_offset = 8; static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8; static constexpr dart::compiler::target::word - Thread_AllocateArray_entry_point_offset = 640; + Thread_AllocateArray_entry_point_offset = 648; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 1336; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 1344; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 1352; static constexpr dart::compiler::target::word - Thread_array_write_barrier_code_offset = 224; + Thread_array_write_barrier_code_offset = 232; static constexpr dart::compiler::target::word - Thread_array_write_barrier_entry_point_offset = 424; + Thread_array_write_barrier_entry_point_offset = 432; static constexpr dart::compiler::target::word - Thread_allocate_mint_with_fpu_regs_entry_point_offset = 472; + Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480; static constexpr dart::compiler::target::word - Thread_allocate_mint_with_fpu_regs_stub_offset = 304; + Thread_allocate_mint_with_fpu_regs_stub_offset = 312; static constexpr dart::compiler::target::word - Thread_allocate_mint_without_fpu_regs_entry_point_offset = 480; + Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488; static constexpr dart::compiler::target::word - Thread_allocate_mint_without_fpu_regs_stub_offset = 312; + Thread_allocate_mint_without_fpu_regs_stub_offset = 320; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = - 176; + 184; static constexpr dart::compiler::target::word - Thread_auto_scope_native_wrapper_entry_point_offset = 560; -static constexpr dart::compiler::target::word Thread_bool_false_offset = 208; -static constexpr dart::compiler::target::word Thread_bool_true_offset = 200; + Thread_auto_scope_native_wrapper_entry_point_offset = 568; +static constexpr dart::compiler::target::word Thread_bool_false_offset = 216; +static constexpr dart::compiler::target::word Thread_bool_true_offset = 208; static constexpr dart::compiler::target::word - Thread_bootstrap_native_wrapper_entry_point_offset = 544; + Thread_bootstrap_native_wrapper_entry_point_offset = 552; static constexpr dart::compiler::target::word - Thread_call_to_runtime_entry_point_offset = 432; + Thread_call_to_runtime_entry_point_offset = 440; static constexpr dart::compiler::target::word - Thread_call_to_runtime_stub_offset = 264; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1408; + Thread_call_to_runtime_stub_offset = 272; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1416; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = - 520; -static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 344; -static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset = 528; +static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 352; +static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset = + 536; static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset = - 352; + 360; static constexpr dart::compiler::target::word Thread_double_abs_address_offset = - 600; + 608; static constexpr dart::compiler::target::word - Thread_double_negate_address_offset = 592; -static constexpr dart::compiler::target::word Thread_end_offset = 128; + Thread_double_negate_address_offset = 600; +static constexpr dart::compiler::target::word Thread_end_offset = 136; static constexpr dart::compiler::target::word - Thread_enter_safepoint_stub_offset = 392; + Thread_enter_safepoint_stub_offset = 400; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 1376; + 1384; static constexpr dart::compiler::target::word - Thread_exit_safepoint_stub_offset = 400; + Thread_exit_safepoint_stub_offset = 408; static constexpr dart::compiler::target::word - Thread_call_native_through_safepoint_stub_offset = 408; + Thread_call_native_through_safepoint_stub_offset = 416; static constexpr dart::compiler::target::word - Thread_call_native_through_safepoint_entry_point_offset = 536; + Thread_call_native_through_safepoint_entry_point_offset = 544; static constexpr dart::compiler::target::word - Thread_fix_allocation_stub_code_offset = 240; + Thread_fix_allocation_stub_code_offset = 248; static constexpr dart::compiler::target::word - Thread_fix_callers_target_code_offset = 232; + Thread_fix_callers_target_code_offset = 240; static constexpr dart::compiler::target::word - Thread_float_absolute_address_offset = 624; + Thread_float_absolute_address_offset = 632; static constexpr dart::compiler::target::word - Thread_float_negate_address_offset = 616; + Thread_float_negate_address_offset = 624; static constexpr dart::compiler::target::word Thread_float_not_address_offset = - 608; + 616; static constexpr dart::compiler::target::word - Thread_float_zerow_address_offset = 632; + Thread_float_zerow_address_offset = 640; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 1352; + 1360; static constexpr dart::compiler::target::word - Thread_interpret_call_entry_point_offset = 568; + Thread_interpret_call_entry_point_offset = 576; static constexpr dart::compiler::target::word - Thread_invoke_dart_code_from_bytecode_stub_offset = 256; + Thread_invoke_dart_code_from_bytecode_stub_offset = 264; static constexpr dart::compiler::target::word - Thread_invoke_dart_code_stub_offset = 248; + Thread_invoke_dart_code_stub_offset = 256; static constexpr dart::compiler::target::word Thread_isolate_offset = 104; +static constexpr dart::compiler::target::word Thread_field_table_values_offset = + 112; static constexpr dart::compiler::target::word - Thread_lazy_deopt_from_return_stub_offset = 360; + Thread_lazy_deopt_from_return_stub_offset = 368; static constexpr dart::compiler::target::word - Thread_lazy_deopt_from_throw_stub_offset = 368; + Thread_lazy_deopt_from_throw_stub_offset = 376; static constexpr dart::compiler::target::word - Thread_lazy_specialize_type_test_stub_offset = 384; + Thread_lazy_specialize_type_test_stub_offset = 392; static constexpr dart::compiler::target::word - Thread_marking_stack_block_offset = 152; + Thread_marking_stack_block_offset = 160; static constexpr dart::compiler::target::word - Thread_megamorphic_call_checked_entry_offset = 504; + Thread_megamorphic_call_checked_entry_offset = 512; static constexpr dart::compiler::target::word - Thread_monomorphic_miss_entry_offset = 512; + Thread_monomorphic_miss_entry_offset = 520; static constexpr dart::compiler::target::word - Thread_monomorphic_miss_stub_offset = 336; + Thread_monomorphic_miss_stub_offset = 344; static constexpr dart::compiler::target::word - Thread_no_scope_native_wrapper_entry_point_offset = 552; + Thread_no_scope_native_wrapper_entry_point_offset = 560; static constexpr dart::compiler::target::word - Thread_null_error_shared_with_fpu_regs_entry_point_offset = 448; + Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456; static constexpr dart::compiler::target::word - Thread_null_error_shared_with_fpu_regs_stub_offset = 280; + Thread_null_error_shared_with_fpu_regs_stub_offset = 288; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 464; + Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 296; + Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304; static constexpr dart::compiler::target::word - Thread_null_error_shared_without_fpu_regs_entry_point_offset = 440; + Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448; static constexpr dart::compiler::target::word - Thread_null_error_shared_without_fpu_regs_stub_offset = 272; + Thread_null_error_shared_without_fpu_regs_stub_offset = 280; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 456; + Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 288; -static constexpr dart::compiler::target::word Thread_object_null_offset = 192; + Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296; +static constexpr dart::compiler::target::word Thread_object_null_offset = 200; static constexpr dart::compiler::target::word - Thread_predefined_symbols_address_offset = 576; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1360; + Thread_predefined_symbols_address_offset = 584; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1368; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 1368; + Thread_saved_shadow_call_stack_offset = 1376; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 1384; + 1392; static constexpr dart::compiler::target::word - Thread_slow_type_test_stub_offset = 376; + Thread_slow_type_test_stub_offset = 384; static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72; static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset = 80; static constexpr dart::compiler::target::word Thread_stack_overflow_flags_offset = 88; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 496; + Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 328; + Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 488; + Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 320; + Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328; static constexpr dart::compiler::target::word Thread_store_buffer_block_offset = - 144; + 152; static constexpr dart::compiler::target::word - Thread_top_exit_frame_info_offset = 136; -static constexpr dart::compiler::target::word Thread_top_offset = 120; + Thread_top_exit_frame_info_offset = 144; +static constexpr dart::compiler::target::word Thread_top_offset = 128; static constexpr dart::compiler::target::word Thread_top_resource_offset = 48; static constexpr dart::compiler::target::word - Thread_unboxed_int64_runtime_arg_offset = 184; -static constexpr dart::compiler::target::word Thread_vm_tag_offset = 168; + Thread_unboxed_int64_runtime_arg_offset = 192; +static constexpr dart::compiler::target::word Thread_vm_tag_offset = 176; static constexpr dart::compiler::target::word Thread_write_barrier_code_offset = - 216; + 224; static constexpr dart::compiler::target::word - Thread_write_barrier_entry_point_offset = 416; + Thread_write_barrier_entry_point_offset = 424; static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 96; static constexpr dart::compiler::target::word Thread_callback_code_offset = - 1392; + 1400; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word TwoByteString_data_offset = 16; @@ -738,8 +740,8 @@ static constexpr dart::compiler::target::word Code_function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 1248, 1256, 1264, 1272, -1, -1, 1280, 1288, - 1296, 1304, 1312, -1, 1320, 1328, -1, -1}; + 1256, 1264, 1272, 1280, -1, -1, 1288, 1296, + 1304, 1312, 1320, -1, 1328, 1336, -1, -1}; static constexpr dart::compiler::target::word Array_header_size = 24; static constexpr dart::compiler::target::word Context_header_size = 24; static constexpr dart::compiler::target::word Double_InstanceSize = 16; @@ -849,14 +851,13 @@ static constexpr dart::compiler::target::word ExternalTwoByteString_external_data_offset = 12; static constexpr dart::compiler::target::word Float32x4_value_offset = 8; static constexpr dart::compiler::target::word Float64x2_value_offset = 8; -static constexpr dart::compiler::target::word Field_guarded_cid_offset = 48; +static constexpr dart::compiler::target::word Field_guarded_cid_offset = 44; static constexpr dart::compiler::target::word - Field_guarded_list_length_in_object_offset_offset = 56; + Field_guarded_list_length_in_object_offset_offset = 52; static constexpr dart::compiler::target::word Field_guarded_list_length_offset = - 28; -static constexpr dart::compiler::target::word Field_is_nullable_offset = 50; -static constexpr dart::compiler::target::word Field_static_value_offset = 16; -static constexpr dart::compiler::target::word Field_kind_bits_offset = 58; + 24; +static constexpr dart::compiler::target::word Field_is_nullable_offset = 46; +static constexpr dart::compiler::target::word Field_kind_bits_offset = 60; static constexpr dart::compiler::target::word Function_code_offset = 44; static constexpr dart::compiler::target::word Function_entry_point_offset = 4; static constexpr dart::compiler::target::word @@ -884,7 +885,7 @@ static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word Isolate_object_store_offset = 36; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 60; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 64; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16; static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16; static constexpr dart::compiler::target::word @@ -950,7 +951,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_allocate_mint_without_fpu_regs_stub_offset = 164; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = - 88; + 92; static constexpr dart::compiler::target::word Thread_auto_scope_native_wrapper_entry_point_offset = 288; static constexpr dart::compiler::target::word Thread_bool_false_offset = 112; @@ -973,7 +974,7 @@ static constexpr dart::compiler::target::word Thread_double_abs_address_offset = 308; static constexpr dart::compiler::target::word Thread_double_negate_address_offset = 304; -static constexpr dart::compiler::target::word Thread_end_offset = 64; +static constexpr dart::compiler::target::word Thread_end_offset = 68; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 204; static constexpr dart::compiler::target::word Thread_execution_state_offset = @@ -1005,6 +1006,8 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 132; static constexpr dart::compiler::target::word Thread_isolate_offset = 52; +static constexpr dart::compiler::target::word Thread_field_table_values_offset = + 56; static constexpr dart::compiler::target::word Thread_lazy_deopt_from_return_stub_offset = 188; static constexpr dart::compiler::target::word @@ -1012,7 +1015,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_lazy_specialize_type_test_stub_offset = 200; static constexpr dart::compiler::target::word - Thread_marking_stack_block_offset = 76; + Thread_marking_stack_block_offset = 80; static constexpr dart::compiler::target::word Thread_megamorphic_call_checked_entry_offset = 260; static constexpr dart::compiler::target::word @@ -1061,14 +1064,14 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168; static constexpr dart::compiler::target::word Thread_store_buffer_block_offset = - 72; + 76; static constexpr dart::compiler::target::word - Thread_top_exit_frame_info_offset = 68; -static constexpr dart::compiler::target::word Thread_top_offset = 60; + Thread_top_exit_frame_info_offset = 72; +static constexpr dart::compiler::target::word Thread_top_offset = 64; static constexpr dart::compiler::target::word Thread_top_resource_offset = 24; static constexpr dart::compiler::target::word Thread_unboxed_int64_runtime_arg_offset = 96; -static constexpr dart::compiler::target::word Thread_vm_tag_offset = 84; +static constexpr dart::compiler::target::word Thread_vm_tag_offset = 88; static constexpr dart::compiler::target::word Thread_write_barrier_code_offset = 116; static constexpr dart::compiler::target::word @@ -1218,14 +1221,13 @@ static constexpr dart::compiler::target::word ExternalTwoByteString_external_data_offset = 16; static constexpr dart::compiler::target::word Float32x4_value_offset = 8; static constexpr dart::compiler::target::word Float64x2_value_offset = 8; -static constexpr dart::compiler::target::word Field_guarded_cid_offset = 88; +static constexpr dart::compiler::target::word Field_guarded_cid_offset = 80; static constexpr dart::compiler::target::word - Field_guarded_list_length_in_object_offset_offset = 96; + Field_guarded_list_length_in_object_offset_offset = 88; static constexpr dart::compiler::target::word Field_guarded_list_length_offset = - 56; -static constexpr dart::compiler::target::word Field_is_nullable_offset = 90; -static constexpr dart::compiler::target::word Field_static_value_offset = 32; -static constexpr dart::compiler::target::word Field_kind_bits_offset = 98; + 48; +static constexpr dart::compiler::target::word Field_is_nullable_offset = 82; +static constexpr dart::compiler::target::word Field_kind_bits_offset = 104; static constexpr dart::compiler::target::word Function_code_offset = 88; static constexpr dart::compiler::target::word Function_entry_point_offset = 8; static constexpr dart::compiler::target::word @@ -1253,7 +1255,7 @@ static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word Isolate_object_store_offset = 72; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 120; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 128; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32; static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32; static constexpr dart::compiler::target::word @@ -1301,151 +1303,153 @@ static constexpr dart::compiler::target::word String_hash_offset = 4; static constexpr dart::compiler::target::word String_length_offset = 8; static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8; static constexpr dart::compiler::target::word - Thread_AllocateArray_entry_point_offset = 640; + Thread_AllocateArray_entry_point_offset = 648; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 1416; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 1424; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 1432; static constexpr dart::compiler::target::word - Thread_array_write_barrier_code_offset = 224; + Thread_array_write_barrier_code_offset = 232; static constexpr dart::compiler::target::word - Thread_array_write_barrier_entry_point_offset = 424; + Thread_array_write_barrier_entry_point_offset = 432; static constexpr dart::compiler::target::word - Thread_allocate_mint_with_fpu_regs_entry_point_offset = 472; + Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480; static constexpr dart::compiler::target::word - Thread_allocate_mint_with_fpu_regs_stub_offset = 304; + Thread_allocate_mint_with_fpu_regs_stub_offset = 312; static constexpr dart::compiler::target::word - Thread_allocate_mint_without_fpu_regs_entry_point_offset = 480; + Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488; static constexpr dart::compiler::target::word - Thread_allocate_mint_without_fpu_regs_stub_offset = 312; + Thread_allocate_mint_without_fpu_regs_stub_offset = 320; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = - 176; + 184; static constexpr dart::compiler::target::word - Thread_auto_scope_native_wrapper_entry_point_offset = 560; -static constexpr dart::compiler::target::word Thread_bool_false_offset = 208; -static constexpr dart::compiler::target::word Thread_bool_true_offset = 200; + Thread_auto_scope_native_wrapper_entry_point_offset = 568; +static constexpr dart::compiler::target::word Thread_bool_false_offset = 216; +static constexpr dart::compiler::target::word Thread_bool_true_offset = 208; static constexpr dart::compiler::target::word - Thread_bootstrap_native_wrapper_entry_point_offset = 544; + Thread_bootstrap_native_wrapper_entry_point_offset = 552; static constexpr dart::compiler::target::word - Thread_call_to_runtime_entry_point_offset = 432; + Thread_call_to_runtime_entry_point_offset = 440; static constexpr dart::compiler::target::word - Thread_call_to_runtime_stub_offset = 264; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1488; + Thread_call_to_runtime_stub_offset = 272; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1496; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = - 520; -static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 344; -static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset = 528; +static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 352; +static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset = + 536; static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset = - 352; + 360; static constexpr dart::compiler::target::word Thread_double_abs_address_offset = - 600; + 608; static constexpr dart::compiler::target::word - Thread_double_negate_address_offset = 592; -static constexpr dart::compiler::target::word Thread_end_offset = 128; + Thread_double_negate_address_offset = 600; +static constexpr dart::compiler::target::word Thread_end_offset = 136; static constexpr dart::compiler::target::word - Thread_enter_safepoint_stub_offset = 392; + Thread_enter_safepoint_stub_offset = 400; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 1456; + 1464; static constexpr dart::compiler::target::word - Thread_exit_safepoint_stub_offset = 400; + Thread_exit_safepoint_stub_offset = 408; static constexpr dart::compiler::target::word - Thread_call_native_through_safepoint_stub_offset = 408; + Thread_call_native_through_safepoint_stub_offset = 416; static constexpr dart::compiler::target::word - Thread_call_native_through_safepoint_entry_point_offset = 536; + Thread_call_native_through_safepoint_entry_point_offset = 544; static constexpr dart::compiler::target::word - Thread_fix_allocation_stub_code_offset = 240; + Thread_fix_allocation_stub_code_offset = 248; static constexpr dart::compiler::target::word - Thread_fix_callers_target_code_offset = 232; + Thread_fix_callers_target_code_offset = 240; static constexpr dart::compiler::target::word - Thread_float_absolute_address_offset = 624; + Thread_float_absolute_address_offset = 632; static constexpr dart::compiler::target::word - Thread_float_negate_address_offset = 616; + Thread_float_negate_address_offset = 624; static constexpr dart::compiler::target::word Thread_float_not_address_offset = - 608; + 616; static constexpr dart::compiler::target::word - Thread_float_zerow_address_offset = 632; + Thread_float_zerow_address_offset = 640; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 1432; + 1440; static constexpr dart::compiler::target::word - Thread_interpret_call_entry_point_offset = 568; + Thread_interpret_call_entry_point_offset = 576; static constexpr dart::compiler::target::word - Thread_invoke_dart_code_from_bytecode_stub_offset = 256; + Thread_invoke_dart_code_from_bytecode_stub_offset = 264; static constexpr dart::compiler::target::word - Thread_invoke_dart_code_stub_offset = 248; + Thread_invoke_dart_code_stub_offset = 256; static constexpr dart::compiler::target::word Thread_isolate_offset = 104; +static constexpr dart::compiler::target::word Thread_field_table_values_offset = + 112; static constexpr dart::compiler::target::word - Thread_lazy_deopt_from_return_stub_offset = 360; + Thread_lazy_deopt_from_return_stub_offset = 368; static constexpr dart::compiler::target::word - Thread_lazy_deopt_from_throw_stub_offset = 368; + Thread_lazy_deopt_from_throw_stub_offset = 376; static constexpr dart::compiler::target::word - Thread_lazy_specialize_type_test_stub_offset = 384; + Thread_lazy_specialize_type_test_stub_offset = 392; static constexpr dart::compiler::target::word - Thread_marking_stack_block_offset = 152; + Thread_marking_stack_block_offset = 160; static constexpr dart::compiler::target::word - Thread_megamorphic_call_checked_entry_offset = 504; + Thread_megamorphic_call_checked_entry_offset = 512; static constexpr dart::compiler::target::word - Thread_monomorphic_miss_entry_offset = 512; + Thread_monomorphic_miss_entry_offset = 520; static constexpr dart::compiler::target::word - Thread_monomorphic_miss_stub_offset = 336; + Thread_monomorphic_miss_stub_offset = 344; static constexpr dart::compiler::target::word - Thread_no_scope_native_wrapper_entry_point_offset = 552; + Thread_no_scope_native_wrapper_entry_point_offset = 560; static constexpr dart::compiler::target::word - Thread_null_error_shared_with_fpu_regs_entry_point_offset = 448; + Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456; static constexpr dart::compiler::target::word - Thread_null_error_shared_with_fpu_regs_stub_offset = 280; + Thread_null_error_shared_with_fpu_regs_stub_offset = 288; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 464; + Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 296; + Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304; static constexpr dart::compiler::target::word - Thread_null_error_shared_without_fpu_regs_entry_point_offset = 440; + Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448; static constexpr dart::compiler::target::word - Thread_null_error_shared_without_fpu_regs_stub_offset = 272; + Thread_null_error_shared_without_fpu_regs_stub_offset = 280; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 456; + Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464; static constexpr dart::compiler::target::word - Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 288; -static constexpr dart::compiler::target::word Thread_object_null_offset = 192; + Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296; +static constexpr dart::compiler::target::word Thread_object_null_offset = 200; static constexpr dart::compiler::target::word - Thread_predefined_symbols_address_offset = 576; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1440; + Thread_predefined_symbols_address_offset = 584; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1448; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 1448; + Thread_saved_shadow_call_stack_offset = 1456; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 1464; + 1472; static constexpr dart::compiler::target::word - Thread_slow_type_test_stub_offset = 376; + Thread_slow_type_test_stub_offset = 384; static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72; static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset = 80; static constexpr dart::compiler::target::word Thread_stack_overflow_flags_offset = 88; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 496; + Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 328; + Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 488; + Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496; static constexpr dart::compiler::target::word - Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 320; + Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328; static constexpr dart::compiler::target::word Thread_store_buffer_block_offset = - 144; + 152; static constexpr dart::compiler::target::word - Thread_top_exit_frame_info_offset = 136; -static constexpr dart::compiler::target::word Thread_top_offset = 120; + Thread_top_exit_frame_info_offset = 144; +static constexpr dart::compiler::target::word Thread_top_offset = 128; static constexpr dart::compiler::target::word Thread_top_resource_offset = 48; static constexpr dart::compiler::target::word - Thread_unboxed_int64_runtime_arg_offset = 184; -static constexpr dart::compiler::target::word Thread_vm_tag_offset = 168; + Thread_unboxed_int64_runtime_arg_offset = 192; +static constexpr dart::compiler::target::word Thread_vm_tag_offset = 176; static constexpr dart::compiler::target::word Thread_write_barrier_code_offset = - 216; + 224; static constexpr dart::compiler::target::word - Thread_write_barrier_entry_point_offset = 416; + Thread_write_barrier_entry_point_offset = 424; static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 96; static constexpr dart::compiler::target::word Thread_callback_code_offset = - 1472; + 1480; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word TwoByteString_data_offset = 16; @@ -1480,9 +1484,9 @@ static constexpr dart::compiler::target::word Code_function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, - 1336, 1344, 1352, 1360, -1, -1, -1, -1, 1368, 1376, 1384, - -1, 1392, 1400, 1408, -1, -1, -1, -1, -1, -1}; + 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, 1336, + 1344, 1352, 1360, 1368, -1, -1, -1, -1, 1376, 1384, 1392, + -1, 1400, 1408, 1416, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word Array_header_size = 24; static constexpr dart::compiler::target::word Context_header_size = 24; static constexpr dart::compiler::target::word Double_InstanceSize = 16; diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h index ac10bf29a51c6..5c88c8e61f409 100644 --- a/runtime/vm/compiler/runtime_offsets_list.h +++ b/runtime/vm/compiler/runtime_offsets_list.h @@ -88,7 +88,6 @@ PRECOMP_NO_CHECK(FIELD(Field, guarded_list_length_in_object_offset_offset)) \ PRECOMP_NO_CHECK(FIELD(Field, guarded_list_length_offset)) \ PRECOMP_NO_CHECK(FIELD(Field, is_nullable_offset)) \ - FIELD(Field, static_value_offset) \ PRECOMP_NO_CHECK(FIELD(Field, kind_bits_offset)) \ FIELD(Function, code_offset) \ FIELD(Function, entry_point_offset) \ @@ -181,6 +180,7 @@ FIELD(Thread, invoke_dart_code_from_bytecode_stub_offset) \ FIELD(Thread, invoke_dart_code_stub_offset) \ FIELD(Thread, isolate_offset) \ + FIELD(Thread, field_table_values_offset) \ FIELD(Thread, lazy_deopt_from_return_stub_offset) \ FIELD(Thread, lazy_deopt_from_throw_stub_offset) \ FIELD(Thread, lazy_specialize_type_test_stub_offset) \ diff --git a/runtime/vm/field_table.cc b/runtime/vm/field_table.cc new file mode 100644 index 0000000000000..5a248c144b988 --- /dev/null +++ b/runtime/vm/field_table.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "vm/field_table.h" + +#include "platform/atomic.h" +#include "vm/flags.h" +#include "vm/growable_array.h" +#include "vm/heap/heap.h" +#include "vm/object.h" +#include "vm/object_graph.h" +#include "vm/object_store.h" +#include "vm/raw_object.h" +#include "vm/visitor.h" + +namespace dart { + +FieldTable::~FieldTable() { + FreeOldTables(); + delete old_tables_; // Allocated in FieldTable::FieldTable() + free(table_); // Allocated in FieldTable::Grow() +} + +void FieldTable::FreeOldTables() { + while (old_tables_->length() > 0) { + free(old_tables_->RemoveLast()); + } +} + +intptr_t FieldTable::FieldOffsetFor(intptr_t field_id) { + return field_id * sizeof(RawInstance*); // NOLINT +} + +void FieldTable::Register(const Field& field) { + ASSERT(Thread::Current()->IsMutatorThread()); + if (free_head_ < 0) { + if (top_ == capacity_) { + const intptr_t new_capacity = capacity_ + kCapacityIncrement; + Grow(new_capacity); + } + + ASSERT(top_ < capacity_); + + field.set_field_id(top_); + table_[top_] = Object::sentinel().raw(); + + ++top_; + return; + } + + // Reuse existing free element. This is "slow path" that should only be + // triggered after hot reload. + intptr_t reused_free = free_head_; + free_head_ = Smi::Value(Smi::RawCast(table_[free_head_])); + field.set_field_id(reused_free); + table_[reused_free] = Object::sentinel().raw(); +} + +void FieldTable::Free(intptr_t field_id) { + table_[field_id] = Smi::New(free_head_); + free_head_ = field_id; +} + +void FieldTable::SetAt(intptr_t index, RawInstance* raw_instance) { + ASSERT(index < capacity_); + table_[index] = raw_instance; +} + +void FieldTable::AllocateIndex(intptr_t index) { + if (index >= capacity_) { + const intptr_t new_capacity = index + kCapacityIncrement; + Grow(new_capacity); + } + + ASSERT(table_[index] == nullptr); + if (index >= top_) { + top_ = index + 1; + } +} + +void FieldTable::Grow(intptr_t new_capacity) { + ASSERT(new_capacity > capacity_); + + auto new_table = static_cast( + malloc(new_capacity * sizeof(RawInstance*))); // NOLINT + memmove(new_table, table_, top_ * sizeof(RawInstance*)); + memset(new_table + top_, 0, (new_capacity - top_) * sizeof(RawInstance*)); + capacity_ = new_capacity; + old_tables_->Add(table_); + // Ensure that new_table_ is populated before it is published + // via store to table_. + std::atomic_thread_fence(std::memory_order_release); + table_ = new_table; + Thread::Current()->field_table_values_ = table_; +} + +void FieldTable::VisitObjectPointers(ObjectPointerVisitor* visitor) { + ASSERT(visitor != NULL); + visitor->set_gc_root_type("static fields table"); + visitor->VisitPointers(reinterpret_cast(&table_[0]), + reinterpret_cast(&table_[top_ - 1])); + visitor->clear_gc_root_type(); +} + +} // namespace dart diff --git a/runtime/vm/field_table.h b/runtime/vm/field_table.h new file mode 100644 index 0000000000000..e89c733f2a3d4 --- /dev/null +++ b/runtime/vm/field_table.h @@ -0,0 +1,88 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef RUNTIME_VM_FIELD_TABLE_H_ +#define RUNTIME_VM_FIELD_TABLE_H_ + +#include "platform/assert.h" +#include "platform/atomic.h" + +#include "vm/bitfield.h" +#include "vm/class_id.h" +#include "vm/globals.h" +#include "vm/growable_array.h" + +namespace dart { + +class Field; +class RawInstance; + +class FieldTable { + public: + FieldTable() + : top_(0), + capacity_(0), + free_head_(-1), + table_(nullptr), + old_tables_(new MallocGrowableArray()) {} + + ~FieldTable(); + + intptr_t NumFieldIds() const { return top_; } + intptr_t Capacity() const { return capacity_; } + + RawInstance** table() { return table_; } + + void FreeOldTables(); + + // Used by the generated code. + static intptr_t FieldOffsetFor(intptr_t field_id); + + bool IsValidIndex(intptr_t index) const { return index >= 0 && index < top_; } + + void Register(const Field& field); + void AllocateIndex(intptr_t index); + + // Static field elements are being freed only during isolate reload + // when initially created static field have to get remapped to point + // to an existing static field value. + void Free(intptr_t index); + + RawInstance* At(intptr_t index) const { + ASSERT(IsValidIndex(index)); + return table_[index]; + } + void SetAt(intptr_t index, RawInstance* raw_instance); + + void VisitObjectPointers(ObjectPointerVisitor* visitor); + + static const int kInitialCapacity = 512; + static const int kCapacityIncrement = 256; + + private: + friend class GCMarker; + friend class MarkingWeakVisitor; + friend class Scavenger; + friend class ScavengerWeakVisitor; + + void Grow(intptr_t new_capacity); + + intptr_t top_; + intptr_t capacity_; + // -1 if free list is empty, otherwise index of first empty element. Empty + // elements are organized into linked list - they contain index of next + // element, last element contains -1. + intptr_t free_head_; + + RawInstance** table_; + // When table_ grows and have to reallocated, keep the old one here + // so it will get freed when its are no longer in use. + MallocGrowableArray* old_tables_; + + DISALLOW_COPY_AND_ASSIGN(FieldTable); +}; + +} // namespace dart + +#endif // RUNTIME_VM_FIELD_TABLE_H_ diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc index aab4df6fcc367..a0fd0b43c3a8d 100644 --- a/runtime/vm/heap/pages.cc +++ b/runtime/vm/heap/pages.cc @@ -1052,6 +1052,7 @@ void PageSpace::CollectGarbageAtSafepoint(bool compact, // Perform various cleanup that relies on no tasks interfering. isolate->class_table()->FreeOldTables(); + isolate->field_table()->FreeOldTables(); NoSafepointScope no_safepoints; diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc index 0246b5cd442f7..87a3ed00cb89b 100644 --- a/runtime/vm/interpreter.cc +++ b/runtime/vm/interpreter.cc @@ -2333,7 +2333,7 @@ RawObject* Interpreter::Call(RawFunction* function, BYTECODE(InitLateField, D); RawField* field = RAW_CAST(Field, LOAD_CONSTANT(rD + 1)); RawInstance* instance = reinterpret_cast(SP[0]); - intptr_t offset_in_words = Smi::Value(field->ptr()->value_.offset_); + intptr_t offset_in_words = field->ptr()->offset_or_field_id_; instance->StorePointer( reinterpret_cast(instance->ptr()) + offset_in_words, @@ -2362,14 +2362,16 @@ RawObject* Interpreter::Call(RawFunction* function, BYTECODE(StoreStaticTOS, D); RawField* field = reinterpret_cast(LOAD_CONSTANT(rD)); RawInstance* value = static_cast(*SP--); - field->StorePointer(&field->ptr()->value_.static_value_, value, thread); + intptr_t field_id = field->ptr()->offset_or_field_id_; + thread->field_table_values()[field_id] = value; DISPATCH(); } { BYTECODE(LoadStatic, D); RawField* field = reinterpret_cast(LOAD_CONSTANT(rD)); - RawInstance* value = field->ptr()->value_.static_value_; + intptr_t field_id = field->ptr()->offset_or_field_id_; + RawInstance* value = thread->field_table_values()[field_id]; ASSERT((value != Object::sentinel().raw()) && (value != Object::transition_sentinel().raw())); *++SP = value; @@ -2381,7 +2383,7 @@ RawObject* Interpreter::Call(RawFunction* function, RawField* field = RAW_CAST(Field, LOAD_CONSTANT(rD + 1)); RawInstance* instance = reinterpret_cast(SP[-1]); RawObject* value = reinterpret_cast(SP[0]); - intptr_t offset_in_words = Smi::Value(field->ptr()->value_.offset_); + intptr_t offset_in_words = field->ptr()->offset_or_field_id_; if (InterpreterHelpers::FieldNeedsGuardUpdate(field, value)) { SP[1] = 0; // Unused result of runtime call. @@ -3166,7 +3168,7 @@ RawObject* Interpreter::Call(RawFunction* function, // Field object is cached in function's data_. RawField* field = reinterpret_cast(function->ptr()->data_); - intptr_t offset_in_words = Smi::Value(field->ptr()->value_.offset_); + intptr_t offset_in_words = field->ptr()->offset_or_field_id_; const intptr_t kArgc = 1; RawInstance* instance = @@ -3186,7 +3188,7 @@ RawObject* Interpreter::Call(RawFunction* function, function = FrameFunction(FP); instance = reinterpret_cast(SP[2]); field = reinterpret_cast(SP[3]); - offset_in_words = Smi::Value(field->ptr()->value_.offset_); + offset_in_words = field->ptr()->offset_or_field_id_; value = reinterpret_cast(instance->ptr())[offset_in_words]; } @@ -3247,7 +3249,7 @@ RawObject* Interpreter::Call(RawFunction* function, // Field object is cached in function's data_. RawField* field = reinterpret_cast(function->ptr()->data_); - intptr_t offset_in_words = Smi::Value(field->ptr()->value_.offset_); + intptr_t offset_in_words = field->ptr()->offset_or_field_id_; const intptr_t kArgc = 2; RawInstance* instance = reinterpret_cast(FrameArguments(FP, kArgc)[0]); @@ -3327,7 +3329,8 @@ RawObject* Interpreter::Call(RawFunction* function, // Field object is cached in function's data_. RawField* field = reinterpret_cast(function->ptr()->data_); - RawInstance* value = field->ptr()->value_.static_value_; + intptr_t field_id = field->ptr()->offset_or_field_id_; + RawInstance* value = thread->field_table_values()[field_id]; if (value == Object::sentinel().raw() || value == Object::transition_sentinel().raw()) { SP[1] = 0; // Unused result of invoking the initializer. @@ -3340,7 +3343,8 @@ RawObject* Interpreter::Call(RawFunction* function, function = FrameFunction(FP); field = reinterpret_cast(function->ptr()->data_); // The field is initialized by the runtime call, but not returned. - value = field->ptr()->value_.static_value_; + intptr_t field_id = field->ptr()->offset_or_field_id_; + value = thread->field_table_values()[field_id]; } // Field was initialized. Return its value. diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index da424ebace909..7bb5bf4c77bf7 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -280,6 +280,7 @@ Thread* IsolateGroup::ScheduleThreadLocked(MonitorLocker* ml, // Set up other values and set the TLS value. thread->isolate_ = nullptr; thread->isolate_group_ = this; + thread->field_table_values_ = nullptr; thread->set_os_thread(os_thread); ASSERT(thread->execution_state() == Thread::kThreadInNative); thread->set_execution_state(Thread::kThreadInVM); @@ -527,6 +528,10 @@ void Isolate::ValidateClassTable() { } #endif // DEBUG +void Isolate::RegisterStaticField(const Field& field) { + field_table()->Register(field); +} + void Isolate::RehashConstants() { Thread* thread = Thread::Current(); StackZone stack_zone(thread); @@ -1224,6 +1229,7 @@ Isolate::Isolate(IsolateGroup* isolate_group, ic_miss_code_(Code::null()), shared_class_table_(new SharedClassTable()), class_table_(shared_class_table_.get()), + field_table_(new FieldTable()), store_buffer_(new StoreBuffer()), #if !defined(DART_PRECOMPILED_RUNTIME) native_callback_trampolines_(), @@ -1325,6 +1331,7 @@ Isolate::~Isolate() { delete heap_; ASSERT(marking_stack_ == nullptr); delete object_store_; + delete field_table_; delete api_state_; #if defined(USING_SIMULATOR) delete simulator_; @@ -2307,6 +2314,9 @@ void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor, // Visit objects in the class table. class_table()->VisitObjectPointers(visitor); + // Visit objects in the field table. + field_table()->VisitObjectPointers(visitor); + // Visit the dart api state for all local and persistent handles. if (api_state() != nullptr) { api_state()->VisitObjectPointers(visitor); @@ -3277,6 +3287,7 @@ Thread* Isolate::ScheduleThread(bool is_mutator, bool bypass_safepoint) { scheduled_mutator_thread_ = thread; } thread->isolate_ = this; + thread->field_table_values_ = field_table_->table(); ASSERT(heap() != nullptr); thread->heap_ = heap(); @@ -3312,6 +3323,7 @@ void Isolate::UnscheduleThread(Thread* thread, ASSERT(mutator_thread_ == scheduled_mutator_thread_); scheduled_mutator_thread_ = nullptr; } + thread->field_table_values_ = nullptr; group()->UnscheduleThreadLocked(&ml, thread, is_mutator, bypass_safepoint); } diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index c8cf0251f79bc..bab82c151d9ac 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -21,6 +21,7 @@ #include "vm/constants_kbc.h" #include "vm/exceptions.h" #include "vm/ffi_callback_trampolines.h" +#include "vm/field_table.h" #include "vm/fixed_cache.h" #include "vm/growable_array.h" #include "vm/handles.h" @@ -444,6 +445,8 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { #if defined(DEBUG) void ValidateClassTable(); #endif + // Register a newly introduced static field. + void RegisterStaticField(const Field& field); void RehashConstants(); #if defined(DEBUG) @@ -478,6 +481,8 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { return OFFSET_OF(Isolate, class_table_); } + FieldTable* field_table() const { return field_table_; } + // Prefers old classes when we are in the middle of a reload. RawClass* GetClassForHeapWalkAt(intptr_t cid); intptr_t GetClassSizeForHeapWalkAt(intptr_t cid); @@ -1136,6 +1141,7 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { std::unique_ptr shared_class_table_; ObjectStore* object_store_ = nullptr; ClassTable class_table_; + FieldTable* field_table_ = nullptr; bool single_step_ = false; // End accessed from generated code. diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc index 79325d844c974..b69cee3e68b03 100644 --- a/runtime/vm/isolate_reload_test.cc +++ b/runtime/vm/isolate_reload_test.cc @@ -3752,6 +3752,130 @@ TEST_CASE(IsolateReload_RunNewFieldInitializersWithGenerics) { SimpleInvokeStr(lib, "main")); } +TEST_CASE(IsolateReload_AddNewStaticField) { + const char* kScript = + "class C {\n" + "}\n" + "main() {\n" + " return 'Okay';\n" + "}\n"; + + Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); + EXPECT_VALID(lib); + EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main")); + + const char* kReloadScript = + "class C {\n" + " static var x = 42;\n" + "}\n" + "main() {\n" + " return '${C.x}';\n" + "}\n"; + + lib = TestCase::ReloadTestScript(kReloadScript); + EXPECT_VALID(lib); + EXPECT_STREQ("42", SimpleInvokeStr(lib, "main")); +} + +TEST_CASE(IsolateReload_StaticFieldInitialValueDoesnotChange) { + const char* kScript = + "class C {\n" + " static var x = 42;\n" + "}\n" + "main() {\n" + " return '${C.x}';\n" + "}\n"; + + Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); + EXPECT_VALID(lib); + EXPECT_STREQ("42", SimpleInvokeStr(lib, "main")); + + const char* kReloadScript = + "class C {\n" + " static var x = 13;\n" + "}\n" + "main() {\n" + " return '${C.x}';\n" + "}\n"; + + lib = TestCase::ReloadTestScript(kReloadScript); + EXPECT_VALID(lib); + // Newly loaded field maintained old static value + EXPECT_STREQ("42", SimpleInvokeStr(lib, "main")); +} + +class FindNoInstancesOfClass : public FindObjectVisitor { + public: + explicit FindNoInstancesOfClass(intptr_t cid) : cid_(cid) { +#if defined(DEBUG) + EXPECT_GT(Thread::Current()->no_safepoint_scope_depth(), 0); +#endif + } + virtual ~FindNoInstancesOfClass() {} + + virtual bool FindObject(RawObject* obj) const { + return obj->GetClassId() == cid_; + } + + private: + intptr_t cid_; +}; + +TEST_CASE(IsolateReload_DeleteStaticField) { + const char* kScript = + "class C {\n" + "}\n" + "class Foo {\n" + "static var x = C();\n" + "}\n" + "main() {\n" + " return Foo.x;\n" + "}\n"; + + Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); + EXPECT_VALID(lib); + intptr_t cid = 1118; + { + Dart_EnterScope(); + Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); + EXPECT_VALID(result); + { + TransitionNativeToVM transition(thread); + cid = Api::ClassId(result); + } + Dart_ExitScope(); + } + + const char* kReloadScript = + "class C {\n" + "}\n" + "class Foo {\n" + "}\n" + "main() {\n" + " return '${Foo()}';\n" + "}\n"; + + lib = TestCase::ReloadTestScript(kReloadScript); + EXPECT_VALID(lib); + Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); + EXPECT_VALID(result); + { + TransitionNativeToVM transition(thread); + GCTestHelper::CollectAllGarbage(); + + { + HeapIterationScope iteration(thread); + NoSafepointScope no_safepoint; + FindNoInstancesOfClass find_only(cid); + Isolate* isolate = Isolate::Current(); + Heap* heap = isolate->heap(); + // We still expect to find references to static field values + // because they are not deleted after hot reload. + EXPECT_NE(heap->FindObject(&find_only), Object::null()); + } + } +} + TEST_CASE(IsolateReload_ExistingFieldChangesType) { const char* kScript = R"( class Foo { diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 136a6f36ad570..28d3e2511128c 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -8885,6 +8885,9 @@ void Field::InitializeNew(const Field& result, result.set_static_type_exactness_state( StaticTypeExactnessState::NotTracking()); Isolate* isolate = Isolate::Current(); + if (is_static) { + isolate->RegisterStaticField(result); + } // Use field guards if they are enabled and the isolate has never reloaded. // TODO(johnmccutchan): The reload case assumes the worst case (everything is @@ -9156,9 +9159,11 @@ bool Field::IsConsistentWith(const Field& other) const { } bool Field::IsUninitialized() const { - const Instance& value = Instance::Handle(raw_ptr()->value_.static_value_); - ASSERT(value.raw() != Object::transition_sentinel().raw()); - return value.raw() == Object::sentinel().raw(); + Thread* thread = Thread::Current(); + const FieldTable* field_table = thread->isolate()->field_table(); + const RawInstance* raw_value = field_table->At(field_id()); + ASSERT(raw_value != Object::transition_sentinel().raw()); + return raw_value == Object::sentinel().raw(); } RawFunction* Field::EnsureInitializerFunction() const { @@ -9429,6 +9434,20 @@ static bool FindInstantiationOf(const Type& type, return false; // Not found. } +void Field::SetStaticValue(const Instance& value, + bool save_initial_value) const { + ASSERT(Thread::Current()->IsMutatorThread()); + ASSERT(is_static()); // Valid only for static dart fields. + Isolate* isolate = Isolate::Current(); + const intptr_t id = field_id(); + isolate->field_table()->SetAt(id, value.raw()); + if (save_initial_value) { +#if !defined(DART_PRECOMPILED_RUNTIME) + StorePointer(&raw_ptr()->saved_initial_value_, value.raw()); +#endif + } +} + static StaticTypeExactnessState TrivialTypeExactnessFor(const Class& cls) { const intptr_t type_arguments_offset = cls.type_arguments_field_offset(); ASSERT(type_arguments_offset != Class::kNoTypeArguments); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 626e91dd9a7cb..00b1f8029f23f 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -3583,8 +3583,11 @@ class Field : public Object { inline void SetOffset(intptr_t offset_in_bytes) const; inline RawInstance* StaticValue() const; - inline void SetStaticValue(const Instance& value, - bool save_initial_value = false) const; + void SetStaticValue(const Instance& value, + bool save_initial_value = false) const; + + intptr_t field_id() const { return raw_ptr()->offset_or_field_id_; } + inline void set_field_id(intptr_t field_id) const; #ifndef DART_PRECOMPILED_RUNTIME RawInstance* saved_initial_value() const { @@ -3632,13 +3635,6 @@ class Field : public Object { // original is specified. RawField* Clone(const Field& original) const; - static intptr_t instance_field_offset() { - return OFFSET_OF(RawField, value_.offset_); - } - static intptr_t static_value_offset() { - return OFFSET_OF(RawField, value_.static_value_); - } - static intptr_t kind_bits_offset() { return OFFSET_OF(RawField, kind_bits_); } TokenPosition token_pos() const { return raw_ptr()->token_pos_; } @@ -3960,6 +3956,7 @@ class Field : public Object { friend class HeapProfiler; friend class RawField; friend class FieldSerializationCluster; + friend class FieldDeserializationCluster; }; class Script : public Object { @@ -10223,32 +10220,24 @@ bool Function::HasBytecode(RawFunction* function) { intptr_t Field::Offset() const { ASSERT(is_instance()); // Valid only for dart instance fields. - intptr_t value = Smi::Value(raw_ptr()->value_.offset_); - return (value * kWordSize); + return (raw_ptr()->offset_or_field_id_ * kWordSize); } void Field::SetOffset(intptr_t offset_in_bytes) const { ASSERT(is_instance()); // Valid only for dart instance fields. ASSERT(kWordSize != 0); - StorePointer(&raw_ptr()->value_.offset_, - Smi::New(offset_in_bytes / kWordSize)); + StoreNonPointer(&raw_ptr()->offset_or_field_id_, offset_in_bytes / kWordSize); } RawInstance* Field::StaticValue() const { ASSERT(is_static()); // Valid only for static dart fields. - return raw_ptr()->value_.static_value_; + return Isolate::Current()->field_table()->At(raw_ptr()->offset_or_field_id_); } -void Field::SetStaticValue(const Instance& value, - bool save_initial_value) const { +void Field::set_field_id(intptr_t field_id) const { + ASSERT(is_static()); ASSERT(Thread::Current()->IsMutatorThread()); - ASSERT(is_static()); // Valid only for static dart fields. - StorePointer(&raw_ptr()->value_.static_value_, value.raw()); - if (save_initial_value) { -#if !defined(DART_PRECOMPILED_RUNTIME) - StorePointer(&raw_ptr()->saved_initial_value_, value.raw()); -#endif - } + StoreNonPointer(&raw_ptr()->offset_or_field_id_, field_id); } #ifndef DART_PRECOMPILED_RUNTIME diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc index c2c29dc31051a..fe1066c092109 100644 --- a/runtime/vm/object_reload.cc +++ b/runtime/vm/object_reload.cc @@ -255,7 +255,6 @@ void Class::CopyStaticFieldValues(IsolateReloadContext* reload_context, Field& field = Field::Handle(); String& name = String::Handle(); - Instance& value = Instance::Handle(); for (intptr_t i = 0; i < field_list.Length(); i++) { field = Field::RawCast(field_list.At(i)); name = field.name(); @@ -269,8 +268,10 @@ void Class::CopyStaticFieldValues(IsolateReloadContext* reload_context, // We only copy values if requested and if the field is not a const // field. We let const fields be updated with a reload. if (update_values && !field.is_const()) { - value = old_field.StaticValue(); - field.SetStaticValue(value); + // Make new field point to the old field value so that both + // old and new code see and update same value. + reload_context->isolate()->field_table()->Free(field.field_id()); + field.set_field_id(old_field.field_id()); } reload_context->AddStaticFieldMapping(old_field, field); } else { diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 5f0b727dbbab0..2771eb2b69044 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -1126,17 +1126,11 @@ class RawField : public RawObject { RawObject* owner_; // Class or patch class or mixin class // where this field is defined or original field. RawAbstractType* type_; - union { - RawInstance* static_value_; // Value for static fields. - RawSmi* offset_; // Offset in words for instance fields. - } value_; RawFunction* initializer_function_; // Static initializer function. // When generating APPJIT snapshots after running the application it is // necessary to save the initial value of static fields so that we can // restore the value back to the original initial value. - NOT_IN_PRECOMPILED( - RawInstance* - saved_initial_value_); // Saved initial value - static fields. + NOT_IN_PRECOMPILED(RawInstance* saved_initial_value_); // Saved initial value RawSmi* guarded_list_length_; RawArray* dependent_code_; RawObject** to_snapshot(Snapshot::Kind kind) { @@ -1183,6 +1177,10 @@ class RawField : public RawObject { // field. int8_t static_type_exactness_state_; + // - for instance fields: offset in words to the value in the class instance. + // - for static fields: index into field_table. + intptr_t offset_or_field_id_; + uint16_t kind_bits_; // static, final, const, has initializer.... friend class CidRewriteVisitor; diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc index 6516e8ecdc1d5..03e9d51a0d87b 100644 --- a/runtime/vm/raw_object_fields.cc +++ b/runtime/vm/raw_object_fields.cc @@ -212,8 +212,8 @@ namespace dart { F(ICData, receivers_static_type_) \ F(Function, bytecode_) \ F(Function, unoptimized_code_) \ - F(Field, type_test_cache_) \ - F(Field, saved_initial_value_) + F(Field, saved_initial_value_) \ + F(Field, type_test_cache_) OffsetsTable::OffsetsTable(Zone* zone) : cached_offsets_(zone) { for (intptr_t i = 0; offsets_table[i].class_id != -1; ++i) { diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h index 0adba981c0552..a4969ee292877 100644 --- a/runtime/vm/thread.h +++ b/runtime/vm/thread.h @@ -36,6 +36,7 @@ class Bytecode; class Error; class ExceptionHandlers; class Field; +class FieldTable; class Function; class GrowableObjectArray; class HandleScope; @@ -384,6 +385,10 @@ class Thread : public ThreadState { // The isolate group that this thread is operating on, or nullptr if none. IsolateGroup* isolate_group() const { return isolate_group_; } + static intptr_t field_table_values_offset() { + return OFFSET_OF(Thread, field_table_values_); + } + bool IsMutatorThread() const; bool CanCollectGarbage() const; @@ -858,6 +863,7 @@ class Thread : public ThreadState { uword stack_overflow_flags_; uword write_barrier_mask_; Isolate* isolate_; + RawInstance** field_table_values_; Heap* heap_; uword top_; uword end_; @@ -939,6 +945,8 @@ class Thread : public ThreadState { intptr_t ffi_marshalled_arguments_size_ = 0; uint64_t* ffi_marshalled_arguments_; + RawInstance** field_table_values() const { return field_table_values_; } + // Reusable handles support. #define REUSABLE_HANDLE_FIELDS(object) object* object##_handle_; REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_FIELDS) @@ -1005,6 +1013,7 @@ class Thread : public ThreadState { friend class ThreadRegistry; friend class CompilerState; friend class compiler::target::Thread; + friend class FieldTable; DISALLOW_COPY_AND_ASSIGN(Thread); }; diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni index 1a6c0de171959..acc81abcaf27d 100644 --- a/runtime/vm/vm_sources.gni +++ b/runtime/vm/vm_sources.gni @@ -101,6 +101,8 @@ vm_sources = [ "ffi_callback_trampolines.cc", "ffi_callback_trampolines.h", "finalizable_data.h", + "field_table.cc", + "field_table.h", "fixed_cache.h", "flag_list.h", "flags.cc",