| Index: runtime/vm/kernel_to_il.cc
|
| diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
|
| index 5b10f05fa41a64ffd304d0ef1c7eb76b1348fe06..f9f4e351199ec32af0e7bd1cf192853ce4f1f337 100644
|
| --- a/runtime/vm/kernel_to_il.cc
|
| +++ b/runtime/vm/kernel_to_il.cc
|
| @@ -30,40 +30,6 @@ namespace kernel {
|
| #define I Isolate::Current()
|
|
|
|
|
| -static void DiscoverEnclosingElements(Zone* zone,
|
| - const Function& function,
|
| - Function* outermost_function,
|
| - TreeNode** outermost_node,
|
| - Class** klass) {
|
| - // Find out if there is an enclosing kernel class (which will be used to
|
| - // resolve type parameters).
|
| - *outermost_function = function.raw();
|
| - while (outermost_function->parent_function() != Object::null()) {
|
| - *outermost_function = outermost_function->parent_function();
|
| - }
|
| - *outermost_node =
|
| - static_cast<TreeNode*>(outermost_function->kernel_function());
|
| - if (*outermost_node != NULL) {
|
| - TreeNode* parent = NULL;
|
| - if ((*outermost_node)->IsProcedure()) {
|
| - parent = Procedure::Cast(*outermost_node)->parent();
|
| - } else if ((*outermost_node)->IsConstructor()) {
|
| - parent = Constructor::Cast(*outermost_node)->parent();
|
| - } else if ((*outermost_node)->IsField()) {
|
| - parent = Field::Cast(*outermost_node)->parent();
|
| - }
|
| - if (parent != NULL && parent->IsClass()) *klass = Class::Cast(parent);
|
| - }
|
| -}
|
| -
|
| -
|
| -static bool IsStaticInitializer(const Function& function, Zone* zone) {
|
| - return (function.kind() == RawFunction::kImplicitStaticFinalGetter) &&
|
| - dart::String::Handle(zone, function.name())
|
| - .StartsWith(Symbols::InitPrefix());
|
| -}
|
| -
|
| -
|
| Fragment& Fragment::operator+=(const Fragment& other) {
|
| if (entry == NULL) {
|
| entry = other.entry;
|
| @@ -684,581 +650,9 @@ const Array& TranslationHelper::ArgumentNames(List<NamedExpression>* named) {
|
| return names;
|
| }
|
|
|
| -ConstantEvaluator::ConstantEvaluator(FlowGraphBuilder* builder,
|
| - Zone* zone,
|
| - TranslationHelper* h,
|
| - DartTypeTranslator* type_translator)
|
| - : builder_(builder),
|
| - isolate_(Isolate::Current()),
|
| - zone_(zone),
|
| - translation_helper_(*h),
|
| - type_translator_(*type_translator),
|
| - script_(Script::Handle(
|
| - zone,
|
| - builder == NULL ? Script::null()
|
| - : builder_->parsed_function_->function().script())),
|
| - result_(Instance::Handle(zone)) {}
|
| -
|
| -
|
| -Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) {
|
| - if (!GetCachedConstant(expression, &result_)) {
|
| - expression->AcceptExpressionVisitor(this);
|
| - CacheConstantValue(expression, result_);
|
| - }
|
| - // We return a new `ZoneHandle` here on purpose: The intermediate language
|
| - // instructions do not make a copy of the handle, so we do it.
|
| - return Instance::ZoneHandle(Z, result_.raw());
|
| -}
|
| -
|
| -
|
| -Object& ConstantEvaluator::EvaluateExpressionSafe(Expression* expression) {
|
| - LongJumpScope jump;
|
| - if (setjmp(*jump.Set()) == 0) {
|
| - return EvaluateExpression(expression);
|
| - } else {
|
| - Thread* thread = H.thread();
|
| - Error& error = Error::Handle(Z);
|
| - error = thread->sticky_error();
|
| - thread->clear_sticky_error();
|
| - return error;
|
| - }
|
| -}
|
| -
|
| -
|
| -Instance& ConstantEvaluator::EvaluateConstructorInvocation(
|
| - ConstructorInvocation* node) {
|
| - if (!GetCachedConstant(node, &result_)) {
|
| - VisitConstructorInvocation(node);
|
| - CacheConstantValue(node, result_);
|
| - }
|
| - // 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& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) {
|
| - if (!GetCachedConstant(node, &result_)) {
|
| - VisitListLiteral(node);
|
| - CacheConstantValue(node, result_);
|
| - }
|
| - // 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& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) {
|
| - if (!GetCachedConstant(node, &result_)) {
|
| - VisitMapLiteral(node);
|
| - CacheConstantValue(node, result_);
|
| - }
|
| - // 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());
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitBigintLiteral(BigintLiteral* node) {
|
| - const dart::String& value = H.DartString(node->value());
|
| - result_ = Integer::New(value, Heap::kOld);
|
| - result_ = H.Canonicalize(result_);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitBoolLiteral(BoolLiteral* node) {
|
| - result_ = Bool::Get(node->value()).raw();
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitDoubleLiteral(DoubleLiteral* node) {
|
| - result_ = Double::New(H.DartString(node->value()), Heap::kOld);
|
| - result_ = H.Canonicalize(result_);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitIntLiteral(IntLiteral* node) {
|
| - result_ = Integer::New(node->value(), Heap::kOld);
|
| - result_ = H.Canonicalize(result_);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitNullLiteral(NullLiteral* node) {
|
| - result_ = Instance::null();
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitStringLiteral(StringLiteral* node) {
|
| - result_ = H.DartSymbol(node->value()).raw();
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitTypeLiteral(TypeLiteral* node) {
|
| - const AbstractType& type = T.TranslateType(node->type());
|
| - if (type.IsMalformed()) {
|
| - H.ReportError("Malformed type literal in constant expression.");
|
| - }
|
| - result_ = type.raw();
|
| -}
|
| -
|
| -
|
| -RawObject* ConstantEvaluator::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 kTypeArgsLen = 0;
|
| - 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(kTypeArgsLen, 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);
|
| -}
|
| -
|
| -
|
| -bool ConstantEvaluator::GetCachedConstant(TreeNode* node, 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(node->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 ConstantEvaluator::CacheConstantValue(TreeNode* node,
|
| - 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(node->kernel_offset(), value);
|
| - script_.set_compile_time_constants(constants.Release());
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) {
|
| - const dart::String& symbol_value = H.DartSymbol(node->value());
|
| -
|
| - const dart::Class& symbol_class =
|
| - dart::Class::ZoneHandle(Z, I->object_store()->symbol_class());
|
| - ASSERT(!symbol_class.IsNull());
|
| - const Function& symbol_constructor = Function::ZoneHandle(
|
| - Z, symbol_class.LookupConstructor(Symbols::SymbolCtor()));
|
| - ASSERT(!symbol_constructor.IsNull());
|
| - result_ ^= EvaluateConstConstructorCall(
|
| - symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitListLiteral(ListLiteral* node) {
|
| - DartType* types[] = {node->type()};
|
| - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1);
|
| -
|
| - intptr_t length = node->expressions().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(node->expressions()[i]);
|
| - const_list.SetAt(i, expression);
|
| - }
|
| - const_list.MakeImmutable();
|
| - result_ = H.Canonicalize(const_list);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitMapLiteral(MapLiteral* node) {
|
| - DartType* types[] = {node->key_type(), node->value_type()};
|
| - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2);
|
| -
|
| - intptr_t length = node->entries().length();
|
| -
|
| - 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(node->entries()[i]->key()));
|
| - const_kv_array.SetAt(2 * i + 1,
|
| - EvaluateExpression(node->entries()[i]->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 ConstantEvaluator::VisitConstructorInvocation(
|
| - ConstructorInvocation* node) {
|
| - Arguments* kernel_arguments = node->arguments();
|
| -
|
| - const Function& constructor = Function::Handle(
|
| - Z, H.LookupConstructorByKernelConstructor(node->target()));
|
| - dart::Class& klass = dart::Class::Handle(Z, constructor.Owner());
|
| -
|
| - // Build the type arguments vector (if necessary).
|
| - const TypeArguments* type_arguments =
|
| - TranslateTypeArguments(constructor, &klass, kernel_arguments);
|
| -
|
| - // Prepare either the instance or the type argument vector for the constructor
|
| - // call.
|
| - Instance* receiver = NULL;
|
| - const TypeArguments* type_arguments_argument = NULL;
|
| - if (!constructor.IsFactory()) {
|
| - receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld));
|
| - if (type_arguments != NULL) {
|
| - receiver->SetTypeArguments(*type_arguments);
|
| - }
|
| - } else {
|
| - type_arguments_argument = type_arguments;
|
| - }
|
| -
|
| - const Object& result = RunFunction(constructor, kernel_arguments, 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 ConstantEvaluator::VisitMethodInvocation(MethodInvocation* node) {
|
| - Arguments* kernel_arguments = node->arguments();
|
| -
|
| - // Dart does not support generic methods yet.
|
| - ASSERT(kernel_arguments->types().length() == 0);
|
| -
|
| - const Instance& receiver = EvaluateExpression(node->receiver());
|
| - dart::Class& klass = dart::Class::Handle(
|
| - Z, isolate_->class_table()->At(receiver.GetClassId()));
|
| - ASSERT(!klass.IsNull());
|
| -
|
| - // Search the superclass chain for the selector.
|
| - Function& function = Function::Handle(Z);
|
| - const dart::String& method_name = H.DartMethodName(node->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());
|
| -
|
| - // Run the method and canonicalize the result.
|
| - const Object& result = RunFunction(function, kernel_arguments, &receiver);
|
| - result_ ^= result.raw();
|
| - result_ = H.Canonicalize(result_);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitStaticGet(StaticGet* node) {
|
| - NameIndex target = node->target();
|
| - if (H.IsField(target)) {
|
| - const dart::Field& field =
|
| - dart::Field::Handle(Z, H.LookupFieldByKernelField(target));
|
| - if (field.StaticValue() == Object::sentinel().raw() ||
|
| - field.StaticValue() == Object::transition_sentinel().raw()) {
|
| - field.EvaluateInitializer();
|
| - result_ = field.StaticValue();
|
| - result_ = H.Canonicalize(result_);
|
| - field.SetStaticValue(result_, true);
|
| - } else {
|
| - result_ = field.StaticValue();
|
| - }
|
| - } else if (H.IsProcedure(target)) {
|
| - const Function& function =
|
| - Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
|
| -
|
| - if (H.IsMethod(target)) {
|
| - Function& closure_function =
|
| - Function::ZoneHandle(Z, function.ImplicitClosureFunction());
|
| - closure_function.set_kernel_function(function.kernel_function());
|
| - result_ = closure_function.ImplicitStaticClosure();
|
| - result_ = H.Canonicalize(result_);
|
| - } else if (H.IsGetter(target)) {
|
| - UNIMPLEMENTED();
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitVariableGet(VariableGet* node) {
|
| - // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
|
| - // been executed already. It therefore must have a constant object associated
|
| - // with it.
|
| - LocalVariable* variable = builder_->LookupVariable(node->variable());
|
| - ASSERT(variable->IsConst());
|
| - result_ = variable->ConstValue()->raw();
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitLet(Let* node) {
|
| - VariableDeclaration* variable = node->variable();
|
| - LocalVariable* local = builder_->LookupVariable(variable);
|
| - local->SetConstValue(EvaluateExpression(variable->initializer()));
|
| - node->body()->AcceptExpressionVisitor(this);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitStaticInvocation(StaticInvocation* node) {
|
| - const Function& function = Function::ZoneHandle(
|
| - Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
|
| - dart::Class& klass = dart::Class::Handle(Z, function.Owner());
|
| -
|
| - // Build the type arguments vector (if necessary).
|
| - const TypeArguments* type_arguments =
|
| - TranslateTypeArguments(function, &klass, node->arguments());
|
| -
|
| - const Object& result =
|
| - RunFunction(function, node->arguments(), NULL, type_arguments);
|
| - result_ ^= result.raw();
|
| - result_ = H.Canonicalize(result_);
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) {
|
| - intptr_t length = node->expressions().length();
|
| -
|
| - bool all_string = true;
|
| - const Array& strings = Array::Handle(Z, Array::New(length));
|
| - for (intptr_t i = 0; i < length; i++) {
|
| - EvaluateExpression(node->expressions()[i]);
|
| - 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 ConstantEvaluator::VisitConditionalExpression(
|
| - ConditionalExpression* node) {
|
| - if (EvaluateBooleanExpression(node->condition())) {
|
| - EvaluateExpression(node->then());
|
| - } else {
|
| - EvaluateExpression(node->otherwise());
|
| - }
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) {
|
| - if (node->op() == LogicalExpression::kAnd) {
|
| - if (EvaluateBooleanExpression(node->left())) {
|
| - EvaluateBooleanExpression(node->right());
|
| - }
|
| - } else {
|
| - ASSERT(node->op() == LogicalExpression::kOr);
|
| - if (!EvaluateBooleanExpression(node->left())) {
|
| - EvaluateBooleanExpression(node->right());
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitNot(Not* node) {
|
| - result_ ^= Bool::Get(!EvaluateBooleanExpression(node->expression())).raw();
|
| -}
|
| -
|
| -
|
| -void ConstantEvaluator::VisitPropertyGet(PropertyGet* node) {
|
| - StringIndex string_index = node->name()->string_index();
|
| - if (H.StringEquals(string_index, "length")) {
|
| - node->receiver()->AcceptExpressionVisitor(this);
|
| - 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 {
|
| - VisitDefaultExpression(node);
|
| - }
|
| -}
|
| -
|
| -
|
| -const TypeArguments* ConstantEvaluator::TranslateTypeArguments(
|
| - const Function& target,
|
| - dart::Class* target_klass,
|
| - Arguments* kernel_arguments) {
|
| - List<DartType>& kernel_type_arguments = kernel_arguments->types();
|
| -
|
| - const TypeArguments* type_arguments = NULL;
|
| - if (kernel_type_arguments.length() > 0) {
|
| - type_arguments = &T.TranslateInstantiatedTypeArguments(
|
| - *target_klass, kernel_type_arguments.raw_array(),
|
| - kernel_type_arguments.length());
|
| -
|
| - 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;
|
| -}
|
| -
|
| -
|
| -const Object& ConstantEvaluator::RunFunction(const Function& function,
|
| - Arguments* kernel_arguments,
|
| - 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 + kernel_arguments->count()));
|
| - const Array& names =
|
| - Array::ZoneHandle(Z, Array::New(kernel_arguments->named().length()));
|
| - intptr_t pos = 0;
|
| - if (receiver != NULL) {
|
| - arguments.SetAt(pos++, *receiver);
|
| - }
|
| - if (type_args != NULL) {
|
| - arguments.SetAt(pos++, *type_args);
|
| - }
|
| - for (intptr_t i = 0; i < kernel_arguments->positional().length(); i++) {
|
| - EvaluateExpression(kernel_arguments->positional()[i]);
|
| - arguments.SetAt(pos++, result_);
|
| - }
|
| - for (intptr_t i = 0; i < kernel_arguments->named().length(); i++) {
|
| - NamedExpression* named_expression = kernel_arguments->named()[i];
|
| - EvaluateExpression(named_expression->expression());
|
| - arguments.SetAt(pos++, result_);
|
| - names.SetAt(i, H.DartSymbol(named_expression->name()));
|
| - }
|
| - return RunFunction(function, arguments, names);
|
| -}
|
| -
|
| -
|
| -const Object& ConstantEvaluator::RunFunction(const Function& function,
|
| - const Array& arguments,
|
| - const Array& names) {
|
| - const int kTypeArgsLen = 0; // Generic functions not yet supported.
|
| - const Array& args_descriptor = Array::Handle(
|
| - Z, ArgumentsDescriptor::New(kTypeArgsLen, arguments.Length(), names));
|
| - const Object& result = Object::Handle(
|
| - Z, DartEntry::InvokeFunction(function, arguments, args_descriptor));
|
| - if (result.IsError()) {
|
| - H.ReportError(Error::Cast(result), "error evaluating constant constructor");
|
| - }
|
| - return result;
|
| -}
|
| -
|
|
|
| FlowGraphBuilder::FlowGraphBuilder(
|
| - TreeNode* node,
|
| + intptr_t kernel_offset,
|
| ParsedFunction* parsed_function,
|
| const ZoneGrowableArray<const ICData*>& ic_data_array,
|
| ZoneGrowableArray<intptr_t>* context_level_array,
|
| @@ -1268,7 +662,7 @@ FlowGraphBuilder::FlowGraphBuilder(
|
| : translation_helper_(Thread::Current()),
|
| thread_(translation_helper_.thread()),
|
| zone_(translation_helper_.zone()),
|
| - node_(node),
|
| + kernel_offset_(kernel_offset),
|
| parsed_function_(parsed_function),
|
| osr_id_(osr_id),
|
| ic_data_array_(ic_data_array),
|
| @@ -1294,7 +688,6 @@ FlowGraphBuilder::FlowGraphBuilder(
|
| type_translator_(&translation_helper_,
|
| &active_class_,
|
| /* finalize= */ true),
|
| - constant_evaluator_(this, zone_, &translation_helper_, &type_translator_),
|
| streaming_flow_graph_builder_(NULL) {
|
| Script& script = Script::Handle(Z, parsed_function->function().script());
|
| H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets()));
|
| @@ -1349,9 +742,7 @@ Fragment FlowGraphBuilder::TranslateFinallyFinalizers(
|
| try_finally_block_->finalizer_kernel_offset();
|
| try_finally_block_ = try_finally_block_->outer();
|
| if (finalizer != NULL) {
|
| - // This will potentially have exceptional cases as described in
|
| - // [VisitTryFinally] and will handle them.
|
| - instructions += TranslateStatement(finalizer);
|
| + UNREACHABLE();
|
| } else {
|
| instructions += streaming_flow_graph_builder_->BuildStatementAt(
|
| finalizer_kernel_offset);
|
| @@ -1378,11 +769,6 @@ Fragment FlowGraphBuilder::TranslateFinallyFinalizers(
|
| }
|
|
|
|
|
| -Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) {
|
| - return EnterScope(node->kernel_offset(), new_context);
|
| -}
|
| -
|
| -
|
| Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset,
|
| bool* new_context) {
|
| Fragment instructions;
|
| @@ -1399,11 +785,6 @@ Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset,
|
| }
|
|
|
|
|
| -Fragment FlowGraphBuilder::ExitScope(TreeNode* node) {
|
| - return ExitScope(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
|
| Fragment instructions;
|
| const intptr_t context_size =
|
| @@ -1474,8 +855,7 @@ Fragment FlowGraphBuilder::LoadInstantiatorTypeArguments() {
|
| #endif
|
| instructions += LoadLocal(scopes_->type_arguments_variable);
|
| } else if (scopes_->this_variable != NULL &&
|
| - active_class_.kernel_class != NULL &&
|
| - active_class_.kernel_class->type_parameters().length() > 0) {
|
| + active_class_.class_type_parameters > 0) {
|
| ASSERT(!parsed_function_->function().IsFactory());
|
| intptr_t type_arguments_field_offset =
|
| active_class_.klass->type_arguments_field_offset();
|
| @@ -2410,431 +1790,48 @@ FlowGraph* FlowGraphBuilder::BuildGraph() {
|
|
|
| if (function.IsConstructorClosureFunction()) return NULL;
|
|
|
| - TreeNode* library_node = node_;
|
| - if (node_ != NULL) {
|
| - const Function* parent = &function;
|
| - while (true) {
|
| - library_node = static_cast<kernel::TreeNode*>(parent->kernel_function());
|
| - while (library_node != NULL && !library_node->IsLibrary()) {
|
| - if (library_node->IsMember()) {
|
| - library_node = Member::Cast(library_node)->parent();
|
| - } else if (library_node->IsClass()) {
|
| - library_node = Class::Cast(library_node)->parent();
|
| - break;
|
| - } else {
|
| - library_node = NULL;
|
| - break;
|
| - }
|
| - }
|
| - if (library_node != NULL) break;
|
| - parent = &Function::Handle(parent->parent_function());
|
| - }
|
| - }
|
| if (streaming_flow_graph_builder_ != NULL) {
|
| delete streaming_flow_graph_builder_;
|
| streaming_flow_graph_builder_ = NULL;
|
| }
|
| - if (library_node != NULL && library_node->IsLibrary()) {
|
| - Library* library = Library::Cast(library_node);
|
| - streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder(
|
| - this, library->kernel_data(), library->kernel_data_size());
|
| - }
|
|
|
| - dart::Class& klass =
|
| - dart::Class::Handle(zone_, parsed_function_->function().Owner());
|
| -
|
| - Function& outermost_function = Function::Handle(Z);
|
| - TreeNode* outermost_node = NULL;
|
| - Class* kernel_class = NULL;
|
| - DiscoverEnclosingElements(Z, function, &outermost_function, &outermost_node,
|
| - &kernel_class);
|
| -
|
| - // Mark that we are using [klass]/[kernell_klass] as active class. Resolving
|
| - // of type parameters will get resolved via [kernell_klass] unless we are
|
| - // nested inside a static factory in which case we will use [member].
|
| - ActiveClassScope active_class_scope(&active_class_, kernel_class, &klass);
|
| - Member* member = ((outermost_node != NULL) && outermost_node->IsMember())
|
| - ? Member::Cast(outermost_node)
|
| - : NULL;
|
| - ActiveMemberScope active_member(&active_class_, member);
|
| -
|
| - // The IR builder will create its own local variables and scopes, and it
|
| - // will not need an AST. The code generator will assume that there is a
|
| - // local variable stack slot allocated for the current context and (I
|
| - // think) that the runtime will expect it to be at a fixed offset which
|
| - // requires allocating an unused expression temporary variable.
|
| - scopes_ = parsed_function_->EnsureKernelScopes();
|
| -
|
| - switch (function.kind()) {
|
| - case RawFunction::kClosureFunction:
|
| - case RawFunction::kRegularFunction:
|
| - case RawFunction::kGetterFunction:
|
| - case RawFunction::kSetterFunction: {
|
| - FunctionNode* kernel_function = node_->IsProcedure()
|
| - ? Procedure::Cast(node_)->function()
|
| - : FunctionNode::Cast(node_);
|
| - return function.IsImplicitClosureFunction()
|
| - ? BuildGraphOfImplicitClosureFunction(kernel_function,
|
| - function)
|
| - : BuildGraphOfFunction(kernel_function);
|
| - }
|
| - case RawFunction::kConstructor: {
|
| - bool is_factory = function.IsFactory();
|
| - if (is_factory) {
|
| - Procedure* procedure = Procedure::Cast(node_);
|
| - FunctionNode* function = procedure->function();
|
| - return BuildGraphOfFunction(function, NULL);
|
| - } else {
|
| - Constructor* constructor = Constructor::Cast(node_);
|
| - FunctionNode* function = constructor->function();
|
| - return BuildGraphOfFunction(function, constructor);
|
| - }
|
| - }
|
| - case RawFunction::kImplicitGetter:
|
| - case RawFunction::kImplicitStaticFinalGetter:
|
| - case RawFunction::kImplicitSetter: {
|
| - Field* field = Field::Cast(node_);
|
| - return IsStaticInitializer(function, Z)
|
| - ? BuildGraphOfStaticFieldInitializer(field)
|
| - : BuildGraphOfFieldAccessor(field, scopes_->setter_value);
|
| - }
|
| - case RawFunction::kMethodExtractor:
|
| - return BuildGraphOfMethodExtractor(function);
|
| - case RawFunction::kNoSuchMethodDispatcher:
|
| - return BuildGraphOfNoSuchMethodDispatcher(function);
|
| - case RawFunction::kInvokeFieldDispatcher:
|
| - return BuildGraphOfInvokeFieldDispatcher(function);
|
| - case RawFunction::kSignatureFunction:
|
| - case RawFunction::kIrregexpFunction:
|
| - break;
|
| - }
|
| - UNREACHABLE();
|
| - return NULL;
|
| -}
|
| + Script& script = Script::Handle(Z, function.script());
|
| + streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder(
|
| + this, script.kernel_data(), script.kernel_data_size());
|
|
|
| + return streaming_flow_graph_builder_->BuildGraph(kernel_offset_);
|
| +}
|
|
|
| -FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function,
|
| - Constructor* constructor) {
|
| - const Function& dart_function = parsed_function_->function();
|
| - TargetEntryInstr* normal_entry = BuildTargetEntry();
|
| - graph_entry_ =
|
| - new (Z) GraphEntryInstr(*parsed_function_, normal_entry, osr_id_);
|
|
|
| - SetupDefaultParameterValues(function);
|
| +Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset,
|
| + const Function& function) {
|
| + ASSERT(function.is_native());
|
| + // We explicitly build the graph for native functions in the same way that the
|
| + // from-source backend does. We should find a way to have a single component
|
| + // to build these graphs so that this code is not duplicated.
|
|
|
| Fragment body;
|
| - if (!dart_function.is_native()) body += CheckStackOverflowInPrologue();
|
| - intptr_t context_size =
|
| - parsed_function_->node_sequence()->scope()->num_context_variables();
|
| - if (context_size > 0) {
|
| - body += PushContext(context_size);
|
| - LocalVariable* context = MakeTemporary();
|
| -
|
| - // Copy captured parameters from the stack into the context.
|
| - LocalScope* scope = parsed_function_->node_sequence()->scope();
|
| - intptr_t parameter_count = dart_function.NumParameters();
|
| - intptr_t parameter_index = parsed_function_->first_parameter_index();
|
| - for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) {
|
| - LocalVariable* variable = scope->VariableAt(i);
|
| - if (variable->is_captured()) {
|
| - // There is no LocalVariable describing the on-stack parameter so
|
| - // create one directly and use the same type.
|
| - LocalVariable* parameter = new (Z)
|
| - LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| - Symbols::TempParam(), variable->type());
|
| - parameter->set_index(parameter_index);
|
| - // Mark the stack variable so it will be ignored by the code for
|
| - // try/catch.
|
| - parameter->set_is_captured_parameter(true);
|
| -
|
| - // Copy the parameter from the stack to the context. Overwrite it
|
| - // with a null constant on the stack so the original value is
|
| - // eligible for garbage collection.
|
| - body += LoadLocal(context);
|
| - body += LoadLocal(parameter);
|
| - body += StoreInstanceField(TokenPosition::kNoSource,
|
| - Context::variable_offset(variable->index()));
|
| - body += NullConstant();
|
| - body += StoreLocal(TokenPosition::kNoSource, parameter);
|
| - body += Drop();
|
| - }
|
| - }
|
| - body += Drop(); // The context.
|
| - }
|
| - if (constructor != NULL) {
|
| - // TODO(27590): Currently the [VariableDeclaration]s from the
|
| - // initializers will be visible inside the entire body of the constructor.
|
| - // We should make a separate scope for them.
|
| - Class* kernel_class = Class::Cast(constructor->parent());
|
| - body += TranslateInitializers(kernel_class, &constructor->initializers());
|
| - }
|
| -
|
| - // The specification defines the result of `a == b` to be:
|
| - //
|
| - // a) if either side is `null` then the result is `identical(a, b)`.
|
| - // b) else the result is `a.operator==(b)`
|
| - //
|
| - // For user-defined implementations of `operator==` we need therefore
|
| - // implement the handling of a).
|
| - //
|
| - // The default `operator==` implementation in `Object` is implemented in terms
|
| - // of identical (which we assume here!) which means that case a) is actually
|
| - // included in b). So we just use the normal implementation in the body.
|
| - if ((dart_function.NumParameters() == 2) &&
|
| - (dart_function.name() == Symbols::EqualOperator().raw()) &&
|
| - (dart_function.Owner() != I->object_store()->object_class())) {
|
| - LocalVariable* parameter =
|
| - LookupVariable(function->positional_parameters()[0]);
|
| -
|
| - TargetEntryInstr* null_entry;
|
| - TargetEntryInstr* non_null_entry;
|
| -
|
| - body += LoadLocal(parameter);
|
| - body += BranchIfNull(&null_entry, &non_null_entry);
|
| -
|
| - // The argument was `null` and the receiver is not the null class (we only
|
| - // go into this branch for user-defined == operators) so we can return
|
| - // false.
|
| - Fragment null_fragment(null_entry);
|
| - null_fragment += Constant(Bool::False());
|
| - null_fragment += Return(dart_function.end_token_pos());
|
| -
|
| - body = Fragment(body.entry, non_null_entry);
|
| - }
|
| -
|
| - // If we run in checked mode, we have to check the type of the passed
|
| - // arguments.
|
| - if (I->type_checks()) {
|
| - List<VariableDeclaration>& positional = function->positional_parameters();
|
| - List<VariableDeclaration>& named = function->named_parameters();
|
| -
|
| - for (intptr_t i = 0; i < positional.length(); i++) {
|
| - VariableDeclaration* variable = positional[i];
|
| - body += LoadLocal(LookupVariable(variable));
|
| - body += CheckVariableTypeInCheckedMode(variable);
|
| - body += Drop();
|
| - }
|
| - for (intptr_t i = 0; i < named.length(); i++) {
|
| - VariableDeclaration* variable = named[i];
|
| - body += LoadLocal(LookupVariable(variable));
|
| - body += CheckVariableTypeInCheckedMode(variable);
|
| - body += Drop();
|
| - }
|
| - }
|
| -
|
| - if (FLAG_causal_async_stacks &&
|
| - (dart_function.IsAsyncFunction() || dart_function.IsAsyncGenerator())) {
|
| - LocalScope* scope = parsed_function_->node_sequence()->scope();
|
| - // :async_stack_trace = _asyncStackTraceHelper(:async_op);
|
| - const dart::Library& async_lib =
|
| - dart::Library::Handle(dart::Library::AsyncLibrary());
|
| - const Function& target = Function::ZoneHandle(
|
| - Z,
|
| - async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper()));
|
| - ASSERT(!target.IsNull());
|
| -
|
| - // TODO(johnmccutchan): Why does this have the null value?
|
| - LocalVariable* async_op =
|
| - scope->child()->LookupVariable(Symbols::AsyncOperation(), false);
|
| - ASSERT(async_op != NULL);
|
| - ASSERT(async_op->is_captured());
|
| - body += LoadLocal(async_op);
|
| - body += PushArgument();
|
| - body += StaticCall(TokenPosition::kNoSource, target, 1);
|
| - LocalVariable* async_stack_trace_var =
|
| - scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
|
| - ASSERT(async_stack_trace_var != NULL);
|
| - body += StoreLocal(TokenPosition::kNoSource, async_stack_trace_var);
|
| - body += Drop();
|
| - }
|
| -
|
| - if (dart_function.is_native()) {
|
| - body += NativeFunctionBody(function, dart_function);
|
| - } else if (function->body() != NULL) {
|
| - body += TranslateStatement(function->body());
|
| - }
|
| - if (body.is_open()) {
|
| - body += NullConstant();
|
| - body += Return(dart_function.end_token_pos());
|
| - }
|
| -
|
| - // If functions body contains any yield points build switch statement that
|
| - // selects a continuation point based on the value of :await_jump_var.
|
| - if (!yield_continuations_.is_empty()) {
|
| - // The code we are building will be executed right after we enter
|
| - // the function and before any nested contexts are allocated.
|
| - // Reset current context_depth_ to match this.
|
| - const intptr_t current_context_depth = context_depth_;
|
| - context_depth_ = scopes_->yield_jump_variable->owner()->context_level();
|
| -
|
| - // Prepend an entry corresponding to normal entry to the function.
|
| - yield_continuations_.InsertAt(
|
| - 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL),
|
| - CatchClauseNode::kInvalidTryIndex));
|
| - yield_continuations_[0].entry->LinkTo(body.entry);
|
| -
|
| - // Build a switch statement.
|
| - Fragment dispatch;
|
| -
|
| - // Load :await_jump_var into a temporary.
|
| - dispatch += LoadLocal(scopes_->yield_jump_variable);
|
| - dispatch += StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable);
|
| - dispatch += Drop();
|
| -
|
| - BlockEntryInstr* block = NULL;
|
| - for (intptr_t i = 0; i < yield_continuations_.length(); i++) {
|
| - if (i == 1) {
|
| - // This is not a normal entry but a resumption. Restore
|
| - // :current_context_var from :await_ctx_var.
|
| - // Note: after this point context_depth_ does not match current context
|
| - // depth so we should not access any local variables anymore.
|
| - dispatch += LoadLocal(scopes_->yield_context_variable);
|
| - dispatch += StoreLocal(TokenPosition::kNoSource,
|
| - parsed_function_->current_context_var());
|
| - dispatch += Drop();
|
| - }
|
| - if (i == (yield_continuations_.length() - 1)) {
|
| - // We reached the last possility, no need to build more ifs.
|
| - // Continue to the last continuation.
|
| - // Note: continuations start with nop DropTemps instruction
|
| - // which acts like an anchor, so we need to skip it.
|
| - block->set_try_index(yield_continuations_[i].try_index);
|
| - dispatch <<= yield_continuations_[i].entry->next();
|
| - break;
|
| - }
|
| -
|
| - // Build comparison:
|
| - //
|
| - // if (:await_ctx_var == i) {
|
| - // -> yield_continuations_[i]
|
| - // } else ...
|
| - //
|
| - TargetEntryInstr* then;
|
| - TargetEntryInstr* otherwise;
|
| - dispatch += LoadLocal(scopes_->switch_variable);
|
| - dispatch += IntConstant(i);
|
| - dispatch += BranchIfStrictEqual(&then, &otherwise);
|
| -
|
| - // True branch is linked to appropriate continuation point.
|
| - // Note: continuations start with nop DropTemps instruction
|
| - // which acts like an anchor, so we need to skip it.
|
| - then->LinkTo(yield_continuations_[i].entry->next());
|
| - then->set_try_index(yield_continuations_[i].try_index);
|
| - // False branch will contain the next comparison.
|
| - dispatch = Fragment(dispatch.entry, otherwise);
|
| - block = otherwise;
|
| - }
|
| - body = dispatch;
|
| -
|
| - context_depth_ = current_context_depth;
|
| - }
|
| -
|
| - if (FLAG_causal_async_stacks &&
|
| - (dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) {
|
| - // The code we are building will be executed right after we enter
|
| - // the function and before any nested contexts are allocated.
|
| - // Reset current context_depth_ to match this.
|
| - const intptr_t current_context_depth = context_depth_;
|
| - context_depth_ = scopes_->yield_jump_variable->owner()->context_level();
|
| -
|
| - Fragment instructions;
|
| - LocalScope* scope = parsed_function_->node_sequence()->scope();
|
| -
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, I->object_store()->async_set_thread_stack_trace());
|
| - ASSERT(!target.IsNull());
|
| -
|
| - // Fetch and load :async_stack_trace
|
| - LocalVariable* async_stack_trace_var =
|
| - scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
|
| - ASSERT((async_stack_trace_var != NULL) &&
|
| - async_stack_trace_var->is_captured());
|
| - instructions += LoadLocal(async_stack_trace_var);
|
| - instructions += PushArgument();
|
| -
|
| - // Call _asyncSetThreadStackTrace
|
| - instructions += StaticCall(TokenPosition::kNoSource, target, 1);
|
| - instructions += Drop();
|
| -
|
| - // TODO(29737): This sequence should be generated in order.
|
| - body = instructions + body;
|
| - context_depth_ = current_context_depth;
|
| - }
|
| -
|
| - if (NeedsDebugStepCheck(dart_function, function->position())) {
|
| - const intptr_t current_context_depth = context_depth_;
|
| - context_depth_ = 0;
|
| -
|
| - // If a switch was added above: Start the switch by injecting a debuggable
|
| - // safepoint so stepping over an await works.
|
| - // If not, still start the body with a debuggable safepoint to ensure
|
| - // breaking on a method always happens, even if there are no
|
| - // assignments/calls/runtimecalls in the first basic block.
|
| - // Place this check at the last parameter to ensure parameters
|
| - // are in scope in the debugger at method entry.
|
| - const int num_params = dart_function.NumParameters();
|
| - TokenPosition check_pos = TokenPosition::kNoSource;
|
| - if (num_params > 0) {
|
| - LocalScope* scope = parsed_function_->node_sequence()->scope();
|
| - const LocalVariable& parameter = *scope->VariableAt(num_params - 1);
|
| - check_pos = parameter.token_pos();
|
| - }
|
| - if (!check_pos.IsDebugPause()) {
|
| - // No parameters or synthetic parameters.
|
| - check_pos = function->position();
|
| - ASSERT(check_pos.IsDebugPause());
|
| - }
|
| -
|
| - // TODO(29737): This sequence should be generated in order.
|
| - body = DebugStepCheck(check_pos) + body;
|
| - context_depth_ = current_context_depth;
|
| - }
|
| -
|
| - normal_entry->LinkTo(body.entry);
|
| -
|
| - // When compiling for OSR, use a depth first search to prune instructions
|
| - // unreachable from the OSR entry. Catch entries are always considered
|
| - // reachable, even if they become unreachable after OSR.
|
| - if (osr_id_ != Compiler::kNoOSRDeoptId) {
|
| - BitVector* block_marks = new (Z) BitVector(Z, next_block_id_);
|
| - bool found = graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_,
|
| - block_marks);
|
| - ASSERT(found);
|
| - }
|
| - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| - const Function& function) {
|
| - ASSERT(function.is_native());
|
| - // We explicitly build the graph for native functions in the same way that the
|
| - // from-source backend does. We should find a way to have a single component
|
| - // to build these graphs so that this code is not duplicated.
|
| -
|
| - Fragment body;
|
| - MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
|
| - switch (kind) {
|
| - case MethodRecognizer::kObjectEquals:
|
| - body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| - body += StrictCompare(Token::kEQ_STRICT);
|
| - break;
|
| - case MethodRecognizer::kStringBaseLength:
|
| - case MethodRecognizer::kStringBaseIsEmpty:
|
| - // Depending on FLAG_support_externalizable_strings, treat string length
|
| - // loads as mutable so that the class check that precedes them will not be
|
| - // hoisted. This is unsafe because string externalization can change the
|
| - // class.
|
| - body += LoadLocal(scopes_->this_variable);
|
| - body += LoadNativeField(MethodRecognizer::kStringBaseLength,
|
| - dart::String::length_offset(),
|
| - Type::ZoneHandle(Z, Type::SmiType()), kSmiCid,
|
| - !FLAG_support_externalizable_strings);
|
| - if (kind == MethodRecognizer::kStringBaseIsEmpty) {
|
| - body += IntConstant(0);
|
| - body += StrictCompare(Token::kEQ_STRICT);
|
| + MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
|
| + switch (kind) {
|
| + case MethodRecognizer::kObjectEquals:
|
| + body += LoadLocal(scopes_->this_variable);
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| + body += StrictCompare(Token::kEQ_STRICT);
|
| + break;
|
| + case MethodRecognizer::kStringBaseLength:
|
| + case MethodRecognizer::kStringBaseIsEmpty:
|
| + // Depending on FLAG_support_externalizable_strings, treat string length
|
| + // loads as mutable so that the class check that precedes them will not be
|
| + // hoisted. This is unsafe because string externalization can change the
|
| + // class.
|
| + body += LoadLocal(scopes_->this_variable);
|
| + body += LoadNativeField(MethodRecognizer::kStringBaseLength,
|
| + dart::String::length_offset(),
|
| + Type::ZoneHandle(Z, Type::SmiType()), kSmiCid,
|
| + !FLAG_support_externalizable_strings);
|
| + if (kind == MethodRecognizer::kStringBaseIsEmpty) {
|
| + body += IntConstant(0);
|
| + body += StrictCompare(Token::kEQ_STRICT);
|
| }
|
| break;
|
| case MethodRecognizer::kGrowableArrayLength:
|
| @@ -2856,8 +1853,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true);
|
| break;
|
| case MethodRecognizer::kClassIDgetID:
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += LoadClassId();
|
| break;
|
| case MethodRecognizer::kGrowableArrayCapacity:
|
| @@ -2869,8 +1865,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| break;
|
| case MethodRecognizer::kObjectArrayAllocate:
|
| body += LoadLocal(scopes_->type_arguments_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += CreateArray();
|
| break;
|
| case MethodRecognizer::kBigint_getDigits:
|
| @@ -2890,8 +1885,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| break;
|
| case MethodRecognizer::kLinkedHashMap_setIndex:
|
| body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += StoreInstanceField(TokenPosition::kNoSource,
|
| LinkedHashMap::index_offset());
|
| body += NullConstant();
|
| @@ -2903,8 +1897,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| break;
|
| case MethodRecognizer::kLinkedHashMap_setData:
|
| body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += StoreInstanceField(TokenPosition::kNoSource,
|
| LinkedHashMap::data_offset());
|
| body += NullConstant();
|
| @@ -2916,8 +1909,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| break;
|
| case MethodRecognizer::kLinkedHashMap_setHashMask:
|
| body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += StoreInstanceField(TokenPosition::kNoSource,
|
| LinkedHashMap::hash_mask_offset(),
|
| kNoStoreBarrier);
|
| @@ -2930,8 +1922,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| break;
|
| case MethodRecognizer::kLinkedHashMap_setUsedData:
|
| body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += StoreInstanceField(TokenPosition::kNoSource,
|
| LinkedHashMap::used_data_offset(),
|
| kNoStoreBarrier);
|
| @@ -2944,8 +1935,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| break;
|
| case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
|
| body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(
|
| - LookupVariable(kernel_function->positional_parameters()[0]));
|
| + body += LoadLocal(LookupVariable(first_positional_offset));
|
| body += StoreInstanceField(TokenPosition::kNoSource,
|
| LinkedHashMap::deleted_keys_offset(),
|
| kNoStoreBarrier);
|
| @@ -2966,82 +1956,6 @@ Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
|
| }
|
|
|
|
|
| -FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor(
|
| - Field* kernel_field,
|
| - LocalVariable* setter_value) {
|
| - const Function& function = parsed_function_->function();
|
| -
|
| - bool is_setter = function.IsImplicitSetterFunction();
|
| - bool is_method = !function.IsStaticFunction();
|
| - dart::Field& field = dart::Field::ZoneHandle(
|
| - Z, H.LookupFieldByKernelField(kernel_field->canonical_name()));
|
| -
|
| - TargetEntryInstr* normal_entry = BuildTargetEntry();
|
| - graph_entry_ = new (Z)
|
| - GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
|
| -
|
| - Fragment body(normal_entry);
|
| - if (is_setter) {
|
| - if (is_method) {
|
| - body += LoadLocal(scopes_->this_variable);
|
| - body += LoadLocal(setter_value);
|
| - body += StoreInstanceFieldGuarded(field, false);
|
| - } else {
|
| - body += LoadLocal(setter_value);
|
| - body += StoreStaticField(TokenPosition::kNoSource, field);
|
| - }
|
| - body += NullConstant();
|
| - } else if (is_method) {
|
| - body += LoadLocal(scopes_->this_variable);
|
| - body += LoadField(field);
|
| - } else if (field.is_const()) {
|
| - // If the parser needs to know the value of an uninitialized constant field
|
| - // it will set the value to the transition sentinel (used to detect circular
|
| - // initialization) and then call the implicit getter. Thus, the getter
|
| - // cannot contain the InitStaticField instruction that normal static getters
|
| - // contain because it would detect spurious circular initialization when it
|
| - // checks for the transition sentinel.
|
| - Expression* initializer = kernel_field->initializer();
|
| - ASSERT(initializer != NULL);
|
| - body += Constant(constant_evaluator_.EvaluateExpression(initializer));
|
| - } else {
|
| - // The field always has an initializer because static fields without
|
| - // initializers are initialized eagerly and do not have implicit getters.
|
| - ASSERT(field.has_initializer());
|
| - body += Constant(field);
|
| - body += InitStaticField(field);
|
| - body += Constant(field);
|
| - body += LoadStaticField();
|
| - }
|
| - body += Return(TokenPosition::kNoSource);
|
| -
|
| - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
|
| -}
|
| -
|
| -
|
| -FlowGraph* FlowGraphBuilder::BuildGraphOfStaticFieldInitializer(
|
| - Field* kernel_field) {
|
| - ASSERT(kernel_field->IsStatic());
|
| -
|
| - Expression* initializer = kernel_field->initializer();
|
| -
|
| - TargetEntryInstr* normal_entry = BuildTargetEntry();
|
| - graph_entry_ = new (Z)
|
| - GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
|
| -
|
| - Fragment body(normal_entry);
|
| - body += CheckStackOverflowInPrologue();
|
| - if (kernel_field->IsConst()) {
|
| - body += Constant(constant_evaluator_.EvaluateExpression(initializer));
|
| - } else {
|
| - body += TranslateExpression(initializer);
|
| - }
|
| - body += Return(TokenPosition::kNoSource);
|
| -
|
| - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
|
| -}
|
| -
|
| -
|
| Fragment FlowGraphBuilder::BuildImplicitClosureCreation(
|
| const Function& target) {
|
| Fragment fragment;
|
| @@ -3100,19 +2014,6 @@ Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field,
|
| }
|
|
|
|
|
| -Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
|
| - VariableDeclaration* variable) {
|
| - if (I->type_checks()) {
|
| - const AbstractType& dst_type = T.TranslateType(variable->type());
|
| - if (dst_type.IsMalformed()) {
|
| - return ThrowTypeError();
|
| - }
|
| - return CheckAssignableInCheckedMode(dst_type,
|
| - H.DartSymbol(variable->name()));
|
| - }
|
| - return Fragment();
|
| -}
|
| -
|
| Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
|
| const AbstractType& dst_type,
|
| const dart::String& name_symbol) {
|
| @@ -3257,58 +2158,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
|
| }
|
|
|
|
|
| -FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
|
| - FunctionNode* kernel_function,
|
| - const Function& function) {
|
| - const Function& target = Function::ZoneHandle(Z, function.parent_function());
|
| -
|
| - TargetEntryInstr* normal_entry = BuildTargetEntry();
|
| - graph_entry_ = new (Z)
|
| - GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
|
| - SetupDefaultParameterValues(kernel_function);
|
| -
|
| - Fragment body(normal_entry);
|
| - body += CheckStackOverflowInPrologue();
|
| -
|
| - // Load all the arguments.
|
| - if (!target.is_static()) {
|
| - // The context has a fixed shape: a single variable which is the
|
| - // closed-over receiver.
|
| - body += LoadLocal(parsed_function_->current_context_var());
|
| - body += LoadField(Context::variable_offset(0));
|
| - body += PushArgument();
|
| - }
|
| - intptr_t positional_argument_count =
|
| - kernel_function->positional_parameters().length();
|
| - for (intptr_t i = 0; i < positional_argument_count; i++) {
|
| - body +=
|
| - LoadLocal(LookupVariable(kernel_function->positional_parameters()[i]));
|
| - body += PushArgument();
|
| - }
|
| - intptr_t named_argument_count = kernel_function->named_parameters().length();
|
| - Array& argument_names = Array::ZoneHandle(Z);
|
| - if (named_argument_count > 0) {
|
| - argument_names = Array::New(named_argument_count);
|
| - for (intptr_t i = 0; i < named_argument_count; i++) {
|
| - VariableDeclaration* variable = kernel_function->named_parameters()[i];
|
| - body += LoadLocal(LookupVariable(variable));
|
| - body += PushArgument();
|
| - argument_names.SetAt(i, H.DartSymbol(variable->name()));
|
| - }
|
| - }
|
| - // Forward them to the target.
|
| - intptr_t argument_count = positional_argument_count + named_argument_count;
|
| - if (!target.is_static()) ++argument_count;
|
| - body += StaticCall(TokenPosition::kNoSource, target, argument_count,
|
| - argument_names);
|
| -
|
| - // Return the result.
|
| - body += Return(kernel_function->end_position());
|
| -
|
| - return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
|
| -}
|
| -
|
| -
|
| FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
|
| const Function& function) {
|
| // This function is specialized for a receiver class, a method name, and
|
| @@ -3500,47 +2349,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
|
| }
|
|
|
|
|
| -void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) {
|
| - intptr_t num_optional_parameters =
|
| - parsed_function_->function().NumOptionalParameters();
|
| - if (num_optional_parameters > 0) {
|
| - ZoneGrowableArray<const Instance*>* default_values =
|
| - new ZoneGrowableArray<const Instance*>(Z, num_optional_parameters);
|
| -
|
| - if (parsed_function_->function().HasOptionalNamedParameters()) {
|
| - ASSERT(!parsed_function_->function().HasOptionalPositionalParameters());
|
| - for (intptr_t i = 0; i < num_optional_parameters; i++) {
|
| - VariableDeclaration* variable = function->named_parameters()[i];
|
| - Instance* default_value;
|
| - if (variable->initializer() != NULL) {
|
| - default_value =
|
| - &constant_evaluator_.EvaluateExpression(variable->initializer());
|
| - } else {
|
| - default_value = &Instance::ZoneHandle(Z, Instance::null());
|
| - }
|
| - default_values->Add(default_value);
|
| - }
|
| - } else {
|
| - ASSERT(parsed_function_->function().HasOptionalPositionalParameters());
|
| - intptr_t required = function->required_parameter_count();
|
| - for (intptr_t i = 0; i < num_optional_parameters; i++) {
|
| - VariableDeclaration* variable =
|
| - function->positional_parameters()[required + i];
|
| - Instance* default_value;
|
| - if (variable->initializer() != NULL) {
|
| - default_value =
|
| - &constant_evaluator_.EvaluateExpression(variable->initializer());
|
| - } else {
|
| - default_value = &Instance::ZoneHandle(Z, Instance::null());
|
| - }
|
| - default_values->Add(default_value);
|
| - }
|
| - }
|
| - parsed_function_->set_default_parameter_values(default_values);
|
| - }
|
| -}
|
| -
|
| -
|
| TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() {
|
| return new (Z)
|
| TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
|
| @@ -3557,171 +2365,6 @@ JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() {
|
| JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
|
| }
|
|
|
| -
|
| -Fragment FlowGraphBuilder::TranslateFieldInitializer(NameIndex canonical_name,
|
| - Expression* init) {
|
| - dart::Field& field =
|
| - dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name));
|
| - if (init->IsNullLiteral()) {
|
| - field.RecordStore(Object::null_object());
|
| - return Fragment();
|
| - }
|
| - Fragment instructions;
|
| - instructions += LoadLocal(scopes_->this_variable);
|
| - instructions += TranslateExpression(init);
|
| - instructions += StoreInstanceFieldGuarded(field, true);
|
| - return instructions;
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::TranslateInitializers(
|
| - Class* kernel_class,
|
| - List<Initializer>* initializers) {
|
| - Fragment instructions;
|
| -
|
| - // These come from:
|
| - // class A {
|
| - // var x = (expr);
|
| - // }
|
| - for (intptr_t i = 0; i < kernel_class->fields().length(); i++) {
|
| - Field* kernel_field = kernel_class->fields()[i];
|
| - Expression* init = kernel_field->initializer();
|
| - if (!kernel_field->IsStatic() && init != NULL) {
|
| - EnterScope(kernel_field);
|
| - instructions +=
|
| - TranslateFieldInitializer(kernel_field->canonical_name(), init);
|
| - ExitScope(kernel_field);
|
| - }
|
| - }
|
| -
|
| - // These to come from:
|
| - // class A {
|
| - // var x;
|
| - // var y;
|
| - // A(this.x) : super(expr), y = (expr);
|
| - // }
|
| - for (intptr_t i = 0; i < initializers->length(); i++) {
|
| - Initializer* initializer = (*initializers)[i];
|
| - if (initializer->IsFieldInitializer()) {
|
| - FieldInitializer* init = FieldInitializer::Cast(initializer);
|
| - instructions += TranslateFieldInitializer(init->field(), init->value());
|
| - } else if (initializer->IsSuperInitializer()) {
|
| - SuperInitializer* init = SuperInitializer::Cast(initializer);
|
| -
|
| - instructions += LoadLocal(scopes_->this_variable);
|
| - instructions += PushArgument();
|
| -
|
| - ASSERT(init->arguments()->types().length() == 0);
|
| - Array& argument_names = Array::ZoneHandle(Z);
|
| - instructions += TranslateArguments(init->arguments(), &argument_names);
|
| -
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, H.LookupConstructorByKernelConstructor(init->target()));
|
| - intptr_t argument_count = init->arguments()->count() + 1;
|
| - instructions += StaticCall(TokenPosition::kNoSource, target,
|
| - argument_count, argument_names);
|
| - instructions += Drop();
|
| - } else if (initializer->IsRedirectingInitializer()) {
|
| - RedirectingInitializer* init = RedirectingInitializer::Cast(initializer);
|
| -
|
| - instructions += LoadLocal(scopes_->this_variable);
|
| - instructions += PushArgument();
|
| -
|
| - ASSERT(init->arguments()->types().length() == 0);
|
| - Array& argument_names = Array::ZoneHandle(Z);
|
| - instructions += TranslateArguments(init->arguments(), &argument_names);
|
| -
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, H.LookupConstructorByKernelConstructor(init->target()));
|
| - intptr_t argument_count = init->arguments()->count() + 1;
|
| - instructions += StaticCall(TokenPosition::kNoSource, target,
|
| - argument_count, argument_names);
|
| - instructions += Drop();
|
| - } else if (initializer->IsLocalInitializer()) {
|
| - // The other initializers following this one might read the variable. This
|
| - // is used e.g. for evaluating the arguments to a super call first, run
|
| - // normal field initializers next and then make the actual super call:
|
| - //
|
| - // The frontend converts
|
| - //
|
| - // class A {
|
| - // var x;
|
| - // A(a, b) : super(a + b), x = 2*b {}
|
| - // }
|
| - //
|
| - // to
|
| - //
|
| - // class A {
|
| - // var x;
|
| - // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {}
|
| - // }
|
| - //
|
| - // (This is strictly speaking not what one should do in terms of the
|
| - // specification but that is how it is currently implemented.)
|
| - LocalInitializer* init = LocalInitializer::Cast(initializer);
|
| -
|
| - VariableDeclaration* declaration = init->variable();
|
| - LocalVariable* variable = LookupVariable(declaration);
|
| - Expression* initializer = init->variable()->initializer();
|
| - ASSERT(initializer != NULL);
|
| - ASSERT(!declaration->IsConst());
|
| -
|
| - instructions += TranslateExpression(initializer);
|
| - instructions += StoreLocal(TokenPosition::kNoSource, variable);
|
| - instructions += Drop();
|
| -
|
| - fragment_ = instructions;
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - }
|
| - }
|
| - return instructions;
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) {
|
| -#ifdef DEBUG
|
| - intptr_t original_context_depth = context_depth_;
|
| -#endif
|
| -
|
| - // TODO(jensj): VariableDeclaration doesn't necessarily have a tag.
|
| - if (statement->can_stream() &&
|
| - statement->Type() != Node::kTypeVariableDeclaration) {
|
| - fragment_ = streaming_flow_graph_builder_->BuildStatementAt(
|
| - statement->kernel_offset());
|
| - } else {
|
| - statement->AcceptStatementVisitor(this);
|
| - }
|
| - DEBUG_ASSERT(context_depth_ == original_context_depth);
|
| - return fragment_;
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::TranslateCondition(Expression* expression,
|
| - bool* negate) {
|
| - *negate = expression->IsNot();
|
| - Fragment instructions;
|
| - if (*negate) {
|
| - instructions += TranslateExpression(Not::Cast(expression)->expression());
|
| - } else {
|
| - instructions += TranslateExpression(expression);
|
| - }
|
| - instructions += CheckBooleanInCheckedMode();
|
| - return instructions;
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) {
|
| - if (expression->can_stream()) {
|
| - fragment_ = streaming_flow_graph_builder_->BuildExpressionAt(
|
| - expression->kernel_offset());
|
| - } else {
|
| - expression->AcceptExpressionVisitor(this);
|
| - }
|
| - return fragment_;
|
| -}
|
| -
|
| -
|
| ArgumentArray FlowGraphBuilder::GetArguments(int count) {
|
| ArgumentArray arguments =
|
| new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count);
|
| @@ -3746,54 +2389,6 @@ ArgumentArray FlowGraphBuilder::GetArguments(int count) {
|
| }
|
|
|
|
|
| -void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| AbstractType& DartTypeTranslator::TranslateType(DartType* node) {
|
| node->AcceptDartTypeVisitor(this);
|
|
|
| @@ -4093,1944 +2688,23 @@ const Type& DartTypeTranslator::ReceiverType(const dart::Class& klass) {
|
| return type;
|
| }
|
|
|
| -void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - const AbstractType& type = T.TranslateType(node->type());
|
| - if (type.IsMalformed()) H.ReportError("Malformed type literal");
|
| +RawObject* EvaluateMetadata(const dart::Field& metadata_field) {
|
| + LongJumpScope jump;
|
| + if (setjmp(*jump.Set()) == 0) {
|
| + Thread* thread = Thread::Current();
|
| + Zone* zone_ = thread->zone();
|
| + TranslationHelper helper(thread);
|
| + Script& script = Script::Handle(Z, metadata_field.Script());
|
| + helper.SetStringOffsets(
|
| + TypedData::Handle(Z, script.kernel_string_offsets()));
|
| + helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data()));
|
| + helper.SetCanonicalNames(
|
| + TypedData::Handle(Z, script.kernel_canonical_names()));
|
|
|
| - 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);
|
| - }
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitVariableGet(VariableGet* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->expression());
|
| - if (NeedsDebugStepCheck(stack_, node->position())) {
|
| - instructions = DebugStepCheck(node->position()) + instructions;
|
| - }
|
| - instructions += CheckVariableTypeInCheckedMode(node->variable());
|
| - instructions +=
|
| - StoreLocal(node->position(), LookupVariable(node->variable()));
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitStaticGet(StaticGet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - // A StaticGet will always have a kernel_offset, except for the StaticGet that
|
| - // was manually created for _getMainClosure in dart:_builtin. Compile that
|
| - // one specially here.
|
| - const dart::Library& builtin =
|
| - dart::Library::Handle(Z, I->object_store()->builtin_library());
|
| - const Object& main =
|
| - Object::Handle(Z, builtin.LookupObjectAllowPrivate(dart::String::Handle(
|
| - Z, dart::String::New("main"))));
|
| - if (main.IsField()) {
|
| - UNIMPLEMENTED();
|
| - } else if (main.IsFunction()) {
|
| - const Function& function = Function::Cast(main);
|
| - if (function.kind() == RawFunction::kRegularFunction) {
|
| - const Function& closure_function =
|
| - Function::Handle(Z, function.ImplicitClosureFunction());
|
| - closure_function.set_kernel_function(function.kernel_function());
|
| - const Instance& closure =
|
| - Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure());
|
| - fragment_ = Constant(closure);
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - }
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - }
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitStaticSet(StaticSet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - NameIndex target = node->target();
|
| - 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 = TranslateExpression(node->expression());
|
| - if (NeedsDebugStepCheck(stack_, node->position())) {
|
| - instructions = DebugStepCheck(node->position()) + instructions;
|
| - }
|
| - instructions += CheckAssignableInCheckedMode(
|
| - dst_type, dart::String::ZoneHandle(Z, field.name()));
|
| - LocalVariable* variable = MakeTemporary();
|
| - instructions += LoadLocal(variable);
|
| - fragment_ = instructions + StoreStaticField(node->position(), field);
|
| - } else {
|
| - ASSERT(H.IsProcedure(target));
|
| -
|
| - // Evaluate the expression on the right hand side.
|
| - Fragment instructions = TranslateExpression(node->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(node->position(), function, 1);
|
| -
|
| - // Drop the unused result & leave the stored value on the stack.
|
| - fragment_ = instructions + Drop();
|
| - }
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->receiver());
|
| - instructions += PushArgument();
|
| - const dart::String& getter_name = H.DartGetterName(node->name());
|
| - fragment_ = instructions +
|
| - InstanceCall(node->position(), getter_name, Token::kGET, 1);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitPropertySet(PropertySet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions(NullConstant());
|
| - LocalVariable* variable = MakeTemporary();
|
| - instructions += TranslateExpression(node->receiver());
|
| - instructions += PushArgument();
|
| - instructions += TranslateExpression(node->value());
|
| - instructions += StoreLocal(TokenPosition::kNoSource, variable);
|
| - instructions += PushArgument();
|
| -
|
| - const dart::String& setter_name = H.DartSetterName(node->name());
|
| - instructions += InstanceCall(node->position(), setter_name, Token::kSET, 2);
|
| - fragment_ = instructions + Drop();
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Function& target = Function::ZoneHandle(Z);
|
| - NameIndex kernel_name = node->target();
|
| - if (H.IsProcedure(kernel_name)) {
|
| - if (H.IsGetter(kernel_name)) {
|
| - target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name));
|
| - } else {
|
| - target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name));
|
| - target = target.ImplicitClosureFunction();
|
| - ASSERT(!target.IsNull());
|
| - fragment_ = BuildImplicitClosureCreation(target);
|
| - return;
|
| - }
|
| - } 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());
|
| - }
|
| -
|
| - Fragment instructions = TranslateExpression(node->receiver());
|
| - instructions += PushArgument();
|
| - fragment_ = instructions + StaticCall(node->position(), target, 1);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - const dart::String& method_name = H.DartSetterName(node->target());
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, LookupMethodByMember(node->target(), method_name));
|
| - ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
|
| -
|
| - Fragment instructions(NullConstant());
|
| - LocalVariable* value = MakeTemporary();
|
| - instructions += TranslateExpression(node->receiver());
|
| - instructions += PushArgument();
|
| - instructions += TranslateExpression(node->value());
|
| - instructions += StoreLocal(TokenPosition::kNoSource, value);
|
| - instructions += PushArgument();
|
| - instructions += StaticCall(node->position(), target, 2);
|
| -
|
| - fragment_ = instructions + Drop();
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
|
| - const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner());
|
| - intptr_t argument_count = node->arguments()->count();
|
| - if (target.IsGenerativeConstructor() || target.IsFactory()) {
|
| - // The VM requires a TypeArguments object as first parameter for
|
| - // every factory constructor.
|
| - ++argument_count;
|
| - }
|
| -
|
| - List<NamedExpression>& named = node->arguments()->named();
|
| - const Array& argument_names = H.ArgumentNames(&named);
|
| -
|
| - // The frontend ensures we the [StaticInvocation] has matching arguments.
|
| - const intptr_t kTypeArgsLen = 0; // Generic functions not yet supported.
|
| - ASSERT(target.AreValidArguments(kTypeArgsLen, argument_count, argument_names,
|
| - NULL));
|
| -
|
| - 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) {
|
| - List<DartType>& kernel_type_arguments = node->arguments()->types();
|
| - const TypeArguments& type_arguments =
|
| - T.TranslateInstantiatedTypeArguments(
|
| - klass, kernel_type_arguments.raw_array(),
|
| - kernel_type_arguments.length());
|
| - 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.
|
| - List<DartType>& kernel_type_arguments = node->arguments()->types();
|
| -
|
| - const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
|
| - klass, kernel_type_arguments.raw_array(),
|
| - kernel_type_arguments.length());
|
| -
|
| - instructions += TranslateInstantiatedTypeArguments(type_arguments);
|
| - instructions += PushArgument();
|
| - } else {
|
| - // TODO(28109) Support generic methods in the VM or reify them away.
|
| - }
|
| -
|
| - // Special case identical(x, y) call.
|
| - // TODO(27590) consider moving this into the inliner and force inline it
|
| - // there.
|
| - if (klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) &&
|
| - (target.name() == Symbols::Identical().raw())) {
|
| - ASSERT(argument_count == 2);
|
| -
|
| - List<Expression>& positional = node->arguments()->positional();
|
| - for (intptr_t i = 0; i < positional.length(); ++i) {
|
| - instructions += TranslateExpression(positional[i]);
|
| - }
|
| - instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
|
| - } else {
|
| - instructions += TranslateArguments(node->arguments(), NULL);
|
| - instructions +=
|
| - StaticCall(node->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();
|
| - }
|
| - }
|
| -
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -static bool IsNumberLiteral(Node* node) {
|
| - return node->IsIntLiteral() || node->IsDoubleLiteral();
|
| -}
|
| -
|
| -template <class Invocation>
|
| -bool FlowGraphBuilder::RecognizeComparisonWithNull(Token::Kind token_kind,
|
| - Invocation* node) {
|
| - if (token_kind == Token::kEQ || token_kind == Token::kNE) {
|
| - if (node->arguments()->positional().length() != 1) return false;
|
| - Fragment instructions;
|
| - Expression* left = node->receiver();
|
| - Expression* right = node->arguments()->positional()[0];
|
| - if (left->IsNullLiteral() || right->IsNullLiteral()) {
|
| - instructions += TranslateExpression(left);
|
| - instructions += TranslateExpression(right);
|
| - Token::Kind strict_cmp_kind =
|
| - token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
|
| - fragment_ = instructions + StrictCompare(strict_cmp_kind,
|
| - /*number_check = */ true);
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - const dart::String& name = H.DartMethodName(node->name());
|
| - const intptr_t argument_count = node->arguments()->count() + 1;
|
| - const Token::Kind token_kind = MethodKind(name);
|
| - if (IsNumberLiteral(node->receiver())) {
|
| - if ((argument_count == 1) && (token_kind == Token::kNEGATE)) {
|
| - const Object& result = constant_evaluator_.EvaluateExpressionSafe(node);
|
| - if (!result.IsError()) {
|
| - fragment_ = Constant(result);
|
| - return;
|
| - }
|
| - } else if ((argument_count == 2) &&
|
| - Token::IsBinaryArithmeticOperator(token_kind) &&
|
| - IsNumberLiteral(node->arguments()->positional()[0])) {
|
| - const Object& result = constant_evaluator_.EvaluateExpressionSafe(node);
|
| - if (!result.IsError()) {
|
| - fragment_ = Constant(result);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (RecognizeComparisonWithNull(token_kind, node)) return;
|
| -
|
| - Fragment instructions = TranslateExpression(node->receiver());
|
| - instructions += PushArgument();
|
| -
|
| - // TODO(28109) Support generic methods in the VM or reify them away.
|
| - Array& argument_names = Array::ZoneHandle(Z);
|
| - instructions += TranslateArguments(node->arguments(), &argument_names);
|
| -
|
| - 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;
|
| - }
|
| -
|
| - fragment_ = instructions + InstanceCall(node->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()) {
|
| - fragment_ += Drop();
|
| - fragment_ += NullConstant();
|
| - }
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitDirectMethodInvocation(
|
| - DirectMethodInvocation* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - const dart::String& method_name = H.DartProcedureName(node->target());
|
| - const Token::Kind token_kind = MethodKind(method_name);
|
| -
|
| - if (RecognizeComparisonWithNull(token_kind, node)) return;
|
| -
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, LookupMethodByMember(node->target(), method_name));
|
| -
|
| - intptr_t argument_count = node->arguments()->count() + 1;
|
| - Array& argument_names = Array::ZoneHandle(Z);
|
| -
|
| - // TODO(28109) Support generic methods in the VM or reify them away.
|
| - Fragment instructions = TranslateExpression(node->receiver());
|
| - instructions += PushArgument();
|
| - instructions += TranslateArguments(node->arguments(), &argument_names);
|
| - fragment_ = instructions + StaticCall(node->position(), target,
|
| - argument_count, argument_names);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - if (node->is_const()) {
|
| - fragment_ =
|
| - Constant(constant_evaluator_.EvaluateConstructorInvocation(node));
|
| - return;
|
| - }
|
| -
|
| - dart::Class& klass = dart::Class::ZoneHandle(
|
| - Z, H.LookupClassByKernelClass(H.EnclosingName(node->target())));
|
| -
|
| - Fragment instructions;
|
| -
|
| - // Check for malbounded-ness of type.
|
| - if (I->type_checks()) {
|
| - List<DartType>& kernel_type_arguments = node->arguments()->types();
|
| - const TypeArguments& type_arguments = T.TranslateTypeArguments(
|
| - kernel_type_arguments.raw_array(), kernel_type_arguments.length());
|
| -
|
| - AbstractType& type = AbstractType::Handle(
|
| - Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
|
| - type = ClassFinalizer::FinalizeType(klass, type);
|
| -
|
| - if (type.IsMalbounded()) {
|
| - // Evaluate expressions for correctness.
|
| - List<Expression>& positional = node->arguments()->positional();
|
| - List<NamedExpression>& named = node->arguments()->named();
|
| - for (intptr_t i = 0; i < positional.length(); ++i) {
|
| - instructions += TranslateExpression(positional[i]);
|
| - instructions += Drop();
|
| - }
|
| - for (intptr_t i = 0; i < named.length(); ++i) {
|
| - instructions += TranslateExpression(named[i]->expression());
|
| - instructions += Drop();
|
| - }
|
| -
|
| - // Throw an error & keep the [Value] on the stack.
|
| - instructions += ThrowTypeError();
|
| -
|
| - // Bail out early.
|
| - fragment_ = instructions;
|
| - return;
|
| - }
|
| - }
|
| -
|
| - if (klass.NumTypeArguments() > 0) {
|
| - List<DartType>& kernel_type_arguments = node->arguments()->types();
|
| - const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
|
| - klass, kernel_type_arguments.raw_array(),
|
| - kernel_type_arguments.length());
|
| - 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);
|
| - instructions += TranslateArguments(node->arguments(), &argument_names);
|
| -
|
| - const Function& target = Function::ZoneHandle(
|
| - Z, H.LookupConstructorByKernelConstructor(klass, node->target()));
|
| - intptr_t argument_count = node->arguments()->count() + 1;
|
| - instructions +=
|
| - StaticCall(node->position(), target, argument_count, argument_names);
|
| - fragment_ = instructions + Drop();
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitIsExpression(IsExpression* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->operand());
|
| -
|
| - // 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());
|
| - const AbstractType& type = T.TranslateType(node->type());
|
| - if (type.IsMalformed()) {
|
| - instructions += Drop();
|
| - instructions += ThrowTypeError();
|
| - fragment_ = instructions;
|
| - return;
|
| - }
|
| -
|
| - 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(
|
| - node->position(),
|
| - dart::Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()),
|
| - Token::kIS, 2, 2); // 2 checked arguments.
|
| - fragment_ = instructions;
|
| - return;
|
| - }
|
| -
|
| - 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(node->position(),
|
| - dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
|
| - Token::kIS, 4);
|
| - }
|
| -
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitAsExpression(AsExpression* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->operand());
|
| -
|
| - // 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());
|
| - const AbstractType& type = T.TranslateType(node->type());
|
| - if (type.IsMalformed()) {
|
| - instructions += Drop();
|
| - instructions += ThrowTypeError();
|
| - fragment_ = instructions;
|
| - return;
|
| - }
|
| -
|
| - 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(
|
| - node->position(), dart::Library::PrivateCoreLibName(Symbols::_as()),
|
| - Token::kAS, 4);
|
| - }
|
| -
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - bool negate;
|
| - Fragment instructions = TranslateCondition(node->condition(), &negate);
|
| -
|
| - TargetEntryInstr* then_entry;
|
| - TargetEntryInstr* otherwise_entry;
|
| - instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
|
| -
|
| - Value* top = stack_;
|
| - Fragment then_fragment(then_entry);
|
| - then_fragment += TranslateExpression(node->then());
|
| - then_fragment += StoreLocal(TokenPosition::kNoSource,
|
| - parsed_function_->expression_temp_var());
|
| - then_fragment += Drop();
|
| - ASSERT(stack_ == top);
|
| -
|
| - Fragment otherwise_fragment(otherwise_entry);
|
| - otherwise_fragment += TranslateExpression(node->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);
|
| -
|
| - fragment_ = Fragment(instructions.entry, join) +
|
| - LoadLocal(parsed_function_->expression_temp_var());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - bool negate;
|
| - Fragment instructions = TranslateCondition(node->left(), &negate);
|
| - TargetEntryInstr* right_entry;
|
| - TargetEntryInstr* constant_entry;
|
| -
|
| - if (node->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(node->right(), &negate);
|
| - 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(node->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);
|
| -
|
| - fragment_ = Fragment(instructions.entry, join) +
|
| - LoadLocal(parsed_function_->expression_temp_var());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitNot(Not* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->expression());
|
| - instructions += CheckBooleanInCheckedMode();
|
| - instructions += BooleanNegate();
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - List<Expression>& expressions = node->expressions();
|
| -
|
| - Fragment instructions;
|
| -
|
| - if (node->expressions().length() == 1) {
|
| - instructions += TranslateExpression(node->expressions()[0]);
|
| - instructions += StringInterpolateSingle(node->position());
|
| - } else {
|
| - // The type arguments for CreateArray.
|
| - instructions += Constant(TypeArguments::ZoneHandle(Z));
|
| - instructions += IntConstant(expressions.length());
|
| - instructions += CreateArray();
|
| - LocalVariable* array = MakeTemporary();
|
| -
|
| - for (intptr_t i = 0; i < node->expressions().length(); i++) {
|
| - instructions += LoadLocal(array);
|
| - instructions += IntConstant(i);
|
| - instructions += TranslateExpression(node->expressions()[i]);
|
| - instructions += StoreIndexed(kArrayCid);
|
| - instructions += Drop();
|
| - }
|
| -
|
| - instructions += StringInterpolate(node->position());
|
| - }
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - if (node->is_const()) {
|
| - fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node));
|
| - return;
|
| - }
|
| -
|
| - DartType* types[] = {node->type()};
|
| - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1);
|
| -
|
| - // The type argument for the factory call.
|
| - Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
|
| - instructions += PushArgument();
|
| - List<Expression>& expressions = node->expressions();
|
| - if (expressions.length() == 0) {
|
| - instructions += Constant(Object::empty_array());
|
| - } else {
|
| - // The type arguments for CreateArray.
|
| - instructions += Constant(TypeArguments::ZoneHandle(Z));
|
| - instructions += IntConstant(expressions.length());
|
| - instructions += CreateArray();
|
| -
|
| - LocalVariable* array = MakeTemporary();
|
| - for (intptr_t i = 0; i < expressions.length(); ++i) {
|
| - instructions += LoadLocal(array);
|
| - instructions += IntConstant(i);
|
| - instructions += TranslateExpression(expressions[i]);
|
| - 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())));
|
| - fragment_ = instructions + StaticCall(node->position(), factory_method, 2);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - if (node->is_const()) {
|
| - fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node));
|
| - return;
|
| - }
|
| -
|
| - 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())));
|
| -
|
| - DartType* types[] = {node->key_type(), node->value_type()};
|
| - const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2);
|
| -
|
| - // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
|
| - Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
|
| - instructions += PushArgument();
|
| -
|
| - List<MapEntry>& entries = node->entries();
|
| - if (entries.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 * entries.length());
|
| - instructions += CreateArray();
|
| -
|
| - LocalVariable* array = MakeTemporary();
|
| - for (intptr_t i = 0; i < entries.length(); ++i) {
|
| - instructions += LoadLocal(array);
|
| - instructions += IntConstant(2 * i);
|
| - instructions += TranslateExpression(entries[i]->key());
|
| - instructions += StoreIndexed(kArrayCid);
|
| - instructions += Drop();
|
| -
|
| - instructions += LoadLocal(array);
|
| - instructions += IntConstant(2 * i + 1);
|
| - instructions += TranslateExpression(entries[i]->value());
|
| - instructions += StoreIndexed(kArrayCid);
|
| - instructions += Drop();
|
| - }
|
| - }
|
| - instructions += PushArgument(); // The array.
|
| -
|
| - fragment_ = instructions + StaticCall(node->position(), factory_method, 2);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitFunctionExpression(FunctionExpression* node) {
|
| - fragment_ = TranslateFunctionNode(node->function(), node);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitLet(Let* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateStatement(node->variable());
|
| - instructions += TranslateExpression(node->body());
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitThrow(Throw* node) {
|
| - STREAM_EXPRESSION_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions;
|
| -
|
| - instructions += TranslateExpression(node->expression());
|
| - if (NeedsDebugStepCheck(stack_, node->position())) {
|
| - instructions = DebugStepCheck(node->position()) + instructions;
|
| - }
|
| - instructions += PushArgument();
|
| - instructions += ThrowException(node->position());
|
| - ASSERT(instructions.is_closed());
|
| -
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitRethrow(Rethrow* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::TranslateArguments(Arguments* node,
|
| - Array* argument_names) {
|
| - Fragment instructions;
|
| -
|
| - List<Expression>& positional = node->positional();
|
| - for (intptr_t i = 0; i < positional.length(); ++i) {
|
| - instructions += TranslateExpression(positional[i]);
|
| - instructions += PushArgument();
|
| - }
|
| -
|
| - List<NamedExpression>& named = node->named();
|
| - if (argument_names != NULL) {
|
| - *argument_names = H.ArgumentNames(&named).raw();
|
| - }
|
| - for (intptr_t i = 0; i < named.length(); ++i) {
|
| - NamedExpression* named_expression = named[i];
|
| - instructions += TranslateExpression(named_expression->expression());
|
| - instructions += PushArgument();
|
| - }
|
| - return instructions;
|
| -}
|
| -
|
| -#define STREAM_STATEMENT_IF_POSSIBLE(node) \
|
| - if (node->can_stream()) { \
|
| - fragment_ = streaming_flow_graph_builder_->BuildStatementAt( \
|
| - node->kernel_offset()); \
|
| - return; \
|
| - }
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitBlock(Block* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions;
|
| -
|
| - instructions += EnterScope(node);
|
| - List<Statement>& statements = node->statements();
|
| - for (intptr_t i = 0; (i < statements.length()) && instructions.is_open();
|
| - ++i) {
|
| - instructions += TranslateStatement(statements[i]);
|
| - }
|
| - instructions += ExitScope(node);
|
| -
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - bool inside_try_finally = try_finally_block_ != NULL;
|
| -
|
| - Fragment instructions = node->expression() == NULL
|
| - ? NullConstant()
|
| - : TranslateExpression(node->expression());
|
| - if (instructions.is_open()) {
|
| - if (inside_try_finally) {
|
| - ASSERT(scopes_->finally_return_variable != NULL);
|
| - const Function& function = parsed_function_->function();
|
| - if (NeedsDebugStepCheck(function, node->position())) {
|
| - instructions += DebugStepCheck(node->position());
|
| - }
|
| - instructions +=
|
| - StoreLocal(node->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(node->position());
|
| - }
|
| - } else {
|
| - Pop();
|
| - }
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->expression());
|
| - instructions += Drop();
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) {
|
| - LocalVariable* variable = LookupVariable(node);
|
| - Expression* initializer = node->initializer();
|
| -
|
| - Fragment instructions;
|
| - if (initializer == NULL) {
|
| - instructions += NullConstant();
|
| - } else {
|
| - if (node->IsConst()) {
|
| - const Instance& constant_value =
|
| - constant_evaluator_.EvaluateExpression(initializer);
|
| - variable->SetConstValue(constant_value);
|
| - instructions += Constant(constant_value);
|
| - } else {
|
| - instructions += TranslateExpression(initializer);
|
| - instructions += CheckVariableTypeInCheckedMode(node);
|
| - }
|
| - }
|
| - // 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(node->position(), node->equals_position());
|
| - if (NeedsDebugStepCheck(stack_, debug_position)) {
|
| - instructions = DebugStepCheck(debug_position) + instructions;
|
| - }
|
| - instructions += StoreLocal(node->position(), variable);
|
| - instructions += Drop();
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) {
|
| - Fragment instructions = DebugStepCheck(node->position());
|
| - instructions += TranslateFunctionNode(node->function(), node);
|
| - instructions +=
|
| - StoreLocal(node->position(), LookupVariable(node->variable()));
|
| - instructions += Drop();
|
| - fragment_ = instructions;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitIfStatement(IfStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - bool negate;
|
| - Fragment instructions = TranslateCondition(node->condition(), &negate);
|
| - TargetEntryInstr* then_entry;
|
| - TargetEntryInstr* otherwise_entry;
|
| - instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
|
| -
|
| - Fragment then_fragment(then_entry);
|
| - then_fragment += TranslateStatement(node->then());
|
| -
|
| - Fragment otherwise_fragment(otherwise_entry);
|
| - otherwise_fragment += TranslateStatement(node->otherwise());
|
| -
|
| - if (then_fragment.is_open()) {
|
| - if (otherwise_fragment.is_open()) {
|
| - JoinEntryInstr* join = BuildJoinEntry();
|
| - then_fragment += Goto(join);
|
| - otherwise_fragment += Goto(join);
|
| - fragment_ = Fragment(instructions.entry, join);
|
| - } else {
|
| - fragment_ = Fragment(instructions.entry, then_fragment.current);
|
| - }
|
| - } else if (otherwise_fragment.is_open()) {
|
| - fragment_ = Fragment(instructions.entry, otherwise_fragment.current);
|
| - } else {
|
| - fragment_ = instructions.closed();
|
| - }
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - ++loop_depth_;
|
| - bool negate;
|
| - Fragment condition = TranslateCondition(node->condition(), &negate);
|
| - TargetEntryInstr* body_entry;
|
| - TargetEntryInstr* loop_exit;
|
| - condition += BranchIfTrue(&body_entry, &loop_exit, negate);
|
| -
|
| - Fragment body(body_entry);
|
| - body += TranslateStatement(node->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, GetNextDeoptId());
|
| - } else {
|
| - entry = condition.entry;
|
| - }
|
| -
|
| -
|
| - fragment_ = Fragment(entry, loop_exit);
|
| - --loop_depth_;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitDoStatement(DoStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - ++loop_depth_;
|
| - Fragment body = TranslateStatement(node->body());
|
| -
|
| - if (body.is_closed()) {
|
| - fragment_ = body;
|
| - --loop_depth_;
|
| - return;
|
| - }
|
| -
|
| - bool negate;
|
| - JoinEntryInstr* join = BuildJoinEntry();
|
| - Fragment loop(join);
|
| - loop += CheckStackOverflow();
|
| - loop += body;
|
| - loop += TranslateCondition(node->condition(), &negate);
|
| - TargetEntryInstr* loop_repeat;
|
| - TargetEntryInstr* loop_exit;
|
| - loop += BranchIfTrue(&loop_repeat, &loop_exit, negate);
|
| -
|
| - Fragment repeat(loop_repeat);
|
| - repeat += Goto(join);
|
| -
|
| - fragment_ = Fragment(new (Z) GotoInstr(join, GetNextDeoptId()), loop_exit);
|
| - --loop_depth_;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitForStatement(ForStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - Fragment declarations;
|
| -
|
| - bool new_context = false;
|
| - declarations += EnterScope(node, &new_context);
|
| -
|
| - List<VariableDeclaration>& variables = node->variables();
|
| - for (intptr_t i = 0; i < variables.length(); ++i) {
|
| - declarations += TranslateStatement(variables[i]);
|
| - }
|
| -
|
| - ++loop_depth_;
|
| - bool negate = false;
|
| - Fragment condition = node->condition() == NULL
|
| - ? Constant(Bool::True())
|
| - : TranslateCondition(node->condition(), &negate);
|
| - TargetEntryInstr* body_entry;
|
| - TargetEntryInstr* loop_exit;
|
| - condition += BranchIfTrue(&body_entry, &loop_exit, negate);
|
| -
|
| - Fragment body(body_entry);
|
| - body += TranslateStatement(node->body());
|
| -
|
| - if (body.is_open()) {
|
| - // We allocated a fresh context before the loop which contains captured
|
| - // [ForStatement] variables. Before jumping back to the loop entry we clone
|
| - // the context object (at same depth) which ensures the next iteration of
|
| - // the body gets a fresh set of [ForStatement] variables (with the old
|
| - // (possibly updated) values).
|
| - if (new_context) body += CloneContext();
|
| -
|
| - List<Expression>& updates = node->updates();
|
| - for (intptr_t i = 0; i < updates.length(); ++i) {
|
| - body += TranslateExpression(updates[i]);
|
| - body += Drop();
|
| - }
|
| - JoinEntryInstr* join = BuildJoinEntry();
|
| - declarations += Goto(join);
|
| - body += Goto(join);
|
| -
|
| - Fragment loop(join);
|
| - loop += CheckStackOverflow();
|
| - loop += condition;
|
| - } else {
|
| - declarations += condition;
|
| - }
|
| -
|
| - Fragment loop(declarations.entry, loop_exit);
|
| - --loop_depth_;
|
| -
|
| - loop += ExitScope(node);
|
| -
|
| - fragment_ = loop;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - Fragment instructions = TranslateExpression(node->iterable());
|
| - instructions += PushArgument();
|
| -
|
| - const dart::String& iterator_getter = dart::String::ZoneHandle(
|
| - Z, dart::Field::GetterSymbol(Symbols::Iterator()));
|
| - instructions += InstanceCall(node->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_;
|
| - ++loop_depth_;
|
| - Fragment condition = LoadLocal(iterator);
|
| - condition += PushArgument();
|
| - condition += InstanceCall(node->iterable()->position(), Symbols::MoveNext(),
|
| - Token::kILLEGAL, 1);
|
| - TargetEntryInstr* body_entry;
|
| - TargetEntryInstr* loop_exit;
|
| - condition += BranchIfTrue(&body_entry, &loop_exit);
|
| -
|
| - Fragment body(body_entry);
|
| - body += EnterScope(node);
|
| - body += LoadLocal(iterator);
|
| - body += PushArgument();
|
| - const dart::String& current_getter = dart::String::ZoneHandle(
|
| - Z, dart::Field::GetterSymbol(Symbols::Current()));
|
| - body += InstanceCall(node->position(), current_getter, Token::kGET, 1);
|
| - body +=
|
| - StoreLocal(TokenPosition::kNoSource, LookupVariable(node->variable()));
|
| - body += Drop();
|
| - body += TranslateStatement(node->body());
|
| - body += ExitScope(node);
|
| -
|
| - if (body.is_open()) {
|
| - JoinEntryInstr* join = BuildJoinEntry();
|
| - instructions += Goto(join);
|
| - body += Goto(join);
|
| -
|
| - Fragment loop(join);
|
| - loop += CheckStackOverflow();
|
| - loop += condition;
|
| - } else {
|
| - instructions += condition;
|
| - }
|
| -
|
| - fragment_ = Fragment(instructions.entry, loop_exit);
|
| - --loop_depth_;
|
| - --for_in_depth_;
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - // 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(this);
|
| - Fragment instructions = TranslateStatement(node->body());
|
| - if (block.HadJumper()) {
|
| - if (instructions.is_open()) {
|
| - instructions += Goto(block.destination());
|
| - }
|
| - fragment_ = Fragment(instructions.entry, block.destination());
|
| - } else {
|
| - fragment_ = instructions;
|
| - }
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - SwitchBlock block(this, node->cases().length());
|
| -
|
| - // 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 = TranslateExpression(node->condition());
|
| - head_instructions +=
|
| - StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable);
|
| - head_instructions += Drop();
|
| -
|
| - // 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[node->cases().length()];
|
| -
|
| - intptr_t num_cases = node->cases().length();
|
| - for (intptr_t i = 0; i < num_cases; i++) {
|
| - SwitchCase* switch_case = node->cases()[i];
|
| - Fragment& body_fragment = body_fragments[i] =
|
| - TranslateStatement(switch_case->body());
|
| -
|
| - if (body_fragment.entry == NULL) {
|
| - // Make a NOP in order to ensure linking works properly.
|
| - body_fragment = NullConstant();
|
| - body_fragment += Drop();
|
| - }
|
| -
|
| - // The Dart language specification mandates fall-throughs in [SwitchCase]es
|
| - // to be runtime errors.
|
| - if (!switch_case->is_default() && body_fragment.is_open() &&
|
| - (i < (node->cases().length() - 1))) {
|
| - const dart::Class& klass = dart::Class::ZoneHandle(
|
| - Z, dart::Library::LookupCoreClass(Symbols::FallThroughError()));
|
| - ASSERT(!klass.IsNull());
|
| - const Function& constructor = 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();
|
| -
|
| - // Call _FallThroughError._create constructor.
|
| - body_fragment += LoadLocal(instance);
|
| - body_fragment += PushArgument(); // this
|
| -
|
| - body_fragment += Constant(url);
|
| - body_fragment += PushArgument(); // url
|
| -
|
| - body_fragment += NullConstant();
|
| - body_fragment += PushArgument(); // line
|
| -
|
| - body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3);
|
| - body_fragment += Drop();
|
| -
|
| - // Throw the exception
|
| - body_fragment += PushArgument();
|
| - body_fragment += ThrowException(TokenPosition::kNoSource);
|
| - body_fragment += Drop();
|
| - }
|
| -
|
| - // If there is an implicit fall-through we have one [SwitchCase] and
|
| - // multiple expressions, e.g.
|
| - //
|
| - // switch(expr) {
|
| - // case a:
|
| - // case b:
|
| - // <stmt-body>
|
| - // }
|
| - //
|
| - // This means that the <stmt-body> will have more than 1 incoming edge (one
|
| - // from `a == expr` and one from `a != expr && b == expr`). The
|
| - // `block.Destination()` records the additional jump.
|
| - if (switch_case->expressions().length() > 1) {
|
| - block.DestinationDirect(i);
|
| - }
|
| - }
|
| -
|
| - // 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++) {
|
| - SwitchCase* switch_case = node->cases()[i];
|
| -
|
| - if (switch_case->is_default()) {
|
| - ASSERT(i == (node->cases().length() - 1));
|
| -
|
| - // Evaluate the conditions for the default [SwitchCase] just for the
|
| - // purpose of potentially triggering a compile-time error.
|
| - for (intptr_t k = 0; k < switch_case->expressions().length(); k++) {
|
| - constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]);
|
| - }
|
| -
|
| - if (block.HadJumper(i)) {
|
| - // There are several branches to the body, so we will make a goto to
|
| - // the join block (and prepend a join instruction to the real body).
|
| - JoinEntryInstr* join = block.DestinationDirect(i);
|
| - current_instructions += Goto(join);
|
| -
|
| - current_instructions = Fragment(current_instructions.entry, join);
|
| - current_instructions += body_fragments[i];
|
| - } else {
|
| - current_instructions += body_fragments[i];
|
| - }
|
| - } else {
|
| - JoinEntryInstr* body_join = NULL;
|
| - if (block.HadJumper(i)) {
|
| - body_join = block.DestinationDirect(i);
|
| - body_fragments[i] = Fragment(body_join) + body_fragments[i];
|
| - }
|
| -
|
| - for (intptr_t j = 0; j < switch_case->expressions().length(); j++) {
|
| - TargetEntryInstr* then;
|
| - TargetEntryInstr* otherwise;
|
| -
|
| - Expression* expression = switch_case->expressions()[j];
|
| - current_instructions +=
|
| - Constant(constant_evaluator_.EvaluateExpression(expression));
|
| - current_instructions += PushArgument();
|
| - current_instructions += LoadLocal(scopes_->switch_variable);
|
| - current_instructions += PushArgument();
|
| - current_instructions += InstanceCall(
|
| - expression->position(), Symbols::EqualOperator(), Token::kEQ,
|
| - /*argument_count=*/2,
|
| - /*num_args_checked=*/2);
|
| - current_instructions += BranchIfTrue(&then, &otherwise);
|
| -
|
| - Fragment then_fragment(then);
|
| -
|
| - if (body_join != NULL) {
|
| - // There are several branches to the body, so we will make a goto to
|
| - // the join block (the real body has already been prepended with a
|
| - // join instruction).
|
| - then_fragment += Goto(body_join);
|
| - } else {
|
| - // There is only a signle branch to the body, so we will just append
|
| - // the body fragment.
|
| - then_fragment += body_fragments[i];
|
| - }
|
| -
|
| - current_instructions = Fragment(otherwise);
|
| - }
|
| - }
|
| - }
|
| -
|
| - bool has_no_default =
|
| - num_cases > 0 && !node->cases()[num_cases - 1]->is_default();
|
| - 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[node->cases().length() - 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;
|
| -
|
| - fragment_ = Fragment(head_instructions.entry, current_instructions.current);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitContinueSwitchStatement(
|
| - ContinueSwitchStatement* node) {
|
| - fragment_ =
|
| - streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - if (!I->asserts()) {
|
| - fragment_ = Fragment();
|
| - return;
|
| - }
|
| -
|
| - 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 += TranslateExpression(node->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 Function& constructor =
|
| - 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
|
| -
|
| - otherwise_fragment +=
|
| - node->message() != NULL
|
| - ? TranslateExpression(node->message())
|
| - : 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();
|
| -
|
| - fragment_ = Fragment(instructions.entry, then);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitTryFinally(TryFinally* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
|
| -
|
| - // There are 5 different cases where we need to execute the finally block:
|
| - //
|
| - // a) 1/2/3th case: Special control flow going out of `node->body()`:
|
| - //
|
| - // * [BreakStatement] transfers control to a [LabledStatement]
|
| - // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
|
| - // * [ReturnStatement] returns a value
|
| - //
|
| - // => All three cases will automatically append all finally blocks
|
| - // between the branching point and the destination (so we don't need to
|
| - // do anything here).
|
| - //
|
| - // b) 4th case: Translating the body resulted in an open fragment (i.e. body
|
| - // executes without any control flow out of it)
|
| - //
|
| - // => We are responsible for jumping out of the body to a new block (with
|
| - // different try index) and execute the finalizer.
|
| - //
|
| - // c) 5th case: An exception occured 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();
|
| -
|
| - // Fill in the body of the try.
|
| - ++try_depth_;
|
| - {
|
| - TryFinallyBlock tfb(this, node->finalizer(), -1);
|
| - TryCatchBlock tcb(this, try_handler_index);
|
| - try_body += TranslateStatement(node->body());
|
| - }
|
| - --try_depth_;
|
| -
|
| - if (try_body.is_open()) {
|
| - // Please note: The try index will be on level out of this block,
|
| - // thereby ensuring if there's an exception in the finally block we
|
| - // won't run it twice.
|
| - JoinEntryInstr* finally_entry = BuildJoinEntry();
|
| -
|
| - try_body += Goto(finally_entry);
|
| -
|
| - Fragment finally_body(finally_entry);
|
| - finally_body += TranslateStatement(node->finalizer());
|
| - finally_body += Goto(after_try);
|
| - }
|
| -
|
| - // Fill in the body of the catch.
|
| - ++catch_depth_;
|
| - 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);
|
| - finally_body += TranslateStatement(node->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_;
|
| -
|
| - fragment_ = Fragment(try_body.entry, after_try);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
|
| -
|
| - intptr_t try_handler_index = AllocateTryIndex();
|
| - Fragment try_body = TryCatch(try_handler_index);
|
| - JoinEntryInstr* after_try = BuildJoinEntry();
|
| -
|
| - // Fill in the body of the try.
|
| - ++try_depth_;
|
| - {
|
| - TryCatchBlock block(this, try_handler_index);
|
| - try_body += TranslateStatement(node->body());
|
| - try_body += Goto(after_try);
|
| - }
|
| - --try_depth_;
|
| -
|
| - ++catch_depth_;
|
| - const Array& handler_types =
|
| - Array::ZoneHandle(Z, Array::New(node->catches().length(), Heap::kOld));
|
| - bool needs_stacktrace = false;
|
| - for (intptr_t i = 0; i < node->catches().length(); i++) {
|
| - if (node->catches()[i]->stack_trace() != NULL) {
|
| - needs_stacktrace = true;
|
| - break;
|
| - }
|
| - }
|
| - Fragment catch_body =
|
| - CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace);
|
| - // Fill in the body of the catch.
|
| - for (intptr_t i = 0; i < node->catches().length(); i++) {
|
| - Catch* catch_clause = node->catches()[i];
|
| -
|
| - Fragment catch_handler_body;
|
| -
|
| - catch_handler_body += EnterScope(catch_clause);
|
| -
|
| - if (catch_clause->exception() != NULL) {
|
| - catch_handler_body += LoadLocal(CurrentException());
|
| - catch_handler_body += StoreLocal(
|
| - TokenPosition::kNoSource, LookupVariable(catch_clause->exception()));
|
| - catch_handler_body += Drop();
|
| - }
|
| - if (catch_clause->stack_trace() != NULL) {
|
| - catch_handler_body += LoadLocal(CurrentStackTrace());
|
| - catch_handler_body +=
|
| - StoreLocal(TokenPosition::kNoSource,
|
| - LookupVariable(catch_clause->stack_trace()));
|
| - catch_handler_body += Drop();
|
| - }
|
| - AbstractType* type_guard = NULL;
|
| - if (catch_clause->guard() != NULL &&
|
| - !catch_clause->guard()->IsDynamicType()) {
|
| - type_guard = &T.TranslateType(catch_clause->guard());
|
| - handler_types.SetAt(i, *type_guard);
|
| - } else {
|
| - handler_types.SetAt(i, Object::dynamic_type());
|
| - }
|
| -
|
| - {
|
| - CatchBlock block(this, CurrentException(), CurrentStackTrace(),
|
| - try_handler_index);
|
| -
|
| - catch_handler_body += TranslateStatement(catch_clause->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_clause);
|
| - if (catch_handler_body.is_open()) {
|
| - catch_handler_body += Goto(after_try);
|
| - }
|
| - }
|
| -
|
| - if (type_guard != NULL) {
|
| - if (type_guard->IsMalformed()) {
|
| - catch_body += ThrowTypeError();
|
| - catch_body += Drop();
|
| - } else {
|
| - catch_body += LoadLocal(CurrentException());
|
| - catch_body += PushArgument(); // exception
|
| - 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);
|
| -
|
| - Fragment(catch_entry) + catch_handler_body;
|
| - catch_body = Fragment(next_catch_entry);
|
| - }
|
| - } else {
|
| - catch_body += catch_handler_body;
|
| - }
|
| - }
|
| -
|
| - // In case the last catch body was not handling the exception and branching to
|
| - // after the try block, we will rethrow the exception (i.e. no default catch
|
| - // handler).
|
| - if (catch_body.is_open()) {
|
| - catch_body += LoadLocal(CurrentException());
|
| - catch_body += PushArgument();
|
| - catch_body += LoadLocal(CurrentStackTrace());
|
| - catch_body += PushArgument();
|
| - catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
|
| - Drop();
|
| - }
|
| - --catch_depth_;
|
| -
|
| - fragment_ = Fragment(try_body.entry, after_try);
|
| -}
|
| -
|
| -
|
| -void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) {
|
| - STREAM_STATEMENT_IF_POSSIBLE(node);
|
| -
|
| - ASSERT(node->is_native()); // 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 += TranslateExpression(node->expression());
|
| - instructions += Return(TokenPosition::kNoSource);
|
| -
|
| - // Note: DropTempsInstr serves as an anchor instruction. It will not
|
| - // be linked into the resulting graph.
|
| - DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL);
|
| - yield_continuations_.Add(YieldContinuation(anchor, CurrentTryIndex()));
|
| -
|
| - Fragment continuation(instructions.entry, anchor);
|
| -
|
| - if (parsed_function_->function().IsAsyncClosure() ||
|
| - parsed_function_->function().IsAsyncGenClosure()) {
|
| - // If function is async closure or async gen closure it takes three
|
| - // parameters where the second and the third are exception and stack_trace.
|
| - // Check if exception is non-null and rethrow it.
|
| - //
|
| - // :async_op([:result, :exception, :stack_trace]) {
|
| - // ...
|
| - // Continuation<index>:
|
| - // if (:exception != null) rethrow(:exception, :stack_trace);
|
| - // ...
|
| - // }
|
| - //
|
| - LocalScope* scope = parsed_function_->node_sequence()->scope();
|
| - LocalVariable* exception_var = scope->VariableAt(2);
|
| - LocalVariable* stack_trace_var = scope->VariableAt(3);
|
| - ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw());
|
| - ASSERT(stack_trace_var->name().raw() ==
|
| - Symbols::StackTraceParameter().raw());
|
| -
|
| - TargetEntryInstr* no_error;
|
| - TargetEntryInstr* error;
|
| -
|
| - continuation += LoadLocal(exception_var);
|
| - continuation += BranchIfNull(&no_error, &error);
|
| -
|
| - Fragment rethrow(error);
|
| - rethrow += LoadLocal(exception_var);
|
| - rethrow += PushArgument();
|
| - rethrow += LoadLocal(stack_trace_var);
|
| - rethrow += PushArgument();
|
| - rethrow +=
|
| - RethrowException(node->position(), CatchClauseNode::kInvalidTryIndex);
|
| - Drop();
|
| -
|
| -
|
| - continuation = Fragment(continuation.entry, no_error);
|
| - }
|
| -
|
| - fragment_ = continuation;
|
| -}
|
| -
|
| -
|
| -Fragment FlowGraphBuilder::TranslateFunctionNode(FunctionNode* node,
|
| - TreeNode* parent) {
|
| - // The VM has a per-isolate table of functions indexed by the enclosing
|
| - // function and token position.
|
| - Function& function = Function::ZoneHandle(Z);
|
| - for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) {
|
| - if (scopes_->function_scopes[i].kernel_offset != node->kernel_offset()) {
|
| - continue;
|
| - }
|
| -
|
| - TokenPosition position = node->position();
|
| - if (parent->IsFunctionDeclaration()) {
|
| - position = FunctionDeclaration::Cast(parent)->position();
|
| - }
|
| - if (!position.IsReal()) {
|
| - // Positions has to be unique in regards to the parent.
|
| - // A non-real at this point is probably -1, we cannot blindly use that
|
| - // as others might use it too. Create a new dummy non-real TokenPosition.
|
| - position = TokenPosition(i).ToSynthetic();
|
| - }
|
| -
|
| - // NOTE: This is not TokenPosition in the general sense!
|
| - function = I->LookupClosureFunction(parsed_function_->function(), position);
|
| - if (function.IsNull()) {
|
| - const dart::String* name;
|
| - if (parent->IsFunctionExpression()) {
|
| - name = &Symbols::AnonymousClosure();
|
| - } else {
|
| - ASSERT(parent->IsFunctionDeclaration());
|
| - name = &H.DartSymbol(
|
| - FunctionDeclaration::Cast(parent)->variable()->name());
|
| - }
|
| - // NOTE: This is not TokenPosition in the general sense!
|
| - function = Function::NewClosureFunction(
|
| - *name, parsed_function_->function(), position);
|
| -
|
| - function.set_is_debuggable(node->dart_async_marker() ==
|
| - FunctionNode::kSync);
|
| - switch (node->dart_async_marker()) {
|
| - case FunctionNode::kSyncStar:
|
| - function.set_modifier(RawFunction::kSyncGen);
|
| - break;
|
| - case FunctionNode::kAsync:
|
| - function.set_modifier(RawFunction::kAsync);
|
| - function.set_is_inlinable(!FLAG_causal_async_stacks);
|
| - break;
|
| - case FunctionNode::kAsyncStar:
|
| - function.set_modifier(RawFunction::kAsyncGen);
|
| - function.set_is_inlinable(!FLAG_causal_async_stacks);
|
| - break;
|
| - default:
|
| - // no special modifier
|
| - break;
|
| - }
|
| - function.set_is_generated_body(node->async_marker() ==
|
| - FunctionNode::kSyncYielding);
|
| - if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
|
| - function.set_is_inlinable(!FLAG_causal_async_stacks);
|
| - }
|
| -
|
| - function.set_end_token_pos(node->end_position());
|
| - LocalScope* scope = scopes_->function_scopes[i].scope;
|
| - const ContextScope& context_scope =
|
| - ContextScope::Handle(Z, scope->PreserveOuterScope(context_depth_));
|
| - function.set_context_scope(context_scope);
|
| - function.set_kernel_function(node);
|
| - KernelReader::SetupFunctionParameters(H, T, dart::Class::Handle(Z),
|
| - function, node,
|
| - false, // is_method
|
| - true); // is_closure
|
| - // Finalize function type.
|
| - Type& signature_type = Type::Handle(Z, function.SignatureType());
|
| - signature_type ^=
|
| - ClassFinalizer::FinalizeType(*active_class_.klass, signature_type);
|
| - function.SetSignatureType(signature_type);
|
| -
|
| - I->AddClosureFunction(function);
|
| - }
|
| - break;
|
| - }
|
| -
|
| - const dart::Class& closure_class =
|
| - dart::Class::ZoneHandle(Z, I->object_store()->closure_class());
|
| - ASSERT(!closure_class.IsNull());
|
| - Fragment instructions = AllocateObject(closure_class, function);
|
| - LocalVariable* closure = MakeTemporary();
|
| -
|
| - // The function signature can have uninstantiated class type parameters.
|
| - //
|
| - // TODO(regis): Also handle the case of a function signature that has
|
| - // uninstantiated function type parameters.
|
| - if (!function.HasInstantiatedSignature(kCurrentClass)) {
|
| - instructions += LoadLocal(closure);
|
| - instructions += LoadInstantiatorTypeArguments();
|
| - instructions +=
|
| - StoreInstanceField(TokenPosition::kNoSource,
|
| - Closure::instantiator_type_arguments_offset());
|
| - }
|
| -
|
| - // Store the function and the context in the closure.
|
| - instructions += LoadLocal(closure);
|
| - instructions += Constant(function);
|
| - instructions +=
|
| - StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset());
|
| -
|
| - instructions += LoadLocal(closure);
|
| - instructions += LoadLocal(parsed_function_->current_context_var());
|
| - instructions +=
|
| - StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset());
|
| -
|
| - return instructions;
|
| -}
|
| -
|
| -
|
| -RawObject* EvaluateMetadata(const dart::Field& metadata_field) {
|
| - LongJumpScope jump;
|
| - if (setjmp(*jump.Set()) == 0) {
|
| - Thread* thread = Thread::Current();
|
| - Zone* zone_ = thread->zone();
|
| -
|
| - TreeNode* kernel_node =
|
| - reinterpret_cast<TreeNode*>(metadata_field.kernel_field());
|
| - List<Expression>* metadata_expressions = NULL;
|
| - if (kernel_node->IsClass()) {
|
| - metadata_expressions = &Class::Cast(kernel_node)->annotations();
|
| - } else if (kernel_node->IsProcedure()) {
|
| - metadata_expressions = &Procedure::Cast(kernel_node)->annotations();
|
| - } else if (kernel_node->IsField()) {
|
| - metadata_expressions = &Field::Cast(kernel_node)->annotations();
|
| - } else if (kernel_node->IsConstructor()) {
|
| - metadata_expressions = &Constructor::Cast(kernel_node)->annotations();
|
| - } else {
|
| - FATAL1("No support for metadata on this type of kernel node %p\n",
|
| - kernel_node);
|
| - }
|
| -
|
| - TranslationHelper helper(thread);
|
| - Script& script = Script::Handle(Z, metadata_field.Script());
|
| - helper.SetStringOffsets(
|
| - TypedData::Handle(Z, script.kernel_string_offsets()));
|
| - helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data()));
|
| - helper.SetCanonicalNames(
|
| - TypedData::Handle(Z, script.kernel_canonical_names()));
|
| - DartTypeTranslator type_translator(&helper, NULL, true);
|
| - ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z,
|
| - &helper, &type_translator);
|
| -
|
| - const Array& metadata_values =
|
| - Array::Handle(Z, Array::New(metadata_expressions->length()));
|
| -
|
| - for (intptr_t i = 0; i < metadata_expressions->length(); i++) {
|
| - const Instance& value =
|
| - constant_evaluator.EvaluateExpression((*metadata_expressions)[i]);
|
| - metadata_values.SetAt(i, value);
|
| - }
|
| -
|
| - return metadata_values.raw();
|
| + StreamingFlowGraphBuilder streaming_flow_graph_builder(
|
| + &helper, zone_, script.kernel_data(), script.kernel_data_size());
|
| + return streaming_flow_graph_builder.EvaluateMetadata(
|
| + metadata_field.kernel_offset());
|
| } else {
|
| Thread* thread = Thread::Current();
|
| Error& error = Error::Handle();
|
| @@ -6044,20 +2718,6 @@ RawObject* EvaluateMetadata(const dart::Field& metadata_field) {
|
| RawObject* BuildParameterDescriptor(const Function& function) {
|
| LongJumpScope jump;
|
| if (setjmp(*jump.Set()) == 0) {
|
| - TreeNode* kernel_node =
|
| - reinterpret_cast<TreeNode*>(function.kernel_function());
|
| - FunctionNode* function_node = NULL;
|
| - if (kernel_node->IsProcedure()) {
|
| - function_node = Procedure::Cast(kernel_node)->function();
|
| - } else if (kernel_node->IsConstructor()) {
|
| - function_node = Constructor::Cast(kernel_node)->function();
|
| - } else if (kernel_node->IsFunctionNode()) {
|
| - function_node = FunctionNode::Cast(kernel_node);
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| - }
|
| -
|
| Thread* thread = Thread::Current();
|
| Zone* zone_ = thread->zone();
|
| TranslationHelper helper(thread);
|
| @@ -6067,45 +2727,11 @@ RawObject* BuildParameterDescriptor(const Function& function) {
|
| helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data()));
|
| helper.SetCanonicalNames(
|
| TypedData::Handle(Z, script.kernel_canonical_names()));
|
| - DartTypeTranslator type_translator(&helper, NULL, true);
|
| - ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z,
|
| - &helper, &type_translator);
|
| -
|
| - const intptr_t positional_count =
|
| - function_node->positional_parameters().length();
|
| - const intptr_t param_count =
|
| - positional_count + function_node->named_parameters().length();
|
| - const Array& param_descriptor = Array::Handle(
|
| - Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld));
|
| - for (intptr_t i = 0; i < param_count; ++i) {
|
| - const intptr_t entry_start = i * Parser::kParameterEntrySize;
|
| -
|
| - VariableDeclaration* variable;
|
| - if (i < positional_count) {
|
| - variable = function_node->positional_parameters()[i];
|
| - } else {
|
| - variable = function_node->named_parameters()[i - positional_count];
|
| - }
|
| -
|
| - param_descriptor.SetAt(
|
| - entry_start + Parser::kParameterIsFinalOffset,
|
| - variable->IsFinal() ? Bool::True() : Bool::False());
|
|
|
| - if (variable->initializer() != NULL) {
|
| - param_descriptor.SetAt(
|
| - entry_start + Parser::kParameterDefaultValueOffset,
|
| - constant_evaluator.EvaluateExpression(variable->initializer()));
|
| - } else {
|
| - param_descriptor.SetAt(
|
| - entry_start + Parser::kParameterDefaultValueOffset,
|
| - Object::null_instance());
|
| - }
|
| -
|
| - param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset,
|
| - /* Issue(28434): Missing parameter metadata. */
|
| - Object::null_instance());
|
| - }
|
| - return param_descriptor.raw();
|
| + StreamingFlowGraphBuilder streaming_flow_graph_builder(
|
| + &helper, zone_, script.kernel_data(), script.kernel_data_size());
|
| + return streaming_flow_graph_builder.BuildParameterDescriptor(
|
| + function.kernel_offset());
|
| } else {
|
| Thread* thread = Thread::Current();
|
| Error& error = Error::Handle();
|
|
|