Index: runtime/vm/kernel_binary_flowgraph.cc |
diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc |
index adcfcec719e3b803ee48ddef5a1239653079e14e..c88ddce65eb74777894c05761bfd4fd69d1c7b92 100644 |
--- a/runtime/vm/kernel_binary_flowgraph.cc |
+++ b/runtime/vm/kernel_binary_flowgraph.cc |
@@ -4,7 +4,6 @@ |
#include "vm/kernel_binary_flowgraph.h" |
-#include "vm/compiler.h" |
#include "vm/longjump.h" |
#include "vm/object_store.h" |
@@ -55,6 +54,27 @@ 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_; |
@@ -71,18 +91,16 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
Function& outermost_function = Function::Handle(Z); |
intptr_t outermost_kernel_offset = -1; |
intptr_t parent_class_offset = -1; |
- builder_->DiscoverEnclosingElements(Z, function, &outermost_function, |
- &outermost_kernel_offset, |
- &parent_class_offset); |
+ 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) { |
- builder_->GetTypeParameterInfoForClass(parent_class_offset, |
- &class_type_parameters, |
- &class_type_parameters_offset_start); |
+ 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, |
@@ -92,7 +110,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
bool is_factory_procedure = false; |
intptr_t member_type_parameters = 0; |
intptr_t member_type_parameters_offset_start = -1; |
- builder_->GetTypeParameterInfoForPossibleProcedure( |
+ GetTypeParameterInfoForPossibleProcedure( |
outermost_kernel_offset, &member_is_procedure, &is_factory_procedure, |
&member_type_parameters, &member_type_parameters_offset_start); |
@@ -126,10 +144,27 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
case RawFunction::kSetterFunction: |
case RawFunction::kConstructor: { |
const Tag tag = builder_->PeekTag(); |
- parent_offset = builder_->ReadUntilFunctionNode(); |
+ 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(); |
+ } |
word async_marker_word; |
- builder_->ReadFunctionNodeUntilTypeParameters( |
- &unused_tokenposition, &unused_tokenposition, &async_marker_word, |
+ ReadFunctionNodeUntilTypeParameters( |
+ &async_marker_word, |
&unused_word); // read first part of function node. |
current_function_async_marker_ = |
static_cast<FunctionNode::AsyncMarker>(async_marker_word); |
@@ -158,7 +193,7 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
if (tag == kConstructor) { |
ASSERT(parent_offset >= 0); |
AlternativeReadingScope alt(builder_->reader_, parent_offset); |
- builder_->ReadClassUntilFields(); // read first part of class. |
+ 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++) { |
@@ -166,14 +201,12 @@ ScopeBuildingResult* StreamingScopeBuilder::BuildScopes() { |
TokenPosition position; |
TokenPosition end_position; |
word flags; |
- builder_->ReadFieldUntilAnnotation(&unused_nameindex, &position, |
- &end_position, &flags, |
- &unused_intptr); |
+ ReadFieldUntilAnnotation(&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(); // read first part of initializer. |
+ Tag initializer_tag = builder_->ReadTag(); |
if (!is_static && initializer_tag == kSomething) { |
EnterScope(field_offset); |
VisitExpression(); // read initializer. |
@@ -193,7 +226,6 @@ 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. |
@@ -287,6 +319,40 @@ 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) { |
@@ -308,25 +374,37 @@ 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 = builder_->ReadConstructorUntilFunctionNode(); |
+ intptr_t parent_offset = ReadConstructorUntilFunctionNode(); |
ASSERT(parent_offset >= 0); |
{ |
AlternativeReadingScope alt(builder_->reader_, parent_offset); |
- builder_->ReadClassUntilFields(); // read first part of class. |
+ 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; |
- builder_->ReadFieldUntilAnnotation( |
- &unused_nameindex, &unused_tokenposition, &unused_tokenposition, |
- &flags, &unused_intptr); |
+ ReadFieldUntilAnnotation(&unused_tokenposition, &unused_tokenposition, |
+ &flags, &unused_intptr); |
bool is_static = (flags & Field::kFlagStatic) == Field::kFlagStatic; |
builder_->SkipListOfExpressions(); // read annotations. |
builder_->SkipDartType(); // read type. |
@@ -349,17 +427,34 @@ void StreamingScopeBuilder::VisitConstructor() { |
} |
void StreamingScopeBuilder::VisitProcedure() { |
- Tag function_node = builder_->ReadProcedureUntilFunctionNode( |
+ Tag function_node = 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() { |
- builder_->ReadFieldUntilAnnotation( |
- &unused_nameindex, &unused_tokenposition, &unused_tokenposition, |
- &unused_intptr, &unused_word); // read first part of field. |
+ ReadFieldUntilAnnotation(&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). |
@@ -368,12 +463,98 @@ 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; |
- builder_->ReadFunctionNodeUntilTypeParameters( |
- &unused_tokenposition, &unused_tokenposition, &async_marker_word, |
- &dart_async_marker_word); |
+ ReadFunctionNodeUntilTypeParameters(&async_marker_word, |
+ &dart_async_marker_word); |
FunctionNode::AsyncMarker async_marker = |
static_cast<FunctionNode::AsyncMarker>(async_marker_word); |
FunctionNode::AsyncMarker dart_async_marker = |
@@ -408,7 +589,6 @@ 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. |
@@ -463,11 +643,11 @@ void StreamingScopeBuilder::VisitInitializer() { |
VisitExpression(); // read value. |
return; |
case kSuperInitializer: |
- builder_->SkipCanonicalNameReference(); // read target_reference. |
+ builder_->SkipCanonicalNameReference(); // read field_reference. |
VisitArguments(); // read arguments. |
return; |
case kRedirectingInitializer: |
- builder_->SkipCanonicalNameReference(); // read target_reference. |
+ builder_->SkipCanonicalNameReference(); // read field_reference. |
VisitArguments(); // read arguments. |
return; |
case kLocalInitializer: |
@@ -1140,7 +1320,6 @@ 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(); |
@@ -1302,6 +1481,16 @@ 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) { |
@@ -1312,7 +1501,7 @@ void StreamingScopeBuilder::LookupVariable(intptr_t declaration_binary_offest) { |
ASSERT(current_function_scope_->parent() != NULL); |
StringIndex var_name = |
- builder_->GetNameFromVariableDeclaration(declaration_binary_offest); |
+ GetNameFromVariableDeclaration(declaration_binary_offest); |
const dart::String& name = H.DartSymbol(var_name); |
variable = current_function_scope_->parent()->LookupVariable(name, true); |
@@ -1397,17 +1586,6 @@ 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(); |
@@ -2011,6 +2189,7 @@ 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)) { |
@@ -2408,1198 +2587,115 @@ RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall( |
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); |
-} |
- |
-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. |
+ instance.SetTypeArguments( |
+ TypeArguments::Handle(Z, type_arguments.Canonicalize())); |
} |
+ arg_values.SetAt(0, instance); |
} else { |
- // Still skip past the parameters. |
- SkipListOfVariableDeclarations(); // read list of positionals. |
- SkipListOfVariableDeclarations(); // read list of named. |
- } |
- |
- SkipDartType(); // read return type. |
- |
- 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. |
- } |
+ // Prepend type_arguments to list of arguments to factory. |
+ ASSERT(type_arguments.IsZoneHandle()); |
+ arg_values.SetAt(0, type_arguments); |
} |
- 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; |
- } |
- |
- // 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; |
- } |
- body = dispatch; |
- |
- flow_graph_builder_->context_depth_ = current_context_depth; |
+ 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); |
+} |
- 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(); |
- |
- 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(); |
+const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments( |
+ const Function& target, |
+ dart::Class* target_klass) { |
+ intptr_t types_count = builder_->ReadListLength(); // read types count. |
- // 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()); |
- } |
+ const TypeArguments* type_arguments = NULL; |
+ if (types_count > 0) { |
+ type_arguments = &T.BuildInstantiatedTypeArguments( |
+ *target_klass, types_count); // read types. |
- // 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(); |
+ if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) { |
+ H.ReportError("Type must be constant in const constructor."); |
} |
- } else { |
- UNIMPLEMENTED(); |
+ } 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 Fragment(); |
+ return type_arguments; |
} |
-FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) { |
- const Function& function = parsed_function()->function(); |
+bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() { |
+ EvaluateExpression(builder_->ReaderOffset(), false); |
+ AssertBoolInCheckedMode(); |
+ return result_.raw() == Bool::True().raw(); |
+} |
- // 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(); |
+bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset, |
+ Instance* value) { |
+ if (builder_ == NULL) return false; |
- 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); |
+ 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; |
} |
- 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); |
+ 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; |
+} |
- 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()); |
+void StreamingConstantEvaluator::CacheConstantValue(intptr_t kernel_offset, |
+ const Instance& value) { |
+ ASSERT(Thread::Current()->IsMutatorThread()); |
- SetOffset(kernel_offset); |
+ if (builder_ == NULL) return; |
- 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; |
+ 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; |
} |
- UNREACHABLE(); |
- return NULL; |
+ const intptr_t kInitialConstMapSize = 16; |
+ ASSERT(!script_.InVMHeap()); |
+ if (script_.compile_time_constants() == Array::null()) { |
+ const Array& array = Array::Handle( |
+ HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew)); |
+ script_.set_compile_time_constants(array); |
+ } |
+ KernelConstantsMap constants(script_.compile_time_constants()); |
+ constants.InsertNewOrGetValue(kernel_offset, value); |
+ script_.set_compile_time_constants(constants.Release()); |
} |
+Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) { |
+ SetOffset(kernel_offset); |
+ return BuildExpression(); // read expression. |
+} |
+ |
Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) { |
SetOffset(kernel_offset); |
return BuildStatement(); // read statement. |
@@ -3674,7 +2770,9 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) { |
case kConstMapLiteral: |
return BuildMapLiteral(true, position); |
case kFunctionExpression: |
- return BuildFunctionExpression(); |
+ // TODO(jensj) |
+ UNIMPLEMENTED(); |
+ return Fragment(); |
case kLet: |
return BuildLet(position); |
case kBigIntLiteral: |
@@ -3746,7 +2844,9 @@ Fragment StreamingFlowGraphBuilder::BuildStatement() { |
case kVariableDeclaration: |
return BuildVariableDeclaration(); |
case kFunctionDeclaration: |
- return BuildFunctionDeclaration(); |
+ // TODO(jensj) |
+ UNIMPLEMENTED(); |
+ return Fragment(); |
default: |
UNREACHABLE(); |
} |
@@ -4261,7 +3361,6 @@ 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. |
@@ -4386,10 +3485,6 @@ 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_; |
} |
@@ -5773,11 +4868,6 @@ 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; |
@@ -6785,372 +5875,6 @@ 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 |