Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(941)

Unified Diff: runtime/vm/kernel_binary_flowgraph.cc

Issue 2854393002: [kernel] [partial] Streaming of kernel binary without AST nodes (Closed)
Patch Set: Address comments; small fixes; rebased. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/kernel_binary_flowgraph.h ('k') | runtime/vm/kernel_reader.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/kernel_binary_flowgraph.cc
diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc
index ca318176b4f2fc75745a7c9406ae88a344333d5f..dec055dba6fbb19866275ad23170c33afddf2d56 100644
--- a/runtime/vm/kernel_binary_flowgraph.cc
+++ b/runtime/vm/kernel_binary_flowgraph.cc
@@ -4,6 +4,7 @@
#include "vm/kernel_binary_flowgraph.h"
+#include "vm/longjump.h"
#include "vm/object_store.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -13,54 +14,599 @@ namespace kernel {
#define Z (zone_)
#define H (translation_helper_)
+#define T (type_translator_)
#define I Isolate::Current()
-StreamingConstantEvaluator::StreamingConstantEvaluator(
+
+StreamingDartTypeTranslator::StreamingDartTypeTranslator(
StreamingFlowGraphBuilder* builder,
- Zone* zone,
- TranslationHelper* h,
- DartTypeTranslator* type_translator)
+ bool finalize)
+ : builder_(builder),
+ translation_helper_(builder->translation_helper_),
+ active_class_(builder->active_class()),
+ type_parameter_scope_(NULL),
+ zone_(translation_helper_.zone()),
+ result_(AbstractType::Handle(translation_helper_.zone())),
+ finalize_(finalize) {}
+
+
+AbstractType& StreamingDartTypeTranslator::BuildType() {
+ BuildTypeInternal();
+
+ // We return a new `ZoneHandle` here on purpose: The intermediate language
+ // instructions do not make a copy of the handle, so we do it.
+ return dart::AbstractType::ZoneHandle(Z, result_.raw());
+}
+
+void StreamingDartTypeTranslator::BuildTypeInternal() {
+ Tag tag = builder_->ReadTag();
+ switch (tag) {
+ case kInvalidType:
+ result_ = ClassFinalizer::NewFinalizedMalformedType(
+ Error::Handle(Z), // No previous error.
+ dart::Script::Handle(Z, dart::Script::null()),
+ TokenPosition::kNoSource, "[InvalidType] in Kernel IR.");
+ break;
+ case kDynamicType:
+ result_ = Object::dynamic_type().raw();
+ break;
+ case kVoidType:
+ result_ = Object::void_type().raw();
+ break;
+ case kBottomType:
+ result_ = dart::Class::Handle(Z, I->object_store()->null_class())
+ .CanonicalType();
+ break;
+ case kInterfaceType:
+ BuildInterfaceType(false);
+ break;
+ case kSimpleInterfaceType:
+ BuildInterfaceType(true);
+ break;
+ case kFunctionType:
+ BuildFunctionType(false);
+ break;
+ case kSimpleFunctionType:
+ BuildFunctionType(true);
+ break;
+ case kTypeParameterType:
+ BuildTypeParameterType();
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+void StreamingDartTypeTranslator::BuildInterfaceType(bool simple) {
+ // NOTE: That an interface type like `T<A, B>` is considered to be
+ // malformed iff `T` is malformed.
+ // => We therefore ignore errors in `A` or `B`.
+
+ NameIndex klass_name =
+ builder_->ReadCanonicalNameReference(); // read klass_name.
+
+ intptr_t length;
+ if (simple) {
+ length = 0;
+ } else {
+ length = builder_->ReadListLength(); // read type_arguments list length.
+ }
+ const TypeArguments& type_arguments =
+ BuildTypeArguments(length); // read type arguments.
+
+ dart::Object& klass =
+ dart::Object::Handle(Z, H.LookupClassByKernelClass(klass_name));
+ result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource);
+ if (finalize_) {
+ ASSERT(active_class_->klass != NULL);
+ result_ = ClassFinalizer::FinalizeType(*active_class_->klass, result_);
+ }
+}
+
+void StreamingDartTypeTranslator::BuildFunctionType(bool simple) {
+ intptr_t list_length = 0;
+ intptr_t* type_parameters = NULL;
+ if (!simple) {
+ list_length =
+ builder_->ReadListLength(); // read type_parameters list length
+ type_parameters = new intptr_t[list_length];
+ for (int i = 0; i < list_length; ++i) {
+ type_parameters[i] = builder_->ReaderOffset();
+ builder_->SkipStringReference(); // read string index (name).
+ builder_->SkipDartType(); // read dart type.
+ }
+ }
+
+ // The spec describes in section "19.1 Static Types":
+ //
+ // Any use of a malformed type gives rise to a static warning. A
+ // malformed type is then interpreted as dynamic by the static type
+ // checker and the runtime unless explicitly specified otherwise.
+ //
+ // So we convert malformed return/parameter types to `dynamic`.
+ TypeParameterScope scope(this, type_parameters, list_length);
+
+ Function& signature_function = Function::ZoneHandle(
+ Z, Function::NewSignatureFunction(*active_class_->klass,
+ TokenPosition::kNoSource));
+
+ intptr_t required_count;
+ intptr_t all_count;
+ intptr_t positional_count;
+ if (!simple) {
+ required_count = builder_->ReadUInt(); // read required parameter count.
+ all_count = builder_->ReadUInt(); // read total parameter count.
+ positional_count =
+ builder_->ReadListLength(); // read positional_parameters list length.
+ } else {
+ positional_count =
+ builder_->ReadListLength(); // read positional_parameters list length.
+ required_count = positional_count;
+ all_count = positional_count;
+ }
+
+ const Array& parameter_types =
+ Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
+ signature_function.set_parameter_types(parameter_types);
+ const Array& parameter_names =
+ Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
+ signature_function.set_parameter_names(parameter_names);
+
+ intptr_t pos = 0;
+ parameter_types.SetAt(pos, AbstractType::dynamic_type());
+ parameter_names.SetAt(pos, H.DartSymbol("_receiver_"));
+ ++pos;
+ for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
+ BuildTypeInternal(); // read ith positional parameter.
+ if (result_.IsMalformed()) {
+ result_ = AbstractType::dynamic_type().raw();
+ }
+ parameter_types.SetAt(pos, result_);
+ parameter_names.SetAt(pos, H.DartSymbol("noname"));
+ }
+
+ // The additional first parameter is the receiver type (set to dynamic).
+ signature_function.set_num_fixed_parameters(1 + required_count);
+ signature_function.SetNumOptionalParameters(
+ all_count - required_count, positional_count > required_count);
+
+ if (!simple) {
+ const intptr_t named_count =
+ builder_->ReadListLength(); // read named_parameters list length.
+ for (intptr_t i = 0; i < named_count; ++i, ++pos) {
+ // read string reference (i.e. named_parameters[i].name).
+ dart::String& name = H.DartSymbol(builder_->ReadStringReference());
+ BuildTypeInternal(); // read named_parameters[i].type.
+ if (result_.IsMalformed()) {
+ result_ = AbstractType::dynamic_type().raw();
+ }
+ parameter_types.SetAt(pos, result_);
+ parameter_names.SetAt(pos, name);
+ }
+ }
+
+ BuildTypeInternal(); // read return type.
+ if (result_.IsMalformed()) {
+ result_ = AbstractType::dynamic_type().raw();
+ }
+ signature_function.set_result_type(result_);
+
+ Type& signature_type =
+ Type::ZoneHandle(Z, signature_function.SignatureType());
+
+ if (finalize_) {
+ signature_type ^=
+ ClassFinalizer::FinalizeType(*active_class_->klass, signature_type);
+ // Do not refer to signature_function anymore, since it may have been
+ // replaced during canonicalization.
+ signature_function = Function::null();
+ }
+
+ result_ = signature_type.raw();
+}
+
+static intptr_t FindTypeParameterIndex(intptr_t* parameters,
+ intptr_t parameters_count,
+ intptr_t look_for) {
+ for (intptr_t i = 0; i < parameters_count; ++i) {
+ if (look_for == parameters[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static intptr_t FindTypeParameterIndex(List<TypeParameter>* parameters,
+ intptr_t look_for) {
+ for (intptr_t i = 0; i < parameters->length(); ++i) {
+ if (look_for == (*parameters)[i]->kernel_offset()) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void StreamingDartTypeTranslator::BuildTypeParameterType() {
+ builder_->ReadUInt(); // read parameter index.
+ intptr_t binary_offset = builder_->ReadUInt(); // read binary offset.
+ builder_->SkipOptionalDartType(); // read bound.
+
+ if (binary_offset == 0) {
+ // TODO(jensj): This doesn't appear to actually happen.
+ UNIMPLEMENTED();
+ return;
+ }
+
+ for (TypeParameterScope* scope = type_parameter_scope_; scope != NULL;
+ scope = scope->outer()) {
+ const intptr_t index = FindTypeParameterIndex(
+ scope->parameters(), scope->parameters_count(), binary_offset);
+ if (index >= 0) {
+ result_ ^= dart::Type::DynamicType();
+ return;
+ }
+ }
+
+ if ((active_class_->member != NULL) && active_class_->member->IsProcedure()) {
+ Procedure* procedure = Procedure::Cast(active_class_->member);
+ if ((procedure->function() != NULL) &&
+ (procedure->function()->type_parameters().length() > 0)) {
+ //
+ // WARNING: This is a little hackish:
+ //
+ // We have a static factory constructor. The kernel IR gives the factory
+ // constructor function it's own type parameters (which are equal in name
+ // and number to the ones of the enclosing class).
+ // I.e.,
+ //
+ // class A<T> {
+ // factory A.x() { return new B<T>(); }
+ // }
+ //
+ // is basically translated to this:
+ //
+ // class A<T> {
+ // static A.x<T'>() { return new B<T'>(); }
+ // }
+ //
+ const intptr_t index = FindTypeParameterIndex(
+ &procedure->function()->type_parameters(), binary_offset);
+ if (index >= 0) {
+ if (procedure->kind() == Procedure::kFactory) {
+ // The index of the type parameter in [parameters] is
+ // the same index into the `klass->type_parameters()` array.
+ result_ ^= dart::TypeArguments::Handle(
+ Z, active_class_->klass->type_parameters())
+ .TypeAt(index);
+ } else {
+ result_ ^= dart::Type::DynamicType();
+ }
+ return;
+ }
+ }
+ }
+
+ ASSERT(active_class_->kernel_class != NULL);
+ List<TypeParameter>* parameters =
+ &active_class_->kernel_class->type_parameters();
+ const intptr_t index = FindTypeParameterIndex(parameters, binary_offset);
+ if (index >= 0) {
+ // The index of the type parameter in [parameters] is
+ // the same index into the `klass->type_parameters()` array.
+ result_ ^=
+ dart::TypeArguments::Handle(Z, active_class_->klass->type_parameters())
+ .TypeAt(index);
+ return;
+ }
+
+ UNREACHABLE();
+}
+
+const TypeArguments& StreamingDartTypeTranslator::BuildTypeArguments(
+ intptr_t length) {
+ bool only_dynamic = true;
+ intptr_t offset = builder_->ReaderOffset();
+ for (intptr_t i = 0; i < length; ++i) {
+ if (builder_->ReadTag() != kDynamicType) { // read ith type's tag.
+ only_dynamic = false;
+ builder_->SetOffset(offset);
+ break;
+ }
+ }
+ TypeArguments& type_arguments = TypeArguments::ZoneHandle(Z);
+ if (!only_dynamic) {
+ type_arguments = TypeArguments::New(length);
+ for (intptr_t i = 0; i < length; ++i) {
+ BuildTypeInternal(); // read ith type.
+ if (!result_.IsDynamicType()) {
+ only_dynamic = false;
+ }
+ if (result_.IsMalformed()) {
+ type_arguments = TypeArguments::null();
+ return type_arguments;
+ }
+ type_arguments.SetTypeAt(i, result_);
+ }
+
+ if (finalize_) {
+ type_arguments = type_arguments.Canonicalize();
+ }
+ }
+ return type_arguments;
+}
+
+const TypeArguments&
+StreamingDartTypeTranslator::BuildInstantiatedTypeArguments(
+ const dart::Class& receiver_class,
+ intptr_t length) {
+ const TypeArguments& type_arguments = BuildTypeArguments(length);
+ if (type_arguments.IsNull()) return type_arguments;
+
+ // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to
+ // finalize the argument types.
+ // (This can for example make the [type_arguments] vector larger)
+ Type& type = Type::Handle(
+ Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource));
+ if (finalize_) {
+ type ^=
+ ClassFinalizer::FinalizeType(*builder_->active_class()->klass, type);
+ }
+
+ const TypeArguments& instantiated_type_arguments =
+ TypeArguments::ZoneHandle(Z, type.arguments());
+ return instantiated_type_arguments;
+}
+
+
+const Type& StreamingDartTypeTranslator::ReceiverType(
+ const dart::Class& klass) {
+ ASSERT(!klass.IsNull());
+ ASSERT(!klass.IsTypedefClass());
+ // Note that if klass is _Closure, the returned type will be _Closure,
+ // and not the signature type.
+ Type& type = Type::ZoneHandle(Z, klass.CanonicalType());
+ if (!type.IsNull()) {
+ return type;
+ }
+ type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
+ klass.token_pos());
+ if (klass.is_type_finalized()) {
+ type ^= ClassFinalizer::FinalizeType(klass, type);
+ klass.SetCanonicalType(type);
+ }
+ return type;
+}
+
+
+StreamingConstantEvaluator::StreamingConstantEvaluator(
+ StreamingFlowGraphBuilder* builder)
: builder_(builder),
isolate_(Isolate::Current()),
- zone_(zone),
- translation_helper_(*h),
- // type_translator_(*type_translator),
+ zone_(builder_->zone_),
+ translation_helper_(builder_->translation_helper_),
+ type_translator_(builder_->type_translator_),
script_(Script::Handle(
- zone,
+ zone_,
builder == NULL ? Script::null()
: builder_->parsed_function()->function().script())),
- result_(Instance::Handle(zone)) {}
+ result_(Instance::Handle(zone_)) {}
-Instance& StreamingConstantEvaluator::EvaluateExpression() {
- intptr_t offset = builder_->ReaderOffset();
+Instance& StreamingConstantEvaluator::EvaluateExpression(intptr_t offset,
+ bool reset_position) {
if (!GetCachedConstant(offset, &result_)) {
+ intptr_t original_offset = builder_->ReaderOffset();
+ builder_->SetOffset(offset);
uint8_t payload = 0;
- Tag tag = builder_->ReadTag(&payload);
+ Tag tag = builder_->ReadTag(&payload); // read tag.
switch (tag) {
+ case kVariableGet:
+ EvaluateVariableGet();
+ break;
+ case kSpecializedVariableGet:
+ EvaluateVariableGet(payload);
+ break;
+ case kPropertyGet:
+ EvaluatePropertyGet();
+ break;
case kStaticGet:
EvaluateStaticGet();
break;
+ case kMethodInvocation:
+ EvaluateMethodInvocation();
+ break;
+ case kStaticInvocation:
+ case kConstStaticInvocation:
+ EvaluateStaticInvocation();
+ break;
+ case kConstructorInvocation:
+ case kConstConstructorInvocation:
+ EvaluateConstructorInvocationInternal();
+ break;
+ case kNot:
+ EvaluateNot();
+ break;
+ case kLogicalExpression:
+ EvaluateLogicalExpression();
+ break;
+ case kConditionalExpression:
+ EvaluateConditionalExpression();
+ break;
+ case kStringConcatenation:
+ EvaluateStringConcatenation();
+ break;
case kSymbolLiteral:
EvaluateSymbolLiteral();
break;
+ case kTypeLiteral:
+ EvaluateTypeLiteral();
+ break;
+ case kListLiteral:
+ case kConstListLiteral:
+ EvaluateListLiteralInternal();
+ break;
+ case kMapLiteral:
+ case kConstMapLiteral:
+ EvaluateMapLiteralInternal();
+ break;
+ case kLet:
+ EvaluateLet();
+ break;
+ case kBigIntLiteral:
+ EvaluateBigIntLiteral();
+ break;
+ case kStringLiteral:
+ EvaluateStringLiteral();
+ break;
+ case kSpecialIntLiteral:
+ EvaluateIntLiteral(payload);
+ break;
+ case kNegativeIntLiteral:
+ EvaluateIntLiteral(true);
+ break;
+ case kPositiveIntLiteral:
+ EvaluateIntLiteral(false);
+ break;
case kDoubleLiteral:
EvaluateDoubleLiteral();
break;
+ case kTrueLiteral:
+ EvaluateBoolLiteral(true);
+ break;
+ case kFalseLiteral:
+ EvaluateBoolLiteral(false);
+ break;
+ case kNullLiteral:
+ EvaluateNullLiteral();
+ break;
default:
UNREACHABLE();
}
CacheConstantValue(offset, result_);
+ if (reset_position) builder_->SetOffset(original_offset);
+ }
+ // We return a new `ZoneHandle` here on purpose: The intermediate language
+ // instructions do not make a copy of the handle, so we do it.
+ return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Instance& StreamingConstantEvaluator::EvaluateListLiteral(intptr_t offset,
+ bool reset_position) {
+ if (!GetCachedConstant(offset, &result_)) {
+ intptr_t original_offset = builder_->ReaderOffset();
+ builder_->SetOffset(offset);
+ builder_->ReadTag(); // skip tag.
+ EvaluateListLiteralInternal();
+
+ CacheConstantValue(offset, result_);
+ if (reset_position) builder_->SetOffset(original_offset);
+ }
+ // We return a new `ZoneHandle` here on purpose: The intermediate language
+ // instructions do not make a copy of the handle, so we do it.
+ return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Instance& StreamingConstantEvaluator::EvaluateMapLiteral(intptr_t offset,
+ bool reset_position) {
+ if (!GetCachedConstant(offset, &result_)) {
+ intptr_t original_offset = builder_->ReaderOffset();
+ builder_->SetOffset(offset);
+ builder_->ReadTag(); // skip tag.
+ EvaluateMapLiteralInternal();
+
+ CacheConstantValue(offset, result_);
+ if (reset_position) builder_->SetOffset(original_offset);
+ }
+ // We return a new `ZoneHandle` here on purpose: The intermediate language
+ // instructions do not make a copy of the handle, so we do it.
+ return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Instance& StreamingConstantEvaluator::EvaluateConstructorInvocation(
+ intptr_t offset,
+ bool reset_position) {
+ if (!GetCachedConstant(offset, &result_)) {
+ intptr_t original_offset = builder_->ReaderOffset();
+ builder_->SetOffset(offset);
+ builder_->ReadTag(); // skip tag.
+ EvaluateConstructorInvocationInternal();
+
+ CacheConstantValue(offset, result_);
+ if (reset_position) builder_->SetOffset(original_offset);
}
// We return a new `ZoneHandle` here on purpose: The intermediate language
// instructions do not make a copy of the handle, so we do it.
- return dart::Instance::ZoneHandle(Z, result_.raw());
+ return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Object& StreamingConstantEvaluator::EvaluateExpressionSafe(intptr_t offset) {
+ LongJumpScope jump;
+ if (setjmp(*jump.Set()) == 0) {
+ return EvaluateExpression(offset);
+ } else {
+ Thread* thread = H.thread();
+ Error& error = Error::Handle(Z);
+ error = thread->sticky_error();
+ thread->clear_sticky_error();
+ return error;
+ }
+}
+
+void StreamingConstantEvaluator::EvaluateVariableGet() {
+ // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
+ // been executed already. It therefore must have a constant object associated
+ // with it.
+ builder_->ReadPosition(); // read position.
+ intptr_t variable_kernel_position =
+ builder_->ReadUInt(); // read kernel position.
+ builder_->ReadUInt(); // read relative variable index.
+ builder_->SkipOptionalDartType(); // read promoted type.
+ LocalVariable* variable = builder_->LookupVariable(variable_kernel_position);
+ ASSERT(variable->IsConst());
+ result_ = variable->ConstValue()->raw();
+}
+
+void StreamingConstantEvaluator::EvaluateVariableGet(uint8_t payload) {
+ // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
+ // been executed already. It therefore must have a constant object associated
+ // with it.
+ builder_->ReadPosition(); // read position.
+ intptr_t variable_kernel_position =
+ builder_->ReadUInt(); // read kernel position.
+ LocalVariable* variable = builder_->LookupVariable(variable_kernel_position);
+ ASSERT(variable->IsConst());
+ result_ = variable->ConstValue()->raw();
+}
+
+void StreamingConstantEvaluator::EvaluatePropertyGet() {
+ builder_->ReadPosition(); // read position.
+ intptr_t expression_offset = builder_->ReaderOffset();
+ builder_->SkipExpression(); // read receiver.
+ StringIndex name = builder_->ReadNameAsStringIndex(); // read name.
+ // Read unused "interface_target_reference".
+ builder_->SkipCanonicalNameReference();
+
+ if (H.StringEquals(name, "length")) {
+ EvaluateExpression(expression_offset);
+ if (result_.IsString()) {
+ const dart::String& str =
+ dart::String::Handle(Z, dart::String::RawCast(result_.raw()));
+ result_ = Integer::New(str.Length());
+ } else {
+ H.ReportError(
+ "Constant expressions can only call "
+ "'length' on string constants.");
+ }
+ } else {
+ UNREACHABLE();
+ }
}
void StreamingConstantEvaluator::EvaluateStaticGet() {
- builder_->ReadPosition();
- NameIndex target = builder_->ReadCanonicalNameReference();
+ builder_->ReadPosition(); // read position.
+ NameIndex target =
+ builder_->ReadCanonicalNameReference(); // read target_reference.
if (H.IsField(target)) {
const dart::Field& field =
@@ -92,10 +638,183 @@ void StreamingConstantEvaluator::EvaluateStaticGet() {
}
}
+void StreamingConstantEvaluator::EvaluateMethodInvocation() {
+ builder_->ReadPosition(); // read position.
+ // This method call wasn't cached, so receiver et al. isn't cached either.
+ const dart::Instance& receiver =
+ EvaluateExpression(builder_->ReaderOffset(), false); // read receiver.
+ dart::Class& klass = dart::Class::Handle(
+ Z, isolate_->class_table()->At(receiver.GetClassId()));
+ ASSERT(!klass.IsNull());
+
+ // Search the superclass chain for the selector.
+ dart::Function& function = dart::Function::Handle(Z);
+ const dart::String& method_name =
+ builder_->ReadNameAsMethodName(); // read name.
+ while (!klass.IsNull()) {
+ function = klass.LookupDynamicFunctionAllowPrivate(method_name);
+ if (!function.IsNull()) break;
+ klass = klass.SuperClass();
+ }
+
+ // The frontend should guarantee that [MethodInvocation]s inside constant
+ // expressions are always valid.
+ ASSERT(!function.IsNull());
+
+ // Read first parts of arguments: count and list of types.
+ intptr_t argument_count = builder_->PeekArgumentsCount();
+ // Dart does not support generic methods yet.
+ ASSERT(builder_->PeekArgumentsTypeCount() == 0);
+ builder_->SkipArgumentsBeforeActualArguments();
+
+ // Run the method and canonicalize the result.
+ const Object& result = RunFunction(function, argument_count, &receiver, NULL);
+ result_ ^= result.raw();
+ result_ = H.Canonicalize(result_);
+
+ builder_->SkipCanonicalNameReference(); // read "interface_target_reference"
+}
+
+void StreamingConstantEvaluator::EvaluateStaticInvocation() {
+ builder_->ReadPosition(); // read position.
+ NameIndex procedue_reference =
+ builder_->ReadCanonicalNameReference(); // read procedure reference.
+
+ const Function& function = Function::ZoneHandle(
+ Z, H.LookupStaticMethodByKernelProcedure(procedue_reference));
+ dart::Class& klass = dart::Class::Handle(Z, function.Owner());
+
+ intptr_t argument_count =
+ builder_->ReadUInt(); // read arguments part #1: arguments count.
+
+ // Build the type arguments vector (if necessary).
+ const TypeArguments* type_arguments =
+ TranslateTypeArguments(function, &klass); // read argument types.
+
+ // read positional and named parameters.
+ const Object& result =
+ RunFunction(function, argument_count, NULL, type_arguments);
+ result_ ^= result.raw();
+ result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateConstructorInvocationInternal() {
+ builder_->ReadPosition(); // read position.
+
+ NameIndex target = builder_->ReadCanonicalNameReference(); // read target.
+ const Function& constructor =
+ Function::Handle(Z, H.LookupConstructorByKernelConstructor(target));
+ dart::Class& klass = dart::Class::Handle(Z, constructor.Owner());
+
+ intptr_t argument_count =
+ builder_->ReadUInt(); // read arguments part #1: arguments count.
+
+ // Build the type arguments vector (if necessary).
+ const TypeArguments* type_arguments =
+ TranslateTypeArguments(constructor, &klass); // read argument types.
+
+ // Prepare either the instance or the type argument vector for the constructor
+ // call.
+ Instance* receiver = NULL;
+ const TypeArguments* type_arguments_argument = NULL;
+ if (!constructor.IsFactory()) {
+ receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld));
+ if (type_arguments != NULL) {
+ receiver->SetTypeArguments(*type_arguments);
+ }
+ } else {
+ type_arguments_argument = type_arguments;
+ }
+
+ // read positional and named parameters.
+ const Object& result = RunFunction(constructor, argument_count, receiver,
+ type_arguments_argument);
+
+ if (constructor.IsFactory()) {
+ // Factories return the new object.
+ result_ ^= result.raw();
+ result_ = H.Canonicalize(result_);
+ } else {
+ ASSERT(!receiver->IsNull());
+ result_ = H.Canonicalize(*receiver);
+ }
+}
+
+void StreamingConstantEvaluator::EvaluateNot() {
+ result_ ^= Bool::Get(!EvaluateBooleanExpressionHere()).raw();
+}
+
+void StreamingConstantEvaluator::EvaluateLogicalExpression() {
+ bool left = EvaluateBooleanExpressionHere(); // read left.
+ LogicalExpression::Operator op = static_cast<LogicalExpression::Operator>(
+ builder_->ReadByte()); // read operator.
+ if (op == LogicalExpression::kAnd) {
+ if (left) {
+ EvaluateBooleanExpressionHere(); // read right.
+ } else {
+ builder_->SkipExpression(); // read right.
+ }
+ } else {
+ ASSERT(op == LogicalExpression::kOr);
+ if (!left) {
+ EvaluateBooleanExpressionHere(); // read right.
+ } else {
+ builder_->SkipExpression(); // read right.
+ }
+ }
+}
+
+void StreamingConstantEvaluator::EvaluateConditionalExpression() {
+ bool condition = EvaluateBooleanExpressionHere();
+ if (condition) {
+ EvaluateExpression(builder_->ReaderOffset(), false); // read then.
+ builder_->SkipExpression(); // read otherwise.
+ } else {
+ builder_->SkipExpression(); // read then.
+ EvaluateExpression(builder_->ReaderOffset(), false); // read otherwise.
+ }
+ builder_->SkipOptionalDartType(); // read unused static type.
+}
+
+void StreamingConstantEvaluator::EvaluateStringConcatenation() {
+ builder_->ReadPosition(); // read position.
+ intptr_t length = builder_->ReadListLength(); // read list length.
+
+ bool all_string = true;
+ const Array& strings = Array::Handle(Z, Array::New(length));
+ for (intptr_t i = 0; i < length; ++i) {
+ EvaluateExpression(builder_->ReaderOffset(),
+ false); // read ith expression.
+ strings.SetAt(i, result_);
+ all_string = all_string && result_.IsString();
+ }
+ if (all_string) {
+ result_ = dart::String::ConcatAll(strings, Heap::kOld);
+ result_ = H.Canonicalize(result_);
+ } else {
+ // Get string interpolation function.
+ const dart::Class& cls = dart::Class::Handle(
+ Z, dart::Library::LookupCoreClass(Symbols::StringBase()));
+ ASSERT(!cls.IsNull());
+ const Function& func = Function::Handle(
+ Z, cls.LookupStaticFunction(
+ dart::Library::PrivateCoreLibName(Symbols::Interpolate())));
+ ASSERT(!func.IsNull());
+
+ // Build argument array to pass to the interpolation function.
+ const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld));
+ interpolate_arg.SetAt(0, strings);
+
+ // Run and canonicalize.
+ const Object& result =
+ RunFunction(func, interpolate_arg, Array::null_array());
+ result_ = H.Canonicalize(dart::String::Cast(result));
+ }
+}
void StreamingConstantEvaluator::EvaluateSymbolLiteral() {
- StringIndex str_index(builder_->ReadUInt());
- const dart::String& symbol_value = H.DartSymbol(str_index);
+ const dart::String& symbol_value = H.DartSymbol(
+ builder_->ReadStringReference()); // read index into string table.
const dart::Class& symbol_class =
dart::Class::ZoneHandle(Z, I->object_store()->symbol_class());
@@ -107,424 +826,3493 @@ void StreamingConstantEvaluator::EvaluateSymbolLiteral() {
symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value);
}
+void StreamingConstantEvaluator::EvaluateTypeLiteral() {
+ const AbstractType& type = T.BuildType();
+ if (type.IsMalformed()) {
+ H.ReportError("Malformed type literal in constant expression.");
+ }
+ result_ = type.raw();
+}
-void StreamingConstantEvaluator::EvaluateDoubleLiteral() {
- StringIndex str_index(builder_->ReadUInt());
- result_ = dart::Double::New(H.DartString(str_index), Heap::kOld);
+void StreamingConstantEvaluator::EvaluateListLiteralInternal() {
+ builder_->ReadPosition(); // read position.
+ const TypeArguments& type_arguments = T.BuildTypeArguments(1); // read type.
+ intptr_t length = builder_->ReadListLength(); // read list length.
+ const Array& const_list =
+ Array::ZoneHandle(Z, Array::New(length, Heap::kOld));
+ const_list.SetTypeArguments(type_arguments);
+ for (intptr_t i = 0; i < length; ++i) {
+ const Instance& expression = EvaluateExpression(
+ builder_->ReaderOffset(), false); // read ith expression.
+ const_list.SetAt(i, expression);
+ }
+ const_list.MakeImmutable();
+ result_ = H.Canonicalize(const_list);
+}
+
+void StreamingConstantEvaluator::EvaluateMapLiteralInternal() {
+ builder_->ReadPosition(); // read position.
+ const TypeArguments& type_arguments =
+ T.BuildTypeArguments(2); // read key type and value type.
+
+ intptr_t length = builder_->ReadListLength(); // read length of entries.
+
+ // This MapLiteral wasn't cached, so content isn't cached either.
+ Array& const_kv_array =
+ Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld));
+ for (intptr_t i = 0; i < length; ++i) {
+ const_kv_array.SetAt(2 * i + 0, EvaluateExpression(builder_->ReaderOffset(),
+ false)); // read key.
+ const_kv_array.SetAt(2 * i + 1, EvaluateExpression(builder_->ReaderOffset(),
+ false)); // read value.
+ }
+
+ const_kv_array.MakeImmutable();
+ const_kv_array ^= H.Canonicalize(const_kv_array);
+
+ const dart::Class& map_class = dart::Class::Handle(
+ Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap()));
+ ASSERT(!map_class.IsNull());
+ ASSERT(map_class.NumTypeArguments() == 2);
+
+ const dart::Field& field = dart::Field::Handle(
+ Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs")));
+ ASSERT(!field.IsNull());
+
+ // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`!
+ result_ = Instance::New(map_class, Heap::kOld);
+ ASSERT(!result_.IsNull());
+ result_.SetTypeArguments(type_arguments);
+ result_.SetField(field, const_kv_array);
result_ = H.Canonicalize(result_);
}
+void StreamingConstantEvaluator::EvaluateLet() {
+ intptr_t kernel_position = builder_->ReaderOffset();
+ LocalVariable* local = builder_->LookupVariable(kernel_position);
-RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall(
- const dart::Class& type_class,
- const TypeArguments& type_arguments,
- const Function& constructor,
- const Object& argument) {
- // Factories have one extra argument: the type arguments.
- // Constructors have 1 extra arguments: receiver.
- const int kNumArgs = 1;
- const int kNumExtraArgs = 1;
- const int num_arguments = kNumArgs + kNumExtraArgs;
- const Array& arg_values =
- Array::Handle(Z, Array::New(num_arguments, Heap::kOld));
- Instance& instance = Instance::Handle(Z);
- if (!constructor.IsFactory()) {
- instance = Instance::New(type_class, Heap::kOld);
- if (!type_arguments.IsNull()) {
- ASSERT(type_arguments.IsInstantiated());
- instance.SetTypeArguments(
- TypeArguments::Handle(Z, type_arguments.Canonicalize()));
- }
- arg_values.SetAt(0, instance);
+ // read variable declaration.
+ builder_->ReadPosition(); // read position.
+ builder_->ReadPosition(); // read equals position.
+ builder_->ReadFlags(); // read flags.
+ builder_->SkipStringReference(); // read name index.
+ builder_->SkipDartType(); // read type.
+ Tag tag = builder_->ReadTag(); // read (first part of) initializer.
+ if (tag == kNothing) {
+ local->SetConstValue(Instance::ZoneHandle(Z, dart::Instance::null()));
} else {
- // Prepend type_arguments to list of arguments to factory.
- ASSERT(type_arguments.IsZoneHandle());
- arg_values.SetAt(0, type_arguments);
+ local->SetConstValue(EvaluateExpression(
+ builder_->ReaderOffset(), false)); // read rest of initializer.
}
- arg_values.SetAt((0 + kNumExtraArgs), argument);
- const Array& args_descriptor = Array::Handle(
- Z, ArgumentsDescriptor::New(num_arguments, Object::empty_array()));
- const Object& result = Object::Handle(
- Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor));
- ASSERT(!result.IsError());
- if (constructor.IsFactory()) {
- // The factory method returns the allocated object.
- instance ^= result.raw();
+
+ EvaluateExpression(builder_->ReaderOffset(), false); // read body
+}
+
+void StreamingConstantEvaluator::EvaluateBigIntLiteral() {
+ const dart::String& value =
+ H.DartString(builder_->ReadStringReference()); // read string reference.
+ result_ = Integer::New(value, Heap::kOld);
+ result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateStringLiteral() {
+ result_ = H.DartSymbol(builder_->ReadStringReference())
+ .raw(); // read string reference.
+}
+
+void StreamingConstantEvaluator::EvaluateIntLiteral(uint8_t payload) {
+ int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
+ result_ = dart::Integer::New(value, Heap::kOld);
+ result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateIntLiteral(bool is_negative) {
+ int64_t value = is_negative ? -static_cast<int64_t>(builder_->ReadUInt())
+ : builder_->ReadUInt(); // read value.
+ result_ = dart::Integer::New(value, Heap::kOld);
+ result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateDoubleLiteral() {
+ result_ = Double::New(H.DartString(builder_->ReadStringReference()),
+ Heap::kOld); // read string reference.
+ result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateBoolLiteral(bool value) {
+ result_ = dart::Bool::Get(value).raw();
+}
+
+void StreamingConstantEvaluator::EvaluateNullLiteral() {
+ result_ = dart::Instance::null();
+}
+
+// This depends on being about to read the list of positionals on arguments.
+const Object& StreamingConstantEvaluator::RunFunction(
+ const Function& function,
+ intptr_t argument_count,
+ const Instance* receiver,
+ const TypeArguments* type_args) {
+ // We do not support generic methods yet.
+ ASSERT((receiver == NULL) || (type_args == NULL));
+ intptr_t extra_arguments =
+ (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0);
+
+ // Build up arguments.
+ const Array& arguments =
+ Array::ZoneHandle(Z, Array::New(extra_arguments + argument_count));
+ intptr_t pos = 0;
+ if (receiver != NULL) {
+ arguments.SetAt(pos++, *receiver);
+ }
+ if (type_args != NULL) {
+ arguments.SetAt(pos++, *type_args);
+ }
+
+ // List of positional.
+ intptr_t list_length = builder_->ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ EvaluateExpression(builder_->ReaderOffset(),
+ false); // read ith expression.
+ arguments.SetAt(pos++, result_);
+ }
+
+ // List of named.
+ list_length = builder_->ReadListLength(); // read list length.
+ const Array& names = Array::ZoneHandle(Z, Array::New(list_length));
+ for (intptr_t i = 0; i < list_length; ++i) {
+ dart::String& name =
+ H.DartSymbol(builder_->ReadStringReference()); // read ith name index.
+ names.SetAt(i, name);
+ EvaluateExpression(builder_->ReaderOffset(),
+ false); // read ith expression.
+ arguments.SetAt(pos++, result_);
+ }
+
+ return RunFunction(function, arguments, names);
+}
+
+const Object& StreamingConstantEvaluator::RunFunction(const Function& function,
+ const Array& arguments,
+ const Array& names) {
+ const Array& args_descriptor =
+ Array::Handle(Z, ArgumentsDescriptor::New(arguments.Length(), names));
+ const Object& result = Object::Handle(
+ Z, DartEntry::InvokeFunction(function, arguments, args_descriptor));
+ if (result.IsError()) {
+ H.ReportError(Error::Cast(result), "error evaluating constant constructor");
+ }
+ return result;
+}
+
+RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall(
+ const dart::Class& type_class,
+ const TypeArguments& type_arguments,
+ const Function& constructor,
+ const Object& argument) {
+ // Factories have one extra argument: the type arguments.
+ // Constructors have 1 extra arguments: receiver.
+ const int kNumArgs = 1;
+ const int kNumExtraArgs = 1;
+ const int num_arguments = kNumArgs + kNumExtraArgs;
+ const Array& arg_values =
+ Array::Handle(Z, Array::New(num_arguments, Heap::kOld));
+ Instance& instance = Instance::Handle(Z);
+ if (!constructor.IsFactory()) {
+ instance = Instance::New(type_class, Heap::kOld);
+ if (!type_arguments.IsNull()) {
+ ASSERT(type_arguments.IsInstantiated());
+ instance.SetTypeArguments(
+ TypeArguments::Handle(Z, type_arguments.Canonicalize()));
+ }
+ arg_values.SetAt(0, instance);
+ } else {
+ // Prepend type_arguments to list of arguments to factory.
+ ASSERT(type_arguments.IsZoneHandle());
+ arg_values.SetAt(0, type_arguments);
+ }
+ arg_values.SetAt((0 + kNumExtraArgs), argument);
+ const Array& args_descriptor = Array::Handle(
+ Z, ArgumentsDescriptor::New(num_arguments, Object::empty_array()));
+ const Object& result = Object::Handle(
+ Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor));
+ ASSERT(!result.IsError());
+ if (constructor.IsFactory()) {
+ // The factory method returns the allocated object.
+ instance ^= result.raw();
+ }
+ return H.Canonicalize(instance);
+}
+
+const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments(
+ const Function& target,
+ dart::Class* target_klass) {
+ intptr_t types_count = builder_->ReadListLength(); // read types count.
+
+ const TypeArguments* type_arguments = NULL;
+ if (types_count > 0) {
+ type_arguments = &T.BuildInstantiatedTypeArguments(
+ *target_klass, types_count); // read types.
+
+ if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) {
+ H.ReportError("Type must be constant in const constructor.");
+ }
+ } else if (target.IsFactory() && type_arguments == NULL) {
+ // All factories take a type arguments vector as first argument (independent
+ // of whether the class is generic or not).
+ type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null());
+ }
+ return type_arguments;
+}
+
+bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() {
+ EvaluateExpression(builder_->ReaderOffset(), false);
+ AssertBoolInCheckedMode();
+ return result_.raw() == Bool::True().raw();
+}
+
+bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset,
+ Instance* value) {
+ if (builder_ == NULL) return false;
+
+ const Function& function = builder_->parsed_function()->function();
+ if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
+ // Don't cache constants in initializer expressions. They get
+ // evaluated only once.
+ return false;
+ }
+
+ bool is_present = false;
+ ASSERT(!script_.InVMHeap());
+ if (script_.compile_time_constants() == Array::null()) {
+ return false;
+ }
+ KernelConstantsMap constants(script_.compile_time_constants());
+ *value ^= constants.GetOrNull(kernel_offset, &is_present);
+ // Mutator compiler thread may add constants while background compiler
+ // is running, and thus change the value of 'compile_time_constants';
+ // do not assert that 'compile_time_constants' has not changed.
+ constants.Release();
+ if (FLAG_compiler_stats && is_present) {
+ ++H.thread()->compiler_stats()->num_const_cache_hits;
+ }
+ return is_present;
+}
+
+
+void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset,
+ const Instance& value) {
+ ASSERT(Thread::Current()->IsMutatorThread());
+
+ if (builder_ == NULL) return;
+
+ const Function& function = builder_->parsed_function()->function();
+ if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
+ // Don't cache constants in initializer expressions. They get
+ // evaluated only once.
+ return;
+ }
+ const intptr_t kInitialConstMapSize = 16;
+ ASSERT(!script_.InVMHeap());
+ if (script_.compile_time_constants() == Array::null()) {
+ const Array& array = Array::Handle(
+ HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew));
+ script_.set_compile_time_constants(array);
+ }
+ KernelConstantsMap constants(script_.compile_time_constants());
+ constants.InsertNewOrGetValue(kernel_offset, value);
+ script_.set_compile_time_constants(constants.Release());
+}
+
+
+Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) {
+ SetOffset(kernel_offset);
+ return BuildExpression(); // read expression.
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) {
+ SetOffset(kernel_offset);
+ return BuildStatement(); // read statement.
+}
+
+Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
+ uint8_t payload = 0;
+ Tag tag = ReadTag(&payload); // read tag.
+ switch (tag) {
+ case kInvalidExpression:
+ return BuildInvalidExpression(position);
+ case kVariableGet:
+ return BuildVariableGet(position);
+ case kSpecializedVariableGet:
+ return BuildVariableGet(payload, position);
+ case kVariableSet:
+ return BuildVariableSet(position);
+ case kSpecializedVariableSet:
+ return BuildVariableSet(payload, position);
+ case kPropertyGet:
+ return BuildPropertyGet(position);
+ case kPropertySet:
+ return BuildPropertySet(position);
+ case kDirectPropertyGet:
+ return BuildDirectPropertyGet(position);
+ case kDirectPropertySet:
+ return BuildDirectPropertySet(position);
+ case kStaticGet:
+ return BuildStaticGet(position);
+ case kStaticSet:
+ return BuildStaticSet(position);
+ case kMethodInvocation:
+ return BuildMethodInvocation(position);
+ case kDirectMethodInvocation:
+ return BuildDirectMethodInvocation(position);
+ case kStaticInvocation:
+ return BuildStaticInvocation(false, position);
+ case kConstStaticInvocation:
+ return BuildStaticInvocation(true, position);
+ case kConstructorInvocation:
+ return BuildConstructorInvocation(false, position);
+ case kConstConstructorInvocation:
+ return BuildConstructorInvocation(true, position);
+ case kNot:
+ return BuildNot(position);
+ case kLogicalExpression:
+ return BuildLogicalExpression(position);
+ case kConditionalExpression:
+ return BuildConditionalExpression(position);
+ case kStringConcatenation:
+ return BuildStringConcatenation(position);
+ case kIsExpression:
+ return BuildIsExpression(position);
+ case kAsExpression:
+ return BuildAsExpression(position);
+ case kSymbolLiteral:
+ return BuildSymbolLiteral(position);
+ case kTypeLiteral:
+ return BuildTypeLiteral(position);
+ case kThisExpression:
+ return BuildThisExpression(position);
+ case kRethrow:
+ return BuildRethrow(position);
+ case kThrow:
+ return BuildThrow(position);
+ case kListLiteral:
+ return BuildListLiteral(false, position);
+ case kConstListLiteral:
+ return BuildListLiteral(true, position);
+ case kMapLiteral:
+ return BuildMapLiteral(false, position);
+ case kConstMapLiteral:
+ return BuildMapLiteral(true, position);
+ case kFunctionExpression:
+ // TODO(jensj)
+ UNIMPLEMENTED();
+ return Fragment();
+ case kLet:
+ return BuildLet(position);
+ case kBigIntLiteral:
+ return BuildBigIntLiteral(position);
+ case kStringLiteral:
+ return BuildStringLiteral(position);
+ case kSpecialIntLiteral:
+ return BuildIntLiteral(payload, position);
+ case kNegativeIntLiteral:
+ return BuildIntLiteral(true, position);
+ case kPositiveIntLiteral:
+ return BuildIntLiteral(false, position);
+ case kDoubleLiteral:
+ return BuildDoubleLiteral(position);
+ case kTrueLiteral:
+ return BuildBoolLiteral(true, position);
+ case kFalseLiteral:
+ return BuildBoolLiteral(false, position);
+ case kNullLiteral:
+ return BuildNullLiteral(position);
+ default:
+ UNREACHABLE();
+ }
+
+ return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStatement() {
+ Tag tag = ReadTag(); // read tag.
+ switch (tag) {
+ case kInvalidStatement:
+ return BuildInvalidStatement();
+ case kExpressionStatement:
+ return BuildExpressionStatement();
+ case kBlock:
+ return BuildBlock();
+ case kEmptyStatement:
+ return BuildEmptyStatement();
+ case kAssertStatement:
+ return BuildAssertStatement();
+ case kLabeledStatement:
+ return BuildLabeledStatement();
+ case kBreakStatement:
+ return BuildBreakStatement();
+ case kWhileStatement:
+ return BuildWhileStatement();
+ case kDoStatement:
+ return BuildDoStatement();
+ case kForStatement:
+ return BuildForStatement();
+ case kForInStatement:
+ return BuildForInStatement(false);
+ case kAsyncForInStatement:
+ return BuildForInStatement(true);
+ case kSwitchStatement:
+ return BuildSwitchStatement();
+ case kContinueSwitchStatement:
+ return BuildContinueSwitchStatement();
+ case kIfStatement:
+ return BuildIfStatement();
+ case kReturnStatement:
+ return BuildReturnStatement();
+ case kTryCatch:
+ return BuildTryCatch();
+ case kTryFinally:
+ return BuildTryFinally();
+ case kYieldStatement:
+ return BuildYieldStatement();
+ case kVariableDeclaration:
+ return BuildVariableDeclaration(true);
+ case kFunctionDeclaration:
+ // TODO(jensj)
+ UNIMPLEMENTED();
+ return Fragment();
+ default:
+ UNREACHABLE();
+ }
+ return Fragment();
+}
+
+intptr_t StreamingFlowGraphBuilder::ReaderOffset() {
+ return reader_->offset();
+}
+
+void StreamingFlowGraphBuilder::SetOffset(intptr_t offset) {
+ reader_->set_offset(offset);
+}
+
+void StreamingFlowGraphBuilder::SkipBytes(intptr_t bytes) {
+ reader_->set_offset(ReaderOffset() + bytes);
+}
+
+bool StreamingFlowGraphBuilder::ReadBool() {
+ return reader_->ReadBool();
+}
+
+uint8_t StreamingFlowGraphBuilder::ReadByte() {
+ return reader_->ReadByte();
+}
+
+uint32_t StreamingFlowGraphBuilder::ReadUInt() {
+ return reader_->ReadUInt();
+}
+
+uint32_t StreamingFlowGraphBuilder::PeekUInt() {
+ intptr_t offset = ReaderOffset();
+ uint32_t result = reader_->ReadUInt();
+ SetOffset(offset);
+ return result;
+}
+
+intptr_t StreamingFlowGraphBuilder::ReadListLength() {
+ return reader_->ReadListLength();
+}
+
+StringIndex StreamingFlowGraphBuilder::ReadStringReference() {
+ return StringIndex(ReadUInt());
+}
+
+NameIndex StreamingFlowGraphBuilder::ReadCanonicalNameReference() {
+ return reader_->ReadCanonicalNameReference();
+}
+
+StringIndex StreamingFlowGraphBuilder::ReadNameAsStringIndex() {
+ StringIndex name_index = ReadStringReference(); // read name index.
+ if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+ ReadUInt(); // read library index.
+ }
+ return name_index;
+}
+
+const dart::String& StreamingFlowGraphBuilder::ReadNameAsMethodName() {
+ StringIndex name_index = ReadStringReference(); // read name index.
+ if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+ NameIndex library_reference =
+ ReadCanonicalNameReference(); // read library index.
+ return H.DartMethodName(library_reference, name_index);
+ } else {
+ return H.DartMethodName(NameIndex(NULL), name_index);
+ }
+}
+
+const dart::String& StreamingFlowGraphBuilder::ReadNameAsSetterName() {
+ StringIndex name_index = ReadStringReference(); // read name index.
+ if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+ NameIndex library_reference =
+ ReadCanonicalNameReference(); // read library index.
+ return H.DartSetterName(library_reference, name_index);
+ } else {
+ return H.DartSetterName(NameIndex(NULL), name_index);
+ }
+}
+
+const dart::String& StreamingFlowGraphBuilder::ReadNameAsGetterName() {
+ StringIndex name_index = ReadStringReference(); // read name index.
+ if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+ NameIndex library_reference =
+ ReadCanonicalNameReference(); // read library index.
+ return H.DartGetterName(library_reference, name_index);
+ } else {
+ return H.DartGetterName(NameIndex(NULL), name_index);
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipStringReference() {
+ ReadUInt();
+}
+
+void StreamingFlowGraphBuilder::SkipCanonicalNameReference() {
+ ReadUInt();
+}
+
+void StreamingFlowGraphBuilder::SkipDartType() {
+ Tag tag = ReadTag();
+ switch (tag) {
+ case kInvalidType:
+ case kDynamicType:
+ case kVoidType:
+ case kBottomType:
+ // those contain nothing.
+ return;
+ case kInterfaceType:
+ SkipInterfaceType(false);
+ return;
+ case kSimpleInterfaceType:
+ SkipInterfaceType(true);
+ return;
+ case kFunctionType:
+ SkipFunctionType(false);
+ return;
+ case kSimpleFunctionType:
+ SkipFunctionType(true);
+ return;
+ case kTypeParameterType:
+ ReadUInt(); // read index for parameter.
+ ReadUInt(); // read binary offset.
+ SkipOptionalDartType(); // read bound bound.
+ return;
+ default:
+ UNREACHABLE();
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipOptionalDartType() {
+ Tag tag = ReadTag(); // read tag.
+ if (tag == kNothing) {
+ return;
+ }
+ ASSERT(tag == kSomething);
+
+ SkipDartType(); // read type.
+}
+
+void StreamingFlowGraphBuilder::SkipInterfaceType(bool simple) {
+ ReadUInt(); // read klass_name.
+ if (!simple) {
+ intptr_t length = ReadListLength(); // read number of types.
+ for (intptr_t i = 0; i < length; ++i) {
+ SkipDartType(); // skip the ith type.
+ }
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipFunctionType(bool simple) {
+ if (!simple) {
+ intptr_t list_length =
+ ReadListLength(); // read type_parameters list length.
+ for (int i = 0; i < list_length; ++i) {
+ SkipStringReference(); // read string index (name).
+ SkipDartType(); // read dart type.
+ }
+ ReadUInt(); // read required parameter count.
+ ReadUInt(); // read total parameter count.
+ }
+
+ const intptr_t positional_count =
+ ReadListLength(); // read positional_parameters list length.
+ for (intptr_t i = 0; i < positional_count; ++i) {
+ SkipDartType(); // read ith positional parameter.
+ }
+
+ if (!simple) {
+ const intptr_t named_count =
+ ReadListLength(); // read named_parameters list length.
+ for (intptr_t i = 0; i < named_count; ++i) {
+ // read string reference (i.e. named_parameters[i].name).
+ SkipStringReference();
+ SkipDartType(); // read named_parameters[i].type.
+ }
+ }
+
+ SkipDartType(); // read return type.
+}
+
+void StreamingFlowGraphBuilder::SkipExpression() {
+ uint8_t payload = 0;
+ Tag tag = ReadTag(&payload);
+ switch (tag) {
+ case kInvalidExpression:
+ return;
+ case kVariableGet:
+ ReadPosition(); // read position.
+ ReadUInt(); // read kernel position.
+ ReadUInt(); // read relative variable index.
+ SkipOptionalDartType(); // read promoted type.
+ return;
+ case kSpecializedVariableGet:
+ ReadPosition(); // read position.
+ ReadUInt(); // read kernel position.
+ return;
+ case kVariableSet:
+ ReadPosition(); // read position.
+ ReadUInt(); // read kernel position.
+ ReadUInt(); // read relative variable index.
+ SkipExpression(); // read expression.
+ return;
+ case kSpecializedVariableSet:
+ ReadPosition(); // read position.
+ ReadUInt(); // read kernel position.
+ SkipExpression(); // read expression.
+ return;
+ case kPropertyGet:
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ // Read unused "interface_target_reference".
+ SkipCanonicalNameReference();
+ return;
+ case kPropertySet:
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipExpression(); // read value.
+ // read unused "interface_target_reference".
+ SkipCanonicalNameReference();
+ return;
+ case kDirectPropertyGet:
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipCanonicalNameReference(); // read target_reference.
+ return;
+ case kDirectPropertySet:
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipCanonicalNameReference(); // read target_reference.
+ SkipExpression(); // read value·
+ return;
+ case kStaticGet:
+ ReadPosition(); // read position.
+ SkipCanonicalNameReference(); // read target_reference.
+ return;
+ case kStaticSet:
+ ReadPosition(); // read position.
+ SkipCanonicalNameReference(); // read target_reference.
+ SkipExpression(); // read expression.
+ return;
+ case kMethodInvocation:
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipArguments(); // read arguments.
+ // read unused "interface_target_reference".
+ SkipCanonicalNameReference();
+ return;
+ case kDirectMethodInvocation:
+ SkipExpression(); // read receiver.
+ SkipCanonicalNameReference(); // read target_reference.
+ SkipArguments(); // read arguments.
+ return;
+ case kStaticInvocation:
+ case kConstStaticInvocation:
+ ReadPosition(); // read position.
+ SkipCanonicalNameReference(); // read procedure_reference.
+ SkipArguments(); // read arguments.
+ return;
+ case kConstructorInvocation:
+ case kConstConstructorInvocation:
+ ReadPosition(); // read position.
+ SkipCanonicalNameReference(); // read target_reference.
+ SkipArguments(); // read arguments.
+ return;
+ case kNot:
+ SkipExpression(); // read expression.
+ return;
+ case kLogicalExpression:
+ SkipExpression(); // read left.
+ SkipBytes(1); // read operator.
+ SkipExpression(); // read right.
+ return;
+ case kConditionalExpression:
+ SkipExpression(); // read condition.
+ SkipExpression(); // read then.
+ SkipExpression(); // read otherwise.
+ SkipOptionalDartType(); // read unused static type.
+ return;
+ case kStringConcatenation: {
+ ReadPosition(); // read position.
+ intptr_t list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipExpression(); // read ith expression.
+ }
+ return;
+ }
+ case kIsExpression:
+ ReadPosition(); // read position.
+ SkipExpression(); // read operand.
+ SkipDartType(); // read type.
+ return;
+ case kAsExpression:
+ ReadPosition(); // read position.
+ SkipExpression(); // read operand.
+ SkipDartType(); // read type.
+ return;
+ case kSymbolLiteral:
+ SkipStringReference(); // read index into string table.
+ return;
+ case kTypeLiteral:
+ SkipDartType(); // read type.
+ return;
+ case kThisExpression:
+ return;
+ case kRethrow:
+ ReadPosition(); // read position.
+ return;
+ case kThrow:
+ ReadPosition(); // read position.
+ SkipExpression(); // read expression.
+ return;
+ case kListLiteral:
+ case kConstListLiteral: {
+ ReadPosition(); // read position.
+ SkipDartType(); // read type.
+ intptr_t list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipExpression(); // read ith expression.
+ }
+ return;
+ }
+ case kMapLiteral:
+ case kConstMapLiteral: {
+ ReadPosition(); // read position.
+ SkipDartType(); // read key type.
+ SkipDartType(); // read value type.
+ intptr_t list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipExpression(); // read ith key.
+ SkipExpression(); // read ith value.
+ }
+ return;
+ }
+ case kFunctionExpression:
+ // TODO(jensj)
+ UNIMPLEMENTED();
+ return;
+ case kLet:
+ SkipVariableDeclaration(); // read variable declaration.
+ SkipExpression(); // read expression.
+ return;
+ case kBigIntLiteral:
+ SkipStringReference(); // read string reference.
+ return;
+ case kStringLiteral:
+ SkipStringReference(); // read string reference.
+ return;
+ case kSpecialIntLiteral:
+ return;
+ case kNegativeIntLiteral:
+ ReadUInt(); // read value.
+ return;
+ case kPositiveIntLiteral:
+ ReadUInt(); // read value.
+ return;
+ case kDoubleLiteral:
+ SkipStringReference(); // read index into string table.
+ return;
+ case kTrueLiteral:
+ return;
+ case kFalseLiteral:
+ return;
+ case kNullLiteral:
+ return;
+ default:
+ UNREACHABLE();
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipStatement() {
+ Tag tag = ReadTag(); // read tag.
+ switch (tag) {
+ case kInvalidStatement:
+ return;
+ case kExpressionStatement:
+ SkipExpression(); // read expression.
+ return;
+ case kBlock: {
+ intptr_t list_length = ReadListLength(); // read number of statements.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipStatement(); // read ith statement.
+ }
+ return;
+ }
+ case kEmptyStatement:
+ return;
+ case kAssertStatement: {
+ SkipExpression(); // Read condition.
+ Tag tag = ReadTag(); // read (first part of) message.
+ if (tag == kSomething) {
+ SkipExpression(); // read (rest of) message.
+ }
+ return;
+ }
+ case kLabeledStatement:
+ SkipStatement(); // read body.
+ return;
+ case kBreakStatement:
+ ReadPosition(); // read position.
+ ReadUInt(); // read target_index.
+ return;
+ case kWhileStatement:
+ SkipExpression(); // read condition.
+ SkipStatement(); // read body.
+ return;
+ case kDoStatement:
+ SkipStatement(); // read body.
+ SkipExpression(); // read condition.
+ return;
+ case kForStatement: {
+ intptr_t list_length = ReadListLength(); // read number of variables.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipVariableDeclaration(); // read ith variable.
+ }
+ Tag tag = ReadTag(); // Read first part of condition.
+ if (tag == kSomething) {
+ SkipExpression(); // read rest of condition.
+ }
+ list_length = ReadListLength(); // read number of updates.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipExpression(); // read ith update.
+ }
+ SkipStatement(); // read body.
+ return;
+ }
+ case kForInStatement:
+ case kAsyncForInStatement:
+ ReadPosition(); // read position.
+ SkipVariableDeclaration(); // read variable.
+ SkipExpression(); // read iterable.
+ SkipStatement(); // read body.
+ return;
+ case kSwitchStatement: {
+ SkipExpression(); // read condition.
+ int num_cases = ReadListLength(); // read number of cases.
+ for (intptr_t i = 0; i < num_cases; ++i) {
+ int num_expressions = ReadListLength(); // read number of expressions.
+ for (intptr_t j = 0; j < num_expressions; ++j) {
+ ReadPosition(); // read jth position.
+ SkipExpression(); // read jth expression.
+ }
+ ReadBool(); // read is_default.
+ SkipStatement(); // read body.
+ }
+ return;
+ }
+ case kContinueSwitchStatement:
+ ReadUInt(); // read target_index.
+ return;
+ case kIfStatement:
+ SkipExpression(); // read condition.
+ SkipStatement(); // read then.
+ SkipStatement(); // read otherwise.
+ return;
+ case kReturnStatement: {
+ ReadPosition(); // read position
+ Tag tag = ReadTag(); // read (first part of) expression.
+ if (tag == kSomething) {
+ SkipExpression(); // read (rest of) expression.
+ }
+ return;
+ }
+ case kTryCatch: {
+ SkipStatement(); // read body.
+ ReadBool(); // read any_catch_needs_stack_trace.
+ intptr_t num_matches = ReadListLength(); // read number of catches.
+ for (intptr_t i = 0; i < num_matches; ++i) {
+ SkipDartType(); // read guard.
+ tag = ReadTag(); // read first part of exception.
+ if (tag == kSomething) {
+ SkipVariableDeclaration(); // read exception.
+ }
+ tag = ReadTag(); // read first part of stack trace.
+ if (tag == kSomething) {
+ SkipVariableDeclaration(); // read stack trace.
+ }
+ SkipStatement(); // read body.
+ }
+ return;
+ }
+ case kTryFinally:
+ SkipStatement(); // read body.
+ SkipStatement(); // read finalizer.
+ return;
+ case kYieldStatement:
+ ReadPosition(); // read position.
+ ReadByte(); // read flags.
+ SkipExpression(); // read expression.
+ return;
+ case kVariableDeclaration:
+ SkipVariableDeclaration();
+ return;
+ case kFunctionDeclaration:
+ // TODO(jensj)
+ UNIMPLEMENTED();
+ return;
+ default:
+ UNREACHABLE();
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipName() {
+ StringIndex name_index = ReadStringReference(); // read name index.
+ if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+ SkipCanonicalNameReference(); // read library index.
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipArguments() {
+ ReadUInt(); // read argument count.
+
+ // List of types.
+ intptr_t list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipDartType(); // read ith type.
+ }
+
+ // List of positional.
+ list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipExpression(); // read ith expression.
+ }
+
+ // List of named.
+ list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipStringReference(); // read ith name index.
+ SkipExpression(); // read ith expression.
+ }
+}
+
+void StreamingFlowGraphBuilder::SkipVariableDeclaration() {
+ ReadPosition(); // read position.
+ ReadPosition(); // read equals position.
+ ReadFlags(); // read flags.
+ SkipStringReference(); // read name index.
+ SkipDartType(); // read type.
+ Tag tag = ReadTag(); // read (first part of) initializer.
+ if (tag == kSomething) {
+ SkipExpression(); // read (actual) initializer.
+ }
+}
+
+TokenPosition StreamingFlowGraphBuilder::ReadPosition(bool record) {
+ return reader_->ReadPosition(record);
+}
+
+Tag StreamingFlowGraphBuilder::ReadTag(uint8_t* payload) {
+ return reader_->ReadTag(payload);
+}
+
+Tag StreamingFlowGraphBuilder::PeekTag(uint8_t* payload) {
+ return reader_->PeekTag(payload);
+}
+
+word StreamingFlowGraphBuilder::ReadFlags() {
+ return reader_->ReadFlags();
+}
+
+void StreamingFlowGraphBuilder::loop_depth_inc() {
+ ++flow_graph_builder_->loop_depth_;
+}
+
+void StreamingFlowGraphBuilder::loop_depth_dec() {
+ --flow_graph_builder_->loop_depth_;
+}
+
+intptr_t StreamingFlowGraphBuilder::for_in_depth() {
+ return flow_graph_builder_->for_in_depth_;
+}
+
+void StreamingFlowGraphBuilder::for_in_depth_inc() {
+ ++flow_graph_builder_->for_in_depth_;
+}
+
+void StreamingFlowGraphBuilder::for_in_depth_dec() {
+ --flow_graph_builder_->for_in_depth_;
+}
+
+void StreamingFlowGraphBuilder::catch_depth_inc() {
+ ++flow_graph_builder_->catch_depth_;
+}
+
+void StreamingFlowGraphBuilder::catch_depth_dec() {
+ --flow_graph_builder_->catch_depth_;
+}
+
+void StreamingFlowGraphBuilder::try_depth_inc() {
+ ++flow_graph_builder_->try_depth_;
+}
+
+void StreamingFlowGraphBuilder::try_depth_dec() {
+ --flow_graph_builder_->try_depth_;
+}
+
+intptr_t StreamingFlowGraphBuilder::CurrentTryIndex() {
+ return flow_graph_builder_->CurrentTryIndex();
+}
+
+intptr_t StreamingFlowGraphBuilder::AllocateTryIndex() {
+ return flow_graph_builder_->AllocateTryIndex();
+}
+
+LocalVariable* StreamingFlowGraphBuilder::CurrentException() {
+ return flow_graph_builder_->CurrentException();
+}
+
+LocalVariable* StreamingFlowGraphBuilder::CurrentStackTrace() {
+ return flow_graph_builder_->CurrentStackTrace();
+}
+
+CatchBlock* StreamingFlowGraphBuilder::catch_block() {
+ return flow_graph_builder_->catch_block_;
+}
+
+ActiveClass* StreamingFlowGraphBuilder::active_class() {
+ return &flow_graph_builder_->active_class_;
+}
+
+ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
+ return flow_graph_builder_->scopes_;
+}
+
+ParsedFunction* StreamingFlowGraphBuilder::parsed_function() {
+ return flow_graph_builder_->parsed_function_;
+}
+
+TryFinallyBlock* StreamingFlowGraphBuilder::try_finally_block() {
+ return flow_graph_builder_->try_finally_block_;
+}
+
+SwitchBlock* StreamingFlowGraphBuilder::switch_block() {
+ return flow_graph_builder_->switch_block_;
+}
+
+BreakableBlock* StreamingFlowGraphBuilder::breakable_block() {
+ return flow_graph_builder_->breakable_block_;
+}
+
+GrowableArray<YieldContinuation>&
+StreamingFlowGraphBuilder::yield_continuations() {
+ return flow_graph_builder_->yield_continuations_;
+}
+
+Value* StreamingFlowGraphBuilder::stack() {
+ return flow_graph_builder_->stack_;
+}
+
+Value* StreamingFlowGraphBuilder::Pop() {
+ return flow_graph_builder_->Pop();
+}
+
+Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() {
+ // read parts of arguments, then go back to before doing so.
+ intptr_t offset = ReaderOffset();
+ ReadUInt(); // read number of arguments.
+
+ // List of types.
+ intptr_t list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipDartType(); // read ith type.
+ }
+
+ // List of positional.
+ list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ Tag tag = ReadTag(); // read first tag.
+ SetOffset(offset); // reset offset.
+ return tag;
+ }
+
+ UNREACHABLE();
+ return kNothing;
+}
+
+const TypeArguments& StreamingFlowGraphBuilder::PeekArgumentsInstantiatedType(
+ const dart::Class& klass) {
+ // read parts of arguments, then go back to before doing so.
+ intptr_t offset = ReaderOffset();
+ ReadUInt(); // read argument count.
+ intptr_t list_length = ReadListLength(); // read types list length.
+ const TypeArguments& type_arguments =
+ T.BuildInstantiatedTypeArguments(klass, list_length); // read types.
+ SetOffset(offset);
+ return type_arguments;
+}
+
+intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() {
+ return PeekUInt();
+}
+
+intptr_t StreamingFlowGraphBuilder::PeekArgumentsTypeCount() {
+ intptr_t offset = ReaderOffset();
+ ReadUInt(); // read arguments count.
+ intptr_t types_count = ReadListLength(); // read length of types list.
+ SetOffset(offset);
+ return types_count;
+}
+
+void StreamingFlowGraphBuilder::SkipArgumentsBeforeActualArguments() {
+ ReadUInt(); // read arguments count.
+ intptr_t types_count = ReadListLength();
+ for (intptr_t i = 0; i < types_count; ++i) {
+ SkipDartType(); // read ith type.
+ }
+}
+
+LocalVariable* StreamingFlowGraphBuilder::LookupVariable(
+ intptr_t kernel_offset) {
+ return flow_graph_builder_->LookupVariable(kernel_offset);
+}
+
+LocalVariable* StreamingFlowGraphBuilder::MakeTemporary() {
+ return flow_graph_builder_->MakeTemporary();
+}
+
+Token::Kind StreamingFlowGraphBuilder::MethodKind(const dart::String& name) {
+ return flow_graph_builder_->MethodKind(name);
+}
+
+dart::RawFunction* StreamingFlowGraphBuilder::LookupMethodByMember(
+ NameIndex target,
+ const dart::String& method_name) {
+ return flow_graph_builder_->LookupMethodByMember(target, method_name);
+}
+
+bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
+ TokenPosition position) {
+ return flow_graph_builder_->NeedsDebugStepCheck(function, position);
+}
+
+bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(Value* value,
+ TokenPosition position) {
+ return flow_graph_builder_->NeedsDebugStepCheck(value, position);
+}
+
+void StreamingFlowGraphBuilder::InlineBailout(const char* reason) {
+ flow_graph_builder_->InlineBailout(reason);
+}
+
+Fragment StreamingFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
+ return flow_graph_builder_->DebugStepCheck(position);
+}
+
+Fragment StreamingFlowGraphBuilder::LoadLocal(LocalVariable* variable) {
+ return flow_graph_builder_->LoadLocal(variable);
+}
+
+Fragment StreamingFlowGraphBuilder::Return(TokenPosition position) {
+ return flow_graph_builder_->Return(position);
+}
+
+Fragment StreamingFlowGraphBuilder::PushArgument() {
+ return flow_graph_builder_->PushArgument();
+}
+
+Fragment StreamingFlowGraphBuilder::EvaluateAssertion() {
+ return flow_graph_builder_->EvaluateAssertion();
+}
+
+Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
+ int catch_try_index) {
+ return flow_graph_builder_->RethrowException(position, catch_try_index);
+}
+
+Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError() {
+ return flow_graph_builder_->ThrowNoSuchMethodError();
+}
+
+Fragment StreamingFlowGraphBuilder::Constant(const Object& value) {
+ return flow_graph_builder_->Constant(value);
+}
+
+Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) {
+ return flow_graph_builder_->IntConstant(value);
+}
+
+Fragment StreamingFlowGraphBuilder::LoadStaticField() {
+ return flow_graph_builder_->LoadStaticField();
+}
+
+Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
+ const Function& target,
+ intptr_t argument_count) {
+ return flow_graph_builder_->StaticCall(position, target, argument_count);
+}
+
+Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
+ const Function& target,
+ intptr_t argument_count,
+ const Array& argument_names) {
+ return flow_graph_builder_->StaticCall(position, target, argument_count,
+ argument_names);
+}
+
+Fragment StreamingFlowGraphBuilder::InstanceCall(TokenPosition position,
+ const dart::String& name,
+ Token::Kind kind,
+ intptr_t argument_count,
+ intptr_t num_args_checked) {
+ return flow_graph_builder_->InstanceCall(position, name, kind, argument_count,
+ num_args_checked);
+}
+
+Fragment StreamingFlowGraphBuilder::ThrowException(TokenPosition position) {
+ return flow_graph_builder_->ThrowException(position);
+}
+
+Fragment StreamingFlowGraphBuilder::BooleanNegate() {
+ return flow_graph_builder_->BooleanNegate();
+}
+
+Fragment StreamingFlowGraphBuilder::TranslateInstantiatedTypeArguments(
+ const TypeArguments& type_arguments) {
+ return flow_graph_builder_->TranslateInstantiatedTypeArguments(
+ type_arguments);
+}
+
+Fragment StreamingFlowGraphBuilder::StrictCompare(Token::Kind kind,
+ bool number_check) {
+ return flow_graph_builder_->StrictCompare(kind, number_check);
+}
+
+Fragment StreamingFlowGraphBuilder::AllocateObject(const dart::Class& klass,
+ intptr_t argument_count) {
+ return flow_graph_builder_->AllocateObject(klass, argument_count);
+}
+
+Fragment StreamingFlowGraphBuilder::InstanceCall(TokenPosition position,
+ const dart::String& name,
+ Token::Kind kind,
+ intptr_t argument_count,
+ const Array& argument_names,
+ intptr_t num_args_checked) {
+ return flow_graph_builder_->InstanceCall(position, name, kind, argument_count,
+ argument_names, num_args_checked);
+}
+
+Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position,
+ LocalVariable* variable) {
+ return flow_graph_builder_->StoreLocal(position, variable);
+}
+
+Fragment StreamingFlowGraphBuilder::StoreStaticField(TokenPosition position,
+ const dart::Field& field) {
+ return flow_graph_builder_->StoreStaticField(position, field);
+}
+
+Fragment StreamingFlowGraphBuilder::StringInterpolate(TokenPosition position) {
+ return flow_graph_builder_->StringInterpolate(position);
+}
+
+Fragment StreamingFlowGraphBuilder::StringInterpolateSingle(
+ TokenPosition position) {
+ return flow_graph_builder_->StringInterpolateSingle(position);
+}
+
+Fragment StreamingFlowGraphBuilder::ThrowTypeError() {
+ return flow_graph_builder_->ThrowTypeError();
+}
+
+Fragment StreamingFlowGraphBuilder::LoadInstantiatorTypeArguments() {
+ return flow_graph_builder_->LoadInstantiatorTypeArguments();
+}
+
+Fragment StreamingFlowGraphBuilder::LoadFunctionTypeArguments() {
+ return flow_graph_builder_->LoadFunctionTypeArguments();
+}
+
+Fragment StreamingFlowGraphBuilder::InstantiateType(const AbstractType& type) {
+ return flow_graph_builder_->InstantiateType(type);
+}
+
+Fragment StreamingFlowGraphBuilder::CreateArray() {
+ return flow_graph_builder_->CreateArray();
+}
+
+Fragment StreamingFlowGraphBuilder::StoreIndexed(intptr_t class_id) {
+ return flow_graph_builder_->StoreIndexed(class_id);
+}
+
+Fragment StreamingFlowGraphBuilder::CheckStackOverflow() {
+ return flow_graph_builder_->CheckStackOverflow();
+}
+
+Fragment StreamingFlowGraphBuilder::CloneContext() {
+ return flow_graph_builder_->CloneContext();
+}
+
+Fragment StreamingFlowGraphBuilder::TranslateFinallyFinalizers(
+ TryFinallyBlock* outer_finally,
+ intptr_t target_context_depth) {
+ // TranslateFinallyFinalizers can move the readers offset.
+ // Save the current position and restore it afterwards.
+ intptr_t offset = ReaderOffset();
+ Fragment result = flow_graph_builder_->TranslateFinallyFinalizers(
+ outer_finally, target_context_depth);
+ SetOffset(offset);
+ return result;
+}
+
+Fragment StreamingFlowGraphBuilder::BranchIfTrue(
+ TargetEntryInstr** then_entry,
+ TargetEntryInstr** otherwise_entry,
+ bool negate) {
+ return flow_graph_builder_->BranchIfTrue(then_entry, otherwise_entry, negate);
+}
+
+Fragment StreamingFlowGraphBuilder::BranchIfEqual(
+ TargetEntryInstr** then_entry,
+ TargetEntryInstr** otherwise_entry,
+ bool negate) {
+ return flow_graph_builder_->BranchIfEqual(then_entry, otherwise_entry,
+ negate);
+}
+
+Fragment StreamingFlowGraphBuilder::BranchIfNull(
+ TargetEntryInstr** then_entry,
+ TargetEntryInstr** otherwise_entry,
+ bool negate) {
+ return flow_graph_builder_->BranchIfNull(then_entry, otherwise_entry, negate);
+}
+
+Fragment StreamingFlowGraphBuilder::CatchBlockEntry(const Array& handler_types,
+ intptr_t handler_index,
+ bool needs_stacktrace) {
+ return flow_graph_builder_->CatchBlockEntry(handler_types, handler_index,
+ needs_stacktrace);
+}
+
+Fragment StreamingFlowGraphBuilder::TryCatch(int try_handler_index) {
+ return flow_graph_builder_->TryCatch(try_handler_index);
+}
+
+Fragment StreamingFlowGraphBuilder::Drop() {
+ return flow_graph_builder_->Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::NullConstant() {
+ return flow_graph_builder_->NullConstant();
+}
+
+JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry() {
+ return flow_graph_builder_->BuildJoinEntry();
+}
+
+JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) {
+ return flow_graph_builder_->BuildJoinEntry(try_index);
+}
+
+Fragment StreamingFlowGraphBuilder::Goto(JoinEntryInstr* destination) {
+ return flow_graph_builder_->Goto(destination);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildImplicitClosureCreation(
+ const Function& target) {
+ return flow_graph_builder_->BuildImplicitClosureCreation(target);
+}
+
+Fragment StreamingFlowGraphBuilder::CheckBooleanInCheckedMode() {
+ return flow_graph_builder_->CheckBooleanInCheckedMode();
+}
+
+Fragment StreamingFlowGraphBuilder::CheckAssignableInCheckedMode(
+ const dart::AbstractType& dst_type,
+ const dart::String& dst_name) {
+ return flow_graph_builder_->CheckAssignableInCheckedMode(dst_type, dst_name);
+}
+
+Fragment StreamingFlowGraphBuilder::CheckVariableTypeInCheckedMode(
+ intptr_t variable_kernel_position) {
+ if (I->type_checks()) {
+ LocalVariable* variable = LookupVariable(variable_kernel_position);
+ return flow_graph_builder_->CheckVariableTypeInCheckedMode(
+ variable->type(), variable->name());
+ }
+ return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::CheckVariableTypeInCheckedMode(
+ const AbstractType& dst_type,
+ const dart::String& name_symbol) {
+ return flow_graph_builder_->CheckVariableTypeInCheckedMode(dst_type,
+ name_symbol);
+}
+
+Fragment StreamingFlowGraphBuilder::EnterScope(intptr_t kernel_offset,
+ bool* new_context) {
+ return flow_graph_builder_->EnterScope(kernel_offset, new_context);
+}
+
+Fragment StreamingFlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
+ return flow_graph_builder_->ExitScope(kernel_offset);
+}
+
+Fragment StreamingFlowGraphBuilder::TranslateCondition(bool* negate) {
+ *negate = PeekTag() == kNot;
+ if (*negate) {
+ SkipBytes(1); // Skip Not tag, thus go directly to the inner expression.
+ }
+ Fragment instructions = BuildExpression(); // read expression.
+ instructions += CheckBooleanInCheckedMode();
+ return instructions;
+}
+
+const TypeArguments& StreamingFlowGraphBuilder::BuildTypeArguments() {
+ ReadUInt(); // read arguments count.
+ intptr_t types_count = ReadListLength(); // read type count.
+ return T.BuildTypeArguments(types_count); // read types.
+}
+
+Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names,
+ intptr_t* argument_count,
+ bool skip_push_arguments,
+ bool do_drop) {
+ intptr_t dummy;
+ if (argument_count == NULL) argument_count = &dummy;
+ *argument_count = ReadUInt(); // read arguments count.
+
+ // List of types.
+ intptr_t list_length = ReadListLength(); // read type count.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ SkipDartType(); // read ith type.
+ }
+
+ return BuildArgumentsFromActualArguments(argument_names, skip_push_arguments,
+ do_drop);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments(
+ Array* argument_names,
+ bool skip_push_arguments,
+ bool do_drop) {
+ Fragment instructions;
+
+ // List of positional.
+ intptr_t list_length = ReadListLength(); // read list length.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ instructions += BuildExpression(); // read ith expression.
+ if (!skip_push_arguments) instructions += PushArgument();
+ if (do_drop) instructions += Drop();
+ }
+
+ // List of named.
+ list_length = ReadListLength(); // read list length.
+ if (argument_names != NULL && list_length > 0) {
+ *argument_names ^= Array::New(list_length, Heap::kOld);
+ }
+ for (intptr_t i = 0; i < list_length; ++i) {
+ dart::String& name =
+ H.DartSymbol(ReadStringReference()); // read ith name index.
+ instructions += BuildExpression(); // read ith expression.
+ if (!skip_push_arguments) instructions += PushArgument();
+ if (do_drop) instructions += Drop();
+ if (argument_names != NULL) {
+ argument_names->SetAt(i, name);
+ }
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildInvalidExpression(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ // The frontend will take care of emitting normal errors (like
+ // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special
+ // situations (e.g. an invalid annotation).
+ return ThrowNoSuchMethodError();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableGet(TokenPosition* position) {
+ (position != NULL) ? * position = ReadPosition()
+ : ReadPosition(); // read position.
+ intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
+ ReadUInt(); // read relative variable index.
+ SkipOptionalDartType(); // read promoted type.
+
+ return LoadLocal(LookupVariable(variable_kernel_position));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableGet(uint8_t payload,
+ TokenPosition* position) {
+ (position != NULL) ? * position = ReadPosition()
+ : ReadPosition(); // read position.
+ intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
+ return LoadLocal(LookupVariable(variable_kernel_position));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableSet(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
+ ReadUInt(); // read relative variable index.
+ Fragment instructions = BuildExpression(); // read expression.
+
+ if (NeedsDebugStepCheck(stack(), position)) {
+ instructions = DebugStepCheck(position) + instructions;
+ }
+ instructions += CheckVariableTypeInCheckedMode(variable_kernel_position);
+ instructions +=
+ StoreLocal(position, LookupVariable(variable_kernel_position));
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableSet(uint8_t payload,
+ TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
+ Fragment instructions = BuildExpression(); // read expression.
+
+ if (NeedsDebugStepCheck(stack(), position)) {
+ instructions = DebugStepCheck(position) + instructions;
+ }
+ instructions += CheckVariableTypeInCheckedMode(variable_kernel_position);
+ instructions +=
+ StoreLocal(position, LookupVariable(variable_kernel_position));
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions = BuildExpression(); // read receiver.
+ instructions += PushArgument();
+
+ const dart::String& getter_name = ReadNameAsGetterName(); // read name.
+ SkipCanonicalNameReference(); // Read unused "interface_target_reference".
+
+ return instructions + InstanceCall(position, getter_name, Token::kGET, 1);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) {
+ Fragment instructions(NullConstant());
+ LocalVariable* variable = MakeTemporary();
+
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ instructions += BuildExpression(); // read receiver.
+ instructions += PushArgument();
+
+ const dart::String& setter_name = ReadNameAsSetterName(); // read name.
+
+ instructions += BuildExpression(); // read value.
+ instructions += StoreLocal(TokenPosition::kNoSource, variable);
+ instructions += PushArgument();
+
+ SkipCanonicalNameReference(); // read unused "interface_target_reference".
+
+ instructions += InstanceCall(position, setter_name, Token::kSET, 2);
+ return instructions + Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions = BuildExpression(); // read receiver.
+ NameIndex kernel_name =
+ ReadCanonicalNameReference(); // read target_reference.
+
+ Function& target = Function::ZoneHandle(Z);
+ if (H.IsProcedure(kernel_name)) {
+ if (H.IsGetter(kernel_name)) {
+ target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name));
+ } else {
+ // Undo stack change for the BuildExpression.
+ Pop();
+
+ target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name));
+ target = target.ImplicitClosureFunction();
+ ASSERT(!target.IsNull());
+ return BuildImplicitClosureCreation(target);
+ }
+ } else {
+ ASSERT(H.IsField(kernel_name));
+ const dart::String& getter_name = H.DartGetterName(kernel_name);
+ target = LookupMethodByMember(kernel_name, getter_name);
+ ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction());
+ }
+
+ instructions += PushArgument();
+ return instructions + StaticCall(position, target, 1);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions(NullConstant());
+ LocalVariable* value = MakeTemporary();
+
+ instructions += BuildExpression(); // read receiver.
+ instructions += PushArgument();
+
+ NameIndex target_reference =
+ ReadCanonicalNameReference(); // read target_reference.
+ const dart::String& method_name = H.DartSetterName(target_reference);
+ const Function& target = Function::ZoneHandle(
+ Z, LookupMethodByMember(target_reference, method_name));
+ ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
+
+ instructions += BuildExpression(); // read value.
+ instructions += StoreLocal(TokenPosition::kNoSource, value);
+ instructions += PushArgument();
+
+ instructions += StaticCall(position, target, 2);
+
+ return instructions + Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ NameIndex target = ReadCanonicalNameReference(); // read target_reference.
+
+ if (H.IsField(target)) {
+ const dart::Field& field =
+ dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
+ if (field.is_const()) {
+ return Constant(constant_evaluator_.EvaluateExpression(offset));
+ } else {
+ const dart::Class& owner = dart::Class::Handle(Z, field.Owner());
+ const dart::String& getter_name = H.DartGetterName(target);
+ const Function& getter =
+ Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name));
+ if (getter.IsNull() || !field.has_initializer()) {
+ Fragment instructions = Constant(field);
+ return instructions + LoadStaticField();
+ } else {
+ return StaticCall(position, getter, 0);
+ }
+ }
+ } else {
+ const Function& function =
+ Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
+
+ if (H.IsGetter(target)) {
+ return StaticCall(position, function, 0);
+ } else if (H.IsMethod(target)) {
+ return Constant(constant_evaluator_.EvaluateExpression(offset));
+ } else {
+ UNIMPLEMENTED();
+ }
+ }
+
+ return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ NameIndex target = ReadCanonicalNameReference(); // read target_reference.
+
+ if (H.IsField(target)) {
+ const dart::Field& field =
+ dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
+ const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
+ Fragment instructions = BuildExpression(); // read expression.
+ if (NeedsDebugStepCheck(stack(), position)) {
+ instructions = DebugStepCheck(position) + instructions;
+ }
+ instructions += CheckAssignableInCheckedMode(
+ dst_type, dart::String::ZoneHandle(Z, field.name()));
+ LocalVariable* variable = MakeTemporary();
+ instructions += LoadLocal(variable);
+ return instructions + StoreStaticField(position, field);
+ } else {
+ ASSERT(H.IsProcedure(target));
+
+ // Evaluate the expression on the right hand side.
+ Fragment instructions = BuildExpression(); // read expression.
+ LocalVariable* variable = MakeTemporary();
+
+ // Prepare argument.
+ instructions += LoadLocal(variable);
+ instructions += PushArgument();
+
+ // Invoke the setter function.
+ const Function& function =
+ Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
+ instructions += StaticCall(position, function, 1);
+
+ // Drop the unused result & leave the stored value on the stack.
+ return instructions + Drop();
+ }
+}
+
+static bool IsNumberLiteral(Tag tag) {
+ return tag == kNegativeIntLiteral || tag == kPositiveIntLiteral ||
+ tag == kSpecialIntLiteral || tag == kDoubleLiteral;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Tag receiver_tag = PeekTag(); // peek tag for receiver.
+ if (IsNumberLiteral(receiver_tag)) {
+ intptr_t before_branch_offset = ReaderOffset();
+
+ SkipExpression(); // read receiver (it's just a number literal).
+
+ const dart::String& name = ReadNameAsMethodName(); // read name.
+ const Token::Kind token_kind = MethodKind(name);
+ intptr_t argument_count = PeekArgumentsCount() + 1;
+
+ if ((argument_count == 1) && (token_kind == Token::kNEGATE)) {
+ const Object& result = constant_evaluator_.EvaluateExpressionSafe(offset);
+ if (!result.IsError()) {
+ SkipArguments(); // read arguments,
+ // read unused "interface_target_reference".
+ SkipCanonicalNameReference();
+ return Constant(result);
+ }
+ } else if ((argument_count == 2) &&
+ Token::IsBinaryArithmeticOperator(token_kind) &&
+ IsNumberLiteral(PeekArgumentsFirstPositionalTag())) {
+ const Object& result = constant_evaluator_.EvaluateExpressionSafe(offset);
+ if (!result.IsError()) {
+ SkipArguments();
+ // read unused "interface_target_reference".
+ SkipCanonicalNameReference();
+ return Constant(result);
+ }
+ }
+
+ SetOffset(before_branch_offset);
+ }
+
+ Fragment instructions = BuildExpression(); // read receiver.
+
+ const dart::String& name = ReadNameAsMethodName(); // read name.
+ const Token::Kind token_kind = MethodKind(name);
+
+ // Detect comparison with null.
+ if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
+ PeekArgumentsCount() == 1 &&
+ (receiver_tag == kNullLiteral ||
+ PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
+ // "==" or "!=" with null on either side.
+ instructions += BuildArguments(NULL, NULL, true); // read arguments.
+ SkipCanonicalNameReference(); // read unused "interface_target_reference".
+ Token::Kind strict_cmp_kind =
+ token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
+ return instructions +
+ StrictCompare(strict_cmp_kind, /*number_check = */ true);
+ }
+
+ instructions += PushArgument(); // push receiver as argument.
+
+ // TODO(28109) Support generic methods in the VM or reify them away.
+ Array& argument_names = Array::ZoneHandle(Z);
+ intptr_t argument_count;
+ instructions +=
+ BuildArguments(&argument_names, &argument_count); // read arguments.
+ ++argument_count;
+
+ intptr_t num_args_checked = 1;
+ // If we have a special operation (e.g. +/-/==) we mark both arguments as
+ // to be checked.
+ if (token_kind != Token::kILLEGAL) {
+ ASSERT(argument_count <= 2);
+ num_args_checked = argument_count;
+ }
+
+ instructions += InstanceCall(position, name, token_kind, argument_count,
+ argument_names, num_args_checked);
+ // Later optimization passes assume that result of a x.[]=(...) call is not
+ // used. We must guarantee this invariant because violation will lead to an
+ // illegal IL once we replace x.[]=(...) with a sequence that does not
+ // actually produce any value. See http://dartbug.com/29135 for more details.
+ if (name.raw() == Symbols::AssignIndexToken().raw()) {
+ instructions += Drop();
+ instructions += NullConstant();
+ }
+
+ SkipCanonicalNameReference(); // read unused "interface_target_reference".
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ // TODO(28109) Support generic methods in the VM or reify them away.
+ Tag receiver_tag = PeekTag(); // peek tag for receiver.
+ Fragment instructions = BuildExpression(); // read receiver.
+
+ NameIndex kernel_name =
+ ReadCanonicalNameReference(); // read target_reference.
+ const dart::String& method_name = H.DartProcedureName(kernel_name);
+ const Token::Kind token_kind = MethodKind(method_name);
+
+ // Detect comparison with null.
+ if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
+ PeekArgumentsCount() == 1 &&
+ (receiver_tag == kNullLiteral ||
+ PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
+ // "==" or "!=" with null on either side.
+ instructions += BuildArguments(NULL, NULL, true); // read arguments.
+ Token::Kind strict_cmp_kind =
+ token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
+ return instructions +
+ StrictCompare(strict_cmp_kind, /*number_check = */ true);
+ }
+
+ instructions += PushArgument(); // push receiver as argument.
+
+ const Function& target =
+ Function::ZoneHandle(Z, LookupMethodByMember(kernel_name, method_name));
+
+ Array& argument_names = Array::ZoneHandle(Z);
+ intptr_t argument_count;
+ instructions +=
+ BuildArguments(&argument_names, &argument_count); // read arguments.
+ ++argument_count;
+ return instructions + StaticCall(TokenPosition::kNoSource, target,
+ argument_count, argument_names);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
+ TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ NameIndex procedue_reference =
+ ReadCanonicalNameReference(); // read procedure reference.
+ intptr_t argument_count = PeekArgumentsCount();
+ const Function& target = Function::ZoneHandle(
+ Z, H.LookupStaticMethodByKernelProcedure(procedue_reference));
+ const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner());
+ if (target.IsGenerativeConstructor() || target.IsFactory()) {
+ // The VM requires a TypeArguments object as first parameter for
+ // every factory constructor.
+ ++argument_count;
+ }
+
+ Fragment instructions;
+ LocalVariable* instance_variable = NULL;
+
+ // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
+ // can appear, but the thing we're calling is not a static method, but a
+ // factory constructor.
+ // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the
+ // forwarded constructor.
+ // In that case we'll make an instance and pass it as first argument.
+ //
+ // TODO(27590): Get rid of this after we're using core libraries compiled
+ // into Kernel.
+ if (target.IsGenerativeConstructor()) {
+ if (klass.NumTypeArguments() > 0) {
+ const TypeArguments& type_arguments =
+ PeekArgumentsInstantiatedType(klass);
+ instructions += TranslateInstantiatedTypeArguments(type_arguments);
+ instructions += PushArgument();
+ instructions += AllocateObject(klass, 1);
+ } else {
+ instructions += AllocateObject(klass, 0);
+ }
+
+ instance_variable = MakeTemporary();
+
+ instructions += LoadLocal(instance_variable);
+ instructions += PushArgument();
+ } else if (target.IsFactory()) {
+ // The VM requires currently a TypeArguments object as first parameter for
+ // every factory constructor :-/ !
+ //
+ // TODO(27590): Get rid of this after we're using core libraries compiled
+ // into Kernel.
+ const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
+ instructions += TranslateInstantiatedTypeArguments(type_arguments);
+ instructions += PushArgument();
+ } else {
+ // TODO(28109) Support generic methods in the VM or reify them away.
+ }
+
+ bool special_case_identical =
+ klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) &&
+ (target.name() == Symbols::Identical().raw());
+
+ Array& argument_names = Array::ZoneHandle(Z);
+ instructions += BuildArguments(&argument_names, NULL,
+ special_case_identical); // read arguments.
+ ASSERT(target.AreValidArguments(argument_count, argument_names, NULL));
+
+ // Special case identical(x, y) call.
+ // TODO(27590) consider moving this into the inliner and force inline it
+ // there.
+ if (special_case_identical) {
+ ASSERT(argument_count == 2);
+ instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
+ } else {
+ instructions +=
+ StaticCall(position, target, argument_count, argument_names);
+ if (target.IsGenerativeConstructor()) {
+ // Drop the result of the constructor call and leave [instance_variable]
+ // on top-of-stack.
+ instructions += Drop();
+ }
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
+ bool is_const,
+ TokenPosition* p) {
+ if (is_const) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ (p != NULL) ? * p = ReadPosition() : ReadPosition(); // read position.
+
+ SetOffset(offset);
+ SkipExpression(); // read past this ConstructorInvocation.
+ return Constant(constant_evaluator_.EvaluateConstructorInvocation(offset));
+ }
+
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ NameIndex kernel_name =
+ ReadCanonicalNameReference(); // read target_reference.
+
+ dart::Class& klass = dart::Class::ZoneHandle(
+ Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name)));
+
+ Fragment instructions;
+
+ // Check for malbounded-ness of type.
+ if (I->type_checks()) {
+ intptr_t offset = ReaderOffset();
+
+ const TypeArguments& type_arguments = BuildTypeArguments();
+
+ AbstractType& type = AbstractType::Handle(
+ Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
+ type = ClassFinalizer::FinalizeType(klass, type);
+
+ if (type.IsMalbounded()) {
+ // Evaluate expressions for correctness.
+ instructions +=
+ BuildArgumentsFromActualArguments(NULL, false, /*do_drop*/ true);
+
+ // Throw an error & keep the [Value] on the stack.
+ instructions += ThrowTypeError();
+
+ // Bail out early.
+ return instructions;
+ }
+
+ SetOffset(offset);
+ }
+
+ if (klass.NumTypeArguments() > 0) {
+ const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
+ if (!klass.IsGeneric()) {
+ Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw());
+
+ // TODO(27590): Can we move this code into [ReceiverType]?
+ type ^= ClassFinalizer::FinalizeType(*active_class()->klass, type,
+ ClassFinalizer::kFinalize);
+ ASSERT(!type.IsMalformedOrMalbounded());
+
+ TypeArguments& canonicalized_type_arguments =
+ TypeArguments::ZoneHandle(Z, type.arguments());
+ canonicalized_type_arguments =
+ canonicalized_type_arguments.Canonicalize();
+ instructions += Constant(canonicalized_type_arguments);
+ } else {
+ instructions += TranslateInstantiatedTypeArguments(type_arguments);
+ }
+
+ instructions += PushArgument();
+ instructions += AllocateObject(klass, 1);
+ } else {
+ instructions += AllocateObject(klass, 0);
+ }
+ LocalVariable* variable = MakeTemporary();
+
+ instructions += LoadLocal(variable);
+ instructions += PushArgument();
+
+ Array& argument_names = Array::ZoneHandle(Z);
+ intptr_t argument_count;
+ instructions +=
+ BuildArguments(&argument_names, &argument_count); // read arguments.
+
+ const Function& target = Function::ZoneHandle(
+ Z, H.LookupConstructorByKernelConstructor(klass, kernel_name));
+ ++argument_count;
+ instructions += StaticCall(position, target, argument_count, argument_names);
+ return instructions + Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildNot(TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ Fragment instructions = BuildExpression(); // read expression.
+ instructions += CheckBooleanInCheckedMode();
+ instructions += BooleanNegate();
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildLogicalExpression(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ bool negate;
+ Fragment instructions = TranslateCondition(&negate); // read left.
+
+ TargetEntryInstr* right_entry;
+ TargetEntryInstr* constant_entry;
+ LogicalExpression::Operator op =
+ static_cast<LogicalExpression::Operator>(ReadByte());
+
+ if (op == LogicalExpression::kAnd) {
+ instructions += BranchIfTrue(&right_entry, &constant_entry, negate);
+ } else {
+ instructions += BranchIfTrue(&constant_entry, &right_entry, negate);
+ }
+
+ Value* top = stack();
+ Fragment right_fragment(right_entry);
+ right_fragment += TranslateCondition(&negate); // read right.
+
+ right_fragment += Constant(Bool::True());
+ right_fragment +=
+ StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT);
+ right_fragment += StoreLocal(TokenPosition::kNoSource,
+ parsed_function()->expression_temp_var());
+ right_fragment += Drop();
+
+ ASSERT(top == stack());
+ Fragment constant_fragment(constant_entry);
+ constant_fragment += Constant(Bool::Get(op == LogicalExpression::kOr));
+ constant_fragment += StoreLocal(TokenPosition::kNoSource,
+ parsed_function()->expression_temp_var());
+ constant_fragment += Drop();
+
+ JoinEntryInstr* join = BuildJoinEntry();
+ right_fragment += Goto(join);
+ constant_fragment += Goto(join);
+
+ return Fragment(instructions.entry, join) +
+ LoadLocal(parsed_function()->expression_temp_var());
+}
+
+Fragment StreamingFlowGraphBuilder::BuildConditionalExpression(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ bool negate;
+ Fragment instructions = TranslateCondition(&negate); // read condition.
+
+ TargetEntryInstr* then_entry;
+ TargetEntryInstr* otherwise_entry;
+ instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
+
+ Value* top = stack();
+ Fragment then_fragment(then_entry);
+ then_fragment += BuildExpression(); // read then.
+ then_fragment += StoreLocal(TokenPosition::kNoSource,
+ parsed_function()->expression_temp_var());
+ then_fragment += Drop();
+ ASSERT(stack() == top);
+
+ Fragment otherwise_fragment(otherwise_entry);
+ otherwise_fragment += BuildExpression(); // read otherwise.
+ otherwise_fragment += StoreLocal(TokenPosition::kNoSource,
+ parsed_function()->expression_temp_var());
+ otherwise_fragment += Drop();
+ ASSERT(stack() == top);
+
+ JoinEntryInstr* join = BuildJoinEntry();
+ then_fragment += Goto(join);
+ otherwise_fragment += Goto(join);
+
+ SkipOptionalDartType(); // read unused static type.
+
+ return Fragment(instructions.entry, join) +
+ LoadLocal(parsed_function()->expression_temp_var());
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStringConcatenation(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ intptr_t length = ReadListLength(); // read list length.
+ // Note: there will be "length" expressions.
+
+ Fragment instructions;
+ if (length == 1) {
+ instructions += BuildExpression(); // read expression.
+ instructions += StringInterpolateSingle(position);
+ } else {
+ // The type arguments for CreateArray.
+ instructions += Constant(TypeArguments::ZoneHandle(Z));
+ instructions += IntConstant(length);
+ instructions += CreateArray();
+ LocalVariable* array = MakeTemporary();
+
+ for (intptr_t i = 0; i < length; ++i) {
+ instructions += LoadLocal(array);
+ instructions += IntConstant(i);
+ instructions += BuildExpression(); // read ith expression.
+ instructions += StoreIndexed(kArrayCid);
+ instructions += Drop();
+ }
+
+ instructions += StringInterpolate(position);
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions = BuildExpression(); // read operand.
+
+ const AbstractType& type = T.BuildType(); // read type.
+
+ // The VM does not like an instanceOf call with a dynamic type. We need to
+ // special case this situation.
+ const Type& object_type = Type::Handle(Z, Type::ObjectType());
+
+ if (type.IsMalformed()) {
+ instructions += Drop();
+ instructions += ThrowTypeError();
+ return instructions;
+ }
+
+ if (type.IsInstantiated() &&
+ object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
+ // Evaluate the expression on the left but ignore it's result.
+ instructions += Drop();
+
+ // Let condition be always true.
+ instructions += Constant(Bool::True());
+ } else {
+ instructions += PushArgument();
+
+ // See if simple instanceOf is applicable.
+ if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) {
+ instructions += Constant(type);
+ instructions += PushArgument(); // Type.
+ instructions += InstanceCall(position, dart::Library::PrivateCoreLibName(
+ Symbols::_simpleInstanceOf()),
+ Token::kIS, 2, 2); // 2 checked arguments.
+ return instructions;
+ }
+
+ if (!type.IsInstantiated(kCurrentClass)) {
+ instructions += LoadInstantiatorTypeArguments();
+ } else {
+ instructions += NullConstant();
+ }
+ instructions += PushArgument(); // Instantiator type arguments.
+
+ if (!type.IsInstantiated(kFunctions)) {
+ instructions += LoadFunctionTypeArguments();
+ } else {
+ instructions += NullConstant();
+ }
+ instructions += PushArgument(); // Function type arguments.
+
+ instructions += Constant(type);
+ instructions += PushArgument(); // Type.
+
+ instructions += InstanceCall(
+ position, dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
+ Token::kIS, 4);
+ }
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildAsExpression(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions = BuildExpression(); // read operand.
+
+ const AbstractType& type = T.BuildType(); // read type.
+
+ // The VM does not like an Object_as call with a dynamic type. We need to
+ // special case this situation.
+ const Type& object_type = Type::Handle(Z, Type::ObjectType());
+
+ if (type.IsMalformed()) {
+ instructions += Drop();
+ instructions += ThrowTypeError();
+ return instructions;
+ }
+
+ if (type.IsInstantiated() &&
+ object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
+ // We already evaluated the operand on the left and just leave it there as
+ // the result of the `obj as dynamic` expression.
+ } else {
+ instructions += PushArgument();
+
+ if (!type.IsInstantiated(kCurrentClass)) {
+ instructions += LoadInstantiatorTypeArguments();
+ } else {
+ instructions += NullConstant();
+ }
+ instructions += PushArgument(); // Instantiator type arguments.
+
+ if (!type.IsInstantiated(kFunctions)) {
+ instructions += LoadFunctionTypeArguments();
+ } else {
+ instructions += NullConstant();
+ }
+ instructions += PushArgument(); // Function type arguments.
+
+ instructions += Constant(type);
+ instructions += PushArgument(); // Type.
+
+ instructions += InstanceCall(
+ position, dart::Library::PrivateCoreLibName(Symbols::_as()), Token::kAS,
+ 4);
+ }
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildSymbolLiteral(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ intptr_t offset = ReaderOffset() - 1; // EvaluateExpression needs the tag.
+ SkipStringReference(); // read index into string table.
+ return Constant(constant_evaluator_.EvaluateExpression(offset));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildTypeLiteral(TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ const AbstractType& type = T.BuildType(); // read type.
+ if (type.IsMalformed()) H.ReportError("Malformed type literal");
+
+ Fragment instructions;
+ if (type.IsInstantiated()) {
+ instructions += Constant(type);
+ } else {
+ if (!type.IsInstantiated(kCurrentClass)) {
+ instructions += LoadInstantiatorTypeArguments();
+ } else {
+ instructions += NullConstant();
+ }
+ if (!type.IsInstantiated(kFunctions)) {
+ instructions += LoadFunctionTypeArguments();
+ } else {
+ instructions += NullConstant();
+ }
+ instructions += InstantiateType(type);
+ }
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildThisExpression(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ return LoadLocal(scopes()->this_variable);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildRethrow(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions = DebugStepCheck(position);
+ instructions += LoadLocal(catch_block()->exception_var());
+ instructions += PushArgument();
+ instructions += LoadLocal(catch_block()->stack_trace_var());
+ instructions += PushArgument();
+ instructions += RethrowException(position, catch_block()->catch_try_index());
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildThrow(TokenPosition* p) {
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ Fragment instructions;
+
+ instructions += BuildExpression(); // read expression.
+
+ if (NeedsDebugStepCheck(stack(), position)) {
+ instructions = DebugStepCheck(position) + instructions;
+ }
+ instructions += PushArgument();
+ instructions += ThrowException(position);
+ ASSERT(instructions.is_closed());
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildListLiteral(bool is_const,
+ TokenPosition* p) {
+ if (is_const) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ (p != NULL) ? * p = ReadPosition() : ReadPosition(); // read position.
+
+ SetOffset(offset);
+ SkipExpression(); // read past the ListLiteral.
+ return Constant(constant_evaluator_.EvaluateListLiteral(offset));
+ }
+
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ const TypeArguments& type_arguments = T.BuildTypeArguments(1); // read type.
+ intptr_t length = ReadListLength(); // read list length.
+ // Note: there will be "length" expressions.
+
+ // The type argument for the factory call.
+ Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
+ instructions += PushArgument();
+ if (length == 0) {
+ instructions += Constant(Object::empty_array());
+ } else {
+ // The type arguments for CreateArray.
+ instructions += Constant(TypeArguments::ZoneHandle(Z));
+ instructions += IntConstant(length);
+ instructions += CreateArray();
+
+ LocalVariable* array = MakeTemporary();
+ for (intptr_t i = 0; i < length; ++i) {
+ instructions += LoadLocal(array);
+ instructions += IntConstant(i);
+ instructions += BuildExpression(); // read ith expression.
+ instructions += StoreIndexed(kArrayCid);
+ instructions += Drop();
+ }
+ }
+ instructions += PushArgument(); // The array.
+
+ const dart::Class& factory_class =
+ dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List()));
+ const Function& factory_method = Function::ZoneHandle(
+ Z, factory_class.LookupFactory(
+ dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
+
+ return instructions + StaticCall(position, factory_method, 2);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const,
+ TokenPosition* p) {
+ if (is_const) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ (p != NULL) ? * p = ReadPosition() : ReadPosition();
+
+ SetOffset(offset);
+ SkipExpression(); // Read past the MapLiteral.
+ return Constant(constant_evaluator_.EvaluateMapLiteral(offset));
+ }
+
+ TokenPosition position = ReadPosition(); // read position.
+ if (p != NULL) *p = position;
+
+ const TypeArguments& type_arguments =
+ T.BuildTypeArguments(2); // read key_type and value_type.
+
+ // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
+ Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
+ instructions += PushArgument();
+
+ intptr_t length = ReadListLength(); // read list length.
+ // Note: there will be "length" map entries (i.e. key and value expressions).
+
+ if (length == 0) {
+ instructions += Constant(Object::empty_array());
+ } else {
+ // The type arguments for `new List<X>(int len)`.
+ instructions += Constant(TypeArguments::ZoneHandle(Z));
+
+ // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
+ instructions += IntConstant(2 * length);
+ instructions += CreateArray();
+
+ LocalVariable* array = MakeTemporary();
+ for (intptr_t i = 0; i < length; ++i) {
+ instructions += LoadLocal(array);
+ instructions += IntConstant(2 * i);
+ instructions += BuildExpression(); // read ith key.
+ instructions += StoreIndexed(kArrayCid);
+ instructions += Drop();
+
+ instructions += LoadLocal(array);
+ instructions += IntConstant(2 * i + 1);
+ instructions += BuildExpression(); // read ith value.
+ instructions += StoreIndexed(kArrayCid);
+ instructions += Drop();
+ }
+ }
+ instructions += PushArgument(); // The array.
+
+
+ const dart::Class& map_class =
+ dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map()));
+ const Function& factory_method = Function::ZoneHandle(
+ Z, map_class.LookupFactory(
+ dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory())));
+
+ return instructions + StaticCall(position, factory_method, 2);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ Fragment instructions = BuildVariableDeclaration(false); // read variable.
+ instructions += BuildExpression(); // read body.
+ return instructions;
+}
+
+
+Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ const dart::String& value =
+ H.DartString(ReadStringReference()); // read index into string table.
+ return Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStringLiteral(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ return Constant(
+ H.DartSymbol(ReadStringReference())); // read index into string table.
+}
+
+Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload,
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
+ return IntConstant(value);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative,
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt())
+ : ReadUInt(); // read value.
+ return IntConstant(value);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral(
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ intptr_t offset = ReaderOffset() - 1; // EvaluateExpression needs the tag.
+ SkipStringReference(); // read index into string table.
+ return Constant(constant_evaluator_.EvaluateExpression(offset));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value,
+ TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ return Constant(Bool::Get(value));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildNullLiteral(TokenPosition* position) {
+ if (position != NULL) *position = TokenPosition::kNoSource;
+
+ return Constant(Instance::ZoneHandle(Z, Instance::null()));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildInvalidStatement() {
+ H.ReportError("Invalid statements not implemented yet!");
+ return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildExpressionStatement() {
+ Fragment instructions = BuildExpression(); // read expression.
+ instructions += Drop();
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildBlock() {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+
+ Fragment instructions;
+
+ instructions += EnterScope(offset);
+ intptr_t list_length = ReadListLength(); // read number of statements.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ if (instructions.is_open()) {
+ instructions += BuildStatement(); // read ith statement.
+ } else {
+ SkipStatement(); // read ith statement.
+ }
+ }
+ instructions += ExitScope(offset);
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() {
+ return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildAssertStatement() {
+ if (!I->asserts()) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ SetOffset(offset);
+ SkipStatement(); // read this statement.
+ return Fragment();
+ }
+
+ TargetEntryInstr* then;
+ TargetEntryInstr* otherwise;
+
+ Fragment instructions;
+ // Asserts can be of the following two kinds:
+ //
+ // * `assert(expr)`
+ // * `assert(() { ... })`
+ //
+ // The call to `_AssertionError._evaluateAssertion()` will take care of both
+ // and returns a boolean.
+ instructions += BuildExpression(); // read condition.
+ instructions += PushArgument();
+ instructions += EvaluateAssertion();
+ instructions += CheckBooleanInCheckedMode();
+ instructions += Constant(Bool::True());
+ instructions += BranchIfEqual(&then, &otherwise, false);
+
+ const dart::Class& klass = dart::Class::ZoneHandle(
+ Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
+ ASSERT(!klass.IsNull());
+ const dart::Function& constructor = dart::Function::ZoneHandle(
+ Z, klass.LookupConstructorAllowPrivate(
+ H.DartSymbol("_AssertionError._create")));
+ ASSERT(!constructor.IsNull());
+
+ const dart::String& url = H.DartString(
+ parsed_function()->function().ToLibNamePrefixedQualifiedCString(),
+ Heap::kOld);
+
+ // Create instance of _AssertionError
+ Fragment otherwise_fragment(otherwise);
+ otherwise_fragment += AllocateObject(klass, 0);
+ LocalVariable* instance = MakeTemporary();
+
+ // Call _AssertionError._create constructor.
+ otherwise_fragment += LoadLocal(instance);
+ otherwise_fragment += PushArgument(); // this
+
+ otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
+ otherwise_fragment += PushArgument(); // failedAssertion
+
+ otherwise_fragment += Constant(url);
+ otherwise_fragment += PushArgument(); // url
+
+ otherwise_fragment += IntConstant(0);
+ otherwise_fragment += PushArgument(); // line
+
+ otherwise_fragment += IntConstant(0);
+ otherwise_fragment += PushArgument(); // column
+
+ Tag tag = ReadTag(); // read (first part of) message.
+ if (tag == kSomething) {
+ otherwise_fragment += BuildExpression(); // read (rest of) message.
+ } else {
+ otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
+ }
+ otherwise_fragment += PushArgument(); // message
+
+ otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6);
+ otherwise_fragment += Drop();
+
+ // Throw _AssertionError exception.
+ otherwise_fragment += PushArgument();
+ otherwise_fragment += ThrowException(TokenPosition::kNoSource);
+ otherwise_fragment += Drop();
+
+ return Fragment(instructions.entry, then);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildLabeledStatement() {
+ // There can be serveral cases:
+ //
+ // * the body contains a break
+ // * the body doesn't contain a break
+ //
+ // * translating the body results in a closed fragment
+ // * translating the body results in a open fragment
+ //
+ // => We will only know which case we are in after the body has been
+ // traversed.
+
+ BreakableBlock block(flow_graph_builder_);
+ Fragment instructions = BuildStatement(); // read body.
+ if (block.HadJumper()) {
+ if (instructions.is_open()) {
+ instructions += Goto(block.destination());
+ }
+ return Fragment(instructions.entry, block.destination());
+ } else {
+ return instructions;
+ }
+}
+
+Fragment StreamingFlowGraphBuilder::BuildBreakStatement() {
+ TokenPosition position = ReadPosition(); // read position.
+ intptr_t target_index = ReadUInt(); // read target index.
+
+ TryFinallyBlock* outer_finally = NULL;
+ intptr_t target_context_depth = -1;
+ JoinEntryInstr* destination = breakable_block()->BreakDestination(
+ target_index, &outer_finally, &target_context_depth);
+
+ Fragment instructions;
+ instructions +=
+ TranslateFinallyFinalizers(outer_finally, target_context_depth);
+ if (instructions.is_open()) {
+ if (NeedsDebugStepCheck(parsed_function()->function(), position)) {
+ instructions += DebugStepCheck(position);
+ }
+ instructions += Goto(destination);
+ }
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildWhileStatement() {
+ loop_depth_inc();
+ bool negate;
+ Fragment condition = TranslateCondition(&negate); // read condition.
+ TargetEntryInstr* body_entry;
+ TargetEntryInstr* loop_exit;
+ condition += BranchIfTrue(&body_entry, &loop_exit, negate);
+
+ Fragment body(body_entry);
+ body += BuildStatement(); // read body.
+
+ Instruction* entry;
+ if (body.is_open()) {
+ JoinEntryInstr* join = BuildJoinEntry();
+ body += Goto(join);
+
+ Fragment loop(join);
+ loop += CheckStackOverflow();
+ loop += condition;
+ entry = new (Z) GotoInstr(join);
+ } else {
+ entry = condition.entry;
}
- return H.Canonicalize(instance);
+
+
+ loop_depth_dec();
+ return Fragment(entry, loop_exit);
}
-bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset,
- Instance* value) {
- if (builder_ == NULL) return false;
+Fragment StreamingFlowGraphBuilder::BuildDoStatement() {
+ loop_depth_inc();
+ Fragment body = BuildStatement(); // read body.
- const Function& function = builder_->parsed_function()->function();
- if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
- // Don't cache constants in initializer expressions. They get
- // evaluated only once.
- return false;
+ if (body.is_closed()) {
+ SkipExpression(); // read condition.
+ loop_depth_dec();
+ return body;
}
- bool is_present = false;
- ASSERT(!script_.InVMHeap());
- if (script_.compile_time_constants() == Array::null()) {
- return false;
- }
- KernelConstantsMap constants(script_.compile_time_constants());
- *value ^= constants.GetOrNull(kernel_offset, &is_present);
- // Mutator compiler thread may add constants while background compiler
- // is running, and thus change the value of 'compile_time_constants';
- // do not assert that 'compile_time_constants' has not changed.
- constants.Release();
- if (FLAG_compiler_stats && is_present) {
- H.thread()->compiler_stats()->num_const_cache_hits++;
- }
- return is_present;
+ bool negate;
+ JoinEntryInstr* join = BuildJoinEntry();
+ Fragment loop(join);
+ loop += CheckStackOverflow();
+ loop += body;
+ loop += TranslateCondition(&negate); // read condition.
+ TargetEntryInstr* loop_repeat;
+ TargetEntryInstr* loop_exit;
+ loop += BranchIfTrue(&loop_repeat, &loop_exit, negate);
+
+ Fragment repeat(loop_repeat);
+ repeat += Goto(join);
+
+ loop_depth_dec();
+ return Fragment(new (Z) GotoInstr(join), loop_exit);
}
+Fragment StreamingFlowGraphBuilder::BuildForStatement() {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
-void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset,
- const Instance& value) {
- ASSERT(Thread::Current()->IsMutatorThread());
+ Fragment declarations;
- if (builder_ == NULL) return;
+ bool new_context = false;
+ declarations += EnterScope(offset, &new_context);
- const Function& function = builder_->parsed_function()->function();
- if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
- // Don't cache constants in initializer expressions. They get
- // evaluated only once.
- return;
+ intptr_t list_length = ReadListLength(); // read number of variables.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ declarations += BuildVariableDeclaration(false); // read ith variable.
}
- const intptr_t kInitialConstMapSize = 16;
- ASSERT(!script_.InVMHeap());
- if (script_.compile_time_constants() == Array::null()) {
- const Array& array = Array::Handle(
- HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew));
- script_.set_compile_time_constants(array);
+
+ loop_depth_inc();
+ bool negate = false;
+ Tag tag = ReadTag(); // Read first part of condition.
+ Fragment condition =
+ tag == kNothing ? Constant(Bool::True())
+ : TranslateCondition(&negate); // read rest of condition.
+ TargetEntryInstr* body_entry;
+ TargetEntryInstr* loop_exit;
+ condition += BranchIfTrue(&body_entry, &loop_exit, negate);
+
+ Fragment updates;
+ list_length = ReadListLength(); // read number of updates.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ updates += BuildExpression(); // read ith update.
+ updates += Drop();
}
- KernelConstantsMap constants(script_.compile_time_constants());
- constants.InsertNewOrGetValue(kernel_offset, value);
- script_.set_compile_time_constants(constants.Release());
-}
+ Fragment body(body_entry);
+ body += BuildStatement(); // read body.
-Fragment StreamingFlowGraphBuilder::BuildAt(intptr_t kernel_offset) {
- SetOffset(kernel_offset);
+ if (body.is_open()) {
+ // We allocated a fresh context before the loop which contains captured
+ // [ForStatement] variables. Before jumping back to the loop entry we clone
+ // the context object (at same depth) which ensures the next iteration of
+ // the body gets a fresh set of [ForStatement] variables (with the old
+ // (possibly updated) values).
+ if (new_context) body += CloneContext();
- uint8_t payload = 0;
- Tag tag = ReadTag(&payload);
- switch (tag) {
- case kInvalidExpression:
- return BuildInvalidExpression();
- // case kVariableGet:
- // return VariableGet::ReadFrom(reader_);
- // case kSpecializedVariableGet:
- // return VariableGet::ReadFrom(reader_, payload);
- // case kVariableSet:
- // return VariableSet::ReadFrom(reader_);
- // case kSpecializedVariableSet:
- // return VariableSet::ReadFrom(reader_, payload);
- // case kPropertyGet:
- // return PropertyGet::ReadFrom(reader_);
- // case kPropertySet:
- // return PropertySet::ReadFrom(reader_);
- // case kDirectPropertyGet:
- // return DirectPropertyGet::ReadFrom(reader_);
- // case kDirectPropertySet:
- // return DirectPropertySet::ReadFrom(reader_);
- case kStaticGet:
- return BuildStaticGet();
- // case kStaticSet:
- // return StaticSet::ReadFrom(reader_);
- // case kMethodInvocation:
- // return MethodInvocation::ReadFrom(reader_);
- // case kDirectMethodInvocation:
- // return DirectMethodInvocation::ReadFrom(reader_);
- // case kStaticInvocation:
- // return StaticInvocation::ReadFrom(reader_, false);
- // case kConstStaticInvocation:
- // return StaticInvocation::ReadFrom(reader_, true);
- // case kConstructorInvocation:
- // return ConstructorInvocation::ReadFrom(reader_, false);
- // case kConstConstructorInvocation:
- // return ConstructorInvocation::ReadFrom(reader_, true);
- // case kNot:
- // return Not::ReadFrom(reader_);
- // case kLogicalExpression:
- // return LogicalExpression::ReadFrom(reader_);
- // case kConditionalExpression:
- // return ConditionalExpression::ReadFrom(reader_);
- // case kStringConcatenation:
- // return StringConcatenation::ReadFrom(reader_);
- // case kIsExpression:
- // return IsExpression::ReadFrom(reader_);
- // case kAsExpression:
- // return AsExpression::ReadFrom(reader_);
- case kSymbolLiteral:
- return BuildSymbolLiteral();
- // case kTypeLiteral:
- // return TypeLiteral::ReadFrom(reader_);
- case kThisExpression:
- return BuildThisExpression();
- case kRethrow:
- return BuildRethrow();
- // case kThrow:
- // return Throw::ReadFrom(reader_);
- // case kListLiteral:
- // return ListLiteral::ReadFrom(reader_, false);
- // case kConstListLiteral:
- // return ListLiteral::ReadFrom(reader_, true);
- // case kMapLiteral:
- // return MapLiteral::ReadFrom(reader_, false);
- // case kConstMapLiteral:
- // return MapLiteral::ReadFrom(reader_, true);
- // case kAwaitExpression:
- // return AwaitExpression::ReadFrom(reader_);
- // case kFunctionExpression:
- // return FunctionExpression::ReadFrom(reader_);
- // case kLet:
- // return Let::ReadFrom(reader_);
- case kBigIntLiteral:
- return BuildBigIntLiteral();
- case kStringLiteral:
- return BuildStringLiteral();
- case kSpecialIntLiteral:
- return BuildIntLiteral(payload);
- case kNegativeIntLiteral:
- return BuildIntLiteral(true);
- case kPositiveIntLiteral:
- return BuildIntLiteral(false);
- case kDoubleLiteral:
- return BuildDoubleLiteral();
- case kTrueLiteral:
- return BuildBoolLiteral(true);
- case kFalseLiteral:
- return BuildBoolLiteral(false);
- case kNullLiteral:
- return BuildNullLiteral();
- default:
- UNREACHABLE();
+ body += updates;
+ JoinEntryInstr* join = BuildJoinEntry();
+ declarations += Goto(join);
+ body += Goto(join);
+
+ Fragment loop(join);
+ loop += CheckStackOverflow();
+ loop += condition;
+ } else {
+ declarations += condition;
}
- return Fragment();
-}
+ Fragment loop(declarations.entry, loop_exit);
+ loop_depth_dec();
+ loop += ExitScope(offset);
-intptr_t StreamingFlowGraphBuilder::ReaderOffset() {
- return reader_->offset();
+ return loop;
}
+Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) {
+ intptr_t offset = ReaderOffset() - 1; // Include the tag.
-void StreamingFlowGraphBuilder::SetOffset(intptr_t offset) {
- reader_->set_offset(offset);
-}
+ TokenPosition position = ReadPosition(); // read position.
+ intptr_t variable_kernel_position = ReaderOffset();
+ SkipVariableDeclaration(); // read variable.
+ TokenPosition iterable_position = TokenPosition::kNoSource;
+ Fragment instructions =
+ BuildExpression(&iterable_position); // read iterable.
+ instructions += PushArgument();
-void StreamingFlowGraphBuilder::SkipBytes(intptr_t bytes) {
- reader_->set_offset(ReaderOffset() + bytes);
-}
+ const dart::String& iterator_getter = dart::String::ZoneHandle(
+ Z, dart::Field::GetterSymbol(Symbols::Iterator()));
+ instructions +=
+ InstanceCall(iterable_position, iterator_getter, Token::kGET, 1);
+ LocalVariable* iterator = scopes()->iterator_variables[for_in_depth()];
+ instructions += StoreLocal(TokenPosition::kNoSource, iterator);
+ instructions += Drop();
+ for_in_depth_inc();
+ loop_depth_inc();
+ Fragment condition = LoadLocal(iterator);
+ condition += PushArgument();
+ condition +=
+ InstanceCall(iterable_position, Symbols::MoveNext(), Token::kILLEGAL, 1);
+ TargetEntryInstr* body_entry;
+ TargetEntryInstr* loop_exit;
+ condition += BranchIfTrue(&body_entry, &loop_exit, false);
-uint32_t StreamingFlowGraphBuilder::ReadUInt() {
- return reader_->ReadUInt();
-}
+ Fragment body(body_entry);
+ body += EnterScope(offset);
+ body += LoadLocal(iterator);
+ body += PushArgument();
+ const dart::String& current_getter = dart::String::ZoneHandle(
+ Z, dart::Field::GetterSymbol(Symbols::Current()));
+ body += InstanceCall(position, current_getter, Token::kGET, 1);
+ body += StoreLocal(TokenPosition::kNoSource,
+ LookupVariable(variable_kernel_position));
+ body += Drop();
+ body += BuildStatement(); // read body.
+ body += ExitScope(offset);
+ if (body.is_open()) {
+ JoinEntryInstr* join = BuildJoinEntry();
+ instructions += Goto(join);
+ body += Goto(join);
-intptr_t StreamingFlowGraphBuilder::ReadListLength() {
- return reader_->ReadListLength();
+ Fragment loop(join);
+ loop += CheckStackOverflow();
+ loop += condition;
+ } else {
+ instructions += condition;
+ }
+
+ loop_depth_dec();
+ for_in_depth_dec();
+ return Fragment(instructions.entry, loop_exit);
}
+Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() {
+ // We need the number of cases. So start by getting that, then go back.
+ intptr_t offset = ReaderOffset();
+ SkipExpression(); // temporarily skip condition
+ int num_cases = ReadListLength(); // read number of cases.
+ SetOffset(offset);
-NameIndex StreamingFlowGraphBuilder::ReadCanonicalNameReference() {
- return reader_->ReadCanonicalNameReference();
-}
+ SwitchBlock block(flow_graph_builder_, num_cases);
+ // Instead of using a variable we should reuse the expression on the stack,
+ // since it won't be assigned again, we don't need phi nodes.
+ Fragment head_instructions = BuildExpression(); // read condition.
+ head_instructions +=
+ StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable);
+ head_instructions += Drop();
-TokenPosition StreamingFlowGraphBuilder::ReadPosition(bool record) {
- return reader_->ReadPosition(record);
-}
+ num_cases = ReadListLength(); // read number of cases.
+ // Phase 1: Generate bodies and try to find out whether a body will be target
+ // of a jump due to:
+ // * `continue case_label`
+ // * `case e1: case e2: body`
+ Fragment* body_fragments = new Fragment[num_cases];
+ intptr_t* case_expression_offsets = new intptr_t[num_cases];
+ bool* case_is_default = new bool[num_cases];
-Tag StreamingFlowGraphBuilder::ReadTag(uint8_t* payload) {
- return reader_->ReadTag(payload);
-}
+ for (intptr_t i = 0; i < num_cases; ++i) {
+ case_expression_offsets[i] = ReaderOffset();
+ int num_expressions = ReadListLength(); // read number of expressions.
+ for (intptr_t j = 0; j < num_expressions; ++j) {
+ ReadPosition(); // read jth position.
+ SkipExpression(); // read jth expression.
+ }
+ bool is_default = ReadBool(); // read is_default.
+ case_is_default[i] = is_default;
+ Fragment& body_fragment = body_fragments[i] =
+ BuildStatement(); // read body.
+ if (body_fragment.entry == NULL) {
+ // Make a NOP in order to ensure linking works properly.
+ body_fragment = NullConstant();
+ body_fragment += Drop();
+ }
-CatchBlock* StreamingFlowGraphBuilder::catch_block() {
- return flow_graph_builder_->catch_block_;
-}
+ // The Dart language specification mandates fall-throughs in [SwitchCase]es
+ // to be runtime errors.
+ if (!is_default && body_fragment.is_open() && (i < (num_cases - 1))) {
+ const dart::Class& klass = dart::Class::ZoneHandle(
+ Z, dart::Library::LookupCoreClass(Symbols::FallThroughError()));
+ ASSERT(!klass.IsNull());
+ const dart::Function& constructor = dart::Function::ZoneHandle(
+ Z, klass.LookupConstructorAllowPrivate(
+ H.DartSymbol("FallThroughError._create")));
+ ASSERT(!constructor.IsNull());
+ const dart::String& url = H.DartString(
+ parsed_function()->function().ToLibNamePrefixedQualifiedCString(),
+ Heap::kOld);
+ // Create instance of _FallThroughError
+ body_fragment += AllocateObject(klass, 0);
+ LocalVariable* instance = MakeTemporary();
-ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
- return flow_graph_builder_->scopes_;
-}
+ // Call _FallThroughError._create constructor.
+ body_fragment += LoadLocal(instance);
+ body_fragment += PushArgument(); // this
+ body_fragment += Constant(url);
+ body_fragment += PushArgument(); // url
-ParsedFunction* StreamingFlowGraphBuilder::parsed_function() {
- return flow_graph_builder_->parsed_function_;
-}
+ body_fragment += NullConstant();
+ body_fragment += PushArgument(); // line
+ body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3);
+ body_fragment += Drop();
-Fragment StreamingFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
- return flow_graph_builder_->DebugStepCheck(position);
-}
+ // Throw the exception
+ body_fragment += PushArgument();
+ body_fragment += ThrowException(TokenPosition::kNoSource);
+ body_fragment += Drop();
+ }
+ // If there is an implicit fall-through we have one [SwitchCase] and
+ // multiple expressions, e.g.
+ //
+ // switch(expr) {
+ // case a:
+ // case b:
+ // <stmt-body>
+ // }
+ //
+ // This means that the <stmt-body> will have more than 1 incoming edge (one
+ // from `a == expr` and one from `a != expr && b == expr`). The
+ // `block.Destination()` records the additional jump.
+ if (num_expressions > 1) {
+ block.DestinationDirect(i);
+ }
+ }
-Fragment StreamingFlowGraphBuilder::LoadLocal(LocalVariable* variable) {
- return flow_graph_builder_->LoadLocal(variable);
-}
+ intptr_t end_offset = ReaderOffset();
+ // Phase 2: Generate everything except the real bodies:
+ // * jump directly to a body (if there is no jumper)
+ // * jump to a wrapper block which jumps to the body (if there is a jumper)
+ Fragment current_instructions = head_instructions;
+ for (intptr_t i = 0; i < num_cases; ++i) {
+ SetOffset(case_expression_offsets[i]);
+ int num_expressions = ReadListLength(); // read length of expressions.
-Fragment StreamingFlowGraphBuilder::PushArgument() {
- return flow_graph_builder_->PushArgument();
-}
+ if (case_is_default[i]) {
+ ASSERT(i == (num_cases - 1));
+ // Evaluate the conditions for the default [SwitchCase] just for the
+ // purpose of potentially triggering a compile-time error.
-Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
- int catch_try_index) {
- return flow_graph_builder_->RethrowException(position, catch_try_index);
-}
+ for (intptr_t j = 0; j < num_expressions; ++j) {
+ ReadPosition(); // read jth position.
+ // this reads the expression, but doesn't skip past it.
+ constant_evaluator_.EvaluateExpression(ReaderOffset());
+ SkipExpression(); // read jth expression.
+ }
+ if (block.HadJumper(i)) {
+ // There are several branches to the body, so we will make a goto to
+ // the join block (and prepend a join instruction to the real body).
+ JoinEntryInstr* join = block.DestinationDirect(i);
+ current_instructions += Goto(join);
-Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError() {
- return flow_graph_builder_->ThrowNoSuchMethodError();
-}
+ current_instructions = Fragment(current_instructions.entry, join);
+ current_instructions += body_fragments[i];
+ } else {
+ current_instructions += body_fragments[i];
+ }
+ } else {
+ JoinEntryInstr* body_join = NULL;
+ if (block.HadJumper(i)) {
+ body_join = block.DestinationDirect(i);
+ body_fragments[i] = Fragment(body_join) + body_fragments[i];
+ }
+ for (intptr_t j = 0; j < num_expressions; ++j) {
+ TargetEntryInstr* then;
+ TargetEntryInstr* otherwise;
-Fragment StreamingFlowGraphBuilder::Constant(const Object& value) {
- return flow_graph_builder_->Constant(value);
-}
+ TokenPosition position = ReadPosition(); // read jth position.
+ current_instructions +=
+ Constant(constant_evaluator_.EvaluateExpression(ReaderOffset()));
+ SkipExpression(); // read jth expression.
+ current_instructions += PushArgument();
+ current_instructions += LoadLocal(scopes()->switch_variable);
+ current_instructions += PushArgument();
+ current_instructions +=
+ InstanceCall(position, Symbols::EqualOperator(), Token::kEQ,
+ /*argument_count=*/2,
+ /*num_args_checked=*/2);
+ current_instructions += BranchIfTrue(&then, &otherwise, false);
+ Fragment then_fragment(then);
-Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) {
- return flow_graph_builder_->IntConstant(value);
+ if (body_join != NULL) {
+ // There are several branches to the body, so we will make a goto to
+ // the join block (the real body has already been prepended with a
+ // join instruction).
+ then_fragment += Goto(body_join);
+ } else {
+ // There is only a signle branch to the body, so we will just append
+ // the body fragment.
+ then_fragment += body_fragments[i];
+ }
+
+ current_instructions = Fragment(otherwise);
+ }
+ }
+ }
+
+ bool has_no_default = num_cases > 0 && !case_is_default[num_cases - 1];
+ if (has_no_default) {
+ // There is no default, which means we have an open [current_instructions]
+ // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
+ //
+ // Furthermore the last [SwitchCase] can be open as well. If so, we need
+ // to join these two.
+ Fragment& last_body = body_fragments[num_cases - 1];
+ if (last_body.is_open()) {
+ ASSERT(current_instructions.is_open());
+ ASSERT(current_instructions.current->IsTargetEntry());
+
+ // Join the last "otherwise" branch and the last [SwitchCase] fragment.
+ JoinEntryInstr* join = BuildJoinEntry();
+ current_instructions += Goto(join);
+ last_body += Goto(join);
+
+ current_instructions = Fragment(join);
+ }
+ } else {
+ // All non-default cases will be closed (i.e. break/continue/throw/return)
+ // So it is fine to just let more statements after the switch append to the
+ // default case.
+ }
+
+ delete[] body_fragments;
+
+ SetOffset(end_offset);
+ return Fragment(head_instructions.entry, current_instructions.current);
}
+Fragment StreamingFlowGraphBuilder::BuildContinueSwitchStatement() {
+ intptr_t target_index = ReadUInt(); // read target index.
-Fragment StreamingFlowGraphBuilder::LoadStaticField() {
- return flow_graph_builder_->LoadStaticField();
+ TryFinallyBlock* outer_finally = NULL;
+ intptr_t target_context_depth = -1;
+ JoinEntryInstr* entry = switch_block()->Destination(
+ target_index, &outer_finally, &target_context_depth);
+
+ Fragment instructions;
+ instructions +=
+ TranslateFinallyFinalizers(outer_finally, target_context_depth);
+ if (instructions.is_open()) {
+ instructions += Goto(entry);
+ }
+ return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildIfStatement() {
+ bool negate;
+ Fragment instructions = TranslateCondition(&negate); // read condition.
+ TargetEntryInstr* then_entry;
+ TargetEntryInstr* otherwise_entry;
+ instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
-Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
- const Function& target,
- intptr_t argument_count) {
- return flow_graph_builder_->StaticCall(position, target, argument_count);
+ Fragment then_fragment(then_entry);
+ then_fragment += BuildStatement(); // read then.
+
+ Fragment otherwise_fragment(otherwise_entry);
+ otherwise_fragment += BuildStatement(); // read otherwise.
+
+ if (then_fragment.is_open()) {
+ if (otherwise_fragment.is_open()) {
+ JoinEntryInstr* join = BuildJoinEntry();
+ then_fragment += Goto(join);
+ otherwise_fragment += Goto(join);
+ return Fragment(instructions.entry, join);
+ } else {
+ return Fragment(instructions.entry, then_fragment.current);
+ }
+ } else if (otherwise_fragment.is_open()) {
+ return Fragment(instructions.entry, otherwise_fragment.current);
+ } else {
+ return instructions.closed();
+ }
}
+Fragment StreamingFlowGraphBuilder::BuildReturnStatement() {
+ TokenPosition position = ReadPosition(); // read position.
+ Tag tag = ReadTag(); // read first part of expression.
-Fragment StreamingFlowGraphBuilder::BuildInvalidExpression() {
- // The frontend will take care of emitting normal errors (like
- // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special
- // situations (e.g. an invalid annotation).
- return ThrowNoSuchMethodError();
+ bool inside_try_finally = try_finally_block() != NULL;
+
+ Fragment instructions = tag == kNothing
+ ? NullConstant()
+ : BuildExpression(); // read rest of expression.
+
+ if (instructions.is_open()) {
+ if (inside_try_finally) {
+ ASSERT(scopes()->finally_return_variable != NULL);
+ const Function& function = parsed_function()->function();
+ if (NeedsDebugStepCheck(function, position)) {
+ instructions += DebugStepCheck(position);
+ }
+ instructions += StoreLocal(position, scopes()->finally_return_variable);
+ instructions += Drop();
+ instructions += TranslateFinallyFinalizers(NULL, -1);
+ if (instructions.is_open()) {
+ instructions += LoadLocal(scopes()->finally_return_variable);
+ instructions += Return(TokenPosition::kNoSource);
+ }
+ } else {
+ instructions += Return(position);
+ }
+ } else {
+ Pop();
+ }
+
+ return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildTryCatch() {
+ InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
-Fragment StreamingFlowGraphBuilder::BuildStaticGet() {
- intptr_t saved_offset = ReaderOffset() - 1; // Include the tag.
- TokenPosition position = ReadPosition();
- NameIndex target = ReadCanonicalNameReference();
+ intptr_t try_handler_index = AllocateTryIndex();
+ Fragment try_body = TryCatch(try_handler_index);
+ JoinEntryInstr* after_try = BuildJoinEntry();
- if (H.IsField(target)) {
- const dart::Field& field =
- dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
- if (field.is_const()) {
- SetOffset(saved_offset); // EvaluateExpression needs the tag.
- return Constant(constant_evaluator_.EvaluateExpression());
+ // Fill in the body of the try.
+ try_depth_inc();
+ {
+ TryCatchBlock block(flow_graph_builder_, try_handler_index);
+ try_body += BuildStatement(); // read body.
+ try_body += Goto(after_try);
+ }
+ try_depth_dec();
+
+ bool needs_stacktrace = ReadBool(); // read any_catch_needs_stack_trace
+
+ catch_depth_inc();
+ intptr_t num_matches = ReadListLength(); // read number of catches.
+ const Array& handler_types =
+ Array::ZoneHandle(Z, Array::New(num_matches, Heap::kOld));
+ Fragment catch_body =
+ CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace);
+ // Fill in the body of the catch.
+ for (intptr_t i = 0; i < num_matches; ++i) {
+ intptr_t catch_offset = ReaderOffset(); // Catch has no tag.
+ Tag tag = PeekTag(); // peek guard type.
+ AbstractType* type_guard = NULL;
+ if (tag != kDynamicType) {
+ type_guard = &T.BuildType(); // read guard.
+ handler_types.SetAt(i, *type_guard);
} else {
- const dart::Class& owner = dart::Class::Handle(Z, field.Owner());
- const dart::String& getter_name = H.DartGetterName(target);
- const Function& getter =
- Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name));
- if (getter.IsNull() || !field.has_initializer()) {
- Fragment instructions = Constant(field);
- return instructions + LoadStaticField();
- } else {
- return StaticCall(position, getter, 0);
+ SkipDartType(); // read guard.
+ handler_types.SetAt(i, Object::dynamic_type());
+ }
+
+ Fragment catch_handler_body = EnterScope(catch_offset);
+
+ tag = ReadTag(); // read first part of exception.
+ if (tag == kSomething) {
+ catch_handler_body += LoadLocal(CurrentException());
+ catch_handler_body +=
+ StoreLocal(TokenPosition::kNoSource, LookupVariable(ReaderOffset()));
+ catch_handler_body += Drop();
+ SkipVariableDeclaration(); // read exception.
+ }
+
+ tag = ReadTag(); // read first part of stack trace.
+ if (tag == kSomething) {
+ catch_handler_body += LoadLocal(CurrentStackTrace());
+ catch_handler_body +=
+ StoreLocal(TokenPosition::kNoSource, LookupVariable(ReaderOffset()));
+ catch_handler_body += Drop();
+ SkipVariableDeclaration(); // read stack trace.
+ }
+
+ {
+ CatchBlock block(flow_graph_builder_, CurrentException(),
+ CurrentStackTrace(), try_handler_index);
+
+ catch_handler_body += BuildStatement(); // read body.
+
+ // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
+ // is closed we still need to execute ExitScope for its side effect.
+ catch_handler_body += ExitScope(catch_offset);
+ if (catch_handler_body.is_open()) {
+ catch_handler_body += Goto(after_try);
}
}
- } else {
- const Function& function =
- Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
- if (H.IsGetter(target)) {
- return StaticCall(position, function, 0);
- } else if (H.IsMethod(target)) {
- SetOffset(saved_offset); // EvaluateExpression needs the tag.
- return Constant(constant_evaluator_.EvaluateExpression());
+ if (type_guard != NULL) {
+ if (type_guard->IsMalformed()) {
+ catch_body += ThrowTypeError();
+ catch_body += Drop();
+ } else {
+ catch_body += LoadLocal(CurrentException());
+ catch_body += PushArgument(); // exception
+ catch_body += NullConstant();
+ catch_body += PushArgument(); // instantiator type arguments
+ catch_body += NullConstant();
+ catch_body += PushArgument(); // function type arguments
+ catch_body += Constant(*type_guard);
+ catch_body += PushArgument(); // guard type
+ catch_body += InstanceCall(
+ TokenPosition::kNoSource,
+ dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
+ Token::kIS, 4);
+
+ TargetEntryInstr* catch_entry;
+ TargetEntryInstr* next_catch_entry;
+ catch_body += BranchIfTrue(&catch_entry, &next_catch_entry, false);
+
+ Fragment(catch_entry) + catch_handler_body;
+ catch_body = Fragment(next_catch_entry);
+ }
} else {
- UNIMPLEMENTED();
+ catch_body += catch_handler_body;
}
}
- return Fragment();
+ // In case the last catch body was not handling the exception and branching to
+ // after the try block, we will rethrow the exception (i.e. no default catch
+ // handler).
+ if (catch_body.is_open()) {
+ catch_body += LoadLocal(CurrentException());
+ catch_body += PushArgument();
+ catch_body += LoadLocal(CurrentStackTrace());
+ catch_body += PushArgument();
+ catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
+ Drop();
+ }
+ catch_depth_dec();
+
+ return Fragment(try_body.entry, after_try);
}
+Fragment StreamingFlowGraphBuilder::BuildTryFinally() {
+ // Note on streaming:
+ // We only stream this TryFinally if we can stream everything inside it,
+ // so creating a "TryFinallyBlock" with a kernel binary offset instead of an
+ // AST node isn't a problem.
-Fragment StreamingFlowGraphBuilder::BuildSymbolLiteral() {
- SkipBytes(-1); // EvaluateExpression needs the tag.
- return Constant(constant_evaluator_.EvaluateExpression());
-}
+ InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
-Fragment StreamingFlowGraphBuilder::BuildThisExpression() {
- return LoadLocal(scopes()->this_variable);
-}
+ // There are 5 different cases where we need to execute the finally block:
+ //
+ // a) 1/2/3th case: Special control flow going out of `node->body()`:
+ //
+ // * [BreakStatement] transfers control to a [LabledStatement]
+ // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
+ // * [ReturnStatement] returns a value
+ //
+ // => All three cases will automatically append all finally blocks
+ // between the branching point and the destination (so we don't need to
+ // do anything here).
+ //
+ // b) 4th case: Translating the body resulted in an open fragment (i.e. body
+ // executes without any control flow out of it)
+ //
+ // => We are responsible for jumping out of the body to a new block (with
+ // different try index) and execute the finalizer.
+ //
+ // c) 5th case: An exception occurred inside the body.
+ //
+ // => We are responsible for catching it, executing the finally block and
+ // rethrowing the exception.
+ intptr_t try_handler_index = AllocateTryIndex();
+ Fragment try_body = TryCatch(try_handler_index);
+ JoinEntryInstr* after_try = BuildJoinEntry();
+ intptr_t offset = ReaderOffset();
+ SkipStatement(); // temporarily read body.
+ intptr_t finalizer_offset = ReaderOffset();
+ SetOffset(offset);
-Fragment StreamingFlowGraphBuilder::BuildRethrow() {
- TokenPosition position = ReadPosition();
- Fragment instructions = DebugStepCheck(position);
- instructions += LoadLocal(catch_block()->exception_var());
- instructions += PushArgument();
- instructions += LoadLocal(catch_block()->stack_trace_var());
- instructions += PushArgument();
- instructions += RethrowException(position, catch_block()->catch_try_index());
+ // Fill in the body of the try.
+ try_depth_inc();
+ {
+ TryFinallyBlock tfb(flow_graph_builder_, NULL, finalizer_offset);
+ TryCatchBlock tcb(flow_graph_builder_, try_handler_index);
+ try_body += BuildStatement(); // read body.
+ }
+ try_depth_dec();
- return instructions;
-}
+ if (try_body.is_open()) {
+ // Please note: The try index will be on level out of this block,
+ // thereby ensuring if there's an exception in the finally block we
+ // won't run it twice.
+ JoinEntryInstr* finally_entry = BuildJoinEntry();
+ try_body += Goto(finally_entry);
-Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral() {
- const dart::String& value = H.DartString(StringIndex(ReadUInt()));
- return Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)));
-}
+ Fragment finally_body(finally_entry);
+ finally_body += BuildStatement(); // read finalizer.
+ finally_body += Goto(after_try);
+ }
+ // Fill in the body of the catch.
+ catch_depth_inc();
+ const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
+ handler_types.SetAt(0, Object::dynamic_type());
+ // Note: rethrow will actually force mark the handler as needing a stacktrace.
+ Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index,
+ /* needs_stacktrace = */ false);
+ SetOffset(finalizer_offset);
+ finally_body += BuildStatement(); // read finalizer
+ if (finally_body.is_open()) {
+ finally_body += LoadLocal(CurrentException());
+ finally_body += PushArgument();
+ finally_body += LoadLocal(CurrentStackTrace());
+ finally_body += PushArgument();
+ finally_body +=
+ RethrowException(TokenPosition::kNoSource, try_handler_index);
+ Drop();
+ }
+ catch_depth_dec();
-Fragment StreamingFlowGraphBuilder::BuildStringLiteral() {
- StringIndex str_index(ReadUInt());
- return Constant(H.DartSymbol(str_index));
+ return Fragment(try_body.entry, after_try);
}
+Fragment StreamingFlowGraphBuilder::BuildYieldStatement() {
+ TokenPosition position = ReadPosition(); // read position.
+ uint8_t flags = ReadByte(); // read flags.
-Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload) {
- int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
- return IntConstant(value);
-}
+ ASSERT((flags & YieldStatement::kFlagNative) ==
+ YieldStatement::kFlagNative); // Must have been desugared.
+ // Setup yield/continue point:
+ //
+ // ...
+ // :await_jump_var = index;
+ // :await_ctx_var = :current_context_var
+ // return <expr>
+ //
+ // Continuation<index>:
+ // Drop(1)
+ // ...
+ //
+ // BuildGraphOfFunction will create a dispatch that jumps to
+ // Continuation<:await_jump_var> upon entry to the function.
+ //
+ Fragment instructions = IntConstant(yield_continuations().length() + 1);
+ instructions +=
+ StoreLocal(TokenPosition::kNoSource, scopes()->yield_jump_variable);
+ instructions += Drop();
+ instructions += LoadLocal(parsed_function()->current_context_var());
+ instructions +=
+ StoreLocal(TokenPosition::kNoSource, scopes()->yield_context_variable);
+ instructions += Drop();
+ instructions += BuildExpression(); // read expression.
+ instructions += Return(TokenPosition::kNoSource);
-Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative) {
- int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt()) : ReadUInt();
- return IntConstant(value);
-}
+ // Note: DropTempsInstr serves as an anchor instruction. It will not
+ // be linked into the resulting graph.
+ DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL);
+ yield_continuations().Add(YieldContinuation(anchor, CurrentTryIndex()));
+ Fragment continuation(instructions.entry, anchor);
-Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral() {
- SkipBytes(-1); // EvaluateExpression needs the tag.
- return Constant(constant_evaluator_.EvaluateExpression());
-}
+ if (parsed_function()->function().IsAsyncClosure() ||
+ parsed_function()->function().IsAsyncGenClosure()) {
+ // If function is async closure or async gen closure it takes three
+ // parameters where the second and the third are exception and stack_trace.
+ // Check if exception is non-null and rethrow it.
+ //
+ // :async_op([:result, :exception, :stack_trace]) {
+ // ...
+ // Continuation<index>:
+ // if (:exception != null) rethrow(:exception, :stack_trace);
+ // ...
+ // }
+ //
+ LocalScope* scope = parsed_function()->node_sequence()->scope();
+ LocalVariable* exception_var = scope->VariableAt(2);
+ LocalVariable* stack_trace_var = scope->VariableAt(3);
+ ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw());
+ ASSERT(stack_trace_var->name().raw() ==
+ Symbols::StackTraceParameter().raw());
+ TargetEntryInstr* no_error;
+ TargetEntryInstr* error;
-Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value) {
- return Constant(Bool::Get(value));
-}
+ continuation += LoadLocal(exception_var);
+ continuation += BranchIfNull(&no_error, &error);
+ Fragment rethrow(error);
+ rethrow += LoadLocal(exception_var);
+ rethrow += PushArgument();
+ rethrow += LoadLocal(stack_trace_var);
+ rethrow += PushArgument();
+ rethrow += RethrowException(position, CatchClauseNode::kInvalidTryIndex);
+ Drop();
-Fragment StreamingFlowGraphBuilder::BuildNullLiteral() {
- return Constant(Instance::ZoneHandle(Z, Instance::null()));
+
+ continuation = Fragment(continuation.entry, no_error);
+ }
+
+ return continuation;
}
+Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration(bool has_tag) {
+ intptr_t kernel_position = ReaderOffset() - (has_tag ? 1 : 0);
+ LocalVariable* variable = LookupVariable(kernel_position);
+
+ TokenPosition position = ReadPosition(); // read position.
+ TokenPosition equals_position = ReadPosition(); // read equals position.
+ word flags = ReadFlags(); // read flags.
+ dart::String& name = H.DartSymbol(ReadStringReference()); // read name index.
+ AbstractType& type = T.BuildType(); // read type.
+ Tag tag = ReadTag(); // read (first part of) initializer.
+
+ Fragment instructions;
+ if (tag == kNothing) {
+ instructions += NullConstant();
+ } else {
+ if ((flags & VariableDeclaration::kFlagConst) ==
+ VariableDeclaration::kFlagConst) {
+ // Const!
+ const Instance& constant_value = constant_evaluator_.EvaluateExpression(
+ ReaderOffset()); // read initializer form current position.
+ variable->SetConstValue(constant_value);
+ instructions += Constant(constant_value);
+ SkipExpression(); // skip initializer.
+ } else {
+ // Initializer
+ instructions += BuildExpression(); // read (actual) initializer.
+ instructions += CheckVariableTypeInCheckedMode(type, name);
+ }
+ }
+
+ // Use position of equal sign if it exists. If the equal sign does not exist
+ // use the position of the identifier.
+ TokenPosition debug_position = Utils::Maximum(position, equals_position);
+ if (NeedsDebugStepCheck(stack(), debug_position)) {
+ instructions = DebugStepCheck(debug_position) + instructions;
+ }
+ instructions += StoreLocal(position, variable);
+ instructions += Drop();
+ return instructions;
+}
} // namespace kernel
} // namespace dart
« no previous file with comments | « runtime/vm/kernel_binary_flowgraph.h ('k') | runtime/vm/kernel_reader.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698