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