[vm] Refactoring: move StreamingScopeBuilder out of kernel_binary_flowgraph
After previous refactoring, StreamingScopeBuilder no longer depends on
StreamingFlowGraphBuilder.
This CL moves StreamingScopeBuilder to a separate file
vm/compiler/frontend/scope_builder{.h, .cc}.
Also:
* StreamingScopeBuilder is renamed to ScopeBuilder.
* IntMap is moved to hash_map.h.
* Minor cleanup of unused forward declarations and friend classes.
Change-Id: I5e780a53f37935c0a1d563d4fbaec3a92ae13d6a
Reviewed-on: https://dart-review.googlesource.com/63692
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index d82b788..a583585 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -14,8 +14,6 @@
namespace dart {
-class FlowGraphBuilder;
-class ValueInliningContext;
class VariableLivenessAnalysis;
class BlockIterator : public ValueObject {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 9ebff20..f6bff3f 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -27,7 +27,6 @@
class Definition;
class Environment;
class FlowGraph;
-class FlowGraphBuilder;
class FlowGraphCompiler;
class FlowGraphVisitor;
class Instruction;
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index 5f6b3f9..578dc45 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -87,6 +87,8 @@
"frontend/kernel_translation_helper.h",
"frontend/prologue_builder.cc",
"frontend/prologue_builder.h",
+ "frontend/scope_builder.cc",
+ "frontend/scope_builder.h",
"intrinsifier.cc",
"intrinsifier.h",
"intrinsifier_arm.cc",
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index bb21e9e..70d956b 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -25,1675 +25,6 @@
#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());
-}
-
-// Returns true if the given method can skip type checks for all arguments
-// that are not covariant or generic covariant in its implementation.
-static bool MethodCanSkipTypeChecksForNonCovariantArguments(
- const Function& method,
- const ProcedureAttributesMetadata& attrs) {
- // Dart 2 type system at non-dynamic call sites statically guarantees that
- // argument values match declarated parameter types for all non-covariant
- // and non-generic-covariant parameters. The same applies to type parameters
- // bounds for type parameters of generic functions.
- // In JIT mode we dynamically generate trampolines (dynamic invocation
- // forwarders) that perform type checks when arriving to a method from a
- // dynamic call-site.
- // In AOT mode we don't dynamically generate such trampolines but
- // instead rely on a static analysis to discover which methods can
- // be invoked dynamically.
- if (method.name() == Symbols::Call().raw()) {
- // Currently we consider all call methods to be invoked dynamically and
- // don't mangle their names.
- // TODO(vegorov) remove this once we also introduce special type checking
- // entry point for closures.
- return false;
- }
- return !FLAG_precompiled_mode || !attrs.has_dynamic_invocations;
-}
-
-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),
- helper_(
- zone_,
- &translation_helper_,
- Script::Handle(Z, parsed_function->function().script()),
- ExternalTypedData::Handle(Z,
- parsed_function->function().KernelData()),
- parsed_function->function().KernelDataProgramOffset()),
- inferred_type_metadata_helper_(&helper_),
- procedure_attributes_metadata_helper_(&helper_),
- type_translator_(&helper_,
- &active_class_,
- /*finalize=*/true) {
- H.InitFromScript(helper_.script());
- ASSERT(type_translator_.active_class_ == &active_class_);
-}
-
-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, function.GetOutermostFunction());
-
- 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(VariableIndex(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_));
-
- helper_.SetOffset(function.kernel_offset());
-
- FunctionNodeHelper function_node_helper(&helper_);
- const ProcedureAttributesMetadata attrs =
- procedure_attributes_metadata_helper_.GetProcedureAttributes(
- function.kernel_offset());
-
- switch (function.kind()) {
- case RawFunction::kClosureFunction:
- case RawFunction::kImplicitClosureFunction:
- case RawFunction::kRegularFunction:
- case RawFunction::kGetterFunction:
- case RawFunction::kSetterFunction:
- case RawFunction::kConstructor: {
- const Tag tag = helper_.PeekTag();
- helper_.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()) {
- ExternalTypedData& kernel_data =
- ExternalTypedData::Handle(Z, class_field.KernelData());
- ASSERT(!kernel_data.IsNull());
- intptr_t field_offset = class_field.kernel_offset();
- AlternativeReadingScope alt(&helper_.reader_, &kernel_data,
- field_offset);
- FieldHelper field_helper(&helper_);
- field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
- Tag initializer_tag =
- helper_.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 (MethodCanSkipTypeChecksForNonCovariantArguments(
- Function::Handle(Z, function.parent_function()), attrs)) {
- // 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 =
- kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod;
- }
- } else {
- if (function.is_static()) {
- // In static functions we don't check anything.
- type_check_mode = kTypeCheckForStaticFunction;
- } else if (MethodCanSkipTypeChecksForNonCovariantArguments(function,
- attrs)) {
- // 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()) {
- helper_.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(helper_.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 &&
- MethodCanSkipTypeChecksForNonCovariantArguments(function, attrs)) {
- FieldHelper field_helper(&helper_);
- 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::kDynamicInvocationForwarder: {
- if (helper_.PeekTag() == kField) {
-#ifdef DEBUG
- String& name = String::Handle(Z, function.name());
- ASSERT(Function::IsDynamicInvocationForwaderName(name));
- name = Function::DemangleDynamicInvocationForwarderName(name);
- ASSERT(Field::IsSetterName(name));
-#endif
- // Create [this] variable.
- const Class& klass = Class::Handle(Z, function.Owner());
- result_->this_variable =
- MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
- Symbols::This(), H.GetCanonicalType(klass));
- scope_->InsertParameterAt(0, result_->this_variable);
-
- // Create setter value variable.
- result_->setter_value = MakeVariable(
- TokenPosition::kNoSource, TokenPosition::kNoSource,
- Symbols::Value(),
- AbstractType::ZoneHandle(Z, function.ParameterTypeAt(1)));
- scope_->InsertParameterAt(1, result_->setter_value);
- } else {
- helper_.ReadUntilFunctionNode();
- function_node_helper.ReadUntilExcluding(
- FunctionNodeHelper::kPositionalParameters);
-
- // Create [this] variable.
- intptr_t pos = 0;
- Class& klass = Class::Handle(Z, function.Owner());
- result_->this_variable =
- MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
- Symbols::This(), H.GetCanonicalType(klass));
- scope_->InsertParameterAt(pos++, result_->this_variable);
-
- // Create all positional and named parameters.
- AddPositionalAndNamedParameters(
- pos, kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
- attrs);
- }
- 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(helper_.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 = helper_.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(&helper_);
- 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()) {
- ExternalTypedData& kernel_data =
- ExternalTypedData::Handle(Z, class_field.KernelData());
- ASSERT(!kernel_data.IsNull());
- intptr_t field_offset = class_field.kernel_offset();
- AlternativeReadingScope alt(&helper_.reader_, &kernel_data,
- field_offset);
- FieldHelper field_helper(&helper_);
- field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
- Tag initializer_tag = helper_.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 =
- helper_.ReadListLength(); // read initializers list length.
- for (intptr_t i = 0; i < list_length; i++) {
- VisitInitializer();
- }
-}
-
-void StreamingScopeBuilder::VisitProcedure() {
- ProcedureHelper procedure_helper(&helper_);
- procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
- if (helper_.ReadTag() == kSomething) {
- VisitFunctionNode();
- }
-}
-
-void StreamingScopeBuilder::VisitField() {
- FieldHelper field_helper(&helper_);
- field_helper.ReadUntilExcluding(FieldHelper::kType);
- VisitDartType(); // read type.
- Tag tag = helper_.ReadTag(); // read initializer (part 1).
- if (tag == kSomething) {
- VisitExpression(); // read initializer (part 2).
- }
-}
-
-void StreamingScopeBuilder::VisitFunctionNode() {
- FunctionNodeHelper function_node_helper(&helper_);
- function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
-
- intptr_t list_length =
- helper_.ReadListLength(); // read type_parameters list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- TypeParameterHelper helper(&helper_);
- helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
- VisitDartType(); // read ith bound.
- helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
- if (helper_.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 (helper_.ReadTag() == kSomething) {
- PositionScope scope(&helper_.reader_);
- VisitStatement(); // Read body
- first_body_token_position_ = helper_.reader_.min_position();
- }
-
- // Ensure that :await_jump_var, :await_ctx_var, :async_op,
- // :async_completer 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);
- }
- }
- {
- LocalVariable* temp =
- scope_->LookupVariable(Symbols::AsyncCompleter(), 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 = helper_.ReadTag();
- helper_.ReadByte(); // read isSynthetic flag.
- switch (tag) {
- case kInvalidInitializer:
- return;
- case kFieldInitializer:
- helper_.SkipCanonicalNameReference(); // read field_reference.
- VisitExpression(); // read value.
- return;
- case kSuperInitializer:
- helper_.SkipCanonicalNameReference(); // read target_reference.
- VisitArguments(); // read arguments.
- return;
- case kRedirectingInitializer:
- helper_.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 = helper_.ReadTag(&payload);
- switch (tag) {
- case kInvalidExpression:
- helper_.ReadPosition();
- helper_.SkipStringReference();
- return;
- case kVariableGet: {
- helper_.ReadPosition(); // read position.
- intptr_t variable_kernel_offset =
- helper_.ReadUInt(); // read kernel position.
- helper_.ReadUInt(); // read relative variable index.
- helper_.SkipOptionalDartType(); // read promoted type.
- LookupVariable(variable_kernel_offset);
- return;
- }
- case kSpecializedVariableGet: {
- helper_.ReadPosition(); // read position.
- intptr_t variable_kernel_offset =
- helper_.ReadUInt(); // read kernel position.
- LookupVariable(variable_kernel_offset);
- return;
- }
- case kVariableSet: {
- helper_.ReadPosition(); // read position.
- intptr_t variable_kernel_offset =
- helper_.ReadUInt(); // read kernel position.
- helper_.ReadUInt(); // read relative variable index.
- LookupVariable(variable_kernel_offset);
- VisitExpression(); // read expression.
- return;
- }
- case kSpecializedVariableSet: {
- helper_.ReadPosition(); // read position.
- intptr_t variable_kernel_offset =
- helper_.ReadUInt(); // read kernel position.
- LookupVariable(variable_kernel_offset);
- VisitExpression(); // read expression.
- return;
- }
- case kPropertyGet:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read receiver.
- helper_.SkipName(); // read name.
- // read interface_target_reference.
- helper_.SkipCanonicalNameReference();
- return;
- case kPropertySet:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read receiver.
- helper_.SkipName(); // read name.
- VisitExpression(); // read value.
- // read interface_target_reference.
- helper_.SkipCanonicalNameReference();
- return;
- case kDirectPropertyGet:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read receiver.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- return;
- case kDirectPropertySet:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read receiver.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- VisitExpression(); // read value·
- return;
- case kSuperPropertyGet:
- HandleSpecialLoad(&result_->this_variable, Symbols::This());
- helper_.ReadPosition(); // read position.
- helper_.SkipName(); // read name.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- return;
- case kSuperPropertySet:
- HandleSpecialLoad(&result_->this_variable, Symbols::This());
- helper_.ReadPosition(); // read position.
- helper_.SkipName(); // read name.
- VisitExpression(); // read value.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- return;
- case kStaticGet:
- helper_.ReadPosition(); // read position.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- return;
- case kStaticSet:
- helper_.ReadPosition(); // read position.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- VisitExpression(); // read expression.
- return;
- case kMethodInvocation:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read receiver.
- helper_.SkipName(); // read name.
- VisitArguments(); // read arguments.
- // read interface_target_reference.
- helper_.SkipCanonicalNameReference();
- return;
- case kDirectMethodInvocation:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read receiver.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- VisitArguments(); // read arguments.
- return;
- case kSuperMethodInvocation:
- HandleSpecialLoad(&result_->this_variable, Symbols::This());
- helper_.ReadPosition(); // read position.
- helper_.SkipName(); // read name.
- VisitArguments(); // read arguments.
- // read interface_target_reference.
- helper_.SkipCanonicalNameReference();
- return;
- case kStaticInvocation:
- case kConstStaticInvocation:
- helper_.ReadPosition(); // read position.
- helper_.SkipCanonicalNameReference(); // read procedure_reference.
- VisitArguments(); // read arguments.
- return;
- case kConstructorInvocation:
- case kConstConstructorInvocation:
- helper_.ReadPosition(); // read position.
- helper_.SkipCanonicalNameReference(); // read target_reference.
- VisitArguments(); // read arguments.
- return;
- case kNot:
- VisitExpression(); // read expression.
- return;
- case kLogicalExpression:
- needs_expr_temp_ = true;
- VisitExpression(); // read left.
- helper_.SkipBytes(1); // read operator.
- VisitExpression(); // read right.
- return;
- case kConditionalExpression: {
- needs_expr_temp_ = true;
- VisitExpression(); // read condition.
- VisitExpression(); // read then.
- VisitExpression(); // read otherwise.
- helper_.SkipOptionalDartType(); // read unused static type.
- return;
- }
- case kStringConcatenation: {
- helper_.ReadPosition(); // read position.
- intptr_t list_length = helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitExpression(); // read ith expression.
- }
- return;
- }
- case kIsExpression:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read operand.
- VisitDartType(); // read type.
- return;
- case kAsExpression:
- helper_.ReadPosition(); // read position.
- helper_.ReadFlags(); // read flags.
- VisitExpression(); // read operand.
- VisitDartType(); // read type.
- return;
- case kSymbolLiteral:
- helper_.SkipStringReference(); // read index into string table.
- return;
- case kTypeLiteral:
- VisitDartType(); // read type.
- return;
- case kThisExpression:
- HandleSpecialLoad(&result_->this_variable, Symbols::This());
- return;
- case kRethrow:
- helper_.ReadPosition(); // read position.
- return;
- case kThrow:
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read expression.
- return;
- case kListLiteral:
- case kConstListLiteral: {
- helper_.ReadPosition(); // read position.
- VisitDartType(); // read type.
- intptr_t list_length = helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitExpression(); // read ith expression.
- }
- return;
- }
- case kMapLiteral:
- case kConstMapLiteral: {
- helper_.ReadPosition(); // read position.
- VisitDartType(); // read key type.
- VisitDartType(); // read value type.
- intptr_t list_length = helper_.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 = helper_.ReaderOffset() - 1; // -1 to include tag byte.
- helper_.ReadPosition(); // read position.
- HandleLocalFunction(offset); // read function node.
- return;
- }
- case kLet: {
- PositionScope scope(&helper_.reader_);
- intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
-
- EnterScope(offset);
-
- VisitVariableDeclaration(); // read variable declaration.
- VisitExpression(); // read expression.
-
- ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
- return;
- }
- case kBigIntLiteral:
- helper_.SkipStringReference(); // read string reference.
- return;
- case kStringLiteral:
- helper_.SkipStringReference(); // read string reference.
- return;
- case kSpecializedIntLiteral:
- return;
- case kNegativeIntLiteral:
- helper_.ReadUInt(); // read value.
- return;
- case kPositiveIntLiteral:
- helper_.ReadUInt(); // read value.
- return;
- case kDoubleLiteral:
- helper_.ReadDouble(); // read value.
- return;
- case kTrueLiteral:
- return;
- case kFalseLiteral:
- return;
- case kNullLiteral:
- return;
- case kConstantExpression: {
- helper_.SkipConstantReference();
- return;
- }
- case kInstantiation: {
- VisitExpression();
- const intptr_t list_length =
- helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitDartType(); // read ith type.
- }
- return;
- }
- case kLoadLibrary:
- case kCheckLibraryIsLoaded:
- helper_.ReadUInt(); // library index
- break;
- default:
- ReportUnexpectedTag("expression", tag);
- UNREACHABLE();
- }
-}
-
-void StreamingScopeBuilder::VisitStatement() {
- Tag tag = helper_.ReadTag(); // read tag.
- switch (tag) {
- case kExpressionStatement:
- VisitExpression(); // read expression.
- return;
- case kBlock: {
- PositionScope scope(&helper_.reader_);
- intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
-
- EnterScope(offset);
-
- intptr_t list_length =
- helper_.ReadListLength(); // read number of statements.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitStatement(); // read ith statement.
- }
-
- ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
- return;
- }
- case kEmptyStatement:
- return;
- case kAssertBlock:
- if (I->asserts()) {
- PositionScope scope(&helper_.reader_);
- intptr_t offset =
- helper_.ReaderOffset() - 1; // -1 to include tag byte.
-
- EnterScope(offset);
-
- intptr_t list_length =
- helper_.ReadListLength(); // read number of statements.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitStatement(); // read ith statement.
- }
-
- ExitScope(helper_.reader_.min_position(),
- helper_.reader_.max_position());
- } else {
- helper_.SkipStatementList();
- }
- return;
- case kAssertStatement:
- if (I->asserts()) {
- VisitExpression(); // Read condition.
- helper_.ReadPosition(); // read condition start offset.
- helper_.ReadPosition(); // read condition end offset.
- Tag tag = helper_.ReadTag(); // read (first part of) message.
- if (tag == kSomething) {
- VisitExpression(); // read (rest of) message.
- }
- } else {
- helper_.SkipExpression(); // Read condition.
- helper_.ReadPosition(); // read condition start offset.
- helper_.ReadPosition(); // read condition end offset.
- Tag tag = helper_.ReadTag(); // read (first part of) message.
- if (tag == kSomething) {
- helper_.SkipExpression(); // read (rest of) message.
- }
- }
- return;
- case kLabeledStatement:
- VisitStatement(); // read body.
- return;
- case kBreakStatement:
- helper_.ReadPosition(); // read position.
- helper_.ReadUInt(); // read target_index.
- return;
- case kWhileStatement:
- ++depth_.loop_;
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read condition.
- VisitStatement(); // read body.
- --depth_.loop_;
- return;
- case kDoStatement:
- ++depth_.loop_;
- helper_.ReadPosition(); // read position.
- VisitStatement(); // read body.
- VisitExpression(); // read condition.
- --depth_.loop_;
- return;
- case kForStatement: {
- PositionScope scope(&helper_.reader_);
-
- intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
-
- ++depth_.loop_;
- EnterScope(offset);
-
- TokenPosition position = helper_.ReadPosition(); // read position.
- intptr_t list_length =
- helper_.ReadListLength(); // read number of variables.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitVariableDeclaration(); // read ith variable.
- }
-
- Tag tag = helper_.ReadTag(); // Read first part of condition.
- if (tag == kSomething) {
- VisitExpression(); // read rest of condition.
- }
- list_length = helper_.ReadListLength(); // read number of updates.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitExpression(); // read ith update.
- }
- VisitStatement(); // read body.
-
- ExitScope(position, helper_.reader_.max_position());
- --depth_.loop_;
- return;
- }
- case kForInStatement:
- case kAsyncForInStatement: {
- PositionScope scope(&helper_.reader_);
-
- intptr_t start_offset =
- helper_.ReaderOffset() - 1; // -1 to include tag byte.
-
- helper_.ReadPosition(); // read position.
- TokenPosition body_position =
- helper_.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 = helper_.ReaderOffset();
- helper_.SkipVariableDeclaration(); // read variable.
- VisitExpression(); // read iterable.
-
- ++depth_.for_in_;
- AddIteratorVariable();
- ++depth_.loop_;
- EnterScope(start_offset);
-
- {
- AlternativeReadingScope alt(&helper_.reader_, offset);
- VisitVariableDeclaration(); // read variable.
- }
- VisitStatement(); // read body.
-
- if (!body_position.IsReal()) {
- body_position = helper_.reader_.min_position();
- }
- // TODO(jensj): From kernel_binary.cc
- // forinstmt->variable_->set_end_position(forinstmt->position_);
- ExitScope(body_position, helper_.reader_.max_position());
- --depth_.loop_;
- --depth_.for_in_;
- return;
- }
- case kSwitchStatement: {
- AddSwitchVariable();
- helper_.ReadPosition(); // read position.
- VisitExpression(); // read condition.
- int case_count = helper_.ReadListLength(); // read number of cases.
- for (intptr_t i = 0; i < case_count; ++i) {
- int expression_count =
- helper_.ReadListLength(); // read number of expressions.
- for (intptr_t j = 0; j < expression_count; ++j) {
- helper_.ReadPosition(); // read jth position.
- VisitExpression(); // read jth expression.
- }
- helper_.ReadBool(); // read is_default.
- VisitStatement(); // read body.
- }
- return;
- }
- case kContinueSwitchStatement:
- helper_.ReadPosition(); // read position.
- helper_.ReadUInt(); // read target_index.
- return;
- case kIfStatement:
- helper_.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;
- }
-
- helper_.ReadPosition(); // read position
- Tag tag = helper_.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();
-
- helper_.ReadByte(); // read flags
- intptr_t catch_count =
- helper_.ReadListLength(); // read number of catches.
- for (intptr_t i = 0; i < catch_count; ++i) {
- PositionScope scope(&helper_.reader_);
- intptr_t offset = helper_.ReaderOffset(); // Catch has no tag.
-
- EnterScope(offset);
-
- helper_.ReadPosition(); // read position.
- VisitDartType(); // Read the guard.
- tag = helper_.ReadTag(); // read first part of exception.
- if (tag == kSomething) {
- VisitVariableDeclaration(); // read exception.
- }
- tag = helper_.ReadTag(); // read first part of stack trace.
- if (tag == kSomething) {
- VisitVariableDeclaration(); // read stack trace.
- }
- VisitStatement(); // read body.
-
- ExitScope(helper_.reader_.min_position(),
- helper_.reader_.max_position());
- }
-
- FinalizeCatchVariables();
-
- --depth_.catch_;
- return;
- }
- case kTryFinally: {
- ++depth_.try_;
- ++depth_.finally_;
- AddTryVariables();
-
- VisitStatement(); // read body.
-
- --depth_.finally_;
- --depth_.try_;
- ++depth_.catch_;
- AddCatchVariables();
-
- VisitStatement(); // read finalizer.
-
- FinalizeCatchVariables();
-
- --depth_.catch_;
- return;
- }
- case kYieldStatement: {
- helper_.ReadPosition(); // read position.
- word flags = helper_.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 = helper_.ReaderOffset() - 1; // -1 to include tag byte.
- helper_.ReadPosition(); // read position.
- VisitVariableDeclaration(); // read variable declaration.
- HandleLocalFunction(offset); // read function node.
- return;
- }
- default:
- ReportUnexpectedTag("declaration", tag);
- UNREACHABLE();
- }
-}
-
-void StreamingScopeBuilder::VisitArguments() {
- helper_.ReadUInt(); // read argument_count.
-
- // Types
- intptr_t list_length = helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitDartType(); // read ith type.
- }
-
- // Positional.
- list_length = helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- VisitExpression(); // read ith positional.
- }
-
- // Named.
- list_length = helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- helper_.SkipStringReference(); // read ith name index.
- VisitExpression(); // read ith expression.
- }
-}
-
-void StreamingScopeBuilder::VisitVariableDeclaration() {
- PositionScope scope(&helper_.reader_);
-
- intptr_t kernel_offset_no_tag = helper_.ReaderOffset();
- VariableDeclarationHelper helper(&helper_);
- 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 = helper_.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 = helper_.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(helper_.data_program_offset_ + kernel_offset_no_tag,
- variable);
-}
-
-AbstractType& StreamingScopeBuilder::BuildAndVisitVariableType() {
- const intptr_t offset = helper_.ReaderOffset();
- AbstractType& type = T.BuildVariableType();
- helper_.SetOffset(offset); // rewind
- VisitDartType();
- return type;
-}
-
-void StreamingScopeBuilder::VisitDartType() {
- Tag tag = helper_.ReadTag();
- switch (tag) {
- case kInvalidType:
- case kDynamicType:
- case kVoidType:
- case kBottomType:
- // those contain nothing.
- return;
- case kInterfaceType:
- VisitInterfaceType(false);
- return;
- case kSimpleInterfaceType:
- VisitInterfaceType(true);
- return;
- case kFunctionType:
- VisitFunctionType(false);
- return;
- case kSimpleFunctionType:
- VisitFunctionType(true);
- return;
- case kTypeParameterType:
- VisitTypeParameterType();
- return;
- default:
- ReportUnexpectedTag("type", tag);
- UNREACHABLE();
- }
-}
-
-void StreamingScopeBuilder::VisitInterfaceType(bool simple) {
- helper_.ReadUInt(); // read klass_name.
- if (!simple) {
- intptr_t length = helper_.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 =
- helper_.ReadListLength(); // read type_parameters list length.
- for (int i = 0; i < list_length; ++i) {
- TypeParameterHelper helper(&helper_);
- helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
- VisitDartType(); // read bound.
- helper.ReadUntilExcludingAndSetJustRead(
- TypeParameterHelper::kDefaultType);
- if (helper_.ReadTag() == kSomething) {
- VisitDartType(); // read default type.
- }
- helper.Finish();
- }
- helper_.ReadUInt(); // read required parameter count.
- helper_.ReadUInt(); // read total parameter count.
- }
-
- const intptr_t positional_count =
- helper_.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 =
- helper_.ReadListLength(); // read named_parameters list length.
- for (intptr_t i = 0; i < named_count; ++i) {
- // read string reference (i.e. named_parameters[i].name).
- helper_.SkipStringReference();
- VisitDartType(); // read named_parameters[i].type.
- }
- }
-
- helper_.SkipListOfStrings(); // read positional parameter names.
-
- if (!simple) {
- helper_.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 = helper_.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());
- }
- }
-
- helper_.SkipOptionalDartType(); // read bound bound.
-}
-
-void StreamingScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) {
- // "Peek" ahead into the function node
- intptr_t offset = helper_.ReaderOffset();
-
- FunctionNodeHelper function_node_helper(&helper_);
- 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 _(&helper_.reader_);
- num_type_params = helper_.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.
- TypeTranslator::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.
- helper_.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 = helper_.ReadListLength(); // read list length.
- for (intptr_t i = 0; i < list_length; ++i) {
- AddVariableDeclarationParameter(pos++, type_check_mode, attrs);
- }
-
- // List of named.
- list_length = helper_.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 = helper_.ReaderOffset(); // no tag.
- const InferredTypeMetadata parameter_type =
- inferred_type_metadata_helper_.GetInferredType(kernel_offset);
- VariableDeclarationHelper helper(&helper_);
- 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_check_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 kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod:
- if (needs_covariant_check_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_check_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(helper_.data_program_offset_ + kernel_offset,
- variable);
-
- // The default value may contain 'let' bindings for which the constant
- // evaluator needs scope bindings.
- Tag tag = helper_.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::FinalizeExceptionVariable(
- GrowableArray<LocalVariable*>* variables,
- GrowableArray<LocalVariable*>* raw_variables,
- const String& symbol,
- intptr_t nesting_depth) {
- // No need to create variables for try/catch-statements inside
- // nested functions.
- if (depth_.function_ > 0) return;
-
- LocalVariable* variable = (*variables)[nesting_depth - 1];
- LocalVariable* raw_variable;
- if (variable->is_captured()) {
- raw_variable =
- new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
- symbol, AbstractType::dynamic_type());
- const bool ok = scope_->AddVariable(raw_variable);
- ASSERT(ok);
- } else {
- raw_variable = variable;
- }
- raw_variables->EnsureLength(nesting_depth, nullptr);
- (*raw_variables)[nesting_depth - 1] = raw_variable;
-}
-
-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::FinalizeCatchVariables() {
- const intptr_t unique_id = result_->raw_variable_counter_++;
- FinalizeExceptionVariable(
- &result_->exception_variables, &result_->raw_exception_variables,
- GenerateName(":raw_exception", unique_id), depth_.catch_);
- FinalizeExceptionVariable(
- &result_->stack_trace_variables, &result_->raw_stack_trace_variables,
- GenerateName(":raw_stacktrace", unique_id), 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 = GetNameFromVariableDeclaration(
- declaration_binary_offset - helper_.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());
- }
-}
-
-StringIndex StreamingScopeBuilder::GetNameFromVariableDeclaration(
- intptr_t kernel_offset,
- const Function& function) {
- ExternalTypedData& kernel_data =
- ExternalTypedData::Handle(Z, function.KernelData());
- ASSERT(!kernel_data.IsNull());
-
- // Temporarily go to the variable declaration, read the name.
- AlternativeReadingScope alt(&helper_.reader_, &kernel_data, kernel_offset);
- VariableDeclarationHelper helper(&helper_);
- helper.ReadUntilIncluding(VariableDeclarationHelper::kNameIndex);
- return helper.name_index_;
-}
-
-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);
- }
-}
-
StreamingConstantEvaluator::StreamingConstantEvaluator(
StreamingFlowGraphBuilder* builder)
: builder_(builder),
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index b27d20e..b352dea 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -10,6 +10,7 @@
#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/compiler/frontend/kernel_to_il.h"
#include "vm/compiler/frontend/kernel_translation_helper.h"
+#include "vm/compiler/frontend/scope_builder.h"
#include "vm/kernel.h"
#include "vm/kernel_binary.h"
#include "vm/object.h"
@@ -17,150 +18,6 @@
namespace dart {
namespace kernel {
-class StreamingScopeBuilder {
- public:
- explicit StreamingScopeBuilder(ParsedFunction* parsed_function);
-
- virtual ~StreamingScopeBuilder() = default;
-
- ScopeBuildingResult* BuildScopes();
-
- private:
- void VisitField();
-
- void VisitProcedure();
-
- void VisitConstructor();
-
- void VisitFunctionNode();
- void VisitNode();
- void VisitInitializer();
- void VisitExpression();
- void VisitStatement();
- void VisitArguments();
- void VisitVariableDeclaration();
- void VisitDartType();
- void VisitInterfaceType(bool simple);
- void VisitFunctionType(bool simple);
- void VisitTypeParameterType();
- void HandleLocalFunction(intptr_t parent_kernel_offset);
-
- AbstractType& BuildAndVisitVariableType();
-
- void EnterScope(intptr_t kernel_offset);
- void ExitScope(TokenPosition start_position, TokenPosition end_position);
-
- virtual void ReportUnexpectedTag(const char* variant, Tag tag);
-
- // This enum controls which parameters would be marked as requring type
- // check on the callee side.
- enum ParameterTypeCheckMode {
- // All parameters will be checked.
- kTypeCheckAllParameters,
-
- // Only parameters marked as covariant or generic-covariant-impl will be
- // checked.
- kTypeCheckForNonDynamicallyInvokedMethod,
-
- // Only parameters *not* marked as covariant or generic-covariant-impl will
- // be checked. The rest would be checked in the method itself.
- // Inverse of kTypeCheckForNonDynamicallyInvokedMethod.
- kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
-
- // No parameters will be checked.
- kTypeCheckForStaticFunction,
- };
-
- // This assumes that the reader is at a FunctionNode,
- // about to read the positional parameters.
- void AddPositionalAndNamedParameters(
- intptr_t pos,
- ParameterTypeCheckMode type_check_mode,
- const ProcedureAttributesMetadata& attrs);
-
- // This assumes that the reader is at a FunctionNode,
- // about to read a parameter (i.e. VariableDeclaration).
- void AddVariableDeclarationParameter(
- intptr_t pos,
- ParameterTypeCheckMode type_check_mode,
- const ProcedureAttributesMetadata& attrs);
-
- LocalVariable* MakeVariable(TokenPosition declaration_pos,
- TokenPosition token_pos,
- const String& name,
- const AbstractType& type,
- const InferredTypeMetadata* param_type_md = NULL);
-
- void AddExceptionVariable(GrowableArray<LocalVariable*>* variables,
- const char* prefix,
- intptr_t nesting_depth);
-
- void FinalizeExceptionVariable(GrowableArray<LocalVariable*>* variables,
- GrowableArray<LocalVariable*>* raw_variables,
- const String& symbol,
- intptr_t nesting_depth);
-
- void AddTryVariables();
- void AddCatchVariables();
- void FinalizeCatchVariables();
- void AddIteratorVariable();
- void AddSwitchVariable();
-
- // Record an assignment or reference to a variable. If the occurrence is
- // in a nested function, ensure that the variable is handled properly as a
- // captured variable.
- void LookupVariable(intptr_t declaration_binary_offset);
-
- StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset,
- const Function& function);
-
- const String& GenerateName(const char* prefix, intptr_t suffix);
-
- void HandleSpecialLoad(LocalVariable** variable, const String& symbol);
- void LookupCapturedVariableByName(LocalVariable** variable,
- const String& name);
-
- struct DepthState {
- explicit DepthState(intptr_t function)
- : loop_(0),
- function_(function),
- try_(0),
- catch_(0),
- finally_(0),
- for_in_(0) {}
-
- intptr_t loop_;
- intptr_t function_;
- intptr_t try_;
- intptr_t catch_;
- intptr_t finally_;
- intptr_t for_in_;
- };
-
- ScopeBuildingResult* result_;
- ParsedFunction* parsed_function_;
-
- ActiveClass active_class_;
-
- TranslationHelper translation_helper_;
- Zone* zone_;
-
- FunctionNodeHelper::AsyncMarker current_function_async_marker_;
- LocalScope* current_function_scope_;
- LocalScope* scope_;
- DepthState depth_;
-
- intptr_t name_index_;
-
- bool needs_expr_temp_;
- TokenPosition first_body_token_position_;
-
- KernelReaderHelper helper_;
- InferredTypeMetadataHelper inferred_type_metadata_helper_;
- ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
- TypeTranslator type_translator_;
-};
-
// There are several cases when we are compiling constant expressions:
//
// * constant field initializers:
@@ -728,12 +585,10 @@
InferredTypeMetadataHelper inferred_type_metadata_helper_;
ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
- friend class ClassHelper;
friend class ConstantHelper;
friend class KernelLoader;
friend class SimpleExpressionConverter;
friend class StreamingConstantEvaluator;
- friend class StreamingScopeBuilder;
};
// Helper class that reads a kernel Constant from binary.
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 0811a4e..57f95cc 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -631,7 +631,6 @@
}
Fragment BaseFlowGraphBuilder::TailCall(const Code& code) {
- Fragment instructions;
Value* arg_desc = Pop();
return Fragment(new (Z) TailCallInstr(code, arg_desc));
}
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index c29a950..2fdace5 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -17,6 +17,7 @@
#include "vm/compiler/backend/il.h"
#include "vm/compiler/frontend/flow_graph_builder.h"
#include "vm/compiler/frontend/kernel_translation_helper.h"
+#include "vm/compiler/frontend/scope_builder.h"
namespace dart {
namespace kernel {
@@ -56,53 +57,6 @@
};
typedef UnorderedHashMap<KernelConstMapKeyEqualsTraits> KernelConstantsMap;
-template <typename V>
-class IntKeyRawPointerValueTrait {
- public:
- typedef intptr_t Key;
- typedef V Value;
-
- struct Pair {
- Key key;
- Value value;
- Pair() : key(NULL), value() {}
- Pair(const Key key, const Value& value) : key(key), value(value) {}
- Pair(const Pair& other) : key(other.key), value(other.value) {}
- };
-
- static Key KeyOf(Pair kv) { return kv.key; }
- static Value ValueOf(Pair kv) { return kv.value; }
- static intptr_t Hashcode(Key key) { return key; }
- static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
-};
-
-template <typename V>
-class IntMap : public DirectChainedHashMap<IntKeyRawPointerValueTrait<V> > {
- public:
- typedef typename IntKeyRawPointerValueTrait<V>::Key Key;
- typedef typename IntKeyRawPointerValueTrait<V>::Value Value;
- typedef typename IntKeyRawPointerValueTrait<V>::Pair Pair;
-
- inline void Insert(const Key& key, const Value& value) {
- Pair pair(key, value);
- DirectChainedHashMap<IntKeyRawPointerValueTrait<V> >::Insert(pair);
- }
-
- inline V Lookup(const Key& key) {
- Pair* pair =
- DirectChainedHashMap<IntKeyRawPointerValueTrait<V> >::Lookup(key);
- if (pair == NULL) {
- return V();
- } else {
- return pair->value;
- }
- }
-
- inline Pair* LookupPair(const Key& key) {
- return DirectChainedHashMap<IntKeyRawPointerValueTrait<V> >::Lookup(key);
- }
-};
-
class BreakableBlock;
class CatchBlock;
class FlowGraphBuilder;
@@ -145,68 +99,6 @@
typedef ZoneGrowableArray<PushArgumentInstr*>* ArgumentArray;
-struct FunctionScope {
- intptr_t kernel_offset;
- LocalScope* scope;
-};
-
-class ScopeBuildingResult : public ZoneAllocated {
- public:
- ScopeBuildingResult()
- : this_variable(NULL),
- type_arguments_variable(NULL),
- switch_variable(NULL),
- finally_return_variable(NULL),
- setter_value(NULL),
- yield_jump_variable(NULL),
- yield_context_variable(NULL),
- raw_variable_counter_(0) {}
-
- IntMap<LocalVariable*> locals;
- IntMap<LocalScope*> scopes;
- GrowableArray<FunctionScope> function_scopes;
-
- // Only non-NULL for instance functions.
- LocalVariable* this_variable;
-
- // Only non-NULL for factory constructor functions.
- LocalVariable* type_arguments_variable;
-
- // Non-NULL when the function contains a switch statement.
- LocalVariable* switch_variable;
-
- // Non-NULL when the function contains a return inside a finally block.
- LocalVariable* finally_return_variable;
-
- // Non-NULL when the function is a setter.
- LocalVariable* setter_value;
-
- // Non-NULL if the function contains yield statement.
- // TODO(27590) actual variable is called :await_jump_var, we should rename
- // it to reflect the fact that it is used for both await and yield.
- LocalVariable* yield_jump_variable;
-
- // Non-NULL if the function contains yield statement.
- // TODO(27590) actual variable is called :await_ctx_var, we should rename
- // it to reflect the fact that it is used for both await and yield.
- LocalVariable* yield_context_variable;
-
- // Variables used in exception handlers, one per exception handler nesting
- // level.
- GrowableArray<LocalVariable*> exception_variables;
- GrowableArray<LocalVariable*> stack_trace_variables;
- GrowableArray<LocalVariable*> catch_context_variables;
-
- // These are used to access the raw exception/stacktrace variables (and are
- // used to put them into the captured variables in the context).
- GrowableArray<LocalVariable*> raw_exception_variables;
- GrowableArray<LocalVariable*> raw_stack_trace_variables;
- intptr_t raw_variable_counter_;
-
- // For-in iterators, one per for-in nesting level.
- GrowableArray<LocalVariable*> iterator_variables;
-};
-
struct YieldContinuation {
Instruction* entry;
intptr_t try_index;
@@ -358,7 +250,6 @@
intptr_t pending_argument_count_;
friend class TryCatchBlock;
- friend class KernelReaderHelper;
friend class StreamingFlowGraphBuilder;
friend class FlowGraphBuilder;
friend class PrologueBuilder;
@@ -581,7 +472,6 @@
friend class BreakableBlock;
friend class CatchBlock;
- friend class KernelReaderHelper;
friend class StreamingFlowGraphBuilder;
friend class SwitchBlock;
friend class TryCatchBlock;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 342a8de..eb1564d 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -974,7 +974,7 @@
friend class ProcedureHelper;
friend class SimpleExpressionConverter;
friend class StreamingConstantEvaluator;
- friend class StreamingScopeBuilder;
+ friend class ScopeBuilder;
friend class TypeParameterHelper;
friend class TypeTranslator;
friend class VariableDeclarationHelper;
@@ -1159,7 +1159,7 @@
AbstractType& result_;
bool finalize_;
- friend class StreamingScopeBuilder;
+ friend class ScopeBuilder;
friend class KernelLoader;
};
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
new file mode 100644
index 0000000..faf3885
--- /dev/null
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -0,0 +1,1689 @@
+// Copyright (c) 2018, 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/scope_builder.h"
+
+#include "vm/compiler/backend/il.h" // For CompileType.
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+namespace dart {
+namespace kernel {
+
+#define Z (zone_)
+#define H (translation_helper_)
+#define T (type_translator_)
+#define I Isolate::Current()
+
+bool IsFieldInitializer(const Function& function, Zone* zone) {
+ return (function.kind() == RawFunction::kImplicitStaticFinalGetter) &&
+ String::Handle(zone, function.name())
+ .StartsWith(Symbols::InitPrefix());
+}
+
+// Returns true if the given method can skip type checks for all arguments
+// that are not covariant or generic covariant in its implementation.
+bool MethodCanSkipTypeChecksForNonCovariantArguments(
+ const Function& method,
+ const ProcedureAttributesMetadata& attrs) {
+ // Dart 2 type system at non-dynamic call sites statically guarantees that
+ // argument values match declarated parameter types for all non-covariant
+ // and non-generic-covariant parameters. The same applies to type parameters
+ // bounds for type parameters of generic functions.
+ // In JIT mode we dynamically generate trampolines (dynamic invocation
+ // forwarders) that perform type checks when arriving to a method from a
+ // dynamic call-site.
+ // In AOT mode we don't dynamically generate such trampolines but
+ // instead rely on a static analysis to discover which methods can
+ // be invoked dynamically.
+ if (method.name() == Symbols::Call().raw()) {
+ // Currently we consider all call methods to be invoked dynamically and
+ // don't mangle their names.
+ // TODO(vegorov) remove this once we also introduce special type checking
+ // entry point for closures.
+ return false;
+ }
+ return !FLAG_precompiled_mode || !attrs.has_dynamic_invocations;
+}
+
+ScopeBuilder::ScopeBuilder(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),
+ helper_(
+ zone_,
+ &translation_helper_,
+ Script::Handle(Z, parsed_function->function().script()),
+ ExternalTypedData::Handle(Z,
+ parsed_function->function().KernelData()),
+ parsed_function->function().KernelDataProgramOffset()),
+ inferred_type_metadata_helper_(&helper_),
+ procedure_attributes_metadata_helper_(&helper_),
+ type_translator_(&helper_,
+ &active_class_,
+ /*finalize=*/true) {
+ H.InitFromScript(helper_.script());
+ ASSERT(type_translator_.active_class_ == &active_class_);
+}
+
+ScopeBuildingResult* ScopeBuilder::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, function.GetOutermostFunction());
+
+ 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(VariableIndex(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_));
+
+ helper_.SetOffset(function.kernel_offset());
+
+ FunctionNodeHelper function_node_helper(&helper_);
+ const ProcedureAttributesMetadata attrs =
+ procedure_attributes_metadata_helper_.GetProcedureAttributes(
+ function.kernel_offset());
+
+ switch (function.kind()) {
+ case RawFunction::kClosureFunction:
+ case RawFunction::kImplicitClosureFunction:
+ case RawFunction::kRegularFunction:
+ case RawFunction::kGetterFunction:
+ case RawFunction::kSetterFunction:
+ case RawFunction::kConstructor: {
+ const Tag tag = helper_.PeekTag();
+ helper_.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()) {
+ ExternalTypedData& kernel_data =
+ ExternalTypedData::Handle(Z, class_field.KernelData());
+ ASSERT(!kernel_data.IsNull());
+ intptr_t field_offset = class_field.kernel_offset();
+ AlternativeReadingScope alt(&helper_.reader_, &kernel_data,
+ field_offset);
+ FieldHelper field_helper(&helper_);
+ field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
+ Tag initializer_tag =
+ helper_.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 (MethodCanSkipTypeChecksForNonCovariantArguments(
+ Function::Handle(Z, function.parent_function()), attrs)) {
+ // 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 =
+ kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod;
+ }
+ } else {
+ if (function.is_static()) {
+ // In static functions we don't check anything.
+ type_check_mode = kTypeCheckForStaticFunction;
+ } else if (MethodCanSkipTypeChecksForNonCovariantArguments(function,
+ attrs)) {
+ // 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()) {
+ helper_.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(helper_.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 &&
+ MethodCanSkipTypeChecksForNonCovariantArguments(function, attrs)) {
+ FieldHelper field_helper(&helper_);
+ 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::kDynamicInvocationForwarder: {
+ if (helper_.PeekTag() == kField) {
+#ifdef DEBUG
+ String& name = String::Handle(Z, function.name());
+ ASSERT(Function::IsDynamicInvocationForwaderName(name));
+ name = Function::DemangleDynamicInvocationForwarderName(name);
+ ASSERT(Field::IsSetterName(name));
+#endif
+ // Create [this] variable.
+ const Class& klass = Class::Handle(Z, function.Owner());
+ result_->this_variable =
+ MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+ Symbols::This(), H.GetCanonicalType(klass));
+ scope_->InsertParameterAt(0, result_->this_variable);
+
+ // Create setter value variable.
+ result_->setter_value = MakeVariable(
+ TokenPosition::kNoSource, TokenPosition::kNoSource,
+ Symbols::Value(),
+ AbstractType::ZoneHandle(Z, function.ParameterTypeAt(1)));
+ scope_->InsertParameterAt(1, result_->setter_value);
+ } else {
+ helper_.ReadUntilFunctionNode();
+ function_node_helper.ReadUntilExcluding(
+ FunctionNodeHelper::kPositionalParameters);
+
+ // Create [this] variable.
+ intptr_t pos = 0;
+ Class& klass = Class::Handle(Z, function.Owner());
+ result_->this_variable =
+ MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+ Symbols::This(), H.GetCanonicalType(klass));
+ scope_->InsertParameterAt(pos++, result_->this_variable);
+
+ // Create all positional and named parameters.
+ AddPositionalAndNamedParameters(
+ pos, kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
+ attrs);
+ }
+ 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 ScopeBuilder::ReportUnexpectedTag(const char* variant, Tag tag) {
+ H.ReportError(helper_.script(), TokenPosition::kNoSource,
+ "Unexpected tag %d (%s) in %s, expected %s", tag,
+ Reader::TagName(tag),
+ parsed_function_->function().ToQualifiedCString(), variant);
+}
+
+void ScopeBuilder::VisitNode() {
+ Tag tag = helper_.PeekTag();
+ switch (tag) {
+ case kConstructor:
+ VisitConstructor();
+ return;
+ case kProcedure:
+ VisitProcedure();
+ return;
+ case kField:
+ VisitField();
+ return;
+ case kFunctionNode:
+ VisitFunctionNode();
+ return;
+ default:
+ UNIMPLEMENTED();
+ return;
+ }
+}
+
+void ScopeBuilder::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(&helper_);
+ 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()) {
+ ExternalTypedData& kernel_data =
+ ExternalTypedData::Handle(Z, class_field.KernelData());
+ ASSERT(!kernel_data.IsNull());
+ intptr_t field_offset = class_field.kernel_offset();
+ AlternativeReadingScope alt(&helper_.reader_, &kernel_data,
+ field_offset);
+ FieldHelper field_helper(&helper_);
+ field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
+ Tag initializer_tag = helper_.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 =
+ helper_.ReadListLength(); // read initializers list length.
+ for (intptr_t i = 0; i < list_length; i++) {
+ VisitInitializer();
+ }
+}
+
+void ScopeBuilder::VisitProcedure() {
+ ProcedureHelper procedure_helper(&helper_);
+ procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
+ if (helper_.ReadTag() == kSomething) {
+ VisitFunctionNode();
+ }
+}
+
+void ScopeBuilder::VisitField() {
+ FieldHelper field_helper(&helper_);
+ field_helper.ReadUntilExcluding(FieldHelper::kType);
+ VisitDartType(); // read type.
+ Tag tag = helper_.ReadTag(); // read initializer (part 1).
+ if (tag == kSomething) {
+ VisitExpression(); // read initializer (part 2).
+ }
+}
+
+void ScopeBuilder::VisitFunctionNode() {
+ FunctionNodeHelper function_node_helper(&helper_);
+ function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
+
+ intptr_t list_length =
+ helper_.ReadListLength(); // read type_parameters list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ TypeParameterHelper helper(&helper_);
+ helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
+ VisitDartType(); // read ith bound.
+ helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
+ if (helper_.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 (helper_.ReadTag() == kSomething) {
+ PositionScope scope(&helper_.reader_);
+ VisitStatement(); // Read body
+ first_body_token_position_ = helper_.reader_.min_position();
+ }
+
+ // Ensure that :await_jump_var, :await_ctx_var, :async_op,
+ // :async_completer 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);
+ }
+ }
+ {
+ LocalVariable* temp =
+ scope_->LookupVariable(Symbols::AsyncCompleter(), 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 ScopeBuilder::VisitInitializer() {
+ Tag tag = helper_.ReadTag();
+ helper_.ReadByte(); // read isSynthetic flag.
+ switch (tag) {
+ case kInvalidInitializer:
+ return;
+ case kFieldInitializer:
+ helper_.SkipCanonicalNameReference(); // read field_reference.
+ VisitExpression(); // read value.
+ return;
+ case kSuperInitializer:
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ VisitArguments(); // read arguments.
+ return;
+ case kRedirectingInitializer:
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ VisitArguments(); // read arguments.
+ return;
+ case kLocalInitializer:
+ VisitVariableDeclaration(); // read variable.
+ return;
+ case kAssertInitializer:
+ VisitStatement();
+ return;
+ default:
+ ReportUnexpectedTag("initializer", tag);
+ UNREACHABLE();
+ }
+}
+
+void ScopeBuilder::VisitExpression() {
+ uint8_t payload = 0;
+ Tag tag = helper_.ReadTag(&payload);
+ switch (tag) {
+ case kInvalidExpression:
+ helper_.ReadPosition();
+ helper_.SkipStringReference();
+ return;
+ case kVariableGet: {
+ helper_.ReadPosition(); // read position.
+ intptr_t variable_kernel_offset =
+ helper_.ReadUInt(); // read kernel position.
+ helper_.ReadUInt(); // read relative variable index.
+ helper_.SkipOptionalDartType(); // read promoted type.
+ LookupVariable(variable_kernel_offset);
+ return;
+ }
+ case kSpecializedVariableGet: {
+ helper_.ReadPosition(); // read position.
+ intptr_t variable_kernel_offset =
+ helper_.ReadUInt(); // read kernel position.
+ LookupVariable(variable_kernel_offset);
+ return;
+ }
+ case kVariableSet: {
+ helper_.ReadPosition(); // read position.
+ intptr_t variable_kernel_offset =
+ helper_.ReadUInt(); // read kernel position.
+ helper_.ReadUInt(); // read relative variable index.
+ LookupVariable(variable_kernel_offset);
+ VisitExpression(); // read expression.
+ return;
+ }
+ case kSpecializedVariableSet: {
+ helper_.ReadPosition(); // read position.
+ intptr_t variable_kernel_offset =
+ helper_.ReadUInt(); // read kernel position.
+ LookupVariable(variable_kernel_offset);
+ VisitExpression(); // read expression.
+ return;
+ }
+ case kPropertyGet:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ // read interface_target_reference.
+ helper_.SkipCanonicalNameReference();
+ return;
+ case kPropertySet:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ VisitExpression(); // read value.
+ // read interface_target_reference.
+ helper_.SkipCanonicalNameReference();
+ return;
+ case kDirectPropertyGet:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ return;
+ case kDirectPropertySet:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ VisitExpression(); // read value·
+ return;
+ case kSuperPropertyGet:
+ HandleSpecialLoad(&result_->this_variable, Symbols::This());
+ helper_.ReadPosition(); // read position.
+ helper_.SkipName(); // read name.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ return;
+ case kSuperPropertySet:
+ HandleSpecialLoad(&result_->this_variable, Symbols::This());
+ helper_.ReadPosition(); // read position.
+ helper_.SkipName(); // read name.
+ VisitExpression(); // read value.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ return;
+ case kStaticGet:
+ helper_.ReadPosition(); // read position.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ return;
+ case kStaticSet:
+ helper_.ReadPosition(); // read position.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ VisitExpression(); // read expression.
+ return;
+ case kMethodInvocation:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ VisitArguments(); // read arguments.
+ // read interface_target_reference.
+ helper_.SkipCanonicalNameReference();
+ return;
+ case kDirectMethodInvocation:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ VisitArguments(); // read arguments.
+ return;
+ case kSuperMethodInvocation:
+ HandleSpecialLoad(&result_->this_variable, Symbols::This());
+ helper_.ReadPosition(); // read position.
+ helper_.SkipName(); // read name.
+ VisitArguments(); // read arguments.
+ // read interface_target_reference.
+ helper_.SkipCanonicalNameReference();
+ return;
+ case kStaticInvocation:
+ case kConstStaticInvocation:
+ helper_.ReadPosition(); // read position.
+ helper_.SkipCanonicalNameReference(); // read procedure_reference.
+ VisitArguments(); // read arguments.
+ return;
+ case kConstructorInvocation:
+ case kConstConstructorInvocation:
+ helper_.ReadPosition(); // read position.
+ helper_.SkipCanonicalNameReference(); // read target_reference.
+ VisitArguments(); // read arguments.
+ return;
+ case kNot:
+ VisitExpression(); // read expression.
+ return;
+ case kLogicalExpression:
+ needs_expr_temp_ = true;
+ VisitExpression(); // read left.
+ helper_.SkipBytes(1); // read operator.
+ VisitExpression(); // read right.
+ return;
+ case kConditionalExpression: {
+ needs_expr_temp_ = true;
+ VisitExpression(); // read condition.
+ VisitExpression(); // read then.
+ VisitExpression(); // read otherwise.
+ helper_.SkipOptionalDartType(); // read unused static type.
+ return;
+ }
+ case kStringConcatenation: {
+ helper_.ReadPosition(); // read position.
+ intptr_t list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitExpression(); // read ith expression.
+ }
+ return;
+ }
+ case kIsExpression:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read operand.
+ VisitDartType(); // read type.
+ return;
+ case kAsExpression:
+ helper_.ReadPosition(); // read position.
+ helper_.ReadFlags(); // read flags.
+ VisitExpression(); // read operand.
+ VisitDartType(); // read type.
+ return;
+ case kSymbolLiteral:
+ helper_.SkipStringReference(); // read index into string table.
+ return;
+ case kTypeLiteral:
+ VisitDartType(); // read type.
+ return;
+ case kThisExpression:
+ HandleSpecialLoad(&result_->this_variable, Symbols::This());
+ return;
+ case kRethrow:
+ helper_.ReadPosition(); // read position.
+ return;
+ case kThrow:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read expression.
+ return;
+ case kListLiteral:
+ case kConstListLiteral: {
+ helper_.ReadPosition(); // read position.
+ VisitDartType(); // read type.
+ intptr_t list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitExpression(); // read ith expression.
+ }
+ return;
+ }
+ case kMapLiteral:
+ case kConstMapLiteral: {
+ helper_.ReadPosition(); // read position.
+ VisitDartType(); // read key type.
+ VisitDartType(); // read value type.
+ intptr_t list_length = helper_.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 = helper_.ReaderOffset() - 1; // -1 to include tag byte.
+ helper_.ReadPosition(); // read position.
+ HandleLocalFunction(offset); // read function node.
+ return;
+ }
+ case kLet: {
+ PositionScope scope(&helper_.reader_);
+ intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
+
+ EnterScope(offset);
+
+ VisitVariableDeclaration(); // read variable declaration.
+ VisitExpression(); // read expression.
+
+ ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
+ return;
+ }
+ case kBigIntLiteral:
+ helper_.SkipStringReference(); // read string reference.
+ return;
+ case kStringLiteral:
+ helper_.SkipStringReference(); // read string reference.
+ return;
+ case kSpecializedIntLiteral:
+ return;
+ case kNegativeIntLiteral:
+ helper_.ReadUInt(); // read value.
+ return;
+ case kPositiveIntLiteral:
+ helper_.ReadUInt(); // read value.
+ return;
+ case kDoubleLiteral:
+ helper_.ReadDouble(); // read value.
+ return;
+ case kTrueLiteral:
+ return;
+ case kFalseLiteral:
+ return;
+ case kNullLiteral:
+ return;
+ case kConstantExpression: {
+ helper_.SkipConstantReference();
+ return;
+ }
+ case kInstantiation: {
+ VisitExpression();
+ const intptr_t list_length =
+ helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitDartType(); // read ith type.
+ }
+ return;
+ }
+ case kLoadLibrary:
+ case kCheckLibraryIsLoaded:
+ helper_.ReadUInt(); // library index
+ break;
+ default:
+ ReportUnexpectedTag("expression", tag);
+ UNREACHABLE();
+ }
+}
+
+void ScopeBuilder::VisitStatement() {
+ Tag tag = helper_.ReadTag(); // read tag.
+ switch (tag) {
+ case kExpressionStatement:
+ VisitExpression(); // read expression.
+ return;
+ case kBlock: {
+ PositionScope scope(&helper_.reader_);
+ intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
+
+ EnterScope(offset);
+
+ intptr_t list_length =
+ helper_.ReadListLength(); // read number of statements.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitStatement(); // read ith statement.
+ }
+
+ ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
+ return;
+ }
+ case kEmptyStatement:
+ return;
+ case kAssertBlock:
+ if (I->asserts()) {
+ PositionScope scope(&helper_.reader_);
+ intptr_t offset =
+ helper_.ReaderOffset() - 1; // -1 to include tag byte.
+
+ EnterScope(offset);
+
+ intptr_t list_length =
+ helper_.ReadListLength(); // read number of statements.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitStatement(); // read ith statement.
+ }
+
+ ExitScope(helper_.reader_.min_position(),
+ helper_.reader_.max_position());
+ } else {
+ helper_.SkipStatementList();
+ }
+ return;
+ case kAssertStatement:
+ if (I->asserts()) {
+ VisitExpression(); // Read condition.
+ helper_.ReadPosition(); // read condition start offset.
+ helper_.ReadPosition(); // read condition end offset.
+ Tag tag = helper_.ReadTag(); // read (first part of) message.
+ if (tag == kSomething) {
+ VisitExpression(); // read (rest of) message.
+ }
+ } else {
+ helper_.SkipExpression(); // Read condition.
+ helper_.ReadPosition(); // read condition start offset.
+ helper_.ReadPosition(); // read condition end offset.
+ Tag tag = helper_.ReadTag(); // read (first part of) message.
+ if (tag == kSomething) {
+ helper_.SkipExpression(); // read (rest of) message.
+ }
+ }
+ return;
+ case kLabeledStatement:
+ VisitStatement(); // read body.
+ return;
+ case kBreakStatement:
+ helper_.ReadPosition(); // read position.
+ helper_.ReadUInt(); // read target_index.
+ return;
+ case kWhileStatement:
+ ++depth_.loop_;
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read condition.
+ VisitStatement(); // read body.
+ --depth_.loop_;
+ return;
+ case kDoStatement:
+ ++depth_.loop_;
+ helper_.ReadPosition(); // read position.
+ VisitStatement(); // read body.
+ VisitExpression(); // read condition.
+ --depth_.loop_;
+ return;
+ case kForStatement: {
+ PositionScope scope(&helper_.reader_);
+
+ intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
+
+ ++depth_.loop_;
+ EnterScope(offset);
+
+ TokenPosition position = helper_.ReadPosition(); // read position.
+ intptr_t list_length =
+ helper_.ReadListLength(); // read number of variables.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitVariableDeclaration(); // read ith variable.
+ }
+
+ Tag tag = helper_.ReadTag(); // Read first part of condition.
+ if (tag == kSomething) {
+ VisitExpression(); // read rest of condition.
+ }
+ list_length = helper_.ReadListLength(); // read number of updates.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitExpression(); // read ith update.
+ }
+ VisitStatement(); // read body.
+
+ ExitScope(position, helper_.reader_.max_position());
+ --depth_.loop_;
+ return;
+ }
+ case kForInStatement:
+ case kAsyncForInStatement: {
+ PositionScope scope(&helper_.reader_);
+
+ intptr_t start_offset =
+ helper_.ReaderOffset() - 1; // -1 to include tag byte.
+
+ helper_.ReadPosition(); // read position.
+ TokenPosition body_position =
+ helper_.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 = helper_.ReaderOffset();
+ helper_.SkipVariableDeclaration(); // read variable.
+ VisitExpression(); // read iterable.
+
+ ++depth_.for_in_;
+ AddIteratorVariable();
+ ++depth_.loop_;
+ EnterScope(start_offset);
+
+ {
+ AlternativeReadingScope alt(&helper_.reader_, offset);
+ VisitVariableDeclaration(); // read variable.
+ }
+ VisitStatement(); // read body.
+
+ if (!body_position.IsReal()) {
+ body_position = helper_.reader_.min_position();
+ }
+ // TODO(jensj): From kernel_binary.cc
+ // forinstmt->variable_->set_end_position(forinstmt->position_);
+ ExitScope(body_position, helper_.reader_.max_position());
+ --depth_.loop_;
+ --depth_.for_in_;
+ return;
+ }
+ case kSwitchStatement: {
+ AddSwitchVariable();
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read condition.
+ int case_count = helper_.ReadListLength(); // read number of cases.
+ for (intptr_t i = 0; i < case_count; ++i) {
+ int expression_count =
+ helper_.ReadListLength(); // read number of expressions.
+ for (intptr_t j = 0; j < expression_count; ++j) {
+ helper_.ReadPosition(); // read jth position.
+ VisitExpression(); // read jth expression.
+ }
+ helper_.ReadBool(); // read is_default.
+ VisitStatement(); // read body.
+ }
+ return;
+ }
+ case kContinueSwitchStatement:
+ helper_.ReadPosition(); // read position.
+ helper_.ReadUInt(); // read target_index.
+ return;
+ case kIfStatement:
+ helper_.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;
+ }
+
+ helper_.ReadPosition(); // read position
+ Tag tag = helper_.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();
+
+ helper_.ReadByte(); // read flags
+ intptr_t catch_count =
+ helper_.ReadListLength(); // read number of catches.
+ for (intptr_t i = 0; i < catch_count; ++i) {
+ PositionScope scope(&helper_.reader_);
+ intptr_t offset = helper_.ReaderOffset(); // Catch has no tag.
+
+ EnterScope(offset);
+
+ helper_.ReadPosition(); // read position.
+ VisitDartType(); // Read the guard.
+ tag = helper_.ReadTag(); // read first part of exception.
+ if (tag == kSomething) {
+ VisitVariableDeclaration(); // read exception.
+ }
+ tag = helper_.ReadTag(); // read first part of stack trace.
+ if (tag == kSomething) {
+ VisitVariableDeclaration(); // read stack trace.
+ }
+ VisitStatement(); // read body.
+
+ ExitScope(helper_.reader_.min_position(),
+ helper_.reader_.max_position());
+ }
+
+ FinalizeCatchVariables();
+
+ --depth_.catch_;
+ return;
+ }
+ case kTryFinally: {
+ ++depth_.try_;
+ ++depth_.finally_;
+ AddTryVariables();
+
+ VisitStatement(); // read body.
+
+ --depth_.finally_;
+ --depth_.try_;
+ ++depth_.catch_;
+ AddCatchVariables();
+
+ VisitStatement(); // read finalizer.
+
+ FinalizeCatchVariables();
+
+ --depth_.catch_;
+ return;
+ }
+ case kYieldStatement: {
+ helper_.ReadPosition(); // read position.
+ word flags = helper_.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 = helper_.ReaderOffset() - 1; // -1 to include tag byte.
+ helper_.ReadPosition(); // read position.
+ VisitVariableDeclaration(); // read variable declaration.
+ HandleLocalFunction(offset); // read function node.
+ return;
+ }
+ default:
+ ReportUnexpectedTag("declaration", tag);
+ UNREACHABLE();
+ }
+}
+
+void ScopeBuilder::VisitArguments() {
+ helper_.ReadUInt(); // read argument_count.
+
+ // Types
+ intptr_t list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitDartType(); // read ith type.
+ }
+
+ // Positional.
+ list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitExpression(); // read ith positional.
+ }
+
+ // Named.
+ list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ helper_.SkipStringReference(); // read ith name index.
+ VisitExpression(); // read ith expression.
+ }
+}
+
+void ScopeBuilder::VisitVariableDeclaration() {
+ PositionScope scope(&helper_.reader_);
+
+ intptr_t kernel_offset_no_tag = helper_.ReaderOffset();
+ VariableDeclarationHelper helper(&helper_);
+ 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 = helper_.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 = helper_.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(helper_.data_program_offset_ + kernel_offset_no_tag,
+ variable);
+}
+
+AbstractType& ScopeBuilder::BuildAndVisitVariableType() {
+ const intptr_t offset = helper_.ReaderOffset();
+ AbstractType& type = T.BuildVariableType();
+ helper_.SetOffset(offset); // rewind
+ VisitDartType();
+ return type;
+}
+
+void ScopeBuilder::VisitDartType() {
+ Tag tag = helper_.ReadTag();
+ switch (tag) {
+ case kInvalidType:
+ case kDynamicType:
+ case kVoidType:
+ case kBottomType:
+ // those contain nothing.
+ return;
+ case kInterfaceType:
+ VisitInterfaceType(false);
+ return;
+ case kSimpleInterfaceType:
+ VisitInterfaceType(true);
+ return;
+ case kFunctionType:
+ VisitFunctionType(false);
+ return;
+ case kSimpleFunctionType:
+ VisitFunctionType(true);
+ return;
+ case kTypeParameterType:
+ VisitTypeParameterType();
+ return;
+ default:
+ ReportUnexpectedTag("type", tag);
+ UNREACHABLE();
+ }
+}
+
+void ScopeBuilder::VisitInterfaceType(bool simple) {
+ helper_.ReadUInt(); // read klass_name.
+ if (!simple) {
+ intptr_t length = helper_.ReadListLength(); // read number of types.
+ for (intptr_t i = 0; i < length; ++i) {
+ VisitDartType(); // read the ith type.
+ }
+ }
+}
+
+void ScopeBuilder::VisitFunctionType(bool simple) {
+ if (!simple) {
+ intptr_t list_length =
+ helper_.ReadListLength(); // read type_parameters list length.
+ for (int i = 0; i < list_length; ++i) {
+ TypeParameterHelper helper(&helper_);
+ helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
+ VisitDartType(); // read bound.
+ helper.ReadUntilExcludingAndSetJustRead(
+ TypeParameterHelper::kDefaultType);
+ if (helper_.ReadTag() == kSomething) {
+ VisitDartType(); // read default type.
+ }
+ helper.Finish();
+ }
+ helper_.ReadUInt(); // read required parameter count.
+ helper_.ReadUInt(); // read total parameter count.
+ }
+
+ const intptr_t positional_count =
+ helper_.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 =
+ helper_.ReadListLength(); // read named_parameters list length.
+ for (intptr_t i = 0; i < named_count; ++i) {
+ // read string reference (i.e. named_parameters[i].name).
+ helper_.SkipStringReference();
+ VisitDartType(); // read named_parameters[i].type.
+ }
+ }
+
+ helper_.SkipListOfStrings(); // read positional parameter names.
+
+ if (!simple) {
+ helper_.SkipCanonicalNameReference(); // read typedef reference.
+ }
+
+ VisitDartType(); // read return type.
+}
+
+void ScopeBuilder::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 = helper_.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());
+ }
+ }
+
+ helper_.SkipOptionalDartType(); // read bound bound.
+}
+
+void ScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) {
+ // "Peek" ahead into the function node
+ intptr_t offset = helper_.ReaderOffset();
+
+ FunctionNodeHelper function_node_helper(&helper_);
+ 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 _(&helper_.reader_);
+ num_type_params = helper_.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.
+ TypeTranslator::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.
+ helper_.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 ScopeBuilder::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 ScopeBuilder::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 ScopeBuilder::AddPositionalAndNamedParameters(
+ intptr_t pos,
+ ParameterTypeCheckMode type_check_mode /* = kTypeCheckAllParameters*/,
+ const ProcedureAttributesMetadata& attrs) {
+ // List of positional.
+ intptr_t list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ AddVariableDeclarationParameter(pos++, type_check_mode, attrs);
+ }
+
+ // List of named.
+ list_length = helper_.ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ AddVariableDeclarationParameter(pos++, type_check_mode, attrs);
+ }
+}
+
+void ScopeBuilder::AddVariableDeclarationParameter(
+ intptr_t pos,
+ ParameterTypeCheckMode type_check_mode,
+ const ProcedureAttributesMetadata& attrs) {
+ intptr_t kernel_offset = helper_.ReaderOffset(); // no tag.
+ const InferredTypeMetadata parameter_type =
+ inferred_type_metadata_helper_.GetInferredType(kernel_offset);
+ VariableDeclarationHelper helper(&helper_);
+ 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_check_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 kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod:
+ if (needs_covariant_check_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_check_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(helper_.data_program_offset_ + kernel_offset,
+ variable);
+
+ // The default value may contain 'let' bindings for which the constant
+ // evaluator needs scope bindings.
+ Tag tag = helper_.ReadTag();
+ if (tag == kSomething) {
+ VisitExpression(); // read initializer.
+ }
+}
+
+LocalVariable* ScopeBuilder::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 ScopeBuilder::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 ScopeBuilder::FinalizeExceptionVariable(
+ GrowableArray<LocalVariable*>* variables,
+ GrowableArray<LocalVariable*>* raw_variables,
+ const String& symbol,
+ intptr_t nesting_depth) {
+ // No need to create variables for try/catch-statements inside
+ // nested functions.
+ if (depth_.function_ > 0) return;
+
+ LocalVariable* variable = (*variables)[nesting_depth - 1];
+ LocalVariable* raw_variable;
+ if (variable->is_captured()) {
+ raw_variable =
+ new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+ symbol, AbstractType::dynamic_type());
+ const bool ok = scope_->AddVariable(raw_variable);
+ ASSERT(ok);
+ } else {
+ raw_variable = variable;
+ }
+ raw_variables->EnsureLength(nesting_depth, nullptr);
+ (*raw_variables)[nesting_depth - 1] = raw_variable;
+}
+
+void ScopeBuilder::AddTryVariables() {
+ AddExceptionVariable(&result_->catch_context_variables,
+ ":saved_try_context_var", depth_.try_);
+}
+
+void ScopeBuilder::AddCatchVariables() {
+ AddExceptionVariable(&result_->exception_variables, ":exception",
+ depth_.catch_);
+ AddExceptionVariable(&result_->stack_trace_variables, ":stack_trace",
+ depth_.catch_);
+}
+
+void ScopeBuilder::FinalizeCatchVariables() {
+ const intptr_t unique_id = result_->raw_variable_counter_++;
+ FinalizeExceptionVariable(
+ &result_->exception_variables, &result_->raw_exception_variables,
+ GenerateName(":raw_exception", unique_id), depth_.catch_);
+ FinalizeExceptionVariable(
+ &result_->stack_trace_variables, &result_->raw_stack_trace_variables,
+ GenerateName(":raw_stacktrace", unique_id), depth_.catch_);
+}
+
+void ScopeBuilder::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 ScopeBuilder::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 ScopeBuilder::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 = GetNameFromVariableDeclaration(
+ declaration_binary_offset - helper_.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());
+ }
+}
+
+StringIndex ScopeBuilder::GetNameFromVariableDeclaration(
+ intptr_t kernel_offset,
+ const Function& function) {
+ ExternalTypedData& kernel_data =
+ ExternalTypedData::Handle(Z, function.KernelData());
+ ASSERT(!kernel_data.IsNull());
+
+ // Temporarily go to the variable declaration, read the name.
+ AlternativeReadingScope alt(&helper_.reader_, &kernel_data, kernel_offset);
+ VariableDeclarationHelper helper(&helper_);
+ helper.ReadUntilIncluding(VariableDeclarationHelper::kNameIndex);
+ return helper.name_index_;
+}
+
+const String& ScopeBuilder::GenerateName(const char* prefix, intptr_t suffix) {
+ char name[64];
+ Utils::SNPrint(name, 64, "%s%" Pd "", prefix, suffix);
+ return H.DartSymbolObfuscate(name);
+}
+
+void ScopeBuilder::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 ScopeBuilder::LookupCapturedVariableByName(LocalVariable** variable,
+ const String& name) {
+ if (*variable == NULL) {
+ *variable = scope_->LookupVariable(name, true);
+ ASSERT(*variable != NULL);
+ scope_->CaptureVariable(*variable);
+ }
+}
+
+} // namespace kernel
+} // namespace dart
+
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/frontend/scope_builder.h b/runtime/vm/compiler/frontend/scope_builder.h
new file mode 100644
index 0000000..4d63d92
--- /dev/null
+++ b/runtime/vm/compiler/frontend/scope_builder.h
@@ -0,0 +1,238 @@
+// Copyright (c) 2018, 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.
+
+#ifndef RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_
+#define RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+#include "vm/compiler/frontend/kernel_translation_helper.h"
+#include "vm/hash_map.h"
+#include "vm/object.h"
+#include "vm/parser.h" // For ParsedFunction.
+
+namespace dart {
+namespace kernel {
+
+class ScopeBuildingResult;
+
+class ScopeBuilder {
+ public:
+ explicit ScopeBuilder(ParsedFunction* parsed_function);
+
+ virtual ~ScopeBuilder() = default;
+
+ ScopeBuildingResult* BuildScopes();
+
+ private:
+ void VisitField();
+
+ void VisitProcedure();
+
+ void VisitConstructor();
+
+ void VisitFunctionNode();
+ void VisitNode();
+ void VisitInitializer();
+ void VisitExpression();
+ void VisitStatement();
+ void VisitArguments();
+ void VisitVariableDeclaration();
+ void VisitDartType();
+ void VisitInterfaceType(bool simple);
+ void VisitFunctionType(bool simple);
+ void VisitTypeParameterType();
+ void HandleLocalFunction(intptr_t parent_kernel_offset);
+
+ AbstractType& BuildAndVisitVariableType();
+
+ void EnterScope(intptr_t kernel_offset);
+ void ExitScope(TokenPosition start_position, TokenPosition end_position);
+
+ virtual void ReportUnexpectedTag(const char* variant, Tag tag);
+
+ // This enum controls which parameters would be marked as requring type
+ // check on the callee side.
+ enum ParameterTypeCheckMode {
+ // All parameters will be checked.
+ kTypeCheckAllParameters,
+
+ // Only parameters marked as covariant or generic-covariant-impl will be
+ // checked.
+ kTypeCheckForNonDynamicallyInvokedMethod,
+
+ // Only parameters *not* marked as covariant or generic-covariant-impl will
+ // be checked. The rest would be checked in the method itself.
+ // Inverse of kTypeCheckForNonDynamicallyInvokedMethod.
+ kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
+
+ // No parameters will be checked.
+ kTypeCheckForStaticFunction,
+ };
+
+ // This assumes that the reader is at a FunctionNode,
+ // about to read the positional parameters.
+ void AddPositionalAndNamedParameters(
+ intptr_t pos,
+ ParameterTypeCheckMode type_check_mode,
+ const ProcedureAttributesMetadata& attrs);
+
+ // This assumes that the reader is at a FunctionNode,
+ // about to read a parameter (i.e. VariableDeclaration).
+ void AddVariableDeclarationParameter(
+ intptr_t pos,
+ ParameterTypeCheckMode type_check_mode,
+ const ProcedureAttributesMetadata& attrs);
+
+ LocalVariable* MakeVariable(TokenPosition declaration_pos,
+ TokenPosition token_pos,
+ const String& name,
+ const AbstractType& type,
+ const InferredTypeMetadata* param_type_md = NULL);
+
+ void AddExceptionVariable(GrowableArray<LocalVariable*>* variables,
+ const char* prefix,
+ intptr_t nesting_depth);
+
+ void FinalizeExceptionVariable(GrowableArray<LocalVariable*>* variables,
+ GrowableArray<LocalVariable*>* raw_variables,
+ const String& symbol,
+ intptr_t nesting_depth);
+
+ void AddTryVariables();
+ void AddCatchVariables();
+ void FinalizeCatchVariables();
+ void AddIteratorVariable();
+ void AddSwitchVariable();
+
+ // Record an assignment or reference to a variable. If the occurrence is
+ // in a nested function, ensure that the variable is handled properly as a
+ // captured variable.
+ void LookupVariable(intptr_t declaration_binary_offset);
+
+ StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset,
+ const Function& function);
+
+ const String& GenerateName(const char* prefix, intptr_t suffix);
+
+ void HandleSpecialLoad(LocalVariable** variable, const String& symbol);
+ void LookupCapturedVariableByName(LocalVariable** variable,
+ const String& name);
+
+ struct DepthState {
+ explicit DepthState(intptr_t function)
+ : loop_(0),
+ function_(function),
+ try_(0),
+ catch_(0),
+ finally_(0),
+ for_in_(0) {}
+
+ intptr_t loop_;
+ intptr_t function_;
+ intptr_t try_;
+ intptr_t catch_;
+ intptr_t finally_;
+ intptr_t for_in_;
+ };
+
+ ScopeBuildingResult* result_;
+ ParsedFunction* parsed_function_;
+
+ ActiveClass active_class_;
+
+ TranslationHelper translation_helper_;
+ Zone* zone_;
+
+ FunctionNodeHelper::AsyncMarker current_function_async_marker_;
+ LocalScope* current_function_scope_;
+ LocalScope* scope_;
+ DepthState depth_;
+
+ intptr_t name_index_;
+
+ bool needs_expr_temp_;
+ TokenPosition first_body_token_position_;
+
+ KernelReaderHelper helper_;
+ InferredTypeMetadataHelper inferred_type_metadata_helper_;
+ ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
+ TypeTranslator type_translator_;
+};
+
+struct FunctionScope {
+ intptr_t kernel_offset;
+ LocalScope* scope;
+};
+
+class ScopeBuildingResult : public ZoneAllocated {
+ public:
+ ScopeBuildingResult()
+ : this_variable(NULL),
+ type_arguments_variable(NULL),
+ switch_variable(NULL),
+ finally_return_variable(NULL),
+ setter_value(NULL),
+ yield_jump_variable(NULL),
+ yield_context_variable(NULL),
+ raw_variable_counter_(0) {}
+
+ IntMap<LocalVariable*> locals;
+ IntMap<LocalScope*> scopes;
+ GrowableArray<FunctionScope> function_scopes;
+
+ // Only non-NULL for instance functions.
+ LocalVariable* this_variable;
+
+ // Only non-NULL for factory constructor functions.
+ LocalVariable* type_arguments_variable;
+
+ // Non-NULL when the function contains a switch statement.
+ LocalVariable* switch_variable;
+
+ // Non-NULL when the function contains a return inside a finally block.
+ LocalVariable* finally_return_variable;
+
+ // Non-NULL when the function is a setter.
+ LocalVariable* setter_value;
+
+ // Non-NULL if the function contains yield statement.
+ // TODO(27590) actual variable is called :await_jump_var, we should rename
+ // it to reflect the fact that it is used for both await and yield.
+ LocalVariable* yield_jump_variable;
+
+ // Non-NULL if the function contains yield statement.
+ // TODO(27590) actual variable is called :await_ctx_var, we should rename
+ // it to reflect the fact that it is used for both await and yield.
+ LocalVariable* yield_context_variable;
+
+ // Variables used in exception handlers, one per exception handler nesting
+ // level.
+ GrowableArray<LocalVariable*> exception_variables;
+ GrowableArray<LocalVariable*> stack_trace_variables;
+ GrowableArray<LocalVariable*> catch_context_variables;
+
+ // These are used to access the raw exception/stacktrace variables (and are
+ // used to put them into the captured variables in the context).
+ GrowableArray<LocalVariable*> raw_exception_variables;
+ GrowableArray<LocalVariable*> raw_stack_trace_variables;
+ intptr_t raw_variable_counter_;
+
+ // For-in iterators, one per for-in nesting level.
+ GrowableArray<LocalVariable*> iterator_variables;
+};
+
+bool IsFieldInitializer(const Function& function, Zone* zone);
+
+// Returns true if the given method can skip type checks for all arguments
+// that are not covariant or generic covariant in its implementation.
+bool MethodCanSkipTypeChecksForNonCovariantArguments(
+ const Function& method,
+ const ProcedureAttributesMetadata& attrs);
+
+} // namespace kernel
+} // namespace dart
+
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
+#endif // RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 4e6b0bc..fb6ff15 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -435,6 +435,53 @@
static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
};
+template <typename V>
+class IntKeyRawPointerValueTrait {
+ public:
+ typedef intptr_t Key;
+ typedef V Value;
+
+ struct Pair {
+ Key key;
+ Value value;
+ Pair() : key(NULL), value() {}
+ Pair(const Key key, const Value& value) : key(key), value(value) {}
+ Pair(const Pair& other) : key(other.key), value(other.value) {}
+ };
+
+ static Key KeyOf(Pair kv) { return kv.key; }
+ static Value ValueOf(Pair kv) { return kv.value; }
+ static intptr_t Hashcode(Key key) { return key; }
+ static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
+};
+
+template <typename V>
+class IntMap : public DirectChainedHashMap<IntKeyRawPointerValueTrait<V> > {
+ public:
+ typedef typename IntKeyRawPointerValueTrait<V>::Key Key;
+ typedef typename IntKeyRawPointerValueTrait<V>::Value Value;
+ typedef typename IntKeyRawPointerValueTrait<V>::Pair Pair;
+
+ inline void Insert(const Key& key, const Value& value) {
+ Pair pair(key, value);
+ DirectChainedHashMap<IntKeyRawPointerValueTrait<V> >::Insert(pair);
+ }
+
+ inline V Lookup(const Key& key) {
+ Pair* pair =
+ DirectChainedHashMap<IntKeyRawPointerValueTrait<V> >::Lookup(key);
+ if (pair == NULL) {
+ return V();
+ } else {
+ return pair->value;
+ }
+ }
+
+ inline Pair* LookupPair(const Key& key) {
+ return DirectChainedHashMap<IntKeyRawPointerValueTrait<V> >::Lookup(key);
+ }
+};
+
} // namespace dart
#endif // RUNTIME_VM_HASH_MAP_H_
diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h
index 2bc0bfc..954ef90 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -6,10 +6,10 @@
#define RUNTIME_VM_KERNEL_LOADER_H_
#if !defined(DART_PRECOMPILED_RUNTIME)
-#include <map>
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
#include "vm/compiler/frontend/kernel_to_il.h"
+#include "vm/hash_map.h"
#include "vm/kernel.h"
#include "vm/object.h"
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index eb810c7..3e0d919 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -253,7 +253,7 @@
kernel::ScopeBuildingResult* ParsedFunction::EnsureKernelScopes() {
if (kernel_scopes_ == NULL) {
- kernel::StreamingScopeBuilder builder(this);
+ kernel::ScopeBuilder builder(this);
kernel_scopes_ = builder.BuildScopes();
}
return kernel_scopes_;