[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 <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/closure_functions_cache.cc b/runtime/vm/closure_functions_cache.cc
index add92ff..0cb609b 100644
--- a/runtime/vm/closure_functions_cache.cc
+++ b/runtime/vm/closure_functions_cache.cc
@@ -75,9 +75,13 @@
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 @@
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 @@
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 @@
// 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 d9d2afa..eaa5a82 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::BuildStatement(TokenPosition* position) {
++num_ast_nodes_;
- intptr_t offset = ReaderOffset();
Tag tag = ReadTag(); // read tag.
switch (tag) {
case kExpressionStatement:
@@ -1248,7 +1248,7 @@
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::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::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 @@
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 3b9c6db..2590cb4 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -370,12 +370,8 @@
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 8705862..994b174 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::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 0824575..7c94481 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -9,6 +9,7 @@
#include <memory>
+#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 @@
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 @@
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 @@
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 @@
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 @@
//
// `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 @@
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 @@
return static_cast<UntaggedFunction::Kind>(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 944fc94..f7e46e0 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -212,6 +212,14 @@
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<uint32_t, bool, 0, 1>;
@@ -231,8 +239,7 @@
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 @@
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 30a31f6..a0e7304 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -181,8 +181,6 @@
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());