|  | // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #include "vm/compiler/frontend/kernel_binary_flowgraph.h" | 
|  | #include "vm/compiler/aot/precompiler.h" | 
|  | #include "vm/compiler/frontend/prologue_builder.h" | 
|  | #include "vm/compiler/jit/compiler.h" | 
|  | #include "vm/longjump.h" | 
|  | #include "vm/object_store.h" | 
|  | #include "vm/resolver.h" | 
|  | #include "vm/stack_frame.h" | 
|  |  | 
|  | #if !defined(DART_PRECOMPILED_RUNTIME) | 
|  |  | 
|  | namespace dart { | 
|  | namespace kernel { | 
|  |  | 
|  | #define Z (zone_) | 
|  | #define H (translation_helper_) | 
|  | #define T (type_translator_) | 
|  | #define I Isolate::Current() | 
|  | #define B (flow_graph_builder_) | 
|  |  | 
|  | static bool IsFieldInitializer(const Function& function, Zone* zone) { | 
|  | return (function.kind() == RawFunction::kImplicitStaticFinalGetter) && | 
|  | String::Handle(zone, function.name()) | 
|  | .StartsWith(Symbols::InitPrefix()); | 
|  | } | 
|  |  | 
|  | void FunctionNodeHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kStart: { | 
|  | Tag tag = helper_->ReadTag();  // read tag. | 
|  | ASSERT(tag == kFunctionNode); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kPosition: | 
|  | position_ = helper_->ReadPosition();  // read position. | 
|  | if (++next_read_ == field) return; | 
|  | case kEndPosition: | 
|  | end_position_ = helper_->ReadPosition();  // read end position. | 
|  | if (++next_read_ == field) return; | 
|  | case kAsyncMarker: | 
|  | async_marker_ = static_cast<AsyncMarker>(helper_->ReadByte()); | 
|  | if (++next_read_ == field) return; | 
|  | case kDartAsyncMarker: | 
|  | dart_async_marker_ = static_cast<AsyncMarker>( | 
|  | helper_->ReadByte());  // read dart async marker. | 
|  | if (++next_read_ == field) return; | 
|  | case kTypeParameters: | 
|  | helper_->SkipTypeParametersList();  // read type parameters. | 
|  | if (++next_read_ == field) return; | 
|  | case kTotalParameterCount: | 
|  | total_parameter_count_ = | 
|  | helper_->ReadUInt();  // read total parameter count. | 
|  | if (++next_read_ == field) return; | 
|  | case kRequiredParameterCount: | 
|  | required_parameter_count_ = | 
|  | helper_->ReadUInt();  // read required parameter count. | 
|  | if (++next_read_ == field) return; | 
|  | case kPositionalParameters: | 
|  | helper_->SkipListOfVariableDeclarations();  // read positionals. | 
|  | if (++next_read_ == field) return; | 
|  | case kNamedParameters: | 
|  | helper_->SkipListOfVariableDeclarations();  // read named. | 
|  | if (++next_read_ == field) return; | 
|  | case kReturnType: | 
|  | helper_->SkipDartType();  // read return type. | 
|  | if (++next_read_ == field) return; | 
|  | case kBody: | 
|  | if (helper_->ReadTag() == kSomething) | 
|  | helper_->SkipStatement();  // read body. | 
|  | if (++next_read_ == field) return; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void TypeParameterHelper::ReadUntilExcluding(Field field) { | 
|  | for (; next_read_ < field; ++next_read_) { | 
|  | switch (next_read_) { | 
|  | case kFlags: | 
|  | flags_ = helper_->ReadFlags(); | 
|  | break; | 
|  | case kAnnotations: | 
|  | helper_->SkipListOfExpressions();  // read annotations. | 
|  | break; | 
|  | case kName: | 
|  | name_index_ = helper_->ReadStringReference();  // read name index. | 
|  | break; | 
|  | case kBound: | 
|  | helper_->SkipDartType(); | 
|  | break; | 
|  | case kDefaultType: | 
|  | if (helper_->ReadTag() == kSomething) { | 
|  | helper_->SkipDartType(); | 
|  | } | 
|  | break; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VariableDeclarationHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kPosition: | 
|  | position_ = helper_->ReadPosition();  // read position. | 
|  | if (++next_read_ == field) return; | 
|  | case kEqualPosition: | 
|  | equals_position_ = helper_->ReadPosition();  // read equals position. | 
|  | if (++next_read_ == field) return; | 
|  | case kAnnotations: | 
|  | helper_->SkipListOfExpressions();  // read annotations. | 
|  | if (++next_read_ == field) return; | 
|  | case kFlags: | 
|  | flags_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | case kNameIndex: | 
|  | name_index_ = helper_->ReadStringReference();  // read name index. | 
|  | if (++next_read_ == field) return; | 
|  | case kType: | 
|  | helper_->SkipDartType();  // read type. | 
|  | if (++next_read_ == field) return; | 
|  | case kInitializer: | 
|  | if (helper_->ReadTag() == kSomething) | 
|  | helper_->SkipExpression();  // read initializer. | 
|  | if (++next_read_ == field) return; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | FieldHelper::FieldHelper(KernelReaderHelper* helper, intptr_t offset) | 
|  | : helper_(helper), | 
|  | next_read_(kStart), | 
|  | has_function_literal_initializer_(false) { | 
|  | helper_->SetOffset(offset); | 
|  | } | 
|  |  | 
|  | void FieldHelper::ReadUntilExcluding(Field field, | 
|  | bool detect_function_literal_initializer) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kStart: { | 
|  | Tag tag = helper_->ReadTag();  // read tag. | 
|  | ASSERT(tag == kField); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kCanonicalName: | 
|  | canonical_name_ = | 
|  | helper_->ReadCanonicalNameReference();  // read canonical_name. | 
|  | if (++next_read_ == field) return; | 
|  | case kSourceUriIndex: | 
|  | source_uri_index_ = helper_->ReadUInt();  // read source_uri_index. | 
|  | helper_->set_current_script_id(source_uri_index_); | 
|  | if (++next_read_ == field) return; | 
|  | case kPosition: | 
|  | position_ = helper_->ReadPosition(false);  // read position. | 
|  | helper_->RecordTokenPosition(position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kEndPosition: | 
|  | end_position_ = helper_->ReadPosition(false);  // read end position. | 
|  | helper_->RecordTokenPosition(end_position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kFlags: | 
|  | flags_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | case kFlags2: | 
|  | secondary_flags_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | case kName: | 
|  | helper_->SkipName();  // read name. | 
|  | if (++next_read_ == field) return; | 
|  | case kAnnotations: { | 
|  | annotation_count_ = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < annotation_count_; ++i) { | 
|  | helper_->SkipExpression();  // read ith expression. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kType: | 
|  | helper_->SkipDartType();  // read type. | 
|  | if (++next_read_ == field) return; | 
|  | case kInitializer: | 
|  | if (helper_->ReadTag() == kSomething) { | 
|  | if (detect_function_literal_initializer && | 
|  | helper_->PeekTag() == kFunctionExpression) { | 
|  | AlternativeReadingScope alt(&helper_->reader_); | 
|  | Tag tag = helper_->ReadTag(); | 
|  | ASSERT(tag == kFunctionExpression); | 
|  | helper_->ReadPosition();  // read position. | 
|  |  | 
|  | FunctionNodeHelper helper(helper_); | 
|  | helper.ReadUntilIncluding(FunctionNodeHelper::kEndPosition); | 
|  |  | 
|  | has_function_literal_initializer_ = true; | 
|  | function_literal_start_ = helper.position_; | 
|  | function_literal_end_ = helper.end_position_; | 
|  | } | 
|  | helper_->SkipExpression();  // read initializer. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ProcedureHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kStart: { | 
|  | Tag tag = helper_->ReadTag();  // read tag. | 
|  | ASSERT(tag == kProcedure); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kCanonicalName: | 
|  | canonical_name_ = | 
|  | helper_->ReadCanonicalNameReference();  // read canonical_name. | 
|  | if (++next_read_ == field) return; | 
|  | case kSourceUriIndex: | 
|  | source_uri_index_ = helper_->ReadUInt();  // read source_uri_index. | 
|  | helper_->set_current_script_id(source_uri_index_); | 
|  | if (++next_read_ == field) return; | 
|  | case kPosition: | 
|  | position_ = helper_->ReadPosition(false);  // read position. | 
|  | helper_->RecordTokenPosition(position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kEndPosition: | 
|  | end_position_ = helper_->ReadPosition(false);  // read end position. | 
|  | helper_->RecordTokenPosition(end_position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kKind: | 
|  | kind_ = static_cast<Kind>(helper_->ReadByte()); | 
|  | if (++next_read_ == field) return; | 
|  | case kFlags: | 
|  | flags_ = helper_->ReadFlags(); | 
|  | flags2_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | case kName: | 
|  | helper_->SkipName();  // read name. | 
|  | if (++next_read_ == field) return; | 
|  | case kAnnotations: { | 
|  | annotation_count_ = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < annotation_count_; ++i) { | 
|  | helper_->SkipExpression();  // read ith expression. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kForwardingStubSuperTarget: | 
|  | if (helper_->ReadTag() == kSomething) { | 
|  | forwarding_stub_super_target_ = helper_->ReadCanonicalNameReference(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | case kForwardingStubInterfaceTarget: | 
|  | if (helper_->ReadTag() == kSomething) { | 
|  | helper_->ReadCanonicalNameReference(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | case kFunction: | 
|  | if (helper_->ReadTag() == kSomething) | 
|  | helper_->SkipFunctionNode();  // read function node. | 
|  | if (++next_read_ == field) return; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ConstructorHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kStart: { | 
|  | Tag tag = helper_->ReadTag();  // read tag. | 
|  | ASSERT(tag == kConstructor); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kCanonicalName: | 
|  | canonical_name_ = | 
|  | helper_->ReadCanonicalNameReference();  // read canonical_name. | 
|  | if (++next_read_ == field) return; | 
|  | case kSourceUriIndex: | 
|  | source_uri_index_ = helper_->ReadUInt();  // read source_uri_index. | 
|  | helper_->set_current_script_id(source_uri_index_); | 
|  | if (++next_read_ == field) return; | 
|  | case kPosition: | 
|  | position_ = helper_->ReadPosition();  // read position. | 
|  | helper_->RecordTokenPosition(position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kEndPosition: | 
|  | end_position_ = helper_->ReadPosition();  // read end position. | 
|  | helper_->RecordTokenPosition(end_position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kFlags: | 
|  | flags_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | case kName: | 
|  | helper_->SkipName();  // read name. | 
|  | if (++next_read_ == field) return; | 
|  | case kAnnotations: { | 
|  | annotation_count_ = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < annotation_count_; ++i) { | 
|  | helper_->SkipExpression();  // read ith expression. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kFunction: | 
|  | helper_->SkipFunctionNode();  // read function. | 
|  | if (++next_read_ == field) return; | 
|  | case kInitializers: { | 
|  | intptr_t list_length = | 
|  | helper_->ReadListLength();  // read initializers list length. | 
|  | for (intptr_t i = 0; i < list_length; i++) { | 
|  | helper_->SkipInitializer(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ClassHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kStart: { | 
|  | Tag tag = helper_->ReadTag();  // read tag. | 
|  | ASSERT(tag == kClass); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kCanonicalName: | 
|  | canonical_name_ = | 
|  | helper_->ReadCanonicalNameReference();  // read canonical_name. | 
|  | if (++next_read_ == field) return; | 
|  | case kSourceUriIndex: | 
|  | source_uri_index_ = helper_->ReadUInt();  // read source_uri_index. | 
|  | helper_->set_current_script_id(source_uri_index_); | 
|  | if (++next_read_ == field) return; | 
|  | case kPosition: | 
|  | position_ = helper_->ReadPosition(false);  // read position. | 
|  | helper_->RecordTokenPosition(position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kEndPosition: | 
|  | end_position_ = helper_->ReadPosition();  // read end position. | 
|  | helper_->RecordTokenPosition(end_position_); | 
|  | if (++next_read_ == field) return; | 
|  | case kFlags: | 
|  | flags_ = helper_->ReadFlags();  // read flags. | 
|  | if (++next_read_ == field) return; | 
|  | case kNameIndex: | 
|  | name_index_ = helper_->ReadStringReference();  // read name index. | 
|  | if (++next_read_ == field) return; | 
|  | case kAnnotations: { | 
|  | annotation_count_ = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < annotation_count_; ++i) { | 
|  | helper_->SkipExpression();  // read ith expression. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kTypeParameters: | 
|  | helper_->SkipTypeParametersList();  // read type parameters. | 
|  | if (++next_read_ == field) return; | 
|  | case kSuperClass: { | 
|  | Tag type_tag = helper_->ReadTag();  // read super class type (part 1). | 
|  | if (type_tag == kSomething) { | 
|  | helper_->SkipDartType();  // read super class type (part 2). | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kMixinType: { | 
|  | Tag type_tag = helper_->ReadTag();  // read mixin type (part 1). | 
|  | if (type_tag == kSomething) { | 
|  | helper_->SkipDartType();  // read mixin type (part 2). | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kImplementedClasses: | 
|  | helper_->SkipListOfDartTypes();  // read implemented_classes. | 
|  | if (++next_read_ == field) return; | 
|  | case kFields: { | 
|  | intptr_t list_length = | 
|  | helper_->ReadListLength();  // read fields list length. | 
|  | for (intptr_t i = 0; i < list_length; i++) { | 
|  | FieldHelper field_helper(helper_); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kEnd);  // read field. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kConstructors: { | 
|  | intptr_t list_length = | 
|  | helper_->ReadListLength();  // read constructors list length. | 
|  | for (intptr_t i = 0; i < list_length; i++) { | 
|  | ConstructorHelper constructor_helper(helper_); | 
|  | constructor_helper.ReadUntilExcluding( | 
|  | ConstructorHelper::kEnd);  // read constructor. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kProcedures: { | 
|  | procedure_count_ = helper_->ReadListLength();  // read procedures #. | 
|  | for (intptr_t i = 0; i < procedure_count_; i++) { | 
|  | ProcedureHelper procedure_helper(helper_); | 
|  | procedure_helper.ReadUntilExcluding( | 
|  | ProcedureHelper::kEnd);  // read procedure. | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kClassIndex: | 
|  | // Read class index. | 
|  | for (intptr_t i = 0; i < procedure_count_; ++i) { | 
|  | helper_->reader_.ReadUInt32(); | 
|  | } | 
|  | helper_->reader_.ReadUInt32(); | 
|  | helper_->reader_.ReadUInt32(); | 
|  | if (++next_read_ == field) return; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void LibraryHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kFlags: { | 
|  | flags_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kCanonicalName: | 
|  | canonical_name_ = | 
|  | helper_->ReadCanonicalNameReference();  // read canonical_name. | 
|  | if (++next_read_ == field) return; | 
|  | case kName: | 
|  | name_index_ = helper_->ReadStringReference();  // read name index. | 
|  | if (++next_read_ == field) return; | 
|  | case kSourceUriIndex: | 
|  | source_uri_index_ = helper_->ReadUInt();  // read source_uri_index. | 
|  | helper_->set_current_script_id(source_uri_index_); | 
|  | if (++next_read_ == field) return; | 
|  | case kAnnotations: | 
|  | helper_->SkipListOfExpressions();  // read annotations. | 
|  | if (++next_read_ == field) return; | 
|  | case kDependencies: { | 
|  | intptr_t dependency_count = helper_->ReadUInt();  // read list length. | 
|  | for (intptr_t i = 0; i < dependency_count; ++i) { | 
|  | helper_->SkipLibraryDependency(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kAdditionalExports: { | 
|  | intptr_t name_count = helper_->ReadUInt(); | 
|  | for (intptr_t i = 0; i < name_count; ++i) { | 
|  | helper_->SkipCanonicalNameReference(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kParts: { | 
|  | intptr_t part_count = helper_->ReadUInt();  // read list length. | 
|  | for (intptr_t i = 0; i < part_count; ++i) { | 
|  | helper_->SkipLibraryPart(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kTypedefs: { | 
|  | intptr_t typedef_count = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < typedef_count; i++) { | 
|  | helper_->SkipLibraryTypedef(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kClasses: { | 
|  | class_count_ = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < class_count_; ++i) { | 
|  | ClassHelper class_helper(helper_); | 
|  | class_helper.ReadUntilExcluding(ClassHelper::kEnd); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kToplevelField: { | 
|  | intptr_t field_count = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < field_count; ++i) { | 
|  | FieldHelper field_helper(helper_); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kEnd); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kToplevelProcedures: { | 
|  | procedure_count_ = helper_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < procedure_count_; ++i) { | 
|  | ProcedureHelper procedure_helper(helper_); | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kEnd); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kLibraryIndex: | 
|  | // Read library index. | 
|  | for (intptr_t i = 0; i < class_count_; ++i) { | 
|  | helper_->reader_.ReadUInt32(); | 
|  | } | 
|  | helper_->reader_.ReadUInt32(); | 
|  | helper_->reader_.ReadUInt32(); | 
|  | for (intptr_t i = 0; i < procedure_count_; ++i) { | 
|  | helper_->reader_.ReadUInt32(); | 
|  | } | 
|  | helper_->reader_.ReadUInt32(); | 
|  | helper_->reader_.ReadUInt32(); | 
|  | if (++next_read_ == field) return; | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void LibraryDependencyHelper::ReadUntilExcluding(Field field) { | 
|  | if (field <= next_read_) return; | 
|  |  | 
|  | // Ordered with fall-through. | 
|  | switch (next_read_) { | 
|  | case kFileOffset: { | 
|  | helper_->ReadPosition(); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kFlags: { | 
|  | flags_ = helper_->ReadFlags(); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kAnnotations: { | 
|  | helper_->SkipListOfExpressions(); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kTargetLibrary: { | 
|  | target_library_canonical_name_ = helper_->ReadCanonicalNameReference(); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kName: { | 
|  | name_index_ = helper_->ReadStringReference(); | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kCombinators: { | 
|  | intptr_t count = helper_->ReadListLength(); | 
|  | for (intptr_t i = 0; i < count; ++i) { | 
|  | // Skip flags | 
|  | helper_->SkipBytes(1); | 
|  | // Skip list of names. | 
|  | helper_->SkipListOfStrings(); | 
|  | } | 
|  | if (++next_read_ == field) return; | 
|  | } | 
|  | case kEnd: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | MetadataHelper::MetadataHelper(StreamingFlowGraphBuilder* builder) | 
|  | : builder_(builder), | 
|  | translation_helper_(builder->translation_helper_), | 
|  | mappings_offset_(0), | 
|  | mappings_num_(0), | 
|  | last_node_offset_(0), | 
|  | last_mapping_index_(0) {} | 
|  |  | 
|  | void MetadataHelper::SetMetadataMappings(intptr_t mappings_offset, | 
|  | intptr_t mappings_num) { | 
|  | ASSERT((mappings_offset_ == 0) && (mappings_num_ == 0)); | 
|  | ASSERT((mappings_offset != 0) && (mappings_num != 0)); | 
|  | mappings_offset_ = mappings_offset; | 
|  | mappings_num_ = mappings_num; | 
|  |  | 
|  | #ifdef DEBUG | 
|  | // Verify that node offsets are sorted. | 
|  | { | 
|  | Reader reader(H.metadata_mappings()); | 
|  | reader.set_offset(mappings_offset); | 
|  |  | 
|  | intptr_t prev_node_offset = 0; | 
|  | for (intptr_t i = 0; i < mappings_num; ++i) { | 
|  | intptr_t node_offset = reader.ReadUInt32(); | 
|  | intptr_t md_offset = reader.ReadUInt32(); | 
|  |  | 
|  | ASSERT((node_offset > 0) && (md_offset > 0)); | 
|  | ASSERT(node_offset > prev_node_offset); | 
|  | prev_node_offset = node_offset; | 
|  | } | 
|  | } | 
|  | #endif  // DEBUG | 
|  |  | 
|  | last_node_offset_ = kIntptrMax; | 
|  | last_mapping_index_ = 0; | 
|  | } | 
|  |  | 
|  | intptr_t MetadataHelper::FindMetadataMapping(intptr_t node_offset) { | 
|  | const intptr_t kUInt32Size = 4; | 
|  | ASSERT(mappings_num_ > 0); | 
|  |  | 
|  | Reader reader(H.metadata_mappings()); | 
|  |  | 
|  | intptr_t left = 0; | 
|  | intptr_t right = mappings_num_ - 1; | 
|  | while (left < right) { | 
|  | intptr_t mid = ((right - left) / 2) + left; | 
|  | intptr_t mid_node_offset = | 
|  | reader.ReadUInt32At(mappings_offset_ + mid * 2 * kUInt32Size); | 
|  |  | 
|  | if (node_offset < mid_node_offset) { | 
|  | right = mid - 1; | 
|  | } else if (node_offset > mid_node_offset) { | 
|  | left = mid + 1; | 
|  | } else { | 
|  | return mid;  // Exact match found. | 
|  | } | 
|  | } | 
|  | ASSERT((0 <= left) && (left <= mappings_num_)); | 
|  |  | 
|  | // Approximate match is found. Make sure it has an offset greater or equal | 
|  | // to the given node offset. | 
|  | if (left < mappings_num_) { | 
|  | intptr_t found_node_offset = | 
|  | reader.ReadUInt32At(mappings_offset_ + left * 2 * kUInt32Size); | 
|  |  | 
|  | if (found_node_offset < node_offset) { | 
|  | ++left; | 
|  | } | 
|  | } | 
|  | ASSERT((left == mappings_num_) || | 
|  | static_cast<intptr_t>(reader.ReadUInt32At( | 
|  | mappings_offset_ + left * 2 * kUInt32Size)) >= node_offset); | 
|  |  | 
|  | return left; | 
|  | } | 
|  |  | 
|  | intptr_t MetadataHelper::GetNextMetadataPayloadOffset(intptr_t node_offset) { | 
|  | builder_->EnsureMetadataIsScanned(); | 
|  |  | 
|  | if (mappings_num_ == 0) { | 
|  | return -1;  // No metadata. | 
|  | } | 
|  |  | 
|  | node_offset += builder_->data_program_offset_; | 
|  |  | 
|  | // Nodes are parsed in linear order most of the time, so do the search | 
|  | // only if looking back. | 
|  | if (node_offset < last_node_offset_) { | 
|  | last_mapping_index_ = FindMetadataMapping(node_offset); | 
|  | } | 
|  |  | 
|  | intptr_t index = last_mapping_index_; | 
|  | intptr_t mapping_node_offset = 0; | 
|  | intptr_t mapping_md_offset = 0; | 
|  |  | 
|  | Reader reader(H.metadata_mappings()); | 
|  | const intptr_t kUInt32Size = 4; | 
|  | reader.set_offset(mappings_offset_ + index * 2 * kUInt32Size); | 
|  |  | 
|  | for (; index < mappings_num_; ++index) { | 
|  | mapping_node_offset = reader.ReadUInt32(); | 
|  | mapping_md_offset = reader.ReadUInt32(); | 
|  |  | 
|  | if (mapping_node_offset >= node_offset) { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | last_mapping_index_ = index; | 
|  | last_node_offset_ = node_offset; | 
|  |  | 
|  | if ((index < mappings_num_) && (mapping_node_offset == node_offset)) { | 
|  | ASSERT(mapping_md_offset > 0); | 
|  | return mapping_md_offset; | 
|  | } else { | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool DirectCallMetadataHelper::ReadMetadata(intptr_t node_offset, | 
|  | NameIndex* target_name, | 
|  | bool* check_receiver_for_null) { | 
|  | intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset); | 
|  | if (md_offset < 0) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | AlternativeReadingScope alt(&builder_->reader_, &H.metadata_payloads(), | 
|  | md_offset - MetadataPayloadOffset); | 
|  |  | 
|  | *target_name = builder_->ReadCanonicalNameReference(); | 
|  | *check_receiver_for_null = builder_->ReadBool(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | DirectCallMetadata DirectCallMetadataHelper::GetDirectTargetForPropertyGet( | 
|  | intptr_t node_offset) { | 
|  | NameIndex kernel_name; | 
|  | bool check_receiver_for_null = false; | 
|  | if (!ReadMetadata(node_offset, &kernel_name, &check_receiver_for_null)) { | 
|  | return DirectCallMetadata(Function::null_function(), false); | 
|  | } | 
|  |  | 
|  | if (H.IsProcedure(kernel_name) && !H.IsGetter(kernel_name)) { | 
|  | // Tear-off. Use method extractor as direct call target. | 
|  | const String& method_name = H.DartMethodName(kernel_name); | 
|  | const Function& target_method = Function::ZoneHandle( | 
|  | builder_->zone_, | 
|  | builder_->LookupMethodByMember(kernel_name, method_name)); | 
|  | const String& getter_name = H.DartGetterName(kernel_name); | 
|  | return DirectCallMetadata( | 
|  | Function::ZoneHandle(builder_->zone_, | 
|  | target_method.GetMethodExtractor(getter_name)), | 
|  | check_receiver_for_null); | 
|  | } else { | 
|  | const String& getter_name = H.DartGetterName(kernel_name); | 
|  | const Function& target = Function::ZoneHandle( | 
|  | builder_->zone_, | 
|  | builder_->LookupMethodByMember(kernel_name, getter_name)); | 
|  | ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction()); | 
|  | return DirectCallMetadata(target, check_receiver_for_null); | 
|  | } | 
|  | } | 
|  |  | 
|  | DirectCallMetadata DirectCallMetadataHelper::GetDirectTargetForPropertySet( | 
|  | intptr_t node_offset) { | 
|  | NameIndex kernel_name; | 
|  | bool check_receiver_for_null = false; | 
|  | if (!ReadMetadata(node_offset, &kernel_name, &check_receiver_for_null)) { | 
|  | return DirectCallMetadata(Function::null_function(), false); | 
|  | } | 
|  |  | 
|  | const String& method_name = H.DartSetterName(kernel_name); | 
|  | const Function& target = Function::ZoneHandle( | 
|  | builder_->zone_, | 
|  | builder_->LookupMethodByMember(kernel_name, method_name)); | 
|  | ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction()); | 
|  |  | 
|  | return DirectCallMetadata(target, check_receiver_for_null); | 
|  | } | 
|  |  | 
|  | DirectCallMetadata DirectCallMetadataHelper::GetDirectTargetForMethodInvocation( | 
|  | intptr_t node_offset) { | 
|  | NameIndex kernel_name; | 
|  | bool check_receiver_for_null = false; | 
|  | if (!ReadMetadata(node_offset, &kernel_name, &check_receiver_for_null)) { | 
|  | return DirectCallMetadata(Function::null_function(), false); | 
|  | } | 
|  |  | 
|  | const String& method_name = H.DartProcedureName(kernel_name); | 
|  | const Function& target = Function::ZoneHandle( | 
|  | builder_->zone_, | 
|  | builder_->LookupMethodByMember(kernel_name, method_name)); | 
|  |  | 
|  | return DirectCallMetadata(target, check_receiver_for_null); | 
|  | } | 
|  |  | 
|  | bool ProcedureAttributesMetadataHelper::ReadMetadata( | 
|  | intptr_t node_offset, | 
|  | ProcedureAttributesMetadata* metadata) { | 
|  | intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset); | 
|  | if (md_offset < 0) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | AlternativeReadingScope alt(&builder_->reader_, &H.metadata_payloads(), | 
|  | md_offset - MetadataPayloadOffset); | 
|  |  | 
|  | const int kDynamicUsesBit = 1 << 0; | 
|  | const int kNonThisUsesBit = 1 << 1; | 
|  | const int kTearOffUsesBit = 1 << 2; | 
|  |  | 
|  | const uint8_t flags = builder_->ReadByte(); | 
|  | metadata->has_dynamic_invocations = | 
|  | (flags & kDynamicUsesBit) == kDynamicUsesBit; | 
|  | metadata->has_non_this_uses = (flags & kNonThisUsesBit) == kNonThisUsesBit; | 
|  | metadata->has_tearoff_uses = (flags & kTearOffUsesBit) == kTearOffUsesBit; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | ProcedureAttributesMetadata | 
|  | ProcedureAttributesMetadataHelper::GetProcedureAttributes( | 
|  | intptr_t node_offset) { | 
|  | ProcedureAttributesMetadata metadata; | 
|  | ReadMetadata(node_offset, &metadata); | 
|  | return metadata; | 
|  | } | 
|  |  | 
|  | InferredTypeMetadata InferredTypeMetadataHelper::GetInferredType( | 
|  | intptr_t node_offset) { | 
|  | const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset); | 
|  | if (md_offset < 0) { | 
|  | return InferredTypeMetadata(kDynamicCid, true); | 
|  | } | 
|  |  | 
|  | AlternativeReadingScope alt(&builder_->reader_, &H.metadata_payloads(), | 
|  | md_offset - MetadataPayloadOffset); | 
|  |  | 
|  | const NameIndex kernel_name = builder_->ReadCanonicalNameReference(); | 
|  | const bool nullable = builder_->ReadBool(); | 
|  |  | 
|  | if (H.IsRoot(kernel_name)) { | 
|  | return InferredTypeMetadata(kDynamicCid, nullable); | 
|  | } | 
|  |  | 
|  | const Class& klass = | 
|  | Class::Handle(builder_->zone_, H.LookupClassByKernelClass(kernel_name)); | 
|  | ASSERT(!klass.IsNull()); | 
|  |  | 
|  | intptr_t cid = klass.id(); | 
|  | if (cid == kClosureCid) { | 
|  | // VM uses more specific function types and doesn't expect instances of | 
|  | // _Closure class, so inferred _Closure class doesn't make sense for the VM. | 
|  | cid = kDynamicCid; | 
|  | } | 
|  |  | 
|  | return InferredTypeMetadata(cid, nullable); | 
|  | } | 
|  |  | 
|  | StreamingScopeBuilder::StreamingScopeBuilder(ParsedFunction* parsed_function) | 
|  | : result_(NULL), | 
|  | parsed_function_(parsed_function), | 
|  | 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_, | 
|  | Script::Handle(Z, parsed_function->function().script()), | 
|  | zone_, | 
|  | TypedData::Handle(Z, parsed_function->function().KernelData()), | 
|  | parsed_function->function().KernelDataProgramOffset())), | 
|  | type_translator_(builder_, /*finalize=*/true) { | 
|  | H.InitFromScript(builder_->script()); | 
|  | type_translator_.active_class_ = &active_class_; | 
|  | builder_->type_translator_.active_class_ = &active_class_; | 
|  | } | 
|  |  | 
|  | StreamingScopeBuilder::~StreamingScopeBuilder() { | 
|  | delete builder_; | 
|  | } | 
|  |  | 
|  | ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { | 
|  | if (result_ != NULL) return result_; | 
|  |  | 
|  | ASSERT(scope_ == NULL && depth_.loop_ == 0 && depth_.function_ == 0); | 
|  | result_ = new (Z) ScopeBuildingResult(); | 
|  |  | 
|  | const Function& function = parsed_function_->function(); | 
|  |  | 
|  | // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used | 
|  | // e.g. for type translation. | 
|  | const Class& klass = Class::Handle(zone_, function.Owner()); | 
|  |  | 
|  | Function& outermost_function = Function::Handle(Z); | 
|  | builder_->DiscoverEnclosingElements(Z, function, &outermost_function); | 
|  |  | 
|  | ActiveClassScope active_class_scope(&active_class_, &klass); | 
|  | ActiveMemberScope active_member(&active_class_, &outermost_function); | 
|  | ActiveTypeParametersScope active_type_params(&active_class_, function, Z); | 
|  |  | 
|  | LocalScope* enclosing_scope = NULL; | 
|  | if (function.IsImplicitClosureFunction() && !function.is_static()) { | 
|  | // Create artificial enclosing scope for the tear-off that contains | 
|  | // captured receiver value. This ensure that AssertAssignable will correctly | 
|  | // load instantiator type arguments if they are needed. | 
|  | Class& klass = Class::Handle(Z, function.Owner()); | 
|  | Type& klass_type = H.GetCanonicalType(klass); | 
|  | result_->this_variable = | 
|  | MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, | 
|  | Symbols::This(), klass_type); | 
|  | result_->this_variable->set_index(0); | 
|  | result_->this_variable->set_is_captured(); | 
|  | enclosing_scope = new (Z) LocalScope(NULL, 0, 0); | 
|  | enclosing_scope->set_context_level(0); | 
|  | enclosing_scope->AddVariable(result_->this_variable); | 
|  | } else 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()); | 
|  |  | 
|  | // Add function type arguments variable before current context variable. | 
|  | if (I->reify_generic_functions() && | 
|  | (function.IsGeneric() || function.HasGenericParent())) { | 
|  | LocalVariable* type_args_var = MakeVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, | 
|  | Symbols::FunctionTypeArgumentsVar(), AbstractType::dynamic_type()); | 
|  | scope_->AddVariable(type_args_var); | 
|  | parsed_function_->set_function_type_arguments(type_args_var); | 
|  | } | 
|  |  | 
|  | if (parsed_function_->has_arg_desc_var()) { | 
|  | needs_expr_temp_ = true; | 
|  | scope_->AddVariable(parsed_function_->arg_desc_var()); | 
|  | } | 
|  |  | 
|  | 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_)); | 
|  |  | 
|  | builder_->SetOffset(function.kernel_offset()); | 
|  |  | 
|  | FunctionNodeHelper function_node_helper(builder_); | 
|  | const ProcedureAttributesMetadata attrs = | 
|  | builder_->procedure_attributes_metadata_helper_.GetProcedureAttributes( | 
|  | function.kernel_offset()); | 
|  |  | 
|  | switch (function.kind()) { | 
|  | case RawFunction::kClosureFunction: | 
|  | case RawFunction::kImplicitClosureFunction: | 
|  | case RawFunction::kConvertedClosureFunction: | 
|  | case RawFunction::kRegularFunction: | 
|  | case RawFunction::kGetterFunction: | 
|  | case RawFunction::kSetterFunction: | 
|  | case RawFunction::kConstructor: { | 
|  | const Tag tag = builder_->PeekTag(); | 
|  | builder_->ReadUntilFunctionNode(); | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  | current_function_async_marker_ = function_node_helper.async_marker_; | 
|  | // NOTE: FunctionNode is read further below the if. | 
|  |  | 
|  | intptr_t pos = 0; | 
|  | if (function.IsClosureFunction()) { | 
|  | LocalVariable* closure_parameter = MakeVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, | 
|  | Symbols::ClosureParameter(), AbstractType::dynamic_type()); | 
|  | closure_parameter->set_is_forced_stack(); | 
|  | scope_->InsertParameterAt(pos++, closure_parameter); | 
|  | } else if (!function.is_static()) { | 
|  | // We use [is_static] instead of [IsStaticFunction] because the latter | 
|  | // returns `false` for constructors. | 
|  | Class& klass = 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) { | 
|  | Class& parent_class = Class::Handle(Z, function.Owner()); | 
|  | Array& class_fields = Array::Handle(Z, parent_class.fields()); | 
|  | Field& class_field = Field::Handle(Z); | 
|  | for (intptr_t i = 0; i < class_fields.Length(); ++i) { | 
|  | class_field ^= class_fields.At(i); | 
|  | if (!class_field.is_static()) { | 
|  | TypedData& kernel_data = | 
|  | TypedData::Handle(Z, class_field.KernelData()); | 
|  | ASSERT(!kernel_data.IsNull()); | 
|  | intptr_t field_offset = class_field.kernel_offset(); | 
|  | AlternativeReadingScope alt(&builder_->reader_, &kernel_data, | 
|  | field_offset); | 
|  | FieldHelper field_helper(builder_); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); | 
|  | Tag initializer_tag = | 
|  | builder_->ReadTag();  // read first part of initializer. | 
|  | if (initializer_tag == kSomething) { | 
|  | EnterScope(field_offset); | 
|  | VisitExpression();  // read initializer. | 
|  | ExitScope(field_helper.position_, field_helper.end_position_); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } 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; | 
|  | } | 
|  |  | 
|  | ParameterTypeCheckMode type_check_mode = kTypeCheckAllParameters; | 
|  | if (function.IsNonImplicitClosureFunction()) { | 
|  | type_check_mode = kTypeCheckAllParameters; | 
|  | } else if (function.IsImplicitClosureFunction()) { | 
|  | if (!attrs.has_dynamic_invocations) { | 
|  | // This is a tear-off of an instance method that can not be reached | 
|  | // from any dynamic invocation. The method would not check any | 
|  | // parameters except covariant ones and those annotated with | 
|  | // generic-covariant-impl. Which means that we have to check | 
|  | // the rest in the tear-off itself.. | 
|  | type_check_mode = kTypeCheckForTearOffOfNonDynamicallyInvokedMethod; | 
|  | } | 
|  | } else { | 
|  | if (function.is_static()) { | 
|  | // In static functions we don't check anything. | 
|  | type_check_mode = kTypeCheckForStaticFunction; | 
|  | } else if (!attrs.has_dynamic_invocations) { | 
|  | // If the current function is never a target of a dynamic invocation | 
|  | // and this parameter is not marked with generic-covariant-impl | 
|  | // (which means that among all super-interfaces no type parameters | 
|  | // ever occur at the position of this parameter) then we don't need | 
|  | // to check this parameter on the callee side, because strong mode | 
|  | // guarantees that it was checked at the caller side. | 
|  | type_check_mode = kTypeCheckForNonDynamicallyInvokedMethod; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Continue reading FunctionNode: | 
|  | // read positional_parameters and named_parameters. | 
|  | AddPositionalAndNamedParameters(pos, type_check_mode, attrs); | 
|  |  | 
|  | // We generate a synthetic body for implicit closure functions - which | 
|  | // will forward the call to the real function. | 
|  | //     -> see BuildGraphOfImplicitClosureFunction | 
|  | if (!function.IsImplicitClosureFunction()) { | 
|  | builder_->SetOffset(function.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 (IsFieldInitializer(function, Z)) { | 
|  | VisitNode(); | 
|  | break; | 
|  | } | 
|  | const bool is_setter = function.IsImplicitSetterFunction(); | 
|  | const bool is_method = !function.IsStaticFunction(); | 
|  | intptr_t pos = 0; | 
|  | if (is_method) { | 
|  | Class& klass = 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::ZoneHandle(Z, function.ParameterTypeAt(pos))); | 
|  | scope_->InsertParameterAt(pos++, result_->setter_value); | 
|  |  | 
|  | if (is_method && !attrs.has_dynamic_invocations) { | 
|  | FieldHelper field_helper(builder_); | 
|  | field_helper.ReadUntilIncluding(FieldHelper::kFlags); | 
|  |  | 
|  | if (!field_helper.IsCovariant() && | 
|  | (!field_helper.IsGenericCovariantImpl() || | 
|  | (!attrs.has_non_this_uses && !attrs.has_tearoff_uses))) { | 
|  | result_->setter_value->set_type_check_mode( | 
|  | LocalVariable::kTypeCheckedByCaller); | 
|  | } | 
|  | } | 
|  | } | 
|  | 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. | 
|  | Class& klass = 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, | 
|  | 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_ || function.is_no_such_method_forwarder()) { | 
|  | scope_->AddVariable(parsed_function_->EnsureExpressionTemp()); | 
|  | } | 
|  | parsed_function_->AllocateVariables(); | 
|  |  | 
|  | return result_; | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::ReportUnexpectedTag(const char* variant, Tag tag) { | 
|  | H.ReportError(builder_->script(), TokenPosition::kNoSource, | 
|  | "Unexpected tag %d (%s) in %s, expected %s", tag, | 
|  | Reader::TagName(tag), | 
|  | parsed_function_->function().ToQualifiedCString(), variant); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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. | 
|  | ConstructorHelper constructor_helper(builder_); | 
|  | constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction); | 
|  | { | 
|  | const Function& function = parsed_function_->function(); | 
|  | Class& parent_class = Class::Handle(Z, function.Owner()); | 
|  | Array& class_fields = Array::Handle(Z, parent_class.fields()); | 
|  | Field& class_field = Field::Handle(Z); | 
|  | for (intptr_t i = 0; i < class_fields.Length(); ++i) { | 
|  | class_field ^= class_fields.At(i); | 
|  | if (!class_field.is_static()) { | 
|  | TypedData& kernel_data = TypedData::Handle(Z, class_field.KernelData()); | 
|  | ASSERT(!kernel_data.IsNull()); | 
|  | intptr_t field_offset = class_field.kernel_offset(); | 
|  | AlternativeReadingScope alt(&builder_->reader_, &kernel_data, | 
|  | field_offset); | 
|  | FieldHelper field_helper(builder_); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); | 
|  | Tag initializer_tag = builder_->ReadTag(); | 
|  | if (initializer_tag == kSomething) { | 
|  | VisitExpression();  // 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() { | 
|  | ProcedureHelper procedure_helper(builder_); | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); | 
|  | if (builder_->ReadTag() == kSomething) { | 
|  | VisitFunctionNode(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitField() { | 
|  | FieldHelper field_helper(builder_); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kType); | 
|  | VisitDartType();                // read type. | 
|  | Tag tag = builder_->ReadTag();  // read initializer (part 1). | 
|  | if (tag == kSomething) { | 
|  | VisitExpression();  // read initializer (part 2). | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitFunctionNode() { | 
|  | FunctionNodeHelper function_node_helper(builder_); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  |  | 
|  | intptr_t list_length = | 
|  | builder_->ReadListLength();  // read type_parameters list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | TypeParameterHelper helper(builder_); | 
|  | helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound); | 
|  | VisitDartType();                    // read ith bound. | 
|  | helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType); | 
|  | if (builder_->ReadTag() == kSomething) { | 
|  | VisitDartType();  // read ith default type. | 
|  | } | 
|  | helper.Finish(); | 
|  | } | 
|  | function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters); | 
|  |  | 
|  | if (FLAG_causal_async_stacks && | 
|  | (function_node_helper.dart_async_marker_ == FunctionNodeHelper::kAsync || | 
|  | function_node_helper.dart_async_marker_ == | 
|  | FunctionNodeHelper::kAsyncStar)) { | 
|  | LocalVariable* asyncStackTraceVar = MakeVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, | 
|  | Symbols::AsyncStackTraceVar(), AbstractType::dynamic_type()); | 
|  | scope_->AddVariable(asyncStackTraceVar); | 
|  | } | 
|  |  | 
|  | if (function_node_helper.async_marker_ == FunctionNodeHelper::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. | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kBody); | 
|  |  | 
|  | 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 (function_node_helper.async_marker_ == FunctionNodeHelper::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(); | 
|  | builder_->ReadByte();  // read isSynthetic flag. | 
|  | switch (tag) { | 
|  | case kInvalidInitializer: | 
|  | return; | 
|  | case kFieldInitializer: | 
|  | builder_->SkipCanonicalNameReference();  // read field_reference. | 
|  | VisitExpression();                       // read value. | 
|  | return; | 
|  | case kSuperInitializer: | 
|  | builder_->SkipCanonicalNameReference();  // read target_reference. | 
|  | VisitArguments();                        // read arguments. | 
|  | return; | 
|  | case kRedirectingInitializer: | 
|  | builder_->SkipCanonicalNameReference();  // read target_reference. | 
|  | VisitArguments();                        // read arguments. | 
|  | return; | 
|  | case kLocalInitializer: | 
|  | VisitVariableDeclaration();  // read variable. | 
|  | return; | 
|  | case kAssertInitializer: | 
|  | VisitStatement(); | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("initializer", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitExpression() { | 
|  | uint8_t payload = 0; | 
|  | Tag tag = builder_->ReadTag(&payload); | 
|  | switch (tag) { | 
|  | case kInvalidExpression: | 
|  | builder_->ReadPosition(); | 
|  | builder_->SkipStringReference(); | 
|  | 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 interface_target_reference. | 
|  | builder_->SkipCanonicalNameReference(); | 
|  | return; | 
|  | case kPropertySet: | 
|  | builder_->ReadPosition();  // read position. | 
|  | VisitExpression();         // read receiver. | 
|  | builder_->SkipName();      // read name. | 
|  | VisitExpression();         // read value. | 
|  | // read 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 kSuperPropertyGet: | 
|  | HandleSpecialLoad(&result_->this_variable, Symbols::This()); | 
|  | builder_->ReadPosition();                // read position. | 
|  | builder_->SkipName();                    // read name. | 
|  | builder_->SkipCanonicalNameReference();  // read target_reference. | 
|  | return; | 
|  | case kSuperPropertySet: | 
|  | HandleSpecialLoad(&result_->this_variable, Symbols::This()); | 
|  | builder_->ReadPosition();                // read position. | 
|  | builder_->SkipName();                    // read name. | 
|  | VisitExpression();                       // read value. | 
|  | builder_->SkipCanonicalNameReference();  // read target_reference. | 
|  | 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 interface_target_reference. | 
|  | builder_->SkipCanonicalNameReference(); | 
|  | return; | 
|  | case kDirectMethodInvocation: | 
|  | builder_->ReadPosition();                // read position. | 
|  | VisitExpression();                       // read receiver. | 
|  | builder_->SkipCanonicalNameReference();  // read target_reference. | 
|  | VisitArguments();                        // read arguments. | 
|  | return; | 
|  | case kSuperMethodInvocation: | 
|  | HandleSpecialLoad(&result_->this_variable, Symbols::This()); | 
|  | builder_->ReadPosition();  // read position. | 
|  | builder_->SkipName();      // read name. | 
|  | VisitArguments();          // read arguments. | 
|  | // read interface_target_reference. | 
|  | builder_->SkipCanonicalNameReference(); | 
|  | 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. | 
|  | builder_->ReadFlags();     // read flags. | 
|  | 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. | 
|  | builder_->ReadPosition();          // read position. | 
|  | HandleLocalFunction(offset);       // read function node. | 
|  | 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 kSpecializedIntLiteral: | 
|  | 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; | 
|  | case kVectorCreation: | 
|  | builder_->ReadUInt();  // read size. | 
|  | return; | 
|  | case kVectorGet: | 
|  | VisitExpression();     // read expression. | 
|  | builder_->ReadUInt();  // read index. | 
|  | return; | 
|  | case kVectorSet: | 
|  | VisitExpression();     // read vector expression. | 
|  | builder_->ReadUInt();  // read index. | 
|  | VisitExpression();     // read value. | 
|  | return; | 
|  | case kVectorCopy: | 
|  | VisitExpression();  // read vector expression. | 
|  | return; | 
|  | case kClosureCreation: | 
|  | builder_->SkipCanonicalNameReference();  // read function reference. | 
|  | VisitExpression();                       // read context vector. | 
|  | VisitDartType();                  // read function type of the closure. | 
|  | builder_->SkipListOfDartTypes();  // read type arguments. | 
|  | return; | 
|  | case kConstantExpression: { | 
|  | builder_->SkipConstantReference(); | 
|  | return; | 
|  | } | 
|  | case kInstantiation: { | 
|  | VisitExpression(); | 
|  | const intptr_t list_length = | 
|  | builder_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | VisitDartType();  // read ith type. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kLoadLibrary: | 
|  | case kCheckLibraryIsLoaded: | 
|  | builder_->ReadUInt();  // library index | 
|  | break; | 
|  | default: | 
|  | ReportUnexpectedTag("expression", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitStatement() { | 
|  | Tag tag = builder_->ReadTag();  // read tag. | 
|  | switch (tag) { | 
|  | 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 kAssertBlock: | 
|  | if (I->asserts()) { | 
|  | 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()); | 
|  | } else { | 
|  | builder_->SkipStatementList(); | 
|  | } | 
|  | return; | 
|  | case kAssertStatement: | 
|  | if (I->asserts()) { | 
|  | VisitExpression();              // Read condition. | 
|  | builder_->ReadPosition();       // read condition start offset. | 
|  | builder_->ReadPosition();       // read condition end offset. | 
|  | Tag tag = builder_->ReadTag();  // read (first part of) message. | 
|  | if (tag == kSomething) { | 
|  | VisitExpression();  // read (rest of) message. | 
|  | } | 
|  | } else { | 
|  | builder_->SkipExpression();     // Read condition. | 
|  | builder_->ReadPosition();       // read condition start offset. | 
|  | builder_->ReadPosition();       // read condition end offset. | 
|  | 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_; | 
|  | builder_->ReadPosition();  // read position. | 
|  | VisitExpression();         // read condition. | 
|  | VisitStatement();          // read body. | 
|  | --depth_.loop_; | 
|  | return; | 
|  | case kDoStatement: | 
|  | ++depth_.loop_; | 
|  | builder_->ReadPosition();  // read position. | 
|  | 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. | 
|  |  | 
|  | ++depth_.loop_; | 
|  | EnterScope(offset); | 
|  |  | 
|  | TokenPosition position = builder_->ReadPosition();  // read position. | 
|  | intptr_t list_length = | 
|  | builder_->ReadListLength();  // read number of variables. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | VisitVariableDeclaration();  // read ith variable. | 
|  | } | 
|  |  | 
|  | 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. | 
|  |  | 
|  | ExitScope(position, builder_->reader_.max_position()); | 
|  | --depth_.loop_; | 
|  | return; | 
|  | } | 
|  | case kForInStatement: | 
|  | case kAsyncForInStatement: { | 
|  | PositionScope scope(&builder_->reader_); | 
|  |  | 
|  | intptr_t start_offset = | 
|  | builder_->ReaderOffset() - 1;  // -1 to include tag byte. | 
|  |  | 
|  | builder_->ReadPosition();  // read position. | 
|  | TokenPosition body_position = | 
|  | builder_->ReadPosition();  // read body 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 (!body_position.IsReal()) { | 
|  | body_position = builder_->reader_.min_position(); | 
|  | } | 
|  | // TODO(jensj): From kernel_binary.cc | 
|  | // forinstmt->variable_->set_end_position(forinstmt->position_); | 
|  | ExitScope(body_position, builder_->reader_.max_position()); | 
|  | --depth_.loop_; | 
|  | --depth_.for_in_; | 
|  | return; | 
|  | } | 
|  | case kSwitchStatement: { | 
|  | AddSwitchVariable(); | 
|  | builder_->ReadPosition();                     // read position. | 
|  | VisitExpression();                            // read condition. | 
|  | int case_count = builder_->ReadListLength();  // read number of cases. | 
|  | for (intptr_t i = 0; i < case_count; ++i) { | 
|  | int expression_count = | 
|  | builder_->ReadListLength();  // read number of expressions. | 
|  | for (intptr_t j = 0; j < expression_count; ++j) { | 
|  | builder_->ReadPosition();  // read jth position. | 
|  | VisitExpression();         // read jth expression. | 
|  | } | 
|  | builder_->ReadBool();  // read is_default. | 
|  | VisitStatement();      // read body. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kContinueSwitchStatement: | 
|  | builder_->ReadPosition();  // read position. | 
|  | builder_->ReadUInt();      // read target_index. | 
|  | return; | 
|  | case kIfStatement: | 
|  | builder_->ReadPosition();  // read position. | 
|  | 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 String& name = Symbols::TryFinallyReturnValue(); | 
|  | 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 catch_count = | 
|  | builder_->ReadListLength();  // read number of catches. | 
|  | for (intptr_t i = 0; i < catch_count; ++i) { | 
|  | PositionScope scope(&builder_->reader_); | 
|  | intptr_t offset = builder_->ReaderOffset();  // Catch has no tag. | 
|  |  | 
|  | EnterScope(offset); | 
|  |  | 
|  | builder_->ReadPosition();   // read position. | 
|  | VisitDartType();            // Read the 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. | 
|  | VisitExpression();                  // read expression. | 
|  |  | 
|  | ASSERT(flags == kNativeYieldFlags); | 
|  | 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: | 
|  | ReportUnexpectedTag("declaration", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitArguments() { | 
|  | builder_->ReadUInt();  // read argument_count. | 
|  |  | 
|  | // 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(); | 
|  | VariableDeclarationHelper helper(builder_); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kType); | 
|  | AbstractType& type = BuildAndVisitVariableType(); | 
|  |  | 
|  | // In case `declaration->IsConst()` the flow graph building will take care of | 
|  | // evaluating the constant and setting it via | 
|  | // `declaration->SetConstantValue()`. | 
|  | const String& name = (H.StringSize(helper.name_index_) == 0) | 
|  | ? GenerateName(":var", name_index_++) | 
|  | : H.DartSymbolObfuscate(helper.name_index_); | 
|  |  | 
|  | 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(helper.position_, end_position, name, type); | 
|  | if (helper.IsFinal()) { | 
|  | variable->set_is_final(); | 
|  | } | 
|  | scope_->AddVariable(variable); | 
|  | result_->locals.Insert(builder_->data_program_offset_ + kernel_offset_no_tag, | 
|  | variable); | 
|  | } | 
|  |  | 
|  | AbstractType& StreamingScopeBuilder::BuildAndVisitVariableType() { | 
|  | const intptr_t offset = builder_->ReaderOffset(); | 
|  | AbstractType& type = T.BuildVariableType(); | 
|  | builder_->SetOffset(offset);  // rewind | 
|  | VisitDartType(); | 
|  | return type; | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitDartType() { | 
|  | Tag tag = builder_->ReadTag(); | 
|  | switch (tag) { | 
|  | case kInvalidType: | 
|  | case kDynamicType: | 
|  | case kVoidType: | 
|  | case kBottomType: | 
|  | case kVectorType: | 
|  | // 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: | 
|  | ReportUnexpectedTag("type", tag); | 
|  | 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) { | 
|  | TypeParameterHelper helper(builder_); | 
|  | helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound); | 
|  | VisitDartType();  // read bound. | 
|  | helper.ReadUntilExcludingAndSetJustRead( | 
|  | TypeParameterHelper::kDefaultType); | 
|  | if (builder_->ReadTag() == kSomething) { | 
|  | VisitDartType();  // read default type. | 
|  | } | 
|  | helper.Finish(); | 
|  | } | 
|  | 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. | 
|  | } | 
|  | } | 
|  |  | 
|  | builder_->SkipListOfStrings();  // read positional parameter names. | 
|  |  | 
|  | if (!simple) { | 
|  | builder_->SkipCanonicalNameReference();  // read typedef reference. | 
|  | } | 
|  |  | 
|  | VisitDartType();  // read return type. | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::VisitTypeParameterType() { | 
|  | Function& function = Function::Handle(Z, parsed_function_->function().raw()); | 
|  | while (function.IsClosureFunction()) { | 
|  | function = function.parent_function(); | 
|  | } | 
|  |  | 
|  | // The index here is the index identifying the type parameter binding site | 
|  | // inside the DILL file, which uses a different indexing system than the VM | 
|  | // uses for its 'TypeParameter's internally. This index includes both class | 
|  | // and function type parameters. | 
|  |  | 
|  | intptr_t index = builder_->ReadUInt();  // read index for parameter. | 
|  |  | 
|  | 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 { | 
|  | // If the type parameter is a parameter to this or an enclosing function, we | 
|  | // can read it directly from the function type arguments vector later. | 
|  | // Otherwise, the type arguments vector we need is stored on the instance | 
|  | // object, so we need to capture 'this'. | 
|  | Class& parent_class = Class::Handle(Z, function.Owner()); | 
|  | if (index < parent_class.NumTypeParameters()) { | 
|  | HandleSpecialLoad(&result_->this_variable, Symbols::This()); | 
|  | } | 
|  | } | 
|  |  | 
|  | builder_->SkipOptionalDartType();  // read bound bound. | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) { | 
|  | // "Peek" ahead into the function node | 
|  | intptr_t offset = builder_->ReaderOffset(); | 
|  |  | 
|  | FunctionNodeHelper function_node_helper(builder_); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  |  | 
|  | LocalScope* saved_function_scope = current_function_scope_; | 
|  | FunctionNodeHelper::AsyncMarker saved_function_async_marker = | 
|  | current_function_async_marker_; | 
|  | DepthState saved_depth_state = depth_; | 
|  | depth_ = DepthState(depth_.function_ + 1); | 
|  | EnterScope(parent_kernel_offset); | 
|  | current_function_scope_ = scope_; | 
|  | current_function_async_marker_ = function_node_helper.async_marker_; | 
|  | if (depth_.function_ == 1) { | 
|  | FunctionScope function_scope = {offset, scope_}; | 
|  | result_->function_scopes.Add(function_scope); | 
|  | } | 
|  |  | 
|  | int num_type_params = 0; | 
|  | { | 
|  | AlternativeReadingScope _(&builder_->reader_); | 
|  | num_type_params = builder_->ReadListLength(); | 
|  | } | 
|  | // Adding this scope here informs the type translator the type parameters of | 
|  | // this function are now in scope, although they are not defined and will be | 
|  | // filled in with dynamic. This is OK, since their definitions are not needed | 
|  | // for scope building of the enclosing function. | 
|  | StreamingDartTypeTranslator::TypeParameterScope scope(&type_translator_, | 
|  | num_type_params); | 
|  |  | 
|  | // read positional_parameters and named_parameters. | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  |  | 
|  | ProcedureAttributesMetadata default_attrs; | 
|  | AddPositionalAndNamedParameters(0, kTypeCheckAllParameters, default_attrs); | 
|  |  | 
|  | // "Peek" is now done. | 
|  | builder_->SetOffset(offset); | 
|  |  | 
|  | VisitFunctionNode();  // read function node. | 
|  |  | 
|  | ExitScope(function_node_helper.position_, function_node_helper.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, | 
|  | ParameterTypeCheckMode type_check_mode /* = kTypeCheckAllParameters*/, | 
|  | const ProcedureAttributesMetadata& attrs) { | 
|  | // List of positional. | 
|  | intptr_t list_length = builder_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | AddVariableDeclarationParameter(pos++, type_check_mode, attrs); | 
|  | } | 
|  |  | 
|  | // List of named. | 
|  | list_length = builder_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | AddVariableDeclarationParameter(pos++, type_check_mode, attrs); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::AddVariableDeclarationParameter( | 
|  | intptr_t pos, | 
|  | ParameterTypeCheckMode type_check_mode, | 
|  | const ProcedureAttributesMetadata& attrs) { | 
|  | intptr_t kernel_offset = builder_->ReaderOffset();  // no tag. | 
|  | const InferredTypeMetadata parameter_type = | 
|  | builder_->inferred_type_metadata_helper_.GetInferredType(kernel_offset); | 
|  | VariableDeclarationHelper helper(builder_); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kType); | 
|  | String& name = H.DartSymbolObfuscate(helper.name_index_); | 
|  | AbstractType& type = BuildAndVisitVariableType();  // read type. | 
|  | helper.SetJustRead(VariableDeclarationHelper::kType); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer); | 
|  |  | 
|  | LocalVariable* variable = MakeVariable(helper.position_, helper.position_, | 
|  | name, type, ¶meter_type); | 
|  | if (helper.IsFinal()) { | 
|  | variable->set_is_final(); | 
|  | } | 
|  | if (variable->name().raw() == Symbols::IteratorParameter().raw()) { | 
|  | variable->set_is_forced_stack(); | 
|  | } | 
|  |  | 
|  | const bool needs_covariant_checke_in_method = | 
|  | helper.IsCovariant() || | 
|  | (helper.IsGenericCovariantImpl() && attrs.has_non_this_uses); | 
|  |  | 
|  | switch (type_check_mode) { | 
|  | case kTypeCheckAllParameters: | 
|  | variable->set_type_check_mode(LocalVariable::kDoTypeCheck); | 
|  | break; | 
|  | case kTypeCheckForTearOffOfNonDynamicallyInvokedMethod: | 
|  | if (needs_covariant_checke_in_method) { | 
|  | // Don't type check covariant parameters - they will be checked by | 
|  | // a function we forward to. Their types however are not known. | 
|  | variable->set_type_check_mode(LocalVariable::kSkipTypeCheck); | 
|  | } else { | 
|  | variable->set_type_check_mode(LocalVariable::kDoTypeCheck); | 
|  | } | 
|  | break; | 
|  | case kTypeCheckForNonDynamicallyInvokedMethod: | 
|  | if (needs_covariant_checke_in_method) { | 
|  | variable->set_type_check_mode(LocalVariable::kDoTypeCheck); | 
|  | } else { | 
|  | // Types of non-covariant parameters are guaranteed to match by | 
|  | // front-end enforcing strong mode types at call site. | 
|  | variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller); | 
|  | } | 
|  | break; | 
|  | case kTypeCheckForStaticFunction: | 
|  | variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller); | 
|  | break; | 
|  | } | 
|  | scope_->InsertParameterAt(pos, variable); | 
|  | result_->locals.Insert(builder_->data_program_offset_ + 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 String& name, | 
|  | const AbstractType& type, | 
|  | const InferredTypeMetadata* param_type_md /* = NULL */) { | 
|  | CompileType* param_type = NULL; | 
|  | if ((param_type_md != NULL) && !param_type_md->IsTrivial()) { | 
|  | param_type = new (Z) CompileType(CompileType::CreateNullable( | 
|  | param_type_md->nullable, param_type_md->cid)); | 
|  | } | 
|  | return new (Z) | 
|  | LocalVariable(declaration_pos, token_pos, name, type, param_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_ == FunctionNodeHelper::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; | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offset) { | 
|  | LocalVariable* variable = result_->locals.Lookup(declaration_binary_offset); | 
|  | 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 = builder_->GetNameFromVariableDeclaration( | 
|  | declaration_binary_offset - builder_->data_program_offset_, | 
|  | parsed_function_->function()); | 
|  |  | 
|  | const String& name = H.DartSymbolObfuscate(var_name); | 
|  | variable = current_function_scope_->parent()->LookupVariable(name, true); | 
|  | ASSERT(variable != NULL); | 
|  | result_->locals.Insert(declaration_binary_offset, 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 String& StreamingScopeBuilder::GenerateName(const char* prefix, | 
|  | intptr_t suffix) { | 
|  | char name[64]; | 
|  | Utils::SNPrint(name, 64, "%s%" Pd "", prefix, suffix); | 
|  | return H.DartSymbolObfuscate(name); | 
|  | } | 
|  |  | 
|  | void StreamingScopeBuilder::HandleSpecialLoad(LocalVariable** variable, | 
|  | const 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 String& name) { | 
|  | if (*variable == NULL) { | 
|  | *variable = scope_->LookupVariable(name, true); | 
|  | ASSERT(*variable != NULL); | 
|  | scope_->CaptureVariable(*variable); | 
|  | } | 
|  | } | 
|  |  | 
|  | StreamingDartTypeTranslator::StreamingDartTypeTranslator( | 
|  | StreamingFlowGraphBuilder* builder, | 
|  | bool finalize) | 
|  | : builder_(builder), | 
|  | translation_helper_(builder->translation_helper_), | 
|  | active_class_(builder->active_class()), | 
|  | type_parameter_scope_(NULL), | 
|  | zone_(translation_helper_.zone()), | 
|  | result_(AbstractType::Handle(translation_helper_.zone())), | 
|  | finalize_(finalize) {} | 
|  |  | 
|  | AbstractType& StreamingDartTypeTranslator::BuildType() { | 
|  | BuildTypeInternal(); | 
|  |  | 
|  | // We return a new `ZoneHandle` here on purpose: The intermediate language | 
|  | // instructions do not make a copy of the handle, so we do it. | 
|  | return AbstractType::ZoneHandle(Z, result_.raw()); | 
|  | } | 
|  |  | 
|  | AbstractType& StreamingDartTypeTranslator::BuildTypeWithoutFinalization() { | 
|  | bool saved_finalize = finalize_; | 
|  | finalize_ = false; | 
|  | BuildTypeInternal(); | 
|  | finalize_ = saved_finalize; | 
|  |  | 
|  | // We return a new `ZoneHandle` here on purpose: The intermediate language | 
|  | // instructions do not make a copy of the handle, so we do it. | 
|  | return 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(bool invalid_as_dynamic) { | 
|  | Tag tag = builder_->ReadTag(); | 
|  | switch (tag) { | 
|  | case kInvalidType: | 
|  | if (invalid_as_dynamic) { | 
|  | result_ = Object::dynamic_type().raw(); | 
|  | } else { | 
|  | result_ = ClassFinalizer::NewFinalizedMalformedType( | 
|  | Error::Handle(Z),  // No previous error. | 
|  | Script::Handle(Z, Script::null()), TokenPosition::kNoSource, | 
|  | "[InvalidType] in Kernel IR."); | 
|  | } | 
|  | break; | 
|  | case kDynamicType: | 
|  | result_ = Object::dynamic_type().raw(); | 
|  | break; | 
|  | case kVoidType: | 
|  | result_ = Object::void_type().raw(); | 
|  | break; | 
|  | case kVectorType: | 
|  | result_ = Object::vector_type().raw(); | 
|  | break; | 
|  | case kBottomType: | 
|  | result_ = | 
|  | Class::Handle(Z, I->object_store()->null_class()).CanonicalType(); | 
|  | break; | 
|  | case kInterfaceType: | 
|  | BuildInterfaceType(false); | 
|  | break; | 
|  | case kSimpleInterfaceType: | 
|  | BuildInterfaceType(true); | 
|  | break; | 
|  | case kFunctionType: | 
|  | BuildFunctionType(false); | 
|  | break; | 
|  | case kSimpleFunctionType: | 
|  | BuildFunctionType(true); | 
|  | break; | 
|  | case kTypeParameterType: | 
|  | BuildTypeParameterType(); | 
|  | break; | 
|  | default: | 
|  | builder_->ReportUnexpectedTag("type", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingDartTypeTranslator::BuildInterfaceType(bool simple) { | 
|  | // NOTE: That an interface type like `T<A, B>` is considered to be | 
|  | // malformed iff `T` is malformed. | 
|  | //   => We therefore ignore errors in `A` or `B`. | 
|  |  | 
|  | NameIndex klass_name = | 
|  | builder_->ReadCanonicalNameReference();  // read klass_name. | 
|  |  | 
|  | intptr_t length; | 
|  | if (simple) { | 
|  | length = 0; | 
|  | } else { | 
|  | length = builder_->ReadListLength();  // read type_arguments list length. | 
|  | } | 
|  | const TypeArguments& type_arguments = | 
|  | BuildTypeArguments(length);  // read type arguments. | 
|  |  | 
|  | Object& klass = Object::Handle(Z, H.LookupClassByKernelClass(klass_name)); | 
|  | result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource); | 
|  | if (finalize_) { | 
|  | ASSERT(active_class_->klass != NULL); | 
|  | result_ = ClassFinalizer::FinalizeType(*active_class_->klass, result_); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingDartTypeTranslator::BuildFunctionType(bool simple) { | 
|  | Function& signature_function = Function::ZoneHandle( | 
|  | Z, Function::NewSignatureFunction(*active_class_->klass, | 
|  | active_class_->enclosing != NULL | 
|  | ? *active_class_->enclosing | 
|  | : Function::Handle(Z), | 
|  | TokenPosition::kNoSource)); | 
|  |  | 
|  | // Suspend finalization of types inside this one. They will be finalized after | 
|  | // the whole function type is constructed. | 
|  | // | 
|  | // TODO(31213): Test further when nested generic function types | 
|  | // are supported by fasta. | 
|  | bool finalize = finalize_; | 
|  | finalize_ = false; | 
|  |  | 
|  | if (!simple) { | 
|  | builder_->LoadAndSetupTypeParameters(active_class_, signature_function, | 
|  | builder_->ReadListLength(), | 
|  | signature_function); | 
|  | } | 
|  |  | 
|  | ActiveTypeParametersScope scope( | 
|  | active_class_, &signature_function, | 
|  | TypeArguments::Handle(Z, signature_function.type_parameters()), Z); | 
|  |  | 
|  | intptr_t required_count; | 
|  | intptr_t all_count; | 
|  | intptr_t positional_count; | 
|  | if (!simple) { | 
|  | required_count = builder_->ReadUInt();  // read required parameter count. | 
|  | all_count = builder_->ReadUInt();       // read total parameter count. | 
|  | positional_count = | 
|  | builder_->ReadListLength();  // read positional_parameters list length. | 
|  | } else { | 
|  | positional_count = | 
|  | builder_->ReadListLength();  // read positional_parameters list length. | 
|  | required_count = positional_count; | 
|  | all_count = positional_count; | 
|  | } | 
|  |  | 
|  | const Array& parameter_types = | 
|  | Array::Handle(Z, Array::New(1 + all_count, Heap::kOld)); | 
|  | signature_function.set_parameter_types(parameter_types); | 
|  | const Array& parameter_names = | 
|  | Array::Handle(Z, Array::New(1 + all_count, Heap::kOld)); | 
|  | signature_function.set_parameter_names(parameter_names); | 
|  |  | 
|  | intptr_t pos = 0; | 
|  | parameter_types.SetAt(pos, AbstractType::dynamic_type()); | 
|  | parameter_names.SetAt(pos, H.DartSymbolPlain("_receiver_")); | 
|  | ++pos; | 
|  | for (intptr_t i = 0; i < positional_count; ++i, ++pos) { | 
|  | BuildTypeInternal();  // read ith positional parameter. | 
|  | if (result_.IsMalformed()) { | 
|  | result_ = AbstractType::dynamic_type().raw(); | 
|  | } | 
|  | parameter_types.SetAt(pos, result_); | 
|  | parameter_names.SetAt(pos, H.DartSymbolPlain("noname")); | 
|  | } | 
|  |  | 
|  | // The additional first parameter is the receiver type (set to dynamic). | 
|  | signature_function.set_num_fixed_parameters(1 + required_count); | 
|  | signature_function.SetNumOptionalParameters( | 
|  | all_count - required_count, positional_count > required_count); | 
|  |  | 
|  | if (!simple) { | 
|  | const intptr_t named_count = | 
|  | builder_->ReadListLength();  // read named_parameters list length. | 
|  | for (intptr_t i = 0; i < named_count; ++i, ++pos) { | 
|  | // read string reference (i.e. named_parameters[i].name). | 
|  | String& name = H.DartSymbolObfuscate(builder_->ReadStringReference()); | 
|  | BuildTypeInternal();  // read named_parameters[i].type. | 
|  | if (result_.IsMalformed()) { | 
|  | result_ = AbstractType::dynamic_type().raw(); | 
|  | } | 
|  | parameter_types.SetAt(pos, result_); | 
|  | parameter_names.SetAt(pos, name); | 
|  | } | 
|  | } | 
|  |  | 
|  | builder_->SkipListOfStrings();  // read positional parameter names. | 
|  |  | 
|  | if (!simple) { | 
|  | builder_->SkipCanonicalNameReference();  // read typedef reference. | 
|  | } | 
|  |  | 
|  | BuildTypeInternal();  // read return type. | 
|  | if (result_.IsMalformed()) { | 
|  | result_ = AbstractType::dynamic_type().raw(); | 
|  | } | 
|  | signature_function.set_result_type(result_); | 
|  |  | 
|  | finalize_ = finalize; | 
|  |  | 
|  | Type& signature_type = | 
|  | Type::ZoneHandle(Z, signature_function.SignatureType()); | 
|  |  | 
|  | if (finalize_) { | 
|  | signature_type ^= | 
|  | ClassFinalizer::FinalizeType(*active_class_->klass, signature_type); | 
|  | // Do not refer to signature_function anymore, since it may have been | 
|  | // replaced during canonicalization. | 
|  | signature_function = Function::null(); | 
|  | } | 
|  |  | 
|  | result_ = signature_type.raw(); | 
|  | } | 
|  |  | 
|  | void StreamingDartTypeTranslator::BuildTypeParameterType() { | 
|  | intptr_t parameter_index = builder_->ReadUInt();  // read parameter index. | 
|  | builder_->SkipOptionalDartType();                 // read bound. | 
|  |  | 
|  | const TypeArguments& class_types = | 
|  | TypeArguments::Handle(Z, active_class_->klass->type_parameters()); | 
|  | if (parameter_index < class_types.Length()) { | 
|  | // The index of the type parameter in [parameters] is | 
|  | // the same index into the `klass->type_parameters()` array. | 
|  | result_ ^= class_types.TypeAt(parameter_index); | 
|  | return; | 
|  | } | 
|  | parameter_index -= class_types.Length(); | 
|  |  | 
|  | if (active_class_->HasMember()) { | 
|  | if (active_class_->MemberIsFactoryProcedure()) { | 
|  | // | 
|  | // WARNING: This is a little hackish: | 
|  | // | 
|  | // We have a static factory constructor. The kernel IR gives the factory | 
|  | // constructor function its own type parameters (which are equal in name | 
|  | // and number to the ones of the enclosing class). I.e., | 
|  | // | 
|  | //   class A<T> { | 
|  | //     factory A.x() { return new B<T>(); } | 
|  | //   } | 
|  | // | 
|  | //  is basically translated to this: | 
|  | // | 
|  | //   class A<T> { | 
|  | //     static A.x<T'>() { return new B<T'>(); } | 
|  | //   } | 
|  | // | 
|  | if (class_types.Length() > parameter_index) { | 
|  | result_ ^= class_types.TypeAt(parameter_index); | 
|  | return; | 
|  | } | 
|  | parameter_index -= class_types.Length(); | 
|  | } | 
|  |  | 
|  | intptr_t procedure_type_parameter_count = | 
|  | active_class_->MemberIsProcedure() | 
|  | ? active_class_->MemberTypeParameterCount(Z) | 
|  | : 0; | 
|  | if (procedure_type_parameter_count > 0) { | 
|  | if (procedure_type_parameter_count > parameter_index) { | 
|  | if (I->reify_generic_functions()) { | 
|  | result_ ^= | 
|  | TypeArguments::Handle(Z, active_class_->member->type_parameters()) | 
|  | .TypeAt(parameter_index); | 
|  | } else { | 
|  | result_ ^= Type::DynamicType(); | 
|  | } | 
|  | return; | 
|  | } | 
|  | parameter_index -= procedure_type_parameter_count; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (active_class_->local_type_parameters != NULL) { | 
|  | if (parameter_index < active_class_->local_type_parameters->Length()) { | 
|  | if (I->reify_generic_functions()) { | 
|  | result_ ^= | 
|  | active_class_->local_type_parameters->TypeAt(parameter_index); | 
|  | } else { | 
|  | result_ ^= Type::DynamicType(); | 
|  | } | 
|  | return; | 
|  | } | 
|  | parameter_index -= active_class_->local_type_parameters->Length(); | 
|  | } | 
|  |  | 
|  | if (type_parameter_scope_ != NULL && | 
|  | parameter_index < type_parameter_scope_->outer_parameter_count() + | 
|  | type_parameter_scope_->parameter_count()) { | 
|  | result_ ^= Type::DynamicType(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | H.ReportError( | 
|  | builder_->script(), TokenPosition::kNoSource, | 
|  | "Unbound type parameter found in %s.  Please report this at dartbug.com.", | 
|  | active_class_->ToCString()); | 
|  | } | 
|  |  | 
|  | const TypeArguments& StreamingDartTypeTranslator::BuildTypeArguments( | 
|  | intptr_t length) { | 
|  | bool only_dynamic = true; | 
|  | intptr_t offset = builder_->ReaderOffset(); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | if (builder_->ReadTag() != kDynamicType) {  // Read the ith types tag. | 
|  | only_dynamic = false; | 
|  | builder_->SetOffset(offset); | 
|  | break; | 
|  | } | 
|  | } | 
|  | TypeArguments& type_arguments = TypeArguments::ZoneHandle(Z); | 
|  | if (!only_dynamic) { | 
|  | type_arguments = TypeArguments::New(length); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | BuildTypeInternal(true);  // read ith type. | 
|  | type_arguments.SetTypeAt(i, result_); | 
|  | } | 
|  |  | 
|  | if (finalize_) { | 
|  | type_arguments = type_arguments.Canonicalize(); | 
|  | } | 
|  | } | 
|  | return type_arguments; | 
|  | } | 
|  |  | 
|  | const TypeArguments& | 
|  | StreamingDartTypeTranslator::BuildInstantiatedTypeArguments( | 
|  | const Class& receiver_class, | 
|  | intptr_t length) { | 
|  | const TypeArguments& type_arguments = BuildTypeArguments(length); | 
|  |  | 
|  | // If type_arguments is null all arguments are dynamic. | 
|  | // If, however, this class doesn't specify all the type arguments directly we | 
|  | // still need to finalize the type below in order to get any non-dynamic types | 
|  | // from any super. See http://www.dartbug.com/29537. | 
|  | if (type_arguments.IsNull() && receiver_class.NumTypeArguments() == length) { | 
|  | return type_arguments; | 
|  | } | 
|  |  | 
|  | // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to | 
|  | // finalize the argument types. | 
|  | // (This can for example make the [type_arguments] vector larger) | 
|  | Type& type = Type::Handle( | 
|  | Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource)); | 
|  | if (finalize_) { | 
|  | type ^= ClassFinalizer::FinalizeType(*active_class_->klass, type); | 
|  | } | 
|  |  | 
|  | const TypeArguments& instantiated_type_arguments = | 
|  | TypeArguments::ZoneHandle(Z, type.arguments()); | 
|  | return instantiated_type_arguments; | 
|  | } | 
|  |  | 
|  | const Type& StreamingDartTypeTranslator::ReceiverType(const Class& klass) { | 
|  | ASSERT(!klass.IsNull()); | 
|  | ASSERT(!klass.IsTypedefClass()); | 
|  | // Note that if klass is _Closure, the returned type will be _Closure, | 
|  | // and not the signature type. | 
|  | Type& type = Type::ZoneHandle(Z, klass.CanonicalType()); | 
|  | if (!type.IsNull()) { | 
|  | return type; | 
|  | } | 
|  | type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()), | 
|  | klass.token_pos()); | 
|  | if (klass.is_type_finalized()) { | 
|  | type ^= ClassFinalizer::FinalizeType(klass, type); | 
|  | klass.SetCanonicalType(type); | 
|  | } | 
|  | return type; | 
|  | } | 
|  |  | 
|  | StreamingConstantEvaluator::StreamingConstantEvaluator( | 
|  | StreamingFlowGraphBuilder* builder) | 
|  | : builder_(builder), | 
|  | isolate_(Isolate::Current()), | 
|  | zone_(builder_->zone_), | 
|  | translation_helper_(builder_->translation_helper_), | 
|  | type_translator_(builder_->type_translator_), | 
|  | script_(builder_->script()), | 
|  | result_(Instance::Handle(zone_)) {} | 
|  |  | 
|  | bool StreamingConstantEvaluator::IsCached(intptr_t offset) { | 
|  | return GetCachedConstant(offset, &result_); | 
|  | } | 
|  |  | 
|  | Instance& StreamingConstantEvaluator::EvaluateExpression(intptr_t offset, | 
|  | bool reset_position) { | 
|  | ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull()); | 
|  | if (!GetCachedConstant(offset, &result_)) { | 
|  | ASSERT(IsAllowedToEvaluate()); | 
|  | intptr_t original_offset = builder_->ReaderOffset(); | 
|  | builder_->SetOffset(offset); | 
|  | uint8_t payload = 0; | 
|  | Tag tag = builder_->ReadTag(&payload);  // read tag. | 
|  | switch (tag) { | 
|  | case kVariableGet: | 
|  | EvaluateVariableGet(); | 
|  | break; | 
|  | case kSpecializedVariableGet: | 
|  | EvaluateVariableGet(payload); | 
|  | break; | 
|  | case kPropertyGet: | 
|  | EvaluatePropertyGet(); | 
|  | break; | 
|  | case kDirectPropertyGet: | 
|  | EvaluateDirectPropertyGet(); | 
|  | break; | 
|  | case kStaticGet: | 
|  | EvaluateStaticGet(); | 
|  | break; | 
|  | case kMethodInvocation: | 
|  | EvaluateMethodInvocation(); | 
|  | break; | 
|  | case kDirectMethodInvocation: | 
|  | EvaluateDirectMethodInvocation(); | 
|  | break; | 
|  | case kSuperMethodInvocation: | 
|  | EvaluateSuperMethodInvocation(); | 
|  | break; | 
|  | case kStaticInvocation: | 
|  | case kConstStaticInvocation: | 
|  | EvaluateStaticInvocation(); | 
|  | break; | 
|  | case kConstConstructorInvocation: | 
|  | EvaluateConstructorInvocationInternal(); | 
|  | break; | 
|  | case kNot: | 
|  | EvaluateNot(); | 
|  | break; | 
|  | case kLogicalExpression: | 
|  | EvaluateLogicalExpression(); | 
|  | break; | 
|  | case kConditionalExpression: | 
|  | EvaluateConditionalExpression(); | 
|  | break; | 
|  | case kStringConcatenation: | 
|  | EvaluateStringConcatenation(); | 
|  | break; | 
|  | case kSymbolLiteral: | 
|  | EvaluateSymbolLiteral(); | 
|  | break; | 
|  | case kTypeLiteral: | 
|  | EvaluateTypeLiteral(); | 
|  | break; | 
|  | case kAsExpression: | 
|  | EvaluateAsExpression(); | 
|  | break; | 
|  | case kConstListLiteral: | 
|  | EvaluateListLiteralInternal(); | 
|  | break; | 
|  | case kConstMapLiteral: | 
|  | EvaluateMapLiteralInternal(); | 
|  | break; | 
|  | case kLet: | 
|  | EvaluateLet(); | 
|  | break; | 
|  | case kInstantiation: | 
|  | EvaluatePartialTearoffInstantiation(); | 
|  | break; | 
|  | case kBigIntLiteral: | 
|  | EvaluateBigIntLiteral(); | 
|  | break; | 
|  | case kStringLiteral: | 
|  | EvaluateStringLiteral(); | 
|  | break; | 
|  | case kSpecializedIntLiteral: | 
|  | EvaluateIntLiteral(payload); | 
|  | break; | 
|  | case kNegativeIntLiteral: | 
|  | EvaluateIntLiteral(true); | 
|  | break; | 
|  | case kPositiveIntLiteral: | 
|  | EvaluateIntLiteral(false); | 
|  | break; | 
|  | case kDoubleLiteral: | 
|  | EvaluateDoubleLiteral(); | 
|  | break; | 
|  | case kTrueLiteral: | 
|  | EvaluateBoolLiteral(true); | 
|  | break; | 
|  | case kFalseLiteral: | 
|  | EvaluateBoolLiteral(false); | 
|  | break; | 
|  | case kNullLiteral: | 
|  | EvaluateNullLiteral(); | 
|  | break; | 
|  | case kConstantExpression: | 
|  | EvaluateConstantExpression(); | 
|  | break; | 
|  | default: | 
|  | H.ReportError( | 
|  | script_, TokenPosition::kNoSource, | 
|  | "Not a constant expression: unexpected kernel tag %s (%" Pd ")", | 
|  | Reader::TagName(tag), tag); | 
|  | } | 
|  |  | 
|  | CacheConstantValue(offset, result_); | 
|  | if (reset_position) builder_->SetOffset(original_offset); | 
|  | } else { | 
|  | if (!reset_position) { | 
|  | builder_->SetOffset(offset); | 
|  | builder_->SkipExpression(); | 
|  | } | 
|  | } | 
|  | // We return a new `ZoneHandle` here on purpose: The intermediate language | 
|  | // instructions do not make a copy of the handle, so we do it. | 
|  | return Instance::ZoneHandle(Z, result_.raw()); | 
|  | } | 
|  |  | 
|  | Instance& StreamingConstantEvaluator::EvaluateListLiteral(intptr_t offset, | 
|  | bool reset_position) { | 
|  | if (!GetCachedConstant(offset, &result_)) { | 
|  | ASSERT(IsAllowedToEvaluate()); | 
|  | intptr_t original_offset = builder_->ReaderOffset(); | 
|  | builder_->SetOffset(offset); | 
|  | builder_->ReadTag();  // skip tag. | 
|  | EvaluateListLiteralInternal(); | 
|  |  | 
|  | CacheConstantValue(offset, result_); | 
|  | if (reset_position) builder_->SetOffset(original_offset); | 
|  | } | 
|  | // We return a new `ZoneHandle` here on purpose: The intermediate language | 
|  | // instructions do not make a copy of the handle, so we do it. | 
|  | return Instance::ZoneHandle(Z, result_.raw()); | 
|  | } | 
|  |  | 
|  | Instance& StreamingConstantEvaluator::EvaluateMapLiteral(intptr_t offset, | 
|  | bool reset_position) { | 
|  | if (!GetCachedConstant(offset, &result_)) { | 
|  | ASSERT(IsAllowedToEvaluate()); | 
|  | intptr_t original_offset = builder_->ReaderOffset(); | 
|  | builder_->SetOffset(offset); | 
|  | builder_->ReadTag();  // skip tag. | 
|  | EvaluateMapLiteralInternal(); | 
|  |  | 
|  | CacheConstantValue(offset, result_); | 
|  | if (reset_position) builder_->SetOffset(original_offset); | 
|  | } | 
|  | // We return a new `ZoneHandle` here on purpose: The intermediate language | 
|  | // instructions do not make a copy of the handle, so we do it. | 
|  | return Instance::ZoneHandle(Z, result_.raw()); | 
|  | } | 
|  |  | 
|  | Instance& StreamingConstantEvaluator::EvaluateConstructorInvocation( | 
|  | intptr_t offset, | 
|  | bool reset_position) { | 
|  | if (!GetCachedConstant(offset, &result_)) { | 
|  | ASSERT(IsAllowedToEvaluate()); | 
|  | intptr_t original_offset = builder_->ReaderOffset(); | 
|  | builder_->SetOffset(offset); | 
|  | builder_->ReadTag();  // skip tag. | 
|  | EvaluateConstructorInvocationInternal(); | 
|  |  | 
|  | CacheConstantValue(offset, result_); | 
|  | if (reset_position) builder_->SetOffset(original_offset); | 
|  | } | 
|  | // We return a new `ZoneHandle` here on purpose: The intermediate language | 
|  | // instructions do not make a copy of the handle, so we do it. | 
|  | return Instance::ZoneHandle(Z, result_.raw()); | 
|  | } | 
|  |  | 
|  | Object& StreamingConstantEvaluator::EvaluateExpressionSafe(intptr_t offset) { | 
|  | LongJumpScope jump; | 
|  | if (setjmp(*jump.Set()) == 0) { | 
|  | return EvaluateExpression(offset); | 
|  | } else { | 
|  | Thread* thread = H.thread(); | 
|  | Error& error = Error::Handle(Z); | 
|  | error = thread->sticky_error(); | 
|  | thread->clear_sticky_error(); | 
|  | return error; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool StreamingConstantEvaluator::IsAllowedToEvaluate() { | 
|  | return FLAG_precompiled_mode || builder_->flow_graph_builder_ == NULL || | 
|  | !builder_->optimizing(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateVariableGet() { | 
|  | // When we see a [VariableGet] the corresponding [VariableDeclaration] must've | 
|  | // been executed already. It therefore must have a constant object associated | 
|  | // with it. | 
|  | builder_->ReadPosition();  // read position. | 
|  | intptr_t variable_kernel_position = | 
|  | builder_->ReadUInt();          // read kernel position. | 
|  | builder_->ReadUInt();              // read relative variable index. | 
|  | builder_->SkipOptionalDartType();  // read promoted type. | 
|  | LocalVariable* variable = builder_->LookupVariable(variable_kernel_position); | 
|  | ASSERT(variable->IsConst()); | 
|  | result_ = variable->ConstValue()->raw(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateVariableGet(uint8_t payload) { | 
|  | // When we see a [VariableGet] the corresponding [VariableDeclaration] must've | 
|  | // been executed already. It therefore must have a constant object associated | 
|  | // with it. | 
|  | builder_->ReadPosition();  // read position. | 
|  | intptr_t variable_kernel_position = | 
|  | builder_->ReadUInt();  // read kernel position. | 
|  | LocalVariable* variable = builder_->LookupVariable(variable_kernel_position); | 
|  | ASSERT(variable->IsConst()); | 
|  | result_ = variable->ConstValue()->raw(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateGetStringLength( | 
|  | intptr_t expression_offset, | 
|  | TokenPosition position) { | 
|  | EvaluateExpression(expression_offset); | 
|  | if (result_.IsString()) { | 
|  | const String& str = String::Handle(Z, String::RawCast(result_.raw())); | 
|  | result_ = Integer::New(str.Length(), H.allocation_space()); | 
|  | } else { | 
|  | H.ReportError( | 
|  | script_, position, | 
|  | "Constant expressions can only call 'length' on string constants."); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluatePropertyGet() { | 
|  | const TokenPosition position = builder_->ReadPosition();  // read position. | 
|  | intptr_t expression_offset = builder_->ReaderOffset(); | 
|  | builder_->SkipExpression();                            // read receiver. | 
|  | StringIndex name = builder_->ReadNameAsStringIndex();  // read name. | 
|  | builder_->SkipCanonicalNameReference();  // read interface_target_reference. | 
|  |  | 
|  | if (H.StringEquals(name, "length")) { | 
|  | EvaluateGetStringLength(expression_offset, position); | 
|  | } else { | 
|  | H.ReportError( | 
|  | script_, position, | 
|  | "Constant expressions can only call 'length' on string constants."); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateDirectPropertyGet() { | 
|  | TokenPosition position = builder_->ReadPosition();  // read position. | 
|  | intptr_t expression_offset = builder_->ReaderOffset(); | 
|  | builder_->SkipExpression();  // read receiver. | 
|  | NameIndex kernel_name = | 
|  | builder_->ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | // TODO(vegorov): add check based on the complete canonical name. | 
|  | if (H.IsGetter(kernel_name) && | 
|  | H.StringEquals(H.CanonicalNameString(kernel_name), "length")) { | 
|  | EvaluateGetStringLength(expression_offset, position); | 
|  | } else { | 
|  | H.ReportError( | 
|  | script_, position, | 
|  | "Constant expressions can only call 'length' on string constants."); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateStaticGet() { | 
|  | TokenPosition position = builder_->ReadPosition();  // read position. | 
|  | NameIndex target = | 
|  | builder_->ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull()); | 
|  |  | 
|  | if (H.IsField(target)) { | 
|  | const Field& field = Field::Handle(Z, H.LookupFieldByKernelField(target)); | 
|  | if (!field.is_const()) { | 
|  | H.ReportError(script_, position, "Not a constant field."); | 
|  | } | 
|  | if (field.StaticValue() == Object::transition_sentinel().raw()) { | 
|  | builder_->InlineBailout( | 
|  | "kernel::StreamingConstantEvaluator::EvaluateStaticGet::Cyclic"); | 
|  | H.ReportError(script_, position, "Not a constant expression."); | 
|  | } else if (field.StaticValue() == Object::sentinel().raw()) { | 
|  | field.SetStaticValue(Object::transition_sentinel()); | 
|  | const Object& value = | 
|  | Object::Handle(Compiler::EvaluateStaticInitializer(field)); | 
|  | if (value.IsError()) { | 
|  | field.SetStaticValue(Object::null_instance()); | 
|  | H.ReportError(Error::Cast(value), script_, position, | 
|  | "Not a constant expression."); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | Thread* thread = H.thread(); | 
|  | const Error& error = | 
|  | Error::Handle(thread->zone(), thread->sticky_error()); | 
|  | if (!error.IsNull()) { | 
|  | field.SetStaticValue(Object::null_instance()); | 
|  | thread->clear_sticky_error(); | 
|  | H.ReportError(error, script_, position, "Not a constant expression."); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | ASSERT(value.IsNull() || value.IsInstance()); | 
|  | field.SetStaticValue(value.IsNull() ? Instance::null_instance() | 
|  | : Instance::Cast(value)); | 
|  |  | 
|  | result_ = field.StaticValue(); | 
|  | result_ = H.Canonicalize(result_); | 
|  | field.SetStaticValue(result_, true); | 
|  | } else { | 
|  | result_ = field.StaticValue(); | 
|  | } | 
|  | } else if (H.IsProcedure(target)) { | 
|  | const Function& function = | 
|  | Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); | 
|  |  | 
|  | if (H.IsMethod(target)) { | 
|  | Function& closure_function = | 
|  | Function::ZoneHandle(Z, function.ImplicitClosureFunction()); | 
|  | result_ = closure_function.ImplicitStaticClosure(); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } else if (H.IsGetter(target)) { | 
|  | H.ReportError(script_, position, "Not a constant expression."); | 
|  | } else { | 
|  | H.ReportError(script_, position, "Not a constant expression."); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateMethodInvocation() { | 
|  | builder_->ReadPosition();  // read position. | 
|  | // This method call wasn't cached, so receiver et al. isn't cached either. | 
|  | const Instance& receiver = | 
|  | EvaluateExpression(builder_->ReaderOffset(), false);  // read receiver. | 
|  | Class& klass = | 
|  | Class::Handle(Z, isolate_->class_table()->At(receiver.GetClassId())); | 
|  | ASSERT(!klass.IsNull()); | 
|  |  | 
|  | // Search the superclass chain for the selector. | 
|  | const String& method_name = builder_->ReadNameAsMethodName();  // read name. | 
|  | Function& function = | 
|  | builder_->FindMatchingFunctionAnyArgs(klass, method_name); | 
|  |  | 
|  | // The frontend should guarantee that [MethodInvocation]s inside constant | 
|  | // expressions are always valid. | 
|  | ASSERT(!function.IsNull()); | 
|  |  | 
|  | // Read arguments, run the method and canonicalize the result. | 
|  | const Object& result = RunMethodCall(function, &receiver); | 
|  | result_ ^= result.raw(); | 
|  | result_ = H.Canonicalize(result_); | 
|  |  | 
|  | builder_->SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateDirectMethodInvocation() { | 
|  | builder_->ReadPosition();  // read position. | 
|  |  | 
|  | const Instance& receiver = | 
|  | EvaluateExpression(builder_->ReaderOffset(), false);  // read receiver. | 
|  |  | 
|  | NameIndex kernel_name = | 
|  | builder_->ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | const Function& function = Function::ZoneHandle( | 
|  | Z, builder_->LookupMethodByMember(kernel_name, | 
|  | H.DartProcedureName(kernel_name))); | 
|  |  | 
|  | // Read arguments, run the method and canonicalize the result. | 
|  | const Object& result = RunMethodCall(function, &receiver); | 
|  | result_ ^= result.raw(); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | Class& StreamingFlowGraphBuilder::GetSuperOrDie() { | 
|  | Class& klass = Class::Handle(Z, parsed_function()->function().Owner()); | 
|  | ASSERT(!klass.IsNull()); | 
|  | klass = klass.SuperClass(); | 
|  | ASSERT(!klass.IsNull()); | 
|  | return klass; | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateSuperMethodInvocation() { | 
|  | builder_->ReadPosition();  // read position. | 
|  |  | 
|  | const LocalVariable* this_variable = builder_->scopes()->this_variable; | 
|  | ASSERT(this_variable->IsConst()); | 
|  | const Instance& receiver = | 
|  | Instance::Handle(Z, this_variable->ConstValue()->raw()); | 
|  | ASSERT(!receiver.IsNull()); | 
|  |  | 
|  | Class& klass = builder_->GetSuperOrDie(); | 
|  |  | 
|  | const String& method_name = builder_->ReadNameAsMethodName();  // read name. | 
|  | Function& function = | 
|  | builder_->FindMatchingFunctionAnyArgs(klass, method_name); | 
|  |  | 
|  | // The frontend should guarantee that [MethodInvocation]s inside constant | 
|  | // expressions are always valid. | 
|  | ASSERT(!function.IsNull()); | 
|  |  | 
|  | // Read arguments, run the method and canonicalize the result. | 
|  | const Object& result = RunMethodCall(function, &receiver); | 
|  | result_ ^= result.raw(); | 
|  | result_ = H.Canonicalize(result_); | 
|  |  | 
|  | builder_->SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateStaticInvocation() { | 
|  | builder_->ReadPosition();  // read position. | 
|  | NameIndex procedure_reference = | 
|  | builder_->ReadCanonicalNameReference();  // read procedure reference. | 
|  |  | 
|  | const Function& function = Function::ZoneHandle( | 
|  | Z, H.LookupStaticMethodByKernelProcedure(procedure_reference)); | 
|  | Class& klass = Class::Handle(Z, function.Owner()); | 
|  |  | 
|  | intptr_t argument_count = | 
|  | builder_->ReadUInt();  // read arguments part #1: arguments count. | 
|  |  | 
|  | // Build the type arguments vector (if necessary). | 
|  | const TypeArguments* type_arguments = | 
|  | TranslateTypeArguments(function, &klass);  // read argument types. | 
|  |  | 
|  | // read positional and named parameters. | 
|  | const Object& result = | 
|  | RunFunction(function, argument_count, NULL, type_arguments); | 
|  | result_ ^= result.raw(); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateConstructorInvocationInternal() { | 
|  | builder_->ReadPosition();  // read position. | 
|  |  | 
|  | NameIndex target = builder_->ReadCanonicalNameReference();  // read target. | 
|  | const Function& constructor = | 
|  | Function::Handle(Z, H.LookupConstructorByKernelConstructor(target)); | 
|  | Class& klass = Class::Handle(Z, constructor.Owner()); | 
|  |  | 
|  | intptr_t argument_count = | 
|  | builder_->ReadUInt();  // read arguments part #1: arguments count. | 
|  |  | 
|  | // Build the type arguments vector (if necessary). | 
|  | const TypeArguments* type_arguments = | 
|  | TranslateTypeArguments(constructor, &klass);  // read argument types. | 
|  |  | 
|  | if (klass.NumTypeArguments() > 0 && !klass.IsGeneric()) { | 
|  | Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw()); | 
|  | // TODO(27590): Can we move this code into [ReceiverType]? | 
|  | type ^= ClassFinalizer::FinalizeType(*builder_->active_class()->klass, type, | 
|  | ClassFinalizer::kFinalize); | 
|  | ASSERT(!type.IsMalformedOrMalbounded()); | 
|  |  | 
|  | TypeArguments& canonicalized_type_arguments = | 
|  | TypeArguments::ZoneHandle(Z, type.arguments()); | 
|  | canonicalized_type_arguments = canonicalized_type_arguments.Canonicalize(); | 
|  | type_arguments = &canonicalized_type_arguments; | 
|  | } | 
|  |  | 
|  | // Prepare either the instance or the type argument vector for the constructor | 
|  | // call. | 
|  | Instance* receiver = NULL; | 
|  | const TypeArguments* type_arguments_argument = NULL; | 
|  | if (!constructor.IsFactory()) { | 
|  | receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld)); | 
|  | if (type_arguments != NULL) { | 
|  | receiver->SetTypeArguments(*type_arguments); | 
|  | } | 
|  | } else { | 
|  | type_arguments_argument = type_arguments; | 
|  | } | 
|  |  | 
|  | // read positional and named parameters. | 
|  | const Object& result = RunFunction(constructor, argument_count, receiver, | 
|  | type_arguments_argument); | 
|  |  | 
|  | if (constructor.IsFactory()) { | 
|  | // Factories return the new object. | 
|  | result_ ^= result.raw(); | 
|  | } else { | 
|  | ASSERT(!receiver->IsNull()); | 
|  | result_ ^= (*receiver).raw(); | 
|  | } | 
|  | if (I->obfuscate() && | 
|  | (result_.clazz() == I->object_store()->symbol_class())) { | 
|  | Obfuscator::ObfuscateSymbolInstance(H.thread(), result_); | 
|  | } | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateNot() { | 
|  | result_ ^= Bool::Get(!EvaluateBooleanExpressionHere()).raw(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateLogicalExpression() { | 
|  | bool left = EvaluateBooleanExpressionHere();  // read left. | 
|  | LogicalOperator op = static_cast<LogicalOperator>(builder_->ReadByte()); | 
|  | if (op == kAnd) { | 
|  | if (left) { | 
|  | EvaluateBooleanExpressionHere();  // read right. | 
|  | } else { | 
|  | builder_->SkipExpression();  // read right. | 
|  | } | 
|  | } else { | 
|  | ASSERT(op == kOr); | 
|  | if (!left) { | 
|  | EvaluateBooleanExpressionHere();  // read right. | 
|  | } else { | 
|  | builder_->SkipExpression();  // read right. | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateAsExpression() { | 
|  | builder_->ReadPosition(); | 
|  | const uint8_t flags = builder_->ReadFlags(); | 
|  | const bool is_type_error = (flags & (1 << 0)) != 0; | 
|  |  | 
|  | // Check that this AsExpression was inserted by the front-end. | 
|  | if (!is_type_error) { | 
|  | H.ReportError( | 
|  | script_, TokenPosition::kNoSource, | 
|  | "explicit as operator is not permitted in constant expression"); | 
|  | } | 
|  |  | 
|  | EvaluateExpression(builder_->ReaderOffset(), false); | 
|  |  | 
|  | const AbstractType& type = T.BuildType(); | 
|  | if (!type.IsInstantiated() || type.IsMalformed()) { | 
|  | H.ReportError( | 
|  | script_, TokenPosition::kNoSource, | 
|  | "Not a constant expression: right hand side of an implicit " | 
|  | "as-expression is expected to be an instantiated type, got %s", | 
|  | type.ToCString()); | 
|  | } | 
|  |  | 
|  | const TypeArguments& instantiator_type_arguments = TypeArguments::Handle(); | 
|  | const TypeArguments& function_type_arguments = TypeArguments::Handle(); | 
|  | Error& error = Error::Handle(); | 
|  | if (!result_.IsInstanceOf(type, instantiator_type_arguments, | 
|  | function_type_arguments, &error)) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Not a constant expression: %s is not an instance of %s", | 
|  | result_.ToCString(), type.ToCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateConditionalExpression() { | 
|  | bool condition = EvaluateBooleanExpressionHere(); | 
|  | if (condition) { | 
|  | EvaluateExpression(builder_->ReaderOffset(), false);  // read then. | 
|  | builder_->SkipExpression();                           // read otherwise. | 
|  | } else { | 
|  | builder_->SkipExpression();                           // read then. | 
|  | EvaluateExpression(builder_->ReaderOffset(), false);  // read otherwise. | 
|  | } | 
|  | builder_->SkipOptionalDartType();  // read unused static type. | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateStringConcatenation() { | 
|  | builder_->ReadPosition();                      // read position. | 
|  | intptr_t length = builder_->ReadListLength();  // read list length. | 
|  |  | 
|  | bool all_string = true; | 
|  | const Array& strings = | 
|  | Array::Handle(Z, Array::New(length, H.allocation_space())); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | EvaluateExpression(builder_->ReaderOffset(), | 
|  | false);  // read ith expression. | 
|  | strings.SetAt(i, result_); | 
|  | all_string = all_string && result_.IsString(); | 
|  | } | 
|  | if (all_string) { | 
|  | result_ = String::ConcatAll(strings, Heap::kOld); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } else { | 
|  | // Get string interpolation function. | 
|  | const Class& cls = | 
|  | Class::Handle(Z, Library::LookupCoreClass(Symbols::StringBase())); | 
|  | ASSERT(!cls.IsNull()); | 
|  | const Function& func = Function::Handle( | 
|  | Z, cls.LookupStaticFunction( | 
|  | Library::PrivateCoreLibName(Symbols::Interpolate()))); | 
|  | ASSERT(!func.IsNull()); | 
|  |  | 
|  | // Build argument array to pass to the interpolation function. | 
|  | const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld)); | 
|  | interpolate_arg.SetAt(0, strings); | 
|  |  | 
|  | // Run and canonicalize. | 
|  | const Object& result = | 
|  | RunFunction(func, interpolate_arg, Array::null_array()); | 
|  | result_ = H.Canonicalize(String::Cast(result)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateSymbolLiteral() { | 
|  | // The symbol value is read plain and obfuscated later. | 
|  | const String& symbol_value = H.DartSymbolPlain( | 
|  | builder_->ReadStringReference());  // read index into string table. | 
|  |  | 
|  | const Class& symbol_class = | 
|  | Class::ZoneHandle(Z, I->object_store()->symbol_class()); | 
|  | ASSERT(!symbol_class.IsNull()); | 
|  | const Function& symbol_constructor = Function::ZoneHandle( | 
|  | Z, symbol_class.LookupConstructor(Symbols::SymbolCtor())); | 
|  | ASSERT(!symbol_constructor.IsNull()); | 
|  | result_ ^= EvaluateConstConstructorCall( | 
|  | symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateTypeLiteral() { | 
|  | const AbstractType& type = T.BuildType(); | 
|  | if (type.IsMalformed()) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Malformed type literal in constant expression."); | 
|  | } | 
|  | result_ = type.raw(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateListLiteralInternal() { | 
|  | builder_->ReadPosition();  // read position. | 
|  | const TypeArguments& type_arguments = T.BuildTypeArguments(1);  // read type. | 
|  | intptr_t length = builder_->ReadListLength();  // read list length. | 
|  | const Array& const_list = | 
|  | Array::ZoneHandle(Z, Array::New(length, Heap::kOld)); | 
|  | const_list.SetTypeArguments(type_arguments); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | const Instance& expression = EvaluateExpression( | 
|  | builder_->ReaderOffset(), false);  // read ith expression. | 
|  | const_list.SetAt(i, expression); | 
|  | } | 
|  | const_list.MakeImmutable(); | 
|  | result_ = H.Canonicalize(const_list); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateMapLiteralInternal() { | 
|  | builder_->ReadPosition();  // read position. | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(2);  // read key type and value type. | 
|  |  | 
|  | intptr_t length = builder_->ReadListLength();  // read length of entries. | 
|  |  | 
|  | // This MapLiteral wasn't cached, so content isn't cached either. | 
|  | Array& const_kv_array = | 
|  | Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld)); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | const_kv_array.SetAt(2 * i + 0, EvaluateExpression(builder_->ReaderOffset(), | 
|  | false));  // read key. | 
|  | const_kv_array.SetAt(2 * i + 1, EvaluateExpression(builder_->ReaderOffset(), | 
|  | false));  // read value. | 
|  | } | 
|  |  | 
|  | const_kv_array.MakeImmutable(); | 
|  | const_kv_array ^= H.Canonicalize(const_kv_array); | 
|  |  | 
|  | const Class& map_class = | 
|  | Class::Handle(Z, Library::LookupCoreClass(Symbols::ImmutableMap())); | 
|  | ASSERT(!map_class.IsNull()); | 
|  | ASSERT(map_class.NumTypeArguments() == 2); | 
|  |  | 
|  | const Field& field = | 
|  | Field::Handle(Z, map_class.LookupInstanceFieldAllowPrivate( | 
|  | H.DartSymbolObfuscate("_kvPairs"))); | 
|  | ASSERT(!field.IsNull()); | 
|  |  | 
|  | // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`! | 
|  | result_ = Instance::New(map_class, Heap::kOld); | 
|  | ASSERT(!result_.IsNull()); | 
|  | result_.SetTypeArguments(type_arguments); | 
|  | result_.SetField(field, const_kv_array); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateLet() { | 
|  | intptr_t kernel_position = | 
|  | builder_->ReaderOffset() + builder_->data_program_offset_; | 
|  | LocalVariable* local = builder_->LookupVariable(kernel_position); | 
|  |  | 
|  | // read variable declaration. | 
|  | VariableDeclarationHelper helper(builder_); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer); | 
|  | Tag tag = builder_->ReadTag();  // read (first part of) initializer. | 
|  | if (tag == kNothing) { | 
|  | local->SetConstValue(Instance::ZoneHandle(Z, Instance::null())); | 
|  | } else { | 
|  | local->SetConstValue(EvaluateExpression( | 
|  | builder_->ReaderOffset(), false));  // read rest of initializer. | 
|  | } | 
|  |  | 
|  | EvaluateExpression(builder_->ReaderOffset(), false);  // read body | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluatePartialTearoffInstantiation() { | 
|  | // This method call wasn't cached, so receiver et al. isn't cached either. | 
|  | const Instance& receiver = | 
|  | EvaluateExpression(builder_->ReaderOffset(), false);  // read receiver. | 
|  | if (!receiver.IsClosure()) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, "Expected closure."); | 
|  | } | 
|  | const Closure& old_closure = Closure::Cast(receiver); | 
|  |  | 
|  | // read type arguments. | 
|  | intptr_t num_type_args = builder_->ReadListLength(); | 
|  | const TypeArguments* type_args = &T.BuildTypeArguments(num_type_args); | 
|  | // Even if all dynamic types are passed in, we need to put a vector in here to | 
|  | // distinguish this partially applied tearoff from a normal tearoff. This is | 
|  | // necessary because the tearoff wrapper (BuildGraphOfImplicitClosureFunction) | 
|  | // needs to throw NSM if type arguments are passed to a partially applied | 
|  | // tearoff. | 
|  | if (type_args->IsNull()) { | 
|  | type_args = | 
|  | &TypeArguments::ZoneHandle(Z, TypeArguments::New(num_type_args)); | 
|  | for (intptr_t i = 0; i < num_type_args; ++i) { | 
|  | type_args->SetTypeAt(i, Type::ZoneHandle(Z, Type::DynamicType())); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Create new closure with the type arguments inserted, and other things | 
|  | // copied over. | 
|  | Closure& new_closure = Closure::Handle( | 
|  | Z, Closure::New(TypeArguments::Handle( | 
|  | Z, old_closure.instantiator_type_arguments()), | 
|  | *type_args, Function::Handle(Z, old_closure.function()), | 
|  | Context::Handle(Z, old_closure.context()), Heap::kOld)); | 
|  | result_ = H.Canonicalize(new_closure); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateBigIntLiteral() { | 
|  | const String& value = | 
|  | H.DartString(builder_->ReadStringReference());  // read string reference. | 
|  | result_ = Integer::New(value, Heap::kOld); | 
|  | if (result_.IsNull()) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Integer literal %s is out of range", value.ToCString()); | 
|  | } | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateStringLiteral() { | 
|  | result_ = H.DartSymbolPlain(builder_->ReadStringReference()) | 
|  | .raw();  // read string reference. | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateIntLiteral(uint8_t payload) { | 
|  | int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias; | 
|  | result_ = Integer::New(value, Heap::kOld); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateIntLiteral(bool is_negative) { | 
|  | int64_t value = is_negative ? -static_cast<int64_t>(builder_->ReadUInt()) | 
|  | : builder_->ReadUInt();  // read value. | 
|  | result_ = Integer::New(value, Heap::kOld); | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateDoubleLiteral() { | 
|  | result_ = Double::New(H.DartString(builder_->ReadStringReference()), | 
|  | Heap::kOld);  // read string reference. | 
|  | result_ = H.Canonicalize(result_); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateBoolLiteral(bool value) { | 
|  | result_ = Bool::Get(value).raw(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateNullLiteral() { | 
|  | result_ = Instance::null(); | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::EvaluateConstantExpression() { | 
|  | result_ ^= H.constants().At(builder_->ReadUInt()); | 
|  | } | 
|  |  | 
|  | // This depends on being about to read the list of positionals on arguments. | 
|  | const Object& StreamingConstantEvaluator::RunFunction( | 
|  | const Function& function, | 
|  | intptr_t argument_count, | 
|  | const Instance* receiver, | 
|  | const TypeArguments* type_args) { | 
|  | // We do not support generic methods yet. | 
|  | ASSERT((receiver == NULL) || (type_args == NULL)); | 
|  | intptr_t extra_arguments = | 
|  | (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0); | 
|  |  | 
|  | // Build up arguments. | 
|  | const Array& arguments = Array::ZoneHandle( | 
|  | Z, Array::New(extra_arguments + argument_count, H.allocation_space())); | 
|  | intptr_t pos = 0; | 
|  | if (receiver != NULL) { | 
|  | arguments.SetAt(pos++, *receiver); | 
|  | } | 
|  | if (type_args != NULL) { | 
|  | arguments.SetAt(pos++, *type_args); | 
|  | } | 
|  |  | 
|  | // List of positional. | 
|  | intptr_t list_length = builder_->ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | EvaluateExpression(builder_->ReaderOffset(), | 
|  | false);  // read ith expression. | 
|  | arguments.SetAt(pos++, result_); | 
|  | } | 
|  |  | 
|  | // List of named. | 
|  | list_length = builder_->ReadListLength();  // read list length. | 
|  | const Array& names = | 
|  | Array::ZoneHandle(Z, Array::New(list_length, H.allocation_space())); | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | String& name = H.DartSymbolObfuscate( | 
|  | builder_->ReadStringReference());  // read ith name index. | 
|  | names.SetAt(i, name); | 
|  | EvaluateExpression(builder_->ReaderOffset(), | 
|  | false);  // read ith expression. | 
|  | arguments.SetAt(pos++, result_); | 
|  | } | 
|  |  | 
|  | return RunFunction(function, arguments, names); | 
|  | } | 
|  |  | 
|  | const Object& StreamingConstantEvaluator::RunFunction(const Function& function, | 
|  | const Array& arguments, | 
|  | const Array& names) { | 
|  | // We do not support generic methods yet. | 
|  | const int kTypeArgsLen = 0; | 
|  | const Array& args_descriptor = Array::Handle( | 
|  | Z, ArgumentsDescriptor::New(kTypeArgsLen, arguments.Length(), names)); | 
|  | const Object& result = Object::Handle( | 
|  | Z, DartEntry::InvokeFunction(function, arguments, args_descriptor)); | 
|  | if (result.IsError()) { | 
|  | H.ReportError(Error::Cast(result), "error evaluating constant constructor"); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Object& StreamingConstantEvaluator::RunMethodCall( | 
|  | const Function& function, | 
|  | const Instance* receiver) { | 
|  | intptr_t argument_count = builder_->ReadUInt();  // read arguments count. | 
|  |  | 
|  | // TODO(28109) Support generic methods in the VM or reify them away. | 
|  | ASSERT(builder_->PeekListLength() == 0); | 
|  | builder_->SkipListOfDartTypes();  // read list of types. | 
|  |  | 
|  | // Run the method. | 
|  | return RunFunction(function, argument_count, receiver, NULL); | 
|  | } | 
|  |  | 
|  | RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall( | 
|  | const Class& type_class, | 
|  | const TypeArguments& type_arguments, | 
|  | const Function& constructor, | 
|  | const Object& argument) { | 
|  | // Factories have one extra argument: the type arguments. | 
|  | // Constructors have 1 extra arguments: receiver. | 
|  | const int kTypeArgsLen = 0; | 
|  | const int kNumArgs = 1; | 
|  | const int kNumExtraArgs = 1; | 
|  | const int argument_count = kNumArgs + kNumExtraArgs; | 
|  | const Array& arg_values = | 
|  | Array::Handle(Z, Array::New(argument_count, Heap::kOld)); | 
|  | Instance& instance = Instance::Handle(Z); | 
|  | if (!constructor.IsFactory()) { | 
|  | instance = Instance::New(type_class, Heap::kOld); | 
|  | if (!type_arguments.IsNull()) { | 
|  | ASSERT(type_arguments.IsInstantiated()); | 
|  | instance.SetTypeArguments( | 
|  | TypeArguments::Handle(Z, type_arguments.Canonicalize())); | 
|  | } | 
|  | arg_values.SetAt(0, instance); | 
|  | } else { | 
|  | // Prepend type_arguments to list of arguments to factory. | 
|  | ASSERT(type_arguments.IsZoneHandle()); | 
|  | arg_values.SetAt(0, type_arguments); | 
|  | } | 
|  | arg_values.SetAt((0 + kNumExtraArgs), argument); | 
|  | const Array& args_descriptor = | 
|  | Array::Handle(Z, ArgumentsDescriptor::New(kTypeArgsLen, argument_count, | 
|  | Object::empty_array())); | 
|  | const Object& result = Object::Handle( | 
|  | Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor)); | 
|  | ASSERT(!result.IsError()); | 
|  | if (constructor.IsFactory()) { | 
|  | // The factory method returns the allocated object. | 
|  | instance ^= result.raw(); | 
|  | } | 
|  | if (I->obfuscate() && | 
|  | (instance.clazz() == I->object_store()->symbol_class())) { | 
|  | Obfuscator::ObfuscateSymbolInstance(H.thread(), instance); | 
|  | } | 
|  | return H.Canonicalize(instance); | 
|  | } | 
|  |  | 
|  | const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments( | 
|  | const Function& target, | 
|  | Class* target_klass) { | 
|  | intptr_t type_count = builder_->ReadListLength();  // read type count. | 
|  |  | 
|  | const TypeArguments* type_arguments = NULL; | 
|  | if (type_count > 0) { | 
|  | type_arguments = &T.BuildInstantiatedTypeArguments( | 
|  | *target_klass, type_count);  // read types. | 
|  |  | 
|  | if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Type must be constant in const constructor."); | 
|  | } | 
|  | } else if (target.IsFactory() && type_arguments == NULL) { | 
|  | // All factories take a type arguments vector as first argument (independent | 
|  | // of whether the class is generic or not). | 
|  | type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null()); | 
|  | } | 
|  | return type_arguments; | 
|  | } | 
|  |  | 
|  | bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() { | 
|  | EvaluateExpression(builder_->ReaderOffset(), false); | 
|  | AssertBool(); | 
|  | return result_.raw() == Bool::True().raw(); | 
|  | } | 
|  |  | 
|  | bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset, | 
|  | Instance* value) { | 
|  | if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return false; | 
|  |  | 
|  | const Function& function = builder_->parsed_function()->function(); | 
|  | if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { | 
|  | // Don't cache constants in initializer expressions. They get | 
|  | // evaluated only once. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool is_present = false; | 
|  | ASSERT(!script_.InVMHeap()); | 
|  | if (script_.compile_time_constants() == Array::null()) { | 
|  | return false; | 
|  | } | 
|  | KernelConstantsMap constants(script_.compile_time_constants()); | 
|  | *value ^= constants.GetOrNull(kernel_offset + builder_->data_program_offset_, | 
|  | &is_present); | 
|  | // Mutator compiler thread may add constants while background compiler | 
|  | // is running, and thus change the value of 'compile_time_constants'; | 
|  | // do not assert that 'compile_time_constants' has not changed. | 
|  | constants.Release(); | 
|  | if (FLAG_compiler_stats && is_present) { | 
|  | ++H.thread()->compiler_stats()->num_const_cache_hits; | 
|  | } | 
|  | return is_present; | 
|  | } | 
|  |  | 
|  | void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset, | 
|  | const Instance& value) { | 
|  | ASSERT(Thread::Current()->IsMutatorThread()); | 
|  |  | 
|  | if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return; | 
|  |  | 
|  | const Function& function = builder_->parsed_function()->function(); | 
|  | if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { | 
|  | // Don't cache constants in initializer expressions. They get | 
|  | // evaluated only once. | 
|  | return; | 
|  | } | 
|  | const intptr_t kInitialConstMapSize = 16; | 
|  | ASSERT(!script_.InVMHeap()); | 
|  | if (script_.compile_time_constants() == Array::null()) { | 
|  | const Array& array = Array::Handle( | 
|  | HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew)); | 
|  | script_.set_compile_time_constants(array); | 
|  | } | 
|  | KernelConstantsMap constants(script_.compile_time_constants()); | 
|  | constants.InsertNewOrGetValue(kernel_offset + builder_->data_program_offset_, | 
|  | value); | 
|  | script_.set_compile_time_constants(constants.Release()); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::DiscoverEnclosingElements( | 
|  | Zone* zone, | 
|  | const Function& function, | 
|  | Function* outermost_function) { | 
|  | // 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(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::BuildHash(uint32_t val) { | 
|  | hash_ = CalculateHash(hash_, val); | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateConstructorFingerprint() { | 
|  | ConstructorHelper helper(this); | 
|  |  | 
|  | helper.ReadUntilExcluding(ConstructorHelper::kAnnotations); | 
|  | CalculateListOfExpressionsFingerprint(); | 
|  | CalculateFunctionNodeFingerprint(); | 
|  | intptr_t len = ReadListLength(); | 
|  | for (intptr_t i = 0; i < len; ++i) { | 
|  | CalculateInitializerFingerprint(); | 
|  | } | 
|  | helper.SetJustRead(ConstructorHelper::kInitializers); | 
|  | BuildHash(helper.flags_); | 
|  | BuildHash(helper.annotation_count_); | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateArgumentsFingerprint() { | 
|  | BuildHash(ReadUInt());  // read argument count. | 
|  |  | 
|  | CalculateListOfDartTypesFingerprint();    // read list of types. | 
|  | CalculateListOfExpressionsFingerprint();  // read positionals. | 
|  |  | 
|  | // List of named. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateStringReferenceFingerprint();  // read ith name index. | 
|  | CalculateExpressionFingerprint();       // read ith expression. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateVariableDeclarationFingerprint() { | 
|  | VariableDeclarationHelper helper(this); | 
|  |  | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations); | 
|  | CalculateListOfExpressionsFingerprint(); | 
|  | helper.SetJustRead(VariableDeclarationHelper::kAnnotations); | 
|  |  | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kType); | 
|  | // We don't need to use the helper after this point. | 
|  | CalculateDartTypeFingerprint(); | 
|  | if (ReadTag() == kSomething) { | 
|  | CalculateExpressionFingerprint(); | 
|  | } | 
|  |  | 
|  | BuildHash(helper.flags_); | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateStatementListFingerprint() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateStatementFingerprint();  // read ith expression. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateListOfExpressionsFingerprint() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateExpressionFingerprint();  // read ith expression. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateListOfDartTypesFingerprint() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateDartTypeFingerprint();  // read ith type. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateStringReferenceFingerprint() { | 
|  | BuildHash( | 
|  | H.DartString(ReadStringReference()).Hash());  // read ith string index. | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateListOfStringsFingerprint() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateStringReferenceFingerprint();  // read ith string index. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateListOfVariableDeclarationsFingerprint() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | // read ith variable declaration. | 
|  | CalculateVariableDeclarationFingerprint(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateTypeParameterFingerprint() { | 
|  | TypeParameterHelper helper(this); | 
|  |  | 
|  | helper.ReadUntilExcluding(TypeParameterHelper::kAnnotations); | 
|  | CalculateListOfExpressionsFingerprint(); | 
|  | helper.SetJustRead(TypeParameterHelper::kAnnotations); | 
|  |  | 
|  | helper.ReadUntilExcluding(TypeParameterHelper::kBound); | 
|  | // The helper isn't needed after this point. | 
|  | CalculateDartTypeFingerprint(); | 
|  | if (ReadTag() == kSomething) { | 
|  | CalculateDartTypeFingerprint(); | 
|  | } | 
|  | BuildHash(helper.flags_); | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateTypeParametersListFingerprint() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateTypeParameterFingerprint(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateCanonicalNameFingerprint() { | 
|  | const StringIndex i = H.CanonicalNameString(ReadCanonicalNameReference()); | 
|  | BuildHash(H.DartString(i).Hash()); | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateInitializerFingerprint() { | 
|  | Tag tag = ReadTag(); | 
|  | ReadByte();  // read isSynthetic flag. | 
|  | switch (tag) { | 
|  | case kInvalidInitializer: | 
|  | return; | 
|  | case kFieldInitializer: | 
|  | BuildHash(H.DartFieldName(ReadCanonicalNameReference()).Hash()); | 
|  | CalculateExpressionFingerprint();  // read value. | 
|  | return; | 
|  | case kSuperInitializer: | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference | 
|  | CalculateArgumentsFingerprint();      // read arguments. | 
|  | return; | 
|  | case kRedirectingInitializer: | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference | 
|  | CalculateArgumentsFingerprint();      // read arguments. | 
|  | return; | 
|  | case kLocalInitializer: | 
|  | CalculateVariableDeclarationFingerprint();  // read variable. | 
|  | return; | 
|  | case kAssertInitializer: | 
|  | CalculateStatementFingerprint(); | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("initializer", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateDartTypeFingerprint() { | 
|  | Tag tag = ReadTag(); | 
|  | BuildHash(tag); | 
|  | switch (tag) { | 
|  | case kInvalidType: | 
|  | case kDynamicType: | 
|  | case kVoidType: | 
|  | case kBottomType: | 
|  | case kVectorType: | 
|  | // those contain nothing. | 
|  | break; | 
|  | case kInterfaceType: | 
|  | CalculateInterfaceTypeFingerprint(false); | 
|  | break; | 
|  | case kSimpleInterfaceType: | 
|  | CalculateInterfaceTypeFingerprint(true); | 
|  | break; | 
|  | case kFunctionType: | 
|  | CalculateFunctionTypeFingerprint(false); | 
|  | break; | 
|  | case kSimpleFunctionType: | 
|  | CalculateFunctionTypeFingerprint(true); | 
|  | break; | 
|  | case kTypeParameterType: | 
|  | ReadUInt();                              // read index for parameter. | 
|  | CalculateOptionalDartTypeFingerprint();  // read bound bound. | 
|  | break; | 
|  | default: | 
|  | ReportUnexpectedTag("type", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateOptionalDartTypeFingerprint() { | 
|  | Tag tag = ReadTag();  // read tag. | 
|  | BuildHash(tag); | 
|  | if (tag == kNothing) { | 
|  | return; | 
|  | } | 
|  | ASSERT(tag == kSomething); | 
|  | CalculateDartTypeFingerprint();  // read type. | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateInterfaceTypeFingerprint(bool simple) { | 
|  | BuildHash(ReadUInt());  // read klass_name. | 
|  | if (!simple) { | 
|  | CalculateListOfDartTypesFingerprint();  // read list of types. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateFunctionTypeFingerprint(bool simple) { | 
|  | if (!simple) { | 
|  | CalculateTypeParametersListFingerprint();  // read type_parameters. | 
|  | BuildHash(ReadUInt());                     // read required parameter count. | 
|  | BuildHash(ReadUInt());                     // read total parameter count. | 
|  | } | 
|  |  | 
|  | CalculateListOfDartTypesFingerprint();  // read positional_parameters types. | 
|  |  | 
|  | if (!simple) { | 
|  | const intptr_t named_count = | 
|  | ReadListLength();  // read named_parameters list length. | 
|  | BuildHash(named_count); | 
|  | for (intptr_t i = 0; i < named_count; ++i) { | 
|  | // read string reference (i.e. named_parameters[i].name). | 
|  | CalculateStringReferenceFingerprint(); | 
|  | CalculateDartTypeFingerprint();  // read named_parameters[i].type. | 
|  | } | 
|  | } | 
|  |  | 
|  | CalculateListOfStringsFingerprint();  // read positional parameter names. | 
|  |  | 
|  | if (!simple) { | 
|  | // TODO(bkonyi): include in hash. | 
|  | SkipCanonicalNameReference();  // read typedef reference. | 
|  | } | 
|  |  | 
|  | CalculateDartTypeFingerprint();  // read return type. | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateGetterNameFingerprint() { | 
|  | const NameIndex name = ReadCanonicalNameReference(); | 
|  | if (I->strong() && !H.IsRoot(name) && (H.IsGetter(name) || H.IsField(name))) { | 
|  | BuildHash(H.DartGetterName(name).Hash()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateSetterNameFingerprint() { | 
|  | const NameIndex name = ReadCanonicalNameReference(); | 
|  | if (I->strong() && !H.IsRoot(name)) { | 
|  | BuildHash(H.DartSetterName(name).Hash()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateMethodNameFingerprint() { | 
|  | const NameIndex name = | 
|  | ReadCanonicalNameReference();  // read interface_target_reference. | 
|  | if (I->strong() && !H.IsRoot(name) && !H.IsField(name)) { | 
|  | BuildHash(H.DartProcedureName(name).Hash()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateExpressionFingerprint() { | 
|  | uint8_t payload = 0; | 
|  | Tag tag = ReadTag(&payload); | 
|  | BuildHash(tag); | 
|  | switch (tag) { | 
|  | case kInvalidExpression: | 
|  | ReadPosition(); | 
|  | CalculateStringReferenceFingerprint(); | 
|  | return; | 
|  | case kVariableGet: | 
|  | ReadPosition();                          // read position. | 
|  | ReadUInt();                              // read kernel position. | 
|  | ReadUInt();                              // read relative variable index. | 
|  | CalculateOptionalDartTypeFingerprint();  // read promoted type. | 
|  | return; | 
|  | case kSpecializedVariableGet: | 
|  | ReadPosition();  // read position. | 
|  | ReadUInt();      // read kernel position. | 
|  | return; | 
|  | case kVariableSet: | 
|  | ReadPosition();                    // read position. | 
|  | ReadUInt();                        // read kernel position. | 
|  | ReadUInt();                        // read relative variable index. | 
|  | CalculateExpressionFingerprint();  // read expression. | 
|  | return; | 
|  | case kSpecializedVariableSet: | 
|  | ReadPosition();                    // read position. | 
|  | ReadUInt();                        // read kernel position. | 
|  | CalculateExpressionFingerprint();  // read expression. | 
|  | return; | 
|  | case kPropertyGet: | 
|  | ReadPosition();                            // read position. | 
|  | CalculateExpressionFingerprint();          // read receiver. | 
|  | BuildHash(ReadNameAsGetterName().Hash());  // read name. | 
|  | CalculateGetterNameFingerprint();  // read interface_target_reference. | 
|  | return; | 
|  | case kPropertySet: | 
|  | ReadPosition();                            // read position. | 
|  | CalculateExpressionFingerprint();          // read receiver. | 
|  | BuildHash(ReadNameAsSetterName().Hash());  // read name. | 
|  | CalculateExpressionFingerprint();          // read value. | 
|  | CalculateSetterNameFingerprint();  // read interface_target_reference. | 
|  | return; | 
|  | case kSuperPropertyGet: | 
|  | ReadPosition();                            // read position. | 
|  | BuildHash(ReadNameAsGetterName().Hash());  // read name. | 
|  | CalculateGetterNameFingerprint();  // read interface_target_reference. | 
|  | return; | 
|  | case kSuperPropertySet: | 
|  | ReadPosition();                            // read position. | 
|  | BuildHash(ReadNameAsSetterName().Hash());  // read name. | 
|  | CalculateExpressionFingerprint();          // read value. | 
|  | CalculateSetterNameFingerprint();  // read interface_target_reference. | 
|  | return; | 
|  | case kDirectPropertyGet: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateExpressionFingerprint();     // read receiver. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | return; | 
|  | case kDirectPropertySet: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateExpressionFingerprint();     // read receiver. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | CalculateExpressionFingerprint();     // read value· | 
|  | return; | 
|  | case kStaticGet: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | return; | 
|  | case kStaticSet: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | CalculateExpressionFingerprint();     // read expression. | 
|  | return; | 
|  | case kMethodInvocation: | 
|  | ReadPosition();                            // read position. | 
|  | CalculateExpressionFingerprint();          // read receiver. | 
|  | BuildHash(ReadNameAsMethodName().Hash());  // read name. | 
|  | CalculateArgumentsFingerprint();           // read arguments. | 
|  | CalculateMethodNameFingerprint();  // read interface_target_reference. | 
|  | return; | 
|  | case kSuperMethodInvocation: | 
|  | ReadPosition();                            // read position. | 
|  | BuildHash(ReadNameAsMethodName().Hash());  // read name. | 
|  | CalculateArgumentsFingerprint();           // read arguments. | 
|  | CalculateCanonicalNameFingerprint();       // read target_reference. | 
|  | return; | 
|  | case kDirectMethodInvocation: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateExpressionFingerprint();     // read receiver. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | CalculateArgumentsFingerprint();      // read arguments. | 
|  | return; | 
|  | case kStaticInvocation: | 
|  | case kConstStaticInvocation: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | CalculateArgumentsFingerprint();      // read arguments. | 
|  | return; | 
|  | case kConstructorInvocation: | 
|  | case kConstConstructorInvocation: | 
|  | ReadPosition();                       // read position. | 
|  | CalculateCanonicalNameFingerprint();  // read target_reference. | 
|  | CalculateArgumentsFingerprint();      // read arguments. | 
|  | return; | 
|  | case kNot: | 
|  | CalculateExpressionFingerprint();  // read expression. | 
|  | return; | 
|  | case kLogicalExpression: | 
|  | CalculateExpressionFingerprint();  // read left. | 
|  | SkipBytes(1);                      // read operator. | 
|  | CalculateExpressionFingerprint();  // read right. | 
|  | return; | 
|  | case kConditionalExpression: | 
|  | CalculateExpressionFingerprint();        // read condition. | 
|  | CalculateExpressionFingerprint();        // read then. | 
|  | CalculateExpressionFingerprint();        // read otherwise. | 
|  | CalculateOptionalDartTypeFingerprint();  // read unused static type. | 
|  | return; | 
|  | case kStringConcatenation: | 
|  | ReadPosition();                           // read position. | 
|  | CalculateListOfExpressionsFingerprint();  // read list of expressions. | 
|  | return; | 
|  | case kIsExpression: | 
|  | ReadPosition();                    // read position. | 
|  | CalculateExpressionFingerprint();  // read operand. | 
|  | CalculateDartTypeFingerprint();    // read type. | 
|  | return; | 
|  | case kAsExpression: | 
|  | ReadPosition();                    // read position. | 
|  | BuildHash(ReadFlags());            // read flags. | 
|  | CalculateExpressionFingerprint();  // read operand. | 
|  | CalculateDartTypeFingerprint();    // read type. | 
|  | return; | 
|  | case kSymbolLiteral: | 
|  | CalculateStringReferenceFingerprint();  // read index into string table. | 
|  | return; | 
|  | case kTypeLiteral: | 
|  | CalculateDartTypeFingerprint();  // read type. | 
|  | return; | 
|  | case kThisExpression: | 
|  | return; | 
|  | case kRethrow: | 
|  | ReadPosition();  // read position. | 
|  | return; | 
|  | case kThrow: | 
|  | ReadPosition();                    // read position. | 
|  | CalculateExpressionFingerprint();  // read expression. | 
|  | return; | 
|  | case kListLiteral: | 
|  | case kConstListLiteral: | 
|  | ReadPosition();                           // read position. | 
|  | CalculateDartTypeFingerprint();           // read type. | 
|  | CalculateListOfExpressionsFingerprint();  // read list of expressions. | 
|  | return; | 
|  | case kMapLiteral: | 
|  | case kConstMapLiteral: { | 
|  | ReadPosition();                           // read position. | 
|  | CalculateDartTypeFingerprint();           // read type. | 
|  | CalculateDartTypeFingerprint();           // read value type. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | CalculateExpressionFingerprint();  // read ith key. | 
|  | CalculateExpressionFingerprint();  // read ith value. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kFunctionExpression: | 
|  | ReadPosition();                      // read position. | 
|  | CalculateFunctionNodeFingerprint();  // read function node. | 
|  | return; | 
|  | case kLet: | 
|  | CalculateVariableDeclarationFingerprint();  // read variable declaration. | 
|  | CalculateExpressionFingerprint();           // read expression. | 
|  | return; | 
|  | case kInstantiation: | 
|  | CalculateExpressionFingerprint();       // read expression. | 
|  | CalculateListOfDartTypesFingerprint();  // read type arguments. | 
|  | return; | 
|  | case kVectorCreation: | 
|  | BuildHash(ReadUInt());  // read value. | 
|  | return; | 
|  | case kVectorGet: | 
|  | CalculateExpressionFingerprint();  // read vector expression. | 
|  | BuildHash(ReadUInt());             // read index. | 
|  | return; | 
|  | case kVectorSet: | 
|  | CalculateExpressionFingerprint();  // read vector expression. | 
|  | BuildHash(ReadUInt());             // read index. | 
|  | CalculateExpressionFingerprint();  // read value. | 
|  | return; | 
|  | case kVectorCopy: | 
|  | CalculateExpressionFingerprint();  // read vector expression. | 
|  | return; | 
|  | case kClosureCreation: | 
|  | // read top-level function reference. | 
|  | CalculateCanonicalNameFingerprint(); | 
|  | CalculateExpressionFingerprint();       // read context vector. | 
|  | CalculateDartTypeFingerprint();         // read function type. | 
|  | CalculateListOfDartTypesFingerprint();  // read type arguments. | 
|  | return; | 
|  | case kBigIntLiteral: | 
|  | CalculateStringReferenceFingerprint();  // read string reference. | 
|  | return; | 
|  | case kStringLiteral: | 
|  | CalculateStringReferenceFingerprint();  // read string reference. | 
|  | return; | 
|  | case kSpecializedIntLiteral: | 
|  | return; | 
|  | case kNegativeIntLiteral: | 
|  | BuildHash(ReadUInt());  // read value. | 
|  | return; | 
|  | case kPositiveIntLiteral: | 
|  | BuildHash(ReadUInt());  // read value. | 
|  | return; | 
|  | case kDoubleLiteral: | 
|  | CalculateStringReferenceFingerprint();  // read index into string table. | 
|  | return; | 
|  | case kTrueLiteral: | 
|  | return; | 
|  | case kFalseLiteral: | 
|  | return; | 
|  | case kNullLiteral: | 
|  | return; | 
|  | case kConstantExpression: | 
|  | SkipConstantReference(); | 
|  | return; | 
|  | case kLoadLibrary: | 
|  | case kCheckLibraryIsLoaded: | 
|  | ReadUInt();  // skip library index | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("expression", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateStatementFingerprint() { | 
|  | Tag tag = ReadTag();  // read tag. | 
|  | BuildHash(tag); | 
|  | switch (tag) { | 
|  | case kExpressionStatement: | 
|  | CalculateExpressionFingerprint();  // read expression. | 
|  | return; | 
|  | case kBlock: | 
|  | CalculateStatementListFingerprint(); | 
|  | return; | 
|  | case kEmptyStatement: | 
|  | return; | 
|  | case kAssertBlock: | 
|  | CalculateStatementListFingerprint(); | 
|  | return; | 
|  | case kAssertStatement: | 
|  | CalculateExpressionFingerprint();  // Read condition. | 
|  | ReadPosition();                    // read condition start offset. | 
|  | ReadPosition();                    // read condition end offset. | 
|  | if (ReadTag() == kSomething) { | 
|  | CalculateExpressionFingerprint();  // read (rest of) message. | 
|  | } | 
|  | return; | 
|  | case kLabeledStatement: | 
|  | CalculateStatementFingerprint();  // read body. | 
|  | return; | 
|  | case kBreakStatement: | 
|  | ReadPosition();  // read position. | 
|  | ReadUInt();      // read target_index. | 
|  | return; | 
|  | case kWhileStatement: | 
|  | ReadPosition();                    // read position. | 
|  | CalculateExpressionFingerprint();  // read condition. | 
|  | CalculateStatementFingerprint();   // read body. | 
|  | return; | 
|  | case kDoStatement: | 
|  | ReadPosition();                    // read position. | 
|  | CalculateStatementFingerprint();   // read body. | 
|  | CalculateExpressionFingerprint();  // read condition. | 
|  | return; | 
|  | case kForStatement: { | 
|  | ReadPosition();                                    // read position. | 
|  | CalculateListOfVariableDeclarationsFingerprint();  // read variables. | 
|  | Tag tag = ReadTag();  // Read first part of condition. | 
|  | if (tag == kSomething) { | 
|  | CalculateExpressionFingerprint();  // read rest of condition. | 
|  | } | 
|  | CalculateListOfExpressionsFingerprint();  // read updates. | 
|  | CalculateStatementFingerprint();          // read body. | 
|  | return; | 
|  | } | 
|  | case kForInStatement: | 
|  | case kAsyncForInStatement: | 
|  | ReadPosition();                             // read position. | 
|  | ReadPosition();                             // read body position. | 
|  | CalculateVariableDeclarationFingerprint();  // read variable. | 
|  | CalculateExpressionFingerprint();           // read iterable. | 
|  | CalculateStatementFingerprint();            // read body. | 
|  | return; | 
|  | case kSwitchStatement: { | 
|  | ReadPosition();                     // read position. | 
|  | CalculateExpressionFingerprint();   // read condition. | 
|  | int case_count = ReadListLength();  // read number of cases. | 
|  | for (intptr_t i = 0; i < case_count; ++i) { | 
|  | int expression_count = ReadListLength();  // read number of expressions. | 
|  | for (intptr_t j = 0; j < expression_count; ++j) { | 
|  | ReadPosition();                    // read jth position. | 
|  | CalculateExpressionFingerprint();  // read jth expression. | 
|  | } | 
|  | BuildHash(ReadBool());            // read is_default. | 
|  | CalculateStatementFingerprint();  // read body. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kContinueSwitchStatement: | 
|  | ReadPosition();  // read position. | 
|  | ReadUInt();      // read target_index. | 
|  | return; | 
|  | case kIfStatement: | 
|  | ReadPosition();                    // read position. | 
|  | CalculateExpressionFingerprint();  // read condition. | 
|  | CalculateStatementFingerprint();   // read then. | 
|  | CalculateStatementFingerprint();   // read otherwise. | 
|  | return; | 
|  | case kReturnStatement: { | 
|  | ReadPosition();       // read position | 
|  | Tag tag = ReadTag();  // read (first part of) expression. | 
|  | BuildHash(tag); | 
|  | if (tag == kSomething) { | 
|  | CalculateExpressionFingerprint();  // read (rest of) expression. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kTryCatch: { | 
|  | CalculateStatementFingerprint();  // read body. | 
|  | BuildHash(ReadBool());            // read any_catch_needs_stack_trace. | 
|  | intptr_t catch_count = ReadListLength();  // read number of catches. | 
|  | for (intptr_t i = 0; i < catch_count; ++i) { | 
|  | ReadPosition();                  // read position. | 
|  | CalculateDartTypeFingerprint();  // read guard. | 
|  | tag = ReadTag();                 // read first part of exception. | 
|  | BuildHash(tag); | 
|  | if (tag == kSomething) { | 
|  | CalculateVariableDeclarationFingerprint();  // read exception. | 
|  | } | 
|  | tag = ReadTag();  // read first part of stack trace. | 
|  | BuildHash(tag); | 
|  | if (tag == kSomething) { | 
|  | CalculateVariableDeclarationFingerprint();  // read stack trace. | 
|  | } | 
|  | CalculateStatementFingerprint();  // read body. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kTryFinally: | 
|  | CalculateStatementFingerprint();  // read body. | 
|  | CalculateStatementFingerprint();  // read finalizer. | 
|  | return; | 
|  | case kYieldStatement: { | 
|  | ReadPosition();                    // read position. | 
|  | BuildHash(ReadByte());             // read flags. | 
|  | CalculateExpressionFingerprint();  // read expression. | 
|  | return; | 
|  | } | 
|  | case kVariableDeclaration: | 
|  | CalculateVariableDeclarationFingerprint();  // read variable declaration. | 
|  | return; | 
|  | case kFunctionDeclaration: | 
|  | ReadPosition();                             // read position. | 
|  | CalculateVariableDeclarationFingerprint();  // read variable. | 
|  | CalculateFunctionNodeFingerprint();         // read function node. | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("statement", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32_t KernelFingerprintHelper::CalculateFieldFingerprint() { | 
|  | hash_ = 0; | 
|  | FieldHelper field_helper(this); | 
|  |  | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kName); | 
|  | const String& name = ReadNameAsFieldName();  // read name. | 
|  | field_helper.SetJustRead(FieldHelper::kName); | 
|  |  | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kType); | 
|  | CalculateDartTypeFingerprint();  // read type. | 
|  | field_helper.SetJustRead(FieldHelper::kType); | 
|  |  | 
|  | if (ReadTag() == kSomething) { | 
|  | if (PeekTag() == kFunctionExpression) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | CalculateExpressionFingerprint(); | 
|  | } | 
|  | SkipExpression(); | 
|  | } | 
|  |  | 
|  | BuildHash(name.Hash()); | 
|  | BuildHash((field_helper.flags_ << 8) | field_helper.secondary_flags_); | 
|  | BuildHash(field_helper.annotation_count_); | 
|  | return hash_; | 
|  | } | 
|  |  | 
|  | void KernelFingerprintHelper::CalculateFunctionNodeFingerprint() { | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  | CalculateTypeParametersListFingerprint(); | 
|  | function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters); | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  | CalculateListOfVariableDeclarationsFingerprint();  // read positionals | 
|  | CalculateListOfVariableDeclarationsFingerprint();  // read named | 
|  | CalculateDartTypeFingerprint();                    // read return type. | 
|  |  | 
|  | if (ReadTag() == kSomething) { | 
|  | CalculateStatementFingerprint();  // Read body. | 
|  | } | 
|  | BuildHash(function_node_helper.total_parameter_count_); | 
|  | BuildHash(function_node_helper.required_parameter_count_); | 
|  | } | 
|  |  | 
|  | uint32_t KernelFingerprintHelper::CalculateFunctionFingerprint() { | 
|  | hash_ = 0; | 
|  | Tag tag = PeekTag(); | 
|  | if (tag == kField) { | 
|  | return CalculateFieldFingerprint(); | 
|  | } else if (tag == kConstructor) { | 
|  | CalculateConstructorFingerprint(); | 
|  | return hash_; | 
|  | } | 
|  | ProcedureHelper procedure_helper(this); | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kName); | 
|  | const String& name = ReadNameAsMethodName();  // Read name. | 
|  | procedure_helper.SetJustRead(ProcedureHelper::kName); | 
|  |  | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); | 
|  | if (ReadTag() == kSomething) { | 
|  | CalculateFunctionNodeFingerprint(); | 
|  | } | 
|  |  | 
|  | BuildHash(procedure_helper.kind_); | 
|  | BuildHash(procedure_helper.flags_); | 
|  | BuildHash(procedure_helper.flags2_); | 
|  | BuildHash(procedure_helper.annotation_count_); | 
|  | BuildHash(name.Hash()); | 
|  | return hash_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::ReadUntilFunctionNode( | 
|  | ParsedFunction* parsed_function) { | 
|  | const Tag tag = PeekTag(); | 
|  | if (tag == kProcedure) { | 
|  | ProcedureHelper procedure_helper(this); | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); | 
|  | if (ReadTag() == kNothing) {  // read function node tag. | 
|  | // Running a procedure without a function node doesn't make sense. | 
|  | UNREACHABLE(); | 
|  | } | 
|  | if (parsed_function != NULL && flow_graph_builder_ != nullptr && | 
|  | procedure_helper.IsForwardingStub() && !procedure_helper.IsAbstract()) { | 
|  | ASSERT(procedure_helper.forwarding_stub_super_target_ != -1); | 
|  | parsed_function->MarkForwardingStub( | 
|  | procedure_helper.forwarding_stub_super_target_); | 
|  | } | 
|  | // Now at start of FunctionNode. | 
|  | } else if (tag == kConstructor) { | 
|  | ConstructorHelper constructor_helper(this); | 
|  | constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction); | 
|  | // Now at start of FunctionNode. | 
|  | // Notice that we also have a list of initializers after that! | 
|  | } else if (tag == kFunctionNode) { | 
|  | // Already at start of FunctionNode. | 
|  | } else { | 
|  | ReportUnexpectedTag("a procedure, a constructor or a function node", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | StringIndex StreamingFlowGraphBuilder::GetNameFromVariableDeclaration( | 
|  | intptr_t kernel_offset, | 
|  | const Function& function) { | 
|  | TypedData& kernel_data = TypedData::Handle(Z, function.KernelData()); | 
|  | ASSERT(!kernel_data.IsNull()); | 
|  |  | 
|  | // Temporarily go to the variable declaration, read the name. | 
|  | AlternativeReadingScope alt(&reader_, &kernel_data, kernel_offset); | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilIncluding(VariableDeclarationHelper::kNameIndex); | 
|  | return helper.name_index_; | 
|  | } | 
|  |  | 
|  | bool StreamingFlowGraphBuilder::optimizing() { | 
|  | return flow_graph_builder_->optimizing_; | 
|  | } | 
|  |  | 
|  | FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldInitializer() { | 
|  | FieldHelper field_helper(this); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); | 
|  |  | 
|  | Tag initializer_tag = ReadTag();  // read first part of initializer. | 
|  | if (initializer_tag != kSomething) { | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); | 
|  | flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( | 
|  | *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); | 
|  |  | 
|  | Fragment body(normal_entry); | 
|  | body += | 
|  | flow_graph_builder_->CheckStackOverflowInPrologue(field_helper.position_); | 
|  | if (field_helper.IsConst()) { | 
|  | // this will (potentially) read the initializer, but reset the position. | 
|  | body += Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); | 
|  | SkipExpression();  // read the initializer. | 
|  | } else { | 
|  | body += BuildExpression();  // read initializer. | 
|  | } | 
|  | body += Return(TokenPosition::kNoSource); | 
|  |  | 
|  | PrologueInfo prologue_info(-1, -1); | 
|  | return new (Z) | 
|  | FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, | 
|  | flow_graph_builder_->last_used_block_id_, prologue_info); | 
|  | } | 
|  |  | 
|  | FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldAccessor( | 
|  | LocalVariable* setter_value) { | 
|  | FieldHelper field_helper(this); | 
|  | field_helper.ReadUntilIncluding(FieldHelper::kCanonicalName); | 
|  |  | 
|  | const Function& function = parsed_function()->function(); | 
|  |  | 
|  | bool is_setter = function.IsImplicitSetterFunction(); | 
|  | bool is_method = !function.IsStaticFunction(); | 
|  | Field& field = Field::ZoneHandle( | 
|  | Z, H.LookupFieldByKernelField(field_helper.canonical_name_)); | 
|  |  | 
|  | TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); | 
|  | flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( | 
|  | *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); | 
|  |  | 
|  | Fragment body(normal_entry); | 
|  | if (is_setter) { | 
|  | if (is_method) { | 
|  | body += LoadLocal(scopes()->this_variable); | 
|  | } | 
|  | body += LoadLocal(setter_value); | 
|  | if (I->argument_type_checks() && setter_value->needs_type_check()) { | 
|  | body += CheckArgumentType(setter_value, setter_value->type()); | 
|  | } | 
|  | if (is_method) { | 
|  | body += flow_graph_builder_->StoreInstanceFieldGuarded(field, false); | 
|  | } else { | 
|  | body += StoreStaticField(TokenPosition::kNoSource, field); | 
|  | } | 
|  | body += NullConstant(); | 
|  | } else if (is_method) { | 
|  | body += LoadLocal(scopes()->this_variable); | 
|  | body += flow_graph_builder_->LoadField(field); | 
|  | } else if (field.is_const()) { | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); | 
|  | Tag initializer_tag = ReadTag();  // read first part of initializer. | 
|  |  | 
|  | // If the parser needs to know the value of an uninitialized constant field | 
|  | // it will set the value to the transition sentinel (used to detect circular | 
|  | // initialization) and then call the implicit getter.  Thus, the getter | 
|  | // cannot contain the InitStaticField instruction that normal static getters | 
|  | // contain because it would detect spurious circular initialization when it | 
|  | // checks for the transition sentinel. | 
|  | ASSERT(initializer_tag == kSomething); | 
|  | body += Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); | 
|  | } else { | 
|  | // The field always has an initializer because static fields without | 
|  | // initializers are initialized eagerly and do not have implicit getters. | 
|  | ASSERT(field.has_initializer()); | 
|  | body += Constant(field); | 
|  | body += flow_graph_builder_->InitStaticField(field); | 
|  | body += Constant(field); | 
|  | body += LoadStaticField(); | 
|  | } | 
|  | body += Return(TokenPosition::kNoSource); | 
|  |  | 
|  | PrologueInfo prologue_info(-1, -1); | 
|  | return new (Z) | 
|  | FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, | 
|  | flow_graph_builder_->last_used_block_id_, prologue_info); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::SetupDefaultParameterValues() { | 
|  | intptr_t optional_parameter_count = | 
|  | parsed_function()->function().NumOptionalParameters(); | 
|  | if (optional_parameter_count > 0) { | 
|  | ZoneGrowableArray<const Instance*>* default_values = | 
|  | new ZoneGrowableArray<const Instance*>(Z, optional_parameter_count); | 
|  |  | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  |  | 
|  | if (parsed_function()->function().HasOptionalNamedParameters()) { | 
|  | // List of positional. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipVariableDeclaration();  // read ith variable declaration. | 
|  | } | 
|  |  | 
|  | // List of named. | 
|  | list_length = ReadListLength();  // read list length. | 
|  | ASSERT(optional_parameter_count == list_length); | 
|  | ASSERT(!parsed_function()->function().HasOptionalPositionalParameters()); | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | Instance* default_value; | 
|  |  | 
|  | // Read ith variable declaration | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer); | 
|  | Tag tag = ReadTag();  // read (first part of) initializer. | 
|  | if (tag == kSomething) { | 
|  | // this will (potentially) read the initializer, | 
|  | // but reset the position. | 
|  | default_value = | 
|  | &constant_evaluator_.EvaluateExpression(ReaderOffset()); | 
|  | SkipExpression();  // read (actual) initializer. | 
|  | } else { | 
|  | default_value = &Instance::ZoneHandle(Z, Instance::null()); | 
|  | } | 
|  | default_values->Add(default_value); | 
|  | } | 
|  | } else { | 
|  | // List of positional. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | ASSERT(list_length == function_node_helper.required_parameter_count_ + | 
|  | optional_parameter_count); | 
|  | ASSERT(parsed_function()->function().HasOptionalPositionalParameters()); | 
|  | for (intptr_t i = 0; i < function_node_helper.required_parameter_count_; | 
|  | ++i) { | 
|  | SkipVariableDeclaration();  // read ith variable declaration. | 
|  | } | 
|  | for (intptr_t i = 0; i < optional_parameter_count; ++i) { | 
|  | Instance* default_value; | 
|  |  | 
|  | // Read ith variable declaration | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer); | 
|  | Tag tag = ReadTag();  // read (first part of) initializer. | 
|  | if (tag == kSomething) { | 
|  | // this will (potentially) read the initializer, | 
|  | // but reset the position. | 
|  | default_value = | 
|  | &constant_evaluator_.EvaluateExpression(ReaderOffset()); | 
|  | SkipExpression();  // read (actual) initializer. | 
|  | } else { | 
|  | default_value = &Instance::ZoneHandle(Z, Instance::null()); | 
|  | } | 
|  | default_values->Add(default_value); | 
|  | } | 
|  |  | 
|  | // List of named. | 
|  | list_length = ReadListLength();  // read list length. | 
|  | ASSERT(list_length == 0); | 
|  | } | 
|  | parsed_function()->set_default_parameter_values(default_values); | 
|  | } | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildFieldInitializer( | 
|  | NameIndex canonical_name) { | 
|  | ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull()); | 
|  | Field& field = | 
|  | Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name)); | 
|  | if (PeekTag() == kNullLiteral) { | 
|  | SkipExpression();  // read past the null literal. | 
|  | field.RecordStore(Object::null_object()); | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment instructions; | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += BuildExpression(); | 
|  | instructions += flow_graph_builder_->StoreInstanceFieldGuarded(field, true); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildInitializers( | 
|  | const Class& parent_class) { | 
|  | ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull()); | 
|  | Fragment instructions; | 
|  |  | 
|  | // Start by getting the position of the constructors initializer. | 
|  | intptr_t initializers_offset = -1; | 
|  | { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SkipFunctionNode();  // read constructors function node. | 
|  | initializers_offset = ReaderOffset(); | 
|  | } | 
|  |  | 
|  | // These come from: | 
|  | //   class A { | 
|  | //     var x = (expr); | 
|  | //   } | 
|  | // We don't want to do that when this is a Redirecting Constructors though | 
|  | // (i.e. has a single initializer being of type kRedirectingInitializer). | 
|  | bool is_redirecting_constructor = false; | 
|  | { | 
|  | AlternativeReadingScope alt(&reader_, initializers_offset); | 
|  | intptr_t list_length = ReadListLength();  // read initializers list length. | 
|  | bool no_field_initializers = true; | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | if (PeekTag() == kRedirectingInitializer) { | 
|  | is_redirecting_constructor = true; | 
|  | } else if (PeekTag() == kFieldInitializer) { | 
|  | no_field_initializers = false; | 
|  | } | 
|  | SkipInitializer(); | 
|  | } | 
|  | ASSERT(is_redirecting_constructor ? no_field_initializers : true); | 
|  | } | 
|  |  | 
|  | if (!is_redirecting_constructor) { | 
|  | Array& class_fields = Array::Handle(Z, parent_class.fields()); | 
|  | Field& class_field = Field::Handle(Z); | 
|  | for (intptr_t i = 0; i < class_fields.Length(); ++i) { | 
|  | class_field ^= class_fields.At(i); | 
|  | if (!class_field.is_static()) { | 
|  | TypedData& kernel_data = TypedData::Handle(Z, class_field.KernelData()); | 
|  | ASSERT(!kernel_data.IsNull()); | 
|  | intptr_t field_offset = class_field.kernel_offset(); | 
|  | AlternativeReadingScope alt(&reader_, &kernel_data, field_offset); | 
|  | FieldHelper field_helper(this); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); | 
|  | Tag initializer_tag = ReadTag();  // read first part of initializer. | 
|  | if (initializer_tag == kSomething) { | 
|  | EnterScope(field_offset); | 
|  | instructions += BuildFieldInitializer( | 
|  | field_helper.canonical_name_);  // read initializer. | 
|  | ExitScope(field_offset); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // These to come from: | 
|  | //   class A { | 
|  | //     var x; | 
|  | //     var y; | 
|  | //     A(this.x) : super(expr), y = (expr); | 
|  | //   } | 
|  | { | 
|  | AlternativeReadingScope alt(&reader_, initializers_offset); | 
|  | intptr_t list_length = ReadListLength();  // read initializers list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | Tag tag = ReadTag(); | 
|  | ReadByte();  // read isSynthetic flag. | 
|  | switch (tag) { | 
|  | case kInvalidInitializer: | 
|  | UNIMPLEMENTED(); | 
|  | return Fragment(); | 
|  | case kFieldInitializer: { | 
|  | NameIndex canonical_name = | 
|  | ReadCanonicalNameReference();  // read field_reference. | 
|  | instructions += BuildFieldInitializer(canonical_name);  // read value. | 
|  | break; | 
|  | } | 
|  | case kAssertInitializer: { | 
|  | instructions += BuildStatement(); | 
|  | break; | 
|  | } | 
|  | case kSuperInitializer: { | 
|  | NameIndex canonical_target = | 
|  | ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | intptr_t argument_count; | 
|  | instructions += BuildArguments( | 
|  | &argument_names, &argument_count, | 
|  | /* positional_parameter_count = */ NULL);  // read arguments. | 
|  | argument_count += 1; | 
|  |  | 
|  | Class& parent_klass = GetSuperOrDie(); | 
|  |  | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, H.LookupConstructorByKernelConstructor( | 
|  | parent_klass, H.CanonicalNameString(canonical_target))); | 
|  | instructions += | 
|  | StaticCall(TokenPosition::kNoSource, target, argument_count, | 
|  | argument_names, ICData::kStatic); | 
|  | instructions += Drop(); | 
|  | break; | 
|  | } | 
|  | case kRedirectingInitializer: { | 
|  | NameIndex canonical_target = | 
|  | ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | intptr_t argument_count; | 
|  | instructions += BuildArguments( | 
|  | &argument_names, &argument_count, | 
|  | /* positional_parameter_count = */ NULL);  // read arguments. | 
|  | argument_count += 1; | 
|  |  | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, H.LookupConstructorByKernelConstructor(canonical_target)); | 
|  | instructions += | 
|  | StaticCall(TokenPosition::kNoSource, target, argument_count, | 
|  | argument_names, ICData::kStatic); | 
|  | instructions += Drop(); | 
|  | break; | 
|  | } | 
|  | case kLocalInitializer: { | 
|  | // The other initializers following this one might read the variable. | 
|  | // This is used e.g. for evaluating the arguments to a super call | 
|  | // first, run normal field initializers next and then make the actual | 
|  | // super call: | 
|  | // | 
|  | //   The frontend converts | 
|  | // | 
|  | //      class A { | 
|  | //        var x; | 
|  | //        A(a, b) : super(a + b), x = 2*b {} | 
|  | //      } | 
|  | // | 
|  | //   to | 
|  | // | 
|  | //      class A { | 
|  | //        var x; | 
|  | //        A(a, b) : tmp = a + b, x = 2*b, super(tmp) {} | 
|  | //      } | 
|  | // | 
|  | // (This is strictly speaking not what one should do in terms of the | 
|  | //  specification but that is how it is currently implemented.) | 
|  | LocalVariable* variable = | 
|  | LookupVariable(ReaderOffset() + data_program_offset_); | 
|  |  | 
|  | // Variable declaration | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer); | 
|  | ASSERT(!helper.IsConst()); | 
|  | Tag tag = ReadTag();  // read (first part of) initializer. | 
|  | if (tag != kSomething) { | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | instructions += BuildExpression();  // read initializer. | 
|  | instructions += StoreLocal(TokenPosition::kNoSource, variable); | 
|  | instructions += Drop(); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | ReportUnexpectedTag("initializer", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  | } | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfImplicitClosureFunction( | 
|  | const Function& function) { | 
|  | const Function& parent = Function::ZoneHandle(Z, function.parent_function()); | 
|  | const String& func_name = String::ZoneHandle(Z, parent.name()); | 
|  | const Class& owner = Class::ZoneHandle(Z, parent.Owner()); | 
|  | Function& target = Function::ZoneHandle(Z, owner.LookupFunction(func_name)); | 
|  |  | 
|  | if (!target.IsNull() && (target.raw() != parent.raw())) { | 
|  | DEBUG_ASSERT(Isolate::Current()->HasAttemptedReload()); | 
|  | if ((target.is_static() != parent.is_static()) || | 
|  | (target.kind() != parent.kind())) { | 
|  | target = Function::null(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (target.IsNull() || | 
|  | (parent.num_fixed_parameters() != target.num_fixed_parameters())) { | 
|  | return BuildGraphOfNoSuchMethodForwarder(function, true, | 
|  | parent.is_static()); | 
|  | } | 
|  |  | 
|  | // The prologue builder needs the default parameter values. | 
|  | SetupDefaultParameterValues(); | 
|  |  | 
|  | TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); | 
|  | PrologueInfo prologue_info(-1, -1); | 
|  | BlockEntryInstr* instruction_cursor = | 
|  | flow_graph_builder_->BuildPrologue(normal_entry, &prologue_info); | 
|  |  | 
|  | flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( | 
|  | *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); | 
|  |  | 
|  | Fragment body(instruction_cursor); | 
|  | body += | 
|  | flow_graph_builder_->CheckStackOverflowInPrologue(function.token_pos()); | 
|  |  | 
|  | intptr_t type_args_len = 0; | 
|  | if (I->reify_generic_functions() && function.IsGeneric()) { | 
|  | type_args_len = function.NumTypeParameters(); | 
|  | ASSERT(parsed_function()->function_type_arguments() != NULL); | 
|  | body += LoadLocal(parsed_function()->function_type_arguments()); | 
|  | body += PushArgument(); | 
|  | } | 
|  |  | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  |  | 
|  | if (I->argument_type_checks()) { | 
|  | if (!target.NeedsArgumentTypeChecks(I)) { | 
|  | // Tearoffs of static methods needs to perform arguments checks since | 
|  | // static methods they forward to don't do it themselves. | 
|  | AlternativeReadingScope _(&reader_); | 
|  | body += BuildArgumentTypeChecks(); | 
|  | } else { | 
|  | // Check if parent function was annotated with no-dynamic-invocations. | 
|  | const ProcedureAttributesMetadata attrs = | 
|  | procedure_attributes_metadata_helper_.GetProcedureAttributes( | 
|  | parent.kernel_offset()); | 
|  | if (!attrs.has_dynamic_invocations) { | 
|  | // If it was then we might need to build some checks in the | 
|  | // tear-off. | 
|  | AlternativeReadingScope _(&reader_); | 
|  | body += | 
|  | BuildArgumentTypeChecks(kTypeChecksForNoDynamicInvocationsTearOff); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  |  | 
|  | // Load all the arguments. | 
|  | if (!target.is_static()) { | 
|  | // The context has a fixed shape: a single variable which is the | 
|  | // closed-over receiver. | 
|  | body += LoadLocal(parsed_function()->current_context_var()); | 
|  | body += flow_graph_builder_->LoadField(Context::variable_offset(0)); | 
|  | body += PushArgument(); | 
|  | } | 
|  |  | 
|  | // Positional. | 
|  | intptr_t positional_argument_count = ReadListLength(); | 
|  | for (intptr_t i = 0; i < positional_argument_count; ++i) { | 
|  | body += LoadLocal(LookupVariable( | 
|  | ReaderOffset() + data_program_offset_));  // ith variable offset. | 
|  | body += PushArgument(); | 
|  | SkipVariableDeclaration();  // read ith variable. | 
|  | } | 
|  |  | 
|  | // Named. | 
|  | intptr_t named_argument_count = ReadListLength(); | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | if (named_argument_count > 0) { | 
|  | argument_names = Array::New(named_argument_count, H.allocation_space()); | 
|  | for (intptr_t i = 0; i < named_argument_count; ++i) { | 
|  | // ith variable offset. | 
|  | body += LoadLocal(LookupVariable(ReaderOffset() + data_program_offset_)); | 
|  | body += PushArgument(); | 
|  |  | 
|  | // read ith variable. | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd); | 
|  |  | 
|  | argument_names.SetAt(i, H.DartSymbolObfuscate(helper.name_index_)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Forward them to the parent. | 
|  | intptr_t argument_count = positional_argument_count + named_argument_count; | 
|  | if (!parent.is_static()) { | 
|  | ++argument_count; | 
|  | } | 
|  | body += StaticCall(TokenPosition::kNoSource, target, argument_count, | 
|  | argument_names, ICData::kNoRebind, | 
|  | /* result_type = */ NULL, type_args_len); | 
|  |  | 
|  | // Return the result. | 
|  | body += Return(function_node_helper.end_position_); | 
|  |  | 
|  | return new (Z) | 
|  | FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, | 
|  | flow_graph_builder_->last_used_block_id_, prologue_info); | 
|  | } | 
|  |  | 
|  | // If throw_no_such_method_error is set to true (defaults to false), an | 
|  | // instance of NoSuchMethodError is thrown. Otherwise, the instance | 
|  | // noSuchMethod is called. | 
|  | FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder( | 
|  | const Function& function, | 
|  | bool is_implicit_closure_function, | 
|  | bool throw_no_such_method_error) { | 
|  | // The prologue builder needs the default parameter values. | 
|  | SetupDefaultParameterValues(); | 
|  |  | 
|  | TargetEntryInstr* normal_entry = B->BuildTargetEntry(); | 
|  | PrologueInfo prologue_info(-1, -1); | 
|  | BlockEntryInstr* instruction_cursor = | 
|  | B->BuildPrologue(normal_entry, &prologue_info); | 
|  |  | 
|  | B->graph_entry_ = new (Z) GraphEntryInstr(*parsed_function(), normal_entry, | 
|  | Compiler::kNoOSRDeoptId); | 
|  |  | 
|  | Fragment body(instruction_cursor); | 
|  | body += B->CheckStackOverflowInPrologue(function.token_pos()); | 
|  |  | 
|  | // If we are inside the tearoff wrapper function (implicit closure), we need | 
|  | // to extract the receiver from the context. We just replace it directly on | 
|  | // the stack to simplify the rest of the code. | 
|  | if (is_implicit_closure_function) { | 
|  | if (parsed_function()->has_arg_desc_var()) { | 
|  | body += B->LoadArgDescriptor(); | 
|  | body += LoadField(ArgumentsDescriptor::count_offset()); | 
|  | body += LoadLocal(parsed_function()->current_context_var()); | 
|  | body += B->LoadField(Context::variable_offset(0)); | 
|  | body += B->StoreFpRelativeSlot(kWordSize * kParamEndSlotFromFp); | 
|  | body += Drop(); | 
|  | } else { | 
|  | body += LoadLocal(parsed_function()->current_context_var()); | 
|  | body += B->LoadField(Context::variable_offset(0)); | 
|  | body += B->StoreFpRelativeSlot( | 
|  | kWordSize * (kParamEndSlotFromFp + function.NumParameters())); | 
|  | body += Drop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  |  | 
|  | if (function.NeedsArgumentTypeChecks(I)) { | 
|  | AlternativeReadingScope _(&reader_); | 
|  | body += BuildArgumentTypeChecks(); | 
|  | } | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  |  | 
|  | body += NullConstant(); | 
|  | LocalVariable* result = MakeTemporary(); | 
|  |  | 
|  | // Do "++argument_count" if any type arguments were passed. | 
|  | LocalVariable* argument_count_var = parsed_function()->expression_temp_var(); | 
|  | body += IntConstant(0); | 
|  | body += StoreLocal(TokenPosition::kNoSource, argument_count_var); | 
|  | body += Drop(); | 
|  | if (function.IsGeneric() && Isolate::Current()->reify_generic_functions()) { | 
|  | Fragment test_generic; | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  |  | 
|  | TargetEntryInstr *passed_type_args, *not_passed_type_args; | 
|  | test_generic += B->LoadArgDescriptor(); | 
|  | test_generic += LoadField(ArgumentsDescriptor::type_args_len_offset()); | 
|  | test_generic += IntConstant(0); | 
|  | test_generic += BranchIfEqual(¬_passed_type_args, &passed_type_args, | 
|  | /*negate=*/false); | 
|  |  | 
|  | Fragment passed_type_args_frag(passed_type_args); | 
|  | passed_type_args_frag += IntConstant(1); | 
|  | passed_type_args_frag += | 
|  | StoreLocal(TokenPosition::kNoSource, argument_count_var); | 
|  | passed_type_args_frag += Drop(); | 
|  | passed_type_args_frag += Goto(join); | 
|  |  | 
|  | Fragment not_passed_type_args_frag(not_passed_type_args); | 
|  | not_passed_type_args_frag += Goto(join); | 
|  |  | 
|  | body += Fragment(test_generic.entry, join); | 
|  | } | 
|  |  | 
|  | if (function.HasOptionalParameters()) { | 
|  | body += B->LoadArgDescriptor(); | 
|  | body += LoadField(ArgumentsDescriptor::count_offset()); | 
|  | } else { | 
|  | body += IntConstant(function.NumParameters()); | 
|  | } | 
|  | body += LoadLocal(argument_count_var); | 
|  | body += B->SmiBinaryOp(Token::kADD, /* truncate= */ true); | 
|  | LocalVariable* argument_count = MakeTemporary(); | 
|  |  | 
|  | // We are generating code like the following: | 
|  | // | 
|  | // var arguments = new Array<dynamic>(argument_count); | 
|  | // | 
|  | // for (int i = 0; i < argument_count; ++i) { | 
|  | //   arguments[i] = LoadFpRelativeSlot( | 
|  | //       kWordSize * (kParamEndSlotFromFp + argument_count - i)); | 
|  | // } | 
|  | body += Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null())); | 
|  | body += LoadLocal(argument_count); | 
|  | body += CreateArray(); | 
|  | LocalVariable* arguments = MakeTemporary(); | 
|  |  | 
|  | { | 
|  | // int i = 0 | 
|  | LocalVariable* index = parsed_function()->expression_temp_var(); | 
|  | body += IntConstant(0); | 
|  | body += StoreLocal(TokenPosition::kNoSource, index); | 
|  | body += Drop(); | 
|  |  | 
|  | TargetEntryInstr* body_entry; | 
|  | TargetEntryInstr* loop_exit; | 
|  |  | 
|  | Fragment condition; | 
|  | // i < argument_count | 
|  | condition += LoadLocal(index); | 
|  | condition += LoadLocal(argument_count); | 
|  | condition += B->SmiRelationalOp(Token::kLT); | 
|  | condition += BranchIfTrue(&body_entry, &loop_exit, /*negate=*/false); | 
|  |  | 
|  | Fragment loop_body(body_entry); | 
|  |  | 
|  | // arguments[i] = LoadFpRelativeSlot( | 
|  | //     kWordSize * (kParamEndSlotFromFp + argument_count - i)); | 
|  | loop_body += LoadLocal(arguments); | 
|  | loop_body += LoadLocal(index); | 
|  | loop_body += LoadLocal(argument_count); | 
|  | loop_body += LoadLocal(index); | 
|  | loop_body += B->SmiBinaryOp(Token::kSUB, /*truncate=*/true); | 
|  | loop_body += B->LoadFpRelativeSlot(kWordSize * kParamEndSlotFromFp); | 
|  | loop_body += StoreIndexed(kArrayCid); | 
|  | loop_body += Drop(); | 
|  |  | 
|  | // ++i | 
|  | loop_body += LoadLocal(index); | 
|  | loop_body += IntConstant(1); | 
|  | loop_body += B->SmiBinaryOp(Token::kADD, /*truncate=*/true); | 
|  | loop_body += StoreLocal(TokenPosition::kNoSource, index); | 
|  | loop_body += Drop(); | 
|  |  | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | loop_body += Goto(join); | 
|  |  | 
|  | Fragment loop(join); | 
|  | loop += condition; | 
|  |  | 
|  | Instruction* entry = | 
|  | new (Z) GotoInstr(join, Thread::Current()->GetNextDeoptId()); | 
|  | body += Fragment(entry, loop_exit); | 
|  | } | 
|  |  | 
|  | // Load receiver. | 
|  | if (is_implicit_closure_function) { | 
|  | if (throw_no_such_method_error) { | 
|  | const Function& parent = | 
|  | Function::ZoneHandle(Z, function.parent_function()); | 
|  | const Class& owner = Class::ZoneHandle(Z, parent.Owner()); | 
|  | AbstractType& type = AbstractType::ZoneHandle(Z); | 
|  | type ^= Type::New(owner, TypeArguments::Handle(Z), owner.token_pos(), | 
|  | Heap::kOld); | 
|  | // If the current class is the result of a mixin application, we must | 
|  | // use the class scope of the class from which the function originates. | 
|  | if (owner.IsMixinApplication()) { | 
|  | ClassFinalizer::FinalizeType( | 
|  | Class::Handle(Z, parsed_function()->function().origin()), type); | 
|  | } else { | 
|  | type ^= ClassFinalizer::FinalizeType(owner, type); | 
|  | } | 
|  | body += Constant(type); | 
|  | } else { | 
|  | body += LoadLocal(parsed_function()->current_context_var()); | 
|  | body += B->LoadField(Context::variable_offset(0)); | 
|  | } | 
|  | } else { | 
|  | LocalScope* scope = parsed_function()->node_sequence()->scope(); | 
|  | body += LoadLocal(scope->VariableAt(0)); | 
|  | } | 
|  | body += PushArgument(); | 
|  |  | 
|  | body += Constant(String::ZoneHandle(Z, function.name())); | 
|  | body += PushArgument(); | 
|  |  | 
|  | if (!parsed_function()->has_arg_desc_var()) { | 
|  | // If there is no variable for the arguments descriptor (this function's | 
|  | // signature doesn't require it), then we need to create one. | 
|  | Array& args_desc = Array::ZoneHandle( | 
|  | Z, ArgumentsDescriptor::New(0, function.NumParameters())); | 
|  | body += Constant(args_desc); | 
|  | } else { | 
|  | body += B->LoadArgDescriptor(); | 
|  | } | 
|  | body += PushArgument(); | 
|  |  | 
|  | body += LoadLocal(arguments); | 
|  | body += PushArgument(); | 
|  |  | 
|  | // false -> this is not super NSM | 
|  | body += Constant(Bool::False()); | 
|  | body += PushArgument(); | 
|  |  | 
|  | if (throw_no_such_method_error) { | 
|  | const Function& parent = | 
|  | Function::ZoneHandle(Z, function.parent_function()); | 
|  | const Class& owner = Class::ZoneHandle(Z, parent.Owner()); | 
|  | InvocationMirror::Level im_level = owner.IsTopLevel() | 
|  | ? InvocationMirror::kTopLevel | 
|  | : InvocationMirror::kStatic; | 
|  | InvocationMirror::Kind im_kind; | 
|  | if (function.IsImplicitGetterFunction() || function.IsGetterFunction()) { | 
|  | im_kind = InvocationMirror::kGetter; | 
|  | } else if (function.IsImplicitSetterFunction() || | 
|  | function.IsSetterFunction()) { | 
|  | im_kind = InvocationMirror::kSetter; | 
|  | } else { | 
|  | im_kind = InvocationMirror::kMethod; | 
|  | } | 
|  | body += IntConstant(InvocationMirror::EncodeType(im_level, im_kind)); | 
|  | } else { | 
|  | body += NullConstant(); | 
|  | } | 
|  | body += PushArgument(); | 
|  |  | 
|  | const Class& mirror_class = | 
|  | Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror())); | 
|  | ASSERT(!mirror_class.IsNull()); | 
|  | const Function& allocation_function = Function::ZoneHandle( | 
|  | Z, mirror_class.LookupStaticFunction( | 
|  | Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror()))); | 
|  | ASSERT(!allocation_function.IsNull()); | 
|  | body += StaticCall(TokenPosition::kMinSource, allocation_function, | 
|  | /* argument_count = */ 5, ICData::kStatic); | 
|  | body += PushArgument();  // For the call to noSuchMethod. | 
|  |  | 
|  | if (throw_no_such_method_error) { | 
|  | const Class& klass = Class::ZoneHandle( | 
|  | Z, Library::LookupCoreClass(Symbols::NoSuchMethodError())); | 
|  | ASSERT(!klass.IsNull()); | 
|  | const Function& throw_function = Function::ZoneHandle( | 
|  | Z, | 
|  | klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNewInvocation())); | 
|  | ASSERT(!throw_function.IsNull()); | 
|  | body += StaticCall(TokenPosition::kNoSource, throw_function, 2, | 
|  | ICData::kStatic); | 
|  | } else { | 
|  | body += InstanceCall(TokenPosition::kNoSource, Symbols::NoSuchMethod(), | 
|  | Token::kILLEGAL, 2, 1); | 
|  | } | 
|  | body += StoreLocal(TokenPosition::kNoSource, result); | 
|  | body += Drop(); | 
|  |  | 
|  | body += Drop();  // arguments | 
|  | body += Drop();  // argument count | 
|  |  | 
|  | AbstractType& return_type = AbstractType::Handle(function.result_type()); | 
|  | if (!return_type.IsDynamicType() && !return_type.IsVoidType() && | 
|  | !return_type.IsObjectType()) { | 
|  | body += flow_graph_builder_->AssertAssignable( | 
|  | TokenPosition::kNoSource, return_type, Symbols::Empty()); | 
|  | } | 
|  | body += Return(TokenPosition::kNoSource); | 
|  |  | 
|  | return new (Z) FlowGraph(*parsed_function(), B->graph_entry_, | 
|  | B->last_used_block_id_, prologue_info); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildArgumentTypeChecks( | 
|  | TypeChecksToBuild mode /*= kDefaultTypeChecks*/) { | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.SetNext(FunctionNodeHelper::kTypeParameters); | 
|  | const Function& dart_function = parsed_function()->function(); | 
|  |  | 
|  | Fragment body; | 
|  |  | 
|  | const Function* forwarding_target = NULL; | 
|  | if (parsed_function()->is_forwarding_stub()) { | 
|  | NameIndex target_name = parsed_function()->forwarding_stub_super_target(); | 
|  | const String& name = dart_function.IsSetterFunction() | 
|  | ? H.DartSetterName(target_name) | 
|  | : H.DartProcedureName(target_name); | 
|  | forwarding_target = | 
|  | &Function::ZoneHandle(Z, LookupMethodByMember(target_name, name)); | 
|  | ASSERT(!forwarding_target->IsNull()); | 
|  | } | 
|  |  | 
|  | // Type parameters | 
|  | if (mode == kDefaultTypeChecks) { | 
|  | intptr_t num_type_params = ReadListLength(); | 
|  | TypeArguments& forwarding_params = TypeArguments::Handle(Z); | 
|  | if (forwarding_target != NULL) { | 
|  | forwarding_params = forwarding_target->type_parameters(); | 
|  | ASSERT(forwarding_params.Length() == num_type_params); | 
|  | } | 
|  | TypeParameter& forwarding_param = TypeParameter::Handle(Z); | 
|  | for (intptr_t i = 0; i < num_type_params; ++i) { | 
|  | TypeParameterHelper helper(this); | 
|  | helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound); | 
|  | String& name = H.DartSymbolObfuscate(helper.name_index_); | 
|  | AbstractType& bound = T.BuildType();                 // read bound | 
|  | helper.Finish(); | 
|  |  | 
|  | if (forwarding_target != NULL) { | 
|  | forwarding_param ^= forwarding_params.TypeAt(i); | 
|  | bound = forwarding_param.bound(); | 
|  | } | 
|  |  | 
|  | if (I->strong() && !bound.IsObjectType() && | 
|  | (I->reify_generic_functions() || dart_function.IsFactory())) { | 
|  | ASSERT(!bound.IsDynamicType()); | 
|  | TypeParameter& param = TypeParameter::Handle(Z); | 
|  | if (dart_function.IsFactory()) { | 
|  | param ^= TypeArguments::Handle( | 
|  | Class::Handle(dart_function.Owner()).type_parameters()) | 
|  | .TypeAt(i); | 
|  | } else { | 
|  | param ^= | 
|  | TypeArguments::Handle(dart_function.type_parameters()).TypeAt(i); | 
|  | } | 
|  | ASSERT(param.IsFinalized()); | 
|  | body += CheckTypeArgumentBound(param, bound, name); | 
|  | } | 
|  | } | 
|  | function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters); | 
|  | } | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  |  | 
|  | // Positional. | 
|  | const intptr_t num_positional_params = ReadListLength(); | 
|  | const intptr_t kFirstParameterOffset = 1; | 
|  | for (intptr_t i = 0; i < num_positional_params; ++i) { | 
|  | // ith variable offset. | 
|  | const intptr_t offset = ReaderOffset(); | 
|  | SkipVariableDeclaration(); | 
|  |  | 
|  | LocalVariable* param = LookupVariable(offset + data_program_offset_); | 
|  | if (!param->needs_type_check()) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const AbstractType* target_type = ¶m->type(); | 
|  | if (forwarding_target != NULL) { | 
|  | // We add 1 to the parameter index to account for the receiver. | 
|  | target_type = &AbstractType::ZoneHandle( | 
|  | Z, forwarding_target->ParameterTypeAt(kFirstParameterOffset + i)); | 
|  | } | 
|  | body += LoadLocal(param); | 
|  | body += CheckArgumentType(param, *target_type); | 
|  | body += Drop(); | 
|  | } | 
|  |  | 
|  | // Named. | 
|  | const intptr_t num_named_params = ReadListLength(); | 
|  | for (intptr_t i = 0; i < num_named_params; ++i) { | 
|  | // ith variable offset. | 
|  | const intptr_t offset = ReaderOffset(); | 
|  | SkipVariableDeclaration(); | 
|  |  | 
|  | LocalVariable* param = LookupVariable(offset + data_program_offset_); | 
|  | if (!param->needs_type_check()) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const AbstractType* target_type = ¶m->type(); | 
|  | if (forwarding_target != NULL) { | 
|  | // We add 1 to the parameter index to account for the receiver. | 
|  | target_type = &AbstractType::ZoneHandle( | 
|  | Z, forwarding_target->ParameterTypeAt(num_positional_params + i + 1)); | 
|  | } | 
|  | body += LoadLocal(param); | 
|  | body += CheckArgumentType(param, *target_type); | 
|  | body += Drop(); | 
|  | } | 
|  |  | 
|  | return body; | 
|  | } | 
|  |  | 
|  | FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(bool constructor) { | 
|  | // The prologue builder needs the default parameter values. | 
|  | SetupDefaultParameterValues(); | 
|  |  | 
|  | const Function& dart_function = parsed_function()->function(); | 
|  | TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); | 
|  | PrologueInfo prologue_info(-1, -1); | 
|  | BlockEntryInstr* instruction_cursor = | 
|  | flow_graph_builder_->BuildPrologue(normal_entry, &prologue_info); | 
|  |  | 
|  | flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( | 
|  | *parsed_function(), normal_entry, flow_graph_builder_->osr_id_); | 
|  |  | 
|  | Fragment body; | 
|  |  | 
|  | LocalVariable* closure = NULL; | 
|  | if (dart_function.IsClosureFunction()) { | 
|  | closure = parsed_function()->node_sequence()->scope()->VariableAt(0); | 
|  | } else if (dart_function.IsConvertedClosureFunction()) { | 
|  | closure = new (Z) LocalVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, | 
|  | Symbols::TempParam(), AbstractType::ZoneHandle(Z, Type::DynamicType())); | 
|  | closure->set_index(parsed_function()->first_parameter_index()); | 
|  | closure->set_is_captured_parameter(true); | 
|  | } | 
|  |  | 
|  | if ((dart_function.IsClosureFunction() || | 
|  | dart_function.IsConvertedClosureFunction()) && | 
|  | dart_function.NumParentTypeParameters() > 0 && | 
|  | I->reify_generic_functions()) { | 
|  | LocalVariable* fn_type_args = parsed_function()->function_type_arguments(); | 
|  | ASSERT(fn_type_args != NULL && closure != NULL); | 
|  |  | 
|  | if (dart_function.IsGeneric()) { | 
|  | body += LoadLocal(fn_type_args); | 
|  | body += PushArgument(); | 
|  | body += LoadLocal(closure); | 
|  | body += LoadField(Closure::function_type_arguments_offset()); | 
|  | body += PushArgument(); | 
|  | body += IntConstant(dart_function.NumTypeParameters() + | 
|  | dart_function.NumParentTypeParameters()); | 
|  | body += PushArgument(); | 
|  |  | 
|  | const Library& dart_internal = | 
|  | Library::Handle(Z, Library::InternalLibrary()); | 
|  | const Function& prepend_function = | 
|  | Function::ZoneHandle(Z, dart_internal.LookupFunctionAllowPrivate( | 
|  | Symbols::PrependTypeArguments())); | 
|  | ASSERT(!prepend_function.IsNull()); | 
|  |  | 
|  | body += StaticCall(TokenPosition::kNoSource, prepend_function, 3, | 
|  | ICData::kStatic); | 
|  | body += StoreLocal(TokenPosition::kNoSource, fn_type_args); | 
|  | body += Drop(); | 
|  | } else { | 
|  | body += LoadLocal(closure); | 
|  | body += LoadField(Closure::function_type_arguments_offset()); | 
|  | body += StoreLocal(TokenPosition::kNoSource, fn_type_args); | 
|  | body += Drop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (dart_function.IsConvertedClosureFunction()) { | 
|  | body += LoadLocal(closure); | 
|  | body += LoadField(Closure::context_offset()); | 
|  | LocalVariable* context = closure; | 
|  | body += StoreLocal(TokenPosition::kNoSource, context); | 
|  | body += Drop(); | 
|  | } | 
|  |  | 
|  | if (!dart_function.is_native()) | 
|  | body += flow_graph_builder_->CheckStackOverflowInPrologue( | 
|  | dart_function.token_pos()); | 
|  | intptr_t context_size = | 
|  | parsed_function()->node_sequence()->scope()->num_context_variables(); | 
|  | if (context_size > 0) { | 
|  | body += flow_graph_builder_->PushContext(context_size); | 
|  | LocalVariable* context = MakeTemporary(); | 
|  |  | 
|  | // Copy captured parameters from the stack into the context. | 
|  | LocalScope* scope = parsed_function()->node_sequence()->scope(); | 
|  | intptr_t parameter_count = dart_function.NumParameters(); | 
|  | intptr_t parameter_index = parsed_function()->first_parameter_index(); | 
|  |  | 
|  | const ParsedFunction& pf = *flow_graph_builder_->parsed_function_; | 
|  | const Function& function = pf.function(); | 
|  |  | 
|  | for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) { | 
|  | LocalVariable* variable = scope->VariableAt(i); | 
|  | if (variable->is_captured()) { | 
|  | LocalVariable& raw_parameter = *pf.RawParameterVariable(i); | 
|  | ASSERT((function.HasOptionalParameters() && | 
|  | raw_parameter.owner() == scope) || | 
|  | (!function.HasOptionalParameters() && | 
|  | raw_parameter.owner() == NULL)); | 
|  | ASSERT(!raw_parameter.is_captured()); | 
|  |  | 
|  | // Copy the parameter from the stack to the context.  Overwrite it | 
|  | // with a null constant on the stack so the original value is | 
|  | // eligible for garbage collection. | 
|  | body += LoadLocal(context); | 
|  | body += LoadLocal(&raw_parameter); | 
|  | body += flow_graph_builder_->StoreInstanceField( | 
|  | TokenPosition::kNoSource, | 
|  | Context::variable_offset(variable->index())); | 
|  | body += NullConstant(); | 
|  | body += StoreLocal(TokenPosition::kNoSource, &raw_parameter); | 
|  | body += Drop(); | 
|  | } | 
|  | } | 
|  | body += Drop();  // The context. | 
|  | } | 
|  | if (constructor) { | 
|  | // TODO(27590): Currently the [VariableDeclaration]s from the | 
|  | // initializers will be visible inside the entire body of the constructor. | 
|  | // We should make a separate scope for them. | 
|  | body += BuildInitializers(Class::Handle(Z, dart_function.Owner())); | 
|  | } | 
|  |  | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  | intptr_t type_parameters_offset = ReaderOffset(); | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  | intptr_t first_parameter_offset = -1; | 
|  | { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | intptr_t list_length = ReadListLength();  // read number of positionals. | 
|  | if (list_length > 0) { | 
|  | first_parameter_offset = ReaderOffset() + data_program_offset_; | 
|  | } | 
|  | } | 
|  | // Current position: About to read list of positionals. | 
|  |  | 
|  | // The specification defines the result of `a == b` to be: | 
|  | // | 
|  | //   a) if either side is `null` then the result is `identical(a, b)`. | 
|  | //   b) else the result is `a.operator==(b)` | 
|  | // | 
|  | // For user-defined implementations of `operator==` we need therefore | 
|  | // implement the handling of a). | 
|  | // | 
|  | // The default `operator==` implementation in `Object` is implemented in terms | 
|  | // of identical (which we assume here!) which means that case a) is actually | 
|  | // included in b).  So we just use the normal implementation in the body. | 
|  | if ((dart_function.NumParameters() == 2) && | 
|  | (dart_function.name() == Symbols::EqualOperator().raw()) && | 
|  | (dart_function.Owner() != I->object_store()->object_class())) { | 
|  | LocalVariable* parameter = LookupVariable(first_parameter_offset); | 
|  |  | 
|  | TargetEntryInstr* null_entry; | 
|  | TargetEntryInstr* non_null_entry; | 
|  |  | 
|  | body += LoadLocal(parameter); | 
|  | body += BranchIfNull(&null_entry, &non_null_entry); | 
|  |  | 
|  | // The argument was `null` and the receiver is not the null class (we only | 
|  | // go into this branch for user-defined == operators) so we can return | 
|  | // false. | 
|  | Fragment null_fragment(null_entry); | 
|  | null_fragment += Constant(Bool::False()); | 
|  | null_fragment += Return(dart_function.end_token_pos()); | 
|  |  | 
|  | body = Fragment(body.entry, non_null_entry); | 
|  | } | 
|  |  | 
|  | // If we run in checked mode or strong mode, we have to check the type of the | 
|  | // passed arguments. | 
|  | if (dart_function.NeedsArgumentTypeChecks(I)) { | 
|  | AlternativeReadingScope _(&reader_); | 
|  | SetOffset(type_parameters_offset); | 
|  | body += BuildArgumentTypeChecks(); | 
|  | } | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kBody); | 
|  |  | 
|  | bool has_body = ReadTag() == kSomething;  // read first part of body. | 
|  |  | 
|  | if (dart_function.is_native()) { | 
|  | body += flow_graph_builder_->NativeFunctionBody(first_parameter_offset, | 
|  | dart_function); | 
|  | } else if (has_body) { | 
|  | body += BuildStatement();  // read body. | 
|  | } | 
|  | if (body.is_open()) { | 
|  | body += NullConstant(); | 
|  | body += Return(dart_function.end_token_pos()); | 
|  | } | 
|  |  | 
|  | // If functions body contains any yield points build switch statement that | 
|  | // selects a continuation point based on the value of :await_jump_var. | 
|  | if (!yield_continuations().is_empty()) { | 
|  | // The code we are building will be executed right after we enter | 
|  | // the function and before any nested contexts are allocated. | 
|  | // Reset current context_depth_ to match this. | 
|  | const intptr_t current_context_depth = flow_graph_builder_->context_depth_; | 
|  | flow_graph_builder_->context_depth_ = | 
|  | scopes()->yield_jump_variable->owner()->context_level(); | 
|  |  | 
|  | // Prepend an entry corresponding to normal entry to the function. | 
|  | yield_continuations().InsertAt( | 
|  | 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), | 
|  | CatchClauseNode::kInvalidTryIndex)); | 
|  | yield_continuations()[0].entry->LinkTo(body.entry); | 
|  |  | 
|  | // Build a switch statement. | 
|  | Fragment dispatch; | 
|  |  | 
|  | // Load :await_jump_var into a temporary. | 
|  | dispatch += LoadLocal(scopes()->yield_jump_variable); | 
|  | dispatch += StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable); | 
|  | dispatch += Drop(); | 
|  |  | 
|  | BlockEntryInstr* block = NULL; | 
|  | for (intptr_t i = 0; i < yield_continuations().length(); i++) { | 
|  | if (i == 1) { | 
|  | // This is not a normal entry but a resumption.  Restore | 
|  | // :current_context_var from :await_ctx_var. | 
|  | // Note: after this point context_depth_ does not match current context | 
|  | // depth so we should not access any local variables anymore. | 
|  | dispatch += LoadLocal(scopes()->yield_context_variable); | 
|  | dispatch += StoreLocal(TokenPosition::kNoSource, | 
|  | parsed_function()->current_context_var()); | 
|  | dispatch += Drop(); | 
|  | } | 
|  | if (i == (yield_continuations().length() - 1)) { | 
|  | // We reached the last possility, no need to build more ifs. | 
|  | // Continue to the last continuation. | 
|  | // Note: continuations start with nop DropTemps instruction | 
|  | // which acts like an anchor, so we need to skip it. | 
|  | block->set_try_index(yield_continuations()[i].try_index); | 
|  | dispatch <<= yield_continuations()[i].entry->next(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Build comparison: | 
|  | // | 
|  | //   if (:await_ctx_var == i) { | 
|  | //     -> yield_continuations()[i] | 
|  | //   } else ... | 
|  | // | 
|  | TargetEntryInstr* then; | 
|  | TargetEntryInstr* otherwise; | 
|  | dispatch += LoadLocal(scopes()->switch_variable); | 
|  | dispatch += IntConstant(i); | 
|  | dispatch += flow_graph_builder_->BranchIfStrictEqual(&then, &otherwise); | 
|  |  | 
|  | // True branch is linked to appropriate continuation point. | 
|  | // Note: continuations start with nop DropTemps instruction | 
|  | // which acts like an anchor, so we need to skip it. | 
|  | then->LinkTo(yield_continuations()[i].entry->next()); | 
|  | then->set_try_index(yield_continuations()[i].try_index); | 
|  | // False branch will contain the next comparison. | 
|  | dispatch = Fragment(dispatch.entry, otherwise); | 
|  | block = otherwise; | 
|  | } | 
|  | body = dispatch; | 
|  |  | 
|  | flow_graph_builder_->context_depth_ = current_context_depth; | 
|  | } | 
|  |  | 
|  | if (FLAG_causal_async_stacks && | 
|  | (dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) { | 
|  | // The code we are building will be executed right after we enter | 
|  | // the function and before any nested contexts are allocated. | 
|  | // Reset current context_depth_ to match this. | 
|  | const intptr_t current_context_depth = flow_graph_builder_->context_depth_; | 
|  | flow_graph_builder_->context_depth_ = | 
|  | scopes()->yield_jump_variable->owner()->context_level(); | 
|  |  | 
|  | Fragment instructions; | 
|  | LocalScope* scope = parsed_function()->node_sequence()->scope(); | 
|  |  | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, I->object_store()->async_set_thread_stack_trace()); | 
|  | ASSERT(!target.IsNull()); | 
|  |  | 
|  | // Fetch and load :async_stack_trace | 
|  | LocalVariable* async_stack_trace_var = | 
|  | scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); | 
|  | ASSERT((async_stack_trace_var != NULL) && | 
|  | async_stack_trace_var->is_captured()); | 
|  | instructions += LoadLocal(async_stack_trace_var); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // Call _asyncSetThreadStackTrace | 
|  | instructions += StaticCall(TokenPosition::kNoSource, target, | 
|  | /* argument_count = */ 1, ICData::kStatic); | 
|  | instructions += Drop(); | 
|  |  | 
|  | // TODO(29737): This sequence should be generated in order. | 
|  | body = instructions + body; | 
|  | flow_graph_builder_->context_depth_ = current_context_depth; | 
|  | } | 
|  |  | 
|  | if (NeedsDebugStepCheck(dart_function, function_node_helper.position_)) { | 
|  | const intptr_t current_context_depth = flow_graph_builder_->context_depth_; | 
|  | flow_graph_builder_->context_depth_ = 0; | 
|  | // If a switch was added above: Start the switch by injecting a debuggable | 
|  | // safepoint so stepping over an await works. | 
|  | // If not, still start the body with a debuggable safepoint to ensure | 
|  | // breaking on a method always happens, even if there are no | 
|  | // assignments/calls/runtimecalls in the first basic block. | 
|  | // Place this check at the last parameter to ensure parameters | 
|  | // are in scope in the debugger at method entry. | 
|  | const int parameter_count = dart_function.NumParameters(); | 
|  | TokenPosition check_pos = TokenPosition::kNoSource; | 
|  | if (parameter_count > 0) { | 
|  | LocalScope* scope = parsed_function()->node_sequence()->scope(); | 
|  | const LocalVariable& parameter = *scope->VariableAt(parameter_count - 1); | 
|  | check_pos = parameter.token_pos(); | 
|  | } | 
|  | if (!check_pos.IsDebugPause()) { | 
|  | // No parameters or synthetic parameters. | 
|  | check_pos = function_node_helper.position_; | 
|  | ASSERT(check_pos.IsDebugPause()); | 
|  | } | 
|  |  | 
|  | // TODO(29737): This sequence should be generated in order. | 
|  | body = DebugStepCheck(check_pos) + body; | 
|  | flow_graph_builder_->context_depth_ = current_context_depth; | 
|  | } | 
|  |  | 
|  | instruction_cursor->LinkTo(body.entry); | 
|  |  | 
|  | GraphEntryInstr* graph_entry = flow_graph_builder_->graph_entry_; | 
|  | // When compiling for OSR, use a depth first search to find the OSR | 
|  | // entry and make graph entry jump to it instead of normal entry. | 
|  | // Catch entries are always considered reachable, even if they | 
|  | // become unreachable after OSR. | 
|  | if (flow_graph_builder_->osr_id_ != Compiler::kNoOSRDeoptId) { | 
|  | graph_entry->RelinkToOsrEntry(Z, | 
|  | flow_graph_builder_->last_used_block_id_ + 1); | 
|  | } | 
|  | return new (Z) | 
|  | FlowGraph(*parsed_function(), graph_entry, | 
|  | flow_graph_builder_->last_used_block_id_, prologue_info); | 
|  | } | 
|  |  | 
|  | FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) { | 
|  | ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull()); | 
|  | const Function& function = parsed_function()->function(); | 
|  |  | 
|  | // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used | 
|  | // e.g. for type translation. | 
|  | const Class& klass = | 
|  | Class::Handle(zone_, parsed_function()->function().Owner()); | 
|  | Function& outermost_function = Function::Handle(Z); | 
|  | DiscoverEnclosingElements(Z, function, &outermost_function); | 
|  |  | 
|  | ActiveClassScope active_class_scope(active_class(), &klass); | 
|  | ActiveMemberScope active_member(active_class(), &outermost_function); | 
|  | ActiveTypeParametersScope active_type_params(active_class(), function, Z); | 
|  |  | 
|  | SetOffset(kernel_offset); | 
|  |  | 
|  | // We need to read out the NSM-forwarder bit before we can build scopes. | 
|  | switch (function.kind()) { | 
|  | case RawFunction::kImplicitClosureFunction: | 
|  | case RawFunction::kRegularFunction: { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | ReadUntilFunctionNode(parsed_function());  // read until function node. | 
|  | } | 
|  | default: {} | 
|  | } | 
|  |  | 
|  | // The IR builder will create its own local variables and scopes, and it | 
|  | // will not need an AST.  The code generator will assume that there is a | 
|  | // local variable stack slot allocated for the current context and (I | 
|  | // think) that the runtime will expect it to be at a fixed offset which | 
|  | // requires allocating an unused expression temporary variable. | 
|  | set_scopes(parsed_function()->EnsureKernelScopes()); | 
|  |  | 
|  | switch (function.kind()) { | 
|  | case RawFunction::kRegularFunction: | 
|  | case RawFunction::kImplicitClosureFunction: | 
|  | case RawFunction::kGetterFunction: | 
|  | case RawFunction::kSetterFunction: { | 
|  | ReadUntilFunctionNode(parsed_function()); | 
|  | if (function.is_no_such_method_forwarder()) { | 
|  | return BuildGraphOfNoSuchMethodForwarder( | 
|  | function, function.IsImplicitClosureFunction()); | 
|  | } else if (function.IsImplicitClosureFunction()) { | 
|  | return BuildGraphOfImplicitClosureFunction(function); | 
|  | } | 
|  | } | 
|  | // fallthrough intended | 
|  | case RawFunction::kClosureFunction: | 
|  | case RawFunction::kConvertedClosureFunction: { | 
|  | ReadUntilFunctionNode(parsed_function());  // read until function node. | 
|  | return BuildGraphOfFunction(false); | 
|  | } | 
|  | case RawFunction::kConstructor: { | 
|  | ReadUntilFunctionNode(parsed_function());  // read until function node. | 
|  | return BuildGraphOfFunction(!function.IsFactory()); | 
|  | } | 
|  | case RawFunction::kImplicitGetter: | 
|  | case RawFunction::kImplicitStaticFinalGetter: | 
|  | case RawFunction::kImplicitSetter: { | 
|  | return IsFieldInitializer(function, Z) | 
|  | ? BuildGraphOfFieldInitializer() | 
|  | : BuildGraphOfFieldAccessor(scopes()->setter_value); | 
|  | } | 
|  | case RawFunction::kMethodExtractor: | 
|  | return flow_graph_builder_->BuildGraphOfMethodExtractor(function); | 
|  | case RawFunction::kNoSuchMethodDispatcher: | 
|  | return flow_graph_builder_->BuildGraphOfNoSuchMethodDispatcher(function); | 
|  | case RawFunction::kInvokeFieldDispatcher: | 
|  | return flow_graph_builder_->BuildGraphOfInvokeFieldDispatcher(function); | 
|  | case RawFunction::kSignatureFunction: | 
|  | case RawFunction::kIrregexpFunction: | 
|  | break; | 
|  | } | 
|  | UNREACHABLE(); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) { | 
|  | SetOffset(kernel_offset); | 
|  | return BuildStatement();  // read statement. | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) { | 
|  | uint8_t payload = 0; | 
|  | Tag tag = ReadTag(&payload);  // read tag. | 
|  | switch (tag) { | 
|  | case kInvalidExpression: | 
|  | return BuildInvalidExpression(position); | 
|  | case kVariableGet: | 
|  | return BuildVariableGet(position); | 
|  | case kSpecializedVariableGet: | 
|  | return BuildVariableGet(payload, position); | 
|  | case kVariableSet: | 
|  | return BuildVariableSet(position); | 
|  | case kSpecializedVariableSet: | 
|  | return BuildVariableSet(payload, position); | 
|  | case kPropertyGet: | 
|  | return BuildPropertyGet(position); | 
|  | case kPropertySet: | 
|  | return BuildPropertySet(position); | 
|  | case kDirectPropertyGet: | 
|  | return BuildDirectPropertyGet(position); | 
|  | case kDirectPropertySet: | 
|  | return BuildDirectPropertySet(position); | 
|  | case kSuperPropertyGet: | 
|  | return BuildSuperPropertyGet(position); | 
|  | case kSuperPropertySet: | 
|  | return BuildSuperPropertySet(position); | 
|  | case kStaticGet: | 
|  | return BuildStaticGet(position); | 
|  | case kStaticSet: | 
|  | return BuildStaticSet(position); | 
|  | case kMethodInvocation: | 
|  | return BuildMethodInvocation(position); | 
|  | case kSuperMethodInvocation: | 
|  | return BuildSuperMethodInvocation(position); | 
|  | case kDirectMethodInvocation: | 
|  | return BuildDirectMethodInvocation(position); | 
|  | case kStaticInvocation: | 
|  | return BuildStaticInvocation(false, position); | 
|  | case kConstStaticInvocation: | 
|  | return BuildStaticInvocation(true, position); | 
|  | case kConstructorInvocation: | 
|  | return BuildConstructorInvocation(false, position); | 
|  | case kConstConstructorInvocation: | 
|  | return BuildConstructorInvocation(true, position); | 
|  | case kNot: | 
|  | return BuildNot(position); | 
|  | case kLogicalExpression: | 
|  | return BuildLogicalExpression(position); | 
|  | case kConditionalExpression: | 
|  | return BuildConditionalExpression(position); | 
|  | case kStringConcatenation: | 
|  | return BuildStringConcatenation(position); | 
|  | case kIsExpression: | 
|  | return BuildIsExpression(position); | 
|  | case kAsExpression: | 
|  | return BuildAsExpression(position); | 
|  | case kSymbolLiteral: | 
|  | return BuildSymbolLiteral(position); | 
|  | case kTypeLiteral: | 
|  | return BuildTypeLiteral(position); | 
|  | case kThisExpression: | 
|  | return BuildThisExpression(position); | 
|  | case kRethrow: | 
|  | return BuildRethrow(position); | 
|  | case kThrow: | 
|  | return BuildThrow(position); | 
|  | case kListLiteral: | 
|  | return BuildListLiteral(false, position); | 
|  | case kConstListLiteral: | 
|  | return BuildListLiteral(true, position); | 
|  | case kMapLiteral: | 
|  | return BuildMapLiteral(false, position); | 
|  | case kConstMapLiteral: | 
|  | return BuildMapLiteral(true, position); | 
|  | case kFunctionExpression: | 
|  | return BuildFunctionExpression(); | 
|  | case kLet: | 
|  | return BuildLet(position); | 
|  | case kBigIntLiteral: | 
|  | return BuildBigIntLiteral(position); | 
|  | case kStringLiteral: | 
|  | return BuildStringLiteral(position); | 
|  | case kSpecializedIntLiteral: | 
|  | return BuildIntLiteral(payload, position); | 
|  | case kNegativeIntLiteral: | 
|  | return BuildIntLiteral(true, position); | 
|  | case kPositiveIntLiteral: | 
|  | return BuildIntLiteral(false, position); | 
|  | case kDoubleLiteral: | 
|  | return BuildDoubleLiteral(position); | 
|  | case kTrueLiteral: | 
|  | return BuildBoolLiteral(true, position); | 
|  | case kFalseLiteral: | 
|  | return BuildBoolLiteral(false, position); | 
|  | case kNullLiteral: | 
|  | return BuildNullLiteral(position); | 
|  | case kVectorCreation: | 
|  | return BuildVectorCreation(position); | 
|  | case kVectorGet: | 
|  | return BuildVectorGet(position); | 
|  | case kVectorSet: | 
|  | return BuildVectorSet(position); | 
|  | case kVectorCopy: | 
|  | return BuildVectorCopy(position); | 
|  | case kClosureCreation: | 
|  | return BuildClosureCreation(position); | 
|  | case kConstantExpression: | 
|  | return BuildConstantExpression(position); | 
|  | case kInstantiation: | 
|  | return BuildPartialTearoffInstantiation(position); | 
|  | case kLoadLibrary: | 
|  | case kCheckLibraryIsLoaded: | 
|  | ReadUInt();  // skip library index | 
|  | return BuildFutureNullValue(position); | 
|  | default: | 
|  | ReportUnexpectedTag("expression", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStatement() { | 
|  | Tag tag = ReadTag();  // read tag. | 
|  | switch (tag) { | 
|  | case kExpressionStatement: | 
|  | return BuildExpressionStatement(); | 
|  | case kBlock: | 
|  | return BuildBlock(); | 
|  | case kEmptyStatement: | 
|  | return BuildEmptyStatement(); | 
|  | case kAssertBlock: | 
|  | return BuildAssertBlock(); | 
|  | case kAssertStatement: | 
|  | return BuildAssertStatement(); | 
|  | case kLabeledStatement: | 
|  | return BuildLabeledStatement(); | 
|  | case kBreakStatement: | 
|  | return BuildBreakStatement(); | 
|  | case kWhileStatement: | 
|  | return BuildWhileStatement(); | 
|  | case kDoStatement: | 
|  | return BuildDoStatement(); | 
|  | case kForStatement: | 
|  | return BuildForStatement(); | 
|  | case kForInStatement: | 
|  | return BuildForInStatement(false); | 
|  | case kAsyncForInStatement: | 
|  | return BuildForInStatement(true); | 
|  | case kSwitchStatement: | 
|  | return BuildSwitchStatement(); | 
|  | case kContinueSwitchStatement: | 
|  | return BuildContinueSwitchStatement(); | 
|  | case kIfStatement: | 
|  | return BuildIfStatement(); | 
|  | case kReturnStatement: | 
|  | return BuildReturnStatement(); | 
|  | case kTryCatch: | 
|  | return BuildTryCatch(); | 
|  | case kTryFinally: | 
|  | return BuildTryFinally(); | 
|  | case kYieldStatement: | 
|  | return BuildYieldStatement(); | 
|  | case kVariableDeclaration: | 
|  | return BuildVariableDeclaration(); | 
|  | case kFunctionDeclaration: | 
|  | return BuildFunctionDeclaration(); | 
|  | default: | 
|  | ReportUnexpectedTag("statement", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | intptr_t KernelReaderHelper::ReaderOffset() const { | 
|  | return reader_.offset(); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SetOffset(intptr_t offset) { | 
|  | reader_.set_offset(offset); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipBytes(intptr_t bytes) { | 
|  | reader_.set_offset(ReaderOffset() + bytes); | 
|  | } | 
|  |  | 
|  | bool KernelReaderHelper::ReadBool() { | 
|  | return reader_.ReadBool(); | 
|  | } | 
|  |  | 
|  | uint8_t KernelReaderHelper::ReadByte() { | 
|  | return reader_.ReadByte(); | 
|  | } | 
|  |  | 
|  | uint32_t KernelReaderHelper::ReadUInt() { | 
|  | return reader_.ReadUInt(); | 
|  | } | 
|  |  | 
|  | uint32_t KernelReaderHelper::ReadUInt32() { | 
|  | return reader_.ReadUInt32(); | 
|  | } | 
|  |  | 
|  | uint32_t KernelReaderHelper::PeekUInt() { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | return reader_.ReadUInt(); | 
|  | } | 
|  |  | 
|  | uint32_t KernelReaderHelper::PeekListLength() { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | return reader_.ReadListLength(); | 
|  | } | 
|  |  | 
|  | intptr_t KernelReaderHelper::ReadListLength() { | 
|  | return reader_.ReadListLength(); | 
|  | } | 
|  |  | 
|  | StringIndex KernelReaderHelper::ReadStringReference() { | 
|  | return StringIndex(ReadUInt()); | 
|  | } | 
|  |  | 
|  | NameIndex KernelReaderHelper::ReadCanonicalNameReference() { | 
|  | return reader_.ReadCanonicalNameReference(); | 
|  | } | 
|  |  | 
|  | StringIndex KernelReaderHelper::ReadNameAsStringIndex() { | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') { | 
|  | ReadUInt();  // read library index. | 
|  | } | 
|  | return name_index; | 
|  | } | 
|  |  | 
|  | const String& KernelReaderHelper::ReadNameAsMethodName() { | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') { | 
|  | NameIndex library_reference = | 
|  | ReadCanonicalNameReference();  // read library index. | 
|  | return H.DartMethodName(library_reference, name_index); | 
|  | } else { | 
|  | return H.DartMethodName(NameIndex(), name_index); | 
|  | } | 
|  | } | 
|  |  | 
|  | const String& KernelReaderHelper::ReadNameAsSetterName() { | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') { | 
|  | NameIndex library_reference = | 
|  | ReadCanonicalNameReference();  // read library index. | 
|  | return H.DartSetterName(library_reference, name_index); | 
|  | } else { | 
|  | return H.DartSetterName(NameIndex(), name_index); | 
|  | } | 
|  | } | 
|  |  | 
|  | const String& KernelReaderHelper::ReadNameAsGetterName() { | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') { | 
|  | NameIndex library_reference = | 
|  | ReadCanonicalNameReference();  // read library index. | 
|  | return H.DartGetterName(library_reference, name_index); | 
|  | } else { | 
|  | return H.DartGetterName(NameIndex(), name_index); | 
|  | } | 
|  | } | 
|  |  | 
|  | const String& KernelReaderHelper::ReadNameAsFieldName() { | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') { | 
|  | NameIndex library_reference = | 
|  | ReadCanonicalNameReference();  // read library index. | 
|  | return H.DartFieldName(library_reference, name_index); | 
|  | } else { | 
|  | return H.DartFieldName(NameIndex(), name_index); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipFlags() { | 
|  | ReadFlags(); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipStringReference() { | 
|  | ReadUInt(); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipConstantReference() { | 
|  | ReadUInt(); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipCanonicalNameReference() { | 
|  | ReadUInt(); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::ReportUnexpectedTag(const char* variant, Tag tag) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Unexpected tag %d (%s) in ?, expected %s", tag, | 
|  | Reader::TagName(tag), variant); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::ReportUnexpectedTag(const char* variant, | 
|  | Tag tag) { | 
|  | if ((flow_graph_builder_ == NULL) || (parsed_function() == NULL)) { | 
|  | KernelReaderHelper::ReportUnexpectedTag(variant, tag); | 
|  | } else { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Unexpected tag %d (%s) in %s, expected %s", tag, | 
|  | Reader::TagName(tag), | 
|  | parsed_function()->function().ToQualifiedCString(), variant); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipDartType() { | 
|  | Tag tag = ReadTag(); | 
|  | switch (tag) { | 
|  | case kInvalidType: | 
|  | case kDynamicType: | 
|  | case kVoidType: | 
|  | case kBottomType: | 
|  | case kVectorType: | 
|  | // those contain nothing. | 
|  | return; | 
|  | case kInterfaceType: | 
|  | SkipInterfaceType(false); | 
|  | return; | 
|  | case kSimpleInterfaceType: | 
|  | SkipInterfaceType(true); | 
|  | return; | 
|  | case kFunctionType: | 
|  | SkipFunctionType(false); | 
|  | return; | 
|  | case kSimpleFunctionType: | 
|  | SkipFunctionType(true); | 
|  | return; | 
|  | case kTypeParameterType: | 
|  | ReadUInt();              // read index for parameter. | 
|  | SkipOptionalDartType();  // read bound bound. | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("type", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipOptionalDartType() { | 
|  | Tag tag = ReadTag();  // read tag. | 
|  | if (tag == kNothing) { | 
|  | return; | 
|  | } | 
|  | ASSERT(tag == kSomething); | 
|  |  | 
|  | SkipDartType();  // read type. | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipInterfaceType(bool simple) { | 
|  | ReadUInt();  // read klass_name. | 
|  | if (!simple) { | 
|  | SkipListOfDartTypes();  // read list of types. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipFunctionType(bool simple) { | 
|  | if (!simple) { | 
|  | SkipTypeParametersList();  // read type_parameters. | 
|  | ReadUInt();                // read required parameter count. | 
|  | ReadUInt();                // read total parameter count. | 
|  | } | 
|  |  | 
|  | SkipListOfDartTypes();  // read positional_parameters types. | 
|  |  | 
|  | if (!simple) { | 
|  | const intptr_t named_count = | 
|  | ReadListLength();  // read named_parameters list length. | 
|  | for (intptr_t i = 0; i < named_count; ++i) { | 
|  | // read string reference (i.e. named_parameters[i].name). | 
|  | SkipStringReference(); | 
|  | SkipDartType();  // read named_parameters[i].type. | 
|  | } | 
|  | } | 
|  |  | 
|  | SkipListOfStrings();  // read positional parameter names. | 
|  |  | 
|  | if (!simple) { | 
|  | SkipCanonicalNameReference();  // read typedef reference. | 
|  | } | 
|  |  | 
|  | SkipDartType();  // read return type. | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipStatementList() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipStatement();  // read ith expression. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipListOfExpressions() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipExpression();  // read ith expression. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipListOfDartTypes() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipDartType();  // read ith type. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipListOfStrings() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipStringReference();  // read ith string index. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipListOfVariableDeclarations() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipVariableDeclaration();  // read ith variable declaration. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipTypeParametersList() { | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | TypeParameterHelper helper(this); | 
|  | helper.Finish(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipInitializer() { | 
|  | Tag tag = ReadTag(); | 
|  | ReadByte();  // read isSynthetic flag. | 
|  | switch (tag) { | 
|  | case kInvalidInitializer: | 
|  | return; | 
|  | case kFieldInitializer: | 
|  | SkipCanonicalNameReference();  // read field_reference. | 
|  | SkipExpression();              // read value. | 
|  | return; | 
|  | case kSuperInitializer: | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | SkipArguments();               // read arguments. | 
|  | return; | 
|  | case kRedirectingInitializer: | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | SkipArguments();               // read arguments. | 
|  | return; | 
|  | case kLocalInitializer: | 
|  | SkipVariableDeclaration();  // read variable. | 
|  | return; | 
|  | case kAssertInitializer: | 
|  | SkipStatement(); | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("initializer", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipExpression() { | 
|  | uint8_t payload = 0; | 
|  | Tag tag = ReadTag(&payload); | 
|  | switch (tag) { | 
|  | case kInvalidExpression: | 
|  | ReadPosition(); | 
|  | SkipStringReference(); | 
|  | return; | 
|  | case kVariableGet: | 
|  | ReadPosition();          // read position. | 
|  | ReadUInt();              // read kernel position. | 
|  | ReadUInt();              // read relative variable index. | 
|  | SkipOptionalDartType();  // read promoted type. | 
|  | return; | 
|  | case kSpecializedVariableGet: | 
|  | ReadPosition();  // read position. | 
|  | ReadUInt();      // read kernel position. | 
|  | return; | 
|  | case kVariableSet: | 
|  | ReadPosition();    // read position. | 
|  | ReadUInt();        // read kernel position. | 
|  | ReadUInt();        // read relative variable index. | 
|  | SkipExpression();  // read expression. | 
|  | return; | 
|  | case kSpecializedVariableSet: | 
|  | ReadPosition();    // read position. | 
|  | ReadUInt();        // read kernel position. | 
|  | SkipExpression();  // read expression. | 
|  | return; | 
|  | case kPropertyGet: | 
|  | ReadPosition();                // read position. | 
|  | SkipExpression();              // read receiver. | 
|  | SkipName();                    // read name. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return; | 
|  | case kPropertySet: | 
|  | ReadPosition();                // read position. | 
|  | SkipExpression();              // read receiver. | 
|  | SkipName();                    // read name. | 
|  | SkipExpression();              // read value. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return; | 
|  | case kSuperPropertyGet: | 
|  | ReadPosition();                // read position. | 
|  | SkipName();                    // read name. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return; | 
|  | case kSuperPropertySet: | 
|  | ReadPosition();                // read position. | 
|  | SkipName();                    // read name. | 
|  | SkipExpression();              // read value. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return; | 
|  | case kDirectPropertyGet: | 
|  | ReadPosition();                // read position. | 
|  | SkipExpression();              // read receiver. | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | return; | 
|  | case kDirectPropertySet: | 
|  | ReadPosition();                // read position. | 
|  | SkipExpression();              // read receiver. | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | SkipExpression();              // read value· | 
|  | return; | 
|  | case kStaticGet: | 
|  | ReadPosition();                // read position. | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | return; | 
|  | case kStaticSet: | 
|  | ReadPosition();                // read position. | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | SkipExpression();              // read expression. | 
|  | return; | 
|  | case kMethodInvocation: | 
|  | ReadPosition();                // read position. | 
|  | SkipExpression();              // read receiver. | 
|  | SkipName();                    // read name. | 
|  | SkipArguments();               // read arguments. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return; | 
|  | case kSuperMethodInvocation: | 
|  | ReadPosition();                // read position. | 
|  | SkipName();                    // read name. | 
|  | SkipArguments();               // read arguments. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return; | 
|  | case kDirectMethodInvocation: | 
|  | ReadPosition();                // read position. | 
|  | SkipExpression();              // read receiver. | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | SkipArguments();               // read arguments. | 
|  | return; | 
|  | case kStaticInvocation: | 
|  | case kConstStaticInvocation: | 
|  | ReadPosition();                // read position. | 
|  | SkipCanonicalNameReference();  // read procedure_reference. | 
|  | SkipArguments();               // read arguments. | 
|  | return; | 
|  | case kConstructorInvocation: | 
|  | case kConstConstructorInvocation: | 
|  | ReadPosition();                // read position. | 
|  | SkipCanonicalNameReference();  // read target_reference. | 
|  | SkipArguments();               // read arguments. | 
|  | return; | 
|  | case kNot: | 
|  | SkipExpression();  // read expression. | 
|  | return; | 
|  | case kLogicalExpression: | 
|  | SkipExpression();  // read left. | 
|  | SkipBytes(1);      // read operator. | 
|  | SkipExpression();  // read right. | 
|  | return; | 
|  | case kConditionalExpression: | 
|  | SkipExpression();        // read condition. | 
|  | SkipExpression();        // read then. | 
|  | SkipExpression();        // read otherwise. | 
|  | SkipOptionalDartType();  // read unused static type. | 
|  | return; | 
|  | case kStringConcatenation: | 
|  | ReadPosition();           // read position. | 
|  | SkipListOfExpressions();  // read list of expressions. | 
|  | return; | 
|  | case kIsExpression: | 
|  | ReadPosition();    // read position. | 
|  | SkipExpression();  // read operand. | 
|  | SkipDartType();    // read type. | 
|  | return; | 
|  | case kAsExpression: | 
|  | ReadPosition();    // read position. | 
|  | SkipFlags();       // read flags. | 
|  | SkipExpression();  // read operand. | 
|  | SkipDartType();    // read type. | 
|  | return; | 
|  | case kSymbolLiteral: | 
|  | SkipStringReference();  // read index into string table. | 
|  | return; | 
|  | case kTypeLiteral: | 
|  | SkipDartType();  // read type. | 
|  | return; | 
|  | case kThisExpression: | 
|  | return; | 
|  | case kRethrow: | 
|  | ReadPosition();  // read position. | 
|  | return; | 
|  | case kThrow: | 
|  | ReadPosition();    // read position. | 
|  | SkipExpression();  // read expression. | 
|  | return; | 
|  | case kListLiteral: | 
|  | case kConstListLiteral: | 
|  | ReadPosition();           // read position. | 
|  | SkipDartType();           // read type. | 
|  | SkipListOfExpressions();  // read list of expressions. | 
|  | return; | 
|  | case kMapLiteral: | 
|  | case kConstMapLiteral: { | 
|  | ReadPosition();                           // read position. | 
|  | SkipDartType();                           // read key type. | 
|  | SkipDartType();                           // read value type. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | SkipExpression();  // read ith key. | 
|  | SkipExpression();  // read ith value. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kFunctionExpression: | 
|  | ReadPosition();      // read position. | 
|  | SkipFunctionNode();  // read function node. | 
|  | return; | 
|  | case kLet: | 
|  | SkipVariableDeclaration();  // read variable declaration. | 
|  | SkipExpression();           // read expression. | 
|  | return; | 
|  | case kInstantiation: | 
|  | SkipExpression();       // read expression. | 
|  | SkipListOfDartTypes();  // read type arguments. | 
|  | return; | 
|  | case kVectorCreation: | 
|  | ReadUInt();  // read value. | 
|  | return; | 
|  | case kVectorGet: | 
|  | SkipExpression();  // read vector expression. | 
|  | ReadUInt();        // read index. | 
|  | return; | 
|  | case kVectorSet: | 
|  | SkipExpression();  // read vector expression. | 
|  | ReadUInt();        // read index. | 
|  | SkipExpression();  // read value. | 
|  | return; | 
|  | case kVectorCopy: | 
|  | SkipExpression();  // read vector expression. | 
|  | return; | 
|  | case kClosureCreation: | 
|  | SkipCanonicalNameReference();  // read top-level function reference. | 
|  | SkipExpression();              // read context vector. | 
|  | SkipDartType();                // read function type. | 
|  | SkipListOfDartTypes();         // read type arguments. | 
|  | return; | 
|  | case kBigIntLiteral: | 
|  | SkipStringReference();  // read string reference. | 
|  | return; | 
|  | case kStringLiteral: | 
|  | SkipStringReference();  // read string reference. | 
|  | return; | 
|  | case kSpecializedIntLiteral: | 
|  | return; | 
|  | case kNegativeIntLiteral: | 
|  | ReadUInt();  // read value. | 
|  | return; | 
|  | case kPositiveIntLiteral: | 
|  | ReadUInt();  // read value. | 
|  | return; | 
|  | case kDoubleLiteral: | 
|  | SkipStringReference();  // read index into string table. | 
|  | return; | 
|  | case kTrueLiteral: | 
|  | return; | 
|  | case kFalseLiteral: | 
|  | return; | 
|  | case kNullLiteral: | 
|  | return; | 
|  | case kConstantExpression: | 
|  | SkipConstantReference(); | 
|  | return; | 
|  | case kLoadLibrary: | 
|  | case kCheckLibraryIsLoaded: | 
|  | ReadUInt();  // skip library index | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("expression", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipStatement() { | 
|  | Tag tag = ReadTag();  // read tag. | 
|  | switch (tag) { | 
|  | case kExpressionStatement: | 
|  | SkipExpression();  // read expression. | 
|  | return; | 
|  | case kBlock: | 
|  | SkipStatementList(); | 
|  | return; | 
|  | case kEmptyStatement: | 
|  | return; | 
|  | case kAssertBlock: | 
|  | SkipStatementList(); | 
|  | return; | 
|  | case kAssertStatement: | 
|  | SkipExpression();     // Read condition. | 
|  | ReadPosition();       // read condition start offset. | 
|  | ReadPosition();       // read condition end offset. | 
|  | if (ReadTag() == kSomething) { | 
|  | SkipExpression();  // read (rest of) message. | 
|  | } | 
|  | return; | 
|  | case kLabeledStatement: | 
|  | SkipStatement();  // read body. | 
|  | return; | 
|  | case kBreakStatement: | 
|  | ReadPosition();  // read position. | 
|  | ReadUInt();      // read target_index. | 
|  | return; | 
|  | case kWhileStatement: | 
|  | ReadPosition();    // read position. | 
|  | SkipExpression();  // read condition. | 
|  | SkipStatement();   // read body. | 
|  | return; | 
|  | case kDoStatement: | 
|  | ReadPosition();    // read position. | 
|  | SkipStatement();   // read body. | 
|  | SkipExpression();  // read condition. | 
|  | return; | 
|  | case kForStatement: { | 
|  | ReadPosition();                    // read position. | 
|  | SkipListOfVariableDeclarations();  // read variables. | 
|  | Tag tag = ReadTag();               // Read first part of condition. | 
|  | if (tag == kSomething) { | 
|  | SkipExpression();  // read rest of condition. | 
|  | } | 
|  | SkipListOfExpressions();  // read updates. | 
|  | SkipStatement();          // read body. | 
|  | return; | 
|  | } | 
|  | case kForInStatement: | 
|  | case kAsyncForInStatement: | 
|  | ReadPosition();             // read position. | 
|  | ReadPosition();             // read body position. | 
|  | SkipVariableDeclaration();  // read variable. | 
|  | SkipExpression();           // read iterable. | 
|  | SkipStatement();            // read body. | 
|  | return; | 
|  | case kSwitchStatement: { | 
|  | ReadPosition();                     // read position. | 
|  | SkipExpression();                   // read condition. | 
|  | int case_count = ReadListLength();  // read number of cases. | 
|  | for (intptr_t i = 0; i < case_count; ++i) { | 
|  | int expression_count = ReadListLength();  // read number of expressions. | 
|  | for (intptr_t j = 0; j < expression_count; ++j) { | 
|  | ReadPosition();    // read jth position. | 
|  | SkipExpression();  // read jth expression. | 
|  | } | 
|  | ReadBool();       // read is_default. | 
|  | SkipStatement();  // read body. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kContinueSwitchStatement: | 
|  | ReadPosition();  // read position. | 
|  | ReadUInt();      // read target_index. | 
|  | return; | 
|  | case kIfStatement: | 
|  | ReadPosition();    // read position. | 
|  | SkipExpression();  // read condition. | 
|  | SkipStatement();   // read then. | 
|  | SkipStatement();   // read otherwise. | 
|  | return; | 
|  | case kReturnStatement: { | 
|  | ReadPosition();       // read position | 
|  | Tag tag = ReadTag();  // read (first part of) expression. | 
|  | if (tag == kSomething) { | 
|  | SkipExpression();  // read (rest of) expression. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kTryCatch: { | 
|  | SkipStatement();  // read body. | 
|  | ReadBool();       // read any_catch_needs_stack_trace. | 
|  | intptr_t catch_count = ReadListLength();  // read number of catches. | 
|  | for (intptr_t i = 0; i < catch_count; ++i) { | 
|  | ReadPosition();   // read position. | 
|  | SkipDartType();   // read guard. | 
|  | tag = ReadTag();  // read first part of exception. | 
|  | if (tag == kSomething) { | 
|  | SkipVariableDeclaration();  // read exception. | 
|  | } | 
|  | tag = ReadTag();  // read first part of stack trace. | 
|  | if (tag == kSomething) { | 
|  | SkipVariableDeclaration();  // read stack trace. | 
|  | } | 
|  | SkipStatement();  // read body. | 
|  | } | 
|  | return; | 
|  | } | 
|  | case kTryFinally: | 
|  | SkipStatement();  // read body. | 
|  | SkipStatement();  // read finalizer. | 
|  | return; | 
|  | case kYieldStatement: { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | RecordYieldPosition(position); | 
|  | ReadByte();        // read flags. | 
|  | SkipExpression();  // read expression. | 
|  | return; | 
|  | } | 
|  | case kVariableDeclaration: | 
|  | SkipVariableDeclaration();  // read variable declaration. | 
|  | return; | 
|  | case kFunctionDeclaration: | 
|  | ReadPosition();             // read position. | 
|  | SkipVariableDeclaration();  // read variable. | 
|  | SkipFunctionNode();         // read function node. | 
|  | return; | 
|  | default: | 
|  | ReportUnexpectedTag("statement", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipFunctionNode() { | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipName() { | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') { | 
|  | SkipCanonicalNameReference();  // read library index. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipArguments() { | 
|  | ReadUInt();  // read argument count. | 
|  |  | 
|  | SkipListOfDartTypes();    // read list of types. | 
|  | SkipListOfExpressions();  // read positionals. | 
|  |  | 
|  | // List of named. | 
|  | 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. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipVariableDeclaration() { | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd); | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipLibraryCombinator() { | 
|  | ReadBool();                        // read is_show. | 
|  | intptr_t name_count = ReadUInt();  // read list length. | 
|  | for (intptr_t j = 0; j < name_count; ++j) { | 
|  | ReadUInt();  // read ith entry of name_indices. | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipLibraryDependency() { | 
|  | ReadPosition();  // read file offset. | 
|  | ReadFlags(); | 
|  | SkipListOfExpressions();  // Annotations. | 
|  | ReadCanonicalNameReference(); | 
|  | ReadStringReference();  // Name. | 
|  | intptr_t combinator_count = ReadListLength(); | 
|  | for (intptr_t i = 0; i < combinator_count; ++i) { | 
|  | SkipLibraryCombinator(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipLibraryPart() { | 
|  | SkipListOfExpressions();  // Read annotations. | 
|  | SkipStringReference();    // Read part URI index. | 
|  | } | 
|  |  | 
|  | void KernelReaderHelper::SkipLibraryTypedef() { | 
|  | SkipCanonicalNameReference();  // read canonical name. | 
|  | ReadUInt();                    // read source_uri_index. | 
|  | ReadPosition();                // read position. | 
|  | SkipStringReference();         // read name index. | 
|  | SkipListOfExpressions();       // read annotations. | 
|  | SkipTypeParametersList();      // read type parameters. | 
|  | SkipDartType();                // read type. | 
|  | } | 
|  |  | 
|  | TokenPosition KernelReaderHelper::ReadPosition(bool record) { | 
|  | TokenPosition position = reader_.ReadPosition(); | 
|  | if (record) { | 
|  | RecordTokenPosition(position); | 
|  | } | 
|  | return position; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::RecordTokenPosition(TokenPosition position) { | 
|  | if (record_for_script_id_ == current_script_id_ && | 
|  | record_token_positions_into_ != NULL && position.IsReal()) { | 
|  | record_token_positions_into_->Add(position.value()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::RecordYieldPosition(TokenPosition position) { | 
|  | if (record_for_script_id_ == current_script_id_ && | 
|  | record_yield_positions_into_ != NULL && position.IsReal()) { | 
|  | record_yield_positions_into_->Add(position.value()); | 
|  | } | 
|  | } | 
|  |  | 
|  | Tag KernelReaderHelper::ReadTag(uint8_t* payload) { | 
|  | return reader_.ReadTag(payload); | 
|  | } | 
|  |  | 
|  | Tag KernelReaderHelper::PeekTag(uint8_t* payload) { | 
|  | return reader_.PeekTag(payload); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::loop_depth_inc() { | 
|  | ++flow_graph_builder_->loop_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::loop_depth_dec() { | 
|  | --flow_graph_builder_->loop_depth_; | 
|  | } | 
|  |  | 
|  | intptr_t StreamingFlowGraphBuilder::for_in_depth() { | 
|  | return flow_graph_builder_->for_in_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::for_in_depth_inc() { | 
|  | ++flow_graph_builder_->for_in_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::for_in_depth_dec() { | 
|  | --flow_graph_builder_->for_in_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::catch_depth_inc() { | 
|  | ++flow_graph_builder_->catch_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::catch_depth_dec() { | 
|  | --flow_graph_builder_->catch_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::try_depth_inc() { | 
|  | ++flow_graph_builder_->try_depth_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::try_depth_dec() { | 
|  | --flow_graph_builder_->try_depth_; | 
|  | } | 
|  |  | 
|  | intptr_t StreamingFlowGraphBuilder::CurrentTryIndex() { | 
|  | return flow_graph_builder_->CurrentTryIndex(); | 
|  | } | 
|  |  | 
|  | intptr_t StreamingFlowGraphBuilder::AllocateTryIndex() { | 
|  | return flow_graph_builder_->AllocateTryIndex(); | 
|  | } | 
|  |  | 
|  | LocalVariable* StreamingFlowGraphBuilder::CurrentException() { | 
|  | return flow_graph_builder_->CurrentException(); | 
|  | } | 
|  |  | 
|  | LocalVariable* StreamingFlowGraphBuilder::CurrentStackTrace() { | 
|  | return flow_graph_builder_->CurrentStackTrace(); | 
|  | } | 
|  |  | 
|  | CatchBlock* StreamingFlowGraphBuilder::catch_block() { | 
|  | return flow_graph_builder_->catch_block_; | 
|  | } | 
|  |  | 
|  | ActiveClass* StreamingFlowGraphBuilder::active_class() { | 
|  | return &flow_graph_builder_->active_class_; | 
|  | } | 
|  |  | 
|  | ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() { | 
|  | return flow_graph_builder_->scopes_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::set_scopes(ScopeBuildingResult* scope) { | 
|  | flow_graph_builder_->scopes_ = scope; | 
|  | } | 
|  |  | 
|  | ParsedFunction* StreamingFlowGraphBuilder::parsed_function() { | 
|  | return flow_graph_builder_->parsed_function_; | 
|  | } | 
|  |  | 
|  | TryFinallyBlock* StreamingFlowGraphBuilder::try_finally_block() { | 
|  | return flow_graph_builder_->try_finally_block_; | 
|  | } | 
|  |  | 
|  | SwitchBlock* StreamingFlowGraphBuilder::switch_block() { | 
|  | return flow_graph_builder_->switch_block_; | 
|  | } | 
|  |  | 
|  | BreakableBlock* StreamingFlowGraphBuilder::breakable_block() { | 
|  | return flow_graph_builder_->breakable_block_; | 
|  | } | 
|  |  | 
|  | GrowableArray<YieldContinuation>& | 
|  | StreamingFlowGraphBuilder::yield_continuations() { | 
|  | return flow_graph_builder_->yield_continuations_; | 
|  | } | 
|  |  | 
|  | Value* StreamingFlowGraphBuilder::stack() { | 
|  | return flow_graph_builder_->stack_; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::Push(Definition* definition) { | 
|  | flow_graph_builder_->Push(definition); | 
|  | } | 
|  |  | 
|  | Value* StreamingFlowGraphBuilder::Pop() { | 
|  | return flow_graph_builder_->Pop(); | 
|  | } | 
|  |  | 
|  | Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() { | 
|  | // read parts of arguments, then go back to before doing so. | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | ReadUInt();  // read number of arguments. | 
|  |  | 
|  | SkipListOfDartTypes();  // Read list of types. | 
|  |  | 
|  | // List of positional. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | if (list_length > 0) { | 
|  | return ReadTag();  // read first tag. | 
|  | } | 
|  |  | 
|  | UNREACHABLE(); | 
|  | return kNothing; | 
|  | } | 
|  |  | 
|  | const TypeArguments& StreamingFlowGraphBuilder::PeekArgumentsInstantiatedType( | 
|  | const Class& klass) { | 
|  | // read parts of arguments, then go back to before doing so. | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | ReadUInt();                               // read argument count. | 
|  | intptr_t list_length = ReadListLength();  // read types list length. | 
|  | return T.BuildInstantiatedTypeArguments(klass, list_length);  // read types. | 
|  | } | 
|  |  | 
|  | intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() { | 
|  | return PeekUInt(); | 
|  | } | 
|  |  | 
|  | LocalVariable* StreamingFlowGraphBuilder::LookupVariable( | 
|  | intptr_t kernel_offset) { | 
|  | return flow_graph_builder_->LookupVariable(kernel_offset); | 
|  | } | 
|  |  | 
|  | LocalVariable* StreamingFlowGraphBuilder::MakeTemporary() { | 
|  | return flow_graph_builder_->MakeTemporary(); | 
|  | } | 
|  |  | 
|  | RawFunction* StreamingFlowGraphBuilder::LookupMethodByMember( | 
|  | NameIndex target, | 
|  | const String& method_name) { | 
|  | return flow_graph_builder_->LookupMethodByMember(target, method_name); | 
|  | } | 
|  |  | 
|  | Function& StreamingFlowGraphBuilder::FindMatchingFunctionAnyArgs( | 
|  | const Class& klass, | 
|  | const String& name) { | 
|  | // Search the superclass chain for the selector. | 
|  | Function& function = Function::Handle(Z); | 
|  | Class& iterate_klass = Class::Handle(Z, klass.raw()); | 
|  | while (!iterate_klass.IsNull()) { | 
|  | function = iterate_klass.LookupDynamicFunctionAllowPrivate(name); | 
|  | if (!function.IsNull()) break; | 
|  | iterate_klass = iterate_klass.SuperClass(); | 
|  | } | 
|  | return function; | 
|  | } | 
|  |  | 
|  | Function& StreamingFlowGraphBuilder::FindMatchingFunction( | 
|  | const Class& klass, | 
|  | const String& name, | 
|  | int type_args_len, | 
|  | int argument_count, | 
|  | const Array& argument_names) { | 
|  | // Search the superclass chain for the selector. | 
|  | Function& function = Function::Handle(Z); | 
|  | Class& iterate_klass = Class::Handle(Z, klass.raw()); | 
|  | while (!iterate_klass.IsNull()) { | 
|  | function = iterate_klass.LookupDynamicFunctionAllowPrivate(name); | 
|  | if (!function.IsNull()) { | 
|  | if (function.AreValidArguments(type_args_len, argument_count, | 
|  | argument_names, | 
|  | /* error_message = */ NULL)) { | 
|  | return function; | 
|  | } | 
|  | } | 
|  | iterate_klass = iterate_klass.SuperClass(); | 
|  | } | 
|  | return Function::Handle(); | 
|  | } | 
|  |  | 
|  | bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function, | 
|  | TokenPosition position) { | 
|  | return flow_graph_builder_->NeedsDebugStepCheck(function, position); | 
|  | } | 
|  |  | 
|  | bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(Value* value, | 
|  | TokenPosition position) { | 
|  | return flow_graph_builder_->NeedsDebugStepCheck(value, position); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::InlineBailout(const char* reason) { | 
|  | flow_graph_builder_->InlineBailout(reason); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::DebugStepCheck(TokenPosition position) { | 
|  | return flow_graph_builder_->DebugStepCheck(position); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::LoadLocal(LocalVariable* variable) { | 
|  | return flow_graph_builder_->LoadLocal(variable); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::Return(TokenPosition position) { | 
|  | return flow_graph_builder_->Return(position); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::PushArgument() { | 
|  | return flow_graph_builder_->PushArgument(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::EvaluateAssertion() { | 
|  | return flow_graph_builder_->EvaluateAssertion(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position, | 
|  | int catch_try_index) { | 
|  | return flow_graph_builder_->RethrowException(position, catch_try_index); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError() { | 
|  | return flow_graph_builder_->ThrowNoSuchMethodError(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::Constant(const Object& value) { | 
|  | return flow_graph_builder_->Constant(value); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) { | 
|  | return flow_graph_builder_->IntConstant(value); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::LoadStaticField() { | 
|  | return flow_graph_builder_->LoadStaticField(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckNull(TokenPosition position, | 
|  | LocalVariable* receiver) { | 
|  | return flow_graph_builder_->CheckNull(position, receiver); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position, | 
|  | const Function& target, | 
|  | intptr_t argument_count, | 
|  | ICData::RebindRule rebind_rule) { | 
|  | return flow_graph_builder_->StaticCall(position, target, argument_count, | 
|  | rebind_rule); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StaticCall( | 
|  | TokenPosition position, | 
|  | const Function& target, | 
|  | intptr_t argument_count, | 
|  | const Array& argument_names, | 
|  | ICData::RebindRule rebind_rule, | 
|  | const InferredTypeMetadata* result_type, | 
|  | intptr_t type_args_count) { | 
|  | return flow_graph_builder_->StaticCall(position, target, argument_count, | 
|  | argument_names, rebind_rule, | 
|  | result_type, type_args_count); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::InstanceCall( | 
|  | TokenPosition position, | 
|  | const String& name, | 
|  | Token::Kind kind, | 
|  | intptr_t argument_count, | 
|  | intptr_t checked_argument_count) { | 
|  | const intptr_t kTypeArgsLen = 0; | 
|  | return flow_graph_builder_->InstanceCall( | 
|  | position, name, kind, kTypeArgsLen, argument_count, Array::null_array(), | 
|  | checked_argument_count, Function::null_function()); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::InstanceCall( | 
|  | TokenPosition position, | 
|  | const String& name, | 
|  | Token::Kind kind, | 
|  | intptr_t type_args_len, | 
|  | intptr_t argument_count, | 
|  | const Array& argument_names, | 
|  | intptr_t checked_argument_count, | 
|  | const Function& interface_target, | 
|  | const InferredTypeMetadata* result_type) { | 
|  | return flow_graph_builder_->InstanceCall( | 
|  | position, name, kind, type_args_len, argument_count, argument_names, | 
|  | checked_argument_count, interface_target, result_type); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::ThrowException(TokenPosition position) { | 
|  | return flow_graph_builder_->ThrowException(position); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BooleanNegate() { | 
|  | return flow_graph_builder_->BooleanNegate(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::TranslateInstantiatedTypeArguments( | 
|  | const TypeArguments& type_arguments) { | 
|  | return flow_graph_builder_->TranslateInstantiatedTypeArguments( | 
|  | type_arguments); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StrictCompare(Token::Kind kind, | 
|  | bool number_check) { | 
|  | return flow_graph_builder_->StrictCompare(kind, number_check); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::AllocateObject(TokenPosition position, | 
|  | const Class& klass, | 
|  | intptr_t argument_count) { | 
|  | return flow_graph_builder_->AllocateObject(position, klass, argument_count); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::AllocateObject( | 
|  | const Class& klass, | 
|  | const Function& closure_function) { | 
|  | return flow_graph_builder_->AllocateObject(klass, closure_function); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::AllocateContext(intptr_t size) { | 
|  | return flow_graph_builder_->AllocateContext(size); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::LoadField(intptr_t offset) { | 
|  | return flow_graph_builder_->LoadField(offset); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position, | 
|  | LocalVariable* variable) { | 
|  | return flow_graph_builder_->StoreLocal(position, variable); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StoreStaticField(TokenPosition position, | 
|  | const Field& field) { | 
|  | return flow_graph_builder_->StoreStaticField(position, field); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StoreInstanceField(TokenPosition position, | 
|  | intptr_t offset) { | 
|  | return flow_graph_builder_->StoreInstanceField(position, offset); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StringInterpolate(TokenPosition position) { | 
|  | return flow_graph_builder_->StringInterpolate(position); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StringInterpolateSingle( | 
|  | TokenPosition position) { | 
|  | return flow_graph_builder_->StringInterpolateSingle(position); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::ThrowTypeError() { | 
|  | return flow_graph_builder_->ThrowTypeError(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::LoadInstantiatorTypeArguments() { | 
|  | return flow_graph_builder_->LoadInstantiatorTypeArguments(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::LoadFunctionTypeArguments() { | 
|  | return flow_graph_builder_->LoadFunctionTypeArguments(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::InstantiateType(const AbstractType& type) { | 
|  | return flow_graph_builder_->InstantiateType(type); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CreateArray() { | 
|  | return flow_graph_builder_->CreateArray(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::StoreIndexed(intptr_t class_id) { | 
|  | return flow_graph_builder_->StoreIndexed(class_id); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckStackOverflow(TokenPosition position) { | 
|  | return flow_graph_builder_->CheckStackOverflow(position); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CloneContext( | 
|  | intptr_t num_context_variables) { | 
|  | return flow_graph_builder_->CloneContext(num_context_variables); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::TranslateFinallyFinalizers( | 
|  | TryFinallyBlock* outer_finally, | 
|  | intptr_t target_context_depth) { | 
|  | // TranslateFinallyFinalizers can move the readers offset. | 
|  | // Save the current position and restore it afterwards. | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | return flow_graph_builder_->TranslateFinallyFinalizers(outer_finally, | 
|  | target_context_depth); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BranchIfTrue( | 
|  | TargetEntryInstr** then_entry, | 
|  | TargetEntryInstr** otherwise_entry, | 
|  | bool negate) { | 
|  | return flow_graph_builder_->BranchIfTrue(then_entry, otherwise_entry, negate); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BranchIfEqual( | 
|  | TargetEntryInstr** then_entry, | 
|  | TargetEntryInstr** otherwise_entry, | 
|  | bool negate) { | 
|  | return flow_graph_builder_->BranchIfEqual(then_entry, otherwise_entry, | 
|  | negate); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BranchIfNull( | 
|  | TargetEntryInstr** then_entry, | 
|  | TargetEntryInstr** otherwise_entry, | 
|  | bool negate) { | 
|  | return flow_graph_builder_->BranchIfNull(then_entry, otherwise_entry, negate); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CatchBlockEntry(const Array& handler_types, | 
|  | intptr_t handler_index, | 
|  | bool needs_stacktrace) { | 
|  | return flow_graph_builder_->CatchBlockEntry(handler_types, handler_index, | 
|  | needs_stacktrace); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::TryCatch(int try_handler_index) { | 
|  | return flow_graph_builder_->TryCatch(try_handler_index); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::Drop() { | 
|  | return flow_graph_builder_->Drop(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::DropTempsPreserveTop( | 
|  | intptr_t num_temps_to_drop) { | 
|  | return flow_graph_builder_->DropTempsPreserveTop(num_temps_to_drop); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::NullConstant() { | 
|  | return flow_graph_builder_->NullConstant(); | 
|  | } | 
|  |  | 
|  | JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry() { | 
|  | return flow_graph_builder_->BuildJoinEntry(); | 
|  | } | 
|  |  | 
|  | JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) { | 
|  | return flow_graph_builder_->BuildJoinEntry(try_index); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::Goto(JoinEntryInstr* destination) { | 
|  | return flow_graph_builder_->Goto(destination); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildImplicitClosureCreation( | 
|  | const Function& target) { | 
|  | return flow_graph_builder_->BuildImplicitClosureCreation(target); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckBoolean() { | 
|  | return flow_graph_builder_->CheckBoolean(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckAssignableInCheckedMode( | 
|  | const AbstractType& dst_type, | 
|  | const String& dst_name) { | 
|  | if (I->type_checks()) { | 
|  | return flow_graph_builder_->CheckAssignable(dst_type, dst_name); | 
|  | } | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckArgumentType( | 
|  | LocalVariable* variable, | 
|  | const AbstractType& type) { | 
|  | return flow_graph_builder_->CheckAssignable( | 
|  | type, variable->name(), AssertAssignableInstr::kParameterCheck); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckTypeArgumentBound( | 
|  | const AbstractType& parameter, | 
|  | const AbstractType& bound, | 
|  | const String& dst_name) { | 
|  | return flow_graph_builder_->AssertSubtype(TokenPosition::kNoSource, parameter, | 
|  | bound, dst_name); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckVariableTypeInCheckedMode( | 
|  | intptr_t variable_kernel_position) { | 
|  | if (I->type_checks()) { | 
|  | LocalVariable* variable = LookupVariable(variable_kernel_position); | 
|  | return flow_graph_builder_->CheckVariableTypeInCheckedMode( | 
|  | variable->type(), variable->name()); | 
|  | } | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::CheckVariableTypeInCheckedMode( | 
|  | const AbstractType& dst_type, | 
|  | const String& name_symbol) { | 
|  | return flow_graph_builder_->CheckVariableTypeInCheckedMode(dst_type, | 
|  | name_symbol); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::EnterScope( | 
|  | intptr_t kernel_offset, | 
|  | intptr_t* num_context_variables) { | 
|  | return flow_graph_builder_->EnterScope(kernel_offset, num_context_variables); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::ExitScope(intptr_t kernel_offset) { | 
|  | return flow_graph_builder_->ExitScope(kernel_offset); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::TranslateCondition(bool* negate) { | 
|  | *negate = PeekTag() == kNot; | 
|  | if (*negate) { | 
|  | SkipBytes(1);  // Skip Not tag, thus go directly to the inner expression. | 
|  | } | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  | instructions += CheckBoolean(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | const TypeArguments& StreamingFlowGraphBuilder::BuildTypeArguments() { | 
|  | ReadUInt();                               // read arguments count. | 
|  | intptr_t type_count = ReadListLength();   // read type count. | 
|  | return T.BuildTypeArguments(type_count);  // read types. | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names, | 
|  | intptr_t* argument_count, | 
|  | intptr_t* positional_count, | 
|  | bool skip_push_arguments, | 
|  | bool do_drop) { | 
|  | intptr_t dummy; | 
|  | if (argument_count == NULL) argument_count = &dummy; | 
|  | *argument_count = ReadUInt();  // read arguments count. | 
|  |  | 
|  | // List of types. | 
|  | SkipListOfDartTypes();  // read list of types. | 
|  |  | 
|  | { | 
|  | AlternativeReadingScope _(&reader_); | 
|  | if (positional_count == NULL) positional_count = &dummy; | 
|  | *positional_count = ReadListLength();  // read length of expression list | 
|  | } | 
|  | return BuildArgumentsFromActualArguments(argument_names, skip_push_arguments, | 
|  | do_drop); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments( | 
|  | Array* argument_names, | 
|  | bool skip_push_arguments, | 
|  | bool do_drop) { | 
|  | Fragment instructions; | 
|  |  | 
|  | // List of positional. | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | instructions += BuildExpression();  // read ith expression. | 
|  | if (!skip_push_arguments) instructions += PushArgument(); | 
|  | if (do_drop) instructions += Drop(); | 
|  | } | 
|  |  | 
|  | // List of named. | 
|  | list_length = ReadListLength();  // read list length. | 
|  | if (argument_names != NULL && list_length > 0) { | 
|  | *argument_names ^= Array::New(list_length, Heap::kOld); | 
|  | } | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | String& name = | 
|  | H.DartSymbolObfuscate(ReadStringReference());    // read ith name index. | 
|  | instructions += BuildExpression();                   // read ith expression. | 
|  | if (!skip_push_arguments) instructions += PushArgument(); | 
|  | if (do_drop) instructions += Drop(); | 
|  | if (argument_names != NULL) { | 
|  | argument_names->SetAt(i, name); | 
|  | } | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildInvalidExpression( | 
|  | TokenPosition* position) { | 
|  | // The frontend will take care of emitting normal errors (like | 
|  | // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special | 
|  | // situations (e.g. an invalid annotation). | 
|  | TokenPosition pos = ReadPosition(); | 
|  | if (position != NULL) *position = pos; | 
|  | const String& message = H.DartString(ReadStringReference()); | 
|  | H.ReportError(script(), pos, "%s", message.ToCString()); | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVariableGet(TokenPosition* position) { | 
|  | (position != NULL) ? * position = ReadPosition() : ReadPosition(); | 
|  | intptr_t variable_kernel_position = ReadUInt();  // read kernel position. | 
|  | ReadUInt();              // read relative variable index. | 
|  | SkipOptionalDartType();  // read promoted type. | 
|  | return LoadLocal(LookupVariable(variable_kernel_position)); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVariableGet(uint8_t payload, | 
|  | TokenPosition* position) { | 
|  | (position != NULL) ? * position = ReadPosition() : ReadPosition(); | 
|  | intptr_t variable_kernel_position = ReadUInt();  // read kernel position. | 
|  | return LoadLocal(LookupVariable(variable_kernel_position)); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVariableSet(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | intptr_t variable_kernel_position = ReadUInt();  // read kernel position. | 
|  | ReadUInt();                                 // read relative variable index. | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  |  | 
|  | if (NeedsDebugStepCheck(stack(), position)) { | 
|  | instructions = DebugStepCheck(position) + instructions; | 
|  | } | 
|  | instructions += CheckVariableTypeInCheckedMode(variable_kernel_position); | 
|  | instructions += | 
|  | StoreLocal(position, LookupVariable(variable_kernel_position)); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVariableSet(uint8_t payload, | 
|  | TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | intptr_t variable_kernel_position = ReadUInt();  // read kernel position. | 
|  | Fragment instructions = BuildExpression();       // read expression. | 
|  |  | 
|  | if (NeedsDebugStepCheck(stack(), position)) { | 
|  | instructions = DebugStepCheck(position) + instructions; | 
|  | } | 
|  | instructions += CheckVariableTypeInCheckedMode(variable_kernel_position); | 
|  | instructions += | 
|  | StoreLocal(position, LookupVariable(variable_kernel_position)); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;     // Include the tag. | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const DirectCallMetadata direct_call = | 
|  | direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset); | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | Fragment instructions = BuildExpression();  // read receiver. | 
|  |  | 
|  | LocalVariable* receiver = NULL; | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | // Duplicate receiver for CheckNull before it is consumed by PushArgument. | 
|  | receiver = MakeTemporary(); | 
|  | instructions += LoadLocal(receiver); | 
|  | } | 
|  |  | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | const String& getter_name = ReadNameAsGetterName();  // read name. | 
|  |  | 
|  | const Function* interface_target = &Function::null_function(); | 
|  | const NameIndex itarget_name = | 
|  | ReadCanonicalNameReference();  // read interface_target_reference. | 
|  | if (I->strong() && !H.IsRoot(itarget_name) && | 
|  | (H.IsGetter(itarget_name) || H.IsField(itarget_name))) { | 
|  | interface_target = &Function::ZoneHandle( | 
|  | Z, LookupMethodByMember(itarget_name, H.DartGetterName(itarget_name))); | 
|  | ASSERT(getter_name.raw() == interface_target->name()); | 
|  | } | 
|  |  | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | instructions += CheckNull(TokenPosition::kNoSource, receiver); | 
|  | } | 
|  |  | 
|  | if (!direct_call.target_.IsNull()) { | 
|  | ASSERT(FLAG_precompiled_mode); | 
|  | instructions += | 
|  | StaticCall(position, direct_call.target_, 1, Array::null_array(), | 
|  | ICData::kNoRebind, &result_type); | 
|  | } else { | 
|  | const intptr_t kTypeArgsLen = 0; | 
|  | const intptr_t kNumArgsChecked = 1; | 
|  | instructions += InstanceCall( | 
|  | position, getter_name, Token::kGET, kTypeArgsLen, 1, | 
|  | Array::null_array(), kNumArgsChecked, *interface_target, &result_type); | 
|  | } | 
|  |  | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | instructions += DropTempsPreserveTop(1);  // Drop receiver, preserve result. | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  |  | 
|  | const DirectCallMetadata direct_call = | 
|  | direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset); | 
|  |  | 
|  | Fragment instructions(NullConstant()); | 
|  | LocalVariable* variable = MakeTemporary(); | 
|  |  | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | instructions += BuildExpression();  // read receiver. | 
|  |  | 
|  | LocalVariable* receiver = NULL; | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | // Duplicate receiver for CheckNull before it is consumed by PushArgument. | 
|  | receiver = MakeTemporary(); | 
|  | instructions += LoadLocal(receiver); | 
|  | } | 
|  |  | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | const String& setter_name = ReadNameAsSetterName();  // read name. | 
|  |  | 
|  | instructions += BuildExpression();  // read value. | 
|  | instructions += StoreLocal(TokenPosition::kNoSource, variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | const Function* interface_target = &Function::null_function(); | 
|  | const NameIndex itarget_name = | 
|  | ReadCanonicalNameReference();  // read interface_target_reference. | 
|  | if (I->strong() && !H.IsRoot(itarget_name)) { | 
|  | interface_target = &Function::ZoneHandle( | 
|  | Z, LookupMethodByMember(itarget_name, H.DartSetterName(itarget_name))); | 
|  | ASSERT(setter_name.raw() == interface_target->name()); | 
|  | } | 
|  |  | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | instructions += CheckNull(position, receiver); | 
|  | } | 
|  |  | 
|  | if (!direct_call.target_.IsNull()) { | 
|  | ASSERT(FLAG_precompiled_mode); | 
|  | instructions += | 
|  | StaticCall(position, direct_call.target_, 2, Array::null_array(), | 
|  | ICData::kNoRebind, /* result_type = */ NULL); | 
|  | } else { | 
|  | const intptr_t kTypeArgsLen = 0; | 
|  | const intptr_t kNumArgsChecked = 1; | 
|  | instructions += | 
|  | InstanceCall(position, setter_name, Token::kSET, kTypeArgsLen, 2, | 
|  | Array::null_array(), kNumArgsChecked, *interface_target, | 
|  | /* result_type = */ NULL); | 
|  | } | 
|  |  | 
|  | instructions += Drop();  // Drop result of the setter invocation. | 
|  |  | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | instructions += Drop();  // Drop receiver. | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | static Function& GetNoSuchMethodOrDie(Zone* zone, const Class& klass) { | 
|  | Function& nsm_function = Function::Handle(zone); | 
|  | Class& iterate_klass = Class::Handle(zone, klass.raw()); | 
|  | while (!iterate_klass.IsNull()) { | 
|  | nsm_function = iterate_klass.LookupDynamicFunction(Symbols::NoSuchMethod()); | 
|  | if (!nsm_function.IsNull() && nsm_function.NumParameters() == 2 && | 
|  | nsm_function.NumTypeParameters() == 0) { | 
|  | break; | 
|  | } | 
|  | iterate_klass = iterate_klass.SuperClass(); | 
|  | } | 
|  | // We are guaranteed to find noSuchMethod of class Object. | 
|  | ASSERT(!nsm_function.IsNull()); | 
|  |  | 
|  | return nsm_function; | 
|  | } | 
|  |  | 
|  | // Note, that this will always mark `super` flag to true. | 
|  | Fragment StreamingFlowGraphBuilder::BuildAllocateInvocationMirrorCall( | 
|  | TokenPosition position, | 
|  | const String& name, | 
|  | intptr_t num_type_arguments, | 
|  | intptr_t num_arguments, | 
|  | const Array& argument_names, | 
|  | LocalVariable* actuals_array, | 
|  | Fragment build_rest_of_actuals) { | 
|  | Fragment instructions; | 
|  |  | 
|  | // Populate array containing the actual arguments. Just add [this] here. | 
|  | instructions += LoadLocal(actuals_array);                      // array | 
|  | instructions += IntConstant(num_type_arguments == 0 ? 0 : 1);  // index | 
|  | instructions += LoadLocal(scopes()->this_variable);            // receiver | 
|  | instructions += StoreIndexed(kArrayCid); | 
|  | instructions += Drop();  // dispose of stored value | 
|  | instructions += build_rest_of_actuals; | 
|  |  | 
|  | // First argument is receiver. | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // Push the arguments for allocating the invocation mirror: | 
|  | //   - the name. | 
|  | instructions += Constant(String::ZoneHandle(Z, name.raw())); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | //   - the arguments descriptor. | 
|  | const Array& args_descriptor = | 
|  | Array::Handle(Z, ArgumentsDescriptor::New(num_type_arguments, | 
|  | num_arguments, argument_names)); | 
|  | instructions += Constant(Array::ZoneHandle(Z, args_descriptor.raw())); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | //   - an array containing the actual arguments. | 
|  | instructions += LoadLocal(actuals_array); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | //   - [true] indicating this is a `super` NoSuchMethod. | 
|  | instructions += Constant(Bool::True()); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | const Class& mirror_class = | 
|  | Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror())); | 
|  | ASSERT(!mirror_class.IsNull()); | 
|  | const Function& allocation_function = Function::ZoneHandle( | 
|  | Z, mirror_class.LookupStaticFunction( | 
|  | Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror()))); | 
|  | ASSERT(!allocation_function.IsNull()); | 
|  | instructions += StaticCall(position, allocation_function, | 
|  | /* argument_count = */ 4, ICData::kStatic); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildSuperPropertyGet(TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;     // Include the tag. | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | Class& klass = GetSuperOrDie(); | 
|  |  | 
|  | StringIndex name_index = ReadStringReference();  // read name index. | 
|  | NameIndex library_reference = | 
|  | ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') | 
|  | ? ReadCanonicalNameReference()  // read library index. | 
|  | : NameIndex(); | 
|  | const String& getter_name = H.DartGetterName(library_reference, name_index); | 
|  | const String& method_name = H.DartMethodName(library_reference, name_index); | 
|  |  | 
|  | SkipCanonicalNameReference();  // skip target_reference. | 
|  |  | 
|  | // Search the superclass chain for the selector looking for either getter or | 
|  | // method. | 
|  | Function& function = Function::Handle(Z); | 
|  | while (!klass.IsNull()) { | 
|  | function = klass.LookupDynamicFunction(method_name); | 
|  | if (!function.IsNull()) { | 
|  | Function& target = | 
|  | Function::ZoneHandle(Z, function.ImplicitClosureFunction()); | 
|  | ASSERT(!target.IsNull()); | 
|  | // Generate inline code for allocation closure object with context | 
|  | // which captures `this`. | 
|  | return BuildImplicitClosureCreation(target); | 
|  | } | 
|  | function = klass.LookupDynamicFunction(getter_name); | 
|  | if (!function.IsNull()) break; | 
|  | klass = klass.SuperClass(); | 
|  | } | 
|  |  | 
|  | Fragment instructions; | 
|  | if (klass.IsNull()) { | 
|  | instructions += | 
|  | Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null())); | 
|  | instructions += IntConstant(1);  // array size | 
|  | instructions += CreateArray(); | 
|  | LocalVariable* actuals_array = MakeTemporary(); | 
|  |  | 
|  | Class& parent_klass = GetSuperOrDie(); | 
|  |  | 
|  | instructions += BuildAllocateInvocationMirrorCall( | 
|  | position, getter_name, | 
|  | /* num_type_arguments = */ 0, | 
|  | /* num_arguments = */ 1, | 
|  | /* argument_names = */ Object::empty_array(), actuals_array, | 
|  | /* build_rest_of_actuals = */ Fragment()); | 
|  | instructions += PushArgument();  // second argument is invocation mirror | 
|  |  | 
|  | Function& nsm_function = GetNoSuchMethodOrDie(Z, parent_klass); | 
|  | instructions += | 
|  | StaticCall(position, Function::ZoneHandle(Z, nsm_function.raw()), | 
|  | /* argument_count = */ 2, ICData::kNSMDispatch); | 
|  | instructions += DropTempsPreserveTop(1);  // Drop array | 
|  | } else { | 
|  | ASSERT(!klass.IsNull()); | 
|  | ASSERT(!function.IsNull()); | 
|  |  | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | instructions += | 
|  | StaticCall(position, Function::ZoneHandle(Z, function.raw()), | 
|  | /* argument_count = */ 1, Array::null_array(), | 
|  | ICData::kSuper, &result_type); | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildSuperPropertySet(TokenPosition* p) { | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | Class& klass = GetSuperOrDie(); | 
|  |  | 
|  | const String& setter_name = ReadNameAsSetterName();  // read name. | 
|  |  | 
|  | Function& function = FindMatchingFunctionAnyArgs(klass, setter_name); | 
|  |  | 
|  | Fragment instructions(NullConstant()); | 
|  | LocalVariable* value = MakeTemporary();  // this holds RHS value | 
|  |  | 
|  | if (function.IsNull()) { | 
|  | instructions += | 
|  | Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null())); | 
|  | instructions += IntConstant(2);  // array size | 
|  | instructions += CreateArray(); | 
|  | LocalVariable* actuals_array = MakeTemporary(); | 
|  |  | 
|  | Fragment build_rest_of_actuals; | 
|  | build_rest_of_actuals += LoadLocal(actuals_array);  // array | 
|  | build_rest_of_actuals += IntConstant(1);            // index | 
|  | build_rest_of_actuals += BuildExpression();         // value. | 
|  | build_rest_of_actuals += StoreLocal(position, value); | 
|  | build_rest_of_actuals += StoreIndexed(kArrayCid); | 
|  | build_rest_of_actuals += Drop();  // dispose of stored value | 
|  |  | 
|  | instructions += BuildAllocateInvocationMirrorCall( | 
|  | position, setter_name, /* num_type_arguments = */ 0, | 
|  | /* num_arguments = */ 2, | 
|  | /* argument_names = */ Object::empty_array(), actuals_array, | 
|  | build_rest_of_actuals); | 
|  | instructions += PushArgument();  // second argument - invocation mirror | 
|  |  | 
|  | SkipCanonicalNameReference();  // skip target_reference. | 
|  |  | 
|  | Function& nsm_function = GetNoSuchMethodOrDie(Z, klass); | 
|  | instructions += | 
|  | StaticCall(position, Function::ZoneHandle(Z, nsm_function.raw()), | 
|  | /* argument_count = */ 2, ICData::kNSMDispatch); | 
|  | instructions += Drop();  // Drop result of NoSuchMethod invocation | 
|  | instructions += Drop();  // Drop array | 
|  | } else { | 
|  | // receiver | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | instructions += BuildExpression();  // read value. | 
|  | instructions += StoreLocal(position, value); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | SkipCanonicalNameReference();  // skip target_reference. | 
|  |  | 
|  | instructions += | 
|  | StaticCall(position, Function::ZoneHandle(Z, function.raw()), | 
|  | /* argument_count = */ 2, ICData::kSuper); | 
|  | instructions += Drop();  // Drop result of the setter invocation. | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;     // Include the tag. | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | const Tag receiver_tag = PeekTag();         // peek tag for receiver. | 
|  | Fragment instructions = BuildExpression();  // read receiver. | 
|  | const NameIndex kernel_name = | 
|  | ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | Function& target = Function::ZoneHandle(Z); | 
|  | if (H.IsProcedure(kernel_name)) { | 
|  | if (H.IsGetter(kernel_name)) { | 
|  | target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name)); | 
|  | } else if (receiver_tag == kThisExpression) { | 
|  | // Undo stack change for the BuildExpression. | 
|  | Pop(); | 
|  |  | 
|  | target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name)); | 
|  | target = target.ImplicitClosureFunction(); | 
|  | ASSERT(!target.IsNull()); | 
|  |  | 
|  | // Generate inline code for allocating closure object with context which | 
|  | // captures `this`. | 
|  | return BuildImplicitClosureCreation(target); | 
|  | } else { | 
|  | // Need to create implicit closure (tear-off), receiver != this. | 
|  | // Ensure method extractor exists and call it directly. | 
|  | const Function& target_method = Function::ZoneHandle( | 
|  | Z, LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name))); | 
|  | const String& getter_name = H.DartGetterName(kernel_name); | 
|  | target = target_method.GetMethodExtractor(getter_name); | 
|  | } | 
|  | } else { | 
|  | ASSERT(H.IsField(kernel_name)); | 
|  | const String& getter_name = H.DartGetterName(kernel_name); | 
|  | target = LookupMethodByMember(kernel_name, getter_name); | 
|  | ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction()); | 
|  | } | 
|  |  | 
|  | instructions += PushArgument(); | 
|  | // Static calls are marked as "no-rebind", which is currently safe because | 
|  | // DirectPropertyGet are only used in enums (index in toString) and enums | 
|  | // can't change their structure during hot reload. | 
|  | // If there are other sources of DirectPropertyGet in the future, this code | 
|  | // have to be adjusted. | 
|  | return instructions + StaticCall(position, target, 1, Array::null_array(), | 
|  | ICData::kNoRebind, &result_type); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) { | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | Fragment instructions(NullConstant()); | 
|  | LocalVariable* value = MakeTemporary(); | 
|  |  | 
|  | instructions += BuildExpression();  // read receiver. | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | const NameIndex target_reference = | 
|  | ReadCanonicalNameReference();  // read target_reference. | 
|  | const String& method_name = H.DartSetterName(target_reference); | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, LookupMethodByMember(target_reference, method_name)); | 
|  | ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction()); | 
|  |  | 
|  | instructions += BuildExpression();  // read value. | 
|  | instructions += StoreLocal(TokenPosition::kNoSource, value); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // Static calls are marked as "no-rebind", which is currently safe because | 
|  | // DirectPropertyGet are only used in enums (index in toString) and enums | 
|  | // can't change their structure during hot reload. | 
|  | // If there are other sources of DirectPropertyGet in the future, this code | 
|  | // have to be adjusted. | 
|  | instructions += | 
|  | StaticCall(position, target, 2, Array::null_array(), ICData::kNoRebind, | 
|  | /* result_type = */ NULL); | 
|  |  | 
|  | return instructions + Drop(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) { | 
|  | ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull()); | 
|  | const intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  |  | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | NameIndex target = ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | if (H.IsField(target)) { | 
|  | const Field& field = | 
|  | Field::ZoneHandle(Z, H.LookupFieldByKernelField(target)); | 
|  | if (field.is_const()) { | 
|  | return Constant(constant_evaluator_.EvaluateExpression(offset)); | 
|  | } else { | 
|  | const Class& owner = Class::Handle(Z, field.Owner()); | 
|  | const String& getter_name = H.DartGetterName(target); | 
|  | const Function& getter = | 
|  | Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name)); | 
|  | if (getter.IsNull() || !field.has_initializer()) { | 
|  | Fragment instructions = Constant(field); | 
|  | return instructions + LoadStaticField(); | 
|  | } else { | 
|  | return StaticCall(position, getter, 0, Array::null_array(), | 
|  | ICData::kStatic, &result_type); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | const Function& function = | 
|  | Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); | 
|  |  | 
|  | if (H.IsGetter(target)) { | 
|  | return StaticCall(position, function, 0, Array::null_array(), | 
|  | ICData::kStatic, &result_type); | 
|  | } else if (H.IsMethod(target)) { | 
|  | return Constant(constant_evaluator_.EvaluateExpression(offset)); | 
|  | } else { | 
|  | UNIMPLEMENTED(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | NameIndex target = ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | if (H.IsField(target)) { | 
|  | const Field& field = | 
|  | Field::ZoneHandle(Z, H.LookupFieldByKernelField(target)); | 
|  | const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type()); | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  | if (NeedsDebugStepCheck(stack(), position)) { | 
|  | instructions = DebugStepCheck(position) + instructions; | 
|  | } | 
|  | instructions += CheckAssignableInCheckedMode( | 
|  | dst_type, String::ZoneHandle(Z, field.name())); | 
|  | LocalVariable* variable = MakeTemporary(); | 
|  | instructions += LoadLocal(variable); | 
|  | return instructions + StoreStaticField(position, field); | 
|  | } else { | 
|  | ASSERT(H.IsProcedure(target)); | 
|  |  | 
|  | // Evaluate the expression on the right hand side. | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  | LocalVariable* variable = MakeTemporary(); | 
|  |  | 
|  | // Prepare argument. | 
|  | instructions += LoadLocal(variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // Invoke the setter function. | 
|  | const Function& function = | 
|  | Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target)); | 
|  | instructions += StaticCall(position, function, 1, ICData::kStatic); | 
|  |  | 
|  | // Drop the unused result & leave the stored value on the stack. | 
|  | return instructions + Drop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool IsNumberLiteral(Tag tag) { | 
|  | return tag == kNegativeIntLiteral || tag == kPositiveIntLiteral || | 
|  | tag == kSpecializedIntLiteral || tag == kDoubleLiteral; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;     // Include the tag. | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const DirectCallMetadata direct_call = | 
|  | direct_call_metadata_helper_.GetDirectTargetForMethodInvocation(offset); | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | const Tag receiver_tag = PeekTag();  // peek tag for receiver. | 
|  | if (IsNumberLiteral(receiver_tag) && | 
|  | (!optimizing() || constant_evaluator_.IsCached(offset))) { | 
|  | const intptr_t before_branch_offset = ReaderOffset(); | 
|  |  | 
|  | SkipExpression();  // read receiver (it's just a number literal). | 
|  |  | 
|  | const String& name = ReadNameAsMethodName();  // read name. | 
|  | const Token::Kind token_kind = | 
|  | MethodTokenRecognizer::RecognizeTokenKind(name); | 
|  | intptr_t argument_count = PeekArgumentsCount() + 1; | 
|  |  | 
|  | if ((argument_count == 1) && (token_kind == Token::kNEGATE)) { | 
|  | const Object& result = constant_evaluator_.EvaluateExpressionSafe(offset); | 
|  | if (!result.IsError()) { | 
|  | SkipArguments();               // read arguments. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return Constant(result); | 
|  | } | 
|  | } else if ((argument_count == 2) && | 
|  | Token::IsBinaryArithmeticOperator(token_kind) && | 
|  | IsNumberLiteral(PeekArgumentsFirstPositionalTag())) { | 
|  | const Object& result = constant_evaluator_.EvaluateExpressionSafe(offset); | 
|  | if (!result.IsError()) { | 
|  | SkipArguments();               // read arguments. | 
|  | SkipCanonicalNameReference();  // read interface_target_reference. | 
|  | return Constant(result); | 
|  | } | 
|  | } | 
|  |  | 
|  | SetOffset(before_branch_offset); | 
|  | } | 
|  |  | 
|  | Fragment instructions; | 
|  |  | 
|  | intptr_t type_args_len = 0; | 
|  | LocalVariable* type_arguments_temp = NULL; | 
|  | if (I->reify_generic_functions()) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SkipExpression();                         // skip receiver | 
|  | SkipName();                               // skip method name | 
|  | ReadUInt();                               // read argument count. | 
|  | intptr_t list_length = ReadListLength();  // read types list length. | 
|  | if (list_length > 0) { | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(list_length);  // read types. | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | // Don't yet push type arguments if we need to check receiver for null. | 
|  | // In this case receiver will be duplicated so instead of pushing | 
|  | // type arguments here we need to push it between receiver_temp | 
|  | // and actual receiver. See the code below. | 
|  | type_arguments_temp = MakeTemporary(); | 
|  | } else { | 
|  | instructions += PushArgument(); | 
|  | } | 
|  | } | 
|  | type_args_len = list_length; | 
|  | } | 
|  |  | 
|  | instructions += BuildExpression();  // read receiver. | 
|  |  | 
|  | const String& name = ReadNameAsMethodName();  // read name. | 
|  | const Token::Kind token_kind = | 
|  | MethodTokenRecognizer::RecognizeTokenKind(name); | 
|  |  | 
|  | // Detect comparison with null. | 
|  | if ((token_kind == Token::kEQ || token_kind == Token::kNE) && | 
|  | PeekArgumentsCount() == 1 && | 
|  | (receiver_tag == kNullLiteral || | 
|  | PeekArgumentsFirstPositionalTag() == kNullLiteral)) { | 
|  | ASSERT(type_args_len == 0); | 
|  | // "==" or "!=" with null on either side. | 
|  | instructions += BuildArguments(NULL /* named */, NULL /* arg count */, | 
|  | NULL /* positional arg count */, | 
|  | true);  // read arguments. | 
|  | SkipCanonicalNameReference();          // read interface_target_reference. | 
|  | Token::Kind strict_cmp_kind = | 
|  | token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT; | 
|  | return instructions + | 
|  | StrictCompare(strict_cmp_kind, /*number_check = */ true); | 
|  | } | 
|  |  | 
|  | LocalVariable* receiver_temp = NULL; | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | // Duplicate receiver for CheckNull before it is consumed by PushArgument. | 
|  | receiver_temp = MakeTemporary(); | 
|  | if (type_arguments_temp != NULL) { | 
|  | // If call has type arguments then push them before pushing the receiver. | 
|  | // The stack will contain: | 
|  | // | 
|  | //   [type_arguments_temp][receiver_temp][type_arguments][receiver] ... | 
|  | // | 
|  | instructions += LoadLocal(type_arguments_temp); | 
|  | instructions += PushArgument(); | 
|  | } | 
|  | instructions += LoadLocal(receiver_temp); | 
|  | } | 
|  |  | 
|  | instructions += PushArgument();  // push receiver as argument. | 
|  |  | 
|  | intptr_t argument_count; | 
|  | intptr_t positional_argument_count; | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | instructions += | 
|  | BuildArguments(&argument_names, &argument_count, | 
|  | &positional_argument_count);  // read arguments. | 
|  | ++argument_count;                                // include receiver | 
|  |  | 
|  | intptr_t checked_argument_count = 1; | 
|  | // If we have a special operation (e.g. +/-/==) we mark both arguments as | 
|  | // to be checked. | 
|  | if (token_kind != Token::kILLEGAL) { | 
|  | ASSERT(argument_count <= 2); | 
|  | checked_argument_count = argument_count; | 
|  | } | 
|  |  | 
|  | const Function* interface_target = &Function::null_function(); | 
|  | const NameIndex itarget_name = | 
|  | ReadCanonicalNameReference();  // read interface_target_reference. | 
|  | if (I->strong() && !H.IsRoot(itarget_name) && !H.IsField(itarget_name)) { | 
|  | interface_target = &Function::ZoneHandle( | 
|  | Z, | 
|  | LookupMethodByMember(itarget_name, H.DartProcedureName(itarget_name))); | 
|  | ASSERT((name.raw() == interface_target->name()) || | 
|  | (interface_target->IsGetterFunction() && | 
|  | Field::GetterSymbol(name) == interface_target->name())); | 
|  | } | 
|  |  | 
|  | if (direct_call.check_receiver_for_null_) { | 
|  | instructions += CheckNull(position, receiver_temp); | 
|  | } | 
|  |  | 
|  | if (!direct_call.target_.IsNull()) { | 
|  | ASSERT(FLAG_precompiled_mode); | 
|  | instructions += StaticCall(position, direct_call.target_, argument_count, | 
|  | argument_names, ICData::kNoRebind, &result_type, | 
|  | type_args_len); | 
|  | } else { | 
|  | instructions += | 
|  | InstanceCall(position, name, token_kind, type_args_len, argument_count, | 
|  | argument_names, checked_argument_count, *interface_target, | 
|  | &result_type); | 
|  | } | 
|  |  | 
|  | // Drop temporaries preserving result on the top of the stack. | 
|  | ASSERT((receiver_temp != NULL) || (type_arguments_temp == NULL)); | 
|  | if (receiver_temp != NULL) { | 
|  | const intptr_t num_temps = | 
|  | (receiver_temp != NULL ? 1 : 0) + (type_arguments_temp != NULL ? 1 : 0); | 
|  | instructions += DropTempsPreserveTop(num_temps); | 
|  | } | 
|  |  | 
|  | // Later optimization passes assume that result of a x.[]=(...) call is not | 
|  | // used. We must guarantee this invariant because violation will lead to an | 
|  | // illegal IL once we replace x.[]=(...) with a sequence that does not | 
|  | // actually produce any value. See http://dartbug.com/29135 for more details. | 
|  | if (name.raw() == Symbols::AssignIndexToken().raw()) { | 
|  | instructions += Drop(); | 
|  | instructions += NullConstant(); | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation( | 
|  | TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  | TokenPosition position = ReadPosition();     // read offset. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | Tag receiver_tag = PeekTag();  // peek tag for receiver. | 
|  |  | 
|  | Fragment instructions; | 
|  | intptr_t type_args_len = 0; | 
|  | if (I->reify_generic_functions()) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SkipExpression();                         // skip receiver | 
|  | ReadCanonicalNameReference();             // skip target reference | 
|  | ReadUInt();                               // read argument count. | 
|  | intptr_t list_length = ReadListLength();  // read types list length. | 
|  | if (list_length > 0) { | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(list_length);  // read types. | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | instructions += PushArgument(); | 
|  | } | 
|  | type_args_len = list_length; | 
|  | } | 
|  |  | 
|  | instructions += BuildExpression();  // read receiver. | 
|  |  | 
|  | NameIndex kernel_name = | 
|  | ReadCanonicalNameReference();  // read target_reference. | 
|  | const String& method_name = H.DartProcedureName(kernel_name); | 
|  | const Token::Kind token_kind = | 
|  | MethodTokenRecognizer::RecognizeTokenKind(method_name); | 
|  |  | 
|  | // Detect comparison with null. | 
|  | if ((token_kind == Token::kEQ || token_kind == Token::kNE) && | 
|  | PeekArgumentsCount() == 1 && | 
|  | (receiver_tag == kNullLiteral || | 
|  | PeekArgumentsFirstPositionalTag() == kNullLiteral)) { | 
|  | ASSERT(type_args_len == 0); | 
|  | // "==" or "!=" with null on either side. | 
|  | instructions += BuildArguments(NULL /* names */, NULL /* arg count */, | 
|  | NULL /* positional arg count */, | 
|  | true);  // read arguments. | 
|  | Token::Kind strict_cmp_kind = | 
|  | token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT; | 
|  | return instructions + | 
|  | StrictCompare(strict_cmp_kind, /*number_check = */ true); | 
|  | } | 
|  |  | 
|  | instructions += PushArgument();  // push receiver as argument. | 
|  |  | 
|  | const Function& target = | 
|  | Function::ZoneHandle(Z, LookupMethodByMember(kernel_name, method_name)); | 
|  |  | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | intptr_t argument_count, positional_argument_count; | 
|  | instructions += | 
|  | BuildArguments(&argument_names, &argument_count, | 
|  | &positional_argument_count);  // read arguments. | 
|  | ++argument_count; | 
|  |  | 
|  | return instructions + StaticCall(position, target, argument_count, | 
|  | argument_names, ICData::kNoRebind, | 
|  | &result_type, type_args_len); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation( | 
|  | TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;     // Include the tag. | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | intptr_t type_args_len = 0; | 
|  | if (I->reify_generic_functions()) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SkipName();                        // skip method name | 
|  | ReadUInt();                        // read argument count. | 
|  | type_args_len = ReadListLength();  // read types list length. | 
|  | } | 
|  |  | 
|  | Class& klass = GetSuperOrDie(); | 
|  |  | 
|  | // Search the superclass chain for the selector. | 
|  | const String& method_name = ReadNameAsMethodName();  // read name. | 
|  |  | 
|  | // Figure out selector signature. | 
|  | intptr_t argument_count; | 
|  | Array& argument_names = Array::Handle(Z); | 
|  | { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | argument_count = ReadUInt(); | 
|  | SkipListOfDartTypes(); | 
|  |  | 
|  | SkipListOfExpressions(); | 
|  | intptr_t named_list_length = ReadListLength(); | 
|  | argument_names ^= Array::New(named_list_length, H.allocation_space()); | 
|  | for (intptr_t i = 0; i < named_list_length; i++) { | 
|  | const String& arg_name = H.DartSymbolObfuscate(ReadStringReference()); | 
|  | argument_names.SetAt(i, arg_name); | 
|  | SkipExpression(); | 
|  | } | 
|  | } | 
|  |  | 
|  | Function& function = FindMatchingFunction( | 
|  | klass, method_name, type_args_len, | 
|  | argument_count + 1 /* account for 'this' */, argument_names); | 
|  |  | 
|  | if (function.IsNull()) { | 
|  | ReadUInt();  // argument count | 
|  | intptr_t type_list_length = ReadListLength(); | 
|  |  | 
|  | Fragment instructions; | 
|  | instructions += | 
|  | Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null())); | 
|  | instructions += IntConstant(argument_count + 1 /* this */ + | 
|  | (type_list_length == 0 ? 0 : 1));  // array size | 
|  | instructions += CreateArray(); | 
|  | LocalVariable* actuals_array = MakeTemporary(); | 
|  |  | 
|  | // Call allocationInvocationMirror to get instance of Invocation. | 
|  | Fragment build_rest_of_actuals; | 
|  | intptr_t actuals_array_index = 0; | 
|  | if (type_list_length > 0) { | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(type_list_length); | 
|  | build_rest_of_actuals += LoadLocal(actuals_array); | 
|  | build_rest_of_actuals += IntConstant(actuals_array_index); | 
|  | build_rest_of_actuals += | 
|  | TranslateInstantiatedTypeArguments(type_arguments); | 
|  | build_rest_of_actuals += StoreIndexed(kArrayCid); | 
|  | build_rest_of_actuals += Drop();  // dispose of stored value | 
|  | ++actuals_array_index; | 
|  | } | 
|  |  | 
|  | ++actuals_array_index;  // account for 'this'. | 
|  | // Read arguments | 
|  | intptr_t list_length = ReadListLength(); | 
|  | intptr_t i = 0; | 
|  | while (i < list_length) { | 
|  | build_rest_of_actuals += LoadLocal(actuals_array);              // array | 
|  | build_rest_of_actuals += IntConstant(actuals_array_index + i);  // index | 
|  | build_rest_of_actuals += BuildExpression();                     // value. | 
|  | build_rest_of_actuals += StoreIndexed(kArrayCid); | 
|  | build_rest_of_actuals += Drop();  // dispose of stored value | 
|  | ++i; | 
|  | } | 
|  | // Read named arguments | 
|  | intptr_t named_list_length = ReadListLength(); | 
|  | if (named_list_length > 0) { | 
|  | ASSERT(argument_count == list_length + named_list_length); | 
|  | while ((i - list_length) < named_list_length) { | 
|  | SkipStringReference(); | 
|  | build_rest_of_actuals += LoadLocal(actuals_array);              // array | 
|  | build_rest_of_actuals += IntConstant(i + actuals_array_index);  // index | 
|  | build_rest_of_actuals += BuildExpression();  // value. | 
|  | build_rest_of_actuals += StoreIndexed(kArrayCid); | 
|  | build_rest_of_actuals += Drop();  // dispose of stored value | 
|  | ++i; | 
|  | } | 
|  | } | 
|  | instructions += BuildAllocateInvocationMirrorCall( | 
|  | position, method_name, type_list_length, | 
|  | /* num_arguments = */ argument_count + 1, argument_names, actuals_array, | 
|  | build_rest_of_actuals); | 
|  | instructions += PushArgument();  // second argument - invocation mirror | 
|  |  | 
|  | SkipCanonicalNameReference();  //  skip target_reference. | 
|  |  | 
|  | Function& nsm_function = GetNoSuchMethodOrDie(Z, klass); | 
|  | instructions += StaticCall(TokenPosition::kNoSource, | 
|  | Function::ZoneHandle(Z, nsm_function.raw()), | 
|  | /* argument_count = */ 2, ICData::kNSMDispatch); | 
|  | instructions += DropTempsPreserveTop(1);  // Drop actuals_array temp. | 
|  | return instructions; | 
|  | } else { | 
|  | Fragment instructions; | 
|  |  | 
|  | if (I->reify_generic_functions()) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | ReadUInt();                               // read argument count. | 
|  | intptr_t list_length = ReadListLength();  // read types list length. | 
|  | if (list_length > 0) { | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(list_length);  // read types. | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | instructions += PushArgument(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // receiver | 
|  | instructions += LoadLocal(scopes()->this_variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | intptr_t argument_count; | 
|  | instructions += BuildArguments( | 
|  | &argument_names, &argument_count, | 
|  | /* positional_argument_count = */ NULL);  // read arguments. | 
|  | ++argument_count;                             // include receiver | 
|  | SkipCanonicalNameReference();                 // interfaceTargetReference | 
|  | return instructions + | 
|  | StaticCall(position, Function::ZoneHandle(Z, function.raw()), | 
|  | argument_count, argument_names, ICData::kSuper, | 
|  | &result_type, type_args_len); | 
|  | } | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const, | 
|  | TokenPosition* p) { | 
|  | const intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  | TokenPosition position = ReadPosition();     // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const InferredTypeMetadata result_type = | 
|  | inferred_type_metadata_helper_.GetInferredType(offset); | 
|  |  | 
|  | NameIndex procedure_reference = | 
|  | ReadCanonicalNameReference();  // read procedure reference. | 
|  | intptr_t argument_count = PeekArgumentsCount(); | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, H.LookupStaticMethodByKernelProcedure(procedure_reference)); | 
|  | const Class& klass = Class::ZoneHandle(Z, target.Owner()); | 
|  | if (target.IsGenerativeConstructor() || target.IsFactory()) { | 
|  | // The VM requires a TypeArguments object as first parameter for | 
|  | // every factory constructor. | 
|  | ++argument_count; | 
|  | } | 
|  |  | 
|  | Fragment instructions; | 
|  | LocalVariable* instance_variable = NULL; | 
|  |  | 
|  | bool special_case_identical = klass.IsTopLevel() && | 
|  | (klass.library() == Library::CoreLibrary()) && | 
|  | (target.name() == Symbols::Identical().raw()); | 
|  |  | 
|  | // If we cross the Kernel -> VM core library boundary, a [StaticInvocation] | 
|  | // can appear, but the thing we're calling is not a static method, but a | 
|  | // factory constructor. | 
|  | // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the | 
|  | // forwarded constructor. | 
|  | // In that case we'll make an instance and pass it as first argument. | 
|  | // | 
|  | // TODO(27590): Get rid of this after we're using core libraries compiled | 
|  | // into Kernel. | 
|  | intptr_t type_args_len = 0; | 
|  | if (target.IsGenerativeConstructor()) { | 
|  | if (klass.NumTypeArguments() > 0) { | 
|  | const TypeArguments& type_arguments = | 
|  | PeekArgumentsInstantiatedType(klass); | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | instructions += PushArgument(); | 
|  | instructions += AllocateObject(position, klass, 1); | 
|  | } else { | 
|  | instructions += AllocateObject(position, klass, 0); | 
|  | } | 
|  |  | 
|  | instance_variable = MakeTemporary(); | 
|  |  | 
|  | instructions += LoadLocal(instance_variable); | 
|  | instructions += PushArgument(); | 
|  | } else if (target.IsFactory()) { | 
|  | // The VM requires currently a TypeArguments object as first parameter for | 
|  | // every factory constructor :-/ ! | 
|  | // | 
|  | // TODO(27590): Get rid of this after we're using core libraries compiled | 
|  | // into Kernel. | 
|  | const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass); | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | instructions += PushArgument(); | 
|  | } else if (!special_case_identical && I->reify_generic_functions()) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | ReadUInt();                               // read argument count. | 
|  | intptr_t list_length = ReadListLength();  // read types list length. | 
|  | if (list_length > 0) { | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(list_length);  // read types. | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | instructions += PushArgument(); | 
|  | } | 
|  | type_args_len = list_length; | 
|  | } | 
|  |  | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | instructions += BuildArguments(&argument_names, NULL /* arg count */, | 
|  | NULL /* positional arg count */, | 
|  | special_case_identical);  // read arguments. | 
|  | ASSERT(target.AreValidArguments(type_args_len, argument_count, argument_names, | 
|  | NULL)); | 
|  |  | 
|  | // Special case identical(x, y) call. | 
|  | // TODO(27590) consider moving this into the inliner and force inline it | 
|  | // there. | 
|  | if (special_case_identical) { | 
|  | ASSERT(argument_count == 2); | 
|  | instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true); | 
|  | } else { | 
|  | instructions += StaticCall(position, target, argument_count, argument_names, | 
|  | ICData::kStatic, &result_type, type_args_len); | 
|  | if (target.IsGenerativeConstructor()) { | 
|  | // Drop the result of the constructor call and leave [instance_variable] | 
|  | // on top-of-stack. | 
|  | instructions += Drop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation( | 
|  | bool is_const, | 
|  | TokenPosition* p) { | 
|  | if (is_const) { | 
|  | intptr_t offset = ReaderOffset() - 1;                 // Include the tag. | 
|  | (p != NULL) ? * p = ReadPosition() : ReadPosition();  // read position. | 
|  |  | 
|  | SetOffset(offset); | 
|  | SkipExpression();  // read past this ConstructorInvocation. | 
|  | return Constant(constant_evaluator_.EvaluateConstructorInvocation(offset)); | 
|  | } | 
|  |  | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | NameIndex kernel_name = | 
|  | ReadCanonicalNameReference();  // read target_reference. | 
|  |  | 
|  | Class& klass = Class::ZoneHandle( | 
|  | Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name))); | 
|  |  | 
|  | Fragment instructions; | 
|  |  | 
|  | // Check for malbounded-ness of type. | 
|  | if (I->type_checks()) { | 
|  | intptr_t offset = ReaderOffset(); | 
|  |  | 
|  | const TypeArguments& type_arguments = BuildTypeArguments(); | 
|  |  | 
|  | AbstractType& type = AbstractType::Handle( | 
|  | Z, Type::New(klass, type_arguments, TokenPosition::kNoSource)); | 
|  | type = ClassFinalizer::FinalizeType(klass, type); | 
|  |  | 
|  | if (type.IsMalbounded()) { | 
|  | // Evaluate expressions for correctness. | 
|  | instructions += | 
|  | BuildArgumentsFromActualArguments(NULL, false, /*do_drop*/ true); | 
|  |  | 
|  | // Throw an error & keep the [Value] on the stack. | 
|  | instructions += ThrowTypeError(); | 
|  |  | 
|  | // Bail out early. | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | SetOffset(offset); | 
|  | } | 
|  |  | 
|  | if (klass.NumTypeArguments() > 0) { | 
|  | if (!klass.IsGeneric()) { | 
|  | Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw()); | 
|  |  | 
|  | // TODO(27590): Can we move this code into [ReceiverType]? | 
|  | type ^= ClassFinalizer::FinalizeType(*active_class()->klass, type, | 
|  | ClassFinalizer::kFinalize); | 
|  | ASSERT(!type.IsMalformedOrMalbounded()); | 
|  |  | 
|  | TypeArguments& canonicalized_type_arguments = | 
|  | TypeArguments::ZoneHandle(Z, type.arguments()); | 
|  | canonicalized_type_arguments = | 
|  | canonicalized_type_arguments.Canonicalize(); | 
|  | instructions += Constant(canonicalized_type_arguments); | 
|  | } else { | 
|  | const TypeArguments& type_arguments = | 
|  | PeekArgumentsInstantiatedType(klass); | 
|  | instructions += TranslateInstantiatedTypeArguments(type_arguments); | 
|  | } | 
|  |  | 
|  | instructions += PushArgument(); | 
|  | instructions += AllocateObject(position, klass, 1); | 
|  | } else { | 
|  | instructions += AllocateObject(position, klass, 0); | 
|  | } | 
|  | LocalVariable* variable = MakeTemporary(); | 
|  |  | 
|  | instructions += LoadLocal(variable); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | Array& argument_names = Array::ZoneHandle(Z); | 
|  | intptr_t argument_count; | 
|  | instructions += BuildArguments( | 
|  | &argument_names, &argument_count, | 
|  | /* positional_argument_count = */ NULL);  // read arguments. | 
|  |  | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, H.LookupConstructorByKernelConstructor(klass, kernel_name)); | 
|  | ++argument_count; | 
|  | instructions += StaticCall(position, target, argument_count, argument_names, | 
|  | ICData::kStatic, /* result_type = */ NULL); | 
|  | return instructions + Drop(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildNot(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  | instructions += CheckBoolean(); | 
|  | instructions += BooleanNegate(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildLogicalExpression( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | bool negate; | 
|  | Fragment instructions = TranslateCondition(&negate);  // read left. | 
|  |  | 
|  | TargetEntryInstr* right_entry; | 
|  | TargetEntryInstr* constant_entry; | 
|  | LogicalOperator op = static_cast<LogicalOperator>(ReadByte()); | 
|  |  | 
|  | if (op == kAnd) { | 
|  | instructions += BranchIfTrue(&right_entry, &constant_entry, negate); | 
|  | } else { | 
|  | instructions += BranchIfTrue(&constant_entry, &right_entry, negate); | 
|  | } | 
|  |  | 
|  | Value* top = stack(); | 
|  | Fragment right_fragment(right_entry); | 
|  | right_fragment += TranslateCondition(&negate);  // read right. | 
|  |  | 
|  | right_fragment += Constant(Bool::True()); | 
|  | right_fragment += | 
|  | StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT); | 
|  | right_fragment += StoreLocal(TokenPosition::kNoSource, | 
|  | parsed_function()->expression_temp_var()); | 
|  | right_fragment += Drop(); | 
|  |  | 
|  | ASSERT(top == stack()); | 
|  | Fragment constant_fragment(constant_entry); | 
|  | constant_fragment += Constant(Bool::Get(op == kOr)); | 
|  | constant_fragment += StoreLocal(TokenPosition::kNoSource, | 
|  | parsed_function()->expression_temp_var()); | 
|  | constant_fragment += Drop(); | 
|  |  | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | right_fragment += Goto(join); | 
|  | constant_fragment += Goto(join); | 
|  |  | 
|  | return Fragment(instructions.entry, join) + | 
|  | LoadLocal(parsed_function()->expression_temp_var()); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildConditionalExpression( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | bool negate; | 
|  | Fragment instructions = TranslateCondition(&negate);  // read condition. | 
|  |  | 
|  | TargetEntryInstr* then_entry; | 
|  | TargetEntryInstr* otherwise_entry; | 
|  | instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); | 
|  |  | 
|  | Value* top = stack(); | 
|  | Fragment then_fragment(then_entry); | 
|  | then_fragment += BuildExpression();  // read then. | 
|  | then_fragment += StoreLocal(TokenPosition::kNoSource, | 
|  | parsed_function()->expression_temp_var()); | 
|  | then_fragment += Drop(); | 
|  | ASSERT(stack() == top); | 
|  |  | 
|  | Fragment otherwise_fragment(otherwise_entry); | 
|  | otherwise_fragment += BuildExpression();  // read otherwise. | 
|  | otherwise_fragment += StoreLocal(TokenPosition::kNoSource, | 
|  | parsed_function()->expression_temp_var()); | 
|  | otherwise_fragment += Drop(); | 
|  | ASSERT(stack() == top); | 
|  |  | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | then_fragment += Goto(join); | 
|  | otherwise_fragment += Goto(join); | 
|  |  | 
|  | SkipOptionalDartType();  // read unused static type. | 
|  |  | 
|  | return Fragment(instructions.entry, join) + | 
|  | LoadLocal(parsed_function()->expression_temp_var()); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStringConcatenation(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | intptr_t length = ReadListLength();  // read list length. | 
|  | // Note: there will be "length" expressions. | 
|  |  | 
|  | Fragment instructions; | 
|  | if (length == 1) { | 
|  | instructions += BuildExpression();  // read expression. | 
|  | instructions += StringInterpolateSingle(position); | 
|  | } else { | 
|  | // The type arguments for CreateArray. | 
|  | instructions += Constant(TypeArguments::ZoneHandle(Z)); | 
|  | instructions += IntConstant(length); | 
|  | instructions += CreateArray(); | 
|  | LocalVariable* array = MakeTemporary(); | 
|  |  | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | instructions += LoadLocal(array); | 
|  | instructions += IntConstant(i); | 
|  | instructions += BuildExpression();  // read ith expression. | 
|  | instructions += StoreIndexed(kArrayCid); | 
|  | instructions += Drop(); | 
|  | } | 
|  |  | 
|  | instructions += StringInterpolate(position); | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | Fragment instructions = BuildExpression();  // read operand. | 
|  |  | 
|  | const AbstractType& type = T.BuildType();  // read type. | 
|  |  | 
|  | // The VM does not like an instanceOf call with a dynamic type. We need to | 
|  | // special case this situation. | 
|  | const Type& object_type = Type::Handle(Z, Type::ObjectType()); | 
|  |  | 
|  | if (type.IsMalformed()) { | 
|  | instructions += Drop(); | 
|  | instructions += ThrowTypeError(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | if (type.IsInstantiated() && | 
|  | object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { | 
|  | // Evaluate the expression on the left but ignore it's result. | 
|  | instructions += Drop(); | 
|  |  | 
|  | // Let condition be always true. | 
|  | instructions += Constant(Bool::True()); | 
|  | } else { | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | // See if simple instanceOf is applicable. | 
|  | if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) { | 
|  | instructions += Constant(type); | 
|  | instructions += PushArgument();  // Type. | 
|  | instructions += InstanceCall( | 
|  | position, Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()), | 
|  | Token::kIS, 2, 2);  // 2 checked arguments. | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | if (!type.IsInstantiated(kCurrentClass)) { | 
|  | instructions += LoadInstantiatorTypeArguments(); | 
|  | } else { | 
|  | instructions += NullConstant(); | 
|  | } | 
|  | instructions += PushArgument();  // Instantiator type arguments. | 
|  |  | 
|  | if (!type.IsInstantiated(kFunctions)) { | 
|  | instructions += LoadFunctionTypeArguments(); | 
|  | } else { | 
|  | instructions += NullConstant(); | 
|  | } | 
|  | instructions += PushArgument();  // Function type arguments. | 
|  |  | 
|  | instructions += Constant(type); | 
|  | instructions += PushArgument();  // Type. | 
|  |  | 
|  | instructions += InstanceCall( | 
|  | position, Library::PrivateCoreLibName(Symbols::_instanceOf()), | 
|  | Token::kIS, 4); | 
|  | } | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildAsExpression(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | uint8_t flags = ReadFlags();  // read flags. | 
|  | const bool is_type_error = (flags & (1 << 0)) != 0; | 
|  |  | 
|  | TokenPosition value_position = TokenPosition::kNoSource; | 
|  | Fragment instructions = BuildExpression(&value_position);  // read operand. | 
|  |  | 
|  | const AbstractType& type = T.BuildType();  // read type. | 
|  |  | 
|  | // The VM does not like an Object_as call with a dynamic type. We need to | 
|  | // special case this situation. | 
|  | const Type& object_type = Type::Handle(Z, Type::ObjectType()); | 
|  |  | 
|  | if (type.IsMalformed()) { | 
|  | instructions += Drop(); | 
|  | instructions += ThrowTypeError(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | if (type.IsInstantiated() && | 
|  | object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) { | 
|  | // We already evaluated the operand on the left and just leave it there as | 
|  | // the result of the `obj as dynamic` expression. | 
|  | } else if (is_type_error) { | 
|  | instructions += LoadLocal(MakeTemporary()); | 
|  | instructions += flow_graph_builder_->AssertAssignable( | 
|  | value_position, type, Symbols::Empty(), | 
|  | AssertAssignableInstr::kInsertedByFrontend); | 
|  | instructions += Drop(); | 
|  | } else { | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | if (!type.IsInstantiated(kCurrentClass)) { | 
|  | instructions += LoadInstantiatorTypeArguments(); | 
|  | } else { | 
|  | instructions += NullConstant(); | 
|  | } | 
|  | instructions += PushArgument();  // Instantiator type arguments. | 
|  |  | 
|  | if (!type.IsInstantiated(kFunctions)) { | 
|  | instructions += LoadFunctionTypeArguments(); | 
|  | } else { | 
|  | instructions += NullConstant(); | 
|  | } | 
|  | instructions += PushArgument();  // Function type arguments. | 
|  |  | 
|  | instructions += Constant(type); | 
|  | instructions += PushArgument();  // Type. | 
|  |  | 
|  | instructions += InstanceCall( | 
|  | position, Library::PrivateCoreLibName(Symbols::_as()), Token::kAS, 4); | 
|  | } | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildSymbolLiteral( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | intptr_t offset = ReaderOffset() - 1;  // EvaluateExpression needs the tag. | 
|  | SkipStringReference();                 // read index into string table. | 
|  | return Constant(constant_evaluator_.EvaluateExpression(offset)); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildTypeLiteral(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | const AbstractType& type = T.BuildType();  // read type. | 
|  | if (type.IsMalformed()) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, "Malformed type literal"); | 
|  | } | 
|  |  | 
|  | Fragment instructions; | 
|  | if (type.IsInstantiated()) { | 
|  | instructions += Constant(type); | 
|  | } else { | 
|  | if (!type.IsInstantiated(kCurrentClass)) { | 
|  | instructions += LoadInstantiatorTypeArguments(); | 
|  | } else { | 
|  | instructions += NullConstant(); | 
|  | } | 
|  | if (!type.IsInstantiated(kFunctions)) { | 
|  | instructions += LoadFunctionTypeArguments(); | 
|  | } else { | 
|  | instructions += NullConstant(); | 
|  | } | 
|  | instructions += InstantiateType(type); | 
|  | } | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildThisExpression( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | return LoadLocal(scopes()->this_variable); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildRethrow(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | Fragment instructions = DebugStepCheck(position); | 
|  | instructions += LoadLocal(catch_block()->exception_var()); | 
|  | instructions += PushArgument(); | 
|  | instructions += LoadLocal(catch_block()->stack_trace_var()); | 
|  | instructions += PushArgument(); | 
|  | instructions += RethrowException(position, catch_block()->catch_try_index()); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildThrow(TokenPosition* p) { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | Fragment instructions; | 
|  |  | 
|  | instructions += BuildExpression();  // read expression. | 
|  |  | 
|  | if (NeedsDebugStepCheck(stack(), position)) { | 
|  | instructions = DebugStepCheck(position) + instructions; | 
|  | } | 
|  | instructions += PushArgument(); | 
|  | instructions += ThrowException(position); | 
|  | ASSERT(instructions.is_closed()); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildListLiteral(bool is_const, | 
|  | TokenPosition* p) { | 
|  | if (is_const) { | 
|  | intptr_t offset = ReaderOffset() - 1;                 // Include the tag. | 
|  | (p != NULL) ? * p = ReadPosition() : ReadPosition();  // read position. | 
|  |  | 
|  | SetOffset(offset); | 
|  | SkipExpression();  // read past the ListLiteral. | 
|  | return Constant(constant_evaluator_.EvaluateListLiteral(offset)); | 
|  | } | 
|  |  | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const TypeArguments& type_arguments = T.BuildTypeArguments(1);  // read type. | 
|  | intptr_t length = ReadListLength();  // read list length. | 
|  | // Note: there will be "length" expressions. | 
|  |  | 
|  | // The type argument for the factory call. | 
|  | Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); | 
|  | LocalVariable* type = MakeTemporary(); | 
|  |  | 
|  | instructions += LoadLocal(type); | 
|  | instructions += PushArgument(); | 
|  | if (length == 0) { | 
|  | instructions += Constant(Object::empty_array()); | 
|  | } else { | 
|  | // The type arguments for CreateArray. | 
|  | instructions += LoadLocal(type); | 
|  | instructions += IntConstant(length); | 
|  | instructions += CreateArray(); | 
|  | AbstractType& list_type = AbstractType::ZoneHandle(Z); | 
|  | if (I->type_checks()) { | 
|  | if (type_arguments.IsNull()) { | 
|  | // It was dynamic. | 
|  | list_type = Object::dynamic_type().raw(); | 
|  | } else { | 
|  | list_type = type_arguments.TypeAt(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | LocalVariable* array = MakeTemporary(); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | instructions += LoadLocal(array); | 
|  | instructions += IntConstant(i); | 
|  | instructions += BuildExpression();  // read ith expression. | 
|  | instructions += CheckAssignableInCheckedMode( | 
|  | list_type, Symbols::ListLiteralElement()); | 
|  | instructions += StoreIndexed(kArrayCid); | 
|  | instructions += Drop(); | 
|  | } | 
|  | } | 
|  | instructions += PushArgument();  // The array. | 
|  |  | 
|  | const Class& factory_class = | 
|  | Class::Handle(Z, Library::LookupCoreClass(Symbols::List())); | 
|  | const Function& factory_method = Function::ZoneHandle( | 
|  | Z, factory_class.LookupFactory( | 
|  | Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); | 
|  |  | 
|  | instructions += StaticCall(position, factory_method, 2, ICData::kStatic); | 
|  | instructions += DropTempsPreserveTop(1);  // Instantiated type_arguments. | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const, | 
|  | TokenPosition* p) { | 
|  | if (is_const) { | 
|  | intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  | (p != NULL) ? * p = ReadPosition() : ReadPosition(); | 
|  |  | 
|  | SetOffset(offset); | 
|  | SkipExpression();  // Read past the MapLiteral. | 
|  | return Constant(constant_evaluator_.EvaluateMapLiteral(offset)); | 
|  | } | 
|  |  | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | if (p != NULL) *p = position; | 
|  |  | 
|  | const TypeArguments& type_arguments = | 
|  | T.BuildTypeArguments(2);  // read key_type and value_type. | 
|  |  | 
|  | // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`. | 
|  | Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | intptr_t length = ReadListLength();  // read list length. | 
|  | // Note: there will be "length" map entries (i.e. key and value expressions). | 
|  |  | 
|  | if (length == 0) { | 
|  | instructions += Constant(Object::empty_array()); | 
|  | } else { | 
|  | // The type arguments for `new List<X>(int len)`. | 
|  | instructions += Constant(TypeArguments::ZoneHandle(Z)); | 
|  |  | 
|  | // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN]. | 
|  | instructions += IntConstant(2 * length); | 
|  | instructions += CreateArray(); | 
|  |  | 
|  | LocalVariable* array = MakeTemporary(); | 
|  | for (intptr_t i = 0; i < length; ++i) { | 
|  | instructions += LoadLocal(array); | 
|  | instructions += IntConstant(2 * i); | 
|  | instructions += BuildExpression();  // read ith key. | 
|  | instructions += StoreIndexed(kArrayCid); | 
|  | instructions += Drop(); | 
|  |  | 
|  | instructions += LoadLocal(array); | 
|  | instructions += IntConstant(2 * i + 1); | 
|  | instructions += BuildExpression();  // read ith value. | 
|  | instructions += StoreIndexed(kArrayCid); | 
|  | instructions += Drop(); | 
|  | } | 
|  | } | 
|  | instructions += PushArgument();  // The array. | 
|  |  | 
|  | const Class& map_class = | 
|  | Class::Handle(Z, Library::LookupCoreClass(Symbols::Map())); | 
|  | const Function& factory_method = Function::ZoneHandle( | 
|  | Z, map_class.LookupFactory( | 
|  | Library::PrivateCoreLibName(Symbols::MapLiteralFactory()))); | 
|  |  | 
|  | return instructions + | 
|  | StaticCall(position, factory_method, 2, ICData::kStatic); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() { | 
|  | ReadPosition();  // read position. | 
|  | return BuildFunctionNode(TokenPosition::kNoSource, StringIndex()); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | Fragment instructions = BuildVariableDeclaration();  // read variable. | 
|  | instructions += BuildExpression();                   // read body. | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | const String& value = | 
|  | H.DartString(ReadStringReference());  // read index into string table. | 
|  | const Integer& integer = | 
|  | Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)); | 
|  | if (integer.IsNull()) { | 
|  | H.ReportError(script_, TokenPosition::kNoSource, | 
|  | "Integer literal %s is out of range", value.ToCString()); | 
|  | UNREACHABLE(); | 
|  | } | 
|  | return Constant(integer); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildStringLiteral( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | return Constant(H.DartSymbolPlain( | 
|  | ReadStringReference()));  // read index into string table. | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload, | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias; | 
|  | return IntConstant(value); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative, | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt()) | 
|  | : ReadUInt();  // read value. | 
|  | return IntConstant(value); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | Double& constant = Double::ZoneHandle( | 
|  | Z, Double::NewCanonical( | 
|  | H.DartString(ReadStringReference())));  // read string reference. | 
|  | return Constant(constant); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value, | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | return Constant(Bool::Get(value)); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildNullLiteral(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | return Constant(Instance::ZoneHandle(Z, Instance::null())); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildFutureNullValue( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  | const Class& future = Class::Handle(Z, I->object_store()->future_class()); | 
|  | ASSERT(!future.IsNull()); | 
|  | const Function& constructor = | 
|  | Function::ZoneHandle(Z, future.LookupFunction(Symbols::FutureValue())); | 
|  | ASSERT(!constructor.IsNull()); | 
|  |  | 
|  | Fragment instructions; | 
|  | instructions += BuildNullLiteral(position); | 
|  | instructions += PushArgument(); | 
|  | instructions += StaticCall(TokenPosition::kNoSource, constructor, | 
|  | /* argument_count = */ 1, ICData::kStatic); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVectorCreation( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | intptr_t size = ReadUInt();  // read size. | 
|  | return AllocateContext(size); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVectorGet(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  | intptr_t index = ReadUInt();                // read index. | 
|  | instructions += LoadField(Context::variable_offset(index)); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVectorSet(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | Fragment instructions = NullConstant(); | 
|  | LocalVariable* result = MakeTemporary(); | 
|  |  | 
|  | instructions += BuildExpression();  // read vector expression. | 
|  | intptr_t index = ReadUInt();        // read index. | 
|  | instructions += BuildExpression();  // read value expression. | 
|  | instructions += StoreLocal(TokenPosition::kNoSource, result); | 
|  |  | 
|  | instructions += StoreInstanceField(TokenPosition::kNoSource, | 
|  | Context::variable_offset(index)); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVectorCopy(TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | Fragment instructions = BuildExpression();  // read vector expression. | 
|  | Value* context_to_copy = Pop(); | 
|  | // TODO(dartbug.com/31218) VectorCopy should contain size of the context | 
|  | // as a constant. | 
|  | CloneContextInstr* clone_instruction = | 
|  | new (Z) CloneContextInstr(TokenPosition::kNoSource, context_to_copy, | 
|  | CloneContextInstr::kUnknownContextSize, | 
|  | Thread::Current()->GetNextDeoptId()); | 
|  | instructions <<= clone_instruction; | 
|  | Push(clone_instruction); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildClosureCreation( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | NameIndex function_reference = | 
|  | ReadCanonicalNameReference();  // read function reference. | 
|  | Function& function = Function::ZoneHandle( | 
|  | Z, H.LookupStaticMethodByKernelProcedure(function_reference)); | 
|  |  | 
|  | intptr_t num_type_parameters; | 
|  | { | 
|  | AlternativeReadingScope _(&reader_); | 
|  | SkipExpression();  // context vector | 
|  | SkipDartType();    // skip function type | 
|  | num_type_parameters = ReadListLength(); | 
|  | } | 
|  | function = function.ConvertedClosureFunction(num_type_parameters); | 
|  | ASSERT(!function.IsNull()); | 
|  |  | 
|  | const Class& closure_class = | 
|  | Class::ZoneHandle(Z, I->object_store()->closure_class()); | 
|  | Fragment instructions = AllocateObject(closure_class, function); | 
|  | LocalVariable* closure = MakeTemporary(); | 
|  |  | 
|  | instructions += BuildExpression();  // read context vector. | 
|  | LocalVariable* context = MakeTemporary(); | 
|  |  | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += Constant(function); | 
|  | instructions += | 
|  | StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset()); | 
|  |  | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += LoadLocal(context); | 
|  | instructions += | 
|  | StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset()); | 
|  |  | 
|  | // Skip the function type of the closure (it's predicable from the | 
|  | // target and the supplied type arguments). | 
|  | SkipDartType(); | 
|  |  | 
|  | ReadListLength();  // type parameter count | 
|  | if (num_type_parameters > 0) { | 
|  | instructions += LoadLocal(closure); | 
|  | const TypeArguments& type_args = T.BuildTypeArguments( | 
|  | num_type_parameters);  // read list of type arguments. | 
|  | instructions += TranslateInstantiatedTypeArguments(type_args); | 
|  | instructions += StoreInstanceField( | 
|  | TokenPosition::kNoSource, Closure::function_type_arguments_offset()); | 
|  | } | 
|  |  | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += Constant(Object::empty_type_arguments()); | 
|  | instructions += StoreInstanceField(TokenPosition::kNoSource, | 
|  | Closure::delayed_type_arguments_offset()); | 
|  |  | 
|  | instructions += Drop();  // context | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildConstantExpression( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  | const intptr_t constant_index = ReadUInt(); | 
|  | return Constant(Object::ZoneHandle(Z, H.constants().At(constant_index))); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildPartialTearoffInstantiation( | 
|  | TokenPosition* position) { | 
|  | if (position != NULL) *position = TokenPosition::kNoSource; | 
|  |  | 
|  | // Create a copy of the closure. | 
|  |  | 
|  | Fragment instructions = BuildExpression(); | 
|  | LocalVariable* original_closure = MakeTemporary(); | 
|  |  | 
|  | instructions += AllocateObject( | 
|  | TokenPosition::kNoSource, | 
|  | Class::ZoneHandle(Z, I->object_store()->closure_class()), 0); | 
|  | LocalVariable* new_closure = MakeTemporary(); | 
|  |  | 
|  | instructions += LoadLocal(new_closure); | 
|  |  | 
|  | intptr_t num_type_args = ReadListLength(); | 
|  | const TypeArguments& type_args = T.BuildTypeArguments(num_type_args); | 
|  | instructions += TranslateInstantiatedTypeArguments(type_args); | 
|  | instructions += StoreInstanceField(TokenPosition::kNoSource, | 
|  | Closure::delayed_type_arguments_offset()); | 
|  |  | 
|  | // Copy over the target function. | 
|  | instructions += LoadLocal(new_closure); | 
|  | instructions += LoadLocal(original_closure); | 
|  | instructions += LoadField(Closure::function_offset()); | 
|  | instructions += | 
|  | StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset()); | 
|  |  | 
|  | // Copy over the instantiator type arguments. | 
|  | instructions += LoadLocal(new_closure); | 
|  | instructions += LoadLocal(original_closure); | 
|  | instructions += LoadField(Closure::instantiator_type_arguments_offset()); | 
|  | instructions += StoreInstanceField( | 
|  | TokenPosition::kNoSource, Closure::instantiator_type_arguments_offset()); | 
|  |  | 
|  | // Copy over the function type arguments. | 
|  | instructions += LoadLocal(new_closure); | 
|  | instructions += LoadLocal(original_closure); | 
|  | instructions += LoadField(Closure::function_type_arguments_offset()); | 
|  | instructions += StoreInstanceField(TokenPosition::kNoSource, | 
|  | Closure::function_type_arguments_offset()); | 
|  |  | 
|  | // Copy over the context. | 
|  | instructions += LoadLocal(new_closure); | 
|  | instructions += LoadLocal(original_closure); | 
|  | instructions += LoadField(Closure::context_offset()); | 
|  | instructions += | 
|  | StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset()); | 
|  |  | 
|  | instructions += DropTempsPreserveTop(1);  // drop old closure | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildExpressionStatement() { | 
|  | Fragment instructions = BuildExpression();  // read expression. | 
|  | instructions += Drop(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildBlock() { | 
|  | intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  |  | 
|  | Fragment instructions; | 
|  |  | 
|  | instructions += EnterScope(offset); | 
|  | intptr_t list_length = ReadListLength();  // read number of statements. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | if (instructions.is_open()) { | 
|  | instructions += BuildStatement();  // read ith statement. | 
|  | } else { | 
|  | SkipStatement();  // read ith statement. | 
|  | } | 
|  | } | 
|  | instructions += ExitScope(offset); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() { | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildAssertBlock() { | 
|  | if (!I->asserts()) { | 
|  | SkipStatementList(); | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  |  | 
|  | Fragment instructions; | 
|  |  | 
|  | instructions += EnterScope(offset); | 
|  | intptr_t list_length = ReadListLength();  // read number of statements. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | if (instructions.is_open()) { | 
|  | instructions += BuildStatement();  // read ith statement. | 
|  | } else { | 
|  | SkipStatement();  // read ith statement. | 
|  | } | 
|  | } | 
|  | instructions += ExitScope(offset); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildAssertStatement() { | 
|  | if (!I->asserts()) { | 
|  | SetOffset(ReaderOffset() - 1);  // Include the tag. | 
|  | SkipStatement();                // read this statement. | 
|  | return Fragment(); | 
|  | } | 
|  |  | 
|  | TargetEntryInstr* then; | 
|  | TargetEntryInstr* otherwise; | 
|  |  | 
|  | Fragment instructions; | 
|  | // Asserts can be of the following two kinds: | 
|  | // | 
|  | //    * `assert(expr)` | 
|  | //    * `assert(() { ... })` | 
|  | // | 
|  | // The call to `_AssertionError._evaluateAssertion()` will take care of both | 
|  | // and returns a boolean. | 
|  | instructions += BuildExpression();  // read condition. | 
|  | instructions += PushArgument(); | 
|  | instructions += EvaluateAssertion(); | 
|  | instructions += CheckBoolean(); | 
|  | instructions += Constant(Bool::True()); | 
|  | instructions += BranchIfEqual(&then, &otherwise, false); | 
|  |  | 
|  | TokenPosition condition_start_offset = | 
|  | ReadPosition();  // read condition start offset. | 
|  | TokenPosition condition_end_offset = | 
|  | ReadPosition();  // read condition end offset. | 
|  |  | 
|  | const Class& klass = | 
|  | Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError())); | 
|  | ASSERT(!klass.IsNull()); | 
|  | const Function& target = Function::ZoneHandle( | 
|  | Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew())); | 
|  | ASSERT(!target.IsNull()); | 
|  |  | 
|  | // Build equivalent of `throw _AssertionError._throwNew(start, end, message)` | 
|  | // expression. We build throw (even through _throwNew already throws) because | 
|  | // call is not a valid last instruction for the block. Blocks can only | 
|  | // terminate with explicit control flow instructions (Branch, Goto, Return | 
|  | // or Throw). | 
|  | Fragment otherwise_fragment(otherwise); | 
|  | otherwise_fragment += IntConstant(condition_start_offset.Pos()); | 
|  | otherwise_fragment += PushArgument();  // start | 
|  | otherwise_fragment += IntConstant(condition_end_offset.Pos()); | 
|  | otherwise_fragment += PushArgument();  // end | 
|  | Tag tag = ReadTag();                   // read (first part of) message. | 
|  | if (tag == kSomething) { | 
|  | otherwise_fragment += BuildExpression();  // read (rest of) message. | 
|  | } else { | 
|  | otherwise_fragment += Constant(Instance::ZoneHandle(Z));  // null. | 
|  | } | 
|  | otherwise_fragment += PushArgument();  // message | 
|  |  | 
|  | otherwise_fragment += | 
|  | StaticCall(TokenPosition::kNoSource, target, 3, ICData::kStatic); | 
|  | otherwise_fragment += PushArgument(); | 
|  | otherwise_fragment += ThrowException(TokenPosition::kNoSource); | 
|  | otherwise_fragment += Drop(); | 
|  |  | 
|  | return Fragment(instructions.entry, then); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildLabeledStatement() { | 
|  | // There can be serveral cases: | 
|  | // | 
|  | //   * the body contains a break | 
|  | //   * the body doesn't contain a break | 
|  | // | 
|  | //   * translating the body results in a closed fragment | 
|  | //   * translating the body results in a open fragment | 
|  | // | 
|  | // => We will only know which case we are in after the body has been | 
|  | //    traversed. | 
|  |  | 
|  | BreakableBlock block(flow_graph_builder_); | 
|  | Fragment instructions = BuildStatement();  // read body. | 
|  | if (block.HadJumper()) { | 
|  | if (instructions.is_open()) { | 
|  | instructions += Goto(block.destination()); | 
|  | } | 
|  | return Fragment(instructions.entry, block.destination()); | 
|  | } else { | 
|  | return instructions; | 
|  | } | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildBreakStatement() { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | intptr_t target_index = ReadUInt();       // read target index. | 
|  |  | 
|  | TryFinallyBlock* outer_finally = NULL; | 
|  | intptr_t target_context_depth = -1; | 
|  | JoinEntryInstr* destination = breakable_block()->BreakDestination( | 
|  | target_index, &outer_finally, &target_context_depth); | 
|  |  | 
|  | Fragment instructions; | 
|  | instructions += | 
|  | TranslateFinallyFinalizers(outer_finally, target_context_depth); | 
|  | if (instructions.is_open()) { | 
|  | if (NeedsDebugStepCheck(parsed_function()->function(), position)) { | 
|  | instructions += DebugStepCheck(position); | 
|  | } | 
|  | instructions += Goto(destination); | 
|  | } | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildWhileStatement() { | 
|  | loop_depth_inc(); | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  |  | 
|  | bool negate; | 
|  | Fragment condition = TranslateCondition(&negate);  // read condition. | 
|  | TargetEntryInstr* body_entry; | 
|  | TargetEntryInstr* loop_exit; | 
|  | condition += BranchIfTrue(&body_entry, &loop_exit, negate); | 
|  |  | 
|  | Fragment body(body_entry); | 
|  | body += BuildStatement();  // read body. | 
|  |  | 
|  | Instruction* entry; | 
|  | if (body.is_open()) { | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | body += Goto(join); | 
|  |  | 
|  | Fragment loop(join); | 
|  | loop += CheckStackOverflow(position); | 
|  | loop += condition; | 
|  | entry = new (Z) GotoInstr(join, Thread::Current()->GetNextDeoptId()); | 
|  | } else { | 
|  | entry = condition.entry; | 
|  | } | 
|  |  | 
|  | loop_depth_dec(); | 
|  | return Fragment(entry, loop_exit); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildDoStatement() { | 
|  | loop_depth_inc(); | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | Fragment body = BuildStatement();               // read body. | 
|  |  | 
|  | if (body.is_closed()) { | 
|  | SkipExpression();  // read condition. | 
|  | loop_depth_dec(); | 
|  | return body; | 
|  | } | 
|  |  | 
|  | bool negate; | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | Fragment loop(join); | 
|  | loop += CheckStackOverflow(position); | 
|  | loop += body; | 
|  | loop += TranslateCondition(&negate);  // read condition. | 
|  | TargetEntryInstr* loop_repeat; | 
|  | TargetEntryInstr* loop_exit; | 
|  | loop += BranchIfTrue(&loop_repeat, &loop_exit, negate); | 
|  |  | 
|  | Fragment repeat(loop_repeat); | 
|  | repeat += Goto(join); | 
|  |  | 
|  | loop_depth_dec(); | 
|  | return Fragment(new (Z) GotoInstr(join, Thread::Current()->GetNextDeoptId()), | 
|  | loop_exit); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildForStatement() { | 
|  | intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  |  | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  |  | 
|  | Fragment declarations; | 
|  |  | 
|  | loop_depth_inc(); | 
|  |  | 
|  | intptr_t num_context_variables = 0; | 
|  | declarations += EnterScope(offset, &num_context_variables); | 
|  |  | 
|  | intptr_t list_length = ReadListLength();  // read number of variables. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | declarations += BuildVariableDeclaration();  // read ith variable. | 
|  | } | 
|  |  | 
|  | bool negate = false; | 
|  | Tag tag = ReadTag();  // Read first part of condition. | 
|  | Fragment condition = | 
|  | tag == kNothing ? Constant(Bool::True()) | 
|  | : TranslateCondition(&negate);  // read rest of condition. | 
|  | TargetEntryInstr* body_entry; | 
|  | TargetEntryInstr* loop_exit; | 
|  | condition += BranchIfTrue(&body_entry, &loop_exit, negate); | 
|  |  | 
|  | Fragment updates; | 
|  | list_length = ReadListLength();  // read number of updates. | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | updates += BuildExpression();  // read ith update. | 
|  | updates += Drop(); | 
|  | } | 
|  |  | 
|  | Fragment body(body_entry); | 
|  | body += BuildStatement();  // read body. | 
|  |  | 
|  | if (body.is_open()) { | 
|  | // We allocated a fresh context before the loop which contains captured | 
|  | // [ForStatement] variables.  Before jumping back to the loop entry we clone | 
|  | // the context object (at same depth) which ensures the next iteration of | 
|  | // the body gets a fresh set of [ForStatement] variables (with the old | 
|  | // (possibly updated) values). | 
|  | if (num_context_variables > 0) body += CloneContext(num_context_variables); | 
|  |  | 
|  | body += updates; | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | declarations += Goto(join); | 
|  | body += Goto(join); | 
|  |  | 
|  | Fragment loop(join); | 
|  | loop += CheckStackOverflow(position); | 
|  | loop += condition; | 
|  | } else { | 
|  | declarations += condition; | 
|  | } | 
|  |  | 
|  | Fragment loop(declarations.entry, loop_exit); | 
|  |  | 
|  | loop += ExitScope(offset); | 
|  |  | 
|  | loop_depth_dec(); | 
|  |  | 
|  | return loop; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) { | 
|  | intptr_t offset = ReaderOffset() - 1;  // Include the tag. | 
|  |  | 
|  | const TokenPosition position = ReadPosition();  // read position. | 
|  | TokenPosition body_position = ReadPosition();  // read body position. | 
|  | intptr_t variable_kernel_position = ReaderOffset() + data_program_offset_; | 
|  | SkipVariableDeclaration();  // read variable. | 
|  |  | 
|  | TokenPosition iterable_position = TokenPosition::kNoSource; | 
|  | Fragment instructions = | 
|  | BuildExpression(&iterable_position);  // read iterable. | 
|  | instructions += PushArgument(); | 
|  |  | 
|  | const String& iterator_getter = | 
|  | String::ZoneHandle(Z, Field::GetterSymbol(Symbols::Iterator())); | 
|  | instructions += | 
|  | InstanceCall(iterable_position, iterator_getter, Token::kGET, 1); | 
|  | LocalVariable* iterator = scopes()->iterator_variables[for_in_depth()]; | 
|  | instructions += StoreLocal(TokenPosition::kNoSource, iterator); | 
|  | instructions += Drop(); | 
|  |  | 
|  | for_in_depth_inc(); | 
|  | loop_depth_inc(); | 
|  | Fragment condition = LoadLocal(iterator); | 
|  | condition += PushArgument(); | 
|  | condition += | 
|  | InstanceCall(iterable_position, Symbols::MoveNext(), Token::kILLEGAL, 1); | 
|  | TargetEntryInstr* body_entry; | 
|  | TargetEntryInstr* loop_exit; | 
|  | condition += BranchIfTrue(&body_entry, &loop_exit, false); | 
|  |  | 
|  | Fragment body(body_entry); | 
|  | body += EnterScope(offset); | 
|  | body += LoadLocal(iterator); | 
|  | body += PushArgument(); | 
|  | const String& current_getter = | 
|  | String::ZoneHandle(Z, Field::GetterSymbol(Symbols::Current())); | 
|  | body += InstanceCall(body_position, current_getter, Token::kGET, 1); | 
|  | body += StoreLocal(TokenPosition::kNoSource, | 
|  | LookupVariable(variable_kernel_position)); | 
|  | body += Drop(); | 
|  | body += BuildStatement();  // read body. | 
|  | body += ExitScope(offset); | 
|  |  | 
|  | if (body.is_open()) { | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | instructions += Goto(join); | 
|  | body += Goto(join); | 
|  |  | 
|  | Fragment loop(join); | 
|  | loop += CheckStackOverflow(position); | 
|  | loop += condition; | 
|  | } else { | 
|  | instructions += condition; | 
|  | } | 
|  |  | 
|  | loop_depth_dec(); | 
|  | for_in_depth_dec(); | 
|  | return Fragment(instructions.entry, loop_exit); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() { | 
|  | ReadPosition();  // read position. | 
|  | // We need the number of cases. So start by getting that, then go back. | 
|  | intptr_t offset = ReaderOffset(); | 
|  | SkipExpression();                   // temporarily skip condition | 
|  | int case_count = ReadListLength();  // read number of cases. | 
|  | SetOffset(offset); | 
|  |  | 
|  | SwitchBlock block(flow_graph_builder_, case_count); | 
|  |  | 
|  | // Instead of using a variable we should reuse the expression on the stack, | 
|  | // since it won't be assigned again, we don't need phi nodes. | 
|  | Fragment head_instructions = BuildExpression();  // read condition. | 
|  | head_instructions += | 
|  | StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable); | 
|  | head_instructions += Drop(); | 
|  |  | 
|  | case_count = ReadListLength();  // read number of cases. | 
|  |  | 
|  | // Phase 1: Generate bodies and try to find out whether a body will be target | 
|  | // of a jump due to: | 
|  | //   * `continue case_label` | 
|  | //   * `case e1: case e2: body` | 
|  | Fragment* body_fragments = new Fragment[case_count]; | 
|  | intptr_t* case_expression_offsets = new intptr_t[case_count]; | 
|  | int default_case = -1; | 
|  |  | 
|  | for (intptr_t i = 0; i < case_count; ++i) { | 
|  | case_expression_offsets[i] = ReaderOffset(); | 
|  | int expression_count = ReadListLength();  // read number of expressions. | 
|  | for (intptr_t j = 0; j < expression_count; ++j) { | 
|  | ReadPosition();    // read jth position. | 
|  | SkipExpression();  // read jth expression. | 
|  | } | 
|  | bool is_default = ReadBool();  // read is_default. | 
|  | if (is_default) default_case = i; | 
|  | Fragment& body_fragment = body_fragments[i] = | 
|  | BuildStatement();  // read body. | 
|  |  | 
|  | if (body_fragment.entry == NULL) { | 
|  | // Make a NOP in order to ensure linking works properly. | 
|  | body_fragment = NullConstant(); | 
|  | body_fragment += Drop(); | 
|  | } | 
|  |  | 
|  | // The Dart language specification mandates fall-throughs in [SwitchCase]es | 
|  | // to be runtime errors. | 
|  | if (!is_default && body_fragment.is_open() && (i < (case_count - 1))) { | 
|  | const Class& klass = Class::ZoneHandle( | 
|  | Z, Library::LookupCoreClass(Symbols::FallThroughError())); | 
|  | ASSERT(!klass.IsNull()); | 
|  |  | 
|  | GrowableHandlePtrArray<const String> pieces(Z, 3); | 
|  | pieces.Add(Symbols::FallThroughError()); | 
|  | pieces.Add(Symbols::Dot()); | 
|  | pieces.Add(H.DartSymbolObfuscate("_create")); | 
|  |  | 
|  | const Function& constructor = Function::ZoneHandle( | 
|  | Z, klass.LookupConstructorAllowPrivate(String::ZoneHandle( | 
|  | Z, Symbols::FromConcatAll(H.thread(), pieces)))); | 
|  | ASSERT(!constructor.IsNull()); | 
|  | const String& url = H.DartString( | 
|  | parsed_function()->function().ToLibNamePrefixedQualifiedCString(), | 
|  | Heap::kOld); | 
|  |  | 
|  | // Create instance of _FallThroughError | 
|  | body_fragment += AllocateObject(TokenPosition::kNoSource, klass, 0); | 
|  | LocalVariable* instance = MakeTemporary(); | 
|  |  | 
|  | // Call _FallThroughError._create constructor. | 
|  | body_fragment += LoadLocal(instance); | 
|  | body_fragment += PushArgument();  // this | 
|  |  | 
|  | body_fragment += Constant(url); | 
|  | body_fragment += PushArgument();  // url | 
|  |  | 
|  | body_fragment += NullConstant(); | 
|  | body_fragment += PushArgument();  // line | 
|  |  | 
|  | body_fragment += | 
|  | StaticCall(TokenPosition::kNoSource, constructor, 3, ICData::kStatic); | 
|  | body_fragment += Drop(); | 
|  |  | 
|  | // Throw the exception | 
|  | body_fragment += PushArgument(); | 
|  | body_fragment += ThrowException(TokenPosition::kNoSource); | 
|  | body_fragment += Drop(); | 
|  | } | 
|  |  | 
|  | // If there is an implicit fall-through we have one [SwitchCase] and | 
|  | // multiple expressions, e.g. | 
|  | // | 
|  | //    switch(expr) { | 
|  | //      case a: | 
|  | //      case b: | 
|  | //        <stmt-body> | 
|  | //    } | 
|  | // | 
|  | // This means that the <stmt-body> will have more than 1 incoming edge (one | 
|  | // from `a == expr` and one from `a != expr && b == expr`). The | 
|  | // `block.Destination()` records the additional jump. | 
|  | if (expression_count > 1) { | 
|  | block.DestinationDirect(i); | 
|  | } | 
|  | } | 
|  |  | 
|  | intptr_t end_offset = ReaderOffset(); | 
|  |  | 
|  | // Phase 2: Generate everything except the real bodies: | 
|  | //   * jump directly to a body (if there is no jumper) | 
|  | //   * jump to a wrapper block which jumps to the body (if there is a jumper) | 
|  | Fragment current_instructions = head_instructions; | 
|  | for (intptr_t i = 0; i < case_count; ++i) { | 
|  | SetOffset(case_expression_offsets[i]); | 
|  | int expression_count = ReadListLength();  // read length of expressions. | 
|  |  | 
|  | if (i == default_case) { | 
|  | ASSERT(i == (case_count - 1)); | 
|  |  | 
|  | // Evaluate the conditions for the default [SwitchCase] just for the | 
|  | // purpose of potentially triggering a compile-time error. | 
|  |  | 
|  | for (intptr_t j = 0; j < expression_count; ++j) { | 
|  | ReadPosition();  // read jth position. | 
|  | // this reads the expression, but doesn't skip past it. | 
|  | constant_evaluator_.EvaluateExpression(ReaderOffset()); | 
|  | SkipExpression();  // read jth expression. | 
|  | } | 
|  |  | 
|  | if (block.HadJumper(i)) { | 
|  | // There are several branches to the body, so we will make a goto to | 
|  | // the join block (and prepend a join instruction to the real body). | 
|  | JoinEntryInstr* join = block.DestinationDirect(i); | 
|  | current_instructions += Goto(join); | 
|  |  | 
|  | current_instructions = Fragment(current_instructions.entry, join); | 
|  | current_instructions += body_fragments[i]; | 
|  | } else { | 
|  | current_instructions += body_fragments[i]; | 
|  | } | 
|  | } else { | 
|  | JoinEntryInstr* body_join = NULL; | 
|  | if (block.HadJumper(i)) { | 
|  | body_join = block.DestinationDirect(i); | 
|  | body_fragments[i] = Fragment(body_join) + body_fragments[i]; | 
|  | } | 
|  |  | 
|  | for (intptr_t j = 0; j < expression_count; ++j) { | 
|  | TargetEntryInstr* then; | 
|  | TargetEntryInstr* otherwise; | 
|  |  | 
|  | TokenPosition position = ReadPosition();  // read jth position. | 
|  | current_instructions += | 
|  | Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); | 
|  | SkipExpression();  // read jth expression. | 
|  | current_instructions += PushArgument(); | 
|  | current_instructions += LoadLocal(scopes()->switch_variable); | 
|  | current_instructions += PushArgument(); | 
|  | current_instructions += | 
|  | InstanceCall(position, Symbols::EqualOperator(), Token::kEQ, | 
|  | /*argument_count=*/2, | 
|  | /*checked_argument_count=*/2); | 
|  | current_instructions += BranchIfTrue(&then, &otherwise, false); | 
|  |  | 
|  | Fragment then_fragment(then); | 
|  |  | 
|  | if (body_join != NULL) { | 
|  | // There are several branches to the body, so we will make a goto to | 
|  | // the join block (the real body has already been prepended with a | 
|  | // join instruction). | 
|  | then_fragment += Goto(body_join); | 
|  | } else { | 
|  | // There is only a signle branch to the body, so we will just append | 
|  | // the body fragment. | 
|  | then_fragment += body_fragments[i]; | 
|  | } | 
|  |  | 
|  | current_instructions = Fragment(otherwise); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (case_count > 0 && default_case < 0) { | 
|  | // There is no default, which means we have an open [current_instructions] | 
|  | // (which is a [TargetEntryInstruction] for the last "otherwise" branch). | 
|  | // | 
|  | // Furthermore the last [SwitchCase] can be open as well.  If so, we need | 
|  | // to join these two. | 
|  | Fragment& last_body = body_fragments[case_count - 1]; | 
|  | if (last_body.is_open()) { | 
|  | ASSERT(current_instructions.is_open()); | 
|  | ASSERT(current_instructions.current->IsTargetEntry()); | 
|  |  | 
|  | // Join the last "otherwise" branch and the last [SwitchCase] fragment. | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | current_instructions += Goto(join); | 
|  | last_body += Goto(join); | 
|  |  | 
|  | current_instructions = Fragment(join); | 
|  | } | 
|  | } else { | 
|  | // All non-default cases will be closed (i.e. break/continue/throw/return) | 
|  | // So it is fine to just let more statements after the switch append to the | 
|  | // default case. | 
|  | } | 
|  |  | 
|  | delete[] body_fragments; | 
|  | delete[] case_expression_offsets; | 
|  |  | 
|  | SetOffset(end_offset); | 
|  | return Fragment(head_instructions.entry, current_instructions.current); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildContinueSwitchStatement() { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | intptr_t target_index = ReadUInt();       // read target index. | 
|  |  | 
|  | TryFinallyBlock* outer_finally = NULL; | 
|  | intptr_t target_context_depth = -1; | 
|  | JoinEntryInstr* entry = switch_block()->Destination( | 
|  | target_index, &outer_finally, &target_context_depth); | 
|  |  | 
|  | Fragment instructions; | 
|  | instructions += | 
|  | TranslateFinallyFinalizers(outer_finally, target_context_depth); | 
|  | if (instructions.is_open()) { | 
|  | if (NeedsDebugStepCheck(parsed_function()->function(), position)) { | 
|  | instructions += DebugStepCheck(position); | 
|  | } | 
|  | instructions += Goto(entry); | 
|  | } | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildIfStatement() { | 
|  | bool negate; | 
|  | ReadPosition();                                       // read position. | 
|  | Fragment instructions = TranslateCondition(&negate);  // read condition. | 
|  | TargetEntryInstr* then_entry; | 
|  | TargetEntryInstr* otherwise_entry; | 
|  | instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate); | 
|  |  | 
|  | Fragment then_fragment(then_entry); | 
|  | then_fragment += BuildStatement();  // read then. | 
|  |  | 
|  | Fragment otherwise_fragment(otherwise_entry); | 
|  | otherwise_fragment += BuildStatement();  // read otherwise. | 
|  |  | 
|  | if (then_fragment.is_open()) { | 
|  | if (otherwise_fragment.is_open()) { | 
|  | JoinEntryInstr* join = BuildJoinEntry(); | 
|  | then_fragment += Goto(join); | 
|  | otherwise_fragment += Goto(join); | 
|  | return Fragment(instructions.entry, join); | 
|  | } else { | 
|  | return Fragment(instructions.entry, then_fragment.current); | 
|  | } | 
|  | } else if (otherwise_fragment.is_open()) { | 
|  | return Fragment(instructions.entry, otherwise_fragment.current); | 
|  | } else { | 
|  | return instructions.closed(); | 
|  | } | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildReturnStatement() { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | Tag tag = ReadTag();                      // read first part of expression. | 
|  |  | 
|  | bool inside_try_finally = try_finally_block() != NULL; | 
|  |  | 
|  | Fragment instructions = tag == kNothing | 
|  | ? NullConstant() | 
|  | : BuildExpression();  // read rest of expression. | 
|  |  | 
|  | if (instructions.is_open()) { | 
|  | if (inside_try_finally) { | 
|  | ASSERT(scopes()->finally_return_variable != NULL); | 
|  | const Function& function = parsed_function()->function(); | 
|  | if (NeedsDebugStepCheck(function, position)) { | 
|  | instructions += DebugStepCheck(position); | 
|  | } | 
|  | instructions += StoreLocal(position, scopes()->finally_return_variable); | 
|  | instructions += Drop(); | 
|  | instructions += TranslateFinallyFinalizers(NULL, -1); | 
|  | if (instructions.is_open()) { | 
|  | instructions += LoadLocal(scopes()->finally_return_variable); | 
|  | instructions += Return(TokenPosition::kNoSource); | 
|  | } | 
|  | } else { | 
|  | instructions += Return(position); | 
|  | } | 
|  | } else { | 
|  | Pop(); | 
|  | } | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildTryCatch() { | 
|  | InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch"); | 
|  |  | 
|  | intptr_t try_handler_index = AllocateTryIndex(); | 
|  | Fragment try_body = TryCatch(try_handler_index); | 
|  | JoinEntryInstr* after_try = BuildJoinEntry(); | 
|  |  | 
|  | // Fill in the body of the try. | 
|  | try_depth_inc(); | 
|  | { | 
|  | TryCatchBlock block(flow_graph_builder_, try_handler_index); | 
|  | try_body += BuildStatement();  // read body. | 
|  | try_body += Goto(after_try); | 
|  | } | 
|  | try_depth_dec(); | 
|  |  | 
|  | bool needs_stacktrace = ReadBool();  // read any_catch_needs_stack_trace | 
|  |  | 
|  | catch_depth_inc(); | 
|  | intptr_t catch_count = ReadListLength();  // read number of catches. | 
|  | const Array& handler_types = | 
|  | Array::ZoneHandle(Z, Array::New(catch_count, 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 < catch_count; ++i) { | 
|  | intptr_t catch_offset = ReaderOffset();   // Catch has no tag. | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | Tag tag = PeekTag();                      // peek guard type. | 
|  | AbstractType* type_guard = NULL; | 
|  | if (tag != kDynamicType) { | 
|  | type_guard = &T.BuildType();  // read guard. | 
|  | handler_types.SetAt(i, *type_guard); | 
|  | } else { | 
|  | SkipDartType();  // read guard. | 
|  | handler_types.SetAt(i, Object::dynamic_type()); | 
|  | } | 
|  |  | 
|  | Fragment catch_handler_body = EnterScope(catch_offset); | 
|  |  | 
|  | tag = ReadTag();  // read first part of exception. | 
|  | if (tag == kSomething) { | 
|  | catch_handler_body += LoadLocal(CurrentException()); | 
|  | catch_handler_body += | 
|  | StoreLocal(TokenPosition::kNoSource, | 
|  | LookupVariable(ReaderOffset() + data_program_offset_)); | 
|  | catch_handler_body += Drop(); | 
|  | SkipVariableDeclaration();  // read exception. | 
|  | } | 
|  |  | 
|  | tag = ReadTag();  // read first part of stack trace. | 
|  | if (tag == kSomething) { | 
|  | catch_handler_body += LoadLocal(CurrentStackTrace()); | 
|  | catch_handler_body += | 
|  | StoreLocal(TokenPosition::kNoSource, | 
|  | LookupVariable(ReaderOffset() + data_program_offset_)); | 
|  | catch_handler_body += Drop(); | 
|  | SkipVariableDeclaration();  // read stack trace. | 
|  | } | 
|  |  | 
|  | { | 
|  | CatchBlock block(flow_graph_builder_, CurrentException(), | 
|  | CurrentStackTrace(), try_handler_index); | 
|  |  | 
|  | catch_handler_body += BuildStatement();  // read body. | 
|  |  | 
|  | // Note: ExitScope adjusts context_depth_ so even if catch_handler_body | 
|  | // is closed we still need to execute ExitScope for its side effect. | 
|  | catch_handler_body += ExitScope(catch_offset); | 
|  | if (catch_handler_body.is_open()) { | 
|  | catch_handler_body += Goto(after_try); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (type_guard != NULL) { | 
|  | if (type_guard->IsMalformed()) { | 
|  | catch_body += ThrowTypeError(); | 
|  | catch_body += Drop(); | 
|  | } else { | 
|  | catch_body += LoadLocal(CurrentException()); | 
|  | catch_body += PushArgument();  // exception | 
|  | if (!type_guard->IsInstantiated(kCurrentClass)) { | 
|  | catch_body += LoadInstantiatorTypeArguments(); | 
|  | } else { | 
|  | catch_body += NullConstant(); | 
|  | } | 
|  | catch_body += PushArgument();  // instantiator type arguments | 
|  | if (!type_guard->IsInstantiated(kFunctions)) { | 
|  | catch_body += LoadFunctionTypeArguments(); | 
|  | } else { | 
|  | catch_body += NullConstant(); | 
|  | } | 
|  | catch_body += PushArgument();  // function type arguments | 
|  | catch_body += Constant(*type_guard); | 
|  | catch_body += PushArgument();  // guard type | 
|  | catch_body += InstanceCall( | 
|  | position, Library::PrivateCoreLibName(Symbols::_instanceOf()), | 
|  | Token::kIS, 4); | 
|  |  | 
|  | TargetEntryInstr* catch_entry; | 
|  | TargetEntryInstr* next_catch_entry; | 
|  | catch_body += BranchIfTrue(&catch_entry, &next_catch_entry, false); | 
|  |  | 
|  | Fragment(catch_entry) + catch_handler_body; | 
|  | catch_body = Fragment(next_catch_entry); | 
|  | } | 
|  | } else { | 
|  | catch_body += catch_handler_body; | 
|  | } | 
|  | } | 
|  |  | 
|  | // In case the last catch body was not handling the exception and branching to | 
|  | // after the try block, we will rethrow the exception (i.e. no default catch | 
|  | // handler). | 
|  | if (catch_body.is_open()) { | 
|  | catch_body += LoadLocal(CurrentException()); | 
|  | catch_body += PushArgument(); | 
|  | catch_body += LoadLocal(CurrentStackTrace()); | 
|  | catch_body += PushArgument(); | 
|  | catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index); | 
|  | Drop(); | 
|  | } | 
|  | catch_depth_dec(); | 
|  |  | 
|  | return Fragment(try_body.entry, after_try); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildTryFinally() { | 
|  | // Note on streaming: | 
|  | // We only stream this TryFinally if we can stream everything inside it, | 
|  | // so creating a "TryFinallyBlock" with a kernel binary offset instead of an | 
|  | // AST node isn't a problem. | 
|  |  | 
|  | InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally"); | 
|  |  | 
|  | // There are 5 different cases where we need to execute the finally block: | 
|  | // | 
|  | //  a) 1/2/3th case: Special control flow going out of `node->body()`: | 
|  | // | 
|  | //   * [BreakStatement] transfers control to a [LabledStatement] | 
|  | //   * [ContinueSwitchStatement] transfers control to a [SwitchCase] | 
|  | //   * [ReturnStatement] returns a value | 
|  | // | 
|  | //   => All three cases will automatically append all finally blocks | 
|  | //      between the branching point and the destination (so we don't need to | 
|  | //      do anything here). | 
|  | // | 
|  | //  b) 4th case: Translating the body resulted in an open fragment (i.e. body | 
|  | //               executes without any control flow out of it) | 
|  | // | 
|  | //   => We are responsible for jumping out of the body to a new block (with | 
|  | //      different try index) and execute the finalizer. | 
|  | // | 
|  | //  c) 5th case: An exception occurred inside the body. | 
|  | // | 
|  | //   => We are responsible for catching it, executing the finally block and | 
|  | //      rethrowing the exception. | 
|  | intptr_t try_handler_index = AllocateTryIndex(); | 
|  | Fragment try_body = TryCatch(try_handler_index); | 
|  | JoinEntryInstr* after_try = BuildJoinEntry(); | 
|  |  | 
|  | intptr_t offset = ReaderOffset(); | 
|  | SkipStatement();  // temporarily read body. | 
|  | intptr_t finalizer_offset = ReaderOffset(); | 
|  | SetOffset(offset); | 
|  |  | 
|  | // Fill in the body of the try. | 
|  | try_depth_inc(); | 
|  | { | 
|  | TryFinallyBlock tfb(flow_graph_builder_, finalizer_offset); | 
|  | TryCatchBlock tcb(flow_graph_builder_, try_handler_index); | 
|  | try_body += BuildStatement();  // read body. | 
|  | } | 
|  | try_depth_dec(); | 
|  |  | 
|  | if (try_body.is_open()) { | 
|  | // Please note: The try index will be on level out of this block, | 
|  | // thereby ensuring if there's an exception in the finally block we | 
|  | // won't run it twice. | 
|  | JoinEntryInstr* finally_entry = BuildJoinEntry(); | 
|  |  | 
|  | try_body += Goto(finally_entry); | 
|  |  | 
|  | Fragment finally_body(finally_entry); | 
|  | finally_body += BuildStatement();  // read finalizer. | 
|  | finally_body += Goto(after_try); | 
|  | } | 
|  |  | 
|  | // Fill in the body of the catch. | 
|  | catch_depth_inc(); | 
|  | const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld)); | 
|  | handler_types.SetAt(0, Object::dynamic_type()); | 
|  | // Note: rethrow will actually force mark the handler as needing a stacktrace. | 
|  | Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index, | 
|  | /* needs_stacktrace = */ false); | 
|  | SetOffset(finalizer_offset); | 
|  | finally_body += BuildStatement();  // read finalizer | 
|  | if (finally_body.is_open()) { | 
|  | finally_body += LoadLocal(CurrentException()); | 
|  | finally_body += PushArgument(); | 
|  | finally_body += LoadLocal(CurrentStackTrace()); | 
|  | finally_body += PushArgument(); | 
|  | finally_body += | 
|  | RethrowException(TokenPosition::kNoSource, try_handler_index); | 
|  | Drop(); | 
|  | } | 
|  | catch_depth_dec(); | 
|  |  | 
|  | return Fragment(try_body.entry, after_try); | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildYieldStatement() { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | uint8_t flags = ReadByte();               // read flags. | 
|  |  | 
|  | ASSERT(flags == kNativeYieldFlags);  // Must have been desugared. | 
|  |  | 
|  | // Setup yield/continue point: | 
|  | // | 
|  | //   ... | 
|  | //   :await_jump_var = index; | 
|  | //   :await_ctx_var = :current_context_var | 
|  | //   return <expr> | 
|  | // | 
|  | // Continuation<index>: | 
|  | //   Drop(1) | 
|  | //   ... | 
|  | // | 
|  | // BuildGraphOfFunction will create a dispatch that jumps to | 
|  | // Continuation<:await_jump_var> upon entry to the function. | 
|  | // | 
|  | Fragment instructions = IntConstant(yield_continuations().length() + 1); | 
|  | instructions += | 
|  | StoreLocal(TokenPosition::kNoSource, scopes()->yield_jump_variable); | 
|  | instructions += Drop(); | 
|  | instructions += LoadLocal(parsed_function()->current_context_var()); | 
|  | instructions += | 
|  | StoreLocal(TokenPosition::kNoSource, scopes()->yield_context_variable); | 
|  | instructions += Drop(); | 
|  | instructions += BuildExpression();  // read expression. | 
|  | instructions += Return(TokenPosition::kNoSource); | 
|  |  | 
|  | // Note: DropTempsInstr serves as an anchor instruction. It will not | 
|  | // be linked into the resulting graph. | 
|  | DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL); | 
|  | yield_continuations().Add(YieldContinuation(anchor, CurrentTryIndex())); | 
|  |  | 
|  | Fragment continuation(instructions.entry, anchor); | 
|  |  | 
|  | if (parsed_function()->function().IsAsyncClosure() || | 
|  | parsed_function()->function().IsAsyncGenClosure()) { | 
|  | // If function is async closure or async gen closure it takes three | 
|  | // parameters where the second and the third are exception and stack_trace. | 
|  | // Check if exception is non-null and rethrow it. | 
|  | // | 
|  | //   :async_op([:result, :exception, :stack_trace]) { | 
|  | //     ... | 
|  | //     Continuation<index>: | 
|  | //       if (:exception != null) rethrow(:exception, :stack_trace); | 
|  | //     ... | 
|  | //   } | 
|  | // | 
|  | LocalScope* scope = parsed_function()->node_sequence()->scope(); | 
|  | LocalVariable* exception_var = scope->VariableAt(2); | 
|  | LocalVariable* stack_trace_var = scope->VariableAt(3); | 
|  | ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw()); | 
|  | ASSERT(stack_trace_var->name().raw() == | 
|  | Symbols::StackTraceParameter().raw()); | 
|  |  | 
|  | TargetEntryInstr* no_error; | 
|  | TargetEntryInstr* error; | 
|  |  | 
|  | continuation += LoadLocal(exception_var); | 
|  | continuation += BranchIfNull(&no_error, &error); | 
|  |  | 
|  | Fragment rethrow(error); | 
|  | rethrow += LoadLocal(exception_var); | 
|  | rethrow += PushArgument(); | 
|  | rethrow += LoadLocal(stack_trace_var); | 
|  | rethrow += PushArgument(); | 
|  | rethrow += RethrowException(position, CatchClauseNode::kInvalidTryIndex); | 
|  | Drop(); | 
|  |  | 
|  | continuation = Fragment(continuation.entry, no_error); | 
|  | } | 
|  |  | 
|  | return continuation; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() { | 
|  | intptr_t kernel_position_no_tag = ReaderOffset() + data_program_offset_; | 
|  | LocalVariable* variable = LookupVariable(kernel_position_no_tag); | 
|  |  | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kType); | 
|  | String& name = H.DartSymbolObfuscate(helper.name_index_); | 
|  | AbstractType& type = T.BuildType();  // read type. | 
|  | Tag tag = ReadTag();                 // read (first part of) initializer. | 
|  |  | 
|  | Fragment instructions; | 
|  | if (tag == kNothing) { | 
|  | instructions += NullConstant(); | 
|  | } else { | 
|  | if (helper.IsConst()) { | 
|  | const Instance& constant_value = constant_evaluator_.EvaluateExpression( | 
|  | ReaderOffset());  // read initializer form current position. | 
|  | variable->SetConstValue(constant_value); | 
|  | instructions += Constant(constant_value); | 
|  | SkipExpression();  // skip initializer. | 
|  | } else { | 
|  | // Initializer | 
|  | instructions += BuildExpression();  // read (actual) initializer. | 
|  | instructions += CheckVariableTypeInCheckedMode(type, name); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Use position of equal sign if it exists. If the equal sign does not exist | 
|  | // use the position of the identifier. | 
|  | TokenPosition debug_position = | 
|  | Utils::Maximum(helper.position_, helper.equals_position_); | 
|  | if (NeedsDebugStepCheck(stack(), debug_position)) { | 
|  | instructions = DebugStepCheck(debug_position) + instructions; | 
|  | } | 
|  | instructions += StoreLocal(helper.position_, variable); | 
|  | instructions += Drop(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration() { | 
|  | TokenPosition position = ReadPosition();  // read position. | 
|  | intptr_t variable_offset = ReaderOffset() + data_program_offset_; | 
|  |  | 
|  | // read variable declaration. | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd); | 
|  |  | 
|  | Fragment instructions = DebugStepCheck(position); | 
|  | instructions += BuildFunctionNode(position, helper.name_index_); | 
|  | instructions += StoreLocal(position, LookupVariable(variable_offset)); | 
|  | instructions += Drop(); | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | Fragment StreamingFlowGraphBuilder::BuildFunctionNode( | 
|  | TokenPosition parent_position, | 
|  | StringIndex name_index) { | 
|  | intptr_t offset = ReaderOffset(); | 
|  |  | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); | 
|  | TokenPosition position = function_node_helper.position_; | 
|  |  | 
|  | bool declaration = name_index >= 0; | 
|  |  | 
|  | if (declaration) { | 
|  | position = parent_position; | 
|  | } | 
|  | if (!position.IsReal()) { | 
|  | // Positions has to be unique in regards to the parent. | 
|  | // A non-real at this point is probably -1, we cannot blindly use that | 
|  | // as others might use it too. Create a new dummy non-real TokenPosition. | 
|  | position = TokenPosition(offset).ToSynthetic(); | 
|  | } | 
|  |  | 
|  | // The VM has a per-isolate table of functions indexed by the enclosing | 
|  | // function and token position. | 
|  | Function& function = Function::ZoneHandle(Z); | 
|  |  | 
|  | // NOTE: This is not TokenPosition in the general sense! | 
|  | function = I->LookupClosureFunction(parsed_function()->function(), position); | 
|  | if (function.IsNull()) { | 
|  | for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) { | 
|  | if (scopes()->function_scopes[i].kernel_offset != offset) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const String* name; | 
|  | if (declaration) { | 
|  | name = &H.DartSymbolObfuscate(name_index); | 
|  | } else { | 
|  | name = &Symbols::AnonymousClosure(); | 
|  | } | 
|  | // NOTE: This is not TokenPosition in the general sense! | 
|  | function = Function::NewClosureFunction( | 
|  | *name, parsed_function()->function(), position); | 
|  |  | 
|  | function.set_is_debuggable(function_node_helper.dart_async_marker_ == | 
|  | FunctionNodeHelper::kSync); | 
|  | switch (function_node_helper.dart_async_marker_) { | 
|  | case FunctionNodeHelper::kSyncStar: | 
|  | function.set_modifier(RawFunction::kSyncGen); | 
|  | break; | 
|  | case FunctionNodeHelper::kAsync: | 
|  | function.set_modifier(RawFunction::kAsync); | 
|  | function.set_is_inlinable(!FLAG_causal_async_stacks); | 
|  | break; | 
|  | case FunctionNodeHelper::kAsyncStar: | 
|  | function.set_modifier(RawFunction::kAsyncGen); | 
|  | function.set_is_inlinable(!FLAG_causal_async_stacks); | 
|  | break; | 
|  | default: | 
|  | // no special modifier | 
|  | break; | 
|  | } | 
|  | function.set_is_generated_body(function_node_helper.async_marker_ == | 
|  | FunctionNodeHelper::kSyncYielding); | 
|  | if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { | 
|  | function.set_is_inlinable(!FLAG_causal_async_stacks); | 
|  | } | 
|  |  | 
|  | function.set_end_token_pos(function_node_helper.end_position_); | 
|  | LocalScope* scope = scopes()->function_scopes[i].scope; | 
|  | const ContextScope& context_scope = ContextScope::Handle( | 
|  | Z, scope->PreserveOuterScope(flow_graph_builder_->context_depth_)); | 
|  | function.set_context_scope(context_scope); | 
|  | function.set_kernel_offset(offset); | 
|  | SetupFunctionParameters(active_class(), Class::Handle(Z), function, | 
|  | false,  // is_method | 
|  | true,   // is_closure | 
|  | &function_node_helper); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); | 
|  |  | 
|  | // Finalize function type. | 
|  | Type& signature_type = Type::Handle(Z, function.SignatureType()); | 
|  | signature_type ^= | 
|  | ClassFinalizer::FinalizeType(*active_class()->klass, signature_type); | 
|  | function.SetSignatureType(signature_type); | 
|  |  | 
|  | I->AddClosureFunction(function); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); | 
|  |  | 
|  | const Class& closure_class = | 
|  | Class::ZoneHandle(Z, I->object_store()->closure_class()); | 
|  | ASSERT(!closure_class.IsNull()); | 
|  | Fragment instructions = | 
|  | flow_graph_builder_->AllocateObject(closure_class, function); | 
|  | LocalVariable* closure = MakeTemporary(); | 
|  |  | 
|  | // The function signature can have uninstantiated class type parameters. | 
|  | if (!function.HasInstantiatedSignature(kCurrentClass)) { | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += LoadInstantiatorTypeArguments(); | 
|  | instructions += flow_graph_builder_->StoreInstanceField( | 
|  | TokenPosition::kNoSource, | 
|  | Closure::instantiator_type_arguments_offset()); | 
|  | } | 
|  |  | 
|  | // TODO(30455): We only need to save these if the closure uses any captured | 
|  | // type parameters. | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += LoadFunctionTypeArguments(); | 
|  | instructions += flow_graph_builder_->StoreInstanceField( | 
|  | TokenPosition::kNoSource, Closure::function_type_arguments_offset()); | 
|  |  | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += Constant(Object::empty_type_arguments()); | 
|  | instructions += flow_graph_builder_->StoreInstanceField( | 
|  | TokenPosition::kNoSource, Closure::delayed_type_arguments_offset()); | 
|  |  | 
|  | // Store the function and the context in the closure. | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += Constant(function); | 
|  | instructions += flow_graph_builder_->StoreInstanceField( | 
|  | TokenPosition::kNoSource, Closure::function_offset()); | 
|  |  | 
|  | instructions += LoadLocal(closure); | 
|  | instructions += LoadLocal(parsed_function()->current_context_var()); | 
|  | instructions += flow_graph_builder_->StoreInstanceField( | 
|  | TokenPosition::kNoSource, Closure::context_offset()); | 
|  |  | 
|  | return instructions; | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::LoadAndSetupTypeParameters( | 
|  | ActiveClass* active_class, | 
|  | const Object& set_on, | 
|  | intptr_t type_parameter_count, | 
|  | const Function& parameterized_function) { | 
|  | ASSERT(type_parameter_count >= 0); | 
|  | if (type_parameter_count == 0) { | 
|  | return; | 
|  | } | 
|  | ASSERT(set_on.IsClass() || set_on.IsFunction()); | 
|  | bool set_on_class = set_on.IsClass(); | 
|  | ASSERT(set_on_class == parameterized_function.IsNull()); | 
|  |  | 
|  | // First setup the type parameters, so if any of the following code uses it | 
|  | // (in a recursive way) we're fine. | 
|  | TypeArguments& type_parameters = TypeArguments::Handle(Z); | 
|  | TypeParameter& parameter = TypeParameter::Handle(Z); | 
|  | const Type& null_bound = Type::Handle(Z); | 
|  |  | 
|  | // Step a) Create array of [TypeParameter] objects (without bound). | 
|  | type_parameters = TypeArguments::New(type_parameter_count); | 
|  | { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | for (intptr_t i = 0; i < type_parameter_count; i++) { | 
|  | TypeParameterHelper helper(this); | 
|  | helper.Finish(); | 
|  | parameter = TypeParameter::New( | 
|  | set_on_class ? *active_class->klass : Class::Handle(Z), | 
|  | parameterized_function, i, | 
|  | H.DartSymbolObfuscate(helper.name_index_),  // read ith name index. | 
|  | null_bound, TokenPosition::kNoSource); | 
|  | type_parameters.SetTypeAt(i, parameter); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (set_on.IsClass()) { | 
|  | Class::Cast(set_on).set_type_parameters(type_parameters); | 
|  | } else { | 
|  | Function::Cast(set_on).set_type_parameters(type_parameters); | 
|  | } | 
|  |  | 
|  | const Function* enclosing = NULL; | 
|  | if (!parameterized_function.IsNull()) { | 
|  | enclosing = ¶meterized_function; | 
|  | } | 
|  | ActiveTypeParametersScope scope(active_class, enclosing, type_parameters, Z); | 
|  |  | 
|  | // Step b) Fill in the bounds of all [TypeParameter]s. | 
|  | for (intptr_t i = 0; i < type_parameter_count; i++) { | 
|  | TypeParameterHelper helper(this); | 
|  | helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound); | 
|  |  | 
|  | // TODO(github.com/dart-lang/kernel/issues/42): This should be handled | 
|  | // by the frontend. | 
|  | parameter ^= type_parameters.TypeAt(i); | 
|  | const Tag tag = PeekTag();  // peek ith bound type. | 
|  | if (tag == kDynamicType) { | 
|  | SkipDartType();  // read ith bound. | 
|  | parameter.set_bound(Type::Handle(Z, I->object_store()->object_type())); | 
|  | } else { | 
|  | AbstractType& bound = | 
|  | T.BuildTypeWithoutFinalization();  // read ith bound. | 
|  | if (bound.IsMalformedOrMalbounded()) { | 
|  | bound = I->object_store()->object_type(); | 
|  | } | 
|  | parameter.set_bound(bound); | 
|  | } | 
|  |  | 
|  | helper.Finish(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::SetupFunctionParameters( | 
|  | ActiveClass* active_class, | 
|  | const Class& klass, | 
|  | const Function& function, | 
|  | bool is_method, | 
|  | bool is_closure, | 
|  | FunctionNodeHelper* function_node_helper) { | 
|  | ASSERT(!(is_method && is_closure)); | 
|  | bool is_factory = function.IsFactory(); | 
|  | intptr_t extra_parameters = (is_method || is_closure || is_factory) ? 1 : 0; | 
|  |  | 
|  | if (!is_factory) { | 
|  | LoadAndSetupTypeParameters(active_class, function, ReadListLength(), | 
|  | function); | 
|  | function_node_helper->SetJustRead(FunctionNodeHelper::kTypeParameters); | 
|  | } | 
|  |  | 
|  | ActiveTypeParametersScope scope( | 
|  | active_class, &function, | 
|  | TypeArguments::Handle(Z, function.type_parameters()), Z); | 
|  |  | 
|  | function_node_helper->ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  |  | 
|  | intptr_t required_parameter_count = | 
|  | function_node_helper->required_parameter_count_; | 
|  | intptr_t total_parameter_count = function_node_helper->total_parameter_count_; | 
|  |  | 
|  | intptr_t positional_parameter_count = ReadListLength();  // read list length. | 
|  |  | 
|  | intptr_t named_parameter_count = | 
|  | total_parameter_count - positional_parameter_count; | 
|  |  | 
|  | function.set_num_fixed_parameters(extra_parameters + | 
|  | required_parameter_count); | 
|  | if (named_parameter_count > 0) { | 
|  | function.SetNumOptionalParameters(named_parameter_count, false); | 
|  | } else { | 
|  | function.SetNumOptionalParameters( | 
|  | positional_parameter_count - required_parameter_count, true); | 
|  | } | 
|  | intptr_t parameter_count = extra_parameters + total_parameter_count; | 
|  | function.set_parameter_types( | 
|  | Array::Handle(Z, Array::New(parameter_count, Heap::kOld))); | 
|  | function.set_parameter_names( | 
|  | Array::Handle(Z, Array::New(parameter_count, Heap::kOld))); | 
|  | intptr_t pos = 0; | 
|  | if (is_method) { | 
|  | ASSERT(!klass.IsNull()); | 
|  | function.SetParameterTypeAt(pos, H.GetCanonicalType(klass)); | 
|  | function.SetParameterNameAt(pos, Symbols::This()); | 
|  | pos++; | 
|  | } else if (is_closure) { | 
|  | function.SetParameterTypeAt(pos, AbstractType::dynamic_type()); | 
|  | function.SetParameterNameAt(pos, Symbols::ClosureParameter()); | 
|  | pos++; | 
|  | } else if (is_factory) { | 
|  | function.SetParameterTypeAt(pos, AbstractType::dynamic_type()); | 
|  | function.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter()); | 
|  | pos++; | 
|  | } | 
|  |  | 
|  | for (intptr_t i = 0; i < positional_parameter_count; ++i, ++pos) { | 
|  | // Read ith variable declaration. | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kType); | 
|  | const AbstractType& type = T.BuildTypeWithoutFinalization();  // read type. | 
|  | Tag tag = ReadTag();  // read (first part of) initializer. | 
|  | if (tag == kSomething) { | 
|  | SkipExpression();  // read (actual) initializer. | 
|  | } | 
|  |  | 
|  | function.SetParameterTypeAt( | 
|  | pos, type.IsMalformed() ? Type::dynamic_type() : type); | 
|  | function.SetParameterNameAt(pos, H.DartSymbolObfuscate(helper.name_index_)); | 
|  | } | 
|  |  | 
|  | intptr_t named_parameter_count_check = ReadListLength();  // read list length. | 
|  | ASSERT(named_parameter_count_check == named_parameter_count); | 
|  | for (intptr_t i = 0; i < named_parameter_count; ++i, ++pos) { | 
|  | // Read ith variable declaration. | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kType); | 
|  | const AbstractType& type = T.BuildTypeWithoutFinalization();  // read type. | 
|  | Tag tag = ReadTag();  // read (first part of) initializer. | 
|  | if (tag == kSomething) { | 
|  | SkipExpression();  // read (actual) initializer. | 
|  | } | 
|  |  | 
|  | function.SetParameterTypeAt( | 
|  | pos, type.IsMalformed() ? Type::dynamic_type() : type); | 
|  | function.SetParameterNameAt(pos, H.DartSymbolObfuscate(helper.name_index_)); | 
|  | } | 
|  |  | 
|  | function_node_helper->SetJustRead(FunctionNodeHelper::kNamedParameters); | 
|  |  | 
|  | // The result type for generative constructors has already been set. | 
|  | if (!function.IsGenerativeConstructor()) { | 
|  | const AbstractType& return_type = | 
|  | T.BuildTypeWithoutFinalization();  // read return type. | 
|  | function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type() | 
|  | : return_type); | 
|  | function_node_helper->SetJustRead(FunctionNodeHelper::kReturnType); | 
|  | } | 
|  | } | 
|  |  | 
|  | RawObject* StreamingFlowGraphBuilder::BuildParameterDescriptor( | 
|  | intptr_t kernel_offset) { | 
|  | SetOffset(kernel_offset); | 
|  | ReadUntilFunctionNode();  // read until function node. | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding( | 
|  | FunctionNodeHelper::kPositionalParameters); | 
|  | intptr_t param_count = function_node_helper.total_parameter_count_; | 
|  | intptr_t positional_count = ReadListLength();  // read list length. | 
|  | intptr_t named_parameter_count = param_count - positional_count; | 
|  |  | 
|  | const Array& param_descriptor = Array::Handle( | 
|  | Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld)); | 
|  | for (intptr_t i = 0; i < param_count; ++i) { | 
|  | const intptr_t entry_start = i * Parser::kParameterEntrySize; | 
|  |  | 
|  | if (i == positional_count) { | 
|  | intptr_t named_parameter_count_check = | 
|  | ReadListLength();  // read list length. | 
|  | ASSERT(named_parameter_count_check == named_parameter_count); | 
|  | } | 
|  |  | 
|  | // Read ith variable declaration. | 
|  | VariableDeclarationHelper helper(this); | 
|  | helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer); | 
|  | param_descriptor.SetAt(entry_start + Parser::kParameterIsFinalOffset, | 
|  | helper.IsFinal() ? Bool::True() : Bool::False()); | 
|  |  | 
|  | Tag tag = ReadTag();  // read (first part of) initializer. | 
|  | if (tag == kSomething) { | 
|  | // this will (potentially) read the initializer, but reset the position. | 
|  | Instance& constant = | 
|  | constant_evaluator_.EvaluateExpression(ReaderOffset()); | 
|  | SkipExpression();  // read (actual) initializer. | 
|  | param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset, | 
|  | constant); | 
|  | } else { | 
|  | param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset, | 
|  | Object::null_instance()); | 
|  | } | 
|  |  | 
|  | param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset, | 
|  | /* Issue(28434): Missing parameter metadata. */ | 
|  | Object::null_instance()); | 
|  | } | 
|  | return param_descriptor.raw(); | 
|  | } | 
|  |  | 
|  | RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(intptr_t kernel_offset) { | 
|  | SetOffset(kernel_offset); | 
|  | const Tag tag = PeekTag(); | 
|  |  | 
|  | if (tag == kClass) { | 
|  | ClassHelper class_helper(this); | 
|  | class_helper.ReadUntilExcluding(ClassHelper::kAnnotations); | 
|  | } else if (tag == kProcedure) { | 
|  | ProcedureHelper procedure_helper(this); | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations); | 
|  | } else if (tag == kField) { | 
|  | FieldHelper field_helper(this); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kAnnotations); | 
|  | } else if (tag == kConstructor) { | 
|  | ConstructorHelper constructor_helper(this); | 
|  | constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations); | 
|  | } else { | 
|  | FATAL("No support for metadata on this type of kernel node\n"); | 
|  | } | 
|  |  | 
|  | intptr_t list_length = ReadListLength();  // read list length. | 
|  | const Array& metadata_values = | 
|  | Array::Handle(Z, Array::New(list_length, H.allocation_space())); | 
|  | for (intptr_t i = 0; i < list_length; ++i) { | 
|  | // this will (potentially) read the expression, but reset the position. | 
|  | Instance& value = constant_evaluator_.EvaluateExpression(ReaderOffset()); | 
|  | SkipExpression();  // read (actual) initializer. | 
|  | metadata_values.SetAt(i, value); | 
|  | } | 
|  |  | 
|  | return metadata_values.raw(); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::CollectTokenPositionsFor( | 
|  | intptr_t script_index, | 
|  | intptr_t initial_script_index, | 
|  | intptr_t kernel_offset, | 
|  | GrowableArray<intptr_t>* record_token_positions_in, | 
|  | GrowableArray<intptr_t>* record_yield_positions_in) { | 
|  | record_token_positions_into_ = record_token_positions_in; | 
|  | record_yield_positions_into_ = record_yield_positions_in; | 
|  | record_for_script_id_ = script_index; | 
|  | current_script_id_ = initial_script_index; | 
|  |  | 
|  | SetOffset(kernel_offset); | 
|  |  | 
|  | const Tag tag = PeekTag(); | 
|  | if (tag == kProcedure) { | 
|  | ProcedureHelper procedure_helper(this); | 
|  | procedure_helper.ReadUntilExcluding(ProcedureHelper::kEnd); | 
|  | } else if (tag == kConstructor) { | 
|  | ConstructorHelper constructor_helper(this); | 
|  | constructor_helper.ReadUntilExcluding(ConstructorHelper::kEnd); | 
|  | } else if (tag == kFunctionNode) { | 
|  | FunctionNodeHelper function_node_helper(this); | 
|  | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); | 
|  | } else if (tag == kField) { | 
|  | FieldHelper field_helper(this); | 
|  | field_helper.ReadUntilExcluding(FieldHelper::kEnd); | 
|  | } else if (tag == kClass) { | 
|  | ClassHelper class_helper(this); | 
|  | class_helper.ReadUntilExcluding(ClassHelper::kEnd); | 
|  | } else { | 
|  | ReportUnexpectedTag("a class or a member", tag); | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | record_token_positions_into_ = NULL; | 
|  | record_yield_positions_into_ = NULL; | 
|  | record_for_script_id_ = -1; | 
|  | } | 
|  |  | 
|  | intptr_t StreamingFlowGraphBuilder::SourceTableSize() { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | intptr_t library_count = reader_.ReadFromIndexNoReset( | 
|  | reader_.size(), LibraryCountFieldCountFromEnd, 1, 0); | 
|  | intptr_t source_table_offset = reader_.ReadFromIndexNoReset( | 
|  | reader_.size(), | 
|  | LibraryCountFieldCountFromEnd + 1 + library_count + 1 + | 
|  | SourceTableFieldCountFromFirstLibraryOffset, | 
|  | 1, 0); | 
|  | SetOffset(source_table_offset);  // read source table offset. | 
|  | return reader_.ReadUInt32();     // read source table size. | 
|  | } | 
|  |  | 
|  | intptr_t StreamingFlowGraphBuilder::GetOffsetForSourceInfo(intptr_t index) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | intptr_t library_count = reader_.ReadFromIndexNoReset( | 
|  | reader_.size(), LibraryCountFieldCountFromEnd, 1, 0); | 
|  | intptr_t source_table_offset = reader_.ReadFromIndexNoReset( | 
|  | reader_.size(), | 
|  | LibraryCountFieldCountFromEnd + 1 + library_count + 1 + | 
|  | SourceTableFieldCountFromFirstLibraryOffset, | 
|  | 1, 0); | 
|  | intptr_t next_field_offset = reader_.ReadUInt32(); | 
|  | SetOffset(source_table_offset); | 
|  | intptr_t size = reader_.ReadUInt32();  // read source table size. | 
|  |  | 
|  | return reader_.ReadFromIndexNoReset(next_field_offset, 0, size, index); | 
|  | } | 
|  |  | 
|  | String& StreamingFlowGraphBuilder::SourceTableUriFor(intptr_t index) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SetOffset(GetOffsetForSourceInfo(index)); | 
|  | intptr_t size = ReadUInt();  // read uri List<byte> size. | 
|  | return H.DartString(reader_.CopyDataIntoZone(Z, ReaderOffset(), size), size, | 
|  | Heap::kOld); | 
|  | } | 
|  |  | 
|  | String& StreamingFlowGraphBuilder::GetSourceFor(intptr_t index) { | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SetOffset(GetOffsetForSourceInfo(index)); | 
|  | SkipBytes(ReadUInt());       // skip uri. | 
|  | intptr_t size = ReadUInt();  // read source List<byte> size. | 
|  | return H.DartString(reader_.CopyDataIntoZone(Z, ReaderOffset(), size), size, | 
|  | Heap::kOld); | 
|  | } | 
|  |  | 
|  | RawTypedData* StreamingFlowGraphBuilder::GetLineStartsFor(intptr_t index) { | 
|  | // Line starts are delta encoded. So get the max delta first so that we | 
|  | // can store them as tighly as possible. | 
|  | AlternativeReadingScope alt(&reader_); | 
|  | SetOffset(GetOffsetForSourceInfo(index)); | 
|  | SkipBytes(ReadUInt());                         // skip uri. | 
|  | SkipBytes(ReadUInt());                         // skip source. | 
|  | const intptr_t line_start_count = ReadUInt();  // read number of line start | 
|  | // entries. | 
|  | MallocGrowableArray<int32_t> line_starts_array; | 
|  |  | 
|  | intptr_t max_delta = 0; | 
|  | for (intptr_t i = 0; i < line_start_count; ++i) { | 
|  | int32_t delta = ReadUInt(); | 
|  | line_starts_array.Add(delta); | 
|  | if (delta > max_delta) { | 
|  | max_delta = delta; | 
|  | } | 
|  | } | 
|  |  | 
|  | intptr_t cid; | 
|  | if (max_delta <= kMaxInt8) { | 
|  | cid = kTypedDataInt8ArrayCid; | 
|  | } else if (max_delta <= kMaxInt16) { | 
|  | cid = kTypedDataInt16ArrayCid; | 
|  | } else { | 
|  | cid = kTypedDataInt32ArrayCid; | 
|  | } | 
|  |  | 
|  | TypedData& line_starts_data = | 
|  | TypedData::Handle(Z, TypedData::New(cid, line_start_count, Heap::kOld)); | 
|  | for (intptr_t j = 0; j < line_start_count; ++j) { | 
|  | int32_t line_start = line_starts_array[j]; | 
|  | switch (cid) { | 
|  | case kTypedDataInt8ArrayCid: | 
|  | line_starts_data.SetInt8(j, static_cast<int8_t>(line_start)); | 
|  | break; | 
|  | case kTypedDataInt16ArrayCid: | 
|  | line_starts_data.SetInt16(j << 1, static_cast<int16_t>(line_start)); | 
|  | break; | 
|  | case kTypedDataInt32ArrayCid: | 
|  | line_starts_data.SetInt32(j << 2, line_start); | 
|  | break; | 
|  | default: | 
|  | UNREACHABLE(); | 
|  | } | 
|  | } | 
|  | return line_starts_data.raw(); | 
|  | } | 
|  |  | 
|  | void StreamingFlowGraphBuilder::EnsureMetadataIsScanned() { | 
|  | // Scan metadata mappings only once. | 
|  | if (metadata_scanned_) { | 
|  | return; | 
|  | } | 
|  | metadata_scanned_ = true; | 
|  |  | 
|  | const intptr_t kUInt32Size = 4; | 
|  | Reader reader(H.metadata_mappings()); | 
|  | if (reader.size() == 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Scan through metadata mappings in reverse direction. | 
|  |  | 
|  | // Read metadataMappings length. | 
|  | intptr_t offset = reader.size() - kUInt32Size; | 
|  | uint32_t metadata_num = reader.ReadUInt32At(offset); | 
|  |  | 
|  | if (metadata_num == 0) { | 
|  | ASSERT(H.metadata_mappings().LengthInBytes() == kUInt32Size); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Read metadataMappings elements. | 
|  | for (uint32_t i = 0; i < metadata_num; ++i) { | 
|  | // Read nodeReferences length. | 
|  | offset -= kUInt32Size; | 
|  | uint32_t node_references_num = reader.ReadUInt32At(offset); | 
|  |  | 
|  | // Skip nodeReferences and read nodeOffsetToMetadataOffset length. | 
|  | offset -= node_references_num * kUInt32Size + kUInt32Size; | 
|  | uint32_t mappings_num = reader.ReadUInt32At(offset); | 
|  |  | 
|  | // Skip nodeOffsetToMetadataOffset and read tag. | 
|  | offset -= mappings_num * 2 * kUInt32Size + kUInt32Size; | 
|  | StringIndex tag = StringIndex(reader.ReadUInt32At(offset)); | 
|  |  | 
|  | // Check recognized metadata | 
|  | if (H.StringEquals(tag, DirectCallMetadataHelper::tag())) { | 
|  | ASSERT(node_references_num == 0); | 
|  |  | 
|  | if (mappings_num > 0) { | 
|  | if (!FLAG_precompiled_mode) { | 
|  | FATAL("DirectCallMetadata is allowed in precompiled mode only"); | 
|  | } | 
|  | direct_call_metadata_helper_.SetMetadataMappings(offset + kUInt32Size, | 
|  | mappings_num); | 
|  | } | 
|  | } else if (H.StringEquals(tag, InferredTypeMetadataHelper::tag())) { | 
|  | ASSERT(node_references_num == 0); | 
|  |  | 
|  | if (mappings_num > 0) { | 
|  | if (!FLAG_precompiled_mode) { | 
|  | FATAL("InferredTypeMetadata is allowed in precompiled mode only"); | 
|  | } | 
|  | inferred_type_metadata_helper_.SetMetadataMappings(offset + kUInt32Size, | 
|  | mappings_num); | 
|  | } | 
|  | } else if (H.StringEquals(tag, ProcedureAttributesMetadataHelper::tag())) { | 
|  | ASSERT(node_references_num == 0); | 
|  |  | 
|  | if (mappings_num > 0) { | 
|  | if (!FLAG_precompiled_mode) { | 
|  | FATAL( | 
|  | "ProcedureAttributesMetadata is allowed in precompiled mode " | 
|  | "only"); | 
|  | } | 
|  | procedure_attributes_metadata_helper_.SetMetadataMappings( | 
|  | offset + kUInt32Size, mappings_num); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | const Array& ConstantHelper::ReadConstantTable() { | 
|  | const intptr_t number_of_constants = builder_.ReadUInt(); | 
|  | if (number_of_constants == 0) { | 
|  | return Array::Handle(Z, Array::null()); | 
|  | } | 
|  |  | 
|  | const Library& corelib = Library::Handle(Z, Library::CoreLibrary()); | 
|  | const Class& list_class = | 
|  | Class::Handle(Z, corelib.LookupClassAllowPrivate(Symbols::_List())); | 
|  |  | 
|  | // Eagerly finalize _ImmutableList (instead of doing it on every list | 
|  | // constant). | 
|  | temp_class_ = I->class_table()->At(kImmutableArrayCid); | 
|  | temp_object_ = temp_class_.EnsureIsFinalized(H.thread()); | 
|  | ASSERT(temp_object_.IsNull()); | 
|  |  | 
|  | const Array& constants = | 
|  | Array::Handle(Z, Array::New(number_of_constants, Heap::kOld)); | 
|  | for (intptr_t i = 0; i < number_of_constants; ++i) { | 
|  | const intptr_t constant_tag = builder_.ReadByte(); | 
|  | switch (constant_tag) { | 
|  | case kNullConstant: | 
|  | temp_instance_ = Instance::null(); | 
|  | break; | 
|  | case kBoolConstant: | 
|  | temp_instance_ = builder_.ReadByte() == 1 ? Object::bool_true().raw() | 
|  | : Object::bool_false().raw(); | 
|  | break; | 
|  | case kIntConstant: { | 
|  | temp_instance_ = const_evaluator_ | 
|  | .EvaluateExpression(builder_.ReaderOffset(), | 
|  | false /* reset position */) | 
|  | .raw(); | 
|  | break; | 
|  | } | 
|  | case kDoubleConstant: { | 
|  | temp_instance_ = Double::New( | 
|  | H.DartString(builder_.ReadStringReference()), Heap::kOld); | 
|  | temp_instance_ = H.Canonicalize(temp_instance_); | 
|  | break; | 
|  | } | 
|  | case kStringConstant: { | 
|  | temp_instance_ = | 
|  | H.Canonicalize(H.DartString(builder_.ReadStringReference())); | 
|  | break; | 
|  | } | 
|  | case kListConstant: { | 
|  | temp_type_arguments_ = TypeArguments::New(1, Heap::kOld); | 
|  | const AbstractType& type = type_translator_.BuildType(); | 
|  | temp_type_arguments_.SetTypeAt(0, type); | 
|  | InstantiateTypeArguments(list_class, &temp_type_arguments_); | 
|  |  | 
|  | const intptr_t length = builder_.ReadUInt(); | 
|  | temp_array_ = ImmutableArray::New(length, Heap::kOld); | 
|  | temp_array_.SetTypeArguments(temp_type_arguments_); | 
|  | for (intptr_t j = 0; j < length; ++j) { | 
|  | const intptr_t entry_index = builder_.ReadUInt(); | 
|  | ASSERT(entry_index < i);  // We have a DAG! | 
|  | temp_object_ = constants.At(entry_index); | 
|  | temp_array_.SetAt(j, temp_object_); | 
|  | } | 
|  |  | 
|  | temp_instance_ = H.Canonicalize(temp_array_); | 
|  | break; | 
|  | } | 
|  | case kInstanceConstant: { | 
|  | temp_class_ = | 
|  | H.LookupClassByKernelClass(builder_.ReadCanonicalNameReference()); | 
|  | temp_object_ = temp_class_.EnsureIsFinalized(H.thread()); | 
|  | ASSERT(temp_object_.IsNull()); | 
|  |  | 
|  | temp_instance_ = Instance::New(temp_class_, Heap::kOld); | 
|  |  | 
|  | const intptr_t number_of_type_arguments = builder_.ReadUInt(); | 
|  | if (temp_class_.NumTypeArguments() > 0) { | 
|  | temp_type_arguments_ = | 
|  | TypeArguments::New(number_of_type_arguments, Heap::kOld); | 
|  | for (intptr_t j = 0; j < number_of_type_arguments; ++j) { | 
|  | temp_type_arguments_.SetTypeAt(j, type_translator_.BuildType()); | 
|  | } | 
|  | InstantiateTypeArguments(temp_class_, &temp_type_arguments_); | 
|  | temp_instance_.SetTypeArguments(temp_type_arguments_); | 
|  | } else { | 
|  | ASSERT(number_of_type_arguments == 0); | 
|  | } | 
|  |  | 
|  | const intptr_t number_of_fields = builder_.ReadUInt(); | 
|  | for (intptr_t j = 0; j < number_of_fields; ++j) { | 
|  | temp_field_ = | 
|  | H.LookupFieldByKernelField(builder_.ReadCanonicalNameReference()); | 
|  | const intptr_t entry_index = builder_.ReadUInt(); | 
|  | ASSERT(entry_index < i);  // We have a DAG! | 
|  | temp_object_ = constants.At(entry_index); | 
|  | temp_instance_.SetField(temp_field_, temp_object_); | 
|  | } | 
|  |  | 
|  | temp_instance_ = H.Canonicalize(temp_instance_); | 
|  | break; | 
|  | } | 
|  | case kTearOffConstant: { | 
|  | const NameIndex index = builder_.ReadCanonicalNameReference(); | 
|  | NameIndex lib_index = index; | 
|  | while (!H.IsLibrary(lib_index)) { | 
|  | lib_index = H.CanonicalNameParent(lib_index); | 
|  | } | 
|  | ASSERT(H.IsLibrary(lib_index)); | 
|  | if (lib_index == skip_vmservice_library_) { | 
|  | temp_instance_ = Instance::null(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | temp_function_ = H.LookupStaticMethodByKernelProcedure(index); | 
|  | temp_function_ = temp_function_.ImplicitClosureFunction(); | 
|  | temp_instance_ = temp_function_.ImplicitStaticClosure(); | 
|  | temp_instance_ = H.Canonicalize(temp_instance_); | 
|  | break; | 
|  | } | 
|  | case kTypeLiteralConstant: { | 
|  | temp_instance_ = type_translator_.BuildType().raw(); | 
|  | break; | 
|  | } | 
|  | case kMapConstant: | 
|  | // Note: This is already lowered to InstanceConstant/ListConstant. | 
|  | UNREACHABLE(); | 
|  | break; | 
|  | default: | 
|  | UNREACHABLE(); | 
|  | } | 
|  | constants.SetAt(i, temp_instance_); | 
|  | } | 
|  | return constants; | 
|  | } | 
|  |  | 
|  | void ConstantHelper::InstantiateTypeArguments(const Class& receiver_class, | 
|  | TypeArguments* type_arguments) { | 
|  | // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to | 
|  | // finalize the argument types. | 
|  | // (This can for example make the [type_arguments] vector larger) | 
|  | temp_type_ = | 
|  | Type::New(receiver_class, *type_arguments, TokenPosition::kNoSource); | 
|  | temp_type_ = ClassFinalizer::FinalizeType(*active_class_->klass, temp_type_, | 
|  | ClassFinalizer::kCanonicalize); | 
|  | *type_arguments = temp_type_.arguments(); | 
|  | } | 
|  |  | 
|  | }  // namespace kernel | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // !defined(DART_PRECOMPILED_RUNTIME) |