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