[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:
Alexander Markov
2024-03-13 14:33:48 +00:00
committed by Commit Queue
parent ecf5abcbd3
commit 1695da67c7
7 changed files with 242 additions and 183 deletions
+16 -7
View File
@@ -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
View File
@@ -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) {
+15 -2
View File
@@ -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_;
-2
View File
@@ -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());