diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md index b07e9a289b6..09fc3e6277d 100644 --- a/pkg/kernel/binary.md +++ b/pkg/kernel/binary.md @@ -329,6 +329,7 @@ type FunctionNode { Byte asyncMarker; // Index into AsyncMarker above. Byte dartAsyncMarker; // Index into AsyncMarker above. List typeParameters; + UInt parameterCount; // positionalParameters.length + namedParameters.length. UInt requiredParameterCount; List positionalParameters; List namedParameters; diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart index 95a4ea30dd7..b730ddebe8f 100644 --- a/pkg/kernel/lib/binary/ast_from_binary.dart +++ b/pkg/kernel/lib/binary/ast_from_binary.dart @@ -617,6 +617,7 @@ class BinaryBuilder { AsyncMarker dartAsyncMarker = AsyncMarker.values[readByte()]; int typeParameterStackHeight = typeParameterStack.length; var typeParameters = readAndPushTypeParameterList(); + readUInt(); // total parameter count. var requiredParameterCount = readUInt(); int variableStackHeight = variableStack.length; var positional = readAndPushVariableDeclarationList(); diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart index bc293377d98..80a31bc3c57 100644 --- a/pkg/kernel/lib/binary/ast_to_binary.dart +++ b/pkg/kernel/lib/binary/ast_to_binary.dart @@ -482,6 +482,7 @@ class BinaryPrinter extends Visitor { writeByte(node.asyncMarker.index); writeByte(node.dartAsyncMarker.index); writeNodeList(node.typeParameters); + writeUInt30(node.positionalParameters.length + node.namedParameters.length); writeUInt30(node.requiredParameterCount); writeVariableDeclarationList(node.positionalParameters); writeVariableDeclarationList(node.namedParameters); diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index 54b22a663ac..9e2a1ddf04d 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -145,7 +145,7 @@ static RawInstance* CreateParameterMirrorList(const Function& func, // * Whether a parameters has been declared as final. // * Any metadata associated with the parameter. Object& result = Object::Handle(); - if (func.kernel_function() != NULL) { + if (func.kernel_offset() > 0) { result = kernel::BuildParameterDescriptor(func); } else { result = Parser::ParseFunctionParameters(func); diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc index 288e0569838..13ac6751d36 100644 --- a/runtime/vm/class_finalizer.cc +++ b/runtime/vm/class_finalizer.cc @@ -1631,7 +1631,7 @@ void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) { /* is_native = */ false, cls, field.token_pos())); getter.set_result_type(type); getter.set_is_debuggable(false); - getter.set_kernel_function(field.kernel_field()); + getter.set_kernel_offset(field.kernel_offset()); cls.AddFunction(getter); field.SetStaticValue(Object::sentinel(), true); } @@ -2389,7 +2389,7 @@ void ClassFinalizer::ApplyMixinMembers(const Class& cls) { } else { for (intptr_t i = 0; i < functions.Length(); i++) { func ^= functions.At(i); - ASSERT(func.kernel_function() != 0); + ASSERT(func.kernel_offset() > 0); cloned_funcs.Add(func); } } diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc index a99d4ba3b5f..f5a702a4b62 100644 --- a/runtime/vm/compiler.cc +++ b/runtime/vm/compiler.cc @@ -115,7 +115,7 @@ DECLARE_FLAG(bool, trace_irregexp); bool UseKernelFrontEndFor(ParsedFunction* parsed_function) { const Function& function = parsed_function->function(); - return (function.kernel_function() != NULL) || + return (function.kernel_offset() > 0) || (function.kind() == RawFunction::kNoSuchMethodDispatcher) || (function.kind() == RawFunction::kInvokeFieldDispatcher); } @@ -135,11 +135,11 @@ FlowGraph* DartCompilationPipeline::BuildFlowGraph( const ZoneGrowableArray& ic_data_array, intptr_t osr_id) { if (UseKernelFrontEndFor(parsed_function)) { - kernel::TreeNode* node = static_cast( - parsed_function->function().kernel_function()); - kernel::FlowGraphBuilder builder(node, parsed_function, ic_data_array, - /* not building var desc */ NULL, - /* not inlining */ NULL, osr_id); + kernel::FlowGraphBuilder builder( + parsed_function->function().kernel_offset(), parsed_function, + ic_data_array, + /* not building var desc */ NULL, + /* not inlining */ NULL, osr_id); FlowGraph* graph = builder.BuildGraph(); ASSERT(graph != NULL); return graph; @@ -1606,10 +1606,9 @@ void Compiler::ComputeLocalVarDescriptors(const Code& code) { builder.BuildGraph(); } else { parsed_function->EnsureKernelScopes(); - kernel::TreeNode* node = static_cast( - parsed_function->function().kernel_function()); kernel::FlowGraphBuilder builder( - node, parsed_function, *ic_data_array, context_level_array, + parsed_function->function().kernel_offset(), parsed_function, + *ic_data_array, context_level_array, /* not inlining */ NULL, Compiler::kNoOSRDeoptId); builder.BuildGraph(); } @@ -1732,7 +1731,7 @@ RawObject* Compiler::EvaluateStaticInitializer(const Field& field) { // Create a one-time-use function to evaluate the initializer and invoke // it immediately. - if (field.kernel_field() != NULL) { + if (field.kernel_offset() > 0) { parsed_function = kernel::ParseStaticFieldInitializer(zone, field); } else { parsed_function = Parser::ParseStaticFieldInitializer(field); diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc index b5063f899d1..65c37415495 100644 --- a/runtime/vm/flow_graph_inliner.cc +++ b/runtime/vm/flow_graph_inliner.cc @@ -796,12 +796,9 @@ class CallSiteInliner : public ValueObject { new (Z) InlineExitCollector(caller_graph_, call); FlowGraph* callee_graph; if (UseKernelFrontEndFor(parsed_function)) { - kernel::TreeNode* node = static_cast( - parsed_function->function().kernel_function()); - kernel::FlowGraphBuilder builder( - node, parsed_function, *ic_data_array, - /* not building var desc */ NULL, exit_collector, + parsed_function->function().kernel_offset(), parsed_function, + *ic_data_array, /* not building var desc */ NULL, exit_collector, Compiler::kNoOSRDeoptId, caller_graph_->max_block_id() + 1); { CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer); diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h index e2970b11074..70f5f36405f 100644 --- a/runtime/vm/kernel.h +++ b/runtime/vm/kernel.h @@ -429,7 +429,10 @@ class TreeNode : public Node { virtual void AcceptVisitor(Visitor* visitor); virtual void AcceptTreeVisitor(TreeVisitor* visitor) = 0; - intptr_t kernel_offset() const { return kernel_offset_; } + intptr_t kernel_offset() const { + ASSERT(kernel_offset_ > 0); + return kernel_offset_; + } bool can_stream() { return can_stream_; } protected: diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc index dd791b1446b..690224221a3 100644 --- a/runtime/vm/kernel_binary.cc +++ b/runtime/vm/kernel_binary.cc @@ -257,6 +257,7 @@ Typedef* Typedef::ReadFrom(Reader* reader) { Class* Class::ReadFrom(Reader* reader) { TRACE_READ_OFFSET(); + kernel_offset_ = reader->offset() - 1; // -1 to include tag byte. canonical_name_ = reader->ReadCanonicalNameReference(); position_ = reader->ReadPosition(false); is_abstract_ = reader->ReadBool(); @@ -1843,6 +1844,7 @@ FunctionNode* FunctionNode::ReadFrom(Reader* reader) { function->dart_async_marker_ = static_cast(reader->ReadByte()); function->type_parameters().ReadFrom(reader); + reader->ReadUInt(); // total parameter count. function->required_parameter_count_ = reader->ReadUInt(); function->positional_parameters().ReadFromStatic( reader); diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc index c88ddce65eb..adcfcec719e 100644 --- a/runtime/vm/kernel_binary_flowgraph.cc +++ b/runtime/vm/kernel_binary_flowgraph.cc @@ -4,6 +4,7 @@ #include "vm/kernel_binary_flowgraph.h" +#include "vm/compiler.h" #include "vm/longjump.h" #include "vm/object_store.h" @@ -54,27 +55,6 @@ StreamingScopeBuilder::~StreamingScopeBuilder() { delete builder_; } -void StreamingScopeBuilder::DiscoverEnclosingElements( - Zone* zone, - const Function& function, - Function* outermost_function, - intptr_t* outermost_kernel_offset, - intptr_t* parent_class_offset) { - // Find out if there is an enclosing kernel class (which will be used to - // resolve type parameters). - *outermost_function = function.raw(); - while (outermost_function->parent_function() != Object::null()) { - *outermost_function = outermost_function->parent_function(); - } - - if (outermost_function->kernel_function() != NULL) { - *outermost_kernel_offset = - static_cast(outermost_function->kernel_function()) - ->kernel_offset(); - *parent_class_offset = GetParentOffset(*outermost_kernel_offset); - } -} - ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { if (result_ != NULL) return result_; @@ -91,16 +71,18 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { Function& outermost_function = Function::Handle(Z); intptr_t outermost_kernel_offset = -1; intptr_t parent_class_offset = -1; - DiscoverEnclosingElements(Z, function, &outermost_function, - &outermost_kernel_offset, &parent_class_offset); + builder_->DiscoverEnclosingElements(Z, function, &outermost_function, + &outermost_kernel_offset, + &parent_class_offset); // Use [klass]/[kernel_class] as active class. Type parameters will get // resolved via [kernel_class] unless we are nested inside a static factory // in which case we will use [member]. intptr_t class_type_parameters = 0; intptr_t class_type_parameters_offset_start = -1; if (parent_class_offset > 0) { - GetTypeParameterInfoForClass(parent_class_offset, &class_type_parameters, - &class_type_parameters_offset_start); + builder_->GetTypeParameterInfoForClass(parent_class_offset, + &class_type_parameters, + &class_type_parameters_offset_start); } ActiveClassScope active_class_scope(&active_class_, class_type_parameters, class_type_parameters_offset_start, @@ -110,7 +92,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { bool is_factory_procedure = false; intptr_t member_type_parameters = 0; intptr_t member_type_parameters_offset_start = -1; - GetTypeParameterInfoForPossibleProcedure( + builder_->GetTypeParameterInfoForPossibleProcedure( outermost_kernel_offset, &member_is_procedure, &is_factory_procedure, &member_type_parameters, &member_type_parameters_offset_start); @@ -144,27 +126,10 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { case RawFunction::kSetterFunction: case RawFunction::kConstructor: { const Tag tag = builder_->PeekTag(); - if (tag == kProcedure) { - Tag has_function_node = ReadProcedureUntilFunctionNode( - &unused_word, &unused_intptr); // read first part of procedure. - if (has_function_node == kNothing) { - // Running a procedure without a function node doesn't make sense. - UNREACHABLE(); - } - // Now at start of FunctionNode. - } else if (tag == kConstructor) { - // read first part of constructor. - parent_offset = ReadConstructorUntilFunctionNode(); - // 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 { - UNREACHABLE(); - } + parent_offset = builder_->ReadUntilFunctionNode(); word async_marker_word; - ReadFunctionNodeUntilTypeParameters( - &async_marker_word, + builder_->ReadFunctionNodeUntilTypeParameters( + &unused_tokenposition, &unused_tokenposition, &async_marker_word, &unused_word); // read first part of function node. current_function_async_marker_ = static_cast(async_marker_word); @@ -193,7 +158,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { if (tag == kConstructor) { ASSERT(parent_offset >= 0); AlternativeReadingScope alt(builder_->reader_, parent_offset); - ReadClassUntilFields(); // read first part of class. + builder_->ReadClassUntilFields(); // read first part of class. intptr_t list_length = builder_->ReadListLength(); // read fields list length. for (intptr_t i = 0; i < list_length; i++) { @@ -201,12 +166,14 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { TokenPosition position; TokenPosition end_position; word flags; - ReadFieldUntilAnnotation(&position, &end_position, &flags, - &unused_intptr); + builder_->ReadFieldUntilAnnotation(&unused_nameindex, &position, + &end_position, &flags, + &unused_intptr); bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; builder_->SkipListOfExpressions(); // read annotations. builder_->SkipDartType(); // read type. - Tag initializer_tag = builder_->ReadTag(); + Tag initializer_tag = + builder_->ReadTag(); // read first part of initializer. if (!is_static && initializer_tag == kSomething) { EnterScope(field_offset); VisitExpression(); // read initializer. @@ -226,6 +193,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { // Continue reading FunctionNode. builder_->SkipTypeParametersList(); // read type_parameters. + builder_->ReadUInt(); // read total parameter count. builder_->ReadUInt(); // read required_parameter_count. AddPositionalAndNamedParameters( pos); // read positional_parameters and named_parameters. @@ -319,40 +287,6 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { return result_; } -intptr_t StreamingScopeBuilder::GetParentOffset(intptr_t offset) { - AlternativeReadingScope alt(builder_->reader_, offset); - - Tag tag = builder_->PeekTag(); - intptr_t parent_offset = -1; - switch (tag) { - case kConstructor: - return ReadConstructorUntilFunctionNode(); - case kProcedure: - ReadProcedureUntilFunctionNode( - &unused_word, &parent_offset); // read first part of procedure. - return parent_offset; - case kField: - ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, - &unused_word, &parent_offset); - return parent_offset; - default: - UNIMPLEMENTED(); - return -1; - } -} - -void StreamingScopeBuilder::GetTypeParameterInfoForClass( - intptr_t class_offset, - intptr_t* type_paremeter_counts, - intptr_t* type_paremeter_offset) { - AlternativeReadingScope alt(builder_->reader_, class_offset); - - ReadClassUntilTypeParameters(); - *type_paremeter_counts = - builder_->ReadListLength(); // read type_parameters list length. - *type_paremeter_offset = builder_->ReaderOffset(); -} - void StreamingScopeBuilder::VisitNode() { Tag tag = builder_->PeekTag(); switch (tag) { @@ -374,37 +308,25 @@ void StreamingScopeBuilder::VisitNode() { } } -intptr_t StreamingScopeBuilder::ReadConstructorUntilFunctionNode() { - Tag tag = builder_->ReadTag(); - ASSERT(tag == kConstructor); - builder_->SkipCanonicalNameReference(); // read canonical name reference. - builder_->ReadPosition(); // read position. - builder_->ReadPosition(); // read end position. - builder_->ReadFlags(); // read flags. - intptr_t parent_offset = builder_->ReadUInt(); // parent class binary offset. - builder_->SkipName(); // read name. - builder_->SkipListOfExpressions(); // read annotations. - return parent_offset; -} - void StreamingScopeBuilder::VisitConstructor() { // Field initializers that come from non-static field declarations are // compiled as if they appear in the constructor initializer list. This is // important for closure-valued field initializers because the VM expects the // corresponding closure functions to appear as if they were nested inside the // constructor. - intptr_t parent_offset = ReadConstructorUntilFunctionNode(); + intptr_t parent_offset = builder_->ReadConstructorUntilFunctionNode(); ASSERT(parent_offset >= 0); { AlternativeReadingScope alt(builder_->reader_, parent_offset); - ReadClassUntilFields(); // read first part of class. + builder_->ReadClassUntilFields(); // read first part of class. intptr_t list_length = builder_->ReadListLength(); // read fields list length. for (intptr_t i = 0; i < list_length; i++) { word flags; - ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, - &flags, &unused_intptr); + builder_->ReadFieldUntilAnnotation( + &unused_nameindex, &unused_tokenposition, &unused_tokenposition, + &flags, &unused_intptr); bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; builder_->SkipListOfExpressions(); // read annotations. builder_->SkipDartType(); // read type. @@ -427,34 +349,17 @@ void StreamingScopeBuilder::VisitConstructor() { } void StreamingScopeBuilder::VisitProcedure() { - Tag function_node = ReadProcedureUntilFunctionNode( + Tag function_node = builder_->ReadProcedureUntilFunctionNode( &unused_word, &unused_intptr); // read first part of procedure. if (function_node == kSomething) { VisitFunctionNode(); } } -void StreamingScopeBuilder::ReadFieldUntilAnnotation( - TokenPosition* position, - TokenPosition* end_position, - word* flags, - intptr_t* parent_offset) { - Tag tag = builder_->ReadTag(); - ASSERT(tag == kField); - - builder_->SkipCanonicalNameReference(); // read canonical_name. - *position = builder_->ReadPosition(); // read position. - *end_position = builder_->ReadPosition(); // read end position. - *flags = builder_->ReadFlags(); // read flags. - *parent_offset = builder_->ReadUInt(); // read parent class binary offset. - builder_->SkipName(); // read name. - builder_->ReadUInt(); // source_uri_index. -} - void StreamingScopeBuilder::VisitField() { - ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, - &unused_intptr, - &unused_word); // read first part of field. + builder_->ReadFieldUntilAnnotation( + &unused_nameindex, &unused_tokenposition, &unused_tokenposition, + &unused_intptr, &unused_word); // read first part of field. builder_->SkipListOfExpressions(); // read annotations. VisitDartType(); // read type. Tag tag = builder_->ReadTag(); // read initializer (part 1). @@ -463,98 +368,12 @@ void StreamingScopeBuilder::VisitField() { } } -Tag StreamingScopeBuilder::ReadProcedureUntilFunctionNode( - word* kind, - intptr_t* parent_offset) { - Tag tag = builder_->ReadTag(); // read tag. - ASSERT(tag == kProcedure); - builder_->SkipCanonicalNameReference(); // read canonical name reference. - builder_->ReadPosition(); // read position. - builder_->ReadPosition(); // read end position. - *kind = builder_->ReadByte(); // read kind. - builder_->ReadFlags(); // read flags. - *parent_offset = builder_->ReadUInt(); // read parent class binary offset. - builder_->SkipName(); // read name, - builder_->ReadUInt(); // read source_uri_index. - builder_->SkipListOfExpressions(); // read annotations. - return builder_->ReadTag(); // read tag for optional function node. -} - -void StreamingScopeBuilder::GetTypeParameterInfoForPossibleProcedure( - intptr_t outermost_kernel_offset, - bool* member_is_procedure, - bool* is_factory_procedure, - intptr_t* member_type_parameters, - intptr_t* member_type_parameters_offset_start) { - if (outermost_kernel_offset >= 0) { - AlternativeReadingScope alt(builder_->reader_, outermost_kernel_offset); - Tag tag = builder_->PeekTag(); - if (tag == kProcedure) { - *member_is_procedure = true; - - word kind; - tag = ReadProcedureUntilFunctionNode( - &kind, &unused_intptr); // read first part of procedure. - *is_factory_procedure = - static_cast(kind) == Procedure::kFactory; - - if (tag == kSomething) { - ReadFunctionNodeUntilTypeParameters( - &unused_word, &unused_word); // read first part of function node. - - intptr_t list_length = - builder_->ReadListLength(); // read type_parameters list length. - if (list_length > 0) { - *member_type_parameters = list_length; - *member_type_parameters_offset_start = builder_->ReaderOffset(); - } - } - } - } -} - -void StreamingScopeBuilder::ReadClassUntilTypeParameters() { - Tag class_tag = builder_->ReadTag(); - ASSERT(class_tag == kClass); - builder_->SkipCanonicalNameReference(); // read canonical_name. - builder_->ReadPosition(); // read position. - builder_->ReadBool(); // read is_abstract. - builder_->SkipStringReference(); // read name index. - builder_->ReadUInt(); // read source_uri_index. - builder_->SkipListOfExpressions(); // read annotations. -} - -void StreamingScopeBuilder::ReadClassUntilFields() { - ReadClassUntilTypeParameters(); - builder_->SkipTypeParametersList(); // read type_parameters. - Tag type_tag = builder_->ReadTag(); // read type (part 1). - if (type_tag == kSomething) { - builder_->SkipDartType(); // read type (part 2). - } - type_tag = builder_->ReadTag(); // read Mixed-in type (part 1). - if (type_tag == kSomething) { - builder_->SkipDartType(); // read Mixed-in type (part 2). - } - builder_->SkipListOfDartTypes(); // read implemented_classes. -} - -void StreamingScopeBuilder::ReadFunctionNodeUntilTypeParameters( - word* async_marker, - word* dart_async_marker) { - Tag tag = builder_->ReadTag(); // read tag. - ASSERT(tag == kFunctionNode); - - builder_->ReadPosition(); // read position. - builder_->ReadPosition(); // read end position. - *async_marker = builder_->ReadByte(); // read async marker. - *dart_async_marker = builder_->ReadByte(); // read dart async marker. -} - void StreamingScopeBuilder::VisitFunctionNode() { word async_marker_word; word dart_async_marker_word; - ReadFunctionNodeUntilTypeParameters(&async_marker_word, - &dart_async_marker_word); + builder_->ReadFunctionNodeUntilTypeParameters( + &unused_tokenposition, &unused_tokenposition, &async_marker_word, + &dart_async_marker_word); FunctionNode::AsyncMarker async_marker = static_cast(async_marker_word); FunctionNode::AsyncMarker dart_async_marker = @@ -589,6 +408,7 @@ void StreamingScopeBuilder::VisitFunctionNode() { // Read (but don't visit) the positional and named parameters, because they've // already been added to the scope. + builder_->ReadUInt(); // read total parameter count. builder_->ReadUInt(); // read required_parameter_count. builder_->SkipListOfVariableDeclarations(); // read list of positionals. @@ -643,11 +463,11 @@ void StreamingScopeBuilder::VisitInitializer() { VisitExpression(); // read value. return; case kSuperInitializer: - builder_->SkipCanonicalNameReference(); // read field_reference. + builder_->SkipCanonicalNameReference(); // read target_reference. VisitArguments(); // read arguments. return; case kRedirectingInitializer: - builder_->SkipCanonicalNameReference(); // read field_reference. + builder_->SkipCanonicalNameReference(); // read target_reference. VisitArguments(); // read arguments. return; case kLocalInitializer: @@ -1320,6 +1140,7 @@ void StreamingScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) { result_->function_scopes.Add(function_scope); } + builder_->ReadUInt(); // read total parameter count. builder_->ReadUInt(); // read required_parameter_count. // read positional_parameters and named_parameters. AddPositionalAndNamedParameters(); @@ -1481,16 +1302,6 @@ void StreamingScopeBuilder::AddSwitchVariable() { } } -StringIndex StreamingScopeBuilder::GetNameFromVariableDeclaration( - intptr_t kernel_offset) { - // Temporarily go to the variable declaration, read the name. - AlternativeReadingScope alt(builder_->reader_, kernel_offset); - builder_->ReadPosition(); // read position. - builder_->ReadPosition(); // read equals position. - builder_->ReadFlags(); // read flags. - return builder_->ReadStringReference(); // read name index. -} - void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offest) { LocalVariable* variable = result_->locals.Lookup(declaration_binary_offest); if (variable == NULL) { @@ -1501,7 +1312,7 @@ void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offest) { ASSERT(current_function_scope_->parent() != NULL); StringIndex var_name = - GetNameFromVariableDeclaration(declaration_binary_offest); + builder_->GetNameFromVariableDeclaration(declaration_binary_offest); const dart::String& name = H.DartSymbol(var_name); variable = current_function_scope_->parent()->LookupVariable(name, true); @@ -1586,6 +1397,17 @@ AbstractType& StreamingDartTypeTranslator::BuildType() { return dart::AbstractType::ZoneHandle(Z, result_.raw()); } +AbstractType& StreamingDartTypeTranslator::BuildTypeWithoutFinalization() { + bool saved_finalize = finalize_; + finalize_ = false; + BuildTypeInternal(); + finalize_ = saved_finalize; + + // We return a new `ZoneHandle` here on purpose: The intermediate language + // instructions do not make a copy of the handle, so we do it. + return dart::AbstractType::ZoneHandle(Z, result_.raw()); +} + AbstractType& StreamingDartTypeTranslator::BuildVariableType() { AbstractType& abstract_type = BuildType(); @@ -2189,7 +2011,6 @@ void StreamingConstantEvaluator::EvaluateStaticGet() { if (H.IsMethod(target)) { Function& closure_function = Function::ZoneHandle(Z, function.ImplicitClosureFunction()); - closure_function.set_kernel_function(function.kernel_function()); result_ = closure_function.ImplicitStaticClosure(); result_ = H.Canonicalize(result_); } else if (H.IsGetter(target)) { @@ -2639,7 +2460,7 @@ bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() { bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset, Instance* value) { - if (builder_ == NULL) return false; + if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return false; const Function& function = builder_->parsed_function()->function(); if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { @@ -2670,7 +2491,7 @@ void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset, const Instance& value) { ASSERT(Thread::Current()->IsMutatorThread()); - if (builder_ == NULL) return; + if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return; const Function& function = builder_->parsed_function()->function(); if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { @@ -2690,12 +2511,1095 @@ void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset, script_.set_compile_time_constants(constants.Release()); } +void StreamingFlowGraphBuilder::DiscoverEnclosingElements( + Zone* zone, + const Function& function, + Function* outermost_function, + intptr_t* outermost_kernel_offset, + intptr_t* parent_class_offset) { + // Find out if there is an enclosing kernel class (which will be used to + // resolve type parameters). + *outermost_function = function.raw(); + while (outermost_function->parent_function() != Object::null()) { + *outermost_function = outermost_function->parent_function(); + } -Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) { - SetOffset(kernel_offset); - return BuildExpression(); // read expression. + if (outermost_function->kernel_offset() > 0) { + *outermost_kernel_offset = outermost_function->kernel_offset(); + *parent_class_offset = GetParentOffset(*outermost_kernel_offset); + } } +intptr_t StreamingFlowGraphBuilder::GetParentOffset(intptr_t offset) { + AlternativeReadingScope alt(reader_, offset); + + Tag tag = PeekTag(); + intptr_t parent_offset = -1; + switch (tag) { + case kConstructor: + return ReadConstructorUntilFunctionNode(); + case kProcedure: + ReadProcedureUntilFunctionNode( + &unused_word, &parent_offset); // read first part of procedure. + return parent_offset; + case kField: + ReadFieldUntilAnnotation(&unused_nameindex, &unused_tokenposition, + &unused_tokenposition, &unused_word, + &parent_offset); + return parent_offset; + default: + UNIMPLEMENTED(); + return -1; + } +} + +void StreamingFlowGraphBuilder::GetTypeParameterInfoForClass( + intptr_t class_offset, + intptr_t* type_paremeter_counts, + intptr_t* type_paremeter_offset) { + AlternativeReadingScope alt(reader_, class_offset); + + ReadClassUntilTypeParameters(); + *type_paremeter_counts = + ReadListLength(); // read type_parameters list length. + *type_paremeter_offset = ReaderOffset(); +} + +void StreamingFlowGraphBuilder::ReadClassUntilFields() { + ReadClassUntilTypeParameters(); + SkipTypeParametersList(); // read type_parameters. + Tag type_tag = ReadTag(); // read type (part 1). + if (type_tag == kSomething) { + SkipDartType(); // read type (part 2). + } + type_tag = ReadTag(); // read Mixed-in type (part 1). + if (type_tag == kSomething) { + SkipDartType(); // read Mixed-in type (part 2). + } + SkipListOfDartTypes(); // read implemented_classes. +} + +void StreamingFlowGraphBuilder::ReadClassUntilTypeParameters() { + Tag class_tag = ReadTag(); + ASSERT(class_tag == kClass); + SkipCanonicalNameReference(); // read canonical_name. + ReadPosition(); // read position. + ReadBool(); // read is_abstract. + SkipStringReference(); // read name index. + ReadUInt(); // read source_uri_index. + SkipListOfExpressions(); // read annotations. +} + +intptr_t StreamingFlowGraphBuilder::ReadConstructorUntilFunctionNode() { + Tag tag = ReadTag(); + ASSERT(tag == kConstructor); + SkipCanonicalNameReference(); // read canonical name reference. + ReadPosition(); // read position. + ReadPosition(); // read end position. + ReadFlags(); // read flags. + intptr_t parent_offset = ReadUInt(); // parent class binary offset. + SkipName(); // read name. + SkipListOfExpressions(); // read annotations. + return parent_offset; +} + +Tag StreamingFlowGraphBuilder::ReadProcedureUntilFunctionNode( + word* kind, + intptr_t* parent_offset) { + Tag tag = ReadTag(); // read tag. + ASSERT(tag == kProcedure); + SkipCanonicalNameReference(); // read canonical name reference. + ReadPosition(); // read position. + ReadPosition(); // read end position. + *kind = ReadByte(); // read kind. + ReadFlags(); // read flags. + *parent_offset = ReadUInt(); // read parent class binary offset. + SkipName(); // read name, + ReadUInt(); // read source_uri_index. + SkipListOfExpressions(); // read annotations. + return ReadTag(); // read tag for optional function node. +} + +void StreamingFlowGraphBuilder::ReadFieldUntilAnnotation( + NameIndex* canonical_name, + TokenPosition* position, + TokenPosition* end_position, + word* flags, + intptr_t* parent_offset) { + Tag tag = ReadTag(); + ASSERT(tag == kField); + + *canonical_name = ReadCanonicalNameReference(); // read canonical_name. + *position = ReadPosition(); // read position. + *end_position = ReadPosition(); // read end position. + *flags = ReadFlags(); // read flags. + *parent_offset = ReadUInt(); // read parent class binary offset. + SkipName(); // read name. + ReadUInt(); // source_uri_index. +} + +void StreamingFlowGraphBuilder::GetTypeParameterInfoForPossibleProcedure( + intptr_t outermost_kernel_offset, + bool* member_is_procedure, + bool* is_factory_procedure, + intptr_t* member_type_parameters, + intptr_t* member_type_parameters_offset_start) { + if (outermost_kernel_offset >= 0) { + AlternativeReadingScope alt(reader_, outermost_kernel_offset); + Tag tag = PeekTag(); + if (tag == kProcedure) { + *member_is_procedure = true; + + word kind; + tag = ReadProcedureUntilFunctionNode( + &kind, &unused_intptr); // read first part of procedure. + *is_factory_procedure = + static_cast(kind) == Procedure::kFactory; + + if (tag == kSomething) { + ReadFunctionNodeUntilTypeParameters( + &unused_tokenposition, &unused_tokenposition, &unused_word, + &unused_word); // read first part of function node. + + intptr_t list_length = + ReadListLength(); // read type_parameters list length. + if (list_length > 0) { + *member_type_parameters = list_length; + *member_type_parameters_offset_start = ReaderOffset(); + } + } + } + } +} + +void StreamingFlowGraphBuilder::ReadFunctionNodeUntilTypeParameters( + TokenPosition* position, + TokenPosition* end_position, + word* async_marker, + word* dart_async_marker) { + Tag tag = ReadTag(); // read tag. + ASSERT(tag == kFunctionNode); + + *position = ReadPosition(); // read position. + *end_position = ReadPosition(); // read end position. + *async_marker = ReadByte(); // read async marker. + *dart_async_marker = ReadByte(); // read dart async marker. +} + +intptr_t StreamingFlowGraphBuilder::ReadUntilFunctionNode() { + const Tag tag = PeekTag(); + if (tag == kProcedure) { + Tag has_function_node = ReadProcedureUntilFunctionNode( + &unused_word, &unused_intptr); // read first part of procedure. + if (has_function_node == kNothing) { + // Running a procedure without a function node doesn't make sense. + UNREACHABLE(); + } + return -1; + // Now at start of FunctionNode. + } else if (tag == kConstructor) { + // read first part of constructor. + return ReadConstructorUntilFunctionNode(); + // 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 { + UNREACHABLE(); + } + return -1; +} + +StringIndex StreamingFlowGraphBuilder::GetNameFromVariableDeclaration( + intptr_t kernel_offset) { + // Temporarily go to the variable declaration, read the name. + AlternativeReadingScope alt(reader_, kernel_offset); + ReadPosition(); // read position. + ReadPosition(); // read equals position. + ReadFlags(); // read flags. + return ReadStringReference(); // read name index. +} + +FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfStaticFieldInitializer() { + TokenPosition position; + TokenPosition end_position; + word flags; + ReadFieldUntilAnnotation(&unused_nameindex, &position, &end_position, &flags, + &unused_intptr); + bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; + bool is_const = (flags & Field::kFlagConst) == Field::kFlagConst; + ASSERT(is_static); + + SkipListOfExpressions(); // read annotations. + SkipDartType(); // read type. + Tag initializer_tag = ReadTag(); // read first part of initializer. + if (initializer_tag != kSomething) { + UNREACHABLE(); + } + + TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); + flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( + *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); + + Fragment body(normal_entry); + body += flow_graph_builder_->CheckStackOverflowInPrologue(); + if (is_const) { + // this will (potentially) read the initializer, but reset the position. + body += Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); + SkipExpression(); // read the initializer. + } else { + body += BuildExpression(); // read initializer. + } + body += Return(TokenPosition::kNoSource); + + return new (Z) + FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, + flow_graph_builder_->next_block_id_ - 1); +} + +FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldAccessor( + LocalVariable* setter_value) { + NameIndex canonical_name; + ReadFieldUntilAnnotation(&canonical_name, &unused_tokenposition, + &unused_tokenposition, &unused_word, &unused_intptr); + SkipListOfExpressions(); // read annotations. + SkipDartType(); // read type. + Tag initializer_tag = ReadTag(); // read first part of initializer. + + const Function& function = parsed_function()->function(); + + bool is_setter = function.IsImplicitSetterFunction(); + bool is_method = !function.IsStaticFunction(); + dart::Field& field = + dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name)); + + TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); + flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( + *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); + + Fragment body(normal_entry); + if (is_setter) { + if (is_method) { + body += LoadLocal(scopes()->this_variable); + body += LoadLocal(setter_value); + body += flow_graph_builder_->StoreInstanceFieldGuarded(field, false); + } else { + body += LoadLocal(setter_value); + body += StoreStaticField(TokenPosition::kNoSource, field); + } + body += NullConstant(); + } else if (is_method) { + body += LoadLocal(scopes()->this_variable); + body += flow_graph_builder_->LoadField(field); + } else if (field.is_const()) { + // If the parser needs to know the value of an uninitialized constant field + // it will set the value to the transition sentinel (used to detect circular + // initialization) and then call the implicit getter. Thus, the getter + // cannot contain the InitStaticField instruction that normal static getters + // contain because it would detect spurious circular initialization when it + // checks for the transition sentinel. + ASSERT(initializer_tag == kSomething); + // this will (potentially) read the initializer, but reset the position. + body += Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); + SkipExpression(); // read the initializer. + } else { + // The field always has an initializer because static fields without + // initializers are initialized eagerly and do not have implicit getters. + ASSERT(field.has_initializer()); + body += Constant(field); + body += flow_graph_builder_->InitStaticField(field); + body += Constant(field); + body += LoadStaticField(); + } + body += Return(TokenPosition::kNoSource); + + return new (Z) + FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, + flow_graph_builder_->next_block_id_ - 1); +} + +void StreamingFlowGraphBuilder::SetupDefaultParameterValues() { + intptr_t num_optional_parameters = + parsed_function()->function().NumOptionalParameters(); + if (num_optional_parameters > 0) { + ZoneGrowableArray* default_values = + new ZoneGrowableArray(Z, num_optional_parameters); + + AlternativeReadingScope alt(reader_); + ReadFunctionNodeUntilTypeParameters( + &unused_tokenposition, &unused_tokenposition, &unused_word, + &unused_word); // read first part of function node. + SkipTypeParametersList(); // read type_parameters. + ReadUInt(); // read total parameter count. + intptr_t required = ReadUInt(); // read required_parameter_count. + + if (parsed_function()->function().HasOptionalNamedParameters()) { + // List of positional. + intptr_t list_length = ReadListLength(); // read list length. + for (intptr_t i = 0; i < list_length; ++i) { + SkipVariableDeclaration(); // read ith variable declaration. + } + + // List of named. + list_length = ReadListLength(); // read list length. + ASSERT(num_optional_parameters == list_length); + ASSERT(!parsed_function()->function().HasOptionalPositionalParameters()); + for (intptr_t i = 0; i < list_length; ++i) { + Instance* default_value; + + // Read ith variable declaration + ReadPosition(); // read position. + ReadPosition(); // read equals position. + ReadFlags(); // read flags. + SkipStringReference(); // read name index. + SkipDartType(); // read type. + Tag tag = ReadTag(); // read (first part of) initializer. + if (tag == kSomething) { + // this will (potentially) read the initializer, + // but reset the position. + default_value = + &constant_evaluator_.EvaluateExpression(ReaderOffset()); + SkipExpression(); // read (actual) initializer. + } else { + default_value = &Instance::ZoneHandle(Z, Instance::null()); + } + default_values->Add(default_value); + } + } else { + // List of positional. + intptr_t list_length = ReadListLength(); // read list length. + ASSERT(list_length == required + num_optional_parameters); + ASSERT(parsed_function()->function().HasOptionalPositionalParameters()); + for (intptr_t i = 0; i < required; ++i) { + SkipVariableDeclaration(); // read ith variable declaration. + } + for (intptr_t i = 0; i < num_optional_parameters; ++i) { + Instance* default_value; + + // Read ith variable declaration + ReadPosition(); // read position. + ReadPosition(); // read equals position. + ReadFlags(); // read flags. + SkipStringReference(); // read name index. + SkipDartType(); // read type. + Tag tag = ReadTag(); // read (first part of) initializer. + if (tag == kSomething) { + // this will (potentially) read the initializer, + // but reset the position. + default_value = + &constant_evaluator_.EvaluateExpression(ReaderOffset()); + SkipExpression(); // read (actual) initializer. + } else { + default_value = &Instance::ZoneHandle(Z, Instance::null()); + } + default_values->Add(default_value); + } + + // List of named. + list_length = ReadListLength(); // read list length. + ASSERT(list_length == 0); + } + parsed_function()->set_default_parameter_values(default_values); + } +} + +Fragment StreamingFlowGraphBuilder::BuildFieldInitializer( + NameIndex canonical_name) { + dart::Field& field = + dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name)); + if (PeekTag() == kNullLiteral) { + SkipExpression(); // read past the null literal. + field.RecordStore(Object::null_object()); + return Fragment(); + } + + Fragment instructions; + instructions += LoadLocal(scopes()->this_variable); + instructions += BuildExpression(); + instructions += flow_graph_builder_->StoreInstanceFieldGuarded(field, true); + return instructions; +} + +Fragment StreamingFlowGraphBuilder::BuildInitializers( + intptr_t constructor_class_parent_offset) { + Fragment instructions; + + // These come from: + // class A { + // var x = (expr); + // } + { + AlternativeReadingScope alt(reader_, constructor_class_parent_offset); + ReadClassUntilFields(); // read first part of class. + intptr_t list_length = ReadListLength(); // read fields list length. + + for (intptr_t i = 0; i < list_length; ++i) { + intptr_t field_offset = ReaderOffset(); + NameIndex canonical_name; + TokenPosition position; + TokenPosition end_position; + word flags; + ReadFieldUntilAnnotation(&canonical_name, &position, &end_position, + &flags, &unused_intptr); + bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; + SkipListOfExpressions(); // read annotations. + SkipDartType(); // read type. + Tag initializer_tag = ReadTag(); // read first part of initializer. + if (!is_static && initializer_tag == kSomething) { + EnterScope(field_offset); + instructions += + BuildFieldInitializer(canonical_name); // read initializer. + ExitScope(field_offset); + } else if (initializer_tag == kSomething) { + SkipExpression(); // read initializer. + } + } + } + + // These to come from: + // class A { + // var x; + // var y; + // A(this.x) : super(expr), y = (expr); + // } + { + AlternativeReadingScope alt(reader_); + SkipFunctionNode(); // read constructors function node. + + intptr_t list_length = ReadListLength(); // read initializers list length. + for (intptr_t i = 0; i < list_length; ++i) { + Tag tag = ReadTag(); + switch (tag) { + case kInvalidInitializer: + UNIMPLEMENTED(); + return Fragment(); + case kFieldInitializer: { + NameIndex canonical_name = + ReadCanonicalNameReference(); // read field_reference. + instructions += BuildFieldInitializer(canonical_name); // read value. + break; + } + case kSuperInitializer: { + NameIndex canonical_target = + ReadCanonicalNameReference(); // read target_reference. + + instructions += LoadLocal(scopes()->this_variable); + instructions += PushArgument(); + + // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); + Array& argument_names = Array::ZoneHandle(Z); + intptr_t argument_count; + instructions += BuildArguments(&argument_names, + &argument_count); // read arguments. + argument_count += 1; + + const Function& target = Function::ZoneHandle( + Z, H.LookupConstructorByKernelConstructor(canonical_target)); + instructions += StaticCall(TokenPosition::kNoSource, target, + argument_count, argument_names); + instructions += Drop(); + break; + } + case kRedirectingInitializer: { + NameIndex canonical_target = + ReadCanonicalNameReference(); // read target_reference. + + instructions += LoadLocal(scopes()->this_variable); + instructions += PushArgument(); + + // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); + Array& argument_names = Array::ZoneHandle(Z); + intptr_t argument_count; + instructions += BuildArguments(&argument_names, + &argument_count); // read arguments. + argument_count += 1; + + const Function& target = Function::ZoneHandle( + Z, H.LookupConstructorByKernelConstructor(canonical_target)); + instructions += StaticCall(TokenPosition::kNoSource, target, + argument_count, argument_names); + instructions += Drop(); + break; + } + case kLocalInitializer: { + // The other initializers following this one might read the variable. + // This is used e.g. for evaluating the arguments to a super call + // first, run normal field initializers next and then make the actual + // super call: + // + // The frontend converts + // + // class A { + // var x; + // A(a, b) : super(a + b), x = 2*b {} + // } + // + // to + // + // class A { + // var x; + // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {} + // } + // + // (This is strictly speaking not what one should do in terms of the + // specification but that is how it is currently implemented.) + LocalVariable* variable = LookupVariable(ReaderOffset()); + + // Variable declaration + ReadPosition(); // read position. + ReadPosition(); // read equals position. + word flags = ReadFlags(); // read flags. + ASSERT((flags & VariableDeclaration::kFlagConst) != + VariableDeclaration::kFlagConst); + SkipStringReference(); // read name index. + SkipDartType(); // read type. + Tag tag = ReadTag(); // read (first part of) initializer. + if (tag != kSomething) { + UNREACHABLE(); + } + + instructions += BuildExpression(); // read initializer. + instructions += StoreLocal(TokenPosition::kNoSource, variable); + instructions += Drop(); + break; + } + default: + UNREACHABLE(); + } + } + } + return instructions; +} + +FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfImplicitClosureFunction( + const Function& function) { + const Function& target = Function::ZoneHandle(Z, function.parent_function()); + + TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); + flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( + *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); + SetupDefaultParameterValues(); + + Fragment body(normal_entry); + body += flow_graph_builder_->CheckStackOverflowInPrologue(); + + // Load all the arguments. + if (!target.is_static()) { + // The context has a fixed shape: a single variable which is the + // closed-over receiver. + body += LoadLocal(parsed_function()->current_context_var()); + body += flow_graph_builder_->LoadField(Context::variable_offset(0)); + body += PushArgument(); + } + + TokenPosition end_position; + ReadFunctionNodeUntilTypeParameters( + &unused_tokenposition, &end_position, &unused_word, + &unused_word); // read first part of function node. + SkipTypeParametersList(); // read type parameter list. + ReadUInt(); // read total parameter count. + ReadUInt(); // read required_parameter_count. + + // Positional. + intptr_t positional_argument_count = ReadListLength(); + for (intptr_t i = 0; i < positional_argument_count; ++i) { + body += LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. + body += PushArgument(); + SkipVariableDeclaration(); // read ith variable. + } + + // Named. + intptr_t named_argument_count = ReadListLength(); + Array& argument_names = Array::ZoneHandle(Z); + if (named_argument_count > 0) { + argument_names = Array::New(named_argument_count); + for (intptr_t i = 0; i < named_argument_count; ++i) { + body += + LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. + body += PushArgument(); + argument_names.SetAt( + i, H.DartSymbol(GetNameFromVariableDeclaration(ReaderOffset()))); + SkipVariableDeclaration(); // read ith variable. + } + } + + // Forward them to the target. + intptr_t argument_count = positional_argument_count + named_argument_count; + if (!target.is_static()) ++argument_count; + body += StaticCall(TokenPosition::kNoSource, target, argument_count, + argument_names); + + // Return the result. + body += Return(end_position); + + return new (Z) + FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, + flow_graph_builder_->next_block_id_ - 1); +} + +static bool IsGetMainClosure(const String& name) { + if (name.Length() < 16) return false; + const char* cstr = "_getMainClosure@"; + for (intptr_t i = 0; i < 16; ++i) { + if (name.CharAt(i) != cstr[i]) return false; + } + return true; +} + +FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction( + bool is_in_builtin_library_toplevel, + intptr_t constructor_class_parent_offset) { + const Function& dart_function = parsed_function()->function(); + TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); + flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( + *parsed_function(), normal_entry, flow_graph_builder_->osr_id_); + + SetupDefaultParameterValues(); + + Fragment body; + if (!dart_function.is_native()) + body += flow_graph_builder_->CheckStackOverflowInPrologue(); + intptr_t context_size = + parsed_function()->node_sequence()->scope()->num_context_variables(); + if (context_size > 0) { + body += flow_graph_builder_->PushContext(context_size); + LocalVariable* context = MakeTemporary(); + + // Copy captured parameters from the stack into the context. + LocalScope* scope = parsed_function()->node_sequence()->scope(); + intptr_t parameter_count = dart_function.NumParameters(); + intptr_t parameter_index = parsed_function()->first_parameter_index(); + for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) { + LocalVariable* variable = scope->VariableAt(i); + if (variable->is_captured()) { + // There is no LocalVariable describing the on-stack parameter so + // create one directly and use the same type. + LocalVariable* parameter = new (Z) + LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, + Symbols::TempParam(), variable->type()); + parameter->set_index(parameter_index); + // Mark the stack variable so it will be ignored by the code for + // try/catch. + parameter->set_is_captured_parameter(true); + + // Copy the parameter from the stack to the context. Overwrite it + // with a null constant on the stack so the original value is + // eligible for garbage collection. + body += LoadLocal(context); + body += LoadLocal(parameter); + body += flow_graph_builder_->StoreInstanceField( + TokenPosition::kNoSource, + Context::variable_offset(variable->index())); + body += NullConstant(); + body += StoreLocal(TokenPosition::kNoSource, parameter); + body += Drop(); + } + } + body += Drop(); // The context. + } + if (constructor_class_parent_offset > 0) { + // TODO(27590): Currently the [VariableDeclaration]s from the + // initializers will be visible inside the entire body of the constructor. + // We should make a separate scope for them. + body += BuildInitializers(constructor_class_parent_offset); + } + + TokenPosition position; + ReadFunctionNodeUntilTypeParameters( + &position, &unused_tokenposition, &unused_word, + &unused_word); // read first part of function node. + SkipTypeParametersList(); // read type parameter list. + ReadUInt(); // read total parameter count + ReadUInt(); // read required_parameter_count. + intptr_t first_parameter_offset = -1; + { + AlternativeReadingScope alt(reader_); + intptr_t list_length = ReadListLength(); // read number of positionals. + if (list_length > 0) { + first_parameter_offset = ReaderOffset(); + } + } + // Current position: About to read list of positionals. + + // The specification defines the result of `a == b` to be: + // + // a) if either side is `null` then the result is `identical(a, b)`. + // b) else the result is `a.operator==(b)` + // + // For user-defined implementations of `operator==` we need therefore + // implement the handling of a). + // + // The default `operator==` implementation in `Object` is implemented in terms + // of identical (which we assume here!) which means that case a) is actually + // included in b). So we just use the normal implementation in the body. + if ((dart_function.NumParameters() == 2) && + (dart_function.name() == Symbols::EqualOperator().raw()) && + (dart_function.Owner() != I->object_store()->object_class())) { + LocalVariable* parameter = LookupVariable(first_parameter_offset); + + TargetEntryInstr* null_entry; + TargetEntryInstr* non_null_entry; + + body += LoadLocal(parameter); + body += BranchIfNull(&null_entry, &non_null_entry); + + // The argument was `null` and the receiver is not the null class (we only + // go into this branch for user-defined == operators) so we can return + // false. + Fragment null_fragment(null_entry); + null_fragment += Constant(Bool::False()); + null_fragment += Return(dart_function.end_token_pos()); + + body = Fragment(body.entry, non_null_entry); + } + + // If we run in checked mode, we have to check the type of the passed + // arguments. + if (I->type_checks()) { + // Positional. + intptr_t list_length = ReadListLength(); + for (intptr_t i = 0; i < list_length; ++i) { + body += + LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. + body += CheckVariableTypeInCheckedMode(ReaderOffset()); + body += Drop(); + SkipVariableDeclaration(); // read ith variable. + } + + // Named. + list_length = ReadListLength(); + for (intptr_t i = 0; i < list_length; ++i) { + body += + LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. + body += CheckVariableTypeInCheckedMode(ReaderOffset()); + body += Drop(); + SkipVariableDeclaration(); // read ith variable. + } + } else { + // Still skip past the parameters. + SkipListOfVariableDeclarations(); // read list of positionals. + SkipListOfVariableDeclarations(); // read list of named. + } + + SkipDartType(); // read return type. + + if (FLAG_causal_async_stacks && + (dart_function.IsAsyncFunction() || dart_function.IsAsyncGenerator())) { + LocalScope* scope = parsed_function()->node_sequence()->scope(); + // :async_stack_trace = _asyncStackTraceHelper(:async_op); + const dart::Library& async_lib = + dart::Library::Handle(dart::Library::AsyncLibrary()); + const Function& target = Function::ZoneHandle( + Z, + async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper())); + ASSERT(!target.IsNull()); + + // TODO(johnmccutchan): Why does this have the null value? + LocalVariable* async_op = + scope->child()->LookupVariable(Symbols::AsyncOperation(), false); + ASSERT(async_op != NULL); + ASSERT(async_op->is_captured()); + body += LoadLocal(async_op); + body += PushArgument(); + body += StaticCall(TokenPosition::kNoSource, target, 1); + LocalVariable* async_stack_trace_var = + scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); + ASSERT(async_stack_trace_var != NULL); + body += StoreLocal(TokenPosition::kNoSource, async_stack_trace_var); + body += Drop(); + } + + bool has_body = ReadTag() == kSomething; // read first part of body. + + if (dart_function.is_native()) { + body += flow_graph_builder_->NativeFunctionBody(first_parameter_offset, + dart_function); + } else if (has_body) { + if (is_in_builtin_library_toplevel && + IsGetMainClosure(dart::String::Handle(Z, dart_function.name()))) { + body += BuildGetMainClosure(); + } else { + body += BuildStatement(); // read body. + } + } + if (body.is_open()) { + body += NullConstant(); + body += Return(dart_function.end_token_pos()); + } + + // If functions body contains any yield points build switch statement that + // selects a continuation point based on the value of :await_jump_var. + if (!yield_continuations().is_empty()) { + // The code we are building will be executed right after we enter + // the function and before any nested contexts are allocated. + // Reset current context_depth_ to match this. + const intptr_t current_context_depth = flow_graph_builder_->context_depth_; + flow_graph_builder_->context_depth_ = + scopes()->yield_jump_variable->owner()->context_level(); + + // Prepend an entry corresponding to normal entry to the function. + yield_continuations().InsertAt( + 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), + CatchClauseNode::kInvalidTryIndex)); + yield_continuations()[0].entry->LinkTo(body.entry); + + // Build a switch statement. + Fragment dispatch; + + // Load :await_jump_var into a temporary. + dispatch += LoadLocal(scopes()->yield_jump_variable); + dispatch += StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable); + dispatch += Drop(); + + BlockEntryInstr* block = NULL; + for (intptr_t i = 0; i < yield_continuations().length(); i++) { + if (i == 1) { + // This is not a normal entry but a resumption. Restore + // :current_context_var from :await_ctx_var. + // Note: after this point context_depth_ does not match current context + // depth so we should not access any local variables anymore. + dispatch += LoadLocal(scopes()->yield_context_variable); + dispatch += StoreLocal(TokenPosition::kNoSource, + parsed_function()->current_context_var()); + dispatch += Drop(); + } + if (i == (yield_continuations().length() - 1)) { + // We reached the last possility, no need to build more ifs. + // Continue to the last continuation. + // Note: continuations start with nop DropTemps instruction + // which acts like an anchor, so we need to skip it. + block->set_try_index(yield_continuations()[i].try_index); + dispatch <<= yield_continuations()[i].entry->next(); + break; + } + + // Build comparison: + // + // if (:await_ctx_var == i) { + // -> yield_continuations()[i] + // } else ... + // + TargetEntryInstr* then; + TargetEntryInstr* otherwise; + dispatch += LoadLocal(scopes()->switch_variable); + dispatch += IntConstant(i); + dispatch += flow_graph_builder_->BranchIfStrictEqual(&then, &otherwise); + + // True branch is linked to appropriate continuation point. + // Note: continuations start with nop DropTemps instruction + // which acts like an anchor, so we need to skip it. + then->LinkTo(yield_continuations()[i].entry->next()); + then->set_try_index(yield_continuations()[i].try_index); + // False branch will contain the next comparison. + dispatch = Fragment(dispatch.entry, otherwise); + block = otherwise; + } + body = dispatch; + + flow_graph_builder_->context_depth_ = current_context_depth; + } + + if (FLAG_causal_async_stacks && + (dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) { + // The code we are building will be executed right after we enter + // the function and before any nested contexts are allocated. + // Reset current context_depth_ to match this. + const intptr_t current_context_depth = flow_graph_builder_->context_depth_; + flow_graph_builder_->context_depth_ = + scopes()->yield_jump_variable->owner()->context_level(); + + Fragment instructions; + LocalScope* scope = parsed_function()->node_sequence()->scope(); + + const Function& target = Function::ZoneHandle( + Z, I->object_store()->async_set_thread_stack_trace()); + ASSERT(!target.IsNull()); + + // Fetch and load :async_stack_trace + LocalVariable* async_stack_trace_var = + scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); + ASSERT((async_stack_trace_var != NULL) && + async_stack_trace_var->is_captured()); + instructions += LoadLocal(async_stack_trace_var); + instructions += PushArgument(); + + // Call _asyncSetThreadStackTrace + instructions += StaticCall(TokenPosition::kNoSource, target, 1); + instructions += Drop(); + + // TODO(29737): This sequence should be generated in order. + body = instructions + body; + flow_graph_builder_->context_depth_ = current_context_depth; + } + + if (NeedsDebugStepCheck(dart_function, position)) { + const intptr_t current_context_depth = flow_graph_builder_->context_depth_; + flow_graph_builder_->context_depth_ = 0; + + // If a switch was added above: Start the switch by injecting a debuggable + // safepoint so stepping over an await works. + // If not, still start the body with a debuggable safepoint to ensure + // breaking on a method always happens, even if there are no + // assignments/calls/runtimecalls in the first basic block. + // Place this check at the last parameter to ensure parameters + // are in scope in the debugger at method entry. + const int num_params = dart_function.NumParameters(); + TokenPosition check_pos = TokenPosition::kNoSource; + if (num_params > 0) { + LocalScope* scope = parsed_function()->node_sequence()->scope(); + const LocalVariable& parameter = *scope->VariableAt(num_params - 1); + check_pos = parameter.token_pos(); + } + if (!check_pos.IsDebugPause()) { + // No parameters or synthetic parameters. + check_pos = position; + ASSERT(check_pos.IsDebugPause()); + } + + // TODO(29737): This sequence should be generated in order. + body = DebugStepCheck(check_pos) + body; + flow_graph_builder_->context_depth_ = current_context_depth; + } + + normal_entry->LinkTo(body.entry); + + // When compiling for OSR, use a depth first search to prune instructions + // unreachable from the OSR entry. Catch entries are always considered + // reachable, even if they become unreachable after OSR. + if (flow_graph_builder_->osr_id_ != Compiler::kNoOSRDeoptId) { + BitVector* block_marks = + new (Z) BitVector(Z, flow_graph_builder_->next_block_id_); + bool found = flow_graph_builder_->graph_entry_->PruneUnreachable( + flow_graph_builder_->graph_entry_, NULL, flow_graph_builder_->osr_id_, + block_marks); + ASSERT(found); + } + return new (Z) + FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, + flow_graph_builder_->next_block_id_ - 1); +} + +Fragment StreamingFlowGraphBuilder::BuildGetMainClosure() { + // _getMainClosure in dart:_builtin. Compile that one specially here. + const dart::Library& builtin = + dart::Library::Handle(Z, I->object_store()->builtin_library()); + const Object& main = + Object::Handle(Z, builtin.LookupObjectAllowPrivate(dart::String::Handle( + Z, dart::String::New("main")))); + if (main.IsField()) { + UNIMPLEMENTED(); + } else if (main.IsFunction()) { + const Function& function = Function::Cast(main); + if (function.kind() == RawFunction::kRegularFunction) { + const Function& closure_function = + Function::Handle(Z, function.ImplicitClosureFunction()); + const Instance& closure = + Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure()); + return Constant(closure) + Return(TokenPosition::kNoSource); + } else { + UNIMPLEMENTED(); + } + } else { + UNIMPLEMENTED(); + } + return Fragment(); +} + +FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) { + const Function& function = parsed_function()->function(); + + // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used + // e.g. for type translation. + const dart::Class& klass = + dart::Class::Handle(zone_, parsed_function()->function().Owner()); + bool is_in_builtin_library_toplevel = + klass.library() == I->object_store()->builtin_library() && + klass.IsTopLevel(); + + Function& outermost_function = Function::Handle(Z); + intptr_t outermost_kernel_offset = -1; + intptr_t parent_class_offset = -1; + DiscoverEnclosingElements(Z, function, &outermost_function, + &outermost_kernel_offset, &parent_class_offset); + // Use [klass]/[kernel_class] as active class. Type parameters will get + // resolved via [kernel_class] unless we are nested inside a static factory + // in which case we will use [member]. + intptr_t class_type_parameters = 0; + intptr_t class_type_parameters_offset_start = -1; + if (parent_class_offset > 0) { + GetTypeParameterInfoForClass(parent_class_offset, &class_type_parameters, + &class_type_parameters_offset_start); + } + + ActiveClassScope active_class_scope(active_class(), class_type_parameters, + class_type_parameters_offset_start, + &klass); + + bool member_is_procedure = false; + bool is_factory_procedure = false; + intptr_t member_type_parameters = 0; + intptr_t member_type_parameters_offset_start = -1; + GetTypeParameterInfoForPossibleProcedure( + outermost_kernel_offset, &member_is_procedure, &is_factory_procedure, + &member_type_parameters, &member_type_parameters_offset_start); + + ActiveMemberScope active_member(active_class(), member_is_procedure, + is_factory_procedure, member_type_parameters, + member_type_parameters_offset_start); + + // The IR builder will create its own local variables and scopes, and it + // will not need an AST. The code generator will assume that there is a + // local variable stack slot allocated for the current context and (I + // think) that the runtime will expect it to be at a fixed offset which + // requires allocating an unused expression temporary variable. + set_scopes(parsed_function()->EnsureKernelScopes()); + + SetOffset(kernel_offset); + + switch (function.kind()) { + case RawFunction::kClosureFunction: + case RawFunction::kRegularFunction: + case RawFunction::kGetterFunction: + case RawFunction::kSetterFunction: { + ReadUntilFunctionNode(); // read until function node. + return function.IsImplicitClosureFunction() + ? BuildGraphOfImplicitClosureFunction(function) + : BuildGraphOfFunction(is_in_builtin_library_toplevel); + } + case RawFunction::kConstructor: { + bool is_factory = function.IsFactory(); + if (is_factory) { + ReadUntilFunctionNode(); // read until function node. + return BuildGraphOfFunction(is_in_builtin_library_toplevel); + } else { + // Constructor: Pass offset to parent class. + return BuildGraphOfFunction( + is_in_builtin_library_toplevel, + ReadUntilFunctionNode()); // read until function node. + } + } + case RawFunction::kImplicitGetter: + case RawFunction::kImplicitStaticFinalGetter: + case RawFunction::kImplicitSetter: { + return IsStaticInitializer(function, Z) + ? BuildGraphOfStaticFieldInitializer() + : BuildGraphOfFieldAccessor(scopes()->setter_value); + } + case RawFunction::kMethodExtractor: + return flow_graph_builder_->BuildGraphOfMethodExtractor(function); + case RawFunction::kNoSuchMethodDispatcher: + return flow_graph_builder_->BuildGraphOfNoSuchMethodDispatcher(function); + case RawFunction::kInvokeFieldDispatcher: + return flow_graph_builder_->BuildGraphOfInvokeFieldDispatcher(function); + case RawFunction::kSignatureFunction: + case RawFunction::kIrregexpFunction: + break; + } + UNREACHABLE(); + return NULL; +} + + Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) { SetOffset(kernel_offset); return BuildStatement(); // read statement. @@ -2770,9 +3674,7 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) { case kConstMapLiteral: return BuildMapLiteral(true, position); case kFunctionExpression: - // TODO(jensj) - UNIMPLEMENTED(); - return Fragment(); + return BuildFunctionExpression(); case kLet: return BuildLet(position); case kBigIntLiteral: @@ -2844,9 +3746,7 @@ Fragment StreamingFlowGraphBuilder::BuildStatement() { case kVariableDeclaration: return BuildVariableDeclaration(); case kFunctionDeclaration: - // TODO(jensj) - UNIMPLEMENTED(); - return Fragment(); + return BuildFunctionDeclaration(); default: UNREACHABLE(); } @@ -3361,6 +4261,7 @@ void StreamingFlowGraphBuilder::SkipFunctionNode() { ReadByte(); // read async marker. ReadByte(); // read dart async marker. SkipTypeParametersList(); // read type_parameters. + ReadUInt(); // read total parameter count. ReadUInt(); // read required_parameter_count. SkipListOfVariableDeclarations(); // read list of positionals. @@ -3485,6 +4386,10 @@ ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() { return flow_graph_builder_->scopes_; } +void StreamingFlowGraphBuilder::set_scopes(ScopeBuildingResult* scope) { + flow_graph_builder_->scopes_ = scope; +} + ParsedFunction* StreamingFlowGraphBuilder::parsed_function() { return flow_graph_builder_->parsed_function_; } @@ -4868,6 +5773,11 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const, return instructions + StaticCall(position, factory_method, 2); } +Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() { + intptr_t offset = ReaderOffset() - 1; // -1 to include tag byte. + return BuildFunctionNode(offset, TokenPosition::kNoSource, false, -1); +} + Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) { if (position != NULL) *position = TokenPosition::kNoSource; @@ -5875,6 +6785,372 @@ Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() { return instructions; } +Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration() { + intptr_t offset = ReaderOffset() - 1; // -1 to include tag byte. + TokenPosition position = ReadPosition(); // read position. + intptr_t variable_offeset = ReaderOffset(); + SkipVariableDeclaration(); // read variable declaration. + + Fragment instructions = DebugStepCheck(position); + instructions += BuildFunctionNode(offset, position, true, variable_offeset); + instructions += StoreLocal(position, LookupVariable(variable_offeset)); + instructions += Drop(); + return instructions; +} + +Fragment StreamingFlowGraphBuilder::BuildFunctionNode( + intptr_t parent_kernel_offset, + TokenPosition parent_position, + bool declaration, + intptr_t variable_offeset) { + intptr_t offset = ReaderOffset(); + + TokenPosition position; + TokenPosition end_position; + word async_marker_word; + word dart_async_marker_word; + ReadFunctionNodeUntilTypeParameters( + &position, &end_position, &async_marker_word, + &dart_async_marker_word); // read first part of function node. + FunctionNode::AsyncMarker async_marker = + static_cast(async_marker_word); + FunctionNode::AsyncMarker dart_async_marker = + static_cast(dart_async_marker_word); + + if (declaration) { + position = parent_position; + } + if (!position.IsReal()) { + // Positions has to be unique in regards to the parent. + // A non-real at this point is probably -1, we cannot blindly use that + // as others might use it too. Create a new dummy non-real TokenPosition. + position = TokenPosition(offset).ToSynthetic(); + } + + SkipTypeParametersList(); // read type parameters. + + // The VM has a per-isolate table of functions indexed by the enclosing + // function and token position. + Function& function = Function::ZoneHandle(Z); + bool read_rest_of_function_node = false; + + // NOTE: This is not TokenPosition in the general sense! + function = I->LookupClosureFunction(parsed_function()->function(), position); + if (function.IsNull()) { + for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) { + if (scopes()->function_scopes[i].kernel_offset != offset) { + continue; + } + + const dart::String* name; + if (!declaration) { + name = &Symbols::AnonymousClosure(); + } else { + name = &H.DartSymbol(GetNameFromVariableDeclaration(variable_offeset)); + } + // NOTE: This is not TokenPosition in the general sense! + function = Function::NewClosureFunction( + *name, parsed_function()->function(), position); + + function.set_is_debuggable(dart_async_marker == FunctionNode::kSync); + switch (dart_async_marker) { + case FunctionNode::kSyncStar: + function.set_modifier(RawFunction::kSyncGen); + break; + case FunctionNode::kAsync: + function.set_modifier(RawFunction::kAsync); + function.set_is_inlinable(!FLAG_causal_async_stacks); + break; + case FunctionNode::kAsyncStar: + function.set_modifier(RawFunction::kAsyncGen); + function.set_is_inlinable(!FLAG_causal_async_stacks); + break; + default: + // no special modifier + break; + } + function.set_is_generated_body(async_marker == + FunctionNode::kSyncYielding); + if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { + function.set_is_inlinable(!FLAG_causal_async_stacks); + } + + function.set_end_token_pos(end_position); + LocalScope* scope = scopes()->function_scopes[i].scope; + const ContextScope& context_scope = ContextScope::Handle( + Z, scope->PreserveOuterScope(flow_graph_builder_->context_depth_)); + function.set_context_scope(context_scope); + function.set_kernel_offset(offset); + // Read rest of function node. + SetupFunctionParameters(dart::Class::Handle(Z), function, + false, // is_method + true); // is_closure + read_rest_of_function_node = true; + // Finalize function type. + Type& signature_type = Type::Handle(Z, function.SignatureType()); + signature_type ^= + ClassFinalizer::FinalizeType(*active_class()->klass, signature_type); + function.SetSignatureType(signature_type); + + I->AddClosureFunction(function); + break; + } + } + + if (!read_rest_of_function_node) { + ReadUInt(); // read total parameter count. + ReadUInt(); // read required_parameter_count. + SkipListOfVariableDeclarations(); // read list of positionals. + SkipListOfVariableDeclarations(); // read list of named. + SkipDartType(); // read return type. + if (ReadTag() == kSomething) { // read first part of body. + SkipStatement(); // read body. + } + } + + const dart::Class& closure_class = + dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); + ASSERT(!closure_class.IsNull()); + Fragment instructions = + flow_graph_builder_->AllocateObject(closure_class, function); + LocalVariable* closure = MakeTemporary(); + + // The function signature can have uninstantiated class type parameters. + // + // TODO(regis): Also handle the case of a function signature that has + // uninstantiated function type parameters. + if (!function.HasInstantiatedSignature(kCurrentClass)) { + instructions += LoadLocal(closure); + instructions += LoadInstantiatorTypeArguments(); + instructions += flow_graph_builder_->StoreInstanceField( + TokenPosition::kNoSource, + Closure::instantiator_type_arguments_offset()); + } + + // Store the function and the context in the closure. + instructions += LoadLocal(closure); + instructions += Constant(function); + instructions += flow_graph_builder_->StoreInstanceField( + TokenPosition::kNoSource, Closure::function_offset()); + + instructions += LoadLocal(closure); + instructions += LoadLocal(parsed_function()->current_context_var()); + instructions += flow_graph_builder_->StoreInstanceField( + TokenPosition::kNoSource, Closure::context_offset()); + + return instructions; +} + + +void StreamingFlowGraphBuilder::SetupFunctionParameters( + const dart::Class& klass, + const dart::Function& function, + bool is_method, + bool is_closure) { + ASSERT(!(is_method && is_closure)); + bool is_factory = function.IsFactory(); + intptr_t extra_parameters = (is_method || is_closure || is_factory) ? 1 : 0; + + intptr_t total_parameter_count = ReadUInt(); // read total parameter count. + intptr_t required_parameter_count = + ReadUInt(); // read required_parameter_count. + intptr_t positional_parameters_count = ReadListLength(); // read list length. + intptr_t named_parameters_count = + total_parameter_count - positional_parameters_count; + + function.set_num_fixed_parameters(extra_parameters + + required_parameter_count); + if (named_parameters_count > 0) { + function.SetNumOptionalParameters(named_parameters_count, false); + } else { + function.SetNumOptionalParameters( + positional_parameters_count - required_parameter_count, true); + } + intptr_t num_parameters = extra_parameters + total_parameter_count; + function.set_parameter_types( + Array::Handle(Z, Array::New(num_parameters, Heap::kOld))); + function.set_parameter_names( + Array::Handle(Z, Array::New(num_parameters, Heap::kOld))); + intptr_t pos = 0; + if (is_method) { + ASSERT(!klass.IsNull()); + function.SetParameterTypeAt(pos, H.GetCanonicalType(klass)); + function.SetParameterNameAt(pos, Symbols::This()); + pos++; + } else if (is_closure) { + function.SetParameterTypeAt(pos, AbstractType::dynamic_type()); + function.SetParameterNameAt(pos, Symbols::ClosureParameter()); + pos++; + } else if (is_factory) { + function.SetParameterTypeAt(pos, AbstractType::dynamic_type()); + function.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter()); + pos++; + } + + for (intptr_t i = 0; i < positional_parameters_count; ++i, ++pos) { + // Read ith variable declaration. + ReadPosition(); // read position. + ReadPosition(); // read equals position. + ReadFlags(); // read flags. + StringIndex name = ReadStringReference(); // read name index. + const AbstractType& type = T.BuildTypeWithoutFinalization(); // read type. + Tag tag = ReadTag(); // read (first part of) initializer. + if (tag == kSomething) { + SkipExpression(); // read (actual) initializer. + } + + function.SetParameterTypeAt( + pos, type.IsMalformed() ? Type::dynamic_type() : type); + function.SetParameterNameAt(pos, H.DartSymbol(name)); + } + + intptr_t named_parameters_count_check = + ReadListLength(); // read list length. + ASSERT(named_parameters_count_check == named_parameters_count); + for (intptr_t i = 0; i < named_parameters_count; ++i, ++pos) { + // Read ith variable declaration. + ReadPosition(); // read position. + ReadPosition(); // read equals position. + ReadFlags(); // read flags. + StringIndex name = ReadStringReference(); // read name index. + const AbstractType& type = T.BuildTypeWithoutFinalization(); // read type. + Tag tag = ReadTag(); // read (first part of) initializer. + if (tag == kSomething) { + SkipExpression(); // read (actual) initializer. + } + + function.SetParameterTypeAt( + pos, type.IsMalformed() ? Type::dynamic_type() : type); + function.SetParameterNameAt(pos, H.DartSymbol(name)); + } + + // The result type for generative constructors has already been set. + if (!function.IsGenerativeConstructor()) { + const AbstractType& return_type = + T.BuildTypeWithoutFinalization(); // read return type. + function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type() + : return_type); + } else { + SkipDartType(); // read return type. + } + + if (ReadTag() == kSomething) { // read first part of body. + SkipStatement(); // read body. + } +} + +RawObject* StreamingFlowGraphBuilder::BuildParameterDescriptor( + intptr_t kernel_offset) { + SetOffset(kernel_offset); + ReadUntilFunctionNode(); // read until function node. + ReadFunctionNodeUntilTypeParameters( + &unused_tokenposition, &unused_tokenposition, &unused_word, + &unused_word); // read first part of function node. + SkipTypeParametersList(); // read type_parameters. + + intptr_t param_count = ReadUInt(); // read total parameter count. + ReadUInt(); // read required_parameter_count. + intptr_t positional_count = ReadListLength(); // read list length. + intptr_t named_parameters_count = param_count - positional_count; + + const Array& param_descriptor = Array::Handle( + Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld)); + for (intptr_t i = 0; i < param_count; ++i) { + const intptr_t entry_start = i * Parser::kParameterEntrySize; + + if (i == positional_count) { + intptr_t named_parameters_count_check = + ReadListLength(); // read list length. + ASSERT(named_parameters_count_check == named_parameters_count); + } + + // Read ith variable declaration. + ReadPosition(); // read position. + ReadPosition(); // read equals position. + word flags = ReadFlags(); // read flags. + bool is_final = (flags & VariableDeclaration::kFlagFinal) == + VariableDeclaration::kFlagFinal; + param_descriptor.SetAt(entry_start + Parser::kParameterIsFinalOffset, + is_final ? Bool::True() : Bool::False()); + + SkipStringReference(); // read name index. + SkipDartType(); // read type. + Tag tag = ReadTag(); // read (first part of) initializer. + if (tag == kSomething) { + // this will (potentially) read the initializer, but reset the position. + Instance& constant = + constant_evaluator_.EvaluateExpression(ReaderOffset()); + SkipExpression(); // read (actual) initializer. + param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset, + constant); + } else { + param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset, + Object::null_instance()); + } + + param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset, + /* Issue(28434): Missing parameter metadata. */ + Object::null_instance()); + } + return param_descriptor.raw(); +} + +RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(intptr_t kernel_offset) { + SetOffset(kernel_offset); + const Tag tag = PeekTag(); + + if (tag == kClass) { + Tag tag = ReadTag(); // read tag. + ASSERT(tag == kClass); + SkipCanonicalNameReference(); // read canonical name reference. + ReadPosition(); // read position. + ReadByte(); // read is_abstract + SkipStringReference(); // read name_index. + ReadUInt(); // read source_uri_index. + // SkipListOfExpressions(); // read annotations. + } else if (tag == kProcedure) { + Tag tag = ReadTag(); // read tag. + ASSERT(tag == kProcedure); + SkipCanonicalNameReference(); // read canonical name reference. + ReadPosition(); // read position. + ReadPosition(); // read end position. + ReadByte(); // read kind. + ReadFlags(); // read flags. + ReadUInt(); // read parent class binary offset. + SkipName(); // read name, + ReadUInt(); // read source_uri_index. + // SkipListOfExpressions(); // read annotations. + } else if (tag == kField) { + ReadFieldUntilAnnotation(&unused_nameindex, &unused_tokenposition, + &unused_tokenposition, &unused_word, + &unused_intptr); + // SkipListOfExpressions(); // read annotations. + } else if (tag == kConstructor) { + Tag tag = ReadTag(); + ASSERT(tag == kConstructor); + SkipCanonicalNameReference(); // read canonical name reference. + ReadPosition(); // read position. + ReadPosition(); // read end position. + ReadFlags(); // read flags. + ReadUInt(); // parent class binary offset. + SkipName(); // read name. + // SkipListOfExpressions(); // read annotations. + } else { + FATAL("No support for metadata on this type of kernel node\n"); + } + + intptr_t list_length = ReadListLength(); // read list length. + const Array& metadata_values = Array::Handle(Z, Array::New(list_length)); + for (intptr_t i = 0; i < list_length; ++i) { + // this will (potentially) read the expression, but reset the position. + Instance& value = constant_evaluator_.EvaluateExpression(ReaderOffset()); + SkipExpression(); // read (actual) initializer. + metadata_values.SetAt(i, value); + } + + return metadata_values.raw(); +} + } // namespace kernel } // namespace dart diff --git a/runtime/vm/kernel_binary_flowgraph.h b/runtime/vm/kernel_binary_flowgraph.h index 300787d6373..4667e5152d1 100644 --- a/runtime/vm/kernel_binary_flowgraph.h +++ b/runtime/vm/kernel_binary_flowgraph.h @@ -24,6 +24,8 @@ class StreamingDartTypeTranslator { // Can return a malformed type. AbstractType& BuildType(); + // Can return a malformed type. + AbstractType& BuildTypeWithoutFinalization(); // Is guaranteed to be not malformed. AbstractType& BuildVariableType(); @@ -101,46 +103,12 @@ class StreamingScopeBuilder { private: void VisitField(); - void ReadFieldUntilAnnotation(TokenPosition* position, - TokenPosition* end_position, - word* flags, - intptr_t* parent_offset); - /** - * Will read until the function node; as this is optional, will return the tag - * (i.e. either kSomething or kNothing). - */ - Tag ReadProcedureUntilFunctionNode(word* kind, intptr_t* parent_offset); - void GetTypeParameterInfoForPossibleProcedure( - intptr_t outermost_kernel_offset, - bool* member_is_procedure, - bool* is_factory_procedure, - intptr_t* member_type_parameters, - intptr_t* member_type_parameters_offset_start); void VisitProcedure(); - /** - * Will return binary offset of parent class. - */ - intptr_t ReadConstructorUntilFunctionNode(); void VisitConstructor(); - void ReadClassUntilTypeParameters(); - void ReadClassUntilFields(); - - void ReadFunctionNodeUntilTypeParameters(word* async_marker, - word* dart_async_marker); void VisitFunctionNode(); - - void DiscoverEnclosingElements(Zone* zone, - const Function& function, - Function* outermost_function, - intptr_t* outermost_kernel_offset, - intptr_t* parent_class_offset); - intptr_t GetParentOffset(intptr_t offset); - void GetTypeParameterInfoForClass(intptr_t class_offset, - intptr_t* type_paremeter_counts, - intptr_t* type_paremeter_offset); void VisitNode(); void VisitInitializer(); void VisitExpression(); @@ -181,8 +149,6 @@ class StreamingScopeBuilder { void AddIteratorVariable(); void AddSwitchVariable(); - StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset); - // Record an assignment or reference to a variable. If the occurrence is // in a nested function, ensure that the variable is handled properly as a // captured variable. @@ -236,9 +202,29 @@ class StreamingScopeBuilder { word unused_word; intptr_t unused_intptr; TokenPosition unused_tokenposition; + NameIndex unused_nameindex; }; +// There are several cases when we are compiling constant expressions: +// +// * constant field initializers: +// const FieldName = ; +// +// * constant expressions: +// const [, ...] +// const { : , ...} +// const Constructor(, ...) +// +// * constant default parameters: +// f(a, [b = ]) +// f(a, {b: }) +// +// * constant values to compare in a [SwitchCase] +// case : +// +// In all cases `` must be recursively evaluated and canonicalized at +// compile-time. class StreamingConstantEvaluator { public: explicit StreamingConstantEvaluator(StreamingFlowGraphBuilder* builder); @@ -328,12 +314,6 @@ class StreamingFlowGraphBuilder { constant_evaluator_(this), type_translator_(this, /* finalize= */ true) {} - ~StreamingFlowGraphBuilder() { delete reader_; } - - Fragment BuildExpressionAt(intptr_t kernel_offset); - Fragment BuildStatementAt(intptr_t kernel_offset); - - private: StreamingFlowGraphBuilder(TranslationHelper* translation_helper, Zone* zone, const uint8_t* buffer, @@ -345,6 +325,69 @@ class StreamingFlowGraphBuilder { constant_evaluator_(this), type_translator_(this, /* finalize= */ true) {} + ~StreamingFlowGraphBuilder() { delete reader_; } + + FlowGraph* BuildGraph(intptr_t kernel_offset); + + Fragment BuildStatementAt(intptr_t kernel_offset); + RawObject* BuildParameterDescriptor(intptr_t kernel_offset); + RawObject* EvaluateMetadata(intptr_t kernel_offset); + + private: + void DiscoverEnclosingElements(Zone* zone, + const Function& function, + Function* outermost_function, + intptr_t* outermost_kernel_offset, + intptr_t* parent_class_offset); + intptr_t GetParentOffset(intptr_t offset); + void GetTypeParameterInfoForClass(intptr_t class_offset, + intptr_t* type_paremeter_counts, + intptr_t* type_paremeter_offset); + void ReadClassUntilFields(); + void ReadClassUntilTypeParameters(); + /** + * Will return binary offset of parent class. + */ + intptr_t ReadConstructorUntilFunctionNode(); + /** + * Will read until the function node; as this is optional, will return the tag + * (i.e. either kSomething or kNothing). + */ + Tag ReadProcedureUntilFunctionNode(word* kind, intptr_t* parent_offset); + + void ReadFieldUntilAnnotation(NameIndex* canonical_name, + TokenPosition* position, + TokenPosition* end_position, + word* flags, + intptr_t* parent_offset); + void GetTypeParameterInfoForPossibleProcedure( + intptr_t outermost_kernel_offset, + bool* member_is_procedure, + bool* is_factory_procedure, + intptr_t* member_type_parameters, + intptr_t* member_type_parameters_offset_start); + void ReadFunctionNodeUntilTypeParameters(TokenPosition* position, + TokenPosition* end_position, + word* async_marker, + word* dart_async_marker); + /** + * Will return kernel offset for parent class if reading a constructor. + * Will otherwise return -1. + */ + intptr_t ReadUntilFunctionNode(); + StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset); + + FlowGraph* BuildGraphOfStaticFieldInitializer(); + FlowGraph* BuildGraphOfFieldAccessor(LocalVariable* setter_value); + void SetupDefaultParameterValues(); + Fragment BuildFieldInitializer(NameIndex canonical_name); + Fragment BuildInitializers(intptr_t constructor_class_parent_offset); + FlowGraph* BuildGraphOfImplicitClosureFunction(const Function& function); + FlowGraph* BuildGraphOfFunction( + bool is_in_builtin_library_toplevel, + intptr_t constructor_class_parent_offset = -1); + Fragment BuildGetMainClosure(); + Fragment BuildExpression(TokenPosition* position = NULL); Fragment BuildStatement(); @@ -399,6 +442,7 @@ class StreamingFlowGraphBuilder { CatchBlock* catch_block(); ActiveClass* active_class(); ScopeBuildingResult* scopes(); + void set_scopes(ScopeBuildingResult* scope); ParsedFunction* parsed_function(); TryFinallyBlock* try_finally_block(); SwitchBlock* switch_block(); @@ -537,6 +581,7 @@ class StreamingFlowGraphBuilder { Fragment BuildThrow(TokenPosition* position); Fragment BuildListLiteral(bool is_const, TokenPosition* position); Fragment BuildMapLiteral(bool is_const, TokenPosition* position); + Fragment BuildFunctionExpression(); Fragment BuildLet(TokenPosition* position); Fragment BuildBigIntLiteral(TokenPosition* position); Fragment BuildStringLiteral(TokenPosition* position); @@ -565,6 +610,15 @@ class StreamingFlowGraphBuilder { Fragment BuildTryFinally(); Fragment BuildYieldStatement(); Fragment BuildVariableDeclaration(); + Fragment BuildFunctionDeclaration(); + Fragment BuildFunctionNode(intptr_t parent_kernel_offset, + TokenPosition parent_position, + bool declaration, + intptr_t variable_offeset); + void SetupFunctionParameters(const dart::Class& klass, + const dart::Function& function, + bool is_method, + bool is_closure); FlowGraphBuilder* flow_graph_builder_; TranslationHelper& translation_helper_; @@ -573,6 +627,11 @@ class StreamingFlowGraphBuilder { StreamingConstantEvaluator constant_evaluator_; StreamingDartTypeTranslator type_translator_; + word unused_word; + intptr_t unused_intptr; + TokenPosition unused_tokenposition; + NameIndex unused_nameindex; + friend class StreamingConstantEvaluator; friend class StreamingDartTypeTranslator; friend class StreamingScopeBuilder; diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc index 5f4dd9c6cdc..bbc8e1ae8d9 100644 --- a/runtime/vm/kernel_reader.cc +++ b/runtime/vm/kernel_reader.cc @@ -202,24 +202,6 @@ Object& KernelReader::ReadProgram() { Z, library.LookupObjectAllowPrivate(H.DartSymbol("main"))); ASSERT(!main_obj.IsNull()); - Function& to_patch = Function::Handle( - Z, builtin_library.LookupFunctionAllowPrivate( - dart::String::Handle(dart::String::New("_getMainClosure")))); - - Procedure* procedure = - reinterpret_cast(to_patch.kernel_function()); - // If dart:_builtin was not compiled from Kernel at all it does not need - // to be patched. - if (procedure != NULL) { - // We will handle the StaticGet specially and will not use the name. - // Note that we pass "true" in cannot_stream to avoid trying to stream - // a non-existing part of the binary. - // - // TODO(kmillikin): we are leaking the new function body. Find a way to - // deallocate it. - procedure->function()->ReplaceBody( - new ReturnStatement(new StaticGet(NameIndex(), false), false)); - } return library; } } @@ -271,7 +253,7 @@ void KernelReader::ReadLibrary(Library* kernel_library) { Z, dart::Field::NewTopLevel(name, kernel_field->IsFinal(), kernel_field->IsConst(), script_class, kernel_field->position())); - field.set_kernel_field(kernel_field); + field.set_kernel_offset(kernel_field->kernel_offset()); const AbstractType& type = T.TranslateType(kernel_field->type()); field.SetFieldType(type); field.set_has_initializer(kernel_field->initializer() != NULL); @@ -423,7 +405,7 @@ dart::Class& KernelReader::ReadClass(const dart::Library& library, kernel_field->IsConst(), false, // is_reflectable script_class, type, kernel_field->position())); - field.set_kernel_field(kernel_field); + field.set_kernel_offset(kernel_field->kernel_offset()); field.set_has_initializer(kernel_field->initializer() != NULL); GenerateFieldAccessors(klass, field, kernel_field); fields_.Add(&field); @@ -447,7 +429,7 @@ dart::Class& KernelReader::ReadClass(const dart::Library& library, klass, kernel_constructor->position())); function.set_end_token_pos(kernel_constructor->end_position()); functions_.Add(&function); - function.set_kernel_function(kernel_constructor); + function.set_kernel_offset(kernel_constructor->kernel_offset()); function.set_result_type(T.ReceiverType(klass)); SetupFunctionParameters(H, T, klass, function, kernel_constructor->function(), @@ -456,7 +438,7 @@ dart::Class& KernelReader::ReadClass(const dart::Library& library, if (FLAG_enable_mirrors) { library.AddFunctionMetadata(function, TokenPosition::kNoSource, - kernel_constructor); + kernel_constructor->kernel_offset()); } } @@ -474,7 +456,7 @@ dart::Class& KernelReader::ReadClass(const dart::Library& library, if (FLAG_enable_mirrors) { library.AddClassMetadata(klass, toplevel_class, TokenPosition::kNoSource, - kernel_klass); + kernel_klass->kernel_offset()); } return klass; @@ -533,7 +515,7 @@ void KernelReader::ReadProcedure(const dart::Library& library, script_class, kernel_procedure->position())); function.set_end_token_pos(kernel_procedure->end_position()); functions_.Add(&function); - function.set_kernel_function(kernel_procedure); + function.set_kernel_offset(kernel_procedure->kernel_offset()); function.set_is_debuggable( kernel_procedure->function()->dart_async_marker() == FunctionNode::kSync); @@ -572,7 +554,7 @@ void KernelReader::ReadProcedure(const dart::Library& library, } if (FLAG_enable_mirrors) { library.AddFunctionMetadata(function, TokenPosition::kNoSource, - kernel_procedure); + kernel_procedure->kernel_offset()); } } @@ -642,6 +624,8 @@ Script& KernelReader::ScriptAt(intptr_t index, StringIndex import_uri) { H.DartString(source_buffer, source_size, Heap::kOld); script = Script::New(import_uri_string, uri_string, source_code, RawScript::kKernelTag); + script.set_kernel_data(program_->libraries()[0]->kernel_data()); + script.set_kernel_data_size(program_->libraries()[0]->kernel_data_size()); script.set_kernel_string_offsets(H.string_offsets()); script.set_kernel_string_data(H.string_data()); script.set_kernel_canonical_names(H.canonical_names()); @@ -729,7 +713,7 @@ void KernelReader::GenerateFieldAccessors(const dart::Class& klass, script_class, kernel_field->position())); functions_.Add(&getter); getter.set_end_token_pos(kernel_field->end_position()); - getter.set_kernel_function(kernel_field); + getter.set_kernel_offset(kernel_field->kernel_offset()); getter.set_result_type(AbstractType::Handle(Z, field.type())); getter.set_is_debuggable(false); SetupFieldAccessorFunction(klass, getter); @@ -749,7 +733,7 @@ void KernelReader::GenerateFieldAccessors(const dart::Class& klass, script_class, kernel_field->position())); functions_.Add(&setter); setter.set_end_token_pos(kernel_field->end_position()); - setter.set_kernel_function(kernel_field); + setter.set_kernel_offset(kernel_field->kernel_offset()); setter.set_result_type(Object::void_type()); setter.set_is_debuggable(false); SetupFieldAccessorFunction(klass, setter); @@ -916,8 +900,6 @@ RawFunction::Kind KernelReader::GetFunctionType(Procedure* kernel_procedure) { ParsedFunction* ParseStaticFieldInitializer(Zone* zone, const dart::Field& field) { Thread* thread = Thread::Current(); - kernel::Field* kernel_field = kernel::Field::Cast( - reinterpret_cast(field.kernel_field())); dart::String& init_name = dart::String::Handle(zone, field.name()); init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name); @@ -933,7 +915,7 @@ ParsedFunction* ParseStaticFieldInitializer(Zone* zone, false, // is_external false, // is_native owner, TokenPosition::kNoSource)); - initializer_fun.set_kernel_function(kernel_field); + initializer_fun.set_kernel_offset(field.kernel_offset()); initializer_fun.set_result_type(AbstractType::Handle(zone, field.type())); initializer_fun.set_is_debuggable(false); initializer_fun.set_is_reflectable(false); diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc index 5b10f05fa41..f9f4e351199 100644 --- a/runtime/vm/kernel_to_il.cc +++ b/runtime/vm/kernel_to_il.cc @@ -30,40 +30,6 @@ namespace kernel { #define I Isolate::Current() -static void DiscoverEnclosingElements(Zone* zone, - const Function& function, - Function* outermost_function, - TreeNode** outermost_node, - Class** klass) { - // Find out if there is an enclosing kernel class (which will be used to - // resolve type parameters). - *outermost_function = function.raw(); - while (outermost_function->parent_function() != Object::null()) { - *outermost_function = outermost_function->parent_function(); - } - *outermost_node = - static_cast(outermost_function->kernel_function()); - if (*outermost_node != NULL) { - TreeNode* parent = NULL; - if ((*outermost_node)->IsProcedure()) { - parent = Procedure::Cast(*outermost_node)->parent(); - } else if ((*outermost_node)->IsConstructor()) { - parent = Constructor::Cast(*outermost_node)->parent(); - } else if ((*outermost_node)->IsField()) { - parent = Field::Cast(*outermost_node)->parent(); - } - if (parent != NULL && parent->IsClass()) *klass = Class::Cast(parent); - } -} - - -static bool IsStaticInitializer(const Function& function, Zone* zone) { - return (function.kind() == RawFunction::kImplicitStaticFinalGetter) && - dart::String::Handle(zone, function.name()) - .StartsWith(Symbols::InitPrefix()); -} - - Fragment& Fragment::operator+=(const Fragment& other) { if (entry == NULL) { entry = other.entry; @@ -684,581 +650,9 @@ const Array& TranslationHelper::ArgumentNames(List* named) { return names; } -ConstantEvaluator::ConstantEvaluator(FlowGraphBuilder* builder, - Zone* zone, - TranslationHelper* h, - DartTypeTranslator* type_translator) - : builder_(builder), - isolate_(Isolate::Current()), - zone_(zone), - translation_helper_(*h), - type_translator_(*type_translator), - script_(Script::Handle( - zone, - builder == NULL ? Script::null() - : builder_->parsed_function_->function().script())), - result_(Instance::Handle(zone)) {} - - -Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) { - if (!GetCachedConstant(expression, &result_)) { - expression->AcceptExpressionVisitor(this); - CacheConstantValue(expression, result_); - } - // We return a new `ZoneHandle` here on purpose: The intermediate language - // instructions do not make a copy of the handle, so we do it. - return Instance::ZoneHandle(Z, result_.raw()); -} - - -Object& ConstantEvaluator::EvaluateExpressionSafe(Expression* expression) { - LongJumpScope jump; - if (setjmp(*jump.Set()) == 0) { - return EvaluateExpression(expression); - } else { - Thread* thread = H.thread(); - Error& error = Error::Handle(Z); - error = thread->sticky_error(); - thread->clear_sticky_error(); - return error; - } -} - - -Instance& ConstantEvaluator::EvaluateConstructorInvocation( - ConstructorInvocation* node) { - if (!GetCachedConstant(node, &result_)) { - VisitConstructorInvocation(node); - CacheConstantValue(node, result_); - } - // We return a new `ZoneHandle` here on purpose: The intermediate language - // instructions do not make a copy of the handle, so we do it. - return Instance::ZoneHandle(Z, result_.raw()); -} - - -Instance& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) { - if (!GetCachedConstant(node, &result_)) { - VisitListLiteral(node); - CacheConstantValue(node, result_); - } - // We return a new `ZoneHandle` here on purpose: The intermediate language - // instructions do not make a copy of the handle, so we do it. - return Instance::ZoneHandle(Z, result_.raw()); -} - - -Instance& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) { - if (!GetCachedConstant(node, &result_)) { - VisitMapLiteral(node); - CacheConstantValue(node, result_); - } - // We return a new `ZoneHandle` here on purpose: The intermediate language - // instructions do not make a copy of the handle, so we do it. - return Instance::ZoneHandle(Z, result_.raw()); -} - - -void ConstantEvaluator::VisitBigintLiteral(BigintLiteral* node) { - const dart::String& value = H.DartString(node->value()); - result_ = Integer::New(value, Heap::kOld); - result_ = H.Canonicalize(result_); -} - - -void ConstantEvaluator::VisitBoolLiteral(BoolLiteral* node) { - result_ = Bool::Get(node->value()).raw(); -} - - -void ConstantEvaluator::VisitDoubleLiteral(DoubleLiteral* node) { - result_ = Double::New(H.DartString(node->value()), Heap::kOld); - result_ = H.Canonicalize(result_); -} - - -void ConstantEvaluator::VisitIntLiteral(IntLiteral* node) { - result_ = Integer::New(node->value(), Heap::kOld); - result_ = H.Canonicalize(result_); -} - - -void ConstantEvaluator::VisitNullLiteral(NullLiteral* node) { - result_ = Instance::null(); -} - - -void ConstantEvaluator::VisitStringLiteral(StringLiteral* node) { - result_ = H.DartSymbol(node->value()).raw(); -} - - -void ConstantEvaluator::VisitTypeLiteral(TypeLiteral* node) { - const AbstractType& type = T.TranslateType(node->type()); - if (type.IsMalformed()) { - H.ReportError("Malformed type literal in constant expression."); - } - result_ = type.raw(); -} - - -RawObject* ConstantEvaluator::EvaluateConstConstructorCall( - const dart::Class& type_class, - const TypeArguments& type_arguments, - const Function& constructor, - const Object& argument) { - // Factories have one extra argument: the type arguments. - // Constructors have 1 extra arguments: receiver. - const int kTypeArgsLen = 0; - const int kNumArgs = 1; - const int kNumExtraArgs = 1; - const int num_arguments = kNumArgs + kNumExtraArgs; - const Array& arg_values = - Array::Handle(Z, Array::New(num_arguments, Heap::kOld)); - Instance& instance = Instance::Handle(Z); - if (!constructor.IsFactory()) { - instance = Instance::New(type_class, Heap::kOld); - if (!type_arguments.IsNull()) { - ASSERT(type_arguments.IsInstantiated()); - instance.SetTypeArguments( - TypeArguments::Handle(Z, type_arguments.Canonicalize())); - } - arg_values.SetAt(0, instance); - } else { - // Prepend type_arguments to list of arguments to factory. - ASSERT(type_arguments.IsZoneHandle()); - arg_values.SetAt(0, type_arguments); - } - arg_values.SetAt((0 + kNumExtraArgs), argument); - const Array& args_descriptor = - Array::Handle(Z, ArgumentsDescriptor::New(kTypeArgsLen, num_arguments, - Object::empty_array())); - const Object& result = Object::Handle( - Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor)); - ASSERT(!result.IsError()); - if (constructor.IsFactory()) { - // The factory method returns the allocated object. - instance ^= result.raw(); - } - return H.Canonicalize(instance); -} - - -bool ConstantEvaluator::GetCachedConstant(TreeNode* node, Instance* value) { - if (builder_ == NULL) return false; - - const Function& function = builder_->parsed_function_->function(); - if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { - // Don't cache constants in initializer expressions. They get - // evaluated only once. - return false; - } - - bool is_present = false; - ASSERT(!script_.InVMHeap()); - if (script_.compile_time_constants() == Array::null()) { - return false; - } - KernelConstantsMap constants(script_.compile_time_constants()); - *value ^= constants.GetOrNull(node->kernel_offset(), &is_present); - // Mutator compiler thread may add constants while background compiler - // is running, and thus change the value of 'compile_time_constants'; - // do not assert that 'compile_time_constants' has not changed. - constants.Release(); - if (FLAG_compiler_stats && is_present) { - H.thread()->compiler_stats()->num_const_cache_hits++; - } - return is_present; -} - - -void ConstantEvaluator::CacheConstantValue(TreeNode* node, - const Instance& value) { - ASSERT(Thread::Current()->IsMutatorThread()); - - if (builder_ == NULL) return; - - const Function& function = builder_->parsed_function_->function(); - if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { - // Don't cache constants in initializer expressions. They get - // evaluated only once. - return; - } - const intptr_t kInitialConstMapSize = 16; - ASSERT(!script_.InVMHeap()); - if (script_.compile_time_constants() == Array::null()) { - const Array& array = Array::Handle( - HashTables::New(kInitialConstMapSize, Heap::kNew)); - script_.set_compile_time_constants(array); - } - KernelConstantsMap constants(script_.compile_time_constants()); - constants.InsertNewOrGetValue(node->kernel_offset(), value); - script_.set_compile_time_constants(constants.Release()); -} - - -void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) { - const dart::String& symbol_value = H.DartSymbol(node->value()); - - const dart::Class& symbol_class = - dart::Class::ZoneHandle(Z, I->object_store()->symbol_class()); - ASSERT(!symbol_class.IsNull()); - const Function& symbol_constructor = Function::ZoneHandle( - Z, symbol_class.LookupConstructor(Symbols::SymbolCtor())); - ASSERT(!symbol_constructor.IsNull()); - result_ ^= EvaluateConstConstructorCall( - symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value); -} - - -void ConstantEvaluator::VisitListLiteral(ListLiteral* node) { - DartType* types[] = {node->type()}; - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1); - - intptr_t length = node->expressions().length(); - const Array& const_list = - Array::ZoneHandle(Z, Array::New(length, Heap::kOld)); - const_list.SetTypeArguments(type_arguments); - for (intptr_t i = 0; i < length; i++) { - const Instance& expression = EvaluateExpression(node->expressions()[i]); - const_list.SetAt(i, expression); - } - const_list.MakeImmutable(); - result_ = H.Canonicalize(const_list); -} - - -void ConstantEvaluator::VisitMapLiteral(MapLiteral* node) { - DartType* types[] = {node->key_type(), node->value_type()}; - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2); - - intptr_t length = node->entries().length(); - - Array& const_kv_array = - Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld)); - for (intptr_t i = 0; i < length; i++) { - const_kv_array.SetAt(2 * i + 0, - EvaluateExpression(node->entries()[i]->key())); - const_kv_array.SetAt(2 * i + 1, - EvaluateExpression(node->entries()[i]->value())); - } - - const_kv_array.MakeImmutable(); - const_kv_array ^= H.Canonicalize(const_kv_array); - - const dart::Class& map_class = dart::Class::Handle( - Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap())); - ASSERT(!map_class.IsNull()); - ASSERT(map_class.NumTypeArguments() == 2); - - const dart::Field& field = dart::Field::Handle( - Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs"))); - ASSERT(!field.IsNull()); - - // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`! - result_ = Instance::New(map_class, Heap::kOld); - ASSERT(!result_.IsNull()); - result_.SetTypeArguments(type_arguments); - result_.SetField(field, const_kv_array); - result_ = H.Canonicalize(result_); -} - - -void ConstantEvaluator::VisitConstructorInvocation( - ConstructorInvocation* node) { - Arguments* kernel_arguments = node->arguments(); - - const Function& constructor = Function::Handle( - Z, H.LookupConstructorByKernelConstructor(node->target())); - dart::Class& klass = dart::Class::Handle(Z, constructor.Owner()); - - // Build the type arguments vector (if necessary). - const TypeArguments* type_arguments = - TranslateTypeArguments(constructor, &klass, kernel_arguments); - - // Prepare either the instance or the type argument vector for the constructor - // call. - Instance* receiver = NULL; - const TypeArguments* type_arguments_argument = NULL; - if (!constructor.IsFactory()) { - receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld)); - if (type_arguments != NULL) { - receiver->SetTypeArguments(*type_arguments); - } - } else { - type_arguments_argument = type_arguments; - } - - const Object& result = RunFunction(constructor, kernel_arguments, receiver, - type_arguments_argument); - if (constructor.IsFactory()) { - // Factories return the new object. - result_ ^= result.raw(); - result_ = H.Canonicalize(result_); - } else { - ASSERT(!receiver->IsNull()); - result_ = H.Canonicalize(*receiver); - } -} - - -void ConstantEvaluator::VisitMethodInvocation(MethodInvocation* node) { - Arguments* kernel_arguments = node->arguments(); - - // Dart does not support generic methods yet. - ASSERT(kernel_arguments->types().length() == 0); - - const Instance& receiver = EvaluateExpression(node->receiver()); - dart::Class& klass = dart::Class::Handle( - Z, isolate_->class_table()->At(receiver.GetClassId())); - ASSERT(!klass.IsNull()); - - // Search the superclass chain for the selector. - Function& function = Function::Handle(Z); - const dart::String& method_name = H.DartMethodName(node->name()); - while (!klass.IsNull()) { - function = klass.LookupDynamicFunctionAllowPrivate(method_name); - if (!function.IsNull()) break; - klass = klass.SuperClass(); - } - - // The frontend should guarantee that [MethodInvocation]s inside constant - // expressions are always valid. - ASSERT(!function.IsNull()); - - // Run the method and canonicalize the result. - const Object& result = RunFunction(function, kernel_arguments, &receiver); - result_ ^= result.raw(); - result_ = H.Canonicalize(result_); -} - - -void ConstantEvaluator::VisitStaticGet(StaticGet* node) { - NameIndex target = node->target(); - if (H.IsField(target)) { - const dart::Field& field = - dart::Field::Handle(Z, H.LookupFieldByKernelField(target)); - if (field.StaticValue() == Object::sentinel().raw() || - field.StaticValue() == Object::transition_sentinel().raw()) { - field.EvaluateInitializer(); - result_ = field.StaticValue(); - result_ = H.Canonicalize(result_); - field.SetStaticValue(result_, true); - } else { - result_ = field.StaticValue(); - } - } else if (H.IsProcedure(target)) { - const Function& function = - Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); - - if (H.IsMethod(target)) { - Function& closure_function = - Function::ZoneHandle(Z, function.ImplicitClosureFunction()); - closure_function.set_kernel_function(function.kernel_function()); - result_ = closure_function.ImplicitStaticClosure(); - result_ = H.Canonicalize(result_); - } else if (H.IsGetter(target)) { - UNIMPLEMENTED(); - } else { - UNIMPLEMENTED(); - } - } -} - - -void ConstantEvaluator::VisitVariableGet(VariableGet* node) { - // When we see a [VariableGet] the corresponding [VariableDeclaration] must've - // been executed already. It therefore must have a constant object associated - // with it. - LocalVariable* variable = builder_->LookupVariable(node->variable()); - ASSERT(variable->IsConst()); - result_ = variable->ConstValue()->raw(); -} - - -void ConstantEvaluator::VisitLet(Let* node) { - VariableDeclaration* variable = node->variable(); - LocalVariable* local = builder_->LookupVariable(variable); - local->SetConstValue(EvaluateExpression(variable->initializer())); - node->body()->AcceptExpressionVisitor(this); -} - - -void ConstantEvaluator::VisitStaticInvocation(StaticInvocation* node) { - const Function& function = Function::ZoneHandle( - Z, H.LookupStaticMethodByKernelProcedure(node->procedure())); - dart::Class& klass = dart::Class::Handle(Z, function.Owner()); - - // Build the type arguments vector (if necessary). - const TypeArguments* type_arguments = - TranslateTypeArguments(function, &klass, node->arguments()); - - const Object& result = - RunFunction(function, node->arguments(), NULL, type_arguments); - result_ ^= result.raw(); - result_ = H.Canonicalize(result_); -} - - -void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) { - intptr_t length = node->expressions().length(); - - bool all_string = true; - const Array& strings = Array::Handle(Z, Array::New(length)); - for (intptr_t i = 0; i < length; i++) { - EvaluateExpression(node->expressions()[i]); - strings.SetAt(i, result_); - all_string = all_string && result_.IsString(); - } - if (all_string) { - result_ = dart::String::ConcatAll(strings, Heap::kOld); - result_ = H.Canonicalize(result_); - } else { - // Get string interpolation function. - const dart::Class& cls = dart::Class::Handle( - Z, dart::Library::LookupCoreClass(Symbols::StringBase())); - ASSERT(!cls.IsNull()); - const Function& func = Function::Handle( - Z, cls.LookupStaticFunction( - dart::Library::PrivateCoreLibName(Symbols::Interpolate()))); - ASSERT(!func.IsNull()); - - // Build argument array to pass to the interpolation function. - const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld)); - interpolate_arg.SetAt(0, strings); - - // Run and canonicalize. - const Object& result = - RunFunction(func, interpolate_arg, Array::null_array()); - result_ = H.Canonicalize(dart::String::Cast(result)); - } -} - - -void ConstantEvaluator::VisitConditionalExpression( - ConditionalExpression* node) { - if (EvaluateBooleanExpression(node->condition())) { - EvaluateExpression(node->then()); - } else { - EvaluateExpression(node->otherwise()); - } -} - - -void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) { - if (node->op() == LogicalExpression::kAnd) { - if (EvaluateBooleanExpression(node->left())) { - EvaluateBooleanExpression(node->right()); - } - } else { - ASSERT(node->op() == LogicalExpression::kOr); - if (!EvaluateBooleanExpression(node->left())) { - EvaluateBooleanExpression(node->right()); - } - } -} - - -void ConstantEvaluator::VisitNot(Not* node) { - result_ ^= Bool::Get(!EvaluateBooleanExpression(node->expression())).raw(); -} - - -void ConstantEvaluator::VisitPropertyGet(PropertyGet* node) { - StringIndex string_index = node->name()->string_index(); - if (H.StringEquals(string_index, "length")) { - node->receiver()->AcceptExpressionVisitor(this); - if (result_.IsString()) { - const dart::String& str = - dart::String::Handle(Z, dart::String::RawCast(result_.raw())); - result_ = Integer::New(str.Length()); - } else { - H.ReportError( - "Constant expressions can only call " - "'length' on string constants."); - } - } else { - VisitDefaultExpression(node); - } -} - - -const TypeArguments* ConstantEvaluator::TranslateTypeArguments( - const Function& target, - dart::Class* target_klass, - Arguments* kernel_arguments) { - List& kernel_type_arguments = kernel_arguments->types(); - - const TypeArguments* type_arguments = NULL; - if (kernel_type_arguments.length() > 0) { - type_arguments = &T.TranslateInstantiatedTypeArguments( - *target_klass, kernel_type_arguments.raw_array(), - kernel_type_arguments.length()); - - if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { - H.ReportError("Type must be constant in const constructor."); - } - } else if (target.IsFactory() && type_arguments == NULL) { - // All factories take a type arguments vector as first argument (independent - // of whether the class is generic or not). - type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null()); - } - return type_arguments; -} - - -const Object& ConstantEvaluator::RunFunction(const Function& function, - Arguments* kernel_arguments, - const Instance* receiver, - const TypeArguments* type_args) { - // We do not support generic methods yet. - ASSERT((receiver == NULL) || (type_args == NULL)); - intptr_t extra_arguments = - (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0); - - // Build up arguments. - const Array& arguments = Array::ZoneHandle( - Z, Array::New(extra_arguments + kernel_arguments->count())); - const Array& names = - Array::ZoneHandle(Z, Array::New(kernel_arguments->named().length())); - intptr_t pos = 0; - if (receiver != NULL) { - arguments.SetAt(pos++, *receiver); - } - if (type_args != NULL) { - arguments.SetAt(pos++, *type_args); - } - for (intptr_t i = 0; i < kernel_arguments->positional().length(); i++) { - EvaluateExpression(kernel_arguments->positional()[i]); - arguments.SetAt(pos++, result_); - } - for (intptr_t i = 0; i < kernel_arguments->named().length(); i++) { - NamedExpression* named_expression = kernel_arguments->named()[i]; - EvaluateExpression(named_expression->expression()); - arguments.SetAt(pos++, result_); - names.SetAt(i, H.DartSymbol(named_expression->name())); - } - return RunFunction(function, arguments, names); -} - - -const Object& ConstantEvaluator::RunFunction(const Function& function, - const Array& arguments, - const Array& names) { - const int kTypeArgsLen = 0; // Generic functions not yet supported. - const Array& args_descriptor = Array::Handle( - Z, ArgumentsDescriptor::New(kTypeArgsLen, arguments.Length(), names)); - const Object& result = Object::Handle( - Z, DartEntry::InvokeFunction(function, arguments, args_descriptor)); - if (result.IsError()) { - H.ReportError(Error::Cast(result), "error evaluating constant constructor"); - } - return result; -} - FlowGraphBuilder::FlowGraphBuilder( - TreeNode* node, + intptr_t kernel_offset, ParsedFunction* parsed_function, const ZoneGrowableArray& ic_data_array, ZoneGrowableArray* context_level_array, @@ -1268,7 +662,7 @@ FlowGraphBuilder::FlowGraphBuilder( : translation_helper_(Thread::Current()), thread_(translation_helper_.thread()), zone_(translation_helper_.zone()), - node_(node), + kernel_offset_(kernel_offset), parsed_function_(parsed_function), osr_id_(osr_id), ic_data_array_(ic_data_array), @@ -1294,7 +688,6 @@ FlowGraphBuilder::FlowGraphBuilder( type_translator_(&translation_helper_, &active_class_, /* finalize= */ true), - constant_evaluator_(this, zone_, &translation_helper_, &type_translator_), streaming_flow_graph_builder_(NULL) { Script& script = Script::Handle(Z, parsed_function->function().script()); H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets())); @@ -1349,9 +742,7 @@ Fragment FlowGraphBuilder::TranslateFinallyFinalizers( try_finally_block_->finalizer_kernel_offset(); try_finally_block_ = try_finally_block_->outer(); if (finalizer != NULL) { - // This will potentially have exceptional cases as described in - // [VisitTryFinally] and will handle them. - instructions += TranslateStatement(finalizer); + UNREACHABLE(); } else { instructions += streaming_flow_graph_builder_->BuildStatementAt( finalizer_kernel_offset); @@ -1378,11 +769,6 @@ Fragment FlowGraphBuilder::TranslateFinallyFinalizers( } -Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) { - return EnterScope(node->kernel_offset(), new_context); -} - - Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset, bool* new_context) { Fragment instructions; @@ -1399,11 +785,6 @@ Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset, } -Fragment FlowGraphBuilder::ExitScope(TreeNode* node) { - return ExitScope(node->kernel_offset()); -} - - Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) { Fragment instructions; const intptr_t context_size = @@ -1474,8 +855,7 @@ Fragment FlowGraphBuilder::LoadInstantiatorTypeArguments() { #endif instructions += LoadLocal(scopes_->type_arguments_variable); } else if (scopes_->this_variable != NULL && - active_class_.kernel_class != NULL && - active_class_.kernel_class->type_parameters().length() > 0) { + active_class_.class_type_parameters > 0) { ASSERT(!parsed_function_->function().IsFactory()); intptr_t type_arguments_field_offset = active_class_.klass->type_arguments_field_offset(); @@ -2410,402 +1790,20 @@ FlowGraph* FlowGraphBuilder::BuildGraph() { if (function.IsConstructorClosureFunction()) return NULL; - TreeNode* library_node = node_; - if (node_ != NULL) { - const Function* parent = &function; - while (true) { - library_node = static_cast(parent->kernel_function()); - while (library_node != NULL && !library_node->IsLibrary()) { - if (library_node->IsMember()) { - library_node = Member::Cast(library_node)->parent(); - } else if (library_node->IsClass()) { - library_node = Class::Cast(library_node)->parent(); - break; - } else { - library_node = NULL; - break; - } - } - if (library_node != NULL) break; - parent = &Function::Handle(parent->parent_function()); - } - } if (streaming_flow_graph_builder_ != NULL) { delete streaming_flow_graph_builder_; streaming_flow_graph_builder_ = NULL; } - if (library_node != NULL && library_node->IsLibrary()) { - Library* library = Library::Cast(library_node); - streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder( - this, library->kernel_data(), library->kernel_data_size()); - } - dart::Class& klass = - dart::Class::Handle(zone_, parsed_function_->function().Owner()); + Script& script = Script::Handle(Z, function.script()); + streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder( + this, script.kernel_data(), script.kernel_data_size()); - Function& outermost_function = Function::Handle(Z); - TreeNode* outermost_node = NULL; - Class* kernel_class = NULL; - DiscoverEnclosingElements(Z, function, &outermost_function, &outermost_node, - &kernel_class); - - // Mark that we are using [klass]/[kernell_klass] as active class. Resolving - // of type parameters will get resolved via [kernell_klass] unless we are - // nested inside a static factory in which case we will use [member]. - ActiveClassScope active_class_scope(&active_class_, kernel_class, &klass); - Member* member = ((outermost_node != NULL) && outermost_node->IsMember()) - ? Member::Cast(outermost_node) - : NULL; - ActiveMemberScope active_member(&active_class_, member); - - // The IR builder will create its own local variables and scopes, and it - // will not need an AST. The code generator will assume that there is a - // local variable stack slot allocated for the current context and (I - // think) that the runtime will expect it to be at a fixed offset which - // requires allocating an unused expression temporary variable. - scopes_ = parsed_function_->EnsureKernelScopes(); - - switch (function.kind()) { - case RawFunction::kClosureFunction: - case RawFunction::kRegularFunction: - case RawFunction::kGetterFunction: - case RawFunction::kSetterFunction: { - FunctionNode* kernel_function = node_->IsProcedure() - ? Procedure::Cast(node_)->function() - : FunctionNode::Cast(node_); - return function.IsImplicitClosureFunction() - ? BuildGraphOfImplicitClosureFunction(kernel_function, - function) - : BuildGraphOfFunction(kernel_function); - } - case RawFunction::kConstructor: { - bool is_factory = function.IsFactory(); - if (is_factory) { - Procedure* procedure = Procedure::Cast(node_); - FunctionNode* function = procedure->function(); - return BuildGraphOfFunction(function, NULL); - } else { - Constructor* constructor = Constructor::Cast(node_); - FunctionNode* function = constructor->function(); - return BuildGraphOfFunction(function, constructor); - } - } - case RawFunction::kImplicitGetter: - case RawFunction::kImplicitStaticFinalGetter: - case RawFunction::kImplicitSetter: { - Field* field = Field::Cast(node_); - return IsStaticInitializer(function, Z) - ? BuildGraphOfStaticFieldInitializer(field) - : BuildGraphOfFieldAccessor(field, scopes_->setter_value); - } - case RawFunction::kMethodExtractor: - return BuildGraphOfMethodExtractor(function); - case RawFunction::kNoSuchMethodDispatcher: - return BuildGraphOfNoSuchMethodDispatcher(function); - case RawFunction::kInvokeFieldDispatcher: - return BuildGraphOfInvokeFieldDispatcher(function); - case RawFunction::kSignatureFunction: - case RawFunction::kIrregexpFunction: - break; - } - UNREACHABLE(); - return NULL; + return streaming_flow_graph_builder_->BuildGraph(kernel_offset_); } -FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, - Constructor* constructor) { - const Function& dart_function = parsed_function_->function(); - TargetEntryInstr* normal_entry = BuildTargetEntry(); - graph_entry_ = - new (Z) GraphEntryInstr(*parsed_function_, normal_entry, osr_id_); - - SetupDefaultParameterValues(function); - - Fragment body; - if (!dart_function.is_native()) body += CheckStackOverflowInPrologue(); - intptr_t context_size = - parsed_function_->node_sequence()->scope()->num_context_variables(); - if (context_size > 0) { - body += PushContext(context_size); - LocalVariable* context = MakeTemporary(); - - // Copy captured parameters from the stack into the context. - LocalScope* scope = parsed_function_->node_sequence()->scope(); - intptr_t parameter_count = dart_function.NumParameters(); - intptr_t parameter_index = parsed_function_->first_parameter_index(); - for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) { - LocalVariable* variable = scope->VariableAt(i); - if (variable->is_captured()) { - // There is no LocalVariable describing the on-stack parameter so - // create one directly and use the same type. - LocalVariable* parameter = new (Z) - LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, - Symbols::TempParam(), variable->type()); - parameter->set_index(parameter_index); - // Mark the stack variable so it will be ignored by the code for - // try/catch. - parameter->set_is_captured_parameter(true); - - // Copy the parameter from the stack to the context. Overwrite it - // with a null constant on the stack so the original value is - // eligible for garbage collection. - body += LoadLocal(context); - body += LoadLocal(parameter); - body += StoreInstanceField(TokenPosition::kNoSource, - Context::variable_offset(variable->index())); - body += NullConstant(); - body += StoreLocal(TokenPosition::kNoSource, parameter); - body += Drop(); - } - } - body += Drop(); // The context. - } - if (constructor != NULL) { - // TODO(27590): Currently the [VariableDeclaration]s from the - // initializers will be visible inside the entire body of the constructor. - // We should make a separate scope for them. - Class* kernel_class = Class::Cast(constructor->parent()); - body += TranslateInitializers(kernel_class, &constructor->initializers()); - } - - // The specification defines the result of `a == b` to be: - // - // a) if either side is `null` then the result is `identical(a, b)`. - // b) else the result is `a.operator==(b)` - // - // For user-defined implementations of `operator==` we need therefore - // implement the handling of a). - // - // The default `operator==` implementation in `Object` is implemented in terms - // of identical (which we assume here!) which means that case a) is actually - // included in b). So we just use the normal implementation in the body. - if ((dart_function.NumParameters() == 2) && - (dart_function.name() == Symbols::EqualOperator().raw()) && - (dart_function.Owner() != I->object_store()->object_class())) { - LocalVariable* parameter = - LookupVariable(function->positional_parameters()[0]); - - TargetEntryInstr* null_entry; - TargetEntryInstr* non_null_entry; - - body += LoadLocal(parameter); - body += BranchIfNull(&null_entry, &non_null_entry); - - // The argument was `null` and the receiver is not the null class (we only - // go into this branch for user-defined == operators) so we can return - // false. - Fragment null_fragment(null_entry); - null_fragment += Constant(Bool::False()); - null_fragment += Return(dart_function.end_token_pos()); - - body = Fragment(body.entry, non_null_entry); - } - - // If we run in checked mode, we have to check the type of the passed - // arguments. - if (I->type_checks()) { - List& positional = function->positional_parameters(); - List& named = function->named_parameters(); - - for (intptr_t i = 0; i < positional.length(); i++) { - VariableDeclaration* variable = positional[i]; - body += LoadLocal(LookupVariable(variable)); - body += CheckVariableTypeInCheckedMode(variable); - body += Drop(); - } - for (intptr_t i = 0; i < named.length(); i++) { - VariableDeclaration* variable = named[i]; - body += LoadLocal(LookupVariable(variable)); - body += CheckVariableTypeInCheckedMode(variable); - body += Drop(); - } - } - - if (FLAG_causal_async_stacks && - (dart_function.IsAsyncFunction() || dart_function.IsAsyncGenerator())) { - LocalScope* scope = parsed_function_->node_sequence()->scope(); - // :async_stack_trace = _asyncStackTraceHelper(:async_op); - const dart::Library& async_lib = - dart::Library::Handle(dart::Library::AsyncLibrary()); - const Function& target = Function::ZoneHandle( - Z, - async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper())); - ASSERT(!target.IsNull()); - - // TODO(johnmccutchan): Why does this have the null value? - LocalVariable* async_op = - scope->child()->LookupVariable(Symbols::AsyncOperation(), false); - ASSERT(async_op != NULL); - ASSERT(async_op->is_captured()); - body += LoadLocal(async_op); - body += PushArgument(); - body += StaticCall(TokenPosition::kNoSource, target, 1); - LocalVariable* async_stack_trace_var = - scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); - ASSERT(async_stack_trace_var != NULL); - body += StoreLocal(TokenPosition::kNoSource, async_stack_trace_var); - body += Drop(); - } - - if (dart_function.is_native()) { - body += NativeFunctionBody(function, dart_function); - } else if (function->body() != NULL) { - body += TranslateStatement(function->body()); - } - if (body.is_open()) { - body += NullConstant(); - body += Return(dart_function.end_token_pos()); - } - - // If functions body contains any yield points build switch statement that - // selects a continuation point based on the value of :await_jump_var. - if (!yield_continuations_.is_empty()) { - // The code we are building will be executed right after we enter - // the function and before any nested contexts are allocated. - // Reset current context_depth_ to match this. - const intptr_t current_context_depth = context_depth_; - context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); - - // Prepend an entry corresponding to normal entry to the function. - yield_continuations_.InsertAt( - 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), - CatchClauseNode::kInvalidTryIndex)); - yield_continuations_[0].entry->LinkTo(body.entry); - - // Build a switch statement. - Fragment dispatch; - - // Load :await_jump_var into a temporary. - dispatch += LoadLocal(scopes_->yield_jump_variable); - dispatch += StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable); - dispatch += Drop(); - - BlockEntryInstr* block = NULL; - for (intptr_t i = 0; i < yield_continuations_.length(); i++) { - if (i == 1) { - // This is not a normal entry but a resumption. Restore - // :current_context_var from :await_ctx_var. - // Note: after this point context_depth_ does not match current context - // depth so we should not access any local variables anymore. - dispatch += LoadLocal(scopes_->yield_context_variable); - dispatch += StoreLocal(TokenPosition::kNoSource, - parsed_function_->current_context_var()); - dispatch += Drop(); - } - if (i == (yield_continuations_.length() - 1)) { - // We reached the last possility, no need to build more ifs. - // Continue to the last continuation. - // Note: continuations start with nop DropTemps instruction - // which acts like an anchor, so we need to skip it. - block->set_try_index(yield_continuations_[i].try_index); - dispatch <<= yield_continuations_[i].entry->next(); - break; - } - - // Build comparison: - // - // if (:await_ctx_var == i) { - // -> yield_continuations_[i] - // } else ... - // - TargetEntryInstr* then; - TargetEntryInstr* otherwise; - dispatch += LoadLocal(scopes_->switch_variable); - dispatch += IntConstant(i); - dispatch += BranchIfStrictEqual(&then, &otherwise); - - // True branch is linked to appropriate continuation point. - // Note: continuations start with nop DropTemps instruction - // which acts like an anchor, so we need to skip it. - then->LinkTo(yield_continuations_[i].entry->next()); - then->set_try_index(yield_continuations_[i].try_index); - // False branch will contain the next comparison. - dispatch = Fragment(dispatch.entry, otherwise); - block = otherwise; - } - body = dispatch; - - context_depth_ = current_context_depth; - } - - if (FLAG_causal_async_stacks && - (dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) { - // The code we are building will be executed right after we enter - // the function and before any nested contexts are allocated. - // Reset current context_depth_ to match this. - const intptr_t current_context_depth = context_depth_; - context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); - - Fragment instructions; - LocalScope* scope = parsed_function_->node_sequence()->scope(); - - const Function& target = Function::ZoneHandle( - Z, I->object_store()->async_set_thread_stack_trace()); - ASSERT(!target.IsNull()); - - // Fetch and load :async_stack_trace - LocalVariable* async_stack_trace_var = - scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); - ASSERT((async_stack_trace_var != NULL) && - async_stack_trace_var->is_captured()); - instructions += LoadLocal(async_stack_trace_var); - instructions += PushArgument(); - - // Call _asyncSetThreadStackTrace - instructions += StaticCall(TokenPosition::kNoSource, target, 1); - instructions += Drop(); - - // TODO(29737): This sequence should be generated in order. - body = instructions + body; - context_depth_ = current_context_depth; - } - - if (NeedsDebugStepCheck(dart_function, function->position())) { - const intptr_t current_context_depth = context_depth_; - context_depth_ = 0; - - // If a switch was added above: Start the switch by injecting a debuggable - // safepoint so stepping over an await works. - // If not, still start the body with a debuggable safepoint to ensure - // breaking on a method always happens, even if there are no - // assignments/calls/runtimecalls in the first basic block. - // Place this check at the last parameter to ensure parameters - // are in scope in the debugger at method entry. - const int num_params = dart_function.NumParameters(); - TokenPosition check_pos = TokenPosition::kNoSource; - if (num_params > 0) { - LocalScope* scope = parsed_function_->node_sequence()->scope(); - const LocalVariable& parameter = *scope->VariableAt(num_params - 1); - check_pos = parameter.token_pos(); - } - if (!check_pos.IsDebugPause()) { - // No parameters or synthetic parameters. - check_pos = function->position(); - ASSERT(check_pos.IsDebugPause()); - } - - // TODO(29737): This sequence should be generated in order. - body = DebugStepCheck(check_pos) + body; - context_depth_ = current_context_depth; - } - - normal_entry->LinkTo(body.entry); - - // When compiling for OSR, use a depth first search to prune instructions - // unreachable from the OSR entry. Catch entries are always considered - // reachable, even if they become unreachable after OSR. - if (osr_id_ != Compiler::kNoOSRDeoptId) { - BitVector* block_marks = new (Z) BitVector(Z, next_block_id_); - bool found = graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_, - block_marks); - ASSERT(found); - } - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); -} - - -Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, +Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset, const Function& function) { ASSERT(function.is_native()); // We explicitly build the graph for native functions in the same way that the @@ -2817,8 +1815,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, switch (kind) { case MethodRecognizer::kObjectEquals: body += LoadLocal(scopes_->this_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += StrictCompare(Token::kEQ_STRICT); break; case MethodRecognizer::kStringBaseLength: @@ -2856,8 +1853,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true); break; case MethodRecognizer::kClassIDgetID: - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += LoadClassId(); break; case MethodRecognizer::kGrowableArrayCapacity: @@ -2869,8 +1865,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, break; case MethodRecognizer::kObjectArrayAllocate: body += LoadLocal(scopes_->type_arguments_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += CreateArray(); break; case MethodRecognizer::kBigint_getDigits: @@ -2890,8 +1885,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, break; case MethodRecognizer::kLinkedHashMap_setIndex: body += LoadLocal(scopes_->this_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += StoreInstanceField(TokenPosition::kNoSource, LinkedHashMap::index_offset()); body += NullConstant(); @@ -2903,8 +1897,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, break; case MethodRecognizer::kLinkedHashMap_setData: body += LoadLocal(scopes_->this_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += StoreInstanceField(TokenPosition::kNoSource, LinkedHashMap::data_offset()); body += NullConstant(); @@ -2916,8 +1909,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, break; case MethodRecognizer::kLinkedHashMap_setHashMask: body += LoadLocal(scopes_->this_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += StoreInstanceField(TokenPosition::kNoSource, LinkedHashMap::hash_mask_offset(), kNoStoreBarrier); @@ -2930,8 +1922,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, break; case MethodRecognizer::kLinkedHashMap_setUsedData: body += LoadLocal(scopes_->this_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += StoreInstanceField(TokenPosition::kNoSource, LinkedHashMap::used_data_offset(), kNoStoreBarrier); @@ -2944,8 +1935,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, break; case MethodRecognizer::kLinkedHashMap_setDeletedKeys: body += LoadLocal(scopes_->this_variable); - body += LoadLocal( - LookupVariable(kernel_function->positional_parameters()[0])); + body += LoadLocal(LookupVariable(first_positional_offset)); body += StoreInstanceField(TokenPosition::kNoSource, LinkedHashMap::deleted_keys_offset(), kNoStoreBarrier); @@ -2966,82 +1956,6 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function, } -FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor( - Field* kernel_field, - LocalVariable* setter_value) { - const Function& function = parsed_function_->function(); - - bool is_setter = function.IsImplicitSetterFunction(); - bool is_method = !function.IsStaticFunction(); - dart::Field& field = dart::Field::ZoneHandle( - Z, H.LookupFieldByKernelField(kernel_field->canonical_name())); - - TargetEntryInstr* normal_entry = BuildTargetEntry(); - graph_entry_ = new (Z) - GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); - - Fragment body(normal_entry); - if (is_setter) { - if (is_method) { - body += LoadLocal(scopes_->this_variable); - body += LoadLocal(setter_value); - body += StoreInstanceFieldGuarded(field, false); - } else { - body += LoadLocal(setter_value); - body += StoreStaticField(TokenPosition::kNoSource, field); - } - body += NullConstant(); - } else if (is_method) { - body += LoadLocal(scopes_->this_variable); - body += LoadField(field); - } else if (field.is_const()) { - // If the parser needs to know the value of an uninitialized constant field - // it will set the value to the transition sentinel (used to detect circular - // initialization) and then call the implicit getter. Thus, the getter - // cannot contain the InitStaticField instruction that normal static getters - // contain because it would detect spurious circular initialization when it - // checks for the transition sentinel. - Expression* initializer = kernel_field->initializer(); - ASSERT(initializer != NULL); - body += Constant(constant_evaluator_.EvaluateExpression(initializer)); - } else { - // The field always has an initializer because static fields without - // initializers are initialized eagerly and do not have implicit getters. - ASSERT(field.has_initializer()); - body += Constant(field); - body += InitStaticField(field); - body += Constant(field); - body += LoadStaticField(); - } - body += Return(TokenPosition::kNoSource); - - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); -} - - -FlowGraph* FlowGraphBuilder::BuildGraphOfStaticFieldInitializer( - Field* kernel_field) { - ASSERT(kernel_field->IsStatic()); - - Expression* initializer = kernel_field->initializer(); - - TargetEntryInstr* normal_entry = BuildTargetEntry(); - graph_entry_ = new (Z) - GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); - - Fragment body(normal_entry); - body += CheckStackOverflowInPrologue(); - if (kernel_field->IsConst()) { - body += Constant(constant_evaluator_.EvaluateExpression(initializer)); - } else { - body += TranslateExpression(initializer); - } - body += Return(TokenPosition::kNoSource); - - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); -} - - Fragment FlowGraphBuilder::BuildImplicitClosureCreation( const Function& target) { Fragment fragment; @@ -3100,19 +2014,6 @@ Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field, } -Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode( - VariableDeclaration* variable) { - if (I->type_checks()) { - const AbstractType& dst_type = T.TranslateType(variable->type()); - if (dst_type.IsMalformed()) { - return ThrowTypeError(); - } - return CheckAssignableInCheckedMode(dst_type, - H.DartSymbol(variable->name())); - } - return Fragment(); -} - Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode( const AbstractType& dst_type, const dart::String& name_symbol) { @@ -3257,58 +2158,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor( } -FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction( - FunctionNode* kernel_function, - const Function& function) { - const Function& target = Function::ZoneHandle(Z, function.parent_function()); - - TargetEntryInstr* normal_entry = BuildTargetEntry(); - graph_entry_ = new (Z) - GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); - SetupDefaultParameterValues(kernel_function); - - Fragment body(normal_entry); - body += CheckStackOverflowInPrologue(); - - // Load all the arguments. - if (!target.is_static()) { - // The context has a fixed shape: a single variable which is the - // closed-over receiver. - body += LoadLocal(parsed_function_->current_context_var()); - body += LoadField(Context::variable_offset(0)); - body += PushArgument(); - } - intptr_t positional_argument_count = - kernel_function->positional_parameters().length(); - for (intptr_t i = 0; i < positional_argument_count; i++) { - body += - LoadLocal(LookupVariable(kernel_function->positional_parameters()[i])); - body += PushArgument(); - } - intptr_t named_argument_count = kernel_function->named_parameters().length(); - Array& argument_names = Array::ZoneHandle(Z); - if (named_argument_count > 0) { - argument_names = Array::New(named_argument_count); - for (intptr_t i = 0; i < named_argument_count; i++) { - VariableDeclaration* variable = kernel_function->named_parameters()[i]; - body += LoadLocal(LookupVariable(variable)); - body += PushArgument(); - argument_names.SetAt(i, H.DartSymbol(variable->name())); - } - } - // Forward them to the target. - intptr_t argument_count = positional_argument_count + named_argument_count; - if (!target.is_static()) ++argument_count; - body += StaticCall(TokenPosition::kNoSource, target, argument_count, - argument_names); - - // Return the result. - body += Return(kernel_function->end_position()); - - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); -} - - FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( const Function& function) { // This function is specialized for a receiver class, a method name, and @@ -3500,47 +2349,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher( } -void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) { - intptr_t num_optional_parameters = - parsed_function_->function().NumOptionalParameters(); - if (num_optional_parameters > 0) { - ZoneGrowableArray* default_values = - new ZoneGrowableArray(Z, num_optional_parameters); - - if (parsed_function_->function().HasOptionalNamedParameters()) { - ASSERT(!parsed_function_->function().HasOptionalPositionalParameters()); - for (intptr_t i = 0; i < num_optional_parameters; i++) { - VariableDeclaration* variable = function->named_parameters()[i]; - Instance* default_value; - if (variable->initializer() != NULL) { - default_value = - &constant_evaluator_.EvaluateExpression(variable->initializer()); - } else { - default_value = &Instance::ZoneHandle(Z, Instance::null()); - } - default_values->Add(default_value); - } - } else { - ASSERT(parsed_function_->function().HasOptionalPositionalParameters()); - intptr_t required = function->required_parameter_count(); - for (intptr_t i = 0; i < num_optional_parameters; i++) { - VariableDeclaration* variable = - function->positional_parameters()[required + i]; - Instance* default_value; - if (variable->initializer() != NULL) { - default_value = - &constant_evaluator_.EvaluateExpression(variable->initializer()); - } else { - default_value = &Instance::ZoneHandle(Z, Instance::null()); - } - default_values->Add(default_value); - } - } - parsed_function_->set_default_parameter_values(default_values); - } -} - - TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); @@ -3557,171 +2365,6 @@ JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); } - -Fragment FlowGraphBuilder::TranslateFieldInitializer(NameIndex canonical_name, - Expression* init) { - dart::Field& field = - dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name)); - if (init->IsNullLiteral()) { - field.RecordStore(Object::null_object()); - return Fragment(); - } - Fragment instructions; - instructions += LoadLocal(scopes_->this_variable); - instructions += TranslateExpression(init); - instructions += StoreInstanceFieldGuarded(field, true); - return instructions; -} - - -Fragment FlowGraphBuilder::TranslateInitializers( - Class* kernel_class, - List* initializers) { - Fragment instructions; - - // These come from: - // class A { - // var x = (expr); - // } - for (intptr_t i = 0; i < kernel_class->fields().length(); i++) { - Field* kernel_field = kernel_class->fields()[i]; - Expression* init = kernel_field->initializer(); - if (!kernel_field->IsStatic() && init != NULL) { - EnterScope(kernel_field); - instructions += - TranslateFieldInitializer(kernel_field->canonical_name(), init); - ExitScope(kernel_field); - } - } - - // These to come from: - // class A { - // var x; - // var y; - // A(this.x) : super(expr), y = (expr); - // } - for (intptr_t i = 0; i < initializers->length(); i++) { - Initializer* initializer = (*initializers)[i]; - if (initializer->IsFieldInitializer()) { - FieldInitializer* init = FieldInitializer::Cast(initializer); - instructions += TranslateFieldInitializer(init->field(), init->value()); - } else if (initializer->IsSuperInitializer()) { - SuperInitializer* init = SuperInitializer::Cast(initializer); - - instructions += LoadLocal(scopes_->this_variable); - instructions += PushArgument(); - - ASSERT(init->arguments()->types().length() == 0); - Array& argument_names = Array::ZoneHandle(Z); - instructions += TranslateArguments(init->arguments(), &argument_names); - - const Function& target = Function::ZoneHandle( - Z, H.LookupConstructorByKernelConstructor(init->target())); - intptr_t argument_count = init->arguments()->count() + 1; - instructions += StaticCall(TokenPosition::kNoSource, target, - argument_count, argument_names); - instructions += Drop(); - } else if (initializer->IsRedirectingInitializer()) { - RedirectingInitializer* init = RedirectingInitializer::Cast(initializer); - - instructions += LoadLocal(scopes_->this_variable); - instructions += PushArgument(); - - ASSERT(init->arguments()->types().length() == 0); - Array& argument_names = Array::ZoneHandle(Z); - instructions += TranslateArguments(init->arguments(), &argument_names); - - const Function& target = Function::ZoneHandle( - Z, H.LookupConstructorByKernelConstructor(init->target())); - intptr_t argument_count = init->arguments()->count() + 1; - instructions += StaticCall(TokenPosition::kNoSource, target, - argument_count, argument_names); - instructions += Drop(); - } else if (initializer->IsLocalInitializer()) { - // The other initializers following this one might read the variable. This - // is used e.g. for evaluating the arguments to a super call first, run - // normal field initializers next and then make the actual super call: - // - // The frontend converts - // - // class A { - // var x; - // A(a, b) : super(a + b), x = 2*b {} - // } - // - // to - // - // class A { - // var x; - // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {} - // } - // - // (This is strictly speaking not what one should do in terms of the - // specification but that is how it is currently implemented.) - LocalInitializer* init = LocalInitializer::Cast(initializer); - - VariableDeclaration* declaration = init->variable(); - LocalVariable* variable = LookupVariable(declaration); - Expression* initializer = init->variable()->initializer(); - ASSERT(initializer != NULL); - ASSERT(!declaration->IsConst()); - - instructions += TranslateExpression(initializer); - instructions += StoreLocal(TokenPosition::kNoSource, variable); - instructions += Drop(); - - fragment_ = instructions; - } else { - UNIMPLEMENTED(); - } - } - return instructions; -} - - -Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) { -#ifdef DEBUG - intptr_t original_context_depth = context_depth_; -#endif - - // TODO(jensj): VariableDeclaration doesn't necessarily have a tag. - if (statement->can_stream() && - statement->Type() != Node::kTypeVariableDeclaration) { - fragment_ = streaming_flow_graph_builder_->BuildStatementAt( - statement->kernel_offset()); - } else { - statement->AcceptStatementVisitor(this); - } - DEBUG_ASSERT(context_depth_ == original_context_depth); - return fragment_; -} - - -Fragment FlowGraphBuilder::TranslateCondition(Expression* expression, - bool* negate) { - *negate = expression->IsNot(); - Fragment instructions; - if (*negate) { - instructions += TranslateExpression(Not::Cast(expression)->expression()); - } else { - instructions += TranslateExpression(expression); - } - instructions += CheckBooleanInCheckedMode(); - return instructions; -} - - -Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) { - if (expression->can_stream()) { - fragment_ = streaming_flow_graph_builder_->BuildExpressionAt( - expression->kernel_offset()); - } else { - expression->AcceptExpressionVisitor(this); - } - return fragment_; -} - - ArgumentArray FlowGraphBuilder::GetArguments(int count) { ArgumentArray arguments = new (Z) ZoneGrowableArray(Z, count); @@ -3746,54 +2389,6 @@ ArgumentArray FlowGraphBuilder::GetArguments(int count) { } -void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - AbstractType& DartTypeTranslator::TranslateType(DartType* node) { node->AcceptDartTypeVisitor(this); @@ -4093,1923 +2688,11 @@ const Type& DartTypeTranslator::ReceiverType(const dart::Class& klass) { return type; } -void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - const AbstractType& type = T.TranslateType(node->type()); - if (type.IsMalformed()) H.ReportError("Malformed type literal"); - - Fragment instructions; - if (type.IsInstantiated()) { - instructions += Constant(type); - } else { - if (!type.IsInstantiated(kCurrentClass)) { - instructions += LoadInstantiatorTypeArguments(); - } else { - instructions += NullConstant(); - } - if (!type.IsInstantiated(kFunctions)) { - instructions += LoadFunctionTypeArguments(); - } else { - instructions += NullConstant(); - } - instructions += InstantiateType(type); - } - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitVariableGet(VariableGet* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitVariableSet(VariableSet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->expression()); - if (NeedsDebugStepCheck(stack_, node->position())) { - instructions = DebugStepCheck(node->position()) + instructions; - } - instructions += CheckVariableTypeInCheckedMode(node->variable()); - instructions += - StoreLocal(node->position(), LookupVariable(node->variable())); - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitStaticGet(StaticGet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - // A StaticGet will always have a kernel_offset, except for the StaticGet that - // was manually created for _getMainClosure in dart:_builtin. Compile that - // one specially here. - const dart::Library& builtin = - dart::Library::Handle(Z, I->object_store()->builtin_library()); - const Object& main = - Object::Handle(Z, builtin.LookupObjectAllowPrivate(dart::String::Handle( - Z, dart::String::New("main")))); - if (main.IsField()) { - UNIMPLEMENTED(); - } else if (main.IsFunction()) { - const Function& function = Function::Cast(main); - if (function.kind() == RawFunction::kRegularFunction) { - const Function& closure_function = - Function::Handle(Z, function.ImplicitClosureFunction()); - closure_function.set_kernel_function(function.kernel_function()); - const Instance& closure = - Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure()); - fragment_ = Constant(closure); - } else { - UNIMPLEMENTED(); - } - } else { - UNIMPLEMENTED(); - } -} - - -void FlowGraphBuilder::VisitStaticSet(StaticSet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - NameIndex target = node->target(); - if (H.IsField(target)) { - const dart::Field& field = - dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target)); - const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type()); - Fragment instructions = TranslateExpression(node->expression()); - if (NeedsDebugStepCheck(stack_, node->position())) { - instructions = DebugStepCheck(node->position()) + instructions; - } - instructions += CheckAssignableInCheckedMode( - dst_type, dart::String::ZoneHandle(Z, field.name())); - LocalVariable* variable = MakeTemporary(); - instructions += LoadLocal(variable); - fragment_ = instructions + StoreStaticField(node->position(), field); - } else { - ASSERT(H.IsProcedure(target)); - - // Evaluate the expression on the right hand side. - Fragment instructions = TranslateExpression(node->expression()); - LocalVariable* variable = MakeTemporary(); - - // Prepare argument. - instructions += LoadLocal(variable); - instructions += PushArgument(); - - // Invoke the setter function. - const Function& function = - Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); - instructions += StaticCall(node->position(), function, 1); - - // Drop the unused result & leave the stored value on the stack. - fragment_ = instructions + Drop(); - } -} - - -void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->receiver()); - instructions += PushArgument(); - const dart::String& getter_name = H.DartGetterName(node->name()); - fragment_ = instructions + - InstanceCall(node->position(), getter_name, Token::kGET, 1); -} - - -void FlowGraphBuilder::VisitPropertySet(PropertySet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions(NullConstant()); - LocalVariable* variable = MakeTemporary(); - instructions += TranslateExpression(node->receiver()); - instructions += PushArgument(); - instructions += TranslateExpression(node->value()); - instructions += StoreLocal(TokenPosition::kNoSource, variable); - instructions += PushArgument(); - - const dart::String& setter_name = H.DartSetterName(node->name()); - instructions += InstanceCall(node->position(), setter_name, Token::kSET, 2); - fragment_ = instructions + Drop(); -} - - -void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Function& target = Function::ZoneHandle(Z); - NameIndex kernel_name = node->target(); - if (H.IsProcedure(kernel_name)) { - if (H.IsGetter(kernel_name)) { - target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name)); - } else { - target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name)); - target = target.ImplicitClosureFunction(); - ASSERT(!target.IsNull()); - fragment_ = BuildImplicitClosureCreation(target); - return; - } - } else { - ASSERT(H.IsField(kernel_name)); - const dart::String& getter_name = H.DartGetterName(kernel_name); - target = LookupMethodByMember(kernel_name, getter_name); - ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction()); - } - - Fragment instructions = TranslateExpression(node->receiver()); - instructions += PushArgument(); - fragment_ = instructions + StaticCall(node->position(), target, 1); -} - - -void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - const dart::String& method_name = H.DartSetterName(node->target()); - const Function& target = Function::ZoneHandle( - Z, LookupMethodByMember(node->target(), method_name)); - ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction()); - - Fragment instructions(NullConstant()); - LocalVariable* value = MakeTemporary(); - instructions += TranslateExpression(node->receiver()); - instructions += PushArgument(); - instructions += TranslateExpression(node->value()); - instructions += StoreLocal(TokenPosition::kNoSource, value); - instructions += PushArgument(); - instructions += StaticCall(node->position(), target, 2); - - fragment_ = instructions + Drop(); -} - - -void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - const Function& target = Function::ZoneHandle( - Z, H.LookupStaticMethodByKernelProcedure(node->procedure())); - const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner()); - intptr_t argument_count = node->arguments()->count(); - if (target.IsGenerativeConstructor() || target.IsFactory()) { - // The VM requires a TypeArguments object as first parameter for - // every factory constructor. - ++argument_count; - } - - List& named = node->arguments()->named(); - const Array& argument_names = H.ArgumentNames(&named); - - // The frontend ensures we the [StaticInvocation] has matching arguments. - const intptr_t kTypeArgsLen = 0; // Generic functions not yet supported. - ASSERT(target.AreValidArguments(kTypeArgsLen, argument_count, argument_names, - NULL)); - - Fragment instructions; - LocalVariable* instance_variable = NULL; - - // If we cross the Kernel -> VM core library boundary, a [StaticInvocation] - // can appear, but the thing we're calling is not a static method, but a - // factory constructor. - // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the - // forwarded constructor. - // In that case we'll make an instance and pass it as first argument. - // - // TODO(27590): Get rid of this after we're using core libraries compiled - // into Kernel. - if (target.IsGenerativeConstructor()) { - if (klass.NumTypeArguments() > 0) { - List& kernel_type_arguments = node->arguments()->types(); - const TypeArguments& type_arguments = - T.TranslateInstantiatedTypeArguments( - klass, kernel_type_arguments.raw_array(), - kernel_type_arguments.length()); - instructions += TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); - instructions += AllocateObject(klass, 1); - } else { - instructions += AllocateObject(klass, 0); - } - - instance_variable = MakeTemporary(); - - instructions += LoadLocal(instance_variable); - instructions += PushArgument(); - } else if (target.IsFactory()) { - // The VM requires currently a TypeArguments object as first parameter for - // every factory constructor :-/ ! - // - // TODO(27590): Get rid of this after we're using core libraries compiled - // into Kernel. - List& kernel_type_arguments = node->arguments()->types(); - - const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments( - klass, kernel_type_arguments.raw_array(), - kernel_type_arguments.length()); - - instructions += TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); - } else { - // TODO(28109) Support generic methods in the VM or reify them away. - } - - // Special case identical(x, y) call. - // TODO(27590) consider moving this into the inliner and force inline it - // there. - if (klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) && - (target.name() == Symbols::Identical().raw())) { - ASSERT(argument_count == 2); - - List& positional = node->arguments()->positional(); - for (intptr_t i = 0; i < positional.length(); ++i) { - instructions += TranslateExpression(positional[i]); - } - instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true); - } else { - instructions += TranslateArguments(node->arguments(), NULL); - instructions += - StaticCall(node->position(), target, argument_count, argument_names); - - if (target.IsGenerativeConstructor()) { - // Drop the result of the constructor call and leave [instance_variable] - // on top-of-stack. - instructions += Drop(); - } - } - - fragment_ = instructions; -} - - -static bool IsNumberLiteral(Node* node) { - return node->IsIntLiteral() || node->IsDoubleLiteral(); -} - -template -bool FlowGraphBuilder::RecognizeComparisonWithNull(Token::Kind token_kind, - Invocation* node) { - if (token_kind == Token::kEQ || token_kind == Token::kNE) { - if (node->arguments()->positional().length() != 1) return false; - Fragment instructions; - Expression* left = node->receiver(); - Expression* right = node->arguments()->positional()[0]; - if (left->IsNullLiteral() || right->IsNullLiteral()) { - instructions += TranslateExpression(left); - instructions += TranslateExpression(right); - Token::Kind strict_cmp_kind = - token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT; - fragment_ = instructions + StrictCompare(strict_cmp_kind, - /*number_check = */ true); - return true; - } - } - return false; -} - - -void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - const dart::String& name = H.DartMethodName(node->name()); - const intptr_t argument_count = node->arguments()->count() + 1; - const Token::Kind token_kind = MethodKind(name); - if (IsNumberLiteral(node->receiver())) { - if ((argument_count == 1) && (token_kind == Token::kNEGATE)) { - const Object& result = constant_evaluator_.EvaluateExpressionSafe(node); - if (!result.IsError()) { - fragment_ = Constant(result); - return; - } - } else if ((argument_count == 2) && - Token::IsBinaryArithmeticOperator(token_kind) && - IsNumberLiteral(node->arguments()->positional()[0])) { - const Object& result = constant_evaluator_.EvaluateExpressionSafe(node); - if (!result.IsError()) { - fragment_ = Constant(result); - return; - } - } - } - - if (RecognizeComparisonWithNull(token_kind, node)) return; - - Fragment instructions = TranslateExpression(node->receiver()); - instructions += PushArgument(); - - // TODO(28109) Support generic methods in the VM or reify them away. - Array& argument_names = Array::ZoneHandle(Z); - instructions += TranslateArguments(node->arguments(), &argument_names); - - intptr_t num_args_checked = 1; - // If we have a special operation (e.g. +/-/==) we mark both arguments as - // to be checked. - if (token_kind != Token::kILLEGAL) { - ASSERT(argument_count <= 2); - num_args_checked = argument_count; - } - - fragment_ = instructions + InstanceCall(node->position(), name, token_kind, - argument_count, argument_names, - num_args_checked); - // Later optimization passes assume that result of a x.[]=(...) call is not - // used. We must guarantee this invariant because violation will lead to an - // illegal IL once we replace x.[]=(...) with a sequence that does not - // actually produce any value. See http://dartbug.com/29135 for more details. - if (name.raw() == Symbols::AssignIndexToken().raw()) { - fragment_ += Drop(); - fragment_ += NullConstant(); - } -} - - -void FlowGraphBuilder::VisitDirectMethodInvocation( - DirectMethodInvocation* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - const dart::String& method_name = H.DartProcedureName(node->target()); - const Token::Kind token_kind = MethodKind(method_name); - - if (RecognizeComparisonWithNull(token_kind, node)) return; - - const Function& target = Function::ZoneHandle( - Z, LookupMethodByMember(node->target(), method_name)); - - intptr_t argument_count = node->arguments()->count() + 1; - Array& argument_names = Array::ZoneHandle(Z); - - // TODO(28109) Support generic methods in the VM or reify them away. - Fragment instructions = TranslateExpression(node->receiver()); - instructions += PushArgument(); - instructions += TranslateArguments(node->arguments(), &argument_names); - fragment_ = instructions + StaticCall(node->position(), target, - argument_count, argument_names); -} - - -void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - if (node->is_const()) { - fragment_ = - Constant(constant_evaluator_.EvaluateConstructorInvocation(node)); - return; - } - - dart::Class& klass = dart::Class::ZoneHandle( - Z, H.LookupClassByKernelClass(H.EnclosingName(node->target()))); - - Fragment instructions; - - // Check for malbounded-ness of type. - if (I->type_checks()) { - List& kernel_type_arguments = node->arguments()->types(); - const TypeArguments& type_arguments = T.TranslateTypeArguments( - kernel_type_arguments.raw_array(), kernel_type_arguments.length()); - - AbstractType& type = AbstractType::Handle( - Z, Type::New(klass, type_arguments, TokenPosition::kNoSource)); - type = ClassFinalizer::FinalizeType(klass, type); - - if (type.IsMalbounded()) { - // Evaluate expressions for correctness. - List& positional = node->arguments()->positional(); - List& named = node->arguments()->named(); - for (intptr_t i = 0; i < positional.length(); ++i) { - instructions += TranslateExpression(positional[i]); - instructions += Drop(); - } - for (intptr_t i = 0; i < named.length(); ++i) { - instructions += TranslateExpression(named[i]->expression()); - instructions += Drop(); - } - - // Throw an error & keep the [Value] on the stack. - instructions += ThrowTypeError(); - - // Bail out early. - fragment_ = instructions; - return; - } - } - - if (klass.NumTypeArguments() > 0) { - List& kernel_type_arguments = node->arguments()->types(); - const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments( - klass, kernel_type_arguments.raw_array(), - kernel_type_arguments.length()); - if (!klass.IsGeneric()) { - Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw()); - - // TODO(27590): Can we move this code into [ReceiverType]? - type ^= ClassFinalizer::FinalizeType(*active_class_.klass, type, - ClassFinalizer::kFinalize); - ASSERT(!type.IsMalformedOrMalbounded()); - - TypeArguments& canonicalized_type_arguments = - TypeArguments::ZoneHandle(Z, type.arguments()); - canonicalized_type_arguments = - canonicalized_type_arguments.Canonicalize(); - instructions += Constant(canonicalized_type_arguments); - } else { - instructions += TranslateInstantiatedTypeArguments(type_arguments); - } - - instructions += PushArgument(); - instructions += AllocateObject(klass, 1); - } else { - instructions += AllocateObject(klass, 0); - } - LocalVariable* variable = MakeTemporary(); - - instructions += LoadLocal(variable); - instructions += PushArgument(); - - Array& argument_names = Array::ZoneHandle(Z); - instructions += TranslateArguments(node->arguments(), &argument_names); - - const Function& target = Function::ZoneHandle( - Z, H.LookupConstructorByKernelConstructor(klass, node->target())); - intptr_t argument_count = node->arguments()->count() + 1; - instructions += - StaticCall(node->position(), target, argument_count, argument_names); - fragment_ = instructions + Drop(); -} - - -void FlowGraphBuilder::VisitIsExpression(IsExpression* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->operand()); - - // The VM does not like an instanceOf call with a dynamic type. We need to - // special case this situation. - const Type& object_type = Type::Handle(Z, Type::ObjectType()); - const AbstractType& type = T.TranslateType(node->type()); - if (type.IsMalformed()) { - instructions += Drop(); - instructions += ThrowTypeError(); - fragment_ = instructions; - return; - } - - if (type.IsInstantiated() && - object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { - // Evaluate the expression on the left but ignore it's result. - instructions += Drop(); - - // Let condition be always true. - instructions += Constant(Bool::True()); - } else { - instructions += PushArgument(); - - // See if simple instanceOf is applicable. - if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) { - instructions += Constant(type); - instructions += PushArgument(); // Type. - instructions += InstanceCall( - node->position(), - dart::Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()), - Token::kIS, 2, 2); // 2 checked arguments. - fragment_ = instructions; - return; - } - - if (!type.IsInstantiated(kCurrentClass)) { - instructions += LoadInstantiatorTypeArguments(); - } else { - instructions += NullConstant(); - } - instructions += PushArgument(); // Instantiator type arguments. - - if (!type.IsInstantiated(kFunctions)) { - instructions += LoadFunctionTypeArguments(); - } else { - instructions += NullConstant(); - } - instructions += PushArgument(); // Function type arguments. - - instructions += Constant(type); - instructions += PushArgument(); // Type. - - instructions += - InstanceCall(node->position(), - dart::Library::PrivateCoreLibName(Symbols::_instanceOf()), - Token::kIS, 4); - } - - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitAsExpression(AsExpression* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->operand()); - - // The VM does not like an Object_as call with a dynamic type. We need to - // special case this situation. - const Type& object_type = Type::Handle(Z, Type::ObjectType()); - const AbstractType& type = T.TranslateType(node->type()); - if (type.IsMalformed()) { - instructions += Drop(); - instructions += ThrowTypeError(); - fragment_ = instructions; - return; - } - - if (type.IsInstantiated() && - object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { - // We already evaluated the operand on the left and just leave it there as - // the result of the `obj as dynamic` expression. - } else { - instructions += PushArgument(); - - if (!type.IsInstantiated(kCurrentClass)) { - instructions += LoadInstantiatorTypeArguments(); - } else { - instructions += NullConstant(); - } - instructions += PushArgument(); // Instantiator type arguments. - - if (!type.IsInstantiated(kFunctions)) { - instructions += LoadFunctionTypeArguments(); - } else { - instructions += NullConstant(); - } - instructions += PushArgument(); // Function type arguments. - - instructions += Constant(type); - instructions += PushArgument(); // Type. - - instructions += InstanceCall( - node->position(), dart::Library::PrivateCoreLibName(Symbols::_as()), - Token::kAS, 4); - } - - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - bool negate; - Fragment instructions = TranslateCondition(node->condition(), &negate); - - TargetEntryInstr* then_entry; - TargetEntryInstr* otherwise_entry; - instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); - - Value* top = stack_; - Fragment then_fragment(then_entry); - then_fragment += TranslateExpression(node->then()); - then_fragment += StoreLocal(TokenPosition::kNoSource, - parsed_function_->expression_temp_var()); - then_fragment += Drop(); - ASSERT(stack_ == top); - - Fragment otherwise_fragment(otherwise_entry); - otherwise_fragment += TranslateExpression(node->otherwise()); - otherwise_fragment += StoreLocal(TokenPosition::kNoSource, - parsed_function_->expression_temp_var()); - otherwise_fragment += Drop(); - ASSERT(stack_ == top); - - JoinEntryInstr* join = BuildJoinEntry(); - then_fragment += Goto(join); - otherwise_fragment += Goto(join); - - fragment_ = Fragment(instructions.entry, join) + - LoadLocal(parsed_function_->expression_temp_var()); -} - - -void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - bool negate; - Fragment instructions = TranslateCondition(node->left(), &negate); - TargetEntryInstr* right_entry; - TargetEntryInstr* constant_entry; - - if (node->op() == LogicalExpression::kAnd) { - instructions += BranchIfTrue(&right_entry, &constant_entry, negate); - } else { - instructions += BranchIfTrue(&constant_entry, &right_entry, negate); - } - - Value* top = stack_; - Fragment right_fragment(right_entry); - right_fragment += TranslateCondition(node->right(), &negate); - right_fragment += Constant(Bool::True()); - right_fragment += - StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT); - right_fragment += StoreLocal(TokenPosition::kNoSource, - parsed_function_->expression_temp_var()); - right_fragment += Drop(); - - ASSERT(top == stack_); - Fragment constant_fragment(constant_entry); - constant_fragment += - Constant(Bool::Get(node->op() == LogicalExpression::kOr)); - constant_fragment += StoreLocal(TokenPosition::kNoSource, - parsed_function_->expression_temp_var()); - constant_fragment += Drop(); - - JoinEntryInstr* join = BuildJoinEntry(); - right_fragment += Goto(join); - constant_fragment += Goto(join); - - fragment_ = Fragment(instructions.entry, join) + - LoadLocal(parsed_function_->expression_temp_var()); -} - - -void FlowGraphBuilder::VisitNot(Not* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->expression()); - instructions += CheckBooleanInCheckedMode(); - instructions += BooleanNegate(); - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - List& expressions = node->expressions(); - - Fragment instructions; - - if (node->expressions().length() == 1) { - instructions += TranslateExpression(node->expressions()[0]); - instructions += StringInterpolateSingle(node->position()); - } else { - // The type arguments for CreateArray. - instructions += Constant(TypeArguments::ZoneHandle(Z)); - instructions += IntConstant(expressions.length()); - instructions += CreateArray(); - LocalVariable* array = MakeTemporary(); - - for (intptr_t i = 0; i < node->expressions().length(); i++) { - instructions += LoadLocal(array); - instructions += IntConstant(i); - instructions += TranslateExpression(node->expressions()[i]); - instructions += StoreIndexed(kArrayCid); - instructions += Drop(); - } - - instructions += StringInterpolate(node->position()); - } - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - if (node->is_const()) { - fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node)); - return; - } - - DartType* types[] = {node->type()}; - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1); - - // The type argument for the factory call. - Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); - List& expressions = node->expressions(); - if (expressions.length() == 0) { - instructions += Constant(Object::empty_array()); - } else { - // The type arguments for CreateArray. - instructions += Constant(TypeArguments::ZoneHandle(Z)); - instructions += IntConstant(expressions.length()); - instructions += CreateArray(); - - LocalVariable* array = MakeTemporary(); - for (intptr_t i = 0; i < expressions.length(); ++i) { - instructions += LoadLocal(array); - instructions += IntConstant(i); - instructions += TranslateExpression(expressions[i]); - instructions += StoreIndexed(kArrayCid); - instructions += Drop(); - } - } - instructions += PushArgument(); // The array. - - const dart::Class& factory_class = - dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List())); - const Function& factory_method = Function::ZoneHandle( - Z, factory_class.LookupFactory( - dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); - fragment_ = instructions + StaticCall(node->position(), factory_method, 2); -} - - -void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - if (node->is_const()) { - fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node)); - return; - } - - const dart::Class& map_class = - dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map())); - const Function& factory_method = Function::ZoneHandle( - Z, map_class.LookupFactory( - dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory()))); - - DartType* types[] = {node->key_type(), node->value_type()}; - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2); - - // The type argument for the factory call `new Map._fromLiteral(List)`. - Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); - - List& entries = node->entries(); - if (entries.length() == 0) { - instructions += Constant(Object::empty_array()); - } else { - // The type arguments for `new List(int len)`. - instructions += Constant(TypeArguments::ZoneHandle(Z)); - - // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN]. - instructions += IntConstant(2 * entries.length()); - instructions += CreateArray(); - - LocalVariable* array = MakeTemporary(); - for (intptr_t i = 0; i < entries.length(); ++i) { - instructions += LoadLocal(array); - instructions += IntConstant(2 * i); - instructions += TranslateExpression(entries[i]->key()); - instructions += StoreIndexed(kArrayCid); - instructions += Drop(); - - instructions += LoadLocal(array); - instructions += IntConstant(2 * i + 1); - instructions += TranslateExpression(entries[i]->value()); - instructions += StoreIndexed(kArrayCid); - instructions += Drop(); - } - } - instructions += PushArgument(); // The array. - - fragment_ = instructions + StaticCall(node->position(), factory_method, 2); -} - - -void FlowGraphBuilder::VisitFunctionExpression(FunctionExpression* node) { - fragment_ = TranslateFunctionNode(node->function(), node); -} - - -void FlowGraphBuilder::VisitLet(Let* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions = TranslateStatement(node->variable()); - instructions += TranslateExpression(node->body()); - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitThrow(Throw* node) { - STREAM_EXPRESSION_IF_POSSIBLE(node); - - Fragment instructions; - - instructions += TranslateExpression(node->expression()); - if (NeedsDebugStepCheck(stack_, node->position())) { - instructions = DebugStepCheck(node->position()) + instructions; - } - instructions += PushArgument(); - instructions += ThrowException(node->position()); - ASSERT(instructions.is_closed()); - - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitRethrow(Rethrow* node) { - fragment_ = - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); -} - - -Fragment FlowGraphBuilder::TranslateArguments(Arguments* node, - Array* argument_names) { - Fragment instructions; - - List& positional = node->positional(); - for (intptr_t i = 0; i < positional.length(); ++i) { - instructions += TranslateExpression(positional[i]); - instructions += PushArgument(); - } - - List& named = node->named(); - if (argument_names != NULL) { - *argument_names = H.ArgumentNames(&named).raw(); - } - for (intptr_t i = 0; i < named.length(); ++i) { - NamedExpression* named_expression = named[i]; - instructions += TranslateExpression(named_expression->expression()); - instructions += PushArgument(); - } - return instructions; -} - -#define STREAM_STATEMENT_IF_POSSIBLE(node) \ - if (node->can_stream()) { \ - fragment_ = streaming_flow_graph_builder_->BuildStatementAt( \ - node->kernel_offset()); \ - return; \ - } - - -void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) { - fragment_ = - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) { - fragment_ = - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitBlock(Block* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - Fragment instructions; - - instructions += EnterScope(node); - List& statements = node->statements(); - for (intptr_t i = 0; (i < statements.length()) && instructions.is_open(); - ++i) { - instructions += TranslateStatement(statements[i]); - } - instructions += ExitScope(node); - - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - bool inside_try_finally = try_finally_block_ != NULL; - - Fragment instructions = node->expression() == NULL - ? NullConstant() - : TranslateExpression(node->expression()); - if (instructions.is_open()) { - if (inside_try_finally) { - ASSERT(scopes_->finally_return_variable != NULL); - const Function& function = parsed_function_->function(); - if (NeedsDebugStepCheck(function, node->position())) { - instructions += DebugStepCheck(node->position()); - } - instructions += - StoreLocal(node->position(), scopes_->finally_return_variable); - instructions += Drop(); - instructions += TranslateFinallyFinalizers(NULL, -1); - if (instructions.is_open()) { - instructions += LoadLocal(scopes_->finally_return_variable); - instructions += Return(TokenPosition::kNoSource); - } - } else { - instructions += Return(node->position()); - } - } else { - Pop(); - } - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->expression()); - instructions += Drop(); - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) { - LocalVariable* variable = LookupVariable(node); - Expression* initializer = node->initializer(); - - Fragment instructions; - if (initializer == NULL) { - instructions += NullConstant(); - } else { - if (node->IsConst()) { - const Instance& constant_value = - constant_evaluator_.EvaluateExpression(initializer); - variable->SetConstValue(constant_value); - instructions += Constant(constant_value); - } else { - instructions += TranslateExpression(initializer); - instructions += CheckVariableTypeInCheckedMode(node); - } - } - // Use position of equal sign if it exists. If the equal sign does not exist - // use the position of the identifier. - TokenPosition debug_position = - Utils::Maximum(node->position(), node->equals_position()); - if (NeedsDebugStepCheck(stack_, debug_position)) { - instructions = DebugStepCheck(debug_position) + instructions; - } - instructions += StoreLocal(node->position(), variable); - instructions += Drop(); - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) { - Fragment instructions = DebugStepCheck(node->position()); - instructions += TranslateFunctionNode(node->function(), node); - instructions += - StoreLocal(node->position(), LookupVariable(node->variable())); - instructions += Drop(); - fragment_ = instructions; -} - - -void FlowGraphBuilder::VisitIfStatement(IfStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - bool negate; - Fragment instructions = TranslateCondition(node->condition(), &negate); - TargetEntryInstr* then_entry; - TargetEntryInstr* otherwise_entry; - instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); - - Fragment then_fragment(then_entry); - then_fragment += TranslateStatement(node->then()); - - Fragment otherwise_fragment(otherwise_entry); - otherwise_fragment += TranslateStatement(node->otherwise()); - - if (then_fragment.is_open()) { - if (otherwise_fragment.is_open()) { - JoinEntryInstr* join = BuildJoinEntry(); - then_fragment += Goto(join); - otherwise_fragment += Goto(join); - fragment_ = Fragment(instructions.entry, join); - } else { - fragment_ = Fragment(instructions.entry, then_fragment.current); - } - } else if (otherwise_fragment.is_open()) { - fragment_ = Fragment(instructions.entry, otherwise_fragment.current); - } else { - fragment_ = instructions.closed(); - } -} - - -void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - ++loop_depth_; - bool negate; - Fragment condition = TranslateCondition(node->condition(), &negate); - TargetEntryInstr* body_entry; - TargetEntryInstr* loop_exit; - condition += BranchIfTrue(&body_entry, &loop_exit, negate); - - Fragment body(body_entry); - body += TranslateStatement(node->body()); - - Instruction* entry; - if (body.is_open()) { - JoinEntryInstr* join = BuildJoinEntry(); - body += Goto(join); - - Fragment loop(join); - loop += CheckStackOverflow(); - loop += condition; - entry = new (Z) GotoInstr(join, GetNextDeoptId()); - } else { - entry = condition.entry; - } - - - fragment_ = Fragment(entry, loop_exit); - --loop_depth_; -} - - -void FlowGraphBuilder::VisitDoStatement(DoStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - ++loop_depth_; - Fragment body = TranslateStatement(node->body()); - - if (body.is_closed()) { - fragment_ = body; - --loop_depth_; - return; - } - - bool negate; - JoinEntryInstr* join = BuildJoinEntry(); - Fragment loop(join); - loop += CheckStackOverflow(); - loop += body; - loop += TranslateCondition(node->condition(), &negate); - TargetEntryInstr* loop_repeat; - TargetEntryInstr* loop_exit; - loop += BranchIfTrue(&loop_repeat, &loop_exit, negate); - - Fragment repeat(loop_repeat); - repeat += Goto(join); - - fragment_ = Fragment(new (Z) GotoInstr(join, GetNextDeoptId()), loop_exit); - --loop_depth_; -} - - -void FlowGraphBuilder::VisitForStatement(ForStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - Fragment declarations; - - bool new_context = false; - declarations += EnterScope(node, &new_context); - - List& variables = node->variables(); - for (intptr_t i = 0; i < variables.length(); ++i) { - declarations += TranslateStatement(variables[i]); - } - - ++loop_depth_; - bool negate = false; - Fragment condition = node->condition() == NULL - ? Constant(Bool::True()) - : TranslateCondition(node->condition(), &negate); - TargetEntryInstr* body_entry; - TargetEntryInstr* loop_exit; - condition += BranchIfTrue(&body_entry, &loop_exit, negate); - - Fragment body(body_entry); - body += TranslateStatement(node->body()); - - if (body.is_open()) { - // We allocated a fresh context before the loop which contains captured - // [ForStatement] variables. Before jumping back to the loop entry we clone - // the context object (at same depth) which ensures the next iteration of - // the body gets a fresh set of [ForStatement] variables (with the old - // (possibly updated) values). - if (new_context) body += CloneContext(); - - List& updates = node->updates(); - for (intptr_t i = 0; i < updates.length(); ++i) { - body += TranslateExpression(updates[i]); - body += Drop(); - } - JoinEntryInstr* join = BuildJoinEntry(); - declarations += Goto(join); - body += Goto(join); - - Fragment loop(join); - loop += CheckStackOverflow(); - loop += condition; - } else { - declarations += condition; - } - - Fragment loop(declarations.entry, loop_exit); - --loop_depth_; - - loop += ExitScope(node); - - fragment_ = loop; -} - - -void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - Fragment instructions = TranslateExpression(node->iterable()); - instructions += PushArgument(); - - const dart::String& iterator_getter = dart::String::ZoneHandle( - Z, dart::Field::GetterSymbol(Symbols::Iterator())); - instructions += InstanceCall(node->iterable()->position(), iterator_getter, - Token::kGET, 1); - LocalVariable* iterator = scopes_->iterator_variables[for_in_depth_]; - instructions += StoreLocal(TokenPosition::kNoSource, iterator); - instructions += Drop(); - - ++for_in_depth_; - ++loop_depth_; - Fragment condition = LoadLocal(iterator); - condition += PushArgument(); - condition += InstanceCall(node->iterable()->position(), Symbols::MoveNext(), - Token::kILLEGAL, 1); - TargetEntryInstr* body_entry; - TargetEntryInstr* loop_exit; - condition += BranchIfTrue(&body_entry, &loop_exit); - - Fragment body(body_entry); - body += EnterScope(node); - body += LoadLocal(iterator); - body += PushArgument(); - const dart::String& current_getter = dart::String::ZoneHandle( - Z, dart::Field::GetterSymbol(Symbols::Current())); - body += InstanceCall(node->position(), current_getter, Token::kGET, 1); - body += - StoreLocal(TokenPosition::kNoSource, LookupVariable(node->variable())); - body += Drop(); - body += TranslateStatement(node->body()); - body += ExitScope(node); - - if (body.is_open()) { - JoinEntryInstr* join = BuildJoinEntry(); - instructions += Goto(join); - body += Goto(join); - - Fragment loop(join); - loop += CheckStackOverflow(); - loop += condition; - } else { - instructions += condition; - } - - fragment_ = Fragment(instructions.entry, loop_exit); - --loop_depth_; - --for_in_depth_; -} - - -void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - // There can be serveral cases: - // - // * the body contains a break - // * the body doesn't contain a break - // - // * translating the body results in a closed fragment - // * translating the body results in a open fragment - // - // => We will only know which case we are in after the body has been - // traversed. - - BreakableBlock block(this); - Fragment instructions = TranslateStatement(node->body()); - if (block.HadJumper()) { - if (instructions.is_open()) { - instructions += Goto(block.destination()); - } - fragment_ = Fragment(instructions.entry, block.destination()); - } else { - fragment_ = instructions; - } -} - - -void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) { - fragment_ = - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - SwitchBlock block(this, node->cases().length()); - - // Instead of using a variable we should reuse the expression on the stack, - // since it won't be assigned again, we don't need phi nodes. - Fragment head_instructions = TranslateExpression(node->condition()); - head_instructions += - StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable); - head_instructions += Drop(); - - // Phase 1: Generate bodies and try to find out whether a body will be target - // of a jump due to: - // * `continue case_label` - // * `case e1: case e2: body` - Fragment* body_fragments = new Fragment[node->cases().length()]; - - intptr_t num_cases = node->cases().length(); - for (intptr_t i = 0; i < num_cases; i++) { - SwitchCase* switch_case = node->cases()[i]; - Fragment& body_fragment = body_fragments[i] = - TranslateStatement(switch_case->body()); - - if (body_fragment.entry == NULL) { - // Make a NOP in order to ensure linking works properly. - body_fragment = NullConstant(); - body_fragment += Drop(); - } - - // The Dart language specification mandates fall-throughs in [SwitchCase]es - // to be runtime errors. - if (!switch_case->is_default() && body_fragment.is_open() && - (i < (node->cases().length() - 1))) { - const dart::Class& klass = dart::Class::ZoneHandle( - Z, dart::Library::LookupCoreClass(Symbols::FallThroughError())); - ASSERT(!klass.IsNull()); - const Function& constructor = Function::ZoneHandle( - Z, klass.LookupConstructorAllowPrivate( - H.DartSymbol("FallThroughError._create"))); - ASSERT(!constructor.IsNull()); - const dart::String& url = H.DartString( - parsed_function_->function().ToLibNamePrefixedQualifiedCString(), - Heap::kOld); - - // Create instance of _FallThroughError - body_fragment += AllocateObject(klass, 0); - LocalVariable* instance = MakeTemporary(); - - // Call _FallThroughError._create constructor. - body_fragment += LoadLocal(instance); - body_fragment += PushArgument(); // this - - body_fragment += Constant(url); - body_fragment += PushArgument(); // url - - body_fragment += NullConstant(); - body_fragment += PushArgument(); // line - - body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3); - body_fragment += Drop(); - - // Throw the exception - body_fragment += PushArgument(); - body_fragment += ThrowException(TokenPosition::kNoSource); - body_fragment += Drop(); - } - - // If there is an implicit fall-through we have one [SwitchCase] and - // multiple expressions, e.g. - // - // switch(expr) { - // case a: - // case b: - // - // } - // - // This means that the will have more than 1 incoming edge (one - // from `a == expr` and one from `a != expr && b == expr`). The - // `block.Destination()` records the additional jump. - if (switch_case->expressions().length() > 1) { - block.DestinationDirect(i); - } - } - - // Phase 2: Generate everything except the real bodies: - // * jump directly to a body (if there is no jumper) - // * jump to a wrapper block which jumps to the body (if there is a jumper) - Fragment current_instructions = head_instructions; - for (intptr_t i = 0; i < num_cases; i++) { - SwitchCase* switch_case = node->cases()[i]; - - if (switch_case->is_default()) { - ASSERT(i == (node->cases().length() - 1)); - - // Evaluate the conditions for the default [SwitchCase] just for the - // purpose of potentially triggering a compile-time error. - for (intptr_t k = 0; k < switch_case->expressions().length(); k++) { - constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]); - } - - if (block.HadJumper(i)) { - // There are several branches to the body, so we will make a goto to - // the join block (and prepend a join instruction to the real body). - JoinEntryInstr* join = block.DestinationDirect(i); - current_instructions += Goto(join); - - current_instructions = Fragment(current_instructions.entry, join); - current_instructions += body_fragments[i]; - } else { - current_instructions += body_fragments[i]; - } - } else { - JoinEntryInstr* body_join = NULL; - if (block.HadJumper(i)) { - body_join = block.DestinationDirect(i); - body_fragments[i] = Fragment(body_join) + body_fragments[i]; - } - - for (intptr_t j = 0; j < switch_case->expressions().length(); j++) { - TargetEntryInstr* then; - TargetEntryInstr* otherwise; - - Expression* expression = switch_case->expressions()[j]; - current_instructions += - Constant(constant_evaluator_.EvaluateExpression(expression)); - current_instructions += PushArgument(); - current_instructions += LoadLocal(scopes_->switch_variable); - current_instructions += PushArgument(); - current_instructions += InstanceCall( - expression->position(), Symbols::EqualOperator(), Token::kEQ, - /*argument_count=*/2, - /*num_args_checked=*/2); - current_instructions += BranchIfTrue(&then, &otherwise); - - Fragment then_fragment(then); - - if (body_join != NULL) { - // There are several branches to the body, so we will make a goto to - // the join block (the real body has already been prepended with a - // join instruction). - then_fragment += Goto(body_join); - } else { - // There is only a signle branch to the body, so we will just append - // the body fragment. - then_fragment += body_fragments[i]; - } - - current_instructions = Fragment(otherwise); - } - } - } - - bool has_no_default = - num_cases > 0 && !node->cases()[num_cases - 1]->is_default(); - if (has_no_default) { - // There is no default, which means we have an open [current_instructions] - // (which is a [TargetEntryInstruction] for the last "otherwise" branch). - // - // Furthermore the last [SwitchCase] can be open as well. If so, we need - // to join these two. - Fragment& last_body = body_fragments[node->cases().length() - 1]; - if (last_body.is_open()) { - ASSERT(current_instructions.is_open()); - ASSERT(current_instructions.current->IsTargetEntry()); - - // Join the last "otherwise" branch and the last [SwitchCase] fragment. - JoinEntryInstr* join = BuildJoinEntry(); - current_instructions += Goto(join); - last_body += Goto(join); - - current_instructions = Fragment(join); - } - } else { - // All non-default cases will be closed (i.e. break/continue/throw/return) - // So it is fine to just let more statements after the switch append to the - // default case. - } - - delete[] body_fragments; - - fragment_ = Fragment(head_instructions.entry, current_instructions.current); -} - - -void FlowGraphBuilder::VisitContinueSwitchStatement( - ContinueSwitchStatement* node) { - fragment_ = - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset()); -} - - -void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - if (!I->asserts()) { - fragment_ = Fragment(); - return; - } - - TargetEntryInstr* then; - TargetEntryInstr* otherwise; - - Fragment instructions; - // Asserts can be of the following two kinds: - // - // * `assert(expr)` - // * `assert(() { ... })` - // - // The call to `_AssertionError._evaluateAssertion()` will take care of both - // and returns a boolean. - instructions += TranslateExpression(node->condition()); - instructions += PushArgument(); - instructions += EvaluateAssertion(); - instructions += CheckBooleanInCheckedMode(); - instructions += Constant(Bool::True()); - instructions += BranchIfEqual(&then, &otherwise, false); - - const dart::Class& klass = dart::Class::ZoneHandle( - Z, dart::Library::LookupCoreClass(Symbols::AssertionError())); - ASSERT(!klass.IsNull()); - const Function& constructor = - Function::ZoneHandle(Z, klass.LookupConstructorAllowPrivate( - H.DartSymbol("_AssertionError._create"))); - ASSERT(!constructor.IsNull()); - - const dart::String& url = H.DartString( - parsed_function_->function().ToLibNamePrefixedQualifiedCString(), - Heap::kOld); - - // Create instance of _AssertionError - Fragment otherwise_fragment(otherwise); - otherwise_fragment += AllocateObject(klass, 0); - LocalVariable* instance = MakeTemporary(); - - // Call _AssertionError._create constructor. - otherwise_fragment += LoadLocal(instance); - otherwise_fragment += PushArgument(); // this - - otherwise_fragment += Constant(H.DartString("", Heap::kOld)); - otherwise_fragment += PushArgument(); // failedAssertion - - otherwise_fragment += Constant(url); - otherwise_fragment += PushArgument(); // url - - otherwise_fragment += IntConstant(0); - otherwise_fragment += PushArgument(); // line - - otherwise_fragment += IntConstant(0); - otherwise_fragment += PushArgument(); // column - - otherwise_fragment += - node->message() != NULL - ? TranslateExpression(node->message()) - : Constant(H.DartString("", Heap::kOld)); - otherwise_fragment += PushArgument(); // message - - otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6); - otherwise_fragment += Drop(); - - // Throw _AssertionError exception. - otherwise_fragment += PushArgument(); - otherwise_fragment += ThrowException(TokenPosition::kNoSource); - otherwise_fragment += Drop(); - - fragment_ = Fragment(instructions.entry, then); -} - - -void FlowGraphBuilder::VisitTryFinally(TryFinally* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally"); - - // There are 5 different cases where we need to execute the finally block: - // - // a) 1/2/3th case: Special control flow going out of `node->body()`: - // - // * [BreakStatement] transfers control to a [LabledStatement] - // * [ContinueSwitchStatement] transfers control to a [SwitchCase] - // * [ReturnStatement] returns a value - // - // => All three cases will automatically append all finally blocks - // between the branching point and the destination (so we don't need to - // do anything here). - // - // b) 4th case: Translating the body resulted in an open fragment (i.e. body - // executes without any control flow out of it) - // - // => We are responsible for jumping out of the body to a new block (with - // different try index) and execute the finalizer. - // - // c) 5th case: An exception occured inside the body. - // - // => We are responsible for catching it, executing the finally block and - // rethrowing the exception. - intptr_t try_handler_index = AllocateTryIndex(); - Fragment try_body = TryCatch(try_handler_index); - JoinEntryInstr* after_try = BuildJoinEntry(); - - // Fill in the body of the try. - ++try_depth_; - { - TryFinallyBlock tfb(this, node->finalizer(), -1); - TryCatchBlock tcb(this, try_handler_index); - try_body += TranslateStatement(node->body()); - } - --try_depth_; - - if (try_body.is_open()) { - // Please note: The try index will be on level out of this block, - // thereby ensuring if there's an exception in the finally block we - // won't run it twice. - JoinEntryInstr* finally_entry = BuildJoinEntry(); - - try_body += Goto(finally_entry); - - Fragment finally_body(finally_entry); - finally_body += TranslateStatement(node->finalizer()); - finally_body += Goto(after_try); - } - - // Fill in the body of the catch. - ++catch_depth_; - const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld)); - handler_types.SetAt(0, Object::dynamic_type()); - // Note: rethrow will actually force mark the handler as needing a stacktrace. - Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index, - /* needs_stacktrace = */ false); - finally_body += TranslateStatement(node->finalizer()); - if (finally_body.is_open()) { - finally_body += LoadLocal(CurrentException()); - finally_body += PushArgument(); - finally_body += LoadLocal(CurrentStackTrace()); - finally_body += PushArgument(); - finally_body += - RethrowException(TokenPosition::kNoSource, try_handler_index); - Drop(); - } - --catch_depth_; - - fragment_ = Fragment(try_body.entry, after_try); -} - - -void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch"); - - intptr_t try_handler_index = AllocateTryIndex(); - Fragment try_body = TryCatch(try_handler_index); - JoinEntryInstr* after_try = BuildJoinEntry(); - - // Fill in the body of the try. - ++try_depth_; - { - TryCatchBlock block(this, try_handler_index); - try_body += TranslateStatement(node->body()); - try_body += Goto(after_try); - } - --try_depth_; - - ++catch_depth_; - const Array& handler_types = - Array::ZoneHandle(Z, Array::New(node->catches().length(), Heap::kOld)); - bool needs_stacktrace = false; - for (intptr_t i = 0; i < node->catches().length(); i++) { - if (node->catches()[i]->stack_trace() != NULL) { - needs_stacktrace = true; - break; - } - } - Fragment catch_body = - CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace); - // Fill in the body of the catch. - for (intptr_t i = 0; i < node->catches().length(); i++) { - Catch* catch_clause = node->catches()[i]; - - Fragment catch_handler_body; - - catch_handler_body += EnterScope(catch_clause); - - if (catch_clause->exception() != NULL) { - catch_handler_body += LoadLocal(CurrentException()); - catch_handler_body += StoreLocal( - TokenPosition::kNoSource, LookupVariable(catch_clause->exception())); - catch_handler_body += Drop(); - } - if (catch_clause->stack_trace() != NULL) { - catch_handler_body += LoadLocal(CurrentStackTrace()); - catch_handler_body += - StoreLocal(TokenPosition::kNoSource, - LookupVariable(catch_clause->stack_trace())); - catch_handler_body += Drop(); - } - AbstractType* type_guard = NULL; - if (catch_clause->guard() != NULL && - !catch_clause->guard()->IsDynamicType()) { - type_guard = &T.TranslateType(catch_clause->guard()); - handler_types.SetAt(i, *type_guard); - } else { - handler_types.SetAt(i, Object::dynamic_type()); - } - - { - CatchBlock block(this, CurrentException(), CurrentStackTrace(), - try_handler_index); - - catch_handler_body += TranslateStatement(catch_clause->body()); - - // Note: ExitScope adjusts context_depth_ so even if catch_handler_body - // is closed we still need to execute ExitScope for its side effect. - catch_handler_body += ExitScope(catch_clause); - if (catch_handler_body.is_open()) { - catch_handler_body += Goto(after_try); - } - } - - if (type_guard != NULL) { - if (type_guard->IsMalformed()) { - catch_body += ThrowTypeError(); - catch_body += Drop(); - } else { - catch_body += LoadLocal(CurrentException()); - catch_body += PushArgument(); // exception - catch_body += NullConstant(); - catch_body += PushArgument(); // instantiator type arguments - catch_body += NullConstant(); - catch_body += PushArgument(); // function type arguments - catch_body += Constant(*type_guard); - catch_body += PushArgument(); // guard type - catch_body += InstanceCall( - TokenPosition::kNoSource, - dart::Library::PrivateCoreLibName(Symbols::_instanceOf()), - Token::kIS, 4); - - TargetEntryInstr* catch_entry; - TargetEntryInstr* next_catch_entry; - catch_body += BranchIfTrue(&catch_entry, &next_catch_entry); - - Fragment(catch_entry) + catch_handler_body; - catch_body = Fragment(next_catch_entry); - } - } else { - catch_body += catch_handler_body; - } - } - - // In case the last catch body was not handling the exception and branching to - // after the try block, we will rethrow the exception (i.e. no default catch - // handler). - if (catch_body.is_open()) { - catch_body += LoadLocal(CurrentException()); - catch_body += PushArgument(); - catch_body += LoadLocal(CurrentStackTrace()); - catch_body += PushArgument(); - catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index); - Drop(); - } - --catch_depth_; - - fragment_ = Fragment(try_body.entry, after_try); -} - - -void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) { - STREAM_STATEMENT_IF_POSSIBLE(node); - - ASSERT(node->is_native()); // Must have been desugared. - // Setup yield/continue point: - // - // ... - // :await_jump_var = index; - // :await_ctx_var = :current_context_var - // return - // - // Continuation: - // Drop(1) - // ... - // - // BuildGraphOfFunction will create a dispatch that jumps to - // Continuation<:await_jump_var> upon entry to the function. - // - Fragment instructions = IntConstant(yield_continuations_.length() + 1); - instructions += - StoreLocal(TokenPosition::kNoSource, scopes_->yield_jump_variable); - instructions += Drop(); - instructions += LoadLocal(parsed_function_->current_context_var()); - instructions += - StoreLocal(TokenPosition::kNoSource, scopes_->yield_context_variable); - instructions += Drop(); - instructions += TranslateExpression(node->expression()); - instructions += Return(TokenPosition::kNoSource); - - // Note: DropTempsInstr serves as an anchor instruction. It will not - // be linked into the resulting graph. - DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL); - yield_continuations_.Add(YieldContinuation(anchor, CurrentTryIndex())); - - Fragment continuation(instructions.entry, anchor); - - if (parsed_function_->function().IsAsyncClosure() || - parsed_function_->function().IsAsyncGenClosure()) { - // If function is async closure or async gen closure it takes three - // parameters where the second and the third are exception and stack_trace. - // Check if exception is non-null and rethrow it. - // - // :async_op([:result, :exception, :stack_trace]) { - // ... - // Continuation: - // if (:exception != null) rethrow(:exception, :stack_trace); - // ... - // } - // - LocalScope* scope = parsed_function_->node_sequence()->scope(); - LocalVariable* exception_var = scope->VariableAt(2); - LocalVariable* stack_trace_var = scope->VariableAt(3); - ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw()); - ASSERT(stack_trace_var->name().raw() == - Symbols::StackTraceParameter().raw()); - - TargetEntryInstr* no_error; - TargetEntryInstr* error; - - continuation += LoadLocal(exception_var); - continuation += BranchIfNull(&no_error, &error); - - Fragment rethrow(error); - rethrow += LoadLocal(exception_var); - rethrow += PushArgument(); - rethrow += LoadLocal(stack_trace_var); - rethrow += PushArgument(); - rethrow += - RethrowException(node->position(), CatchClauseNode::kInvalidTryIndex); - Drop(); - - - continuation = Fragment(continuation.entry, no_error); - } - - fragment_ = continuation; -} - - -Fragment FlowGraphBuilder::TranslateFunctionNode(FunctionNode* node, - TreeNode* parent) { - // The VM has a per-isolate table of functions indexed by the enclosing - // function and token position. - Function& function = Function::ZoneHandle(Z); - for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) { - if (scopes_->function_scopes[i].kernel_offset != node->kernel_offset()) { - continue; - } - - TokenPosition position = node->position(); - if (parent->IsFunctionDeclaration()) { - position = FunctionDeclaration::Cast(parent)->position(); - } - if (!position.IsReal()) { - // Positions has to be unique in regards to the parent. - // A non-real at this point is probably -1, we cannot blindly use that - // as others might use it too. Create a new dummy non-real TokenPosition. - position = TokenPosition(i).ToSynthetic(); - } - - // NOTE: This is not TokenPosition in the general sense! - function = I->LookupClosureFunction(parsed_function_->function(), position); - if (function.IsNull()) { - const dart::String* name; - if (parent->IsFunctionExpression()) { - name = &Symbols::AnonymousClosure(); - } else { - ASSERT(parent->IsFunctionDeclaration()); - name = &H.DartSymbol( - FunctionDeclaration::Cast(parent)->variable()->name()); - } - // NOTE: This is not TokenPosition in the general sense! - function = Function::NewClosureFunction( - *name, parsed_function_->function(), position); - - function.set_is_debuggable(node->dart_async_marker() == - FunctionNode::kSync); - switch (node->dart_async_marker()) { - case FunctionNode::kSyncStar: - function.set_modifier(RawFunction::kSyncGen); - break; - case FunctionNode::kAsync: - function.set_modifier(RawFunction::kAsync); - function.set_is_inlinable(!FLAG_causal_async_stacks); - break; - case FunctionNode::kAsyncStar: - function.set_modifier(RawFunction::kAsyncGen); - function.set_is_inlinable(!FLAG_causal_async_stacks); - break; - default: - // no special modifier - break; - } - function.set_is_generated_body(node->async_marker() == - FunctionNode::kSyncYielding); - if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { - function.set_is_inlinable(!FLAG_causal_async_stacks); - } - - function.set_end_token_pos(node->end_position()); - LocalScope* scope = scopes_->function_scopes[i].scope; - const ContextScope& context_scope = - ContextScope::Handle(Z, scope->PreserveOuterScope(context_depth_)); - function.set_context_scope(context_scope); - function.set_kernel_function(node); - KernelReader::SetupFunctionParameters(H, T, dart::Class::Handle(Z), - function, node, - false, // is_method - true); // is_closure - // Finalize function type. - Type& signature_type = Type::Handle(Z, function.SignatureType()); - signature_type ^= - ClassFinalizer::FinalizeType(*active_class_.klass, signature_type); - function.SetSignatureType(signature_type); - - I->AddClosureFunction(function); - } - break; - } - - const dart::Class& closure_class = - dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); - ASSERT(!closure_class.IsNull()); - Fragment instructions = AllocateObject(closure_class, function); - LocalVariable* closure = MakeTemporary(); - - // The function signature can have uninstantiated class type parameters. - // - // TODO(regis): Also handle the case of a function signature that has - // uninstantiated function type parameters. - if (!function.HasInstantiatedSignature(kCurrentClass)) { - instructions += LoadLocal(closure); - instructions += LoadInstantiatorTypeArguments(); - instructions += - StoreInstanceField(TokenPosition::kNoSource, - Closure::instantiator_type_arguments_offset()); - } - - // Store the function and the context in the closure. - instructions += LoadLocal(closure); - instructions += Constant(function); - instructions += - StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset()); - - instructions += LoadLocal(closure); - instructions += LoadLocal(parsed_function_->current_context_var()); - instructions += - StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset()); - - return instructions; -} - - RawObject* EvaluateMetadata(const dart::Field& metadata_field) { LongJumpScope jump; if (setjmp(*jump.Set()) == 0) { Thread* thread = Thread::Current(); Zone* zone_ = thread->zone(); - - TreeNode* kernel_node = - reinterpret_cast(metadata_field.kernel_field()); - List* metadata_expressions = NULL; - if (kernel_node->IsClass()) { - metadata_expressions = &Class::Cast(kernel_node)->annotations(); - } else if (kernel_node->IsProcedure()) { - metadata_expressions = &Procedure::Cast(kernel_node)->annotations(); - } else if (kernel_node->IsField()) { - metadata_expressions = &Field::Cast(kernel_node)->annotations(); - } else if (kernel_node->IsConstructor()) { - metadata_expressions = &Constructor::Cast(kernel_node)->annotations(); - } else { - FATAL1("No support for metadata on this type of kernel node %p\n", - kernel_node); - } - TranslationHelper helper(thread); Script& script = Script::Handle(Z, metadata_field.Script()); helper.SetStringOffsets( @@ -6017,20 +2700,11 @@ RawObject* EvaluateMetadata(const dart::Field& metadata_field) { helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); helper.SetCanonicalNames( TypedData::Handle(Z, script.kernel_canonical_names())); - DartTypeTranslator type_translator(&helper, NULL, true); - ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z, - &helper, &type_translator); - const Array& metadata_values = - Array::Handle(Z, Array::New(metadata_expressions->length())); - - for (intptr_t i = 0; i < metadata_expressions->length(); i++) { - const Instance& value = - constant_evaluator.EvaluateExpression((*metadata_expressions)[i]); - metadata_values.SetAt(i, value); - } - - return metadata_values.raw(); + StreamingFlowGraphBuilder streaming_flow_graph_builder( + &helper, zone_, script.kernel_data(), script.kernel_data_size()); + return streaming_flow_graph_builder.EvaluateMetadata( + metadata_field.kernel_offset()); } else { Thread* thread = Thread::Current(); Error& error = Error::Handle(); @@ -6044,20 +2718,6 @@ RawObject* EvaluateMetadata(const dart::Field& metadata_field) { RawObject* BuildParameterDescriptor(const Function& function) { LongJumpScope jump; if (setjmp(*jump.Set()) == 0) { - TreeNode* kernel_node = - reinterpret_cast(function.kernel_function()); - FunctionNode* function_node = NULL; - if (kernel_node->IsProcedure()) { - function_node = Procedure::Cast(kernel_node)->function(); - } else if (kernel_node->IsConstructor()) { - function_node = Constructor::Cast(kernel_node)->function(); - } else if (kernel_node->IsFunctionNode()) { - function_node = FunctionNode::Cast(kernel_node); - } else { - UNIMPLEMENTED(); - return NULL; - } - Thread* thread = Thread::Current(); Zone* zone_ = thread->zone(); TranslationHelper helper(thread); @@ -6067,45 +2727,11 @@ RawObject* BuildParameterDescriptor(const Function& function) { helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data())); helper.SetCanonicalNames( TypedData::Handle(Z, script.kernel_canonical_names())); - DartTypeTranslator type_translator(&helper, NULL, true); - ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z, - &helper, &type_translator); - const intptr_t positional_count = - function_node->positional_parameters().length(); - const intptr_t param_count = - positional_count + function_node->named_parameters().length(); - const Array& param_descriptor = Array::Handle( - Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld)); - for (intptr_t i = 0; i < param_count; ++i) { - const intptr_t entry_start = i * Parser::kParameterEntrySize; - - VariableDeclaration* variable; - if (i < positional_count) { - variable = function_node->positional_parameters()[i]; - } else { - variable = function_node->named_parameters()[i - positional_count]; - } - - param_descriptor.SetAt( - entry_start + Parser::kParameterIsFinalOffset, - variable->IsFinal() ? Bool::True() : Bool::False()); - - if (variable->initializer() != NULL) { - param_descriptor.SetAt( - entry_start + Parser::kParameterDefaultValueOffset, - constant_evaluator.EvaluateExpression(variable->initializer())); - } else { - param_descriptor.SetAt( - entry_start + Parser::kParameterDefaultValueOffset, - Object::null_instance()); - } - - param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset, - /* Issue(28434): Missing parameter metadata. */ - Object::null_instance()); - } - return param_descriptor.raw(); + StreamingFlowGraphBuilder streaming_flow_graph_builder( + &helper, zone_, script.kernel_data(), script.kernel_data_size()); + return streaming_flow_graph_builder.BuildParameterDescriptor( + function.kernel_offset()); } else { Thread* thread = Thread::Current(); Error& error = Error::Handle(); diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h index 038e0e1b0e7..959197744ac 100644 --- a/runtime/vm/kernel_to_il.h +++ b/runtime/vm/kernel_to_il.h @@ -13,7 +13,6 @@ #include "vm/flow_graph.h" #include "vm/flow_graph_builder.h" #include "vm/intermediate_language.h" -#include "vm/kernel.h" namespace dart { namespace kernel { @@ -551,115 +550,6 @@ class DartTypeTranslator : public DartTypeVisitor { }; -// There are several cases when we are compiling constant expressions: -// -// * constant field initializers: -// const FieldName = ; -// -// * constant expressions: -// const [, ...] -// const { : , ...} -// const Constructor(, ...) -// -// * constant default parameters: -// f(a, [b = ]) -// f(a, {b: }) -// -// * constant values to compare in a [SwitchCase] -// case : -// -// In all cases `` must be recursively evaluated and canonicalized at -// compile-time. -class ConstantEvaluator : public ExpressionVisitor { - public: - ConstantEvaluator(FlowGraphBuilder* builder, - Zone* zone, - TranslationHelper* h, - DartTypeTranslator* type_translator); - virtual ~ConstantEvaluator() {} - - Instance& EvaluateExpression(Expression* node); - Object& EvaluateExpressionSafe(Expression* node); - Instance& EvaluateConstructorInvocation(ConstructorInvocation* node); - Instance& EvaluateListLiteral(ListLiteral* node); - Instance& EvaluateMapLiteral(MapLiteral* node); - - virtual void VisitDefaultExpression(Expression* node) { UNREACHABLE(); } - - virtual void VisitBigintLiteral(BigintLiteral* node); - virtual void VisitBoolLiteral(BoolLiteral* node); - virtual void VisitDoubleLiteral(DoubleLiteral* node); - virtual void VisitIntLiteral(IntLiteral* node); - virtual void VisitNullLiteral(NullLiteral* node); - virtual void VisitStringLiteral(StringLiteral* node); - virtual void VisitSymbolLiteral(SymbolLiteral* node); - virtual void VisitTypeLiteral(TypeLiteral* node); - - virtual void VisitListLiteral(ListLiteral* node); - virtual void VisitMapLiteral(MapLiteral* node); - - virtual void VisitConstructorInvocation(ConstructorInvocation* node); - virtual void VisitMethodInvocation(MethodInvocation* node); - virtual void VisitStaticGet(StaticGet* node); - virtual void VisitVariableGet(VariableGet* node); - virtual void VisitLet(Let* node); - virtual void VisitStaticInvocation(StaticInvocation* node); - virtual void VisitStringConcatenation(StringConcatenation* node); - virtual void VisitConditionalExpression(ConditionalExpression* node); - virtual void VisitLogicalExpression(LogicalExpression* node); - virtual void VisitNot(Not* node); - virtual void VisitPropertyGet(PropertyGet* node); - - private: - // This will translate type arguments form [kernel_arguments]. If no type - // arguments are passed and the [target] is a factory then the null type - // argument array will be returned. - // - // If none of these cases apply, NULL will be returned. - const TypeArguments* TranslateTypeArguments(const Function& target, - dart::Class* target_klass, - Arguments* kernel_arguments); - - const Object& RunFunction(const Function& function, - Arguments* arguments, - const Instance* receiver = NULL, - const TypeArguments* type_args = NULL); - - const Object& RunFunction(const Function& function, - const Array& arguments, - const Array& names); - - RawObject* EvaluateConstConstructorCall(const dart::Class& type_class, - const TypeArguments& type_arguments, - const Function& constructor, - const Object& argument); - - void AssertBoolInCheckedMode() { - if (isolate_->type_checks() && !result_.IsBool()) { - translation_helper_.ReportError("Expected boolean expression."); - } - } - - bool EvaluateBooleanExpression(Expression* expression) { - EvaluateExpression(expression); - AssertBoolInCheckedMode(); - return result_.raw() == Bool::True().raw(); - } - - bool GetCachedConstant(TreeNode* node, Instance* value); - void CacheConstantValue(TreeNode* node, const Instance& value); - - FlowGraphBuilder* builder_; - Isolate* isolate_; - Zone* zone_; - TranslationHelper& translation_helper_; - DartTypeTranslator& type_translator_; - - Script& script_; - Instance& result_; -}; - - struct FunctionScope { intptr_t kernel_offset; LocalScope* scope; @@ -728,9 +618,9 @@ struct YieldContinuation { : entry(NULL), try_index(CatchClauseNode::kInvalidTryIndex) {} }; -class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { +class FlowGraphBuilder { public: - FlowGraphBuilder(TreeNode* node, + FlowGraphBuilder(intptr_t kernel_offset, ParsedFunction* parsed_function, const ZoneGrowableArray& ic_data_array, ZoneGrowableArray* context_level_array, @@ -741,106 +631,24 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { FlowGraph* BuildGraph(); - virtual void VisitDefaultExpression(Expression* node) { UNREACHABLE(); } - virtual void VisitDefaultStatement(Statement* node) { UNREACHABLE(); } - - virtual void VisitInvalidExpression(InvalidExpression* node); - virtual void VisitNullLiteral(NullLiteral* node); - virtual void VisitBoolLiteral(BoolLiteral* node); - virtual void VisitIntLiteral(IntLiteral* node); - virtual void VisitBigintLiteral(BigintLiteral* node); - virtual void VisitDoubleLiteral(DoubleLiteral* node); - virtual void VisitStringLiteral(StringLiteral* node); - virtual void VisitSymbolLiteral(SymbolLiteral* node); - virtual void VisitTypeLiteral(TypeLiteral* node); - virtual void VisitVariableGet(VariableGet* node); - virtual void VisitVariableSet(VariableSet* node); - virtual void VisitStaticGet(StaticGet* node); - virtual void VisitStaticSet(StaticSet* node); - virtual void VisitPropertyGet(PropertyGet* node); - virtual void VisitPropertySet(PropertySet* node); - virtual void VisitDirectPropertyGet(DirectPropertyGet* node); - virtual void VisitDirectPropertySet(DirectPropertySet* node); - virtual void VisitStaticInvocation(StaticInvocation* node); - virtual void VisitMethodInvocation(MethodInvocation* node); - virtual void VisitDirectMethodInvocation(DirectMethodInvocation* node); - virtual void VisitConstructorInvocation(ConstructorInvocation* node); - virtual void VisitIsExpression(IsExpression* node); - virtual void VisitAsExpression(AsExpression* node); - virtual void VisitConditionalExpression(ConditionalExpression* node); - virtual void VisitLogicalExpression(LogicalExpression* node); - virtual void VisitNot(Not* node); - virtual void VisitThisExpression(ThisExpression* node); - virtual void VisitStringConcatenation(StringConcatenation* node); - virtual void VisitListLiteral(ListLiteral* node); - virtual void VisitMapLiteral(MapLiteral* node); - virtual void VisitFunctionExpression(FunctionExpression* node); - virtual void VisitLet(Let* node); - virtual void VisitThrow(Throw* node); - virtual void VisitRethrow(Rethrow* node); - - virtual void VisitInvalidStatement(InvalidStatement* node); - virtual void VisitEmptyStatement(EmptyStatement* node); - virtual void VisitBlock(Block* node); - virtual void VisitReturnStatement(ReturnStatement* node); - virtual void VisitExpressionStatement(ExpressionStatement* node); - virtual void VisitVariableDeclaration(VariableDeclaration* node); - virtual void VisitFunctionDeclaration(FunctionDeclaration* node); - virtual void VisitIfStatement(IfStatement* node); - virtual void VisitWhileStatement(WhileStatement* node); - virtual void VisitDoStatement(DoStatement* node); - virtual void VisitForStatement(ForStatement* node); - virtual void VisitForInStatement(ForInStatement* node); - virtual void VisitLabeledStatement(LabeledStatement* node); - virtual void VisitBreakStatement(BreakStatement* node); - virtual void VisitSwitchStatement(SwitchStatement* node); - virtual void VisitContinueSwitchStatement(ContinueSwitchStatement* node); - virtual void VisitAssertStatement(AssertStatement* node); - virtual void VisitTryFinally(TryFinally* node); - virtual void VisitTryCatch(TryCatch* node); - virtual void VisitYieldStatement(YieldStatement* node); - private: - FlowGraph* BuildGraphOfFunction(FunctionNode* node, - Constructor* constructor = NULL); - FlowGraph* BuildGraphOfFieldAccessor(Field* node, - LocalVariable* setter_value); - FlowGraph* BuildGraphOfStaticFieldInitializer(Field* node); FlowGraph* BuildGraphOfMethodExtractor(const Function& method); - FlowGraph* BuildGraphOfImplicitClosureFunction(FunctionNode* kernel_function, - const Function& function); FlowGraph* BuildGraphOfNoSuchMethodDispatcher(const Function& function); FlowGraph* BuildGraphOfInvokeFieldDispatcher(const Function& function); - Fragment NativeFunctionBody(FunctionNode* kernel_function, + Fragment NativeFunctionBody(intptr_t first_positional_offset, const Function& function); - void SetupDefaultParameterValues(FunctionNode* function); - TargetEntryInstr* BuildTargetEntry(); JoinEntryInstr* BuildJoinEntry(); JoinEntryInstr* BuildJoinEntry(intptr_t try_index); - Fragment TranslateArguments(Arguments* node, Array* argument_names); ArgumentArray GetArguments(int count); - Fragment TranslateInitializers(Class* kernel_class, - List* initialiers); - Fragment TranslateFieldInitializer(NameIndex canonical_name, - Expression* init); - - Fragment TranslateStatement(Statement* statement); - Fragment TranslateCondition(Expression* expression, bool* negate); - Fragment TranslateExpression(Expression* expression); - Fragment TranslateFinallyFinalizers(TryFinallyBlock* outer_finally, intptr_t target_context_depth); - Fragment TranslateFunctionNode(FunctionNode* node, TreeNode* parent); - - Fragment EnterScope(TreeNode* node, bool* new_context = NULL); Fragment EnterScope(intptr_t kernel_offset, bool* new_context = NULL); - Fragment ExitScope(TreeNode* node); Fragment ExitScope(intptr_t kernel_offset); Fragment LoadContextAt(int depth); @@ -943,7 +751,6 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { Fragment EvaluateAssertion(); Fragment CheckReturnTypeInCheckedMode(); - Fragment CheckVariableTypeInCheckedMode(VariableDeclaration* variable); Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type, const dart::String& name_symbol); Fragment CheckBooleanInCheckedMode(); @@ -954,9 +761,6 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { Fragment AssertAssignable(const dart::AbstractType& dst_type, const dart::String& dst_name); - template - bool RecognizeComparisonWithNull(Token::Kind token_kind, Invocation* node); - bool NeedsDebugStepCheck(const Function& function, TokenPosition position); bool NeedsDebugStepCheck(Value* value, TokenPosition position); Fragment DebugStepCheck(TokenPosition position); @@ -970,10 +774,6 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { intptr_t CurrentTryIndex(); intptr_t AllocateTryIndex() { return next_used_try_index_++; } - void AddVariable(VariableDeclaration* declaration, LocalVariable* variable); - void AddParameter(VariableDeclaration* declaration, - LocalVariable* variable, - intptr_t pos); dart::LocalVariable* LookupVariable(VariableDeclaration* var); dart::LocalVariable* LookupVariable(intptr_t kernel_offset); @@ -993,9 +793,7 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { Thread* thread_; Zone* zone_; - // The node we are currently compiling (e.g. FunctionNode, Constructor, - // Field) - TreeNode* node_; + intptr_t kernel_offset_; ParsedFunction* parsed_function_; intptr_t osr_id_; @@ -1025,7 +823,6 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { intptr_t try_depth_; intptr_t catch_depth_; intptr_t for_in_depth_; - Fragment fragment_; Value* stack_; intptr_t pending_argument_count_; @@ -1069,7 +866,6 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { ActiveClass active_class_; DartTypeTranslator type_translator_; - ConstantEvaluator constant_evaluator_; StreamingFlowGraphBuilder* streaming_flow_graph_builder_; diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 62844ac8927..a1f636e4d98 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -2740,7 +2740,7 @@ RawFunction* Function::CreateMethodExtractor(const String& getter_name) const { extractor.set_parameter_types(Object::extractor_parameter_types()); extractor.set_parameter_names(Object::extractor_parameter_names()); extractor.set_result_type(Object::dynamic_type()); - extractor.set_kernel_function(kernel_function()); + extractor.set_kernel_offset(kernel_offset()); extractor.set_extracted_method_closure(closure_function); extractor.set_is_debuggable(false); @@ -6814,7 +6814,7 @@ RawFunction* Function::New(const String& name, NOT_IN_PRECOMPILED(result.set_deoptimization_counter(0)); NOT_IN_PRECOMPILED(result.set_optimized_instruction_count(0)); NOT_IN_PRECOMPILED(result.set_optimized_call_site_count(0)); - result.set_kernel_function(NULL); + result.set_kernel_offset(0); result.set_is_optimizable(is_native ? false : true); result.set_is_inlinable(true); result.set_allows_hoisting_check_class(true); @@ -6854,7 +6854,7 @@ RawFunction* Function::Clone(const Class& new_owner) const { clone.set_deoptimization_counter(0); clone.set_optimized_instruction_count(0); clone.set_optimized_call_site_count(0); - clone.set_kernel_function(kernel_function()); + clone.set_kernel_offset(kernel_offset()); if (new_owner.NumTypeParameters() > 0) { // Adjust uninstantiated types to refer to type parameters of the new owner. const TypeArguments& type_params = @@ -7010,7 +7010,7 @@ RawFunction* Function::ImplicitClosureFunction() const { param_name = ParameterNameAt(has_receiver - kClosure + i); closure_function.SetParameterNameAt(i, param_name); } - closure_function.set_kernel_function(kernel_function()); + closure_function.set_kernel_offset(kernel_offset()); const Type& signature_type = Type::Handle(zone, closure_function.SignatureType()); @@ -7480,7 +7480,7 @@ void Function::SetDeoptReasonForAll(intptr_t deopt_id, bool Function::CheckSourceFingerprint(const char* prefix, int32_t fp) const { - if ((kernel_function() == NULL) && (SourceFingerprint() != fp)) { + if ((kernel_offset() <= 0) && (SourceFingerprint() != fp)) { const bool recalculatingFingerprints = false; if (recalculatingFingerprints) { // This output can be copied into a file, then used with sed @@ -7864,7 +7864,7 @@ void Field::InitializeNew(const Field& result, result.set_token_pos(token_pos); result.set_has_initializer(false); result.set_is_unboxing_candidate(true); - result.set_kernel_field(NULL); + result.set_kernel_offset(0); Isolate* isolate = Isolate::Current(); // Use field guards if they are enabled and the isolate has never reloaded. @@ -7944,7 +7944,7 @@ RawField* Field::Clone(const Field& original) const { Field& clone = Field::Handle(); clone ^= Object::Clone(*this, Heap::kOld); clone.SetOriginal(original); - clone.set_kernel_field(original.kernel_field()); + clone.set_kernel_offset(original.kernel_offset()); return clone.raw(); } @@ -9121,6 +9121,16 @@ void Script::set_compile_time_constants(const Array& value) const { } +void Script::set_kernel_data(const uint8_t* kernel_data) const { + StoreNonPointer(&raw_ptr()->kernel_data_, kernel_data); +} + + +void Script::set_kernel_data_size(const intptr_t kernel_data_size) const { + StoreNonPointer(&raw_ptr()->kernel_data_size_, kernel_data_size); +} + + void Script::set_kernel_string_offsets(const TypedData& offsets) const { StorePointer(&raw_ptr()->kernel_string_offsets_, offsets.raw()); } @@ -10085,7 +10095,7 @@ static RawString* MakeTypeParameterMetaName(Thread* thread, void Library::AddMetadata(const Object& owner, const String& name, TokenPosition token_pos, - kernel::TreeNode* kernel_node) const { + intptr_t kernel_offset) const { Thread* thread = Thread::Current(); ASSERT(thread->IsMutatorThread()); Zone* zone = thread->zone(); @@ -10098,7 +10108,7 @@ void Library::AddMetadata(const Object& owner, field.SetFieldType(Object::dynamic_type()); field.set_is_reflectable(false); field.SetStaticValue(Array::empty_array(), true); - field.set_kernel_field(kernel_node); + field.set_kernel_offset(kernel_offset); GrowableObjectArray& metadata = GrowableObjectArray::Handle(zone, this->metadata()); metadata.Add(field, Heap::kOld); @@ -10108,36 +10118,36 @@ void Library::AddMetadata(const Object& owner, void Library::AddClassMetadata(const Class& cls, const Object& tl_owner, TokenPosition token_pos, - kernel::TreeNode* kernel_node) const { + intptr_t kernel_offset) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); // We use the toplevel class as the owner of a class's metadata field because // a class's metadata is in scope of the library, not the class. AddMetadata(tl_owner, String::Handle(zone, MakeClassMetaName(thread, zone, cls)), - token_pos, kernel_node); + token_pos, kernel_offset); } void Library::AddFieldMetadata(const Field& field, TokenPosition token_pos, - kernel::TreeNode* kernel_node) const { + intptr_t kernel_offset) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); AddMetadata(Object::Handle(zone, field.RawOwner()), String::Handle(zone, MakeFieldMetaName(thread, zone, field)), - token_pos, kernel_node); + token_pos, kernel_offset); } void Library::AddFunctionMetadata(const Function& func, TokenPosition token_pos, - kernel::TreeNode* kernel_node) const { + intptr_t kernel_offset) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); AddMetadata(Object::Handle(zone, func.RawOwner()), String::Handle(zone, MakeFunctionMetaName(thread, zone, func)), - token_pos, kernel_node); + token_pos, kernel_offset); } @@ -10213,7 +10223,7 @@ RawObject* Library::GetMetadata(const Object& obj) const { Object& metadata = Object::Handle(); metadata = field.StaticValue(); if (field.StaticValue() == Object::empty_array().raw()) { - if (field.kernel_field() != NULL) { + if (field.kernel_offset() > 0) { metadata = kernel::EvaluateMetadata(field); } else { metadata = Parser::ParseMetadata(field); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 7419287d799..c6715d6f58a 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -2627,17 +2627,17 @@ class Function : public Object { #endif } - void* kernel_function() const { + intptr_t kernel_offset() const { #if defined(DART_PRECOMPILED_RUNTIME) - return NULL; + return 0; #else - return raw_ptr()->kernel_function_; + return raw_ptr()->kernel_offset_; #endif } - void set_kernel_function(void* kernel_function) const { + void set_kernel_offset(intptr_t kernel_offset) const { #if !defined(DART_PRECOMPILED_RUNTIME) - StoreNonPointer(&raw_ptr()->kernel_function_, kernel_function); + StoreNonPointer(&raw_ptr()->kernel_offset_, kernel_offset); #endif } @@ -3181,17 +3181,17 @@ class Field : public Object { set_kind_bits(DoubleInitializedBit::update(value, raw_ptr()->kind_bits_)); } - void* kernel_field() const { + intptr_t kernel_offset() const { #if defined(DART_PRECOMPILED_RUNTIME) return NULL; #else - return raw_ptr()->kernel_field_; + return raw_ptr()->kernel_offset_; #endif } - void set_kernel_field(void* kernel_field) const { + void set_kernel_offset(intptr_t kernel_offset) const { #if !defined(DART_PRECOMPILED_RUNTIME) - StoreNonPointer(&raw_ptr()->kernel_field_, kernel_field); + StoreNonPointer(&raw_ptr()->kernel_offset_, kernel_offset); #endif } @@ -3605,6 +3605,12 @@ class Script : public Object { } void set_compile_time_constants(const Array& value) const; + const uint8_t* kernel_data() { return raw_ptr()->kernel_data_; } + void set_kernel_data(const uint8_t* kernel_data) const; + + intptr_t kernel_data_size() { return raw_ptr()->kernel_data_size_; } + void set_kernel_data_size(const intptr_t kernel_data_size) const; + RawTypedData* kernel_string_offsets() const { return raw_ptr()->kernel_string_offsets_; } @@ -3843,13 +3849,13 @@ class Library : public Object { void AddClassMetadata(const Class& cls, const Object& tl_owner, TokenPosition token_pos, - kernel::TreeNode* kernel_node = NULL) const; + intptr_t kernel_offset = 0) const; void AddFieldMetadata(const Field& field, TokenPosition token_pos, - kernel::TreeNode* kernel_node = NULL) const; + intptr_t kernel_offset = 0) const; void AddFunctionMetadata(const Function& func, TokenPosition token_pos, - kernel::TreeNode* kernel_node = NULL) const; + intptr_t kernel_offset = 0) const; void AddLibraryMetadata(const Object& tl_owner, TokenPosition token_pos) const; void AddTypeParameterMetadata(const TypeParameter& param, @@ -4018,7 +4024,7 @@ class Library : public Object { void AddMetadata(const Object& owner, const String& name, TokenPosition token_pos, - kernel::TreeNode* kernel_node = NULL) const; + intptr_t kernel_offset = 0) const; FINAL_HEAP_OBJECT_IMPLEMENTATION(Library, Object); diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index c3f39cc83de..6f639387c12 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -235,47 +235,11 @@ void ParsedFunction::Bailout(const char* origin, const char* reason) const { kernel::ScopeBuildingResult* ParsedFunction::EnsureKernelScopes() { if (kernel_scopes_ == NULL) { - kernel::TreeNode* node = NULL; - if (function().kernel_function() != NULL) { - node = static_cast(function().kernel_function()); - } - - intptr_t kernel_offset = -1; - const uint8_t* kernel_data = NULL; - intptr_t kernel_data_size = 0; - if (node != NULL) { - kernel::TreeNode* library_node = node; - if (node != NULL) { - const Function* parent = &function(); - while (true) { - library_node = - static_cast(parent->kernel_function()); - while (library_node != NULL && !library_node->IsLibrary()) { - if (library_node->IsMember()) { - library_node = kernel::Member::Cast(library_node)->parent(); - } else if (library_node->IsClass()) { - library_node = kernel::Class::Cast(library_node)->parent(); - break; - } else { - library_node = NULL; - break; - } - } - if (library_node != NULL) break; - parent = &Function::Handle(parent->parent_function()); - } - } - if (library_node != NULL && library_node->IsLibrary()) { - kernel::Library* library = kernel::Library::Cast(library_node); - kernel_offset = node->kernel_offset(); - kernel_data = library->kernel_data(); - kernel_data_size = library->kernel_data_size(); - } - } - - kernel::StreamingScopeBuilder builder2(this, kernel_offset, kernel_data, - kernel_data_size); - kernel_scopes_ = builder2.BuildScopes(); + intptr_t kernel_offset = function().kernel_offset(); + Script& script = Script::Handle(Z, function().script()); + kernel::StreamingScopeBuilder builder( + this, kernel_offset, script.kernel_data(), script.kernel_data_size()); + kernel_scopes_ = builder.BuildScopes(); } return kernel_scopes_; } @@ -1664,7 +1628,7 @@ SequenceNode* Parser::ParseImplicitClosure(const Function& func) { ASSERT(func.num_fixed_parameters() == 2); // closure, value. } else if (!parent.IsGetterFunction() && !parent.IsImplicitGetterFunction()) { // NOTE: For the `kernel -> flowgraph` we don't use the parser. - if (parent.kernel_function() == NULL) { + if (parent.kernel_offset() <= 0) { SkipFunctionPreamble(); const bool use_function_type_syntax = false; const bool allow_explicit_default_values = true; diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc index 8b2ab1340ec..a4297ba7d81 100644 --- a/runtime/vm/precompiler.cc +++ b/runtime/vm/precompiler.cc @@ -1221,7 +1221,7 @@ RawFunction* Precompiler::CompileStaticInitializer(const Field& field, ParsedFunction* parsed_function; // Check if this field is coming from the Kernel binary. - if (field.kernel_field() != NULL) { + if (field.kernel_offset() > 0) { parsed_function = kernel::ParseStaticFieldInitializer(zone, field); } else { parsed_function = Parser::ParseStaticFieldInitializer(field); diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h index dec16dca569..07dfed28c95 100644 --- a/runtime/vm/precompiler.h +++ b/runtime/vm/precompiler.h @@ -108,8 +108,8 @@ class FunctionKeyValueTrait { static inline intptr_t Hashcode(Key key) { // We are using pointer hash for objects originating from Kernel because // Fasta currently does not assign any position information to them. - if (key->kernel_function() != NULL) { - return SimplePointerHash(key->kernel_function()); + if (key->kernel_offset() > 0) { + return key->kernel_offset(); } else { return key->token_pos().value(); } @@ -137,8 +137,8 @@ class FieldKeyValueTrait { static inline intptr_t Hashcode(Key key) { // We are using pointer hash for objects originating from Kernel because // Fasta currently does not assign any position information to them. - if (key->kernel_field() != NULL) { - return SimplePointerHash(key->kernel_field()); + if (key->kernel_offset() > 0) { + return key->kernel_offset(); } else { return key->token_pos().value(); } diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index d9b73be76e6..89e9999932e 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -893,7 +893,7 @@ class RawFunction : public RawObject { uint32_t kind_tag_; // See Function::KindTagBits. int16_t num_fixed_parameters_; int16_t num_optional_parameters_; // > 0: positional; < 0: named. - NOT_IN_PRECOMPILED(void* kernel_function_); + NOT_IN_PRECOMPILED(intptr_t kernel_offset_); NOT_IN_PRECOMPILED(uint16_t optimized_instruction_count_); NOT_IN_PRECOMPILED(uint16_t optimized_call_site_count_); NOT_IN_PRECOMPILED(int8_t deoptimization_counter_); @@ -1005,7 +1005,7 @@ class RawField : public RawObject { int8_t guarded_list_length_in_object_offset_; uint8_t kind_bits_; // static, final, const, has initializer.... - NOT_IN_PRECOMPILED(void* kernel_field_); + NOT_IN_PRECOMPILED(intptr_t kernel_offset_); friend class CidRewriteVisitor; }; @@ -1087,6 +1087,8 @@ class RawScript : public RawObject { int32_t col_offset_; int8_t kind_; // Of type Kind. int64_t load_timestamp_; + const uint8_t* kernel_data_; + intptr_t kernel_data_size_; }; diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc index c6104313fbb..6317a72d021 100644 --- a/runtime/vm/raw_object_snapshot.cc +++ b/runtime/vm/raw_object_snapshot.cc @@ -757,7 +757,7 @@ RawFunction* Function::ReadFrom(SnapshotReader* reader, func.set_deoptimization_counter(reader->Read()); func.set_optimized_instruction_count(reader->Read()); func.set_optimized_call_site_count(reader->Read()); - func.set_kernel_function(NULL); + func.set_kernel_offset(0); func.set_was_compiled(false); // Set all the object fields. @@ -863,7 +863,7 @@ RawField* Field::ReadFrom(SnapshotReader* reader, field.set_guarded_cid(reader->Read()); field.set_is_nullable(reader->Read()); field.set_kind_bits(reader->Read()); - field.set_kernel_field(NULL); + field.set_kernel_offset(0); // Set all the object fields. READ_OBJECT_FIELDS(field, field.raw()->from(), field.raw()->to_snapshot(kind),