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. |