| Index: runtime/vm/kernel_binary_flowgraph.cc
|
| diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc
|
| index adcfcec719e3b803ee48ddef5a1239653079e14e..c88ddce65eb74777894c05761bfd4fd69d1c7b92 100644
|
| --- a/runtime/vm/kernel_binary_flowgraph.cc
|
| +++ b/runtime/vm/kernel_binary_flowgraph.cc
|
| @@ -4,7 +4,6 @@
|
|
|
| #include "vm/kernel_binary_flowgraph.h"
|
|
|
| -#include "vm/compiler.h"
|
| #include "vm/longjump.h"
|
| #include "vm/object_store.h"
|
|
|
| @@ -55,6 +54,27 @@ 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<TreeNode*>(outermost_function->kernel_function())
|
| + ->kernel_offset();
|
| + *parent_class_offset = GetParentOffset(*outermost_kernel_offset);
|
| + }
|
| +}
|
| +
|
| ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
|
| if (result_ != NULL) return result_;
|
|
|
| @@ -71,18 +91,16 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
|
| Function& outermost_function = Function::Handle(Z);
|
| intptr_t outermost_kernel_offset = -1;
|
| intptr_t parent_class_offset = -1;
|
| - builder_->DiscoverEnclosingElements(Z, function, &outermost_function,
|
| - &outermost_kernel_offset,
|
| - &parent_class_offset);
|
| + 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) {
|
| - builder_->GetTypeParameterInfoForClass(parent_class_offset,
|
| - &class_type_parameters,
|
| - &class_type_parameters_offset_start);
|
| + 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,
|
| @@ -92,7 +110,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
|
| bool is_factory_procedure = false;
|
| intptr_t member_type_parameters = 0;
|
| intptr_t member_type_parameters_offset_start = -1;
|
| - builder_->GetTypeParameterInfoForPossibleProcedure(
|
| + GetTypeParameterInfoForPossibleProcedure(
|
| outermost_kernel_offset, &member_is_procedure, &is_factory_procedure,
|
| &member_type_parameters, &member_type_parameters_offset_start);
|
|
|
| @@ -126,10 +144,27 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
|
| case RawFunction::kSetterFunction:
|
| case RawFunction::kConstructor: {
|
| const Tag tag = builder_->PeekTag();
|
| - parent_offset = builder_->ReadUntilFunctionNode();
|
| + 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();
|
| + }
|
| word async_marker_word;
|
| - builder_->ReadFunctionNodeUntilTypeParameters(
|
| - &unused_tokenposition, &unused_tokenposition, &async_marker_word,
|
| + ReadFunctionNodeUntilTypeParameters(
|
| + &async_marker_word,
|
| &unused_word); // read first part of function node.
|
| current_function_async_marker_ =
|
| static_cast<FunctionNode::AsyncMarker>(async_marker_word);
|
| @@ -158,7 +193,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
|
| if (tag == kConstructor) {
|
| ASSERT(parent_offset >= 0);
|
| AlternativeReadingScope alt(builder_->reader_, parent_offset);
|
| - builder_->ReadClassUntilFields(); // read first part of class.
|
| + 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++) {
|
| @@ -166,14 +201,12 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() {
|
| TokenPosition position;
|
| TokenPosition end_position;
|
| word flags;
|
| - builder_->ReadFieldUntilAnnotation(&unused_nameindex, &position,
|
| - &end_position, &flags,
|
| - &unused_intptr);
|
| + ReadFieldUntilAnnotation(&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(); // read first part of initializer.
|
| + Tag initializer_tag = builder_->ReadTag();
|
| if (!is_static && initializer_tag == kSomething) {
|
| EnterScope(field_offset);
|
| VisitExpression(); // read initializer.
|
| @@ -193,7 +226,6 @@ 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.
|
| @@ -287,6 +319,40 @@ 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) {
|
| @@ -308,25 +374,37 @@ 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 = builder_->ReadConstructorUntilFunctionNode();
|
| + intptr_t parent_offset = ReadConstructorUntilFunctionNode();
|
| ASSERT(parent_offset >= 0);
|
| {
|
| AlternativeReadingScope alt(builder_->reader_, parent_offset);
|
| - builder_->ReadClassUntilFields(); // read first part of class.
|
| + 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;
|
| - builder_->ReadFieldUntilAnnotation(
|
| - &unused_nameindex, &unused_tokenposition, &unused_tokenposition,
|
| - &flags, &unused_intptr);
|
| + ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition,
|
| + &flags, &unused_intptr);
|
| bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic;
|
| builder_->SkipListOfExpressions(); // read annotations.
|
| builder_->SkipDartType(); // read type.
|
| @@ -349,17 +427,34 @@ void StreamingScopeBuilder::VisitConstructor() {
|
| }
|
|
|
| void StreamingScopeBuilder::VisitProcedure() {
|
| - Tag function_node = builder_->ReadProcedureUntilFunctionNode(
|
| + Tag function_node = 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() {
|
| - builder_->ReadFieldUntilAnnotation(
|
| - &unused_nameindex, &unused_tokenposition, &unused_tokenposition,
|
| - &unused_intptr, &unused_word); // read first part of field.
|
| + ReadFieldUntilAnnotation(&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).
|
| @@ -368,12 +463,98 @@ 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<Procedure::ProcedureKind>(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;
|
| - builder_->ReadFunctionNodeUntilTypeParameters(
|
| - &unused_tokenposition, &unused_tokenposition, &async_marker_word,
|
| - &dart_async_marker_word);
|
| + ReadFunctionNodeUntilTypeParameters(&async_marker_word,
|
| + &dart_async_marker_word);
|
| FunctionNode::AsyncMarker async_marker =
|
| static_cast<FunctionNode::AsyncMarker>(async_marker_word);
|
| FunctionNode::AsyncMarker dart_async_marker =
|
| @@ -408,7 +589,6 @@ 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.
|
| @@ -463,11 +643,11 @@ void StreamingScopeBuilder::VisitInitializer() {
|
| VisitExpression(); // read value.
|
| return;
|
| case kSuperInitializer:
|
| - builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + builder_->SkipCanonicalNameReference(); // read field_reference.
|
| VisitArguments(); // read arguments.
|
| return;
|
| case kRedirectingInitializer:
|
| - builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + builder_->SkipCanonicalNameReference(); // read field_reference.
|
| VisitArguments(); // read arguments.
|
| return;
|
| case kLocalInitializer:
|
| @@ -1140,7 +1320,6 @@ 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();
|
| @@ -1302,6 +1481,16 @@ 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) {
|
| @@ -1312,7 +1501,7 @@ void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offest) {
|
| ASSERT(current_function_scope_->parent() != NULL);
|
|
|
| StringIndex var_name =
|
| - builder_->GetNameFromVariableDeclaration(declaration_binary_offest);
|
| + GetNameFromVariableDeclaration(declaration_binary_offest);
|
|
|
| const dart::String& name = H.DartSymbol(var_name);
|
| variable = current_function_scope_->parent()->LookupVariable(name, true);
|
| @@ -1397,17 +1586,6 @@ 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();
|
|
|
| @@ -2011,6 +2189,7 @@ 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)) {
|
| @@ -2408,1198 +2587,115 @@ RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall(
|
| 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);
|
| -}
|
| -
|
| -const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments(
|
| - const Function& target,
|
| - dart::Class* target_klass) {
|
| - intptr_t types_count = builder_->ReadListLength(); // read types count.
|
| -
|
| - const TypeArguments* type_arguments = NULL;
|
| - if (types_count > 0) {
|
| - type_arguments = &T.BuildInstantiatedTypeArguments(
|
| - *target_klass, types_count); // read types.
|
| -
|
| - 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;
|
| -}
|
| -
|
| -bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() {
|
| - EvaluateExpression(builder_->ReaderOffset(), false);
|
| - AssertBoolInCheckedMode();
|
| - return result_.raw() == Bool::True().raw();
|
| -}
|
| -
|
| -bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset,
|
| - Instance* value) {
|
| - if (builder_ == NULL || builder_->flow_graph_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(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 StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset,
|
| - const Instance& value) {
|
| - ASSERT(Thread::Current()->IsMutatorThread());
|
| -
|
| - if (builder_ == NULL || builder_->flow_graph_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<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew));
|
| - script_.set_compile_time_constants(array);
|
| - }
|
| - KernelConstantsMap constants(script_.compile_time_constants());
|
| - constants.InsertNewOrGetValue(kernel_offset, value);
|
| - 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();
|
| - }
|
| -
|
| - 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<Procedure::ProcedureKind>(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<const Instance*>* default_values =
|
| - new ZoneGrowableArray<const Instance*>(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.
|
| + instance.SetTypeArguments(
|
| + TypeArguments::Handle(Z, type_arguments.Canonicalize()));
|
| }
|
| + arg_values.SetAt(0, instance);
|
| } 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.
|
| - }
|
| + // Prepend type_arguments to list of arguments to factory.
|
| + ASSERT(type_arguments.IsZoneHandle());
|
| + arg_values.SetAt(0, type_arguments);
|
| }
|
| - 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;
|
| + 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);
|
| +}
|
|
|
| - 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();
|
| +const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments(
|
| + const Function& target,
|
| + dart::Class* target_klass) {
|
| + intptr_t types_count = builder_->ReadListLength(); // read types count.
|
|
|
| - // 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());
|
| - }
|
| + const TypeArguments* type_arguments = NULL;
|
| + if (types_count > 0) {
|
| + type_arguments = &T.BuildInstantiatedTypeArguments(
|
| + *target_klass, types_count); // read types.
|
|
|
| - // 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();
|
| + if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) {
|
| + H.ReportError("Type must be constant in const constructor.");
|
| }
|
| - } else {
|
| - UNIMPLEMENTED();
|
| + } 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 Fragment();
|
| + return type_arguments;
|
| }
|
|
|
| -FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) {
|
| - const Function& function = parsed_function()->function();
|
| +bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() {
|
| + EvaluateExpression(builder_->ReaderOffset(), false);
|
| + AssertBoolInCheckedMode();
|
| + return result_.raw() == Bool::True().raw();
|
| +}
|
|
|
| - // 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();
|
| +bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset,
|
| + Instance* value) {
|
| + if (builder_ == NULL) return false;
|
|
|
| - 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);
|
| + 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;
|
| }
|
|
|
| - 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);
|
| + 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(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;
|
| +}
|
|
|
| - 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());
|
| +void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset,
|
| + const Instance& value) {
|
| + ASSERT(Thread::Current()->IsMutatorThread());
|
|
|
| - SetOffset(kernel_offset);
|
| + if (builder_ == NULL) return;
|
|
|
| - 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;
|
| + 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;
|
| }
|
| - UNREACHABLE();
|
| - return NULL;
|
| + const intptr_t kInitialConstMapSize = 16;
|
| + ASSERT(!script_.InVMHeap());
|
| + if (script_.compile_time_constants() == Array::null()) {
|
| + const Array& array = Array::Handle(
|
| + HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew));
|
| + script_.set_compile_time_constants(array);
|
| + }
|
| + KernelConstantsMap constants(script_.compile_time_constants());
|
| + constants.InsertNewOrGetValue(kernel_offset, value);
|
| + script_.set_compile_time_constants(constants.Release());
|
| }
|
|
|
|
|
| +Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) {
|
| + SetOffset(kernel_offset);
|
| + return BuildExpression(); // read expression.
|
| +}
|
| +
|
| Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) {
|
| SetOffset(kernel_offset);
|
| return BuildStatement(); // read statement.
|
| @@ -3674,7 +2770,9 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
|
| case kConstMapLiteral:
|
| return BuildMapLiteral(true, position);
|
| case kFunctionExpression:
|
| - return BuildFunctionExpression();
|
| + // TODO(jensj)
|
| + UNIMPLEMENTED();
|
| + return Fragment();
|
| case kLet:
|
| return BuildLet(position);
|
| case kBigIntLiteral:
|
| @@ -3746,7 +2844,9 @@ Fragment StreamingFlowGraphBuilder::BuildStatement() {
|
| case kVariableDeclaration:
|
| return BuildVariableDeclaration();
|
| case kFunctionDeclaration:
|
| - return BuildFunctionDeclaration();
|
| + // TODO(jensj)
|
| + UNIMPLEMENTED();
|
| + return Fragment();
|
| default:
|
| UNREACHABLE();
|
| }
|
| @@ -4261,7 +3361,6 @@ 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.
|
| @@ -4386,10 +3485,6 @@ 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_;
|
| }
|
| @@ -5773,11 +4868,6 @@ 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;
|
|
|
| @@ -6785,372 +5875,6 @@ 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<FunctionNode::AsyncMarker>(async_marker_word);
|
| - FunctionNode::AsyncMarker dart_async_marker =
|
| - static_cast<FunctionNode::AsyncMarker>(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
|
|
|
|
|