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",