Chromium Code Reviews| Index: runtime/vm/kernel_to_il.cc |
| diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc |
| index 2d9c2d1869f321cedbb3811463016407a91df8b4..f39bd6e10dcc68a41e2a719d7d31228a5c3b8c16 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,578 +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 kNumArgs = 1; |
| - const int kNumExtraArgs = 1; |
| - const int num_arguments = kNumArgs + kNumExtraArgs; |
| - const Array& arg_values = |
| - Array::Handle(Z, Array::New(num_arguments, Heap::kOld)); |
| - Instance& instance = Instance::Handle(Z); |
| - if (!constructor.IsFactory()) { |
| - instance = Instance::New(type_class, Heap::kOld); |
| - if (!type_arguments.IsNull()) { |
| - ASSERT(type_arguments.IsInstantiated()); |
| - instance.SetTypeArguments( |
| - TypeArguments::Handle(Z, type_arguments.Canonicalize())); |
| - } |
| - arg_values.SetAt(0, instance); |
| - } else { |
| - // Prepend type_arguments to list of arguments to factory. |
| - ASSERT(type_arguments.IsZoneHandle()); |
| - arg_values.SetAt(0, type_arguments); |
| - } |
| - arg_values.SetAt((0 + kNumExtraArgs), argument); |
| - const Array& args_descriptor = Array::Handle( |
| - Z, ArgumentsDescriptor::New(num_arguments, Object::empty_array())); |
| - const Object& result = Object::Handle( |
| - Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor)); |
| - ASSERT(!result.IsError()); |
| - if (constructor.IsFactory()) { |
| - // The factory method returns the allocated object. |
| - instance ^= result.raw(); |
| - } |
| - return H.Canonicalize(instance); |
| -} |
| - |
| - |
| -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 Array& args_descriptor = |
| - Array::Handle(Z, ArgumentsDescriptor::New(arguments.Length(), names)); |
| - const Object& result = Object::Handle( |
| - Z, DartEntry::InvokeFunction(function, arguments, args_descriptor)); |
| - if (result.IsError()) { |
| - H.ReportError(Error::Cast(result), "error evaluating constant constructor"); |
| - } |
| - return result; |
| -} |
| - |
| FlowGraphBuilder::FlowGraphBuilder( |
| - TreeNode* node, |
| + intptr_t kernel_offset, |
| ParsedFunction* parsed_function, |
| const ZoneGrowableArray<const ICData*>& ic_data_array, |
| InlineExitCollector* exit_collector, |
| @@ -1263,7 +660,7 @@ FlowGraphBuilder::FlowGraphBuilder( |
| intptr_t first_block_id) |
| : translation_helper_(Thread::Current()), |
| zone_(translation_helper_.zone()), |
| - node_(node), |
| + kernel_offset_(kernel_offset), |
| parsed_function_(parsed_function), |
| osr_id_(osr_id), |
| ic_data_array_(ic_data_array), |
| @@ -1288,7 +685,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())); |
| @@ -1343,9 +739,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); |
| @@ -1372,11 +766,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; |
| @@ -1393,11 +782,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 = |
| @@ -1468,8 +852,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(); |
| @@ -2392,424 +1775,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(); |
| - |
| - body = instructions + body; |
| - context_depth_ = current_context_depth; |
| - } |
| - |
| - if (NeedsDebugStepCheck(dart_function, function->position())) { |
| - // 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()); |
| - } |
| - body = DebugStepCheck(check_pos) + body; |
| - } |
| - |
| - 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: |
| @@ -2831,8 +1838,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: |
| @@ -2844,8 +1850,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: |
| @@ -2865,8 +1870,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(); |
| @@ -2878,8 +1882,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(); |
| @@ -2891,8 +1894,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); |
| @@ -2905,8 +1907,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); |
| @@ -2919,8 +1920,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); |
| @@ -2941,82 +1941,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; |
| @@ -3064,19 +1988,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) { |
| if (I->type_checks()) { |
| @@ -3220,58 +2131,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 |
| @@ -3460,47 +2319,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()); |
| } |
| @@ -3515,171 +2333,6 @@ JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { |
| return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex()); |
| } |
| - |
| -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); |
| @@ -3704,54 +2357,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); |
| @@ -4051,1959 +2656,38 @@ 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) { |
| + // TODO(jensj) |
|
Kevin Millikin (Google)
2017/06/12 12:01:51
TODO what?
jensj
2017/06/13 13:42:14
(as below)
|
| + 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); |
| + 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 { |
| - 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. |
| - ASSERT(target.AreValidArguments(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); |
| - } 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), 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(); |
| - |
| - // TODO(27590): Generic closures need type arguments. |
| - |
| - // 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(); |
| - } else { |
| - Thread* thread = Thread::Current(); |
| - Error& error = Error::Handle(); |
| - error = thread->sticky_error(); |
| - thread->clear_sticky_error(); |
| - return error.raw(); |
| + Thread* thread = Thread::Current(); |
| + Error& error = Error::Handle(); |
| + error = thread->sticky_error(); |
| + thread->clear_sticky_error(); |
| + return error.raw(); |
| } |
| } |
| RawObject* BuildParameterDescriptor(const Function& function) { |
| + // TODO(jensj) |
|
Kevin Millikin (Google)
2017/06/12 12:01:51
TODO what?
jensj
2017/06/13 13:42:14
Should have been
```
// TODO(jensj): Delete this
|
| 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); |
| @@ -6013,45 +2697,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(); |