[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>
This commit is contained in:
committed by
Commit Queue
parent
ecf5abcbd3
commit
1695da67c7
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
+156
-7
@@ -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 @@ 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<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) {
|
||||
|
||||
@@ -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<uint32_t, bool, 0, 1>;
|
||||
@@ -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_;
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user