mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:13:01 +00:00
[vm/concurrency] Avoid calling into Dart code for evaluation of enum constants
There is no need to call from C++ into Dart code just so the Dart code can return a constant. Instead we can get the constant directly in C++ code. This avoids calling into Dart code during class finalization to evaluate enum constants. Issue https://github.com/dart-lang/sdk/issues/36097 Change-Id: Ia0b09482188be2d0ce83ce9ffc20e5c15e52d070 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/170540 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
4c7740ab07
commit
7e28ecc270
|
@ -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) {
|
||||
|
|
|
@ -23,6 +23,7 @@ class ConstantReader {
|
|||
|
||||
virtual ~ConstantReader() {}
|
||||
|
||||
InstancePtr ReadConstantInitializer();
|
||||
InstancePtr ReadConstantExpression();
|
||||
ObjectPtr ReadAnnotations();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue