| Index: runtime/vm/kernel_binary_flowgraph.cc
|
| diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc
|
| index 9e39c23f5ff2da11bbf27521d69b748cfae5cebc..c88ddce65eb74777894c05761bfd4fd69d1c7b92 100644
|
| --- a/runtime/vm/kernel_binary_flowgraph.cc
|
| +++ b/runtime/vm/kernel_binary_flowgraph.cc
|
| @@ -17,6 +17,1554 @@ namespace kernel {
|
| #define T (type_translator_)
|
| #define I Isolate::Current()
|
|
|
| +static bool IsStaticInitializer(const Function& function, Zone* zone) {
|
| + return (function.kind() == RawFunction::kImplicitStaticFinalGetter) &&
|
| + dart::String::Handle(zone, function.name())
|
| + .StartsWith(Symbols::InitPrefix());
|
| +}
|
| +
|
| +
|
| +StreamingScopeBuilder::StreamingScopeBuilder(ParsedFunction* parsed_function,
|
| + intptr_t kernel_offset,
|
| + const uint8_t* buffer,
|
| + intptr_t buffer_length)
|
| + : result_(NULL),
|
| + parsed_function_(parsed_function),
|
| + kernel_offset_(kernel_offset),
|
| + translation_helper_(Thread::Current()),
|
| + zone_(translation_helper_.zone()),
|
| + current_function_scope_(NULL),
|
| + scope_(NULL),
|
| + depth_(0),
|
| + name_index_(0),
|
| + needs_expr_temp_(false),
|
| + builder_(new StreamingFlowGraphBuilder(&translation_helper_,
|
| + zone_,
|
| + buffer,
|
| + buffer_length)),
|
| + type_translator_(builder_, /*finalize=*/true) {
|
| + Script& script = Script::Handle(Z, parsed_function->function().script());
|
| + H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets()));
|
| + H.SetStringData(TypedData::Handle(Z, script.kernel_string_data()));
|
| + H.SetCanonicalNames(TypedData::Handle(Z, script.kernel_canonical_names()));
|
| + type_translator_.active_class_ = &active_class_;
|
| +}
|
| +
|
| +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_;
|
| +
|
| + ASSERT(scope_ == NULL && depth_.loop_ == 0 && depth_.function_ == 0);
|
| + result_ = new (Z) ScopeBuildingResult();
|
| +
|
| + ParsedFunction* parsed_function = parsed_function_;
|
| + 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());
|
| + 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);
|
| +
|
| + LocalScope* enclosing_scope = NULL;
|
| + if (function.IsLocalFunction()) {
|
| + enclosing_scope = LocalScope::RestoreOuterScope(
|
| + ContextScope::Handle(Z, function.context_scope()));
|
| + }
|
| + current_function_scope_ = scope_ = new (Z) LocalScope(enclosing_scope, 0, 0);
|
| + scope_->set_begin_token_pos(function.token_pos());
|
| + scope_->set_end_token_pos(function.end_token_pos());
|
| +
|
| + LocalVariable* context_var = parsed_function->current_context_var();
|
| + context_var->set_is_forced_stack();
|
| + scope_->AddVariable(context_var);
|
| +
|
| + parsed_function->SetNodeSequence(
|
| + new SequenceNode(TokenPosition::kNoSource, scope_));
|
| +
|
| + intptr_t parent_offset = -1;
|
| + builder_->SetOffset(kernel_offset_);
|
| +
|
| + switch (function.kind()) {
|
| + case RawFunction::kClosureFunction:
|
| + case RawFunction::kRegularFunction:
|
| + case RawFunction::kGetterFunction:
|
| + 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();
|
| + }
|
| + word 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);
|
| + // NOTE: FunctionNode is not read entirely yet! It continues below the if.
|
| +
|
| + intptr_t pos = 0;
|
| + if (function.IsClosureFunction()) {
|
| + LocalVariable* variable = MakeVariable(
|
| + TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::ClosureParameter(), AbstractType::dynamic_type());
|
| + variable->set_is_forced_stack();
|
| + scope_->InsertParameterAt(pos++, variable);
|
| + } else if (!function.is_static()) {
|
| + // We use [is_static] instead of [IsStaticFunction] because the latter
|
| + // returns `false` for constructors.
|
| + dart::Class& klass = dart::Class::Handle(Z, function.Owner());
|
| + Type& klass_type = H.GetCanonicalType(klass);
|
| + LocalVariable* variable =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::This(), klass_type);
|
| + scope_->InsertParameterAt(pos++, variable);
|
| + result_->this_variable = variable;
|
| +
|
| + // We visit instance field initializers because they might contain
|
| + // [Let] expressions and we need to have a mapping.
|
| + if (tag == kConstructor) {
|
| + ASSERT(parent_offset >= 0);
|
| + AlternativeReadingScope alt(builder_->reader_, parent_offset);
|
| + 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++) {
|
| + intptr_t field_offset = builder_->ReaderOffset();
|
| + TokenPosition position;
|
| + TokenPosition end_position;
|
| + word flags;
|
| + 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();
|
| + if (!is_static && initializer_tag == kSomething) {
|
| + EnterScope(field_offset);
|
| + VisitExpression(); // read initializer.
|
| + ExitScope(position, end_position);
|
| + } else if (initializer_tag == kSomething) {
|
| + builder_->SkipExpression(); // read initializer.
|
| + }
|
| + }
|
| + }
|
| + } else if (function.IsFactory()) {
|
| + LocalVariable* variable = MakeVariable(
|
| + TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type());
|
| + scope_->InsertParameterAt(pos++, variable);
|
| + result_->type_arguments_variable = variable;
|
| + }
|
| +
|
| + // Continue reading FunctionNode.
|
| + builder_->SkipTypeParametersList(); // read type_parameters.
|
| + builder_->ReadUInt(); // read required_parameter_count.
|
| + AddPositionalAndNamedParameters(
|
| + pos); // read positional_parameters and named_parameters.
|
| +
|
| + // We generate a syntethic body for implicit closure functions - which
|
| + // will forward the call to the real function.
|
| + // -> see BuildGraphOfImplicitClosureFunction
|
| + if (!function.IsImplicitClosureFunction()) {
|
| + builder_->SetOffset(kernel_offset_);
|
| + first_body_token_position_ = TokenPosition::kNoSource;
|
| + VisitNode();
|
| +
|
| + // TODO(jensj): HACK: Push the begin token to after any parameters to
|
| + // avoid crash when breaking on definition line of async method in
|
| + // debugger. It seems that another scope needs to be added
|
| + // in which captures are made, but I can't make that work.
|
| + // This 'solution' doesn't crash, but I cannot see the parameters at
|
| + // that particular breakpoint either.
|
| + // Also push the end token to after the "}" to avoid crashing on
|
| + // stepping past the last line (to the "}" character).
|
| + if (first_body_token_position_.IsReal()) {
|
| + scope_->set_begin_token_pos(first_body_token_position_);
|
| + }
|
| + if (scope_->end_token_pos().IsReal()) {
|
| + scope_->set_end_token_pos(scope_->end_token_pos().Next());
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + case RawFunction::kImplicitGetter:
|
| + case RawFunction::kImplicitStaticFinalGetter:
|
| + case RawFunction::kImplicitSetter: {
|
| + ASSERT(builder_->PeekTag() == kField);
|
| + if (IsStaticInitializer(function, Z)) {
|
| + VisitNode();
|
| + break;
|
| + }
|
| + bool is_setter = function.IsImplicitSetterFunction();
|
| + bool is_method = !function.IsStaticFunction();
|
| + intptr_t pos = 0;
|
| + if (is_method) {
|
| + dart::Class& klass = dart::Class::Handle(Z, function.Owner());
|
| + Type& klass_type = H.GetCanonicalType(klass);
|
| + LocalVariable* variable =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::This(), klass_type);
|
| + scope_->InsertParameterAt(pos++, variable);
|
| + result_->this_variable = variable;
|
| + }
|
| + if (is_setter) {
|
| + result_->setter_value =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::Value(), AbstractType::dynamic_type());
|
| + scope_->InsertParameterAt(pos++, result_->setter_value);
|
| + }
|
| + break;
|
| + }
|
| + case RawFunction::kMethodExtractor: {
|
| + // Add a receiver parameter. Though it is captured, we emit code to
|
| + // explicitly copy it to a fixed offset in a freshly-allocated context
|
| + // instead of using the generic code for regular functions.
|
| + // Therefore, it isn't necessary to mark it as captured here.
|
| + dart::Class& klass = dart::Class::Handle(Z, function.Owner());
|
| + Type& klass_type = H.GetCanonicalType(klass);
|
| + LocalVariable* variable =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::This(), klass_type);
|
| + scope_->InsertParameterAt(0, variable);
|
| + result_->this_variable = variable;
|
| + break;
|
| + }
|
| + case RawFunction::kNoSuchMethodDispatcher:
|
| + case RawFunction::kInvokeFieldDispatcher:
|
| + for (intptr_t i = 0; i < function.NumParameters(); ++i) {
|
| + LocalVariable* variable = MakeVariable(
|
| + TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + dart::String::ZoneHandle(Z, function.ParameterNameAt(i)),
|
| + AbstractType::dynamic_type());
|
| + scope_->InsertParameterAt(i, variable);
|
| + }
|
| + break;
|
| + case RawFunction::kSignatureFunction:
|
| + case RawFunction::kIrregexpFunction:
|
| + UNREACHABLE();
|
| + }
|
| + if (needs_expr_temp_) {
|
| + scope_->AddVariable(parsed_function_->EnsureExpressionTemp());
|
| + }
|
| + parsed_function->AllocateVariables();
|
| +
|
| + 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) {
|
| + case kConstructor:
|
| + VisitConstructor();
|
| + return;
|
| + case kProcedure:
|
| + VisitProcedure();
|
| + return;
|
| + case kField:
|
| + VisitField();
|
| + return;
|
| + case kFunctionNode:
|
| + VisitFunctionNode();
|
| + return;
|
| + default:
|
| + UNIMPLEMENTED();
|
| + return;
|
| + }
|
| +}
|
| +
|
| +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();
|
| + ASSERT(parent_offset >= 0);
|
| + {
|
| + AlternativeReadingScope alt(builder_->reader_, parent_offset);
|
| + 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);
|
| + bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic;
|
| + builder_->SkipListOfExpressions(); // read annotations.
|
| + builder_->SkipDartType(); // read type.
|
| + Tag initializer_tag = builder_->ReadTag();
|
| + if (!is_static && initializer_tag == kSomething) {
|
| + VisitExpression(); // read initializer.
|
| + } else if (initializer_tag == kSomething) {
|
| + builder_->SkipExpression(); // read initializer.
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Visit children (note that there's no reason to visit the name).
|
| + VisitFunctionNode();
|
| + intptr_t list_length =
|
| + builder_->ReadListLength(); // read initializers list length.
|
| + for (intptr_t i = 0; i < list_length; i++) {
|
| + VisitInitializer();
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitProcedure() {
|
| + 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() {
|
| + 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).
|
| + if (tag == kSomething) {
|
| + VisitExpression(); // read initializer (part 2).
|
| + }
|
| +}
|
| +
|
| +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;
|
| + ReadFunctionNodeUntilTypeParameters(&async_marker_word,
|
| + &dart_async_marker_word);
|
| + FunctionNode::AsyncMarker async_marker =
|
| + static_cast<FunctionNode::AsyncMarker>(async_marker_word);
|
| + FunctionNode::AsyncMarker dart_async_marker =
|
| + static_cast<FunctionNode::AsyncMarker>(dart_async_marker_word);
|
| +
|
| + intptr_t list_length =
|
| + builder_->ReadListLength(); // read type_parameters list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + builder_->SkipStringReference(); // read ith name index.
|
| + VisitDartType(); // read ith bound.
|
| + }
|
| +
|
| + if (FLAG_causal_async_stacks &&
|
| + (dart_async_marker == FunctionNode::kAsync ||
|
| + dart_async_marker == FunctionNode::kAsyncStar)) {
|
| + LocalVariable* asyncStackTraceVar = MakeVariable(
|
| + TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::AsyncStackTraceVar(), AbstractType::dynamic_type());
|
| + scope_->AddVariable(asyncStackTraceVar);
|
| + }
|
| +
|
| + if (async_marker == FunctionNode::kSyncYielding) {
|
| + LocalScope* scope = parsed_function_->node_sequence()->scope();
|
| + intptr_t offset = parsed_function_->function().num_fixed_parameters();
|
| + for (intptr_t i = 0;
|
| + i < parsed_function_->function().NumOptionalPositionalParameters();
|
| + i++) {
|
| + scope->VariableAt(offset + i)->set_is_forced_stack();
|
| + }
|
| + }
|
| +
|
| + // Read (but don't visit) the positional and named parameters, because they've
|
| + // already been added to the scope.
|
| +
|
| + builder_->ReadUInt(); // read required_parameter_count.
|
| +
|
| + builder_->SkipListOfVariableDeclarations(); // read list of positionals.
|
| + builder_->SkipListOfVariableDeclarations(); // read list of named.
|
| + builder_->SkipDartType(); // read return type.
|
| +
|
| + if (builder_->ReadTag() == kSomething) {
|
| + PositionScope scope(builder_->reader_);
|
| + VisitStatement(); // Read body
|
| + first_body_token_position_ = builder_->reader_->min_position();
|
| + }
|
| +
|
| + // Ensure that :await_jump_var, :await_ctx_var, :async_op and
|
| + // :async_stack_trace are captured.
|
| + if (async_marker == FunctionNode::kSyncYielding) {
|
| + {
|
| + LocalVariable* temp = NULL;
|
| + LookupCapturedVariableByName(
|
| + (depth_.function_ == 0) ? &result_->yield_jump_variable : &temp,
|
| + Symbols::AwaitJumpVar());
|
| + }
|
| + {
|
| + LocalVariable* temp = NULL;
|
| + LookupCapturedVariableByName(
|
| + (depth_.function_ == 0) ? &result_->yield_context_variable : &temp,
|
| + Symbols::AwaitContextVar());
|
| + }
|
| + {
|
| + LocalVariable* temp =
|
| + scope_->LookupVariable(Symbols::AsyncOperation(), true);
|
| + if (temp != NULL) {
|
| + scope_->CaptureVariable(temp);
|
| + }
|
| + }
|
| + if (FLAG_causal_async_stacks) {
|
| + LocalVariable* temp =
|
| + scope_->LookupVariable(Symbols::AsyncStackTraceVar(), true);
|
| + if (temp != NULL) {
|
| + scope_->CaptureVariable(temp);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitInitializer() {
|
| + Tag tag = builder_->ReadTag();
|
| + switch (tag) {
|
| + case kInvalidInitializer:
|
| + return;
|
| + case kFieldInitializer:
|
| + builder_->SkipCanonicalNameReference(); // read field_reference.
|
| + VisitExpression(); // read value.
|
| + return;
|
| + case kSuperInitializer:
|
| + builder_->SkipCanonicalNameReference(); // read field_reference.
|
| + VisitArguments(); // read arguments.
|
| + return;
|
| + case kRedirectingInitializer:
|
| + builder_->SkipCanonicalNameReference(); // read field_reference.
|
| + VisitArguments(); // read arguments.
|
| + return;
|
| + case kLocalInitializer:
|
| + VisitVariableDeclaration(); // read variable.
|
| + return;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitExpression() {
|
| + uint8_t payload = 0;
|
| + Tag tag = builder_->ReadTag(&payload);
|
| + switch (tag) {
|
| + case kInvalidExpression:
|
| + return;
|
| + case kVariableGet: {
|
| + builder_->ReadPosition(); // read position.
|
| + intptr_t variable_kernel_offset =
|
| + builder_->ReadUInt(); // read kernel position.
|
| + builder_->ReadUInt(); // read relative variable index.
|
| + builder_->SkipOptionalDartType(); // read promoted type.
|
| + LookupVariable(variable_kernel_offset);
|
| + return;
|
| + }
|
| + case kSpecializedVariableGet: {
|
| + builder_->ReadPosition(); // read position.
|
| + intptr_t variable_kernel_offset =
|
| + builder_->ReadUInt(); // read kernel position.
|
| + LookupVariable(variable_kernel_offset);
|
| + return;
|
| + }
|
| + case kVariableSet: {
|
| + builder_->ReadPosition(); // read position.
|
| + intptr_t variable_kernel_offset =
|
| + builder_->ReadUInt(); // read kernel position.
|
| + builder_->ReadUInt(); // read relative variable index.
|
| + LookupVariable(variable_kernel_offset);
|
| + VisitExpression(); // read expression.
|
| + return;
|
| + }
|
| + case kSpecializedVariableSet: {
|
| + builder_->ReadPosition(); // read position.
|
| + intptr_t variable_kernel_offset =
|
| + builder_->ReadUInt(); // read kernel position.
|
| + LookupVariable(variable_kernel_offset);
|
| + VisitExpression(); // read expression.
|
| + return;
|
| + }
|
| + case kPropertyGet:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read receiver.
|
| + builder_->SkipName(); // read name.
|
| + // Read unused "interface_target_reference".
|
| + builder_->SkipCanonicalNameReference();
|
| + return;
|
| + case kPropertySet:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read receiver.
|
| + builder_->SkipName(); // read name.
|
| + VisitExpression(); // read value.
|
| + // read unused "interface_target_reference".
|
| + builder_->SkipCanonicalNameReference();
|
| + return;
|
| + case kDirectPropertyGet:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read receiver.
|
| + builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + return;
|
| + case kDirectPropertySet:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read receiver.
|
| + builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + VisitExpression(); // read value·
|
| + return;
|
| + case kStaticGet:
|
| + builder_->ReadPosition(); // read position.
|
| + builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + return;
|
| + case kStaticSet:
|
| + builder_->ReadPosition(); // read position.
|
| + builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + VisitExpression(); // read expression.
|
| + return;
|
| + case kMethodInvocation:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read receiver.
|
| + builder_->SkipName(); // read name.
|
| + VisitArguments(); // read arguments.
|
| + // read unused "interface_target_reference".
|
| + builder_->SkipCanonicalNameReference();
|
| + return;
|
| + case kDirectMethodInvocation:
|
| + VisitExpression(); // read receiver.
|
| + builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + VisitArguments(); // read arguments.
|
| + return;
|
| + case kStaticInvocation:
|
| + case kConstStaticInvocation:
|
| + builder_->ReadPosition(); // read position.
|
| + builder_->SkipCanonicalNameReference(); // read procedure_reference.
|
| + VisitArguments(); // read arguments.
|
| + return;
|
| + case kConstructorInvocation:
|
| + case kConstConstructorInvocation:
|
| + builder_->ReadPosition(); // read position.
|
| + builder_->SkipCanonicalNameReference(); // read target_reference.
|
| + VisitArguments(); // read arguments.
|
| + return;
|
| + case kNot:
|
| + VisitExpression(); // read expression.
|
| + return;
|
| + case kLogicalExpression:
|
| + needs_expr_temp_ = true;
|
| + VisitExpression(); // read left.
|
| + builder_->SkipBytes(1); // read operator.
|
| + VisitExpression(); // read right.
|
| + return;
|
| + case kConditionalExpression: {
|
| + needs_expr_temp_ = true;
|
| + VisitExpression(); // read condition.
|
| + VisitExpression(); // read then.
|
| + VisitExpression(); // read otherwise.
|
| + builder_->SkipOptionalDartType(); // read unused static type.
|
| + return;
|
| + }
|
| + case kStringConcatenation: {
|
| + builder_->ReadPosition(); // read position.
|
| + intptr_t list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitExpression(); // read ith expression.
|
| + }
|
| + return;
|
| + }
|
| + case kIsExpression:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read operand.
|
| + VisitDartType(); // read type.
|
| + return;
|
| + case kAsExpression:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read operand.
|
| + VisitDartType(); // read type.
|
| + return;
|
| + case kSymbolLiteral:
|
| + builder_->SkipStringReference(); // read index into string table.
|
| + return;
|
| + case kTypeLiteral:
|
| + VisitDartType(); // read type.
|
| + return;
|
| + case kThisExpression:
|
| + HandleSpecialLoad(&result_->this_variable, Symbols::This());
|
| + return;
|
| + case kRethrow:
|
| + builder_->ReadPosition(); // read position.
|
| + return;
|
| + case kThrow:
|
| + builder_->ReadPosition(); // read position.
|
| + VisitExpression(); // read expression.
|
| + return;
|
| + case kListLiteral:
|
| + case kConstListLiteral: {
|
| + builder_->ReadPosition(); // read position.
|
| + VisitDartType(); // read type.
|
| + intptr_t list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitExpression(); // read ith expression.
|
| + }
|
| + return;
|
| + }
|
| + case kMapLiteral:
|
| + case kConstMapLiteral: {
|
| + builder_->ReadPosition(); // read position.
|
| + VisitDartType(); // read key type.
|
| + VisitDartType(); // read value type.
|
| + intptr_t list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitExpression(); // read ith key.
|
| + VisitExpression(); // read ith value.
|
| + }
|
| + return;
|
| + }
|
| + case kFunctionExpression: {
|
| + intptr_t offset =
|
| + builder_->ReaderOffset() - 1; // -1 to include tag byte.
|
| + HandleLocalFunction(offset);
|
| + return;
|
| + }
|
| + case kLet: {
|
| + PositionScope scope(builder_->reader_);
|
| + intptr_t offset =
|
| + builder_->ReaderOffset() - 1; // -1 to include tag byte.
|
| +
|
| + EnterScope(offset);
|
| +
|
| + VisitVariableDeclaration(); // read variable declaration.
|
| + VisitExpression(); // read expression.
|
| +
|
| + ExitScope(builder_->reader_->min_position(),
|
| + builder_->reader_->max_position());
|
| + return;
|
| + }
|
| + case kBigIntLiteral:
|
| + builder_->SkipStringReference(); // read string reference.
|
| + return;
|
| + case kStringLiteral:
|
| + builder_->SkipStringReference(); // read string reference.
|
| + return;
|
| + case kSpecialIntLiteral:
|
| + return;
|
| + case kNegativeIntLiteral:
|
| + builder_->ReadUInt(); // read value.
|
| + return;
|
| + case kPositiveIntLiteral:
|
| + builder_->ReadUInt(); // read value.
|
| + return;
|
| + case kDoubleLiteral:
|
| + builder_->SkipStringReference(); // read index into string table.
|
| + return;
|
| + case kTrueLiteral:
|
| + return;
|
| + case kFalseLiteral:
|
| + return;
|
| + case kNullLiteral:
|
| + return;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitStatement() {
|
| + Tag tag = builder_->ReadTag(); // read tag.
|
| + switch (tag) {
|
| + case kInvalidStatement:
|
| + return;
|
| + case kExpressionStatement:
|
| + VisitExpression(); // read expression.
|
| + return;
|
| + case kBlock: {
|
| + PositionScope scope(builder_->reader_);
|
| + intptr_t offset =
|
| + builder_->ReaderOffset() - 1; // -1 to include tag byte.
|
| +
|
| + EnterScope(offset);
|
| +
|
| + intptr_t list_length =
|
| + builder_->ReadListLength(); // read number of statements.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitStatement(); // read ith statement.
|
| + }
|
| +
|
| + ExitScope(builder_->reader_->min_position(),
|
| + builder_->reader_->max_position());
|
| + return;
|
| + }
|
| + case kEmptyStatement:
|
| + return;
|
| + case kAssertStatement: {
|
| + if (I->asserts()) {
|
| + VisitExpression(); // Read condition.
|
| + Tag tag = builder_->ReadTag(); // read (first part of) message.
|
| + if (tag == kSomething) {
|
| + VisitExpression(); // read (rest of) message.
|
| + }
|
| + } else {
|
| + builder_->SkipExpression(); // Read condition.
|
| + Tag tag = builder_->ReadTag(); // read (first part of) message.
|
| + if (tag == kSomething) {
|
| + builder_->SkipExpression(); // read (rest of) message.
|
| + }
|
| + }
|
| + return;
|
| + }
|
| + case kLabeledStatement:
|
| + VisitStatement(); // read body.
|
| + return;
|
| + case kBreakStatement:
|
| + builder_->ReadPosition(); // read position.
|
| + builder_->ReadUInt(); // read target_index.
|
| + return;
|
| + case kWhileStatement:
|
| + ++depth_.loop_;
|
| + VisitExpression(); // read condition.
|
| + VisitStatement(); // read body.
|
| + --depth_.loop_;
|
| + return;
|
| + case kDoStatement:
|
| + ++depth_.loop_;
|
| + VisitStatement(); // read body.
|
| + VisitExpression(); // read condition.
|
| + --depth_.loop_;
|
| + return;
|
| + case kForStatement: {
|
| + PositionScope scope(builder_->reader_);
|
| +
|
| + intptr_t offset =
|
| + builder_->ReaderOffset() - 1; // -1 to include tag byte.
|
| +
|
| + EnterScope(offset);
|
| +
|
| + intptr_t list_length =
|
| + builder_->ReadListLength(); // read number of variables.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitVariableDeclaration(); // read ith variable.
|
| + }
|
| +
|
| + ++depth_.loop_;
|
| +
|
| + Tag tag = builder_->ReadTag(); // Read first part of condition.
|
| + if (tag == kSomething) {
|
| + VisitExpression(); // read rest of condition.
|
| + }
|
| + list_length = builder_->ReadListLength(); // read number of updates.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitExpression(); // read ith update.
|
| + }
|
| + VisitStatement(); // read body.
|
| +
|
| + --depth_.loop_;
|
| +
|
| + ExitScope(builder_->reader_->min_position(),
|
| + builder_->reader_->max_position());
|
| + return;
|
| + }
|
| + case kForInStatement:
|
| + case kAsyncForInStatement: {
|
| + PositionScope scope(builder_->reader_);
|
| +
|
| + intptr_t start_offset =
|
| + builder_->ReaderOffset() - 1; // -1 to include tag byte.
|
| +
|
| + TokenPosition position = builder_->ReadPosition(); // read position.
|
| +
|
| + // Notice the ordering: We skip the variable, read the iterable, go back,
|
| + // re-read the variable, go forward to after having read the iterable.
|
| + intptr_t offset = builder_->ReaderOffset();
|
| + builder_->SkipVariableDeclaration(); // read variable.
|
| + VisitExpression(); // read iterable.
|
| +
|
| + ++depth_.for_in_;
|
| + AddIteratorVariable();
|
| + ++depth_.loop_;
|
| + EnterScope(start_offset);
|
| +
|
| + {
|
| + AlternativeReadingScope alt(builder_->reader_, offset);
|
| + VisitVariableDeclaration(); // read variable.
|
| + }
|
| + VisitStatement(); // read body.
|
| +
|
| + if (!position.IsReal()) {
|
| + position = builder_->reader_->min_position();
|
| + }
|
| + // TODO(jensj): From kernel_binary.cc
|
| + // forinstmt->variable_->set_end_position(forinstmt->position_);
|
| + ExitScope(position, builder_->reader_->max_position());
|
| + --depth_.loop_;
|
| + --depth_.for_in_;
|
| + return;
|
| + }
|
| + case kSwitchStatement: {
|
| + AddSwitchVariable();
|
| + VisitExpression(); // read condition.
|
| + int num_cases = builder_->ReadListLength(); // read number of cases.
|
| + for (intptr_t i = 0; i < num_cases; ++i) {
|
| + int num_expressions =
|
| + builder_->ReadListLength(); // read number of expressions.
|
| + for (intptr_t j = 0; j < num_expressions; ++j) {
|
| + builder_->ReadPosition(); // read jth position.
|
| + VisitExpression(); // read jth expression.
|
| + }
|
| + builder_->ReadBool(); // read is_default.
|
| + VisitStatement(); // read body.
|
| + }
|
| + return;
|
| + }
|
| + case kContinueSwitchStatement:
|
| + builder_->ReadUInt(); // read target_index.
|
| + return;
|
| + case kIfStatement:
|
| + VisitExpression(); // read condition.
|
| + VisitStatement(); // read then.
|
| + VisitStatement(); // read otherwise.
|
| + return;
|
| + case kReturnStatement: {
|
| + if ((depth_.function_ == 0) && (depth_.finally_ > 0) &&
|
| + (result_->finally_return_variable == NULL)) {
|
| + const dart::String& name = H.DartSymbol(":try_finally_return_value");
|
| + LocalVariable* variable =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + name, AbstractType::dynamic_type());
|
| + current_function_scope_->AddVariable(variable);
|
| + result_->finally_return_variable = variable;
|
| + }
|
| +
|
| + builder_->ReadPosition(); // read position
|
| + Tag tag = builder_->ReadTag(); // read (first part of) expression.
|
| + if (tag == kSomething) {
|
| + VisitExpression(); // read (rest of) expression.
|
| + }
|
| + return;
|
| + }
|
| + case kTryCatch: {
|
| + ++depth_.try_;
|
| + AddTryVariables();
|
| + VisitStatement(); // read body.
|
| + --depth_.try_;
|
| +
|
| + ++depth_.catch_;
|
| + AddCatchVariables();
|
| +
|
| + builder_->ReadBool(); // read any_catch_needs_stack_trace.
|
| + intptr_t num_catches =
|
| + builder_->ReadListLength(); // read number of catches.
|
| + for (intptr_t i = 0; i < num_catches; ++i) {
|
| + PositionScope scope(builder_->reader_);
|
| + intptr_t offset = builder_->ReaderOffset(); // Catch has no tag.
|
| +
|
| + EnterScope(offset);
|
| +
|
| + builder_->SkipDartType(); // read guard.
|
| + tag = builder_->ReadTag(); // read first part of exception.
|
| + if (tag == kSomething) {
|
| + VisitVariableDeclaration(); // read exception.
|
| + }
|
| + tag = builder_->ReadTag(); // read first part of stack trace.
|
| + if (tag == kSomething) {
|
| + VisitVariableDeclaration(); // read stack trace.
|
| + }
|
| + VisitStatement(); // read body.
|
| +
|
| + ExitScope(builder_->reader_->min_position(),
|
| + builder_->reader_->max_position());
|
| + }
|
| + --depth_.catch_;
|
| + return;
|
| + }
|
| + case kTryFinally: {
|
| + ++depth_.try_;
|
| + ++depth_.finally_;
|
| + AddTryVariables();
|
| +
|
| + VisitStatement(); // read body.
|
| +
|
| + --depth_.finally_;
|
| + --depth_.try_;
|
| + ++depth_.catch_;
|
| + AddCatchVariables();
|
| +
|
| + VisitStatement(); // read finalizer.
|
| +
|
| + --depth_.catch_;
|
| + return;
|
| + }
|
| + case kYieldStatement: {
|
| + builder_->ReadPosition(); // read position.
|
| + word flags = builder_->ReadByte(); // read flags.
|
| + builder_->SkipExpression(); // read expression.
|
| +
|
| + ASSERT((flags & YieldStatement::kFlagNative) ==
|
| + YieldStatement::kFlagNative);
|
| + if (depth_.function_ == 0) {
|
| + AddSwitchVariable();
|
| + // Promote all currently visible local variables into the context.
|
| + // TODO(27590) CaptureLocalVariables promotes to many variables into
|
| + // the scope. Mark those variables as stack_local.
|
| + // TODO(27590) we don't need to promote those variables that are
|
| + // not used across yields.
|
| + scope_->CaptureLocalVariables(current_function_scope_);
|
| + }
|
| + return;
|
| + }
|
| + case kVariableDeclaration:
|
| + VisitVariableDeclaration(); // read variable declaration.
|
| + return;
|
| + case kFunctionDeclaration: {
|
| + intptr_t offset =
|
| + builder_->ReaderOffset() - 1; // -1 to include tag byte.
|
| + builder_->ReadPosition(); // read position.
|
| + VisitVariableDeclaration(); // read variable declaration.
|
| + HandleLocalFunction(offset); // read function node.
|
| + return;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitArguments() {
|
| + builder_->ReadUInt(); // read num_arguments.
|
| +
|
| + // Types
|
| + intptr_t list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitDartType(); // read ith type.
|
| + }
|
| +
|
| + // Positional.
|
| + list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + VisitExpression(); // read ith positional.
|
| + }
|
| +
|
| + // Named.
|
| + list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + builder_->SkipStringReference(); // read ith name index.
|
| + VisitExpression(); // read ith expression.
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitVariableDeclaration() {
|
| + PositionScope scope(builder_->reader_);
|
| +
|
| + intptr_t kernel_offset_no_tag = builder_->ReaderOffset();
|
| + TokenPosition position = builder_->ReadPosition(); // read position.
|
| + builder_->ReadPosition(); // read equals position.
|
| + word flags = builder_->ReadFlags(); // read flags.
|
| + bool is_final = (flags & VariableDeclaration::kFlagFinal) ==
|
| + VariableDeclaration::kFlagFinal;
|
| + StringIndex name_index = builder_->ReadStringReference(); // read name index.
|
| + intptr_t offset_for_type = builder_->ReaderOffset();
|
| + AbstractType& type = T.BuildVariableType(); // read type.
|
| +
|
| + // In case `declaration->IsConst()` the flow graph building will take care of
|
| + // evaluating the constant and setting it via
|
| + // `declaration->SetConstantValue()`.
|
| + const dart::String& name = (H.StringSize(name_index) == 0)
|
| + ? GenerateName(":var", name_index_++)
|
| + : H.DartSymbol(name_index);
|
| + // We also need to visit the type.
|
| + builder_->SetOffset(offset_for_type);
|
| + VisitDartType(); // read type.
|
| +
|
| + Tag tag = builder_->ReadTag(); // read (first part of) initializer.
|
| + if (tag == kSomething) {
|
| + VisitExpression(); // read (actual) initializer.
|
| + }
|
| +
|
| + // Go to next token position so it ends *after* the last potentially
|
| + // debuggable position in the initializer.
|
| + TokenPosition end_position = builder_->reader_->max_position();
|
| + if (end_position.IsReal()) {
|
| + end_position.Next();
|
| + }
|
| + LocalVariable* variable = MakeVariable(position, end_position, name, type);
|
| + if (is_final) {
|
| + variable->set_is_final();
|
| + }
|
| + scope_->AddVariable(variable);
|
| + result_->locals.Insert(kernel_offset_no_tag, variable);
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitDartType() {
|
| + Tag tag = builder_->ReadTag();
|
| + switch (tag) {
|
| + case kInvalidType:
|
| + case kDynamicType:
|
| + case kVoidType:
|
| + case kBottomType:
|
| + // those contain nothing.
|
| + return;
|
| + case kInterfaceType:
|
| + VisitInterfaceType(false);
|
| + return;
|
| + case kSimpleInterfaceType:
|
| + VisitInterfaceType(true);
|
| + return;
|
| + case kFunctionType:
|
| + VisitFunctionType(false);
|
| + return;
|
| + case kSimpleFunctionType:
|
| + VisitFunctionType(true);
|
| + return;
|
| + case kTypeParameterType:
|
| + VisitTypeParameterType();
|
| + return;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitInterfaceType(bool simple) {
|
| + builder_->ReadUInt(); // read klass_name.
|
| + if (!simple) {
|
| + intptr_t length = builder_->ReadListLength(); // read number of types.
|
| + for (intptr_t i = 0; i < length; ++i) {
|
| + VisitDartType(); // read the ith type.
|
| + }
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitFunctionType(bool simple) {
|
| + if (!simple) {
|
| + intptr_t list_length =
|
| + builder_->ReadListLength(); // read type_parameters list length.
|
| + for (int i = 0; i < list_length; ++i) {
|
| + builder_->SkipStringReference(); // read string index (name).
|
| + VisitDartType(); // read dart type.
|
| + }
|
| + builder_->ReadUInt(); // read required parameter count.
|
| + builder_->ReadUInt(); // read total parameter count.
|
| + }
|
| +
|
| + const intptr_t positional_count =
|
| + builder_->ReadListLength(); // read positional_parameters list length.
|
| + for (intptr_t i = 0; i < positional_count; ++i) {
|
| + VisitDartType(); // read ith positional parameter.
|
| + }
|
| +
|
| + if (!simple) {
|
| + const intptr_t named_count =
|
| + builder_->ReadListLength(); // read named_parameters list length.
|
| + for (intptr_t i = 0; i < named_count; ++i) {
|
| + // read string reference (i.e. named_parameters[i].name).
|
| + builder_->SkipStringReference();
|
| + VisitDartType(); // read named_parameters[i].type.
|
| + }
|
| + }
|
| +
|
| + VisitDartType(); // read return type.
|
| +}
|
| +
|
| +void StreamingScopeBuilder::VisitTypeParameterType() {
|
| + Function& function = Function::Handle(Z, parsed_function_->function().raw());
|
| + while (function.IsClosureFunction()) {
|
| + function = function.parent_function();
|
| + }
|
| +
|
| + if (function.IsFactory()) {
|
| + // The type argument vector is passed as the very first argument to the
|
| + // factory constructor function.
|
| + HandleSpecialLoad(&result_->type_arguments_variable,
|
| + Symbols::TypeArgumentsParameter());
|
| + } else {
|
| + // The type argument vector is stored on the instance object. We therefore
|
| + // need to capture `this`.
|
| + HandleSpecialLoad(&result_->this_variable, Symbols::This());
|
| + }
|
| +
|
| + builder_->ReadUInt(); // read index for parameter.
|
| + builder_->ReadUInt(); // read binary offset.
|
| + builder_->SkipOptionalDartType(); // read bound bound.
|
| +}
|
| +
|
| +void StreamingScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) {
|
| + // "Peek" ahead into the function node
|
| + intptr_t offset = builder_->ReaderOffset();
|
| +
|
| + Tag tag = builder_->ReadTag(); // read tag.
|
| + ASSERT(tag == kFunctionNode);
|
| + TokenPosition position = builder_->ReadPosition(); // read position.
|
| + TokenPosition end_position = builder_->ReadPosition(); // read end position.
|
| + FunctionNode::AsyncMarker async_marker =
|
| + static_cast<FunctionNode::AsyncMarker>(
|
| + builder_->ReadByte()); // read async marker.
|
| + builder_->ReadByte(); // read dart async marker.
|
| + builder_->SkipTypeParametersList(); // read type_parameters.
|
| +
|
| + LocalScope* saved_function_scope = current_function_scope_;
|
| + FunctionNode::AsyncMarker saved_function_async_marker =
|
| + current_function_async_marker_;
|
| + StreamingScopeBuilder::DepthState saved_depth_state = depth_;
|
| + depth_ = DepthState(depth_.function_ + 1);
|
| + EnterScope(parent_kernel_offset);
|
| + current_function_scope_ = scope_;
|
| + current_function_async_marker_ = async_marker;
|
| + if (depth_.function_ == 1) {
|
| + FunctionScope function_scope = {offset, scope_};
|
| + result_->function_scopes.Add(function_scope);
|
| + }
|
| +
|
| + builder_->ReadUInt(); // read required_parameter_count.
|
| + // read positional_parameters and named_parameters.
|
| + AddPositionalAndNamedParameters();
|
| +
|
| + // "Peek" is now done.
|
| + builder_->SetOffset(offset);
|
| +
|
| + VisitFunctionNode(); // read function node.
|
| +
|
| + ExitScope(position, end_position);
|
| + depth_ = saved_depth_state;
|
| + current_function_scope_ = saved_function_scope;
|
| + current_function_async_marker_ = saved_function_async_marker;
|
| +}
|
| +
|
| +void StreamingScopeBuilder::EnterScope(intptr_t kernel_offset) {
|
| + scope_ = new (Z) LocalScope(scope_, depth_.function_, depth_.loop_);
|
| + ASSERT(kernel_offset >= 0);
|
| + result_->scopes.Insert(kernel_offset, scope_);
|
| +}
|
| +
|
| +
|
| +void StreamingScopeBuilder::ExitScope(TokenPosition start_position,
|
| + TokenPosition end_position) {
|
| + scope_->set_begin_token_pos(start_position);
|
| + scope_->set_end_token_pos(end_position);
|
| + scope_ = scope_->parent();
|
| +}
|
| +
|
| +void StreamingScopeBuilder::AddPositionalAndNamedParameters(intptr_t pos) {
|
| + // List of positional.
|
| + intptr_t list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + AddVariableDeclarationParameter(pos++); // read ith positional parameter.
|
| + }
|
| +
|
| + // List of named.
|
| + list_length = builder_->ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + AddVariableDeclarationParameter(pos++); // read ith named parameter.
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::AddVariableDeclarationParameter(intptr_t pos) {
|
| + intptr_t kernel_offset = builder_->ReaderOffset(); // no tag.
|
| + TokenPosition position = builder_->ReadPosition(); // read position.
|
| + builder_->ReadPosition(); // read equals position.
|
| + word flags = builder_->ReadFlags(); // read flags.
|
| + bool is_final = (flags & VariableDeclaration::kFlagFinal) ==
|
| + VariableDeclaration::kFlagFinal;
|
| + String& name = H.DartSymbol(builder_->ReadStringReference()); // read name.
|
| + AbstractType& type = T.BuildVariableType(); // read type.
|
| +
|
| + LocalVariable* variable = MakeVariable(position, position, name, type);
|
| + if (is_final) {
|
| + variable->set_is_final();
|
| + }
|
| + if (variable->name().raw() == Symbols::IteratorParameter().raw()) {
|
| + variable->set_is_forced_stack();
|
| + }
|
| + scope_->InsertParameterAt(pos, variable);
|
| + result_->locals.Insert(kernel_offset, variable);
|
| +
|
| + // The default value may contain 'let' bindings for which the constant
|
| + // evaluator needs scope bindings.
|
| + Tag tag = builder_->ReadTag();
|
| + if (tag == kSomething) {
|
| + VisitExpression(); // read initializer.
|
| + }
|
| +}
|
| +
|
| +LocalVariable* StreamingScopeBuilder::MakeVariable(
|
| + TokenPosition declaration_pos,
|
| + TokenPosition token_pos,
|
| + const dart::String& name,
|
| + const AbstractType& type) {
|
| + return new (Z) LocalVariable(declaration_pos, token_pos, name, type);
|
| +}
|
| +
|
| +void StreamingScopeBuilder::AddExceptionVariable(
|
| + GrowableArray<LocalVariable*>* variables,
|
| + const char* prefix,
|
| + intptr_t nesting_depth) {
|
| + LocalVariable* v = NULL;
|
| +
|
| + // If we are inside a function with yield points then Kernel transformer
|
| + // could have lifted some of the auxiliary exception variables into the
|
| + // context to preserve them across yield points because they might
|
| + // be needed for rethrow.
|
| + // Check if it did and capture such variables instead of introducing
|
| + // new local ones.
|
| + // Note: function that wrap kSyncYielding function does not contain
|
| + // its own try/catches.
|
| + if (current_function_async_marker_ == FunctionNode::kSyncYielding) {
|
| + ASSERT(current_function_scope_->parent() != NULL);
|
| + v = current_function_scope_->parent()->LocalLookupVariable(
|
| + GenerateName(prefix, nesting_depth - 1));
|
| + if (v != NULL) {
|
| + scope_->CaptureVariable(v);
|
| + }
|
| + }
|
| +
|
| + // No need to create variables for try/catch-statements inside
|
| + // nested functions.
|
| + if (depth_.function_ > 0) return;
|
| + if (variables->length() >= nesting_depth) return;
|
| +
|
| + // If variable was not lifted by the transformer introduce a new
|
| + // one into the current function scope.
|
| + if (v == NULL) {
|
| + v = MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + GenerateName(prefix, nesting_depth - 1),
|
| + AbstractType::dynamic_type());
|
| +
|
| + // If transformer did not lift the variable then there is no need
|
| + // to lift it into the context when we encouter a YieldStatement.
|
| + v->set_is_forced_stack();
|
| + current_function_scope_->AddVariable(v);
|
| + }
|
| +
|
| + variables->Add(v);
|
| +}
|
| +
|
| +void StreamingScopeBuilder::AddTryVariables() {
|
| + AddExceptionVariable(&result_->catch_context_variables,
|
| + ":saved_try_context_var", depth_.try_);
|
| +}
|
| +
|
| +
|
| +void StreamingScopeBuilder::AddCatchVariables() {
|
| + AddExceptionVariable(&result_->exception_variables, ":exception",
|
| + depth_.catch_);
|
| + AddExceptionVariable(&result_->stack_trace_variables, ":stack_trace",
|
| + depth_.catch_);
|
| +}
|
| +
|
| +
|
| +void StreamingScopeBuilder::AddIteratorVariable() {
|
| + if (depth_.function_ > 0) return;
|
| + if (result_->iterator_variables.length() >= depth_.for_in_) return;
|
| +
|
| + ASSERT(result_->iterator_variables.length() == depth_.for_in_ - 1);
|
| + LocalVariable* iterator =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + GenerateName(":iterator", depth_.for_in_ - 1),
|
| + AbstractType::dynamic_type());
|
| + current_function_scope_->AddVariable(iterator);
|
| + result_->iterator_variables.Add(iterator);
|
| +}
|
| +
|
| +void StreamingScopeBuilder::AddSwitchVariable() {
|
| + if ((depth_.function_ == 0) && (result_->switch_variable == NULL)) {
|
| + LocalVariable* variable =
|
| + MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::SwitchExpr(), AbstractType::dynamic_type());
|
| + variable->set_is_forced_stack();
|
| + current_function_scope_->AddVariable(variable);
|
| + result_->switch_variable = variable;
|
| + }
|
| +}
|
| +
|
| +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) {
|
| + // We have not seen a declaration of the variable, so it must be the
|
| + // case that we are compiling a nested function and the variable is
|
| + // declared in an outer scope. In that case, look it up in the scope by
|
| + // name and add it to the variable map to simplify later lookup.
|
| + ASSERT(current_function_scope_->parent() != NULL);
|
| +
|
| + StringIndex var_name =
|
| + GetNameFromVariableDeclaration(declaration_binary_offest);
|
| +
|
| + const dart::String& name = H.DartSymbol(var_name);
|
| + variable = current_function_scope_->parent()->LookupVariable(name, true);
|
| + ASSERT(variable != NULL);
|
| + result_->locals.Insert(declaration_binary_offest, variable);
|
| + }
|
| +
|
| + if (variable->owner()->function_level() < scope_->function_level()) {
|
| + // We call `LocalScope->CaptureVariable(variable)` in two scenarios for two
|
| + // different reasons:
|
| + // Scenario 1:
|
| + // We need to know which variables defined in this function
|
| + // are closed over by nested closures in order to ensure we will
|
| + // create a [Context] object of appropriate size and store captured
|
| + // variables there instead of the stack.
|
| + // Scenario 2:
|
| + // We need to find out which variables defined in enclosing functions
|
| + // are closed over by this function/closure or nested closures. This
|
| + // is necessary in order to build a fat flattened [ContextScope]
|
| + // object.
|
| + scope_->CaptureVariable(variable);
|
| + } else {
|
| + ASSERT(variable->owner()->function_level() == scope_->function_level());
|
| + }
|
| +}
|
| +
|
| +const dart::String& StreamingScopeBuilder::GenerateName(const char* prefix,
|
| + intptr_t suffix) {
|
| + char name[64];
|
| + OS::SNPrint(name, 64, "%s%" Pd "", prefix, suffix);
|
| + return H.DartSymbol(name);
|
| +}
|
| +
|
| +void StreamingScopeBuilder::HandleSpecialLoad(LocalVariable** variable,
|
| + const dart::String& symbol) {
|
| + if (current_function_scope_->parent() != NULL) {
|
| + // We are building the scope tree of a closure function and saw [node]. We
|
| + // lazily populate the variable using the parent function scope.
|
| + if (*variable == NULL) {
|
| + *variable =
|
| + current_function_scope_->parent()->LookupVariable(symbol, true);
|
| + ASSERT(*variable != NULL);
|
| + }
|
| + }
|
| +
|
| + if ((current_function_scope_->parent() != NULL) ||
|
| + (scope_->function_level() > 0)) {
|
| + // Every scope we use the [variable] from needs to be notified of the usage
|
| + // in order to ensure that preserving the context scope on that particular
|
| + // use-site also includes the [variable].
|
| + scope_->CaptureVariable(*variable);
|
| + }
|
| +}
|
| +
|
| +void StreamingScopeBuilder::LookupCapturedVariableByName(
|
| + LocalVariable** variable,
|
| + const dart::String& name) {
|
| + if (*variable == NULL) {
|
| + *variable = scope_->LookupVariable(name, true);
|
| + ASSERT(*variable != NULL);
|
| + scope_->CaptureVariable(*variable);
|
| + }
|
| +}
|
|
|
| StreamingDartTypeTranslator::StreamingDartTypeTranslator(
|
| StreamingFlowGraphBuilder* builder,
|
| @@ -38,6 +1586,22 @@ AbstractType& StreamingDartTypeTranslator::BuildType() {
|
| return dart::AbstractType::ZoneHandle(Z, result_.raw());
|
| }
|
|
|
| +AbstractType& StreamingDartTypeTranslator::BuildVariableType() {
|
| + AbstractType& abstract_type = BuildType();
|
| +
|
| + // We return a new `ZoneHandle` here on purpose: The intermediate language
|
| + // instructions do not make a copy of the handle, so we do it.
|
| + AbstractType& type = Type::ZoneHandle(Z);
|
| +
|
| + if (abstract_type.IsMalformed()) {
|
| + type = AbstractType::dynamic_type().raw();
|
| + } else {
|
| + type = result_.raw();
|
| + }
|
| +
|
| + return type;
|
| +}
|
| +
|
| void StreamingDartTypeTranslator::BuildTypeInternal() {
|
| Tag tag = builder_->ReadTag();
|
| switch (tag) {
|
| @@ -105,13 +1669,12 @@ void StreamingDartTypeTranslator::BuildInterfaceType(bool simple) {
|
|
|
| void StreamingDartTypeTranslator::BuildFunctionType(bool simple) {
|
| intptr_t list_length = 0;
|
| - intptr_t* type_parameters = NULL;
|
| + intptr_t first_item_offest = -1;
|
| if (!simple) {
|
| list_length =
|
| builder_->ReadListLength(); // read type_parameters list length
|
| - type_parameters = new intptr_t[list_length];
|
| + first_item_offest = builder_->ReaderOffset();
|
| for (int i = 0; i < list_length; ++i) {
|
| - type_parameters[i] = builder_->ReaderOffset();
|
| builder_->SkipStringReference(); // read string index (name).
|
| builder_->SkipDartType(); // read dart type.
|
| }
|
| @@ -124,7 +1687,7 @@ void StreamingDartTypeTranslator::BuildFunctionType(bool simple) {
|
| // checker and the runtime unless explicitly specified otherwise.
|
| //
|
| // So we convert malformed return/parameter types to `dynamic`.
|
| - TypeParameterScope scope(this, type_parameters, list_length);
|
| + TypeParameterScope scope(this, first_item_offest, list_length);
|
|
|
| Function& signature_function = Function::ZoneHandle(
|
| Z, Function::NewSignatureFunction(*active_class_->klass,
|
| @@ -205,23 +1768,17 @@ void StreamingDartTypeTranslator::BuildFunctionType(bool simple) {
|
| result_ = signature_type.raw();
|
| }
|
|
|
| -static intptr_t FindTypeParameterIndex(intptr_t* parameters,
|
| - intptr_t parameters_count,
|
| - intptr_t look_for) {
|
| +intptr_t StreamingDartTypeTranslator::FindTypeParameterIndex(
|
| + intptr_t parameters_offset,
|
| + intptr_t parameters_count,
|
| + intptr_t look_for) {
|
| + AlternativeReadingScope alt(builder_->reader_, parameters_offset);
|
| for (intptr_t i = 0; i < parameters_count; ++i) {
|
| - if (look_for == parameters[i]) {
|
| - return i;
|
| - }
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -static intptr_t FindTypeParameterIndex(List<TypeParameter>* parameters,
|
| - intptr_t look_for) {
|
| - for (intptr_t i = 0; i < parameters->length(); ++i) {
|
| - if (look_for == (*parameters)[i]->kernel_offset()) {
|
| + if (look_for == builder_->ReaderOffset()) {
|
| return i;
|
| }
|
| + builder_->SkipStringReference(); // read string index (name).
|
| + builder_->SkipDartType(); // read dart type.
|
| }
|
| return -1;
|
| }
|
| @@ -240,17 +1797,15 @@ void StreamingDartTypeTranslator::BuildTypeParameterType() {
|
| for (TypeParameterScope* scope = type_parameter_scope_; scope != NULL;
|
| scope = scope->outer()) {
|
| const intptr_t index = FindTypeParameterIndex(
|
| - scope->parameters(), scope->parameters_count(), binary_offset);
|
| + scope->parameters_offset(), scope->parameters_count(), binary_offset);
|
| if (index >= 0) {
|
| result_ ^= dart::Type::DynamicType();
|
| return;
|
| }
|
| }
|
|
|
| - if ((active_class_->member != NULL) && active_class_->member->IsProcedure()) {
|
| - Procedure* procedure = Procedure::Cast(active_class_->member);
|
| - if ((procedure->function() != NULL) &&
|
| - (procedure->function()->type_parameters().length() > 0)) {
|
| + if (active_class_->member_is_procedure) {
|
| + if (active_class_->member_type_parameters > 0) {
|
| //
|
| // WARNING: This is a little hackish:
|
| //
|
| @@ -270,9 +1825,10 @@ void StreamingDartTypeTranslator::BuildTypeParameterType() {
|
| // }
|
| //
|
| const intptr_t index = FindTypeParameterIndex(
|
| - &procedure->function()->type_parameters(), binary_offset);
|
| + active_class_->member_type_parameters_offset_start,
|
| + active_class_->member_type_parameters, binary_offset);
|
| if (index >= 0) {
|
| - if (procedure->kind() == Procedure::kFactory) {
|
| + if (active_class_->member_is_factory_procedure) {
|
| // The index of the type parameter in [parameters] is
|
| // the same index into the `klass->type_parameters()` array.
|
| result_ ^= dart::TypeArguments::Handle(
|
| @@ -286,10 +1842,9 @@ void StreamingDartTypeTranslator::BuildTypeParameterType() {
|
| }
|
| }
|
|
|
| - ASSERT(active_class_->kernel_class != NULL);
|
| - List<TypeParameter>* parameters =
|
| - &active_class_->kernel_class->type_parameters();
|
| - const intptr_t index = FindTypeParameterIndex(parameters, binary_offset);
|
| + const intptr_t index = FindTypeParameterIndex(
|
| + active_class_->class_type_parameters_offset_start,
|
| + active_class_->class_type_parameters, binary_offset);
|
| if (index >= 0) {
|
| // The index of the type parameter in [parameters] is
|
| // the same index into the `klass->type_parameters()` array.
|
| @@ -323,6 +1878,10 @@ const TypeArguments& StreamingDartTypeTranslator::BuildTypeArguments(
|
| }
|
| if (result_.IsMalformed()) {
|
| type_arguments = TypeArguments::null();
|
| + // skip rest of arguments.
|
| + for (++i; i < length; ++i) {
|
| + builder_->SkipDartType();
|
| + }
|
| return type_arguments;
|
| }
|
| type_arguments.SetTypeAt(i, result_);
|
| @@ -348,8 +1907,7 @@ StreamingDartTypeTranslator::BuildInstantiatedTypeArguments(
|
| Type& type = Type::Handle(
|
| Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource));
|
| if (finalize_) {
|
| - type ^=
|
| - ClassFinalizer::FinalizeType(*builder_->active_class()->klass, type);
|
| + type ^= ClassFinalizer::FinalizeType(*active_class_->klass, type);
|
| }
|
|
|
| const TypeArguments& instantiated_type_arguments =
|
| @@ -387,8 +1945,12 @@ StreamingConstantEvaluator::StreamingConstantEvaluator(
|
| type_translator_(builder_->type_translator_),
|
| script_(Script::Handle(
|
| zone_,
|
| - builder == NULL ? Script::null()
|
| - : builder_->parsed_function()->function().script())),
|
| + // TODO(jensj): This was added to temporarily be able to let the scope
|
| + // builder have a StreamingFlowGraphBuilder to get access to
|
| + // reading functions.
|
| + (builder == NULL || builder_->flow_graph_builder_ == NULL)
|
| + ? Script::null()
|
| + : builder_->parsed_function()->function().script())),
|
| result_(Instance::Handle(zone_)) {}
|
|
|
|
|
| @@ -1280,7 +2842,7 @@ Fragment StreamingFlowGraphBuilder::BuildStatement() {
|
| case kYieldStatement:
|
| return BuildYieldStatement();
|
| case kVariableDeclaration:
|
| - return BuildVariableDeclaration(true);
|
| + return BuildVariableDeclaration();
|
| case kFunctionDeclaration:
|
| // TODO(jensj)
|
| UNIMPLEMENTED();
|
| @@ -1316,10 +2878,8 @@ uint32_t StreamingFlowGraphBuilder::ReadUInt() {
|
| }
|
|
|
| uint32_t StreamingFlowGraphBuilder::PeekUInt() {
|
| - intptr_t offset = ReaderOffset();
|
| - uint32_t result = reader_->ReadUInt();
|
| - SetOffset(offset);
|
| - return result;
|
| + AlternativeReadingScope alt(reader_);
|
| + return reader_->ReadUInt();
|
| }
|
|
|
| intptr_t StreamingFlowGraphBuilder::ReadListLength() {
|
| @@ -1427,30 +2987,18 @@ void StreamingFlowGraphBuilder::SkipOptionalDartType() {
|
| void StreamingFlowGraphBuilder::SkipInterfaceType(bool simple) {
|
| ReadUInt(); // read klass_name.
|
| if (!simple) {
|
| - intptr_t length = ReadListLength(); // read number of types.
|
| - for (intptr_t i = 0; i < length; ++i) {
|
| - SkipDartType(); // skip the ith type.
|
| - }
|
| + SkipListOfDartTypes(); // read list of types.
|
| }
|
| }
|
|
|
| void StreamingFlowGraphBuilder::SkipFunctionType(bool simple) {
|
| if (!simple) {
|
| - intptr_t list_length =
|
| - ReadListLength(); // read type_parameters list length.
|
| - for (int i = 0; i < list_length; ++i) {
|
| - SkipStringReference(); // read string index (name).
|
| - SkipDartType(); // read dart type.
|
| - }
|
| + SkipTypeParametersList(); // read type_parameters.
|
| ReadUInt(); // read required parameter count.
|
| ReadUInt(); // read total parameter count.
|
| }
|
|
|
| - const intptr_t positional_count =
|
| - ReadListLength(); // read positional_parameters list length.
|
| - for (intptr_t i = 0; i < positional_count; ++i) {
|
| - SkipDartType(); // read ith positional parameter.
|
| - }
|
| + SkipListOfDartTypes(); // read positional_parameters types.
|
|
|
| if (!simple) {
|
| const intptr_t named_count =
|
| @@ -1465,6 +3013,35 @@ void StreamingFlowGraphBuilder::SkipFunctionType(bool simple) {
|
| SkipDartType(); // read return type.
|
| }
|
|
|
| +void StreamingFlowGraphBuilder::SkipListOfExpressions() {
|
| + intptr_t list_length = ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + SkipExpression(); // read ith expression.
|
| + }
|
| +}
|
| +
|
| +void StreamingFlowGraphBuilder::SkipListOfDartTypes() {
|
| + intptr_t list_length = ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + SkipDartType(); // read ith type.
|
| + }
|
| +}
|
| +
|
| +void StreamingFlowGraphBuilder::SkipListOfVariableDeclarations() {
|
| + intptr_t list_length = ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + SkipVariableDeclaration(); // read ith variable declaration.
|
| + }
|
| +}
|
| +
|
| +void StreamingFlowGraphBuilder::SkipTypeParametersList() {
|
| + intptr_t list_length = ReadListLength(); // read list length.
|
| + for (intptr_t i = 0; i < list_length; ++i) {
|
| + SkipStringReference(); // read ith name index.
|
| + SkipDartType(); // read ith bound.
|
| + }
|
| +}
|
| +
|
| void StreamingFlowGraphBuilder::SkipExpression() {
|
| uint8_t payload = 0;
|
| Tag tag = ReadTag(&payload);
|
| @@ -1566,14 +3143,10 @@ void StreamingFlowGraphBuilder::SkipExpression() {
|
| SkipExpression(); // read otherwise.
|
| SkipOptionalDartType(); // read unused static type.
|
| return;
|
| - case kStringConcatenation: {
|
| + case kStringConcatenation:
|
| ReadPosition(); // read position.
|
| - intptr_t list_length = ReadListLength(); // read list length.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipExpression(); // read ith expression.
|
| - }
|
| + SkipListOfExpressions(); // read list of expressions.
|
| return;
|
| - }
|
| case kIsExpression:
|
| ReadPosition(); // read position.
|
| SkipExpression(); // read operand.
|
| @@ -1600,15 +3173,11 @@ void StreamingFlowGraphBuilder::SkipExpression() {
|
| SkipExpression(); // read expression.
|
| return;
|
| case kListLiteral:
|
| - case kConstListLiteral: {
|
| + case kConstListLiteral:
|
| ReadPosition(); // read position.
|
| SkipDartType(); // read type.
|
| - intptr_t list_length = ReadListLength(); // read list length.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipExpression(); // read ith expression.
|
| - }
|
| + SkipListOfExpressions(); // read list of expressions.
|
| return;
|
| - }
|
| case kMapLiteral:
|
| case kConstMapLiteral: {
|
| ReadPosition(); // read position.
|
| @@ -1622,8 +3191,7 @@ void StreamingFlowGraphBuilder::SkipExpression() {
|
| return;
|
| }
|
| case kFunctionExpression:
|
| - // TODO(jensj)
|
| - UNIMPLEMENTED();
|
| + SkipFunctionNode(); // read function node.
|
| return;
|
| case kLet:
|
| SkipVariableDeclaration(); // read variable declaration.
|
| @@ -1698,18 +3266,12 @@ void StreamingFlowGraphBuilder::SkipStatement() {
|
| SkipExpression(); // read condition.
|
| return;
|
| case kForStatement: {
|
| - intptr_t list_length = ReadListLength(); // read number of variables.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipVariableDeclaration(); // read ith variable.
|
| - }
|
| + SkipListOfVariableDeclarations(); // read variables.
|
| Tag tag = ReadTag(); // Read first part of condition.
|
| if (tag == kSomething) {
|
| SkipExpression(); // read rest of condition.
|
| }
|
| - list_length = ReadListLength(); // read number of updates.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipExpression(); // read ith update.
|
| - }
|
| + SkipListOfExpressions(); // read updates.
|
| SkipStatement(); // read body.
|
| return;
|
| }
|
| @@ -1753,8 +3315,8 @@ void StreamingFlowGraphBuilder::SkipStatement() {
|
| case kTryCatch: {
|
| SkipStatement(); // read body.
|
| ReadBool(); // read any_catch_needs_stack_trace.
|
| - intptr_t num_matches = ReadListLength(); // read number of catches.
|
| - for (intptr_t i = 0; i < num_matches; ++i) {
|
| + intptr_t num_catches = ReadListLength(); // read number of catches.
|
| + for (intptr_t i = 0; i < num_catches; ++i) {
|
| SkipDartType(); // read guard.
|
| tag = ReadTag(); // read first part of exception.
|
| if (tag == kSomething) {
|
| @@ -1778,17 +3340,38 @@ void StreamingFlowGraphBuilder::SkipStatement() {
|
| SkipExpression(); // read expression.
|
| return;
|
| case kVariableDeclaration:
|
| - SkipVariableDeclaration();
|
| + SkipVariableDeclaration(); // read variable declaration.
|
| return;
|
| case kFunctionDeclaration:
|
| - // TODO(jensj)
|
| - UNIMPLEMENTED();
|
| + ReadPosition(); // read position.
|
| + SkipVariableDeclaration(); // read variable.
|
| + SkipFunctionNode(); // read function node.
|
| return;
|
| default:
|
| UNREACHABLE();
|
| }
|
| }
|
|
|
| +void StreamingFlowGraphBuilder::SkipFunctionNode() {
|
| + Tag tag = ReadTag(); // read tag.
|
| + ASSERT(tag == kFunctionNode);
|
| +
|
| + ReadPosition(); // read position.
|
| + ReadPosition(); // read end position.
|
| + ReadByte(); // read async marker.
|
| + ReadByte(); // read dart async marker.
|
| + SkipTypeParametersList(); // read type_parameters.
|
| + ReadUInt(); // read required_parameter_count.
|
| +
|
| + SkipListOfVariableDeclarations(); // read list of positionals.
|
| + SkipListOfVariableDeclarations(); // read list of named.
|
| + SkipDartType(); // read return type.
|
| +
|
| + if (ReadTag() == kSomething) {
|
| + SkipStatement(); // Read body
|
| + }
|
| +}
|
| +
|
| void StreamingFlowGraphBuilder::SkipName() {
|
| StringIndex name_index = ReadStringReference(); // read name index.
|
| if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
|
| @@ -1799,20 +3382,11 @@ void StreamingFlowGraphBuilder::SkipName() {
|
| void StreamingFlowGraphBuilder::SkipArguments() {
|
| ReadUInt(); // read argument count.
|
|
|
| - // List of types.
|
| - intptr_t list_length = ReadListLength(); // read list length.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipDartType(); // read ith type.
|
| - }
|
| -
|
| - // List of positional.
|
| - list_length = ReadListLength(); // read list length.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipExpression(); // read ith expression.
|
| - }
|
| + SkipListOfDartTypes(); // read list of types.
|
| + SkipListOfExpressions(); // read positionals.
|
|
|
| // List of named.
|
| - list_length = ReadListLength(); // read list length.
|
| + intptr_t list_length = ReadListLength(); // read list length.
|
| for (intptr_t i = 0; i < list_length; ++i) {
|
| SkipStringReference(); // read ith name index.
|
| SkipExpression(); // read ith expression.
|
| @@ -1942,21 +3516,15 @@ Value* StreamingFlowGraphBuilder::Pop() {
|
|
|
| Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() {
|
| // read parts of arguments, then go back to before doing so.
|
| - intptr_t offset = ReaderOffset();
|
| + AlternativeReadingScope alt(reader_);
|
| ReadUInt(); // read number of arguments.
|
|
|
| - // List of types.
|
| - intptr_t list_length = ReadListLength(); // read list length.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipDartType(); // read ith type.
|
| - }
|
| + SkipListOfDartTypes(); // Read list of types.
|
|
|
| // List of positional.
|
| - list_length = ReadListLength(); // read list length.
|
| + intptr_t list_length = ReadListLength(); // read list length.
|
| for (intptr_t i = 0; i < list_length; ++i) {
|
| - Tag tag = ReadTag(); // read first tag.
|
| - SetOffset(offset); // reset offset.
|
| - return tag;
|
| + return ReadTag(); // read first tag.
|
| }
|
|
|
| UNREACHABLE();
|
| @@ -1966,13 +3534,10 @@ Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() {
|
| const TypeArguments& StreamingFlowGraphBuilder::PeekArgumentsInstantiatedType(
|
| const dart::Class& klass) {
|
| // read parts of arguments, then go back to before doing so.
|
| - intptr_t offset = ReaderOffset();
|
| + AlternativeReadingScope alt(reader_);
|
| ReadUInt(); // read argument count.
|
| intptr_t list_length = ReadListLength(); // read types list length.
|
| - const TypeArguments& type_arguments =
|
| - T.BuildInstantiatedTypeArguments(klass, list_length); // read types.
|
| - SetOffset(offset);
|
| - return type_arguments;
|
| + return T.BuildInstantiatedTypeArguments(klass, list_length); // read types.
|
| }
|
|
|
| intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() {
|
| @@ -1980,19 +3545,14 @@ intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() {
|
| }
|
|
|
| intptr_t StreamingFlowGraphBuilder::PeekArgumentsTypeCount() {
|
| - intptr_t offset = ReaderOffset();
|
| + AlternativeReadingScope alt(reader_);
|
| ReadUInt(); // read arguments count.
|
| - intptr_t types_count = ReadListLength(); // read length of types list.
|
| - SetOffset(offset);
|
| - return types_count;
|
| + return ReadListLength(); // read length of types list.
|
| }
|
|
|
| void StreamingFlowGraphBuilder::SkipArgumentsBeforeActualArguments() {
|
| ReadUInt(); // read arguments count.
|
| - intptr_t types_count = ReadListLength();
|
| - for (intptr_t i = 0; i < types_count; ++i) {
|
| - SkipDartType(); // read ith type.
|
| - }
|
| + SkipListOfDartTypes(); // read list of types.
|
| }
|
|
|
| LocalVariable* StreamingFlowGraphBuilder::LookupVariable(
|
| @@ -2182,11 +3742,9 @@ Fragment StreamingFlowGraphBuilder::TranslateFinallyFinalizers(
|
| intptr_t target_context_depth) {
|
| // TranslateFinallyFinalizers can move the readers offset.
|
| // Save the current position and restore it afterwards.
|
| - intptr_t offset = ReaderOffset();
|
| - Fragment result = flow_graph_builder_->TranslateFinallyFinalizers(
|
| - outer_finally, target_context_depth);
|
| - SetOffset(offset);
|
| - return result;
|
| + AlternativeReadingScope alt(reader_);
|
| + return flow_graph_builder_->TranslateFinallyFinalizers(outer_finally,
|
| + target_context_depth);
|
| }
|
|
|
| Fragment StreamingFlowGraphBuilder::BranchIfTrue(
|
| @@ -2308,10 +3866,7 @@ Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names,
|
| *argument_count = ReadUInt(); // read arguments count.
|
|
|
| // List of types.
|
| - intptr_t list_length = ReadListLength(); // read type count.
|
| - for (intptr_t i = 0; i < list_length; ++i) {
|
| - SkipDartType(); // read ith type.
|
| - }
|
| + SkipListOfDartTypes(); // read list of types.
|
|
|
| return BuildArgumentsFromActualArguments(argument_names, skip_push_arguments,
|
| do_drop);
|
| @@ -3316,7 +4871,7 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const,
|
| Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) {
|
| if (position != NULL) *position = TokenPosition::kNoSource;
|
|
|
| - Fragment instructions = BuildVariableDeclaration(false); // read variable.
|
| + Fragment instructions = BuildVariableDeclaration(); // read variable.
|
| instructions += BuildExpression(); // read body.
|
| return instructions;
|
| }
|
| @@ -3414,9 +4969,8 @@ Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() {
|
|
|
| Fragment StreamingFlowGraphBuilder::BuildAssertStatement() {
|
| if (!I->asserts()) {
|
| - intptr_t offset = ReaderOffset() - 1; // Include the tag.
|
| - SetOffset(offset);
|
| - SkipStatement(); // read this statement.
|
| + SetOffset(ReaderOffset() - 1); // Include the tag.
|
| + SkipStatement(); // read this statement.
|
| return Fragment();
|
| }
|
|
|
| @@ -3602,7 +5156,7 @@ Fragment StreamingFlowGraphBuilder::BuildForStatement() {
|
|
|
| intptr_t list_length = ReadListLength(); // read number of variables.
|
| for (intptr_t i = 0; i < list_length; ++i) {
|
| - declarations += BuildVariableDeclaration(false); // read ith variable.
|
| + declarations += BuildVariableDeclaration(); // read ith variable.
|
| }
|
|
|
| loop_depth_inc();
|
| @@ -4017,13 +5571,13 @@ Fragment StreamingFlowGraphBuilder::BuildTryCatch() {
|
| bool needs_stacktrace = ReadBool(); // read any_catch_needs_stack_trace
|
|
|
| catch_depth_inc();
|
| - intptr_t num_matches = ReadListLength(); // read number of catches.
|
| + intptr_t num_catches = ReadListLength(); // read number of catches.
|
| const Array& handler_types =
|
| - Array::ZoneHandle(Z, Array::New(num_matches, Heap::kOld));
|
| + Array::ZoneHandle(Z, Array::New(num_catches, Heap::kOld));
|
| Fragment catch_body =
|
| CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace);
|
| // Fill in the body of the catch.
|
| - for (intptr_t i = 0; i < num_matches; ++i) {
|
| + for (intptr_t i = 0; i < num_catches; ++i) {
|
| intptr_t catch_offset = ReaderOffset(); // Catch has no tag.
|
| Tag tag = PeekTag(); // peek guard type.
|
| AbstractType* type_guard = NULL;
|
| @@ -4280,9 +5834,9 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement() {
|
| return continuation;
|
| }
|
|
|
| -Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration(bool has_tag) {
|
| - intptr_t kernel_position = ReaderOffset() - (has_tag ? 1 : 0);
|
| - LocalVariable* variable = LookupVariable(kernel_position);
|
| +Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() {
|
| + intptr_t kernel_position_no_tag = ReaderOffset();
|
| + LocalVariable* variable = LookupVariable(kernel_position_no_tag);
|
|
|
| TokenPosition position = ReadPosition(); // read position.
|
| TokenPosition equals_position = ReadPosition(); // read equals position.
|
|
|