diff --git a/runtime/vm/compiler/frontend/constant_reader.cc b/runtime/vm/compiler/frontend/constant_reader.cc index 2bb6f2b6df1a..6f66e9c875cf 100644 --- a/runtime/vm/compiler/frontend/constant_reader.cc +++ b/runtime/vm/compiler/frontend/constant_reader.cc @@ -19,6 +19,19 @@ ConstantReader::ConstantReader(KernelReaderHelper* helper, script_(helper->script()), result_(Instance::Handle(zone_)) {} +InstancePtr ConstantReader::ReadConstantInitializer() { + Tag tag = helper_->ReadTag(); // read tag. + switch (tag) { + case kSomething: + return ReadConstantExpression(); + default: + H.ReportError(script_, TokenPosition::kNoSource, + "Not a constant expression: unexpected kernel tag %s (%d)", + Reader::TagName(tag), tag); + } + return result_.raw(); +} + InstancePtr ConstantReader::ReadConstantExpression() { Tag tag = helper_->ReadTag(); // read tag. switch (tag) { diff --git a/runtime/vm/compiler/frontend/constant_reader.h b/runtime/vm/compiler/frontend/constant_reader.h index 871b7f046aeb..85f230d3ea90 100644 --- a/runtime/vm/compiler/frontend/constant_reader.h +++ b/runtime/vm/compiler/frontend/constant_reader.h @@ -23,6 +23,7 @@ class ConstantReader { virtual ~ConstantReader() {} + InstancePtr ReadConstantInitializer(); InstancePtr ReadConstantExpression(); ObjectPtr ReadAnnotations(); diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index 6ae68047e395..75cb4a594b0b 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -33,6 +33,17 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldInitializer() { FieldHelper field_helper(this); field_helper.ReadUntilExcluding(FieldHelper::kInitializer); + // Constants are directly accessed at use sites of Dart code. In C++ - if + // we need to access static constants - we do so directly using the kernel + // evaluation instead of invoking the initializer function in Dart code. + // + // If the field is marked as @pragma('vm:entry-point') then the embedder might + // invoke the getter, so we'll generate the initializer function. + ASSERT(!field_helper.IsConst() || + Field::Handle(Z, parsed_function()->function().accessor_field()) + .VerifyEntryPoint(EntryPointPragma::kGetterOnly) == + Error::null()); + Tag initializer_tag = ReadTag(); // read first part of initializer. if (initializer_tag != kSomething) { UNREACHABLE(); @@ -45,14 +56,8 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldInitializer() { Fragment body(normal_entry); body += B->CheckStackOverflowInPrologue(field_helper.position_); - if (field_helper.IsConst()) { - // This will read the initializer. - body += Constant( - Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression())); - } else { - body += SetupCapturedParameters(parsed_function()->function()); - body += BuildExpression(); // read initializer. - } + body += SetupCapturedParameters(parsed_function()->function()); + body += BuildExpression(); // read initializer. body += Return(TokenPosition::kNoSource); PrologueInfo prologue_info(-1, -1); diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc index 23e5ce872206..7c53e7203be9 100644 --- a/runtime/vm/kernel.cc +++ b/runtime/vm/kernel.cc @@ -347,6 +347,38 @@ void CollectTokenPositionsFor(const Script& interesting_script) { script.set_debug_positions(array_object); } +ObjectPtr EvaluateStaticConstFieldInitializer(const Field& field) { + ASSERT(field.is_static() && field.is_const()); + + LongJumpScope jump; + if (setjmp(*jump.Set()) == 0) { + Thread* thread = Thread::Current(); + Zone* zone = thread->zone(); + TranslationHelper helper(thread); + Script& script = Script::Handle(zone, field.Script()); + helper.InitFromScript(script); + + const Class& owner_class = Class::Handle(zone, field.Owner()); + ActiveClass active_class; + ActiveClassScope active_class_scope(&active_class, &owner_class); + + KernelReaderHelper kernel_reader( + zone, &helper, script, + ExternalTypedData::Handle(zone, field.KernelData()), + field.KernelDataProgramOffset()); + kernel_reader.SetOffset(field.kernel_offset()); + ConstantReader constant_reader(&kernel_reader, &active_class); + + FieldHelper field_helper(&kernel_reader); + field_helper.ReadUntilExcluding(FieldHelper::kInitializer); + ASSERT(field_helper.IsConst()); + + return constant_reader.ReadConstantInitializer(); + } else { + return Thread::Current()->StealStickyError(); + } +} + class MetadataEvaluator : public KernelReaderHelper { public: MetadataEvaluator(Zone* zone, diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h index c31b04560591..9b0d8de98c8e 100644 --- a/runtime/vm/kernel.h +++ b/runtime/vm/kernel.h @@ -195,6 +195,7 @@ class KernelLineStartsReader { void CollectTokenPositionsFor(const Script& script); +ObjectPtr EvaluateStaticConstFieldInitializer(const Field& field); ObjectPtr EvaluateMetadata(const Field& metadata_field, bool is_annotations_offset); ObjectPtr BuildParameterDescriptor(const Function& function); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index ba6d46c70642..53654622eb95 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -10611,6 +10611,14 @@ ErrorPtr Field::InitializeStatic() const { ObjectPtr Field::EvaluateInitializer() const { Thread* const thread = Thread::Current(); ASSERT(thread->IsMutatorThread()); + +#if !defined(DART_PRECOMPILED_RUNTIME) + if (is_static() && is_const()) { + ASSERT(!FLAG_precompiled_mode); + return kernel::EvaluateStaticConstFieldInitializer(*this); + } +#endif // !defined(DART_PRECOMPILED_RUNTIME) + NoOOBMessageScope no_msg_scope(thread); NoReloadScope no_reload_scope(thread->isolate(), thread); const Function& initializer = Function::Handle(EnsureInitializerFunction());