From 1695da67c7460a3c98fb36eaa80cfab58924f7df Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Wed, 13 Mar 2024 14:33:48 +0000 Subject: [PATCH] [vm] Move creation of closure functions to kernel loader This change disentangles creation of closure functions from flow graph building. TEST=ci Change-Id: Ia008c21202453062dd722f64be615e5e6af3bdc2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357222 Reviewed-by: Slava Egorov Reviewed-by: Martin Kustermann Commit-Queue: Alexander Markov --- runtime/vm/closure_functions_cache.cc | 23 ++- .../frontend/kernel_binary_flowgraph.cc | 165 +++--------------- .../frontend/kernel_binary_flowgraph.h | 8 +- .../frontend/kernel_translation_helper.cc | 47 +++-- runtime/vm/kernel_loader.cc | 163 ++++++++++++++++- runtime/vm/kernel_loader.h | 17 +- runtime/vm/object_store.cc | 2 - 7 files changed, 242 insertions(+), 183 deletions(-) diff --git a/runtime/vm/closure_functions_cache.cc b/runtime/vm/closure_functions_cache.cc index add92ff75f3..0cb609b599b 100644 --- a/runtime/vm/closure_functions_cache.cc +++ b/runtime/vm/closure_functions_cache.cc @@ -75,9 +75,13 @@ void ClosureFunctionsCache::AddClosureFunctionLocked( DEBUG_ASSERT( thread->isolate_group()->program_lock()->IsCurrentThreadWriter()); - const auto& closures = + auto& closures = GrowableObjectArray::Handle(zone, object_store->closure_functions()); - ASSERT(!closures.IsNull()); + if (closures.IsNull()) { + closures = GrowableObjectArray::New(); + object_store->set_closure_functions(closures); + } + ASSERT(allow_implicit_closure_functions || function.IsNonImplicitClosureFunction()); closures.Add(function, Heap::kOld); @@ -116,10 +120,12 @@ intptr_t ClosureFunctionsCache::FindClosureIndex(const Function& needle) { const auto& closures_array = GrowableObjectArray::Handle(zone, object_store->closure_functions()); - intptr_t num_closures = closures_array.Length(); - for (intptr_t i = 0; i < num_closures; i++) { - if (closures_array.At(i) == needle.ptr()) { - return i; + if (!closures_array.IsNull()) { + intptr_t num_closures = closures_array.Length(); + for (intptr_t i = 0; i < num_closures; i++) { + if (closures_array.At(i) == needle.ptr()) { + return i; + } } } return -1; @@ -134,7 +140,7 @@ FunctionPtr ClosureFunctionsCache::ClosureFunctionFromIndex(intptr_t idx) { const auto& closures_array = GrowableObjectArray::Handle(zone, object_store->closure_functions()); - if (idx < 0 || idx >= closures_array.Length()) { + if (idx < 0 || closures_array.IsNull() || idx >= closures_array.Length()) { return Function::null(); } return Function::RawCast(closures_array.At(idx)); @@ -161,6 +167,9 @@ void ClosureFunctionsCache::ForAllClosureFunctions( // happen). const auto& closures = GrowableObjectArray::Handle(zone, object_store->closure_functions()); + if (closures.IsNull()) { + return; + } if (!thread->IsInStoppedMutatorsScope()) { // The empty read locker scope will implicitly issue an acquire memory diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index d9d2afac83b..eaa5a82a7bb 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -11,6 +11,7 @@ #include "vm/compiler/frontend/prologue_builder.h" #include "vm/compiler/jit/compiler.h" #include "vm/kernel_binary.h" +#include "vm/kernel_loader.h" #include "vm/object_store.h" #include "vm/resolver.h" #include "vm/stack_frame.h" @@ -1208,7 +1209,6 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) { Fragment StreamingFlowGraphBuilder::BuildStatement(TokenPosition* position) { ++num_ast_nodes_; - intptr_t offset = ReaderOffset(); Tag tag = ReadTag(); // read tag. switch (tag) { case kExpressionStatement: @@ -1248,7 +1248,7 @@ Fragment StreamingFlowGraphBuilder::BuildStatement(TokenPosition* position) { case kVariableDeclaration: return BuildVariableDeclaration(position); case kFunctionDeclaration: - return BuildFunctionDeclaration(offset, position); + return BuildFunctionDeclaration(position); case kForInStatement: case kAsyncForInStatement: case kIfCaseStatement: @@ -4268,10 +4268,9 @@ Fragment StreamingFlowGraphBuilder::BuildRecordFieldGet(TokenPosition* p, } Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() { + const intptr_t offset = ReaderOffset() - 1; // Include the tag. ReadPosition(); // read position. - return BuildFunctionNode(TokenPosition::kNoSource, StringIndex(), - /*has_valid_annotation=*/false, /*has_pragma=*/false, - /*func_decl_offset=*/0); + return BuildFunctionNode(offset); } Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* p) { @@ -5887,180 +5886,56 @@ Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration( } Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration( - intptr_t offset, TokenPosition* position) { + const intptr_t offset = ReaderOffset() - 1; // Include the tag. const TokenPosition pos = ReadPosition(); if (position != nullptr) *position = pos; const intptr_t variable_offset = ReaderOffset() + data_program_offset_; - - // Read variable declaration. - VariableDeclarationHelper helper(this); - - bool has_pragma = false; - bool has_valid_annotation = false; - helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations); - const intptr_t annotation_count = ReadListLength(); - for (intptr_t i = 0; i < annotation_count; ++i) { - const intptr_t tag = PeekTag(); - if (tag != kInvalidExpression) { - has_valid_annotation = true; - } - if (tag == kConstantExpression || tag == kFileUriConstantExpression) { - auto& instance = Instance::Handle(); - instance = constant_reader_.ReadConstantExpression(); - if (instance.clazz() == IG->object_store()->pragma_class()) { - has_pragma = true; - } - continue; - } - SkipExpression(); - } - helper.SetJustRead(VariableDeclarationHelper::kAnnotations); - - helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd); + SkipVariableDeclaration(); Fragment instructions = DebugStepCheck(pos); - instructions += BuildFunctionNode(pos, helper.name_index_, - has_valid_annotation, has_pragma, offset); + instructions += BuildFunctionNode(offset); instructions += StoreLocal(pos, LookupVariable(variable_offset)); instructions += Drop(); return instructions; } Fragment StreamingFlowGraphBuilder::BuildFunctionNode( - TokenPosition parent_position, - StringIndex name_index, - bool has_valid_annotation, - bool has_pragma, intptr_t func_decl_offset) { - const intptr_t offset = ReaderOffset(); - - FunctionNodeHelper function_node_helper(this); - function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); - TokenPosition position = function_node_helper.position_; - - bool declaration = name_index >= 0; - - if (declaration) { - position = parent_position; - } - + const intptr_t func_node_offset = ReaderOffset(); const auto& member_function = Function::Handle(Z, parsed_function()->function().GetOutermostFunction()); - Function& function = Function::ZoneHandle(Z); + const Function& function = Function::ZoneHandle( + Z, KernelLoader::GetClosureFunction( + thread(), func_decl_offset, member_function, + parsed_function()->function(), closure_owner_)); - { - SafepointReadRwLocker ml(thread(), - thread()->isolate_group()->program_lock()); - function = ClosureFunctionsCache::LookupClosureFunctionLocked( - member_function, offset); - } - - if (function.IsNull()) { + if (function.context_scope() == ContextScope::null()) { SafepointWriteRwLocker ml(thread(), thread()->isolate_group()->program_lock()); - function = ClosureFunctionsCache::LookupClosureFunctionLocked( - member_function, offset); - if (function.IsNull()) { + if (function.context_scope() == ContextScope::null()) { for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) { - if (scopes()->function_scopes[i].kernel_offset != offset) { + if (scopes()->function_scopes[i].kernel_offset != + function.kernel_offset()) { continue; } - const String* name; - if (declaration) { - name = &H.DartSymbolObfuscate(name_index); - } else { - name = &Symbols::AnonymousClosure(); - } - if (!closure_owner_.IsNull()) { - function = Function::NewClosureFunctionWithKind( - UntaggedFunction::kClosureFunction, *name, - parsed_function()->function(), - parsed_function()->function().is_static(), position, - closure_owner_); - } else { - function = Function::NewClosureFunction( - *name, parsed_function()->function(), position); - } - - function.set_has_pragma(has_pragma); - if ((FLAG_enable_mirrors && has_valid_annotation) || has_pragma) { - auto& lib = - Library::Handle(Z, Class::Handle(Z, function.Owner()).library()); - lib.AddMetadata(function, func_decl_offset); - } - - if (function_node_helper.async_marker_ == FunctionNodeHelper::kAsync) { - function.set_modifier(UntaggedFunction::kAsync); - function.set_is_inlinable(false); - ASSERT(function.IsAsyncFunction()); - } else if (function_node_helper.async_marker_ == - FunctionNodeHelper::kAsyncStar) { - function.set_modifier(UntaggedFunction::kAsyncGen); - function.set_is_inlinable(false); - ASSERT(function.IsAsyncGenerator()); - } else if (function_node_helper.async_marker_ == - FunctionNodeHelper::kSyncStar) { - function.set_modifier(UntaggedFunction::kSyncGen); - function.set_is_inlinable(false); - ASSERT(function.IsSyncGenerator()); - } else { - ASSERT(function_node_helper.async_marker_ == - FunctionNodeHelper::kSync); - ASSERT(!function.IsAsyncFunction()); - ASSERT(!function.IsAsyncGenerator()); - ASSERT(!function.IsSyncGenerator()); - } - - // If the start token position is synthetic, the end token position - // should be as well. - function.set_end_token_pos( - position.IsReal() ? function_node_helper.end_position_ : position); - LocalScope* scope = scopes()->function_scopes[i].scope; const ContextScope& context_scope = ContextScope::Handle( Z, scope->PreserveOuterScope(function, flow_graph_builder_->context_depth_)); function.set_context_scope(context_scope); - function.set_kernel_offset(offset); - type_translator_.SetupFunctionParameters(Class::Handle(Z), function, - false, // is_method - true, // is_closure - &function_node_helper); - // type_translator_.SetupUnboxingInfoMetadata is not called here at the - // moment because closures do not have unboxed parameters and return - // value - function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); - - // Finalize function type. - FunctionType& signature = FunctionType::Handle(Z, function.signature()); - signature ^= ClassFinalizer::FinalizeType(signature); - function.SetSignature(signature); - - if (has_pragma) { - if (Library::FindPragma(thread(), /*only_core=*/false, function, - Symbols::vm_invisible())) { - function.set_is_visible(false); - } - } - - ASSERT(function.GetOutermostFunction() == member_function.ptr()); - ASSERT(function.kernel_offset() == offset); - ClosureFunctionsCache::AddClosureFunctionLocked(function); - break; } } } - ASSERT(function.token_pos() == position); - ASSERT(function.parent_function() == parsed_function()->function().ptr()); - function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); + ASSERT(function.kernel_offset() == func_node_offset); + SkipFunctionNode(); Fragment instructions; instructions += Constant(function); - if (scopes()->IsClosureWithEmptyContext(offset)) { + if (scopes()->IsClosureWithEmptyContext(func_node_offset)) { instructions += NullConstant(); } else { instructions += LoadLocal(parsed_function()->current_context_var()); @@ -6072,7 +5947,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode( instructions += LoadInstantiatorTypeArguments(); } instructions += flow_graph_builder_->AllocateClosure( - position, has_instantiator_type_args, function.IsGeneric()); + function.token_pos(), has_instantiator_type_args, function.IsGeneric()); LocalVariable* closure = MakeTemporary(); // TODO(30455): We only need to save these if the closure uses any captured diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h index 3b9c6dbd524..2590cb403e5 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h @@ -370,12 +370,8 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper { Fragment BuildTryFinally(TokenPosition* position); Fragment BuildYieldStatement(TokenPosition* position); Fragment BuildVariableDeclaration(TokenPosition* position); - Fragment BuildFunctionDeclaration(intptr_t offset, TokenPosition* position); - Fragment BuildFunctionNode(TokenPosition parent_position, - StringIndex name_index, - bool has_valid_annotation, - bool has_pragma, - intptr_t func_decl_offset); + Fragment BuildFunctionDeclaration(TokenPosition* position); + Fragment BuildFunctionNode(intptr_t func_decl_offset); // Build flow graph for '_nativeEffect'. Fragment BuildNativeEffect(); diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc index 87058627d1a..994b174569d 100644 --- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc +++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc @@ -5,6 +5,7 @@ #include "vm/compiler/frontend/kernel_translation_helper.h" #include "vm/class_finalizer.h" +#include "vm/closure_functions_cache.h" #include "vm/compiler/aot/precompiler.h" #include "vm/compiler/backend/flow_graph_compiler.h" #include "vm/compiler/frontend/constant_reader.h" @@ -2247,21 +2248,39 @@ void KernelReaderHelper::ReportUnexpectedTag(const char* variant, Tag tag) { void KernelReaderHelper::ReadUntilFunctionNode() { const Tag tag = PeekTag(); - if (tag == kProcedure) { - ProcedureHelper procedure_helper(this); - procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); - // Now at start of FunctionNode. - } else if (tag == kConstructor) { - ConstructorHelper constructor_helper(this); - constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction); - // Now at start of FunctionNode. - // Notice that we also have a list of initializers after that! - } else if (tag == kFunctionNode) { - // Already at start of FunctionNode. - } else { - ReportUnexpectedTag("a procedure, a constructor or a function node", tag); - UNREACHABLE(); + switch (tag) { + case kProcedure: { + ProcedureHelper procedure_helper(this); + procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); + // Now at start of FunctionNode. + break; + } + case kConstructor: { + ConstructorHelper constructor_helper(this); + constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction); + // Now at start of FunctionNode. + // Notice that we also have a list of initializers after that! + break; + } + case kFunctionDeclaration: + ReadTag(); + ReadPosition(); + SkipVariableDeclaration(); + break; + case kFunctionExpression: + ReadTag(); + ReadPosition(); + break; + case kFunctionNode: + // Already at start of FunctionNode. + break; + default: + ReportUnexpectedTag( + "a procedure, a constructor, a local function or a function node", + tag); + UNREACHABLE(); } + ASSERT(PeekTag() == kFunctionNode); } void KernelReaderHelper::SkipDartType() { diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc index 08245750ab4..7c944810795 100644 --- a/runtime/vm/kernel_loader.cc +++ b/runtime/vm/kernel_loader.cc @@ -9,6 +9,7 @@ #include +#include "vm/closure_functions_cache.h" #include "vm/compiler/backend/flow_graph_compiler.h" #include "vm/compiler/frontend/constant_reader.h" #include "vm/compiler/frontend/kernel_translation_helper.h" @@ -1037,7 +1038,7 @@ void KernelLoader::FinishTopLevelClassLoading( field_helper.ReadUntilExcluding(FieldHelper::kAnnotations); intptr_t annotation_count = helper_.ReadListLength(); uint32_t pragma_bits = 0; - ReadVMAnnotations(library, annotation_count, &pragma_bits); + ReadVMAnnotations(annotation_count, &pragma_bits); field_helper.SetJustRead(FieldHelper::kAnnotations); field_helper.ReadUntilExcluding(FieldHelper::kType); @@ -1351,7 +1352,7 @@ void KernelLoader::LoadClass(const Library& library, class_helper.ReadUntilExcluding(ClassHelper::kAnnotations); intptr_t annotation_count = helper_.ReadListLength(); uint32_t pragma_bits = 0; - ReadVMAnnotations(library, annotation_count, &pragma_bits); + ReadVMAnnotations(annotation_count, &pragma_bits); if (IsolateUnsendablePragma::decode(pragma_bits)) { out_class->set_is_isolate_unsendable_due_to_pragma(true); } @@ -1440,7 +1441,7 @@ void KernelLoader::FinishClassLoading(const Class& klass, field_helper.ReadUntilExcluding(FieldHelper::kAnnotations); const intptr_t annotation_count = helper_.ReadListLength(); uint32_t pragma_bits = 0; - ReadVMAnnotations(library, annotation_count, &pragma_bits); + ReadVMAnnotations(annotation_count, &pragma_bits); field_helper.SetJustRead(FieldHelper::kAnnotations); field_helper.ReadUntilExcluding(FieldHelper::kType); @@ -1567,7 +1568,7 @@ void KernelLoader::FinishClassLoading(const Class& klass, constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations); const intptr_t annotation_count = helper_.ReadListLength(); uint32_t pragma_bits = 0; - ReadVMAnnotations(library, annotation_count, &pragma_bits); + ReadVMAnnotations(annotation_count, &pragma_bits); constructor_helper.SetJustRead(ConstructorHelper::kAnnotations); constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction); @@ -1721,8 +1722,7 @@ void KernelLoader::FinishLoading(const Class& klass) { // // `pragma_bits`: any recognized pragma that was found // -void KernelLoader::ReadVMAnnotations(const Library& library, - intptr_t annotation_count, +void KernelLoader::ReadVMAnnotations(intptr_t annotation_count, uint32_t* pragma_bits, String* native_name) { *pragma_bits = 0; @@ -1806,7 +1806,7 @@ void KernelLoader::LoadProcedure(const Library& library, String& native_name = String::Handle(Z); uint32_t pragma_bits = 0; const intptr_t annotation_count = helper_.ReadListLength(); - ReadVMAnnotations(library, annotation_count, &pragma_bits, &native_name); + ReadVMAnnotations(annotation_count, &pragma_bits, &native_name); is_external = is_external && native_name.IsNull(); procedure_helper.SetJustRead(ProcedureHelper::kAnnotations); const Object& script_class = @@ -2199,6 +2199,155 @@ UntaggedFunction::Kind KernelLoader::GetFunctionType( return static_cast(lookuptable[kind]); } +FunctionPtr KernelLoader::LoadClosureFunction(const Function& parent_function, + const Object& closure_owner) { + const intptr_t func_decl_offset = helper_.ReaderOffset(); + const Tag tag = helper_.ReadTag(); + ASSERT((tag == kFunctionExpression) || (tag == kFunctionDeclaration)); + const bool is_declaration = (tag == kFunctionDeclaration); + + TokenPosition position = helper_.ReadPosition(); // read position. + + uint32_t pragma_bits = 0; + intptr_t annotation_count = 0; + const String* name; + if (is_declaration) { + // Read variable declaration. + VariableDeclarationHelper variable_helper(&helper_); + + variable_helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations); + const intptr_t annotation_count = helper_.ReadListLength(); + ReadVMAnnotations(annotation_count, &pragma_bits); + variable_helper.SetJustRead(VariableDeclarationHelper::kAnnotations); + + variable_helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd); + name = &H.DartSymbolObfuscate(variable_helper.name_index_); + } else { + name = &Symbols::AnonymousClosure(); + } + + const intptr_t func_node_offset = helper_.ReaderOffset(); + + FunctionNodeHelper function_node_helper(&helper_); + function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); + + Function& function = Function::Handle(Z); + if (!closure_owner.IsNull()) { + function = Function::NewClosureFunctionWithKind( + UntaggedFunction::kClosureFunction, *name, parent_function, + parent_function.is_static(), position, closure_owner); + } else { + function = Function::NewClosureFunction(*name, parent_function, position); + } + + const bool has_pragma = HasPragma::decode(pragma_bits); + function.set_has_pragma(has_pragma); + function.set_is_visible(!InvisibleFunctionPragma::decode(pragma_bits)); + if ((FLAG_enable_mirrors && (annotation_count > 0)) || has_pragma) { + const auto& lib = + Library::Handle(Z, Class::Handle(Z, function.Owner()).library()); + lib.AddMetadata(function, func_decl_offset); + } + + if (function_node_helper.async_marker_ == FunctionNodeHelper::kAsync) { + function.set_modifier(UntaggedFunction::kAsync); + function.set_is_inlinable(false); + ASSERT(function.IsAsyncFunction()); + } else if (function_node_helper.async_marker_ == + FunctionNodeHelper::kAsyncStar) { + function.set_modifier(UntaggedFunction::kAsyncGen); + function.set_is_inlinable(false); + ASSERT(function.IsAsyncGenerator()); + } else if (function_node_helper.async_marker_ == + FunctionNodeHelper::kSyncStar) { + function.set_modifier(UntaggedFunction::kSyncGen); + function.set_is_inlinable(false); + ASSERT(function.IsSyncGenerator()); + } else { + ASSERT(function_node_helper.async_marker_ == FunctionNodeHelper::kSync); + ASSERT(!function.IsAsyncFunction()); + ASSERT(!function.IsAsyncGenerator()); + ASSERT(!function.IsSyncGenerator()); + } + + // If the start token position is synthetic, the end token position + // should be as well. + function.set_end_token_pos( + position.IsReal() ? function_node_helper.end_position_ : position); + + function.set_kernel_offset(func_node_offset); + T.SetupFunctionParameters(Class::Handle(Z), function, + false, // is_method + true, // is_closure + &function_node_helper); + // type_translator->SetupUnboxingInfoMetadata is not called here at the + // moment because closures do not have unboxed parameters and return + // value + + // Finalize function type. + FunctionType& signature = FunctionType::Handle(Z, function.signature()); + signature ^= ClassFinalizer::FinalizeType(signature); + function.SetSignature(signature); + + ClosureFunctionsCache::AddClosureFunctionLocked(function); + + return function.ptr(); +} + +FunctionPtr KernelLoader::GetClosureFunction(Thread* thread, + intptr_t func_decl_offset, + const Function& member_function, + const Function& parent_function, + const Object& closure_owner) { + Zone* zone = thread->zone(); + Function& function = Function::Handle(zone); + intptr_t func_node_offset = -1; + + const auto& kernel_info = + KernelProgramInfo::Handle(zone, member_function.KernelProgramInfo()); + const auto& library_kernel_data = + TypedDataView::Handle(zone, member_function.KernelLibrary()); + ASSERT(!library_kernel_data.IsNull()); + const intptr_t library_kernel_offset = member_function.KernelLibraryOffset(); + + KernelLoader kernel_loader(kernel_info, library_kernel_data, + library_kernel_offset); + { + // TODO(alexmarkov): Use func_decl_offset as a key in ClosureFunctionsCache + // instead of func_node_offset and avoid this reading. + kernel_loader.helper_.SetOffset(func_decl_offset); + kernel_loader.helper_.ReadUntilFunctionNode(); + func_node_offset = kernel_loader.helper_.ReaderOffset(); + + { + SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock()); + function = ClosureFunctionsCache::LookupClosureFunctionLocked( + member_function, func_node_offset); + if (!function.IsNull()) { + return function.ptr(); + } + } + } + + SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock()); + function = ClosureFunctionsCache::LookupClosureFunctionLocked( + member_function, func_node_offset); + if (function.IsNull()) { + ActiveClassScope active_class_scope( + &kernel_loader.active_class_, + &Class::Handle(zone, member_function.Owner())); + ActiveMemberScope active_member(&kernel_loader.active_class_, + &member_function); + ActiveTypeParametersScope active_type_params( + &kernel_loader.active_class_, member_function, + &FunctionType::Handle(zone, parent_function.signature()), zone); + kernel_loader.helper_.SetOffset(func_decl_offset); + function = + kernel_loader.LoadClosureFunction(parent_function, closure_owner); + } + return function.ptr(); +} + FunctionPtr CreateFieldInitializerFunction(Thread* thread, Zone* zone, const Field& field) { diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h index 944fc94c508..f7e46e09346 100644 --- a/runtime/vm/kernel_loader.h +++ b/runtime/vm/kernel_loader.h @@ -212,6 +212,14 @@ class KernelLoader : public ValueObject { void ReadObfuscationProhibitions(); void ReadLoadingUnits(); + // Get closure Function from cache or create it if it is not created yet. + // [func_decl_offset] is an offset FunctionExpression or FunctionDeclaration. + static FunctionPtr GetClosureFunction(Thread* thread, + intptr_t func_decl_offset, + const Function& member_function, + const Function& parent_function, + const Object& closure_owner); + private: // Pragma bits using HasPragma = BitField; @@ -231,8 +239,7 @@ class KernelLoader : public ValueObject { bool IsClassName(NameIndex name, const String& library, const String& klass); - void ReadVMAnnotations(const Library& library, - intptr_t annotation_count, + void ReadVMAnnotations(intptr_t annotation_count, uint32_t* pragma_bits, String* native_name = nullptr); @@ -336,6 +343,12 @@ class KernelLoader : public ValueObject { UntaggedFunction::Kind GetFunctionType(ProcedureHelper::Kind procedure_kind); + // Read local function (either FunctionExpression or FunctionDeclaration) + // and create corresponding Function object. + // If [closure_owner] is not null, it overrides closure function owner. + FunctionPtr LoadClosureFunction(const Function& parent_function, + const Object& closure_owner); + Program* program_; Thread* thread_; diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc index 30a31f6662c..a0e73043558 100644 --- a/runtime/vm/object_store.cc +++ b/runtime/vm/object_store.cc @@ -181,8 +181,6 @@ ErrorPtr ObjectStore::PreallocateObjects() { ASSERT(this->stack_overflow() == Instance::null()); ASSERT(this->out_of_memory() == Instance::null()); - this->closure_functions_ = GrowableObjectArray::New(); - Object& result = Object::Handle(); const Library& library = Library::Handle(Library::CoreLibrary());