Index: runtime/vm/kernel_binary_flowgraph.cc |
diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc |
index c88ddce65eb74777894c05761bfd4fd69d1c7b92..adcfcec719e3b803ee48ddef5a1239653079e14e 100644 |
--- a/runtime/vm/kernel_binary_flowgraph.cc |
+++ b/runtime/vm/kernel_binary_flowgraph.cc |
@@ -4,6 +4,7 @@ |
#include "vm/kernel_binary_flowgraph.h" |
+#include "vm/compiler.h" |
#include "vm/longjump.h" |
#include "vm/object_store.h" |
@@ -54,27 +55,6 @@ StreamingScopeBuilder::~StreamingScopeBuilder() { |
delete builder_; |
} |
-void StreamingScopeBuilder::DiscoverEnclosingElements( |
- Zone* zone, |
- const Function& function, |
- Function* outermost_function, |
- intptr_t* outermost_kernel_offset, |
- intptr_t* parent_class_offset) { |
- // 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(); |
- } |
- |
- if (outermost_function->kernel_function() != NULL) { |
- *outermost_kernel_offset = |
- static_cast<TreeNode*>(outermost_function->kernel_function()) |
- ->kernel_offset(); |
- *parent_class_offset = GetParentOffset(*outermost_kernel_offset); |
- } |
-} |
- |
ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
if (result_ != NULL) return result_; |
@@ -91,16 +71,18 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
Function& outermost_function = Function::Handle(Z); |
intptr_t outermost_kernel_offset = -1; |
intptr_t parent_class_offset = -1; |
- DiscoverEnclosingElements(Z, function, &outermost_function, |
- &outermost_kernel_offset, &parent_class_offset); |
+ builder_->DiscoverEnclosingElements(Z, function, &outermost_function, |
+ &outermost_kernel_offset, |
+ &parent_class_offset); |
// Use [klass]/[kernel_class] as active class. Type parameters will get |
// resolved via [kernel_class] unless we are nested inside a static factory |
// in which case we will use [member]. |
intptr_t class_type_parameters = 0; |
intptr_t class_type_parameters_offset_start = -1; |
if (parent_class_offset > 0) { |
- GetTypeParameterInfoForClass(parent_class_offset, &class_type_parameters, |
- &class_type_parameters_offset_start); |
+ builder_->GetTypeParameterInfoForClass(parent_class_offset, |
+ &class_type_parameters, |
+ &class_type_parameters_offset_start); |
} |
ActiveClassScope active_class_scope(&active_class_, class_type_parameters, |
class_type_parameters_offset_start, |
@@ -110,7 +92,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
bool is_factory_procedure = false; |
intptr_t member_type_parameters = 0; |
intptr_t member_type_parameters_offset_start = -1; |
- GetTypeParameterInfoForPossibleProcedure( |
+ builder_->GetTypeParameterInfoForPossibleProcedure( |
outermost_kernel_offset, &member_is_procedure, &is_factory_procedure, |
&member_type_parameters, &member_type_parameters_offset_start); |
@@ -144,27 +126,10 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
case RawFunction::kSetterFunction: |
case RawFunction::kConstructor: { |
const Tag tag = builder_->PeekTag(); |
- if (tag == kProcedure) { |
- Tag has_function_node = ReadProcedureUntilFunctionNode( |
- &unused_word, &unused_intptr); // read first part of procedure. |
- if (has_function_node == kNothing) { |
- // Running a procedure without a function node doesn't make sense. |
- UNREACHABLE(); |
- } |
- // Now at start of FunctionNode. |
- } else if (tag == kConstructor) { |
- // read first part of constructor. |
- parent_offset = ReadConstructorUntilFunctionNode(); |
- // Now at start of FunctionNode. |
- // Notice that we also have a list of initializers after that! |
- } else if (tag == kFunctionNode) { |
- // Already at start of FunctionNode. |
- } else { |
- UNREACHABLE(); |
- } |
+ parent_offset = builder_->ReadUntilFunctionNode(); |
word async_marker_word; |
- ReadFunctionNodeUntilTypeParameters( |
- &async_marker_word, |
+ builder_->ReadFunctionNodeUntilTypeParameters( |
+ &unused_tokenposition, &unused_tokenposition, &async_marker_word, |
&unused_word); // read first part of function node. |
current_function_async_marker_ = |
static_cast<FunctionNode::AsyncMarker>(async_marker_word); |
@@ -193,7 +158,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
if (tag == kConstructor) { |
ASSERT(parent_offset >= 0); |
AlternativeReadingScope alt(builder_->reader_, parent_offset); |
- ReadClassUntilFields(); // read first part of class. |
+ builder_->ReadClassUntilFields(); // read first part of class. |
intptr_t list_length = |
builder_->ReadListLength(); // read fields list length. |
for (intptr_t i = 0; i < list_length; i++) { |
@@ -201,12 +166,14 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
TokenPosition position; |
TokenPosition end_position; |
word flags; |
- ReadFieldUntilAnnotation(&position, &end_position, &flags, |
- &unused_intptr); |
+ builder_->ReadFieldUntilAnnotation(&unused_nameindex, &position, |
+ &end_position, &flags, |
+ &unused_intptr); |
bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; |
builder_->SkipListOfExpressions(); // read annotations. |
builder_->SkipDartType(); // read type. |
- Tag initializer_tag = builder_->ReadTag(); |
+ Tag initializer_tag = |
+ builder_->ReadTag(); // read first part of initializer. |
if (!is_static && initializer_tag == kSomething) { |
EnterScope(field_offset); |
VisitExpression(); // read initializer. |
@@ -226,6 +193,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
// Continue reading FunctionNode. |
builder_->SkipTypeParametersList(); // read type_parameters. |
+ builder_->ReadUInt(); // read total parameter count. |
builder_->ReadUInt(); // read required_parameter_count. |
AddPositionalAndNamedParameters( |
pos); // read positional_parameters and named_parameters. |
@@ -319,40 +287,6 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
return result_; |
} |
-intptr_t StreamingScopeBuilder::GetParentOffset(intptr_t offset) { |
- AlternativeReadingScope alt(builder_->reader_, offset); |
- |
- Tag tag = builder_->PeekTag(); |
- intptr_t parent_offset = -1; |
- switch (tag) { |
- case kConstructor: |
- return ReadConstructorUntilFunctionNode(); |
- case kProcedure: |
- ReadProcedureUntilFunctionNode( |
- &unused_word, &parent_offset); // read first part of procedure. |
- return parent_offset; |
- case kField: |
- ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, |
- &unused_word, &parent_offset); |
- return parent_offset; |
- default: |
- UNIMPLEMENTED(); |
- return -1; |
- } |
-} |
- |
-void StreamingScopeBuilder::GetTypeParameterInfoForClass( |
- intptr_t class_offset, |
- intptr_t* type_paremeter_counts, |
- intptr_t* type_paremeter_offset) { |
- AlternativeReadingScope alt(builder_->reader_, class_offset); |
- |
- ReadClassUntilTypeParameters(); |
- *type_paremeter_counts = |
- builder_->ReadListLength(); // read type_parameters list length. |
- *type_paremeter_offset = builder_->ReaderOffset(); |
-} |
- |
void StreamingScopeBuilder::VisitNode() { |
Tag tag = builder_->PeekTag(); |
switch (tag) { |
@@ -374,37 +308,25 @@ void StreamingScopeBuilder::VisitNode() { |
} |
} |
-intptr_t StreamingScopeBuilder::ReadConstructorUntilFunctionNode() { |
- Tag tag = builder_->ReadTag(); |
- ASSERT(tag == kConstructor); |
- builder_->SkipCanonicalNameReference(); // read canonical name reference. |
- builder_->ReadPosition(); // read position. |
- builder_->ReadPosition(); // read end position. |
- builder_->ReadFlags(); // read flags. |
- intptr_t parent_offset = builder_->ReadUInt(); // parent class binary offset. |
- builder_->SkipName(); // read name. |
- builder_->SkipListOfExpressions(); // read annotations. |
- return parent_offset; |
-} |
- |
void StreamingScopeBuilder::VisitConstructor() { |
// Field initializers that come from non-static field declarations are |
// compiled as if they appear in the constructor initializer list. This is |
// important for closure-valued field initializers because the VM expects the |
// corresponding closure functions to appear as if they were nested inside the |
// constructor. |
- intptr_t parent_offset = ReadConstructorUntilFunctionNode(); |
+ intptr_t parent_offset = builder_->ReadConstructorUntilFunctionNode(); |
ASSERT(parent_offset >= 0); |
{ |
AlternativeReadingScope alt(builder_->reader_, parent_offset); |
- ReadClassUntilFields(); // read first part of class. |
+ builder_->ReadClassUntilFields(); // read first part of class. |
intptr_t list_length = |
builder_->ReadListLength(); // read fields list length. |
for (intptr_t i = 0; i < list_length; i++) { |
word flags; |
- ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, |
- &flags, &unused_intptr); |
+ builder_->ReadFieldUntilAnnotation( |
+ &unused_nameindex, &unused_tokenposition, &unused_tokenposition, |
+ &flags, &unused_intptr); |
bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; |
builder_->SkipListOfExpressions(); // read annotations. |
builder_->SkipDartType(); // read type. |
@@ -427,34 +349,17 @@ void StreamingScopeBuilder::VisitConstructor() { |
} |
void StreamingScopeBuilder::VisitProcedure() { |
- Tag function_node = ReadProcedureUntilFunctionNode( |
+ Tag function_node = builder_->ReadProcedureUntilFunctionNode( |
&unused_word, &unused_intptr); // read first part of procedure. |
if (function_node == kSomething) { |
VisitFunctionNode(); |
} |
} |
-void StreamingScopeBuilder::ReadFieldUntilAnnotation( |
- TokenPosition* position, |
- TokenPosition* end_position, |
- word* flags, |
- intptr_t* parent_offset) { |
- Tag tag = builder_->ReadTag(); |
- ASSERT(tag == kField); |
- |
- builder_->SkipCanonicalNameReference(); // read canonical_name. |
- *position = builder_->ReadPosition(); // read position. |
- *end_position = builder_->ReadPosition(); // read end position. |
- *flags = builder_->ReadFlags(); // read flags. |
- *parent_offset = builder_->ReadUInt(); // read parent class binary offset. |
- builder_->SkipName(); // read name. |
- builder_->ReadUInt(); // source_uri_index. |
-} |
- |
void StreamingScopeBuilder::VisitField() { |
- ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, |
- &unused_intptr, |
- &unused_word); // read first part of field. |
+ builder_->ReadFieldUntilAnnotation( |
+ &unused_nameindex, &unused_tokenposition, &unused_tokenposition, |
+ &unused_intptr, &unused_word); // read first part of field. |
builder_->SkipListOfExpressions(); // read annotations. |
VisitDartType(); // read type. |
Tag tag = builder_->ReadTag(); // read initializer (part 1). |
@@ -463,98 +368,12 @@ void StreamingScopeBuilder::VisitField() { |
} |
} |
-Tag StreamingScopeBuilder::ReadProcedureUntilFunctionNode( |
- word* kind, |
- intptr_t* parent_offset) { |
- Tag tag = builder_->ReadTag(); // read tag. |
- ASSERT(tag == kProcedure); |
- builder_->SkipCanonicalNameReference(); // read canonical name reference. |
- builder_->ReadPosition(); // read position. |
- builder_->ReadPosition(); // read end position. |
- *kind = builder_->ReadByte(); // read kind. |
- builder_->ReadFlags(); // read flags. |
- *parent_offset = builder_->ReadUInt(); // read parent class binary offset. |
- builder_->SkipName(); // read name, |
- builder_->ReadUInt(); // read source_uri_index. |
- builder_->SkipListOfExpressions(); // read annotations. |
- return builder_->ReadTag(); // read tag for optional function node. |
-} |
- |
-void StreamingScopeBuilder::GetTypeParameterInfoForPossibleProcedure( |
- intptr_t outermost_kernel_offset, |
- bool* member_is_procedure, |
- bool* is_factory_procedure, |
- intptr_t* member_type_parameters, |
- intptr_t* member_type_parameters_offset_start) { |
- if (outermost_kernel_offset >= 0) { |
- AlternativeReadingScope alt(builder_->reader_, outermost_kernel_offset); |
- Tag tag = builder_->PeekTag(); |
- if (tag == kProcedure) { |
- *member_is_procedure = true; |
- |
- word kind; |
- tag = ReadProcedureUntilFunctionNode( |
- &kind, &unused_intptr); // read first part of procedure. |
- *is_factory_procedure = |
- static_cast<Procedure::ProcedureKind>(kind) == Procedure::kFactory; |
- |
- if (tag == kSomething) { |
- ReadFunctionNodeUntilTypeParameters( |
- &unused_word, &unused_word); // read first part of function node. |
- |
- intptr_t list_length = |
- builder_->ReadListLength(); // read type_parameters list length. |
- if (list_length > 0) { |
- *member_type_parameters = list_length; |
- *member_type_parameters_offset_start = builder_->ReaderOffset(); |
- } |
- } |
- } |
- } |
-} |
- |
-void StreamingScopeBuilder::ReadClassUntilTypeParameters() { |
- Tag class_tag = builder_->ReadTag(); |
- ASSERT(class_tag == kClass); |
- builder_->SkipCanonicalNameReference(); // read canonical_name. |
- builder_->ReadPosition(); // read position. |
- builder_->ReadBool(); // read is_abstract. |
- builder_->SkipStringReference(); // read name index. |
- builder_->ReadUInt(); // read source_uri_index. |
- builder_->SkipListOfExpressions(); // read annotations. |
-} |
- |
-void StreamingScopeBuilder::ReadClassUntilFields() { |
- ReadClassUntilTypeParameters(); |
- builder_->SkipTypeParametersList(); // read type_parameters. |
- Tag type_tag = builder_->ReadTag(); // read type (part 1). |
- if (type_tag == kSomething) { |
- builder_->SkipDartType(); // read type (part 2). |
- } |
- type_tag = builder_->ReadTag(); // read Mixed-in type (part 1). |
- if (type_tag == kSomething) { |
- builder_->SkipDartType(); // read Mixed-in type (part 2). |
- } |
- builder_->SkipListOfDartTypes(); // read implemented_classes. |
-} |
- |
-void StreamingScopeBuilder::ReadFunctionNodeUntilTypeParameters( |
- word* async_marker, |
- word* dart_async_marker) { |
- Tag tag = builder_->ReadTag(); // read tag. |
- ASSERT(tag == kFunctionNode); |
- |
- builder_->ReadPosition(); // read position. |
- builder_->ReadPosition(); // read end position. |
- *async_marker = builder_->ReadByte(); // read async marker. |
- *dart_async_marker = builder_->ReadByte(); // read dart async marker. |
-} |
- |
void StreamingScopeBuilder::VisitFunctionNode() { |
word async_marker_word; |
word dart_async_marker_word; |
- ReadFunctionNodeUntilTypeParameters(&async_marker_word, |
- &dart_async_marker_word); |
+ builder_->ReadFunctionNodeUntilTypeParameters( |
+ &unused_tokenposition, &unused_tokenposition, &async_marker_word, |
+ &dart_async_marker_word); |
FunctionNode::AsyncMarker async_marker = |
static_cast<FunctionNode::AsyncMarker>(async_marker_word); |
FunctionNode::AsyncMarker dart_async_marker = |
@@ -589,6 +408,7 @@ void StreamingScopeBuilder::VisitFunctionNode() { |
// Read (but don't visit) the positional and named parameters, because they've |
// already been added to the scope. |
+ builder_->ReadUInt(); // read total parameter count. |
builder_->ReadUInt(); // read required_parameter_count. |
builder_->SkipListOfVariableDeclarations(); // read list of positionals. |
@@ -643,11 +463,11 @@ void StreamingScopeBuilder::VisitInitializer() { |
VisitExpression(); // read value. |
return; |
case kSuperInitializer: |
- builder_->SkipCanonicalNameReference(); // read field_reference. |
+ builder_->SkipCanonicalNameReference(); // read target_reference. |
VisitArguments(); // read arguments. |
return; |
case kRedirectingInitializer: |
- builder_->SkipCanonicalNameReference(); // read field_reference. |
+ builder_->SkipCanonicalNameReference(); // read target_reference. |
VisitArguments(); // read arguments. |
return; |
case kLocalInitializer: |
@@ -1320,6 +1140,7 @@ void StreamingScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) { |
result_->function_scopes.Add(function_scope); |
} |
+ builder_->ReadUInt(); // read total parameter count. |
builder_->ReadUInt(); // read required_parameter_count. |
// read positional_parameters and named_parameters. |
AddPositionalAndNamedParameters(); |
@@ -1481,16 +1302,6 @@ void StreamingScopeBuilder::AddSwitchVariable() { |
} |
} |
-StringIndex StreamingScopeBuilder::GetNameFromVariableDeclaration( |
- intptr_t kernel_offset) { |
- // Temporarily go to the variable declaration, read the name. |
- AlternativeReadingScope alt(builder_->reader_, kernel_offset); |
- builder_->ReadPosition(); // read position. |
- builder_->ReadPosition(); // read equals position. |
- builder_->ReadFlags(); // read flags. |
- return builder_->ReadStringReference(); // read name index. |
-} |
- |
void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offest) { |
LocalVariable* variable = result_->locals.Lookup(declaration_binary_offest); |
if (variable == NULL) { |
@@ -1501,7 +1312,7 @@ void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offest) { |
ASSERT(current_function_scope_->parent() != NULL); |
StringIndex var_name = |
- GetNameFromVariableDeclaration(declaration_binary_offest); |
+ builder_->GetNameFromVariableDeclaration(declaration_binary_offest); |
const dart::String& name = H.DartSymbol(var_name); |
variable = current_function_scope_->parent()->LookupVariable(name, true); |
@@ -1586,6 +1397,17 @@ AbstractType& StreamingDartTypeTranslator::BuildType() { |
return dart::AbstractType::ZoneHandle(Z, result_.raw()); |
} |
+AbstractType& StreamingDartTypeTranslator::BuildTypeWithoutFinalization() { |
+ bool saved_finalize = finalize_; |
+ finalize_ = false; |
+ BuildTypeInternal(); |
+ finalize_ = saved_finalize; |
+ |
+ // We return a new `ZoneHandle` here on purpose: The intermediate language |
+ // instructions do not make a copy of the handle, so we do it. |
+ return dart::AbstractType::ZoneHandle(Z, result_.raw()); |
+} |
+ |
AbstractType& StreamingDartTypeTranslator::BuildVariableType() { |
AbstractType& abstract_type = BuildType(); |
@@ -2189,7 +2011,6 @@ void StreamingConstantEvaluator::EvaluateStaticGet() { |
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)) { |
@@ -2590,112 +2411,1195 @@ RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall( |
instance.SetTypeArguments( |
TypeArguments::Handle(Z, type_arguments.Canonicalize())); |
} |
- arg_values.SetAt(0, instance); |
+ 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); |
+} |
+ |
+const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments( |
+ const Function& target, |
+ dart::Class* target_klass) { |
+ intptr_t types_count = builder_->ReadListLength(); // read types count. |
+ |
+ const TypeArguments* type_arguments = NULL; |
+ if (types_count > 0) { |
+ type_arguments = &T.BuildInstantiatedTypeArguments( |
+ *target_klass, types_count); // read types. |
+ |
+ if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { |
+ H.ReportError("Type must be constant in const constructor."); |
+ } |
+ } else if (target.IsFactory() && type_arguments == NULL) { |
+ // All factories take a type arguments vector as first argument (independent |
+ // of whether the class is generic or not). |
+ type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null()); |
+ } |
+ return type_arguments; |
+} |
+ |
+bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() { |
+ EvaluateExpression(builder_->ReaderOffset(), false); |
+ AssertBoolInCheckedMode(); |
+ return result_.raw() == Bool::True().raw(); |
+} |
+ |
+bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset, |
+ Instance* value) { |
+ if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return false; |
+ |
+ const Function& function = builder_->parsed_function()->function(); |
+ if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { |
+ // Don't cache constants in initializer expressions. They get |
+ // evaluated only once. |
+ return false; |
+ } |
+ |
+ bool is_present = false; |
+ ASSERT(!script_.InVMHeap()); |
+ if (script_.compile_time_constants() == Array::null()) { |
+ return false; |
+ } |
+ KernelConstantsMap constants(script_.compile_time_constants()); |
+ *value ^= constants.GetOrNull(kernel_offset, &is_present); |
+ // Mutator compiler thread may add constants while background compiler |
+ // is running, and thus change the value of 'compile_time_constants'; |
+ // do not assert that 'compile_time_constants' has not changed. |
+ constants.Release(); |
+ if (FLAG_compiler_stats && is_present) { |
+ ++H.thread()->compiler_stats()->num_const_cache_hits; |
+ } |
+ return is_present; |
+} |
+ |
+ |
+void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset, |
+ const Instance& value) { |
+ ASSERT(Thread::Current()->IsMutatorThread()); |
+ |
+ if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return; |
+ |
+ const Function& function = builder_->parsed_function()->function(); |
+ if (function.kind() == RawFunction::kImplicitStaticFinalGetter) { |
+ // Don't cache constants in initializer expressions. They get |
+ // evaluated only once. |
+ return; |
+ } |
+ const intptr_t kInitialConstMapSize = 16; |
+ ASSERT(!script_.InVMHeap()); |
+ if (script_.compile_time_constants() == Array::null()) { |
+ const Array& array = Array::Handle( |
+ HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew)); |
+ script_.set_compile_time_constants(array); |
+ } |
+ KernelConstantsMap constants(script_.compile_time_constants()); |
+ constants.InsertNewOrGetValue(kernel_offset, value); |
+ script_.set_compile_time_constants(constants.Release()); |
+} |
+ |
+void StreamingFlowGraphBuilder::DiscoverEnclosingElements( |
+ Zone* zone, |
+ const Function& function, |
+ Function* outermost_function, |
+ intptr_t* outermost_kernel_offset, |
+ intptr_t* parent_class_offset) { |
+ // 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(); |
+ } |
+ |
+ if (outermost_function->kernel_offset() > 0) { |
+ *outermost_kernel_offset = outermost_function->kernel_offset(); |
+ *parent_class_offset = GetParentOffset(*outermost_kernel_offset); |
+ } |
+} |
+ |
+intptr_t StreamingFlowGraphBuilder::GetParentOffset(intptr_t offset) { |
+ AlternativeReadingScope alt(reader_, offset); |
+ |
+ Tag tag = PeekTag(); |
+ intptr_t parent_offset = -1; |
+ switch (tag) { |
+ case kConstructor: |
+ return ReadConstructorUntilFunctionNode(); |
+ case kProcedure: |
+ ReadProcedureUntilFunctionNode( |
+ &unused_word, &parent_offset); // read first part of procedure. |
+ return parent_offset; |
+ case kField: |
+ ReadFieldUntilAnnotation(&unused_nameindex, &unused_tokenposition, |
+ &unused_tokenposition, &unused_word, |
+ &parent_offset); |
+ return parent_offset; |
+ default: |
+ UNIMPLEMENTED(); |
+ return -1; |
+ } |
+} |
+ |
+void StreamingFlowGraphBuilder::GetTypeParameterInfoForClass( |
+ intptr_t class_offset, |
+ intptr_t* type_paremeter_counts, |
+ intptr_t* type_paremeter_offset) { |
+ AlternativeReadingScope alt(reader_, class_offset); |
+ |
+ ReadClassUntilTypeParameters(); |
+ *type_paremeter_counts = |
+ ReadListLength(); // read type_parameters list length. |
+ *type_paremeter_offset = ReaderOffset(); |
+} |
+ |
+void StreamingFlowGraphBuilder::ReadClassUntilFields() { |
+ ReadClassUntilTypeParameters(); |
+ SkipTypeParametersList(); // read type_parameters. |
+ Tag type_tag = ReadTag(); // read type (part 1). |
+ if (type_tag == kSomething) { |
+ SkipDartType(); // read type (part 2). |
+ } |
+ type_tag = ReadTag(); // read Mixed-in type (part 1). |
+ if (type_tag == kSomething) { |
+ SkipDartType(); // read Mixed-in type (part 2). |
+ } |
+ SkipListOfDartTypes(); // read implemented_classes. |
+} |
+ |
+void StreamingFlowGraphBuilder::ReadClassUntilTypeParameters() { |
+ Tag class_tag = ReadTag(); |
+ ASSERT(class_tag == kClass); |
+ SkipCanonicalNameReference(); // read canonical_name. |
+ ReadPosition(); // read position. |
+ ReadBool(); // read is_abstract. |
+ SkipStringReference(); // read name index. |
+ ReadUInt(); // read source_uri_index. |
+ SkipListOfExpressions(); // read annotations. |
+} |
+ |
+intptr_t StreamingFlowGraphBuilder::ReadConstructorUntilFunctionNode() { |
+ Tag tag = ReadTag(); |
+ ASSERT(tag == kConstructor); |
+ SkipCanonicalNameReference(); // read canonical name reference. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read end position. |
+ ReadFlags(); // read flags. |
+ intptr_t parent_offset = ReadUInt(); // parent class binary offset. |
+ SkipName(); // read name. |
+ SkipListOfExpressions(); // read annotations. |
+ return parent_offset; |
+} |
+ |
+Tag StreamingFlowGraphBuilder::ReadProcedureUntilFunctionNode( |
+ word* kind, |
+ intptr_t* parent_offset) { |
+ Tag tag = ReadTag(); // read tag. |
+ ASSERT(tag == kProcedure); |
+ SkipCanonicalNameReference(); // read canonical name reference. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read end position. |
+ *kind = ReadByte(); // read kind. |
+ ReadFlags(); // read flags. |
+ *parent_offset = ReadUInt(); // read parent class binary offset. |
+ SkipName(); // read name, |
+ ReadUInt(); // read source_uri_index. |
+ SkipListOfExpressions(); // read annotations. |
+ return ReadTag(); // read tag for optional function node. |
+} |
+ |
+void StreamingFlowGraphBuilder::ReadFieldUntilAnnotation( |
+ NameIndex* canonical_name, |
+ TokenPosition* position, |
+ TokenPosition* end_position, |
+ word* flags, |
+ intptr_t* parent_offset) { |
+ Tag tag = ReadTag(); |
+ ASSERT(tag == kField); |
+ |
+ *canonical_name = ReadCanonicalNameReference(); // read canonical_name. |
+ *position = ReadPosition(); // read position. |
+ *end_position = ReadPosition(); // read end position. |
+ *flags = ReadFlags(); // read flags. |
+ *parent_offset = ReadUInt(); // read parent class binary offset. |
+ SkipName(); // read name. |
+ ReadUInt(); // source_uri_index. |
+} |
+ |
+void StreamingFlowGraphBuilder::GetTypeParameterInfoForPossibleProcedure( |
+ intptr_t outermost_kernel_offset, |
+ bool* member_is_procedure, |
+ bool* is_factory_procedure, |
+ intptr_t* member_type_parameters, |
+ intptr_t* member_type_parameters_offset_start) { |
+ if (outermost_kernel_offset >= 0) { |
+ AlternativeReadingScope alt(reader_, outermost_kernel_offset); |
+ Tag tag = PeekTag(); |
+ if (tag == kProcedure) { |
+ *member_is_procedure = true; |
+ |
+ word kind; |
+ tag = ReadProcedureUntilFunctionNode( |
+ &kind, &unused_intptr); // read first part of procedure. |
+ *is_factory_procedure = |
+ static_cast<Procedure::ProcedureKind>(kind) == Procedure::kFactory; |
+ |
+ if (tag == kSomething) { |
+ ReadFunctionNodeUntilTypeParameters( |
+ &unused_tokenposition, &unused_tokenposition, &unused_word, |
+ &unused_word); // read first part of function node. |
+ |
+ intptr_t list_length = |
+ ReadListLength(); // read type_parameters list length. |
+ if (list_length > 0) { |
+ *member_type_parameters = list_length; |
+ *member_type_parameters_offset_start = ReaderOffset(); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+void StreamingFlowGraphBuilder::ReadFunctionNodeUntilTypeParameters( |
+ TokenPosition* position, |
+ TokenPosition* end_position, |
+ word* async_marker, |
+ word* dart_async_marker) { |
+ Tag tag = ReadTag(); // read tag. |
+ ASSERT(tag == kFunctionNode); |
+ |
+ *position = ReadPosition(); // read position. |
+ *end_position = ReadPosition(); // read end position. |
+ *async_marker = ReadByte(); // read async marker. |
+ *dart_async_marker = ReadByte(); // read dart async marker. |
+} |
+ |
+intptr_t StreamingFlowGraphBuilder::ReadUntilFunctionNode() { |
+ const Tag tag = PeekTag(); |
+ if (tag == kProcedure) { |
+ Tag has_function_node = ReadProcedureUntilFunctionNode( |
+ &unused_word, &unused_intptr); // read first part of procedure. |
+ if (has_function_node == kNothing) { |
+ // Running a procedure without a function node doesn't make sense. |
+ UNREACHABLE(); |
+ } |
+ return -1; |
+ // Now at start of FunctionNode. |
+ } else if (tag == kConstructor) { |
+ // read first part of constructor. |
+ return ReadConstructorUntilFunctionNode(); |
+ // Now at start of FunctionNode. |
+ // Notice that we also have a list of initializers after that! |
+ } else if (tag == kFunctionNode) { |
+ // Already at start of FunctionNode. |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ return -1; |
+} |
+ |
+StringIndex StreamingFlowGraphBuilder::GetNameFromVariableDeclaration( |
+ intptr_t kernel_offset) { |
+ // Temporarily go to the variable declaration, read the name. |
+ AlternativeReadingScope alt(reader_, kernel_offset); |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ ReadFlags(); // read flags. |
+ return ReadStringReference(); // read name index. |
+} |
+ |
+FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfStaticFieldInitializer() { |
+ TokenPosition position; |
+ TokenPosition end_position; |
+ word flags; |
+ ReadFieldUntilAnnotation(&unused_nameindex, &position, &end_position, &flags, |
+ &unused_intptr); |
+ bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; |
+ bool is_const = (flags & Field::kFlagConst) == Field::kFlagConst; |
+ ASSERT(is_static); |
+ |
+ SkipListOfExpressions(); // read annotations. |
+ SkipDartType(); // read type. |
+ Tag initializer_tag = ReadTag(); // read first part of initializer. |
+ if (initializer_tag != kSomething) { |
+ UNREACHABLE(); |
+ } |
+ |
+ TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); |
+ flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( |
+ *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); |
+ |
+ Fragment body(normal_entry); |
+ body += flow_graph_builder_->CheckStackOverflowInPrologue(); |
+ if (is_const) { |
+ // this will (potentially) read the initializer, but reset the position. |
+ body += Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); |
+ SkipExpression(); // read the initializer. |
+ } else { |
+ body += BuildExpression(); // read initializer. |
+ } |
+ body += Return(TokenPosition::kNoSource); |
+ |
+ return new (Z) |
+ FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, |
+ flow_graph_builder_->next_block_id_ - 1); |
+} |
+ |
+FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldAccessor( |
+ LocalVariable* setter_value) { |
+ NameIndex canonical_name; |
+ ReadFieldUntilAnnotation(&canonical_name, &unused_tokenposition, |
+ &unused_tokenposition, &unused_word, &unused_intptr); |
+ SkipListOfExpressions(); // read annotations. |
+ SkipDartType(); // read type. |
+ Tag initializer_tag = ReadTag(); // read first part of initializer. |
+ |
+ 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(canonical_name)); |
+ |
+ TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); |
+ flow_graph_builder_->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 += flow_graph_builder_->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 += flow_graph_builder_->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. |
+ ASSERT(initializer_tag == kSomething); |
+ // this will (potentially) read the initializer, but reset the position. |
+ body += Constant(constant_evaluator_.EvaluateExpression(ReaderOffset())); |
+ SkipExpression(); // read the 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 += flow_graph_builder_->InitStaticField(field); |
+ body += Constant(field); |
+ body += LoadStaticField(); |
+ } |
+ body += Return(TokenPosition::kNoSource); |
+ |
+ return new (Z) |
+ FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, |
+ flow_graph_builder_->next_block_id_ - 1); |
+} |
+ |
+void StreamingFlowGraphBuilder::SetupDefaultParameterValues() { |
+ 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); |
+ |
+ AlternativeReadingScope alt(reader_); |
+ ReadFunctionNodeUntilTypeParameters( |
+ &unused_tokenposition, &unused_tokenposition, &unused_word, |
+ &unused_word); // read first part of function node. |
+ SkipTypeParametersList(); // read type_parameters. |
+ ReadUInt(); // read total parameter count. |
+ intptr_t required = ReadUInt(); // read required_parameter_count. |
+ |
+ if (parsed_function()->function().HasOptionalNamedParameters()) { |
+ // List of positional. |
+ intptr_t list_length = ReadListLength(); // read list length. |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ SkipVariableDeclaration(); // read ith variable declaration. |
+ } |
+ |
+ // List of named. |
+ list_length = ReadListLength(); // read list length. |
+ ASSERT(num_optional_parameters == list_length); |
+ ASSERT(!parsed_function()->function().HasOptionalPositionalParameters()); |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ Instance* default_value; |
+ |
+ // Read ith variable declaration |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ ReadFlags(); // read flags. |
+ SkipStringReference(); // read name index. |
+ SkipDartType(); // read type. |
+ Tag tag = ReadTag(); // read (first part of) initializer. |
+ if (tag == kSomething) { |
+ // this will (potentially) read the initializer, |
+ // but reset the position. |
+ default_value = |
+ &constant_evaluator_.EvaluateExpression(ReaderOffset()); |
+ SkipExpression(); // read (actual) initializer. |
+ } else { |
+ default_value = &Instance::ZoneHandle(Z, Instance::null()); |
+ } |
+ default_values->Add(default_value); |
+ } |
+ } else { |
+ // List of positional. |
+ intptr_t list_length = ReadListLength(); // read list length. |
+ ASSERT(list_length == required + num_optional_parameters); |
+ ASSERT(parsed_function()->function().HasOptionalPositionalParameters()); |
+ for (intptr_t i = 0; i < required; ++i) { |
+ SkipVariableDeclaration(); // read ith variable declaration. |
+ } |
+ for (intptr_t i = 0; i < num_optional_parameters; ++i) { |
+ Instance* default_value; |
+ |
+ // Read ith variable declaration |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ ReadFlags(); // read flags. |
+ SkipStringReference(); // read name index. |
+ SkipDartType(); // read type. |
+ Tag tag = ReadTag(); // read (first part of) initializer. |
+ if (tag == kSomething) { |
+ // this will (potentially) read the initializer, |
+ // but reset the position. |
+ default_value = |
+ &constant_evaluator_.EvaluateExpression(ReaderOffset()); |
+ SkipExpression(); // read (actual) initializer. |
+ } else { |
+ default_value = &Instance::ZoneHandle(Z, Instance::null()); |
+ } |
+ default_values->Add(default_value); |
+ } |
+ |
+ // List of named. |
+ list_length = ReadListLength(); // read list length. |
+ ASSERT(list_length == 0); |
+ } |
+ parsed_function()->set_default_parameter_values(default_values); |
+ } |
+} |
+ |
+Fragment StreamingFlowGraphBuilder::BuildFieldInitializer( |
+ NameIndex canonical_name) { |
+ dart::Field& field = |
+ dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name)); |
+ if (PeekTag() == kNullLiteral) { |
+ SkipExpression(); // read past the null literal. |
+ field.RecordStore(Object::null_object()); |
+ return Fragment(); |
+ } |
+ |
+ Fragment instructions; |
+ instructions += LoadLocal(scopes()->this_variable); |
+ instructions += BuildExpression(); |
+ instructions += flow_graph_builder_->StoreInstanceFieldGuarded(field, true); |
+ return instructions; |
+} |
+ |
+Fragment StreamingFlowGraphBuilder::BuildInitializers( |
+ intptr_t constructor_class_parent_offset) { |
+ Fragment instructions; |
+ |
+ // These come from: |
+ // class A { |
+ // var x = (expr); |
+ // } |
+ { |
+ AlternativeReadingScope alt(reader_, constructor_class_parent_offset); |
+ ReadClassUntilFields(); // read first part of class. |
+ intptr_t list_length = ReadListLength(); // read fields list length. |
+ |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ intptr_t field_offset = ReaderOffset(); |
+ NameIndex canonical_name; |
+ TokenPosition position; |
+ TokenPosition end_position; |
+ word flags; |
+ ReadFieldUntilAnnotation(&canonical_name, &position, &end_position, |
+ &flags, &unused_intptr); |
+ bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; |
+ SkipListOfExpressions(); // read annotations. |
+ SkipDartType(); // read type. |
+ Tag initializer_tag = ReadTag(); // read first part of initializer. |
+ if (!is_static && initializer_tag == kSomething) { |
+ EnterScope(field_offset); |
+ instructions += |
+ BuildFieldInitializer(canonical_name); // read initializer. |
+ ExitScope(field_offset); |
+ } else if (initializer_tag == kSomething) { |
+ SkipExpression(); // read initializer. |
+ } |
+ } |
+ } |
+ |
+ // These to come from: |
+ // class A { |
+ // var x; |
+ // var y; |
+ // A(this.x) : super(expr), y = (expr); |
+ // } |
+ { |
+ AlternativeReadingScope alt(reader_); |
+ SkipFunctionNode(); // read constructors function node. |
+ |
+ intptr_t list_length = ReadListLength(); // read initializers list length. |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ Tag tag = ReadTag(); |
+ switch (tag) { |
+ case kInvalidInitializer: |
+ UNIMPLEMENTED(); |
+ return Fragment(); |
+ case kFieldInitializer: { |
+ NameIndex canonical_name = |
+ ReadCanonicalNameReference(); // read field_reference. |
+ instructions += BuildFieldInitializer(canonical_name); // read value. |
+ break; |
+ } |
+ case kSuperInitializer: { |
+ NameIndex canonical_target = |
+ ReadCanonicalNameReference(); // read target_reference. |
+ |
+ instructions += LoadLocal(scopes()->this_variable); |
+ instructions += PushArgument(); |
+ |
+ // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); |
+ Array& argument_names = Array::ZoneHandle(Z); |
+ intptr_t argument_count; |
+ instructions += BuildArguments(&argument_names, |
+ &argument_count); // read arguments. |
+ argument_count += 1; |
+ |
+ const Function& target = Function::ZoneHandle( |
+ Z, H.LookupConstructorByKernelConstructor(canonical_target)); |
+ instructions += StaticCall(TokenPosition::kNoSource, target, |
+ argument_count, argument_names); |
+ instructions += Drop(); |
+ break; |
+ } |
+ case kRedirectingInitializer: { |
+ NameIndex canonical_target = |
+ ReadCanonicalNameReference(); // read target_reference. |
+ |
+ instructions += LoadLocal(scopes()->this_variable); |
+ instructions += PushArgument(); |
+ |
+ // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); |
+ Array& argument_names = Array::ZoneHandle(Z); |
+ intptr_t argument_count; |
+ instructions += BuildArguments(&argument_names, |
+ &argument_count); // read arguments. |
+ argument_count += 1; |
+ |
+ const Function& target = Function::ZoneHandle( |
+ Z, H.LookupConstructorByKernelConstructor(canonical_target)); |
+ instructions += StaticCall(TokenPosition::kNoSource, target, |
+ argument_count, argument_names); |
+ instructions += Drop(); |
+ break; |
+ } |
+ case kLocalInitializer: { |
+ // 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.) |
+ LocalVariable* variable = LookupVariable(ReaderOffset()); |
+ |
+ // Variable declaration |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ word flags = ReadFlags(); // read flags. |
+ ASSERT((flags & VariableDeclaration::kFlagConst) != |
+ VariableDeclaration::kFlagConst); |
+ SkipStringReference(); // read name index. |
+ SkipDartType(); // read type. |
+ Tag tag = ReadTag(); // read (first part of) initializer. |
+ if (tag != kSomething) { |
+ UNREACHABLE(); |
+ } |
+ |
+ instructions += BuildExpression(); // read initializer. |
+ instructions += StoreLocal(TokenPosition::kNoSource, variable); |
+ instructions += Drop(); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ } |
+ return instructions; |
+} |
+ |
+FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfImplicitClosureFunction( |
+ const Function& function) { |
+ const Function& target = Function::ZoneHandle(Z, function.parent_function()); |
+ |
+ TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); |
+ flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( |
+ *parsed_function(), normal_entry, Compiler::kNoOSRDeoptId); |
+ SetupDefaultParameterValues(); |
+ |
+ Fragment body(normal_entry); |
+ body += flow_graph_builder_->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 += flow_graph_builder_->LoadField(Context::variable_offset(0)); |
+ body += PushArgument(); |
+ } |
+ |
+ TokenPosition end_position; |
+ ReadFunctionNodeUntilTypeParameters( |
+ &unused_tokenposition, &end_position, &unused_word, |
+ &unused_word); // read first part of function node. |
+ SkipTypeParametersList(); // read type parameter list. |
+ ReadUInt(); // read total parameter count. |
+ ReadUInt(); // read required_parameter_count. |
+ |
+ // Positional. |
+ intptr_t positional_argument_count = ReadListLength(); |
+ for (intptr_t i = 0; i < positional_argument_count; ++i) { |
+ body += LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. |
+ body += PushArgument(); |
+ SkipVariableDeclaration(); // read ith variable. |
+ } |
+ |
+ // Named. |
+ intptr_t named_argument_count = ReadListLength(); |
+ 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) { |
+ body += |
+ LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. |
+ body += PushArgument(); |
+ argument_names.SetAt( |
+ i, H.DartSymbol(GetNameFromVariableDeclaration(ReaderOffset()))); |
+ SkipVariableDeclaration(); // read ith variable. |
+ } |
+ } |
+ |
+ // 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(end_position); |
+ |
+ return new (Z) |
+ FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, |
+ flow_graph_builder_->next_block_id_ - 1); |
+} |
+ |
+static bool IsGetMainClosure(const String& name) { |
+ if (name.Length() < 16) return false; |
+ const char* cstr = "_getMainClosure@"; |
+ for (intptr_t i = 0; i < 16; ++i) { |
+ if (name.CharAt(i) != cstr[i]) return false; |
+ } |
+ return true; |
+} |
+ |
+FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction( |
+ bool is_in_builtin_library_toplevel, |
+ intptr_t constructor_class_parent_offset) { |
+ const Function& dart_function = parsed_function()->function(); |
+ TargetEntryInstr* normal_entry = flow_graph_builder_->BuildTargetEntry(); |
+ flow_graph_builder_->graph_entry_ = new (Z) GraphEntryInstr( |
+ *parsed_function(), normal_entry, flow_graph_builder_->osr_id_); |
+ |
+ SetupDefaultParameterValues(); |
+ |
+ Fragment body; |
+ if (!dart_function.is_native()) |
+ body += flow_graph_builder_->CheckStackOverflowInPrologue(); |
+ intptr_t context_size = |
+ parsed_function()->node_sequence()->scope()->num_context_variables(); |
+ if (context_size > 0) { |
+ body += flow_graph_builder_->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 += flow_graph_builder_->StoreInstanceField( |
+ TokenPosition::kNoSource, |
+ Context::variable_offset(variable->index())); |
+ body += NullConstant(); |
+ body += StoreLocal(TokenPosition::kNoSource, parameter); |
+ body += Drop(); |
+ } |
+ } |
+ body += Drop(); // The context. |
+ } |
+ if (constructor_class_parent_offset > 0) { |
+ // 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. |
+ body += BuildInitializers(constructor_class_parent_offset); |
+ } |
+ |
+ TokenPosition position; |
+ ReadFunctionNodeUntilTypeParameters( |
+ &position, &unused_tokenposition, &unused_word, |
+ &unused_word); // read first part of function node. |
+ SkipTypeParametersList(); // read type parameter list. |
+ ReadUInt(); // read total parameter count |
+ ReadUInt(); // read required_parameter_count. |
+ intptr_t first_parameter_offset = -1; |
+ { |
+ AlternativeReadingScope alt(reader_); |
+ intptr_t list_length = ReadListLength(); // read number of positionals. |
+ if (list_length > 0) { |
+ first_parameter_offset = ReaderOffset(); |
+ } |
+ } |
+ // Current position: About to read list of positionals. |
+ |
+ // 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(first_parameter_offset); |
+ |
+ 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()) { |
+ // Positional. |
+ intptr_t list_length = ReadListLength(); |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ body += |
+ LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. |
+ body += CheckVariableTypeInCheckedMode(ReaderOffset()); |
+ body += Drop(); |
+ SkipVariableDeclaration(); // read ith variable. |
+ } |
+ |
+ // Named. |
+ list_length = ReadListLength(); |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ body += |
+ LoadLocal(LookupVariable(ReaderOffset())); // ith variable offset. |
+ body += CheckVariableTypeInCheckedMode(ReaderOffset()); |
+ body += Drop(); |
+ SkipVariableDeclaration(); // read ith variable. |
+ } |
} 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(); |
+ // Still skip past the parameters. |
+ SkipListOfVariableDeclarations(); // read list of positionals. |
+ SkipListOfVariableDeclarations(); // read list of named. |
} |
- return H.Canonicalize(instance); |
-} |
-const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments( |
- const Function& target, |
- dart::Class* target_klass) { |
- intptr_t types_count = builder_->ReadListLength(); // read types count. |
+ SkipDartType(); // read return type. |
- const TypeArguments* type_arguments = NULL; |
- if (types_count > 0) { |
- type_arguments = &T.BuildInstantiatedTypeArguments( |
- *target_klass, types_count); // read types. |
+ 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(); |
+ } |
+ |
+ bool has_body = ReadTag() == kSomething; // read first part of body. |
+ |
+ if (dart_function.is_native()) { |
+ body += flow_graph_builder_->NativeFunctionBody(first_parameter_offset, |
+ dart_function); |
+ } else if (has_body) { |
+ if (is_in_builtin_library_toplevel && |
+ IsGetMainClosure(dart::String::Handle(Z, dart_function.name()))) { |
+ body += BuildGetMainClosure(); |
+ } else { |
+ body += BuildStatement(); // read 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 = flow_graph_builder_->context_depth_; |
+ flow_graph_builder_->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; |
+ } |
- if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { |
- H.ReportError("Type must be constant in const constructor."); |
+ // Build comparison: |
+ // |
+ // if (:await_ctx_var == i) { |
+ // -> yield_continuations()[i] |
+ // } else ... |
+ // |
+ TargetEntryInstr* then; |
+ TargetEntryInstr* otherwise; |
+ dispatch += LoadLocal(scopes()->switch_variable); |
+ dispatch += IntConstant(i); |
+ dispatch += flow_graph_builder_->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; |
} |
- } 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()); |
+ body = dispatch; |
+ |
+ flow_graph_builder_->context_depth_ = current_context_depth; |
} |
- return type_arguments; |
-} |
-bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() { |
- EvaluateExpression(builder_->ReaderOffset(), false); |
- AssertBoolInCheckedMode(); |
- return result_.raw() == Bool::True().raw(); |
-} |
+ 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 = flow_graph_builder_->context_depth_; |
+ flow_graph_builder_->context_depth_ = |
+ scopes()->yield_jump_variable->owner()->context_level(); |
+ |
+ Fragment instructions; |
+ LocalScope* scope = parsed_function()->node_sequence()->scope(); |
-bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset, |
- Instance* value) { |
- if (builder_ == NULL) return false; |
+ const Function& target = Function::ZoneHandle( |
+ Z, I->object_store()->async_set_thread_stack_trace()); |
+ ASSERT(!target.IsNull()); |
- 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; |
- } |
+ // 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(); |
- bool is_present = false; |
- ASSERT(!script_.InVMHeap()); |
- if (script_.compile_time_constants() == Array::null()) { |
- return false; |
- } |
- KernelConstantsMap constants(script_.compile_time_constants()); |
- *value ^= constants.GetOrNull(kernel_offset, &is_present); |
- // Mutator compiler thread may add constants while background compiler |
- // is running, and thus change the value of 'compile_time_constants'; |
- // do not assert that 'compile_time_constants' has not changed. |
- constants.Release(); |
- if (FLAG_compiler_stats && is_present) { |
- ++H.thread()->compiler_stats()->num_const_cache_hits; |
+ // Call _asyncSetThreadStackTrace |
+ instructions += StaticCall(TokenPosition::kNoSource, target, 1); |
+ instructions += Drop(); |
+ |
+ // TODO(29737): This sequence should be generated in order. |
+ body = instructions + body; |
+ flow_graph_builder_->context_depth_ = current_context_depth; |
+ } |
+ |
+ if (NeedsDebugStepCheck(dart_function, position)) { |
+ const intptr_t current_context_depth = flow_graph_builder_->context_depth_; |
+ flow_graph_builder_->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 = position; |
+ ASSERT(check_pos.IsDebugPause()); |
+ } |
+ |
+ // TODO(29737): This sequence should be generated in order. |
+ body = DebugStepCheck(check_pos) + body; |
+ flow_graph_builder_->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 (flow_graph_builder_->osr_id_ != Compiler::kNoOSRDeoptId) { |
+ BitVector* block_marks = |
+ new (Z) BitVector(Z, flow_graph_builder_->next_block_id_); |
+ bool found = flow_graph_builder_->graph_entry_->PruneUnreachable( |
+ flow_graph_builder_->graph_entry_, NULL, flow_graph_builder_->osr_id_, |
+ block_marks); |
+ ASSERT(found); |
+ } |
+ return new (Z) |
+ FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_, |
+ flow_graph_builder_->next_block_id_ - 1); |
+} |
+ |
+Fragment StreamingFlowGraphBuilder::BuildGetMainClosure() { |
+ // _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()); |
+ const Instance& closure = |
+ Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure()); |
+ return Constant(closure) + Return(TokenPosition::kNoSource); |
+ } else { |
+ UNIMPLEMENTED(); |
+ } |
+ } else { |
+ UNIMPLEMENTED(); |
} |
- return is_present; |
+ return Fragment(); |
} |
+FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) { |
+ const Function& function = parsed_function()->function(); |
-void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset, |
- const Instance& value) { |
- ASSERT(Thread::Current()->IsMutatorThread()); |
- |
- if (builder_ == NULL) return; |
+ // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used |
+ // e.g. for type translation. |
+ const dart::Class& klass = |
+ dart::Class::Handle(zone_, parsed_function()->function().Owner()); |
+ bool is_in_builtin_library_toplevel = |
+ klass.library() == I->object_store()->builtin_library() && |
+ klass.IsTopLevel(); |
- 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); |
+ Function& outermost_function = Function::Handle(Z); |
+ intptr_t outermost_kernel_offset = -1; |
+ intptr_t parent_class_offset = -1; |
+ DiscoverEnclosingElements(Z, function, &outermost_function, |
+ &outermost_kernel_offset, &parent_class_offset); |
+ // Use [klass]/[kernel_class] as active class. Type parameters will get |
+ // resolved via [kernel_class] unless we are nested inside a static factory |
+ // in which case we will use [member]. |
+ intptr_t class_type_parameters = 0; |
+ intptr_t class_type_parameters_offset_start = -1; |
+ if (parent_class_offset > 0) { |
+ GetTypeParameterInfoForClass(parent_class_offset, &class_type_parameters, |
+ &class_type_parameters_offset_start); |
} |
- KernelConstantsMap constants(script_.compile_time_constants()); |
- constants.InsertNewOrGetValue(kernel_offset, value); |
- script_.set_compile_time_constants(constants.Release()); |
-} |
+ ActiveClassScope active_class_scope(active_class(), class_type_parameters, |
+ class_type_parameters_offset_start, |
+ &klass); |
+ |
+ bool member_is_procedure = false; |
+ bool is_factory_procedure = false; |
+ intptr_t member_type_parameters = 0; |
+ intptr_t member_type_parameters_offset_start = -1; |
+ GetTypeParameterInfoForPossibleProcedure( |
+ outermost_kernel_offset, &member_is_procedure, &is_factory_procedure, |
+ &member_type_parameters, &member_type_parameters_offset_start); |
+ |
+ ActiveMemberScope active_member(active_class(), member_is_procedure, |
+ is_factory_procedure, member_type_parameters, |
+ member_type_parameters_offset_start); |
+ |
+ // 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. |
+ set_scopes(parsed_function()->EnsureKernelScopes()); |
-Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) { |
SetOffset(kernel_offset); |
- return BuildExpression(); // read expression. |
+ |
+ switch (function.kind()) { |
+ case RawFunction::kClosureFunction: |
+ case RawFunction::kRegularFunction: |
+ case RawFunction::kGetterFunction: |
+ case RawFunction::kSetterFunction: { |
+ ReadUntilFunctionNode(); // read until function node. |
+ return function.IsImplicitClosureFunction() |
+ ? BuildGraphOfImplicitClosureFunction(function) |
+ : BuildGraphOfFunction(is_in_builtin_library_toplevel); |
+ } |
+ case RawFunction::kConstructor: { |
+ bool is_factory = function.IsFactory(); |
+ if (is_factory) { |
+ ReadUntilFunctionNode(); // read until function node. |
+ return BuildGraphOfFunction(is_in_builtin_library_toplevel); |
+ } else { |
+ // Constructor: Pass offset to parent class. |
+ return BuildGraphOfFunction( |
+ is_in_builtin_library_toplevel, |
+ ReadUntilFunctionNode()); // read until function node. |
+ } |
+ } |
+ case RawFunction::kImplicitGetter: |
+ case RawFunction::kImplicitStaticFinalGetter: |
+ case RawFunction::kImplicitSetter: { |
+ return IsStaticInitializer(function, Z) |
+ ? BuildGraphOfStaticFieldInitializer() |
+ : BuildGraphOfFieldAccessor(scopes()->setter_value); |
+ } |
+ case RawFunction::kMethodExtractor: |
+ return flow_graph_builder_->BuildGraphOfMethodExtractor(function); |
+ case RawFunction::kNoSuchMethodDispatcher: |
+ return flow_graph_builder_->BuildGraphOfNoSuchMethodDispatcher(function); |
+ case RawFunction::kInvokeFieldDispatcher: |
+ return flow_graph_builder_->BuildGraphOfInvokeFieldDispatcher(function); |
+ case RawFunction::kSignatureFunction: |
+ case RawFunction::kIrregexpFunction: |
+ break; |
+ } |
+ UNREACHABLE(); |
+ return NULL; |
} |
+ |
Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) { |
SetOffset(kernel_offset); |
return BuildStatement(); // read statement. |
@@ -2770,9 +3674,7 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) { |
case kConstMapLiteral: |
return BuildMapLiteral(true, position); |
case kFunctionExpression: |
- // TODO(jensj) |
- UNIMPLEMENTED(); |
- return Fragment(); |
+ return BuildFunctionExpression(); |
case kLet: |
return BuildLet(position); |
case kBigIntLiteral: |
@@ -2844,9 +3746,7 @@ Fragment StreamingFlowGraphBuilder::BuildStatement() { |
case kVariableDeclaration: |
return BuildVariableDeclaration(); |
case kFunctionDeclaration: |
- // TODO(jensj) |
- UNIMPLEMENTED(); |
- return Fragment(); |
+ return BuildFunctionDeclaration(); |
default: |
UNREACHABLE(); |
} |
@@ -3361,6 +4261,7 @@ void StreamingFlowGraphBuilder::SkipFunctionNode() { |
ReadByte(); // read async marker. |
ReadByte(); // read dart async marker. |
SkipTypeParametersList(); // read type_parameters. |
+ ReadUInt(); // read total parameter count. |
ReadUInt(); // read required_parameter_count. |
SkipListOfVariableDeclarations(); // read list of positionals. |
@@ -3485,6 +4386,10 @@ ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() { |
return flow_graph_builder_->scopes_; |
} |
+void StreamingFlowGraphBuilder::set_scopes(ScopeBuildingResult* scope) { |
+ flow_graph_builder_->scopes_ = scope; |
+} |
+ |
ParsedFunction* StreamingFlowGraphBuilder::parsed_function() { |
return flow_graph_builder_->parsed_function_; |
} |
@@ -4868,6 +5773,11 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const, |
return instructions + StaticCall(position, factory_method, 2); |
} |
+Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() { |
+ intptr_t offset = ReaderOffset() - 1; // -1 to include tag byte. |
+ return BuildFunctionNode(offset, TokenPosition::kNoSource, false, -1); |
+} |
+ |
Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) { |
if (position != NULL) *position = TokenPosition::kNoSource; |
@@ -5875,6 +6785,372 @@ Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() { |
return instructions; |
} |
+Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration() { |
+ intptr_t offset = ReaderOffset() - 1; // -1 to include tag byte. |
+ TokenPosition position = ReadPosition(); // read position. |
+ intptr_t variable_offeset = ReaderOffset(); |
+ SkipVariableDeclaration(); // read variable declaration. |
+ |
+ Fragment instructions = DebugStepCheck(position); |
+ instructions += BuildFunctionNode(offset, position, true, variable_offeset); |
+ instructions += StoreLocal(position, LookupVariable(variable_offeset)); |
+ instructions += Drop(); |
+ return instructions; |
+} |
+ |
+Fragment StreamingFlowGraphBuilder::BuildFunctionNode( |
+ intptr_t parent_kernel_offset, |
+ TokenPosition parent_position, |
+ bool declaration, |
+ intptr_t variable_offeset) { |
+ intptr_t offset = ReaderOffset(); |
+ |
+ TokenPosition position; |
+ TokenPosition end_position; |
+ word async_marker_word; |
+ word dart_async_marker_word; |
+ ReadFunctionNodeUntilTypeParameters( |
+ &position, &end_position, &async_marker_word, |
+ &dart_async_marker_word); // read first part of function node. |
+ FunctionNode::AsyncMarker async_marker = |
+ static_cast<FunctionNode::AsyncMarker>(async_marker_word); |
+ FunctionNode::AsyncMarker dart_async_marker = |
+ static_cast<FunctionNode::AsyncMarker>(dart_async_marker_word); |
+ |
+ if (declaration) { |
+ position = 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(offset).ToSynthetic(); |
+ } |
+ |
+ SkipTypeParametersList(); // read type parameters. |
+ |
+ // The VM has a per-isolate table of functions indexed by the enclosing |
+ // function and token position. |
+ Function& function = Function::ZoneHandle(Z); |
+ bool read_rest_of_function_node = false; |
+ |
+ // NOTE: This is not TokenPosition in the general sense! |
+ function = I->LookupClosureFunction(parsed_function()->function(), position); |
+ if (function.IsNull()) { |
+ for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) { |
+ if (scopes()->function_scopes[i].kernel_offset != offset) { |
+ continue; |
+ } |
+ |
+ const dart::String* name; |
+ if (!declaration) { |
+ name = &Symbols::AnonymousClosure(); |
+ } else { |
+ name = &H.DartSymbol(GetNameFromVariableDeclaration(variable_offeset)); |
+ } |
+ // NOTE: This is not TokenPosition in the general sense! |
+ function = Function::NewClosureFunction( |
+ *name, parsed_function()->function(), position); |
+ |
+ function.set_is_debuggable(dart_async_marker == FunctionNode::kSync); |
+ switch (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(async_marker == |
+ FunctionNode::kSyncYielding); |
+ if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { |
+ function.set_is_inlinable(!FLAG_causal_async_stacks); |
+ } |
+ |
+ function.set_end_token_pos(end_position); |
+ LocalScope* scope = scopes()->function_scopes[i].scope; |
+ const ContextScope& context_scope = ContextScope::Handle( |
+ Z, scope->PreserveOuterScope(flow_graph_builder_->context_depth_)); |
+ function.set_context_scope(context_scope); |
+ function.set_kernel_offset(offset); |
+ // Read rest of function node. |
+ SetupFunctionParameters(dart::Class::Handle(Z), function, |
+ false, // is_method |
+ true); // is_closure |
+ read_rest_of_function_node = true; |
+ // 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; |
+ } |
+ } |
+ |
+ if (!read_rest_of_function_node) { |
+ ReadUInt(); // read total parameter count. |
+ ReadUInt(); // read required_parameter_count. |
+ SkipListOfVariableDeclarations(); // read list of positionals. |
+ SkipListOfVariableDeclarations(); // read list of named. |
+ SkipDartType(); // read return type. |
+ if (ReadTag() == kSomething) { // read first part of body. |
+ SkipStatement(); // read body. |
+ } |
+ } |
+ |
+ const dart::Class& closure_class = |
+ dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); |
+ ASSERT(!closure_class.IsNull()); |
+ Fragment instructions = |
+ flow_graph_builder_->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 += flow_graph_builder_->StoreInstanceField( |
+ TokenPosition::kNoSource, |
+ Closure::instantiator_type_arguments_offset()); |
+ } |
+ |
+ // Store the function and the context in the closure. |
+ instructions += LoadLocal(closure); |
+ instructions += Constant(function); |
+ instructions += flow_graph_builder_->StoreInstanceField( |
+ TokenPosition::kNoSource, Closure::function_offset()); |
+ |
+ instructions += LoadLocal(closure); |
+ instructions += LoadLocal(parsed_function()->current_context_var()); |
+ instructions += flow_graph_builder_->StoreInstanceField( |
+ TokenPosition::kNoSource, Closure::context_offset()); |
+ |
+ return instructions; |
+} |
+ |
+ |
+void StreamingFlowGraphBuilder::SetupFunctionParameters( |
+ const dart::Class& klass, |
+ const dart::Function& function, |
+ bool is_method, |
+ bool is_closure) { |
+ ASSERT(!(is_method && is_closure)); |
+ bool is_factory = function.IsFactory(); |
+ intptr_t extra_parameters = (is_method || is_closure || is_factory) ? 1 : 0; |
+ |
+ intptr_t total_parameter_count = ReadUInt(); // read total parameter count. |
+ intptr_t required_parameter_count = |
+ ReadUInt(); // read required_parameter_count. |
+ intptr_t positional_parameters_count = ReadListLength(); // read list length. |
+ intptr_t named_parameters_count = |
+ total_parameter_count - positional_parameters_count; |
+ |
+ function.set_num_fixed_parameters(extra_parameters + |
+ required_parameter_count); |
+ if (named_parameters_count > 0) { |
+ function.SetNumOptionalParameters(named_parameters_count, false); |
+ } else { |
+ function.SetNumOptionalParameters( |
+ positional_parameters_count - required_parameter_count, true); |
+ } |
+ intptr_t num_parameters = extra_parameters + total_parameter_count; |
+ function.set_parameter_types( |
+ Array::Handle(Z, Array::New(num_parameters, Heap::kOld))); |
+ function.set_parameter_names( |
+ Array::Handle(Z, Array::New(num_parameters, Heap::kOld))); |
+ intptr_t pos = 0; |
+ if (is_method) { |
+ ASSERT(!klass.IsNull()); |
+ function.SetParameterTypeAt(pos, H.GetCanonicalType(klass)); |
+ function.SetParameterNameAt(pos, Symbols::This()); |
+ pos++; |
+ } else if (is_closure) { |
+ function.SetParameterTypeAt(pos, AbstractType::dynamic_type()); |
+ function.SetParameterNameAt(pos, Symbols::ClosureParameter()); |
+ pos++; |
+ } else if (is_factory) { |
+ function.SetParameterTypeAt(pos, AbstractType::dynamic_type()); |
+ function.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter()); |
+ pos++; |
+ } |
+ |
+ for (intptr_t i = 0; i < positional_parameters_count; ++i, ++pos) { |
+ // Read ith variable declaration. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ ReadFlags(); // read flags. |
+ StringIndex name = ReadStringReference(); // read name index. |
+ const AbstractType& type = T.BuildTypeWithoutFinalization(); // read type. |
+ Tag tag = ReadTag(); // read (first part of) initializer. |
+ if (tag == kSomething) { |
+ SkipExpression(); // read (actual) initializer. |
+ } |
+ |
+ function.SetParameterTypeAt( |
+ pos, type.IsMalformed() ? Type::dynamic_type() : type); |
+ function.SetParameterNameAt(pos, H.DartSymbol(name)); |
+ } |
+ |
+ intptr_t named_parameters_count_check = |
+ ReadListLength(); // read list length. |
+ ASSERT(named_parameters_count_check == named_parameters_count); |
+ for (intptr_t i = 0; i < named_parameters_count; ++i, ++pos) { |
+ // Read ith variable declaration. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ ReadFlags(); // read flags. |
+ StringIndex name = ReadStringReference(); // read name index. |
+ const AbstractType& type = T.BuildTypeWithoutFinalization(); // read type. |
+ Tag tag = ReadTag(); // read (first part of) initializer. |
+ if (tag == kSomething) { |
+ SkipExpression(); // read (actual) initializer. |
+ } |
+ |
+ function.SetParameterTypeAt( |
+ pos, type.IsMalformed() ? Type::dynamic_type() : type); |
+ function.SetParameterNameAt(pos, H.DartSymbol(name)); |
+ } |
+ |
+ // The result type for generative constructors has already been set. |
+ if (!function.IsGenerativeConstructor()) { |
+ const AbstractType& return_type = |
+ T.BuildTypeWithoutFinalization(); // read return type. |
+ function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type() |
+ : return_type); |
+ } else { |
+ SkipDartType(); // read return type. |
+ } |
+ |
+ if (ReadTag() == kSomething) { // read first part of body. |
+ SkipStatement(); // read body. |
+ } |
+} |
+ |
+RawObject* StreamingFlowGraphBuilder::BuildParameterDescriptor( |
+ intptr_t kernel_offset) { |
+ SetOffset(kernel_offset); |
+ ReadUntilFunctionNode(); // read until function node. |
+ ReadFunctionNodeUntilTypeParameters( |
+ &unused_tokenposition, &unused_tokenposition, &unused_word, |
+ &unused_word); // read first part of function node. |
+ SkipTypeParametersList(); // read type_parameters. |
+ |
+ intptr_t param_count = ReadUInt(); // read total parameter count. |
+ ReadUInt(); // read required_parameter_count. |
+ intptr_t positional_count = ReadListLength(); // read list length. |
+ intptr_t named_parameters_count = param_count - positional_count; |
+ |
+ 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; |
+ |
+ if (i == positional_count) { |
+ intptr_t named_parameters_count_check = |
+ ReadListLength(); // read list length. |
+ ASSERT(named_parameters_count_check == named_parameters_count); |
+ } |
+ |
+ // Read ith variable declaration. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read equals position. |
+ word flags = ReadFlags(); // read flags. |
+ bool is_final = (flags & VariableDeclaration::kFlagFinal) == |
+ VariableDeclaration::kFlagFinal; |
+ param_descriptor.SetAt(entry_start + Parser::kParameterIsFinalOffset, |
+ is_final ? Bool::True() : Bool::False()); |
+ |
+ SkipStringReference(); // read name index. |
+ SkipDartType(); // read type. |
+ Tag tag = ReadTag(); // read (first part of) initializer. |
+ if (tag == kSomething) { |
+ // this will (potentially) read the initializer, but reset the position. |
+ Instance& constant = |
+ constant_evaluator_.EvaluateExpression(ReaderOffset()); |
+ SkipExpression(); // read (actual) initializer. |
+ param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset, |
+ constant); |
+ } 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(); |
+} |
+ |
+RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(intptr_t kernel_offset) { |
+ SetOffset(kernel_offset); |
+ const Tag tag = PeekTag(); |
+ |
+ if (tag == kClass) { |
+ Tag tag = ReadTag(); // read tag. |
+ ASSERT(tag == kClass); |
+ SkipCanonicalNameReference(); // read canonical name reference. |
+ ReadPosition(); // read position. |
+ ReadByte(); // read is_abstract |
+ SkipStringReference(); // read name_index. |
+ ReadUInt(); // read source_uri_index. |
+ // SkipListOfExpressions(); // read annotations. |
+ } else if (tag == kProcedure) { |
+ Tag tag = ReadTag(); // read tag. |
+ ASSERT(tag == kProcedure); |
+ SkipCanonicalNameReference(); // read canonical name reference. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read end position. |
+ ReadByte(); // read kind. |
+ ReadFlags(); // read flags. |
+ ReadUInt(); // read parent class binary offset. |
+ SkipName(); // read name, |
+ ReadUInt(); // read source_uri_index. |
+ // SkipListOfExpressions(); // read annotations. |
+ } else if (tag == kField) { |
+ ReadFieldUntilAnnotation(&unused_nameindex, &unused_tokenposition, |
+ &unused_tokenposition, &unused_word, |
+ &unused_intptr); |
+ // SkipListOfExpressions(); // read annotations. |
+ } else if (tag == kConstructor) { |
+ Tag tag = ReadTag(); |
+ ASSERT(tag == kConstructor); |
+ SkipCanonicalNameReference(); // read canonical name reference. |
+ ReadPosition(); // read position. |
+ ReadPosition(); // read end position. |
+ ReadFlags(); // read flags. |
+ ReadUInt(); // parent class binary offset. |
+ SkipName(); // read name. |
+ // SkipListOfExpressions(); // read annotations. |
+ } else { |
+ FATAL("No support for metadata on this type of kernel node\n"); |
+ } |
+ |
+ intptr_t list_length = ReadListLength(); // read list length. |
+ const Array& metadata_values = Array::Handle(Z, Array::New(list_length)); |
+ for (intptr_t i = 0; i < list_length; ++i) { |
+ // this will (potentially) read the expression, but reset the position. |
+ Instance& value = constant_evaluator_.EvaluateExpression(ReaderOffset()); |
+ SkipExpression(); // read (actual) initializer. |
+ metadata_values.SetAt(i, value); |
+ } |
+ |
+ return metadata_values.raw(); |
+} |
+ |
} // namespace kernel |
} // namespace dart |