[kernel] Stream everything. Replace .kernel_function with .kernel_offset
- Put pointer to kernel data into Script.
- Replace function.kernel_function pointer to AstNode with
kernel_offset():
- Replace field.kernel_field pointer to AstNode with kernel_offest().
- Stream the previously unstreamed AstNodes: FunctionDeclaration and
FunctionExpression.
- Move special handling for _buildin.getMainClosure into the streaming
flowgraph builder.
- Delete big parts of kernel_to_il.
R=kmillikin@google.com
Committed: https://github.com/dart-lang/sdk/commit/948e2f5d7916032ed6f0bfdc316ba4f577a5ea61
Review-Url: https://codereview.chromium.org/2901533002 .
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index b07e9a2..09fc3e6 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -329,6 +329,7 @@
Byte asyncMarker; // Index into AsyncMarker above.
Byte dartAsyncMarker; // Index into AsyncMarker above.
List<TypeParameter> typeParameters;
+ UInt parameterCount; // positionalParameters.length + namedParameters.length.
UInt requiredParameterCount;
List<VariableDeclaration> positionalParameters;
List<VariableDeclaration> namedParameters;
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 95a4ea3..b730dde 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -617,6 +617,7 @@
AsyncMarker dartAsyncMarker = AsyncMarker.values[readByte()];
int typeParameterStackHeight = typeParameterStack.length;
var typeParameters = readAndPushTypeParameterList();
+ readUInt(); // total parameter count.
var requiredParameterCount = readUInt();
int variableStackHeight = variableStack.length;
var positional = readAndPushVariableDeclarationList();
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index bc29337..80a31bc 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -482,6 +482,7 @@
writeByte(node.asyncMarker.index);
writeByte(node.dartAsyncMarker.index);
writeNodeList(node.typeParameters);
+ writeUInt30(node.positionalParameters.length + node.namedParameters.length);
writeUInt30(node.requiredParameterCount);
writeVariableDeclarationList(node.positionalParameters);
writeVariableDeclarationList(node.namedParameters);
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 54b22a6..9e2a1dd 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -145,7 +145,7 @@
// * Whether a parameters has been declared as final.
// * Any metadata associated with the parameter.
Object& result = Object::Handle();
- if (func.kernel_function() != NULL) {
+ if (func.kernel_offset() > 0) {
result = kernel::BuildParameterDescriptor(func);
} else {
result = Parser::ParseFunctionParameters(func);
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 288e056..13ac675 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1631,7 +1631,7 @@
/* is_native = */ false, cls, field.token_pos()));
getter.set_result_type(type);
getter.set_is_debuggable(false);
- getter.set_kernel_function(field.kernel_field());
+ getter.set_kernel_offset(field.kernel_offset());
cls.AddFunction(getter);
field.SetStaticValue(Object::sentinel(), true);
}
@@ -2389,7 +2389,7 @@
} else {
for (intptr_t i = 0; i < functions.Length(); i++) {
func ^= functions.At(i);
- ASSERT(func.kernel_function() != 0);
+ ASSERT(func.kernel_offset() > 0);
cloned_funcs.Add(func);
}
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index a99d4ba..f5a702a 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -115,7 +115,7 @@
bool UseKernelFrontEndFor(ParsedFunction* parsed_function) {
const Function& function = parsed_function->function();
- return (function.kernel_function() != NULL) ||
+ return (function.kernel_offset() > 0) ||
(function.kind() == RawFunction::kNoSuchMethodDispatcher) ||
(function.kind() == RawFunction::kInvokeFieldDispatcher);
}
@@ -135,11 +135,11 @@
const ZoneGrowableArray<const ICData*>& ic_data_array,
intptr_t osr_id) {
if (UseKernelFrontEndFor(parsed_function)) {
- kernel::TreeNode* node = static_cast<kernel::TreeNode*>(
- parsed_function->function().kernel_function());
- kernel::FlowGraphBuilder builder(node, parsed_function, ic_data_array,
- /* not building var desc */ NULL,
- /* not inlining */ NULL, osr_id);
+ kernel::FlowGraphBuilder builder(
+ parsed_function->function().kernel_offset(), parsed_function,
+ ic_data_array,
+ /* not building var desc */ NULL,
+ /* not inlining */ NULL, osr_id);
FlowGraph* graph = builder.BuildGraph();
ASSERT(graph != NULL);
return graph;
@@ -1606,10 +1606,9 @@
builder.BuildGraph();
} else {
parsed_function->EnsureKernelScopes();
- kernel::TreeNode* node = static_cast<kernel::TreeNode*>(
- parsed_function->function().kernel_function());
kernel::FlowGraphBuilder builder(
- node, parsed_function, *ic_data_array, context_level_array,
+ parsed_function->function().kernel_offset(), parsed_function,
+ *ic_data_array, context_level_array,
/* not inlining */ NULL, Compiler::kNoOSRDeoptId);
builder.BuildGraph();
}
@@ -1732,7 +1731,7 @@
// Create a one-time-use function to evaluate the initializer and invoke
// it immediately.
- if (field.kernel_field() != NULL) {
+ if (field.kernel_offset() > 0) {
parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
} else {
parsed_function = Parser::ParseStaticFieldInitializer(field);
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index b5063f8..65c3741 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -796,12 +796,9 @@
new (Z) InlineExitCollector(caller_graph_, call);
FlowGraph* callee_graph;
if (UseKernelFrontEndFor(parsed_function)) {
- kernel::TreeNode* node = static_cast<kernel::TreeNode*>(
- parsed_function->function().kernel_function());
-
kernel::FlowGraphBuilder builder(
- node, parsed_function, *ic_data_array,
- /* not building var desc */ NULL, exit_collector,
+ parsed_function->function().kernel_offset(), parsed_function,
+ *ic_data_array, /* not building var desc */ NULL, exit_collector,
Compiler::kNoOSRDeoptId, caller_graph_->max_block_id() + 1);
{
CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer);
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index e2970b1..70f5f36 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -429,7 +429,10 @@
virtual void AcceptVisitor(Visitor* visitor);
virtual void AcceptTreeVisitor(TreeVisitor* visitor) = 0;
- intptr_t kernel_offset() const { return kernel_offset_; }
+ intptr_t kernel_offset() const {
+ ASSERT(kernel_offset_ > 0);
+ return kernel_offset_;
+ }
bool can_stream() { return can_stream_; }
protected:
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index dd791b1..6902242 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -257,6 +257,7 @@
Class* Class::ReadFrom(Reader* reader) {
TRACE_READ_OFFSET();
+ kernel_offset_ = reader->offset() - 1; // -1 to include tag byte.
canonical_name_ = reader->ReadCanonicalNameReference();
position_ = reader->ReadPosition(false);
is_abstract_ = reader->ReadBool();
@@ -1843,6 +1844,7 @@
function->dart_async_marker_ =
static_cast<FunctionNode::AsyncMarker>(reader->ReadByte());
function->type_parameters().ReadFrom(reader);
+ reader->ReadUInt(); // total parameter count.
function->required_parameter_count_ = reader->ReadUInt();
function->positional_parameters().ReadFromStatic<VariableDeclarationImpl>(
reader);
diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc
index c88ddce..adcfcec 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
}
}
-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::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 @@
}
}
-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 @@
// 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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
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 @@
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)) {
@@ -2639,7 +2460,7 @@
bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset,
Instance* value) {
- if (builder_ == NULL) return false;
+ if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return false;
const Function& function = builder_->parsed_function()->function();
if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
@@ -2670,7 +2491,7 @@
const Instance& value) {
ASSERT(Thread::Current()->IsMutatorThread());
- if (builder_ == NULL) return;
+ if (builder_ == NULL || builder_->flow_graph_builder_ == NULL) return;
const Function& function = builder_->parsed_function()->function();
if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
@@ -2690,12 +2511,1095 @@
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();
+ }
-Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) {
- SetOffset(kernel_offset);
- return BuildExpression(); // read expression.
+ 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 {
+ // 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.
+ }
+ }
+ 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;
+ }
+
+ 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();
+
+ // 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 Fragment();
+}
+
+FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) {
+ const Function& function = parsed_function()->function();
+
+ // 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();
+
+ 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);
+ }
+
+ 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());
+
+ SetOffset(kernel_offset);
+
+ 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 @@
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 @@
case kVariableDeclaration:
return BuildVariableDeclaration();
case kFunctionDeclaration:
- // TODO(jensj)
- UNIMPLEMENTED();
- return Fragment();
+ return BuildFunctionDeclaration();
default:
UNREACHABLE();
}
@@ -3361,6 +4261,7 @@
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 @@
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 @@
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 @@
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
diff --git a/runtime/vm/kernel_binary_flowgraph.h b/runtime/vm/kernel_binary_flowgraph.h
index 300787d..4667e51 100644
--- a/runtime/vm/kernel_binary_flowgraph.h
+++ b/runtime/vm/kernel_binary_flowgraph.h
@@ -24,6 +24,8 @@
// Can return a malformed type.
AbstractType& BuildType();
+ // Can return a malformed type.
+ AbstractType& BuildTypeWithoutFinalization();
// Is guaranteed to be not malformed.
AbstractType& BuildVariableType();
@@ -101,46 +103,12 @@
private:
void VisitField();
- void ReadFieldUntilAnnotation(TokenPosition* position,
- TokenPosition* end_position,
- word* flags,
- intptr_t* parent_offset);
- /**
- * Will read until the function node; as this is optional, will return the tag
- * (i.e. either kSomething or kNothing).
- */
- Tag ReadProcedureUntilFunctionNode(word* kind, intptr_t* parent_offset);
- void 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);
void VisitProcedure();
- /**
- * Will return binary offset of parent class.
- */
- intptr_t ReadConstructorUntilFunctionNode();
void VisitConstructor();
- void ReadClassUntilTypeParameters();
- void ReadClassUntilFields();
-
- void ReadFunctionNodeUntilTypeParameters(word* async_marker,
- word* dart_async_marker);
void VisitFunctionNode();
-
- void DiscoverEnclosingElements(Zone* zone,
- const Function& function,
- Function* outermost_function,
- intptr_t* outermost_kernel_offset,
- intptr_t* parent_class_offset);
- intptr_t GetParentOffset(intptr_t offset);
- void GetTypeParameterInfoForClass(intptr_t class_offset,
- intptr_t* type_paremeter_counts,
- intptr_t* type_paremeter_offset);
void VisitNode();
void VisitInitializer();
void VisitExpression();
@@ -181,8 +149,6 @@
void AddIteratorVariable();
void AddSwitchVariable();
- StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset);
-
// Record an assignment or reference to a variable. If the occurrence is
// in a nested function, ensure that the variable is handled properly as a
// captured variable.
@@ -236,9 +202,29 @@
word unused_word;
intptr_t unused_intptr;
TokenPosition unused_tokenposition;
+ NameIndex unused_nameindex;
};
+// There are several cases when we are compiling constant expressions:
+//
+// * constant field initializers:
+// const FieldName = <expr>;
+//
+// * constant expressions:
+// const [<expr>, ...]
+// const {<expr> : <expr>, ...}
+// const Constructor(<expr>, ...)
+//
+// * constant default parameters:
+// f(a, [b = <expr>])
+// f(a, {b: <expr>})
+//
+// * constant values to compare in a [SwitchCase]
+// case <expr>:
+//
+// In all cases `<expr>` must be recursively evaluated and canonicalized at
+// compile-time.
class StreamingConstantEvaluator {
public:
explicit StreamingConstantEvaluator(StreamingFlowGraphBuilder* builder);
@@ -328,12 +314,6 @@
constant_evaluator_(this),
type_translator_(this, /* finalize= */ true) {}
- ~StreamingFlowGraphBuilder() { delete reader_; }
-
- Fragment BuildExpressionAt(intptr_t kernel_offset);
- Fragment BuildStatementAt(intptr_t kernel_offset);
-
- private:
StreamingFlowGraphBuilder(TranslationHelper* translation_helper,
Zone* zone,
const uint8_t* buffer,
@@ -345,6 +325,69 @@
constant_evaluator_(this),
type_translator_(this, /* finalize= */ true) {}
+ ~StreamingFlowGraphBuilder() { delete reader_; }
+
+ FlowGraph* BuildGraph(intptr_t kernel_offset);
+
+ Fragment BuildStatementAt(intptr_t kernel_offset);
+ RawObject* BuildParameterDescriptor(intptr_t kernel_offset);
+ RawObject* EvaluateMetadata(intptr_t kernel_offset);
+
+ private:
+ void DiscoverEnclosingElements(Zone* zone,
+ const Function& function,
+ Function* outermost_function,
+ intptr_t* outermost_kernel_offset,
+ intptr_t* parent_class_offset);
+ intptr_t GetParentOffset(intptr_t offset);
+ void GetTypeParameterInfoForClass(intptr_t class_offset,
+ intptr_t* type_paremeter_counts,
+ intptr_t* type_paremeter_offset);
+ void ReadClassUntilFields();
+ void ReadClassUntilTypeParameters();
+ /**
+ * Will return binary offset of parent class.
+ */
+ intptr_t ReadConstructorUntilFunctionNode();
+ /**
+ * Will read until the function node; as this is optional, will return the tag
+ * (i.e. either kSomething or kNothing).
+ */
+ Tag ReadProcedureUntilFunctionNode(word* kind, intptr_t* parent_offset);
+
+ void ReadFieldUntilAnnotation(NameIndex* canonical_name,
+ TokenPosition* position,
+ TokenPosition* end_position,
+ word* flags,
+ intptr_t* parent_offset);
+ void 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);
+ void ReadFunctionNodeUntilTypeParameters(TokenPosition* position,
+ TokenPosition* end_position,
+ word* async_marker,
+ word* dart_async_marker);
+ /**
+ * Will return kernel offset for parent class if reading a constructor.
+ * Will otherwise return -1.
+ */
+ intptr_t ReadUntilFunctionNode();
+ StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset);
+
+ FlowGraph* BuildGraphOfStaticFieldInitializer();
+ FlowGraph* BuildGraphOfFieldAccessor(LocalVariable* setter_value);
+ void SetupDefaultParameterValues();
+ Fragment BuildFieldInitializer(NameIndex canonical_name);
+ Fragment BuildInitializers(intptr_t constructor_class_parent_offset);
+ FlowGraph* BuildGraphOfImplicitClosureFunction(const Function& function);
+ FlowGraph* BuildGraphOfFunction(
+ bool is_in_builtin_library_toplevel,
+ intptr_t constructor_class_parent_offset = -1);
+ Fragment BuildGetMainClosure();
+
Fragment BuildExpression(TokenPosition* position = NULL);
Fragment BuildStatement();
@@ -399,6 +442,7 @@
CatchBlock* catch_block();
ActiveClass* active_class();
ScopeBuildingResult* scopes();
+ void set_scopes(ScopeBuildingResult* scope);
ParsedFunction* parsed_function();
TryFinallyBlock* try_finally_block();
SwitchBlock* switch_block();
@@ -537,6 +581,7 @@
Fragment BuildThrow(TokenPosition* position);
Fragment BuildListLiteral(bool is_const, TokenPosition* position);
Fragment BuildMapLiteral(bool is_const, TokenPosition* position);
+ Fragment BuildFunctionExpression();
Fragment BuildLet(TokenPosition* position);
Fragment BuildBigIntLiteral(TokenPosition* position);
Fragment BuildStringLiteral(TokenPosition* position);
@@ -565,6 +610,15 @@
Fragment BuildTryFinally();
Fragment BuildYieldStatement();
Fragment BuildVariableDeclaration();
+ Fragment BuildFunctionDeclaration();
+ Fragment BuildFunctionNode(intptr_t parent_kernel_offset,
+ TokenPosition parent_position,
+ bool declaration,
+ intptr_t variable_offeset);
+ void SetupFunctionParameters(const dart::Class& klass,
+ const dart::Function& function,
+ bool is_method,
+ bool is_closure);
FlowGraphBuilder* flow_graph_builder_;
TranslationHelper& translation_helper_;
@@ -573,6 +627,11 @@
StreamingConstantEvaluator constant_evaluator_;
StreamingDartTypeTranslator type_translator_;
+ word unused_word;
+ intptr_t unused_intptr;
+ TokenPosition unused_tokenposition;
+ NameIndex unused_nameindex;
+
friend class StreamingConstantEvaluator;
friend class StreamingDartTypeTranslator;
friend class StreamingScopeBuilder;
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index 5f4dd9c..bbc8e1a 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -202,24 +202,6 @@
Z, library.LookupObjectAllowPrivate(H.DartSymbol("main")));
ASSERT(!main_obj.IsNull());
- Function& to_patch = Function::Handle(
- Z, builtin_library.LookupFunctionAllowPrivate(
- dart::String::Handle(dart::String::New("_getMainClosure"))));
-
- Procedure* procedure =
- reinterpret_cast<Procedure*>(to_patch.kernel_function());
- // If dart:_builtin was not compiled from Kernel at all it does not need
- // to be patched.
- if (procedure != NULL) {
- // We will handle the StaticGet specially and will not use the name.
- // Note that we pass "true" in cannot_stream to avoid trying to stream
- // a non-existing part of the binary.
- //
- // TODO(kmillikin): we are leaking the new function body. Find a way to
- // deallocate it.
- procedure->function()->ReplaceBody(
- new ReturnStatement(new StaticGet(NameIndex(), false), false));
- }
return library;
}
}
@@ -271,7 +253,7 @@
Z, dart::Field::NewTopLevel(name, kernel_field->IsFinal(),
kernel_field->IsConst(), script_class,
kernel_field->position()));
- field.set_kernel_field(kernel_field);
+ field.set_kernel_offset(kernel_field->kernel_offset());
const AbstractType& type = T.TranslateType(kernel_field->type());
field.SetFieldType(type);
field.set_has_initializer(kernel_field->initializer() != NULL);
@@ -423,7 +405,7 @@
kernel_field->IsConst(),
false, // is_reflectable
script_class, type, kernel_field->position()));
- field.set_kernel_field(kernel_field);
+ field.set_kernel_offset(kernel_field->kernel_offset());
field.set_has_initializer(kernel_field->initializer() != NULL);
GenerateFieldAccessors(klass, field, kernel_field);
fields_.Add(&field);
@@ -447,7 +429,7 @@
klass, kernel_constructor->position()));
function.set_end_token_pos(kernel_constructor->end_position());
functions_.Add(&function);
- function.set_kernel_function(kernel_constructor);
+ function.set_kernel_offset(kernel_constructor->kernel_offset());
function.set_result_type(T.ReceiverType(klass));
SetupFunctionParameters(H, T, klass, function,
kernel_constructor->function(),
@@ -456,7 +438,7 @@
if (FLAG_enable_mirrors) {
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
- kernel_constructor);
+ kernel_constructor->kernel_offset());
}
}
@@ -474,7 +456,7 @@
if (FLAG_enable_mirrors) {
library.AddClassMetadata(klass, toplevel_class, TokenPosition::kNoSource,
- kernel_klass);
+ kernel_klass->kernel_offset());
}
return klass;
@@ -533,7 +515,7 @@
script_class, kernel_procedure->position()));
function.set_end_token_pos(kernel_procedure->end_position());
functions_.Add(&function);
- function.set_kernel_function(kernel_procedure);
+ function.set_kernel_offset(kernel_procedure->kernel_offset());
function.set_is_debuggable(
kernel_procedure->function()->dart_async_marker() == FunctionNode::kSync);
@@ -572,7 +554,7 @@
}
if (FLAG_enable_mirrors) {
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
- kernel_procedure);
+ kernel_procedure->kernel_offset());
}
}
@@ -642,6 +624,8 @@
H.DartString(source_buffer, source_size, Heap::kOld);
script = Script::New(import_uri_string, uri_string, source_code,
RawScript::kKernelTag);
+ script.set_kernel_data(program_->libraries()[0]->kernel_data());
+ script.set_kernel_data_size(program_->libraries()[0]->kernel_data_size());
script.set_kernel_string_offsets(H.string_offsets());
script.set_kernel_string_data(H.string_data());
script.set_kernel_canonical_names(H.canonical_names());
@@ -729,7 +713,7 @@
script_class, kernel_field->position()));
functions_.Add(&getter);
getter.set_end_token_pos(kernel_field->end_position());
- getter.set_kernel_function(kernel_field);
+ getter.set_kernel_offset(kernel_field->kernel_offset());
getter.set_result_type(AbstractType::Handle(Z, field.type()));
getter.set_is_debuggable(false);
SetupFieldAccessorFunction(klass, getter);
@@ -749,7 +733,7 @@
script_class, kernel_field->position()));
functions_.Add(&setter);
setter.set_end_token_pos(kernel_field->end_position());
- setter.set_kernel_function(kernel_field);
+ setter.set_kernel_offset(kernel_field->kernel_offset());
setter.set_result_type(Object::void_type());
setter.set_is_debuggable(false);
SetupFieldAccessorFunction(klass, setter);
@@ -916,8 +900,6 @@
ParsedFunction* ParseStaticFieldInitializer(Zone* zone,
const dart::Field& field) {
Thread* thread = Thread::Current();
- kernel::Field* kernel_field = kernel::Field::Cast(
- reinterpret_cast<kernel::Node*>(field.kernel_field()));
dart::String& init_name = dart::String::Handle(zone, field.name());
init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name);
@@ -933,7 +915,7 @@
false, // is_external
false, // is_native
owner, TokenPosition::kNoSource));
- initializer_fun.set_kernel_function(kernel_field);
+ initializer_fun.set_kernel_offset(field.kernel_offset());
initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
initializer_fun.set_is_debuggable(false);
initializer_fun.set_is_reflectable(false);
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 5b10f05..f9f4e35 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -30,40 +30,6 @@
#define I Isolate::Current()
-static void DiscoverEnclosingElements(Zone* zone,
- const Function& function,
- Function* outermost_function,
- TreeNode** outermost_node,
- Class** klass) {
- // Find out if there is an enclosing kernel class (which will be used to
- // resolve type parameters).
- *outermost_function = function.raw();
- while (outermost_function->parent_function() != Object::null()) {
- *outermost_function = outermost_function->parent_function();
- }
- *outermost_node =
- static_cast<TreeNode*>(outermost_function->kernel_function());
- if (*outermost_node != NULL) {
- TreeNode* parent = NULL;
- if ((*outermost_node)->IsProcedure()) {
- parent = Procedure::Cast(*outermost_node)->parent();
- } else if ((*outermost_node)->IsConstructor()) {
- parent = Constructor::Cast(*outermost_node)->parent();
- } else if ((*outermost_node)->IsField()) {
- parent = Field::Cast(*outermost_node)->parent();
- }
- if (parent != NULL && parent->IsClass()) *klass = Class::Cast(parent);
- }
-}
-
-
-static bool IsStaticInitializer(const Function& function, Zone* zone) {
- return (function.kind() == RawFunction::kImplicitStaticFinalGetter) &&
- dart::String::Handle(zone, function.name())
- .StartsWith(Symbols::InitPrefix());
-}
-
-
Fragment& Fragment::operator+=(const Fragment& other) {
if (entry == NULL) {
entry = other.entry;
@@ -684,581 +650,9 @@
return names;
}
-ConstantEvaluator::ConstantEvaluator(FlowGraphBuilder* builder,
- Zone* zone,
- TranslationHelper* h,
- DartTypeTranslator* type_translator)
- : builder_(builder),
- isolate_(Isolate::Current()),
- zone_(zone),
- translation_helper_(*h),
- type_translator_(*type_translator),
- script_(Script::Handle(
- zone,
- builder == NULL ? Script::null()
- : builder_->parsed_function_->function().script())),
- result_(Instance::Handle(zone)) {}
-
-
-Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) {
- if (!GetCachedConstant(expression, &result_)) {
- expression->AcceptExpressionVisitor(this);
- CacheConstantValue(expression, result_);
- }
- // We return a new `ZoneHandle` here on purpose: The intermediate language
- // instructions do not make a copy of the handle, so we do it.
- return Instance::ZoneHandle(Z, result_.raw());
-}
-
-
-Object& ConstantEvaluator::EvaluateExpressionSafe(Expression* expression) {
- LongJumpScope jump;
- if (setjmp(*jump.Set()) == 0) {
- return EvaluateExpression(expression);
- } else {
- Thread* thread = H.thread();
- Error& error = Error::Handle(Z);
- error = thread->sticky_error();
- thread->clear_sticky_error();
- return error;
- }
-}
-
-
-Instance& ConstantEvaluator::EvaluateConstructorInvocation(
- ConstructorInvocation* node) {
- if (!GetCachedConstant(node, &result_)) {
- VisitConstructorInvocation(node);
- CacheConstantValue(node, result_);
- }
- // We return a new `ZoneHandle` here on purpose: The intermediate language
- // instructions do not make a copy of the handle, so we do it.
- return Instance::ZoneHandle(Z, result_.raw());
-}
-
-
-Instance& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) {
- if (!GetCachedConstant(node, &result_)) {
- VisitListLiteral(node);
- CacheConstantValue(node, result_);
- }
- // We return a new `ZoneHandle` here on purpose: The intermediate language
- // instructions do not make a copy of the handle, so we do it.
- return Instance::ZoneHandle(Z, result_.raw());
-}
-
-
-Instance& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) {
- if (!GetCachedConstant(node, &result_)) {
- VisitMapLiteral(node);
- CacheConstantValue(node, result_);
- }
- // We return a new `ZoneHandle` here on purpose: The intermediate language
- // instructions do not make a copy of the handle, so we do it.
- return Instance::ZoneHandle(Z, result_.raw());
-}
-
-
-void ConstantEvaluator::VisitBigintLiteral(BigintLiteral* node) {
- const dart::String& value = H.DartString(node->value());
- result_ = Integer::New(value, Heap::kOld);
- result_ = H.Canonicalize(result_);
-}
-
-
-void ConstantEvaluator::VisitBoolLiteral(BoolLiteral* node) {
- result_ = Bool::Get(node->value()).raw();
-}
-
-
-void ConstantEvaluator::VisitDoubleLiteral(DoubleLiteral* node) {
- result_ = Double::New(H.DartString(node->value()), Heap::kOld);
- result_ = H.Canonicalize(result_);
-}
-
-
-void ConstantEvaluator::VisitIntLiteral(IntLiteral* node) {
- result_ = Integer::New(node->value(), Heap::kOld);
- result_ = H.Canonicalize(result_);
-}
-
-
-void ConstantEvaluator::VisitNullLiteral(NullLiteral* node) {
- result_ = Instance::null();
-}
-
-
-void ConstantEvaluator::VisitStringLiteral(StringLiteral* node) {
- result_ = H.DartSymbol(node->value()).raw();
-}
-
-
-void ConstantEvaluator::VisitTypeLiteral(TypeLiteral* node) {
- const AbstractType& type = T.TranslateType(node->type());
- if (type.IsMalformed()) {
- H.ReportError("Malformed type literal in constant expression.");
- }
- result_ = type.raw();
-}
-
-
-RawObject* ConstantEvaluator::EvaluateConstConstructorCall(
- const dart::Class& type_class,
- const TypeArguments& type_arguments,
- const Function& constructor,
- const Object& argument) {
- // Factories have one extra argument: the type arguments.
- // Constructors have 1 extra arguments: receiver.
- const int kTypeArgsLen = 0;
- const int kNumArgs = 1;
- const int kNumExtraArgs = 1;
- const int num_arguments = kNumArgs + kNumExtraArgs;
- const Array& arg_values =
- Array::Handle(Z, Array::New(num_arguments, Heap::kOld));
- Instance& instance = Instance::Handle(Z);
- if (!constructor.IsFactory()) {
- instance = Instance::New(type_class, Heap::kOld);
- if (!type_arguments.IsNull()) {
- ASSERT(type_arguments.IsInstantiated());
- instance.SetTypeArguments(
- TypeArguments::Handle(Z, type_arguments.Canonicalize()));
- }
- arg_values.SetAt(0, instance);
- } else {
- // Prepend type_arguments to list of arguments to factory.
- ASSERT(type_arguments.IsZoneHandle());
- arg_values.SetAt(0, type_arguments);
- }
- arg_values.SetAt((0 + kNumExtraArgs), argument);
- const Array& args_descriptor =
- Array::Handle(Z, ArgumentsDescriptor::New(kTypeArgsLen, num_arguments,
- Object::empty_array()));
- const Object& result = Object::Handle(
- Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor));
- ASSERT(!result.IsError());
- if (constructor.IsFactory()) {
- // The factory method returns the allocated object.
- instance ^= result.raw();
- }
- return H.Canonicalize(instance);
-}
-
-
-bool ConstantEvaluator::GetCachedConstant(TreeNode* node, Instance* value) {
- if (builder_ == NULL) return false;
-
- const Function& function = builder_->parsed_function_->function();
- if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
- // Don't cache constants in initializer expressions. They get
- // evaluated only once.
- return false;
- }
-
- bool is_present = false;
- ASSERT(!script_.InVMHeap());
- if (script_.compile_time_constants() == Array::null()) {
- return false;
- }
- KernelConstantsMap constants(script_.compile_time_constants());
- *value ^= constants.GetOrNull(node->kernel_offset(), &is_present);
- // Mutator compiler thread may add constants while background compiler
- // is running, and thus change the value of 'compile_time_constants';
- // do not assert that 'compile_time_constants' has not changed.
- constants.Release();
- if (FLAG_compiler_stats && is_present) {
- H.thread()->compiler_stats()->num_const_cache_hits++;
- }
- return is_present;
-}
-
-
-void ConstantEvaluator::CacheConstantValue(TreeNode* node,
- const Instance& value) {
- ASSERT(Thread::Current()->IsMutatorThread());
-
- if (builder_ == NULL) return;
-
- const Function& function = builder_->parsed_function_->function();
- if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
- // Don't cache constants in initializer expressions. They get
- // evaluated only once.
- return;
- }
- const intptr_t kInitialConstMapSize = 16;
- ASSERT(!script_.InVMHeap());
- if (script_.compile_time_constants() == Array::null()) {
- const Array& array = Array::Handle(
- HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew));
- script_.set_compile_time_constants(array);
- }
- KernelConstantsMap constants(script_.compile_time_constants());
- constants.InsertNewOrGetValue(node->kernel_offset(), value);
- script_.set_compile_time_constants(constants.Release());
-}
-
-
-void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) {
- const dart::String& symbol_value = H.DartSymbol(node->value());
-
- const dart::Class& symbol_class =
- dart::Class::ZoneHandle(Z, I->object_store()->symbol_class());
- ASSERT(!symbol_class.IsNull());
- const Function& symbol_constructor = Function::ZoneHandle(
- Z, symbol_class.LookupConstructor(Symbols::SymbolCtor()));
- ASSERT(!symbol_constructor.IsNull());
- result_ ^= EvaluateConstConstructorCall(
- symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value);
-}
-
-
-void ConstantEvaluator::VisitListLiteral(ListLiteral* node) {
- DartType* types[] = {node->type()};
- const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1);
-
- intptr_t length = node->expressions().length();
- const Array& const_list =
- Array::ZoneHandle(Z, Array::New(length, Heap::kOld));
- const_list.SetTypeArguments(type_arguments);
- for (intptr_t i = 0; i < length; i++) {
- const Instance& expression = EvaluateExpression(node->expressions()[i]);
- const_list.SetAt(i, expression);
- }
- const_list.MakeImmutable();
- result_ = H.Canonicalize(const_list);
-}
-
-
-void ConstantEvaluator::VisitMapLiteral(MapLiteral* node) {
- DartType* types[] = {node->key_type(), node->value_type()};
- const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2);
-
- intptr_t length = node->entries().length();
-
- Array& const_kv_array =
- Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld));
- for (intptr_t i = 0; i < length; i++) {
- const_kv_array.SetAt(2 * i + 0,
- EvaluateExpression(node->entries()[i]->key()));
- const_kv_array.SetAt(2 * i + 1,
- EvaluateExpression(node->entries()[i]->value()));
- }
-
- const_kv_array.MakeImmutable();
- const_kv_array ^= H.Canonicalize(const_kv_array);
-
- const dart::Class& map_class = dart::Class::Handle(
- Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap()));
- ASSERT(!map_class.IsNull());
- ASSERT(map_class.NumTypeArguments() == 2);
-
- const dart::Field& field = dart::Field::Handle(
- Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs")));
- ASSERT(!field.IsNull());
-
- // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`!
- result_ = Instance::New(map_class, Heap::kOld);
- ASSERT(!result_.IsNull());
- result_.SetTypeArguments(type_arguments);
- result_.SetField(field, const_kv_array);
- result_ = H.Canonicalize(result_);
-}
-
-
-void ConstantEvaluator::VisitConstructorInvocation(
- ConstructorInvocation* node) {
- Arguments* kernel_arguments = node->arguments();
-
- const Function& constructor = Function::Handle(
- Z, H.LookupConstructorByKernelConstructor(node->target()));
- dart::Class& klass = dart::Class::Handle(Z, constructor.Owner());
-
- // Build the type arguments vector (if necessary).
- const TypeArguments* type_arguments =
- TranslateTypeArguments(constructor, &klass, kernel_arguments);
-
- // Prepare either the instance or the type argument vector for the constructor
- // call.
- Instance* receiver = NULL;
- const TypeArguments* type_arguments_argument = NULL;
- if (!constructor.IsFactory()) {
- receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld));
- if (type_arguments != NULL) {
- receiver->SetTypeArguments(*type_arguments);
- }
- } else {
- type_arguments_argument = type_arguments;
- }
-
- const Object& result = RunFunction(constructor, kernel_arguments, receiver,
- type_arguments_argument);
- if (constructor.IsFactory()) {
- // Factories return the new object.
- result_ ^= result.raw();
- result_ = H.Canonicalize(result_);
- } else {
- ASSERT(!receiver->IsNull());
- result_ = H.Canonicalize(*receiver);
- }
-}
-
-
-void ConstantEvaluator::VisitMethodInvocation(MethodInvocation* node) {
- Arguments* kernel_arguments = node->arguments();
-
- // Dart does not support generic methods yet.
- ASSERT(kernel_arguments->types().length() == 0);
-
- const Instance& receiver = EvaluateExpression(node->receiver());
- dart::Class& klass = dart::Class::Handle(
- Z, isolate_->class_table()->At(receiver.GetClassId()));
- ASSERT(!klass.IsNull());
-
- // Search the superclass chain for the selector.
- Function& function = Function::Handle(Z);
- const dart::String& method_name = H.DartMethodName(node->name());
- while (!klass.IsNull()) {
- function = klass.LookupDynamicFunctionAllowPrivate(method_name);
- if (!function.IsNull()) break;
- klass = klass.SuperClass();
- }
-
- // The frontend should guarantee that [MethodInvocation]s inside constant
- // expressions are always valid.
- ASSERT(!function.IsNull());
-
- // Run the method and canonicalize the result.
- const Object& result = RunFunction(function, kernel_arguments, &receiver);
- result_ ^= result.raw();
- result_ = H.Canonicalize(result_);
-}
-
-
-void ConstantEvaluator::VisitStaticGet(StaticGet* node) {
- NameIndex target = node->target();
- if (H.IsField(target)) {
- const dart::Field& field =
- dart::Field::Handle(Z, H.LookupFieldByKernelField(target));
- if (field.StaticValue() == Object::sentinel().raw() ||
- field.StaticValue() == Object::transition_sentinel().raw()) {
- field.EvaluateInitializer();
- result_ = field.StaticValue();
- result_ = H.Canonicalize(result_);
- field.SetStaticValue(result_, true);
- } else {
- result_ = field.StaticValue();
- }
- } else if (H.IsProcedure(target)) {
- const Function& function =
- Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
-
- if (H.IsMethod(target)) {
- Function& closure_function =
- Function::ZoneHandle(Z, function.ImplicitClosureFunction());
- closure_function.set_kernel_function(function.kernel_function());
- result_ = closure_function.ImplicitStaticClosure();
- result_ = H.Canonicalize(result_);
- } else if (H.IsGetter(target)) {
- UNIMPLEMENTED();
- } else {
- UNIMPLEMENTED();
- }
- }
-}
-
-
-void ConstantEvaluator::VisitVariableGet(VariableGet* node) {
- // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
- // been executed already. It therefore must have a constant object associated
- // with it.
- LocalVariable* variable = builder_->LookupVariable(node->variable());
- ASSERT(variable->IsConst());
- result_ = variable->ConstValue()->raw();
-}
-
-
-void ConstantEvaluator::VisitLet(Let* node) {
- VariableDeclaration* variable = node->variable();
- LocalVariable* local = builder_->LookupVariable(variable);
- local->SetConstValue(EvaluateExpression(variable->initializer()));
- node->body()->AcceptExpressionVisitor(this);
-}
-
-
-void ConstantEvaluator::VisitStaticInvocation(StaticInvocation* node) {
- const Function& function = Function::ZoneHandle(
- Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
- dart::Class& klass = dart::Class::Handle(Z, function.Owner());
-
- // Build the type arguments vector (if necessary).
- const TypeArguments* type_arguments =
- TranslateTypeArguments(function, &klass, node->arguments());
-
- const Object& result =
- RunFunction(function, node->arguments(), NULL, type_arguments);
- result_ ^= result.raw();
- result_ = H.Canonicalize(result_);
-}
-
-
-void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) {
- intptr_t length = node->expressions().length();
-
- bool all_string = true;
- const Array& strings = Array::Handle(Z, Array::New(length));
- for (intptr_t i = 0; i < length; i++) {
- EvaluateExpression(node->expressions()[i]);
- strings.SetAt(i, result_);
- all_string = all_string && result_.IsString();
- }
- if (all_string) {
- result_ = dart::String::ConcatAll(strings, Heap::kOld);
- result_ = H.Canonicalize(result_);
- } else {
- // Get string interpolation function.
- const dart::Class& cls = dart::Class::Handle(
- Z, dart::Library::LookupCoreClass(Symbols::StringBase()));
- ASSERT(!cls.IsNull());
- const Function& func = Function::Handle(
- Z, cls.LookupStaticFunction(
- dart::Library::PrivateCoreLibName(Symbols::Interpolate())));
- ASSERT(!func.IsNull());
-
- // Build argument array to pass to the interpolation function.
- const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld));
- interpolate_arg.SetAt(0, strings);
-
- // Run and canonicalize.
- const Object& result =
- RunFunction(func, interpolate_arg, Array::null_array());
- result_ = H.Canonicalize(dart::String::Cast(result));
- }
-}
-
-
-void ConstantEvaluator::VisitConditionalExpression(
- ConditionalExpression* node) {
- if (EvaluateBooleanExpression(node->condition())) {
- EvaluateExpression(node->then());
- } else {
- EvaluateExpression(node->otherwise());
- }
-}
-
-
-void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) {
- if (node->op() == LogicalExpression::kAnd) {
- if (EvaluateBooleanExpression(node->left())) {
- EvaluateBooleanExpression(node->right());
- }
- } else {
- ASSERT(node->op() == LogicalExpression::kOr);
- if (!EvaluateBooleanExpression(node->left())) {
- EvaluateBooleanExpression(node->right());
- }
- }
-}
-
-
-void ConstantEvaluator::VisitNot(Not* node) {
- result_ ^= Bool::Get(!EvaluateBooleanExpression(node->expression())).raw();
-}
-
-
-void ConstantEvaluator::VisitPropertyGet(PropertyGet* node) {
- StringIndex string_index = node->name()->string_index();
- if (H.StringEquals(string_index, "length")) {
- node->receiver()->AcceptExpressionVisitor(this);
- if (result_.IsString()) {
- const dart::String& str =
- dart::String::Handle(Z, dart::String::RawCast(result_.raw()));
- result_ = Integer::New(str.Length());
- } else {
- H.ReportError(
- "Constant expressions can only call "
- "'length' on string constants.");
- }
- } else {
- VisitDefaultExpression(node);
- }
-}
-
-
-const TypeArguments* ConstantEvaluator::TranslateTypeArguments(
- const Function& target,
- dart::Class* target_klass,
- Arguments* kernel_arguments) {
- List<DartType>& kernel_type_arguments = kernel_arguments->types();
-
- const TypeArguments* type_arguments = NULL;
- if (kernel_type_arguments.length() > 0) {
- type_arguments = &T.TranslateInstantiatedTypeArguments(
- *target_klass, kernel_type_arguments.raw_array(),
- kernel_type_arguments.length());
-
- if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) {
- H.ReportError("Type must be constant in const constructor.");
- }
- } else if (target.IsFactory() && type_arguments == NULL) {
- // All factories take a type arguments vector as first argument (independent
- // of whether the class is generic or not).
- type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null());
- }
- return type_arguments;
-}
-
-
-const Object& ConstantEvaluator::RunFunction(const Function& function,
- Arguments* kernel_arguments,
- const Instance* receiver,
- const TypeArguments* type_args) {
- // We do not support generic methods yet.
- ASSERT((receiver == NULL) || (type_args == NULL));
- intptr_t extra_arguments =
- (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0);
-
- // Build up arguments.
- const Array& arguments = Array::ZoneHandle(
- Z, Array::New(extra_arguments + kernel_arguments->count()));
- const Array& names =
- Array::ZoneHandle(Z, Array::New(kernel_arguments->named().length()));
- intptr_t pos = 0;
- if (receiver != NULL) {
- arguments.SetAt(pos++, *receiver);
- }
- if (type_args != NULL) {
- arguments.SetAt(pos++, *type_args);
- }
- for (intptr_t i = 0; i < kernel_arguments->positional().length(); i++) {
- EvaluateExpression(kernel_arguments->positional()[i]);
- arguments.SetAt(pos++, result_);
- }
- for (intptr_t i = 0; i < kernel_arguments->named().length(); i++) {
- NamedExpression* named_expression = kernel_arguments->named()[i];
- EvaluateExpression(named_expression->expression());
- arguments.SetAt(pos++, result_);
- names.SetAt(i, H.DartSymbol(named_expression->name()));
- }
- return RunFunction(function, arguments, names);
-}
-
-
-const Object& ConstantEvaluator::RunFunction(const Function& function,
- const Array& arguments,
- const Array& names) {
- const int kTypeArgsLen = 0; // Generic functions not yet supported.
- const Array& args_descriptor = Array::Handle(
- Z, ArgumentsDescriptor::New(kTypeArgsLen, arguments.Length(), names));
- const Object& result = Object::Handle(
- Z, DartEntry::InvokeFunction(function, arguments, args_descriptor));
- if (result.IsError()) {
- H.ReportError(Error::Cast(result), "error evaluating constant constructor");
- }
- return result;
-}
-
FlowGraphBuilder::FlowGraphBuilder(
- TreeNode* node,
+ intptr_t kernel_offset,
ParsedFunction* parsed_function,
const ZoneGrowableArray<const ICData*>& ic_data_array,
ZoneGrowableArray<intptr_t>* context_level_array,
@@ -1268,7 +662,7 @@
: translation_helper_(Thread::Current()),
thread_(translation_helper_.thread()),
zone_(translation_helper_.zone()),
- node_(node),
+ kernel_offset_(kernel_offset),
parsed_function_(parsed_function),
osr_id_(osr_id),
ic_data_array_(ic_data_array),
@@ -1294,7 +688,6 @@
type_translator_(&translation_helper_,
&active_class_,
/* finalize= */ true),
- constant_evaluator_(this, zone_, &translation_helper_, &type_translator_),
streaming_flow_graph_builder_(NULL) {
Script& script = Script::Handle(Z, parsed_function->function().script());
H.SetStringOffsets(TypedData::Handle(Z, script.kernel_string_offsets()));
@@ -1349,9 +742,7 @@
try_finally_block_->finalizer_kernel_offset();
try_finally_block_ = try_finally_block_->outer();
if (finalizer != NULL) {
- // This will potentially have exceptional cases as described in
- // [VisitTryFinally] and will handle them.
- instructions += TranslateStatement(finalizer);
+ UNREACHABLE();
} else {
instructions += streaming_flow_graph_builder_->BuildStatementAt(
finalizer_kernel_offset);
@@ -1378,11 +769,6 @@
}
-Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) {
- return EnterScope(node->kernel_offset(), new_context);
-}
-
-
Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset,
bool* new_context) {
Fragment instructions;
@@ -1399,11 +785,6 @@
}
-Fragment FlowGraphBuilder::ExitScope(TreeNode* node) {
- return ExitScope(node->kernel_offset());
-}
-
-
Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
Fragment instructions;
const intptr_t context_size =
@@ -1474,8 +855,7 @@
#endif
instructions += LoadLocal(scopes_->type_arguments_variable);
} else if (scopes_->this_variable != NULL &&
- active_class_.kernel_class != NULL &&
- active_class_.kernel_class->type_parameters().length() > 0) {
+ active_class_.class_type_parameters > 0) {
ASSERT(!parsed_function_->function().IsFactory());
intptr_t type_arguments_field_offset =
active_class_.klass->type_arguments_field_offset();
@@ -2410,402 +1790,20 @@
if (function.IsConstructorClosureFunction()) return NULL;
- TreeNode* library_node = node_;
- if (node_ != NULL) {
- const Function* parent = &function;
- while (true) {
- library_node = static_cast<kernel::TreeNode*>(parent->kernel_function());
- while (library_node != NULL && !library_node->IsLibrary()) {
- if (library_node->IsMember()) {
- library_node = Member::Cast(library_node)->parent();
- } else if (library_node->IsClass()) {
- library_node = Class::Cast(library_node)->parent();
- break;
- } else {
- library_node = NULL;
- break;
- }
- }
- if (library_node != NULL) break;
- parent = &Function::Handle(parent->parent_function());
- }
- }
if (streaming_flow_graph_builder_ != NULL) {
delete streaming_flow_graph_builder_;
streaming_flow_graph_builder_ = NULL;
}
- if (library_node != NULL && library_node->IsLibrary()) {
- Library* library = Library::Cast(library_node);
- streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder(
- this, library->kernel_data(), library->kernel_data_size());
- }
- dart::Class& klass =
- dart::Class::Handle(zone_, parsed_function_->function().Owner());
+ Script& script = Script::Handle(Z, function.script());
+ streaming_flow_graph_builder_ = new StreamingFlowGraphBuilder(
+ this, script.kernel_data(), script.kernel_data_size());
- Function& outermost_function = Function::Handle(Z);
- TreeNode* outermost_node = NULL;
- Class* kernel_class = NULL;
- DiscoverEnclosingElements(Z, function, &outermost_function, &outermost_node,
- &kernel_class);
-
- // Mark that we are using [klass]/[kernell_klass] as active class. Resolving
- // of type parameters will get resolved via [kernell_klass] unless we are
- // nested inside a static factory in which case we will use [member].
- ActiveClassScope active_class_scope(&active_class_, kernel_class, &klass);
- Member* member = ((outermost_node != NULL) && outermost_node->IsMember())
- ? Member::Cast(outermost_node)
- : NULL;
- ActiveMemberScope active_member(&active_class_, member);
-
- // The IR builder will create its own local variables and scopes, and it
- // will not need an AST. The code generator will assume that there is a
- // local variable stack slot allocated for the current context and (I
- // think) that the runtime will expect it to be at a fixed offset which
- // requires allocating an unused expression temporary variable.
- scopes_ = parsed_function_->EnsureKernelScopes();
-
- switch (function.kind()) {
- case RawFunction::kClosureFunction:
- case RawFunction::kRegularFunction:
- case RawFunction::kGetterFunction:
- case RawFunction::kSetterFunction: {
- FunctionNode* kernel_function = node_->IsProcedure()
- ? Procedure::Cast(node_)->function()
- : FunctionNode::Cast(node_);
- return function.IsImplicitClosureFunction()
- ? BuildGraphOfImplicitClosureFunction(kernel_function,
- function)
- : BuildGraphOfFunction(kernel_function);
- }
- case RawFunction::kConstructor: {
- bool is_factory = function.IsFactory();
- if (is_factory) {
- Procedure* procedure = Procedure::Cast(node_);
- FunctionNode* function = procedure->function();
- return BuildGraphOfFunction(function, NULL);
- } else {
- Constructor* constructor = Constructor::Cast(node_);
- FunctionNode* function = constructor->function();
- return BuildGraphOfFunction(function, constructor);
- }
- }
- case RawFunction::kImplicitGetter:
- case RawFunction::kImplicitStaticFinalGetter:
- case RawFunction::kImplicitSetter: {
- Field* field = Field::Cast(node_);
- return IsStaticInitializer(function, Z)
- ? BuildGraphOfStaticFieldInitializer(field)
- : BuildGraphOfFieldAccessor(field, scopes_->setter_value);
- }
- case RawFunction::kMethodExtractor:
- return BuildGraphOfMethodExtractor(function);
- case RawFunction::kNoSuchMethodDispatcher:
- return BuildGraphOfNoSuchMethodDispatcher(function);
- case RawFunction::kInvokeFieldDispatcher:
- return BuildGraphOfInvokeFieldDispatcher(function);
- case RawFunction::kSignatureFunction:
- case RawFunction::kIrregexpFunction:
- break;
- }
- UNREACHABLE();
- return NULL;
+ return streaming_flow_graph_builder_->BuildGraph(kernel_offset_);
}
-FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function,
- Constructor* constructor) {
- const Function& dart_function = parsed_function_->function();
- TargetEntryInstr* normal_entry = BuildTargetEntry();
- graph_entry_ =
- new (Z) GraphEntryInstr(*parsed_function_, normal_entry, osr_id_);
-
- SetupDefaultParameterValues(function);
-
- Fragment body;
- if (!dart_function.is_native()) body += CheckStackOverflowInPrologue();
- intptr_t context_size =
- parsed_function_->node_sequence()->scope()->num_context_variables();
- if (context_size > 0) {
- body += PushContext(context_size);
- LocalVariable* context = MakeTemporary();
-
- // Copy captured parameters from the stack into the context.
- LocalScope* scope = parsed_function_->node_sequence()->scope();
- intptr_t parameter_count = dart_function.NumParameters();
- intptr_t parameter_index = parsed_function_->first_parameter_index();
- for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) {
- LocalVariable* variable = scope->VariableAt(i);
- if (variable->is_captured()) {
- // There is no LocalVariable describing the on-stack parameter so
- // create one directly and use the same type.
- LocalVariable* parameter = new (Z)
- LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
- Symbols::TempParam(), variable->type());
- parameter->set_index(parameter_index);
- // Mark the stack variable so it will be ignored by the code for
- // try/catch.
- parameter->set_is_captured_parameter(true);
-
- // Copy the parameter from the stack to the context. Overwrite it
- // with a null constant on the stack so the original value is
- // eligible for garbage collection.
- body += LoadLocal(context);
- body += LoadLocal(parameter);
- body += StoreInstanceField(TokenPosition::kNoSource,
- Context::variable_offset(variable->index()));
- body += NullConstant();
- body += StoreLocal(TokenPosition::kNoSource, parameter);
- body += Drop();
- }
- }
- body += Drop(); // The context.
- }
- if (constructor != NULL) {
- // TODO(27590): Currently the [VariableDeclaration]s from the
- // initializers will be visible inside the entire body of the constructor.
- // We should make a separate scope for them.
- Class* kernel_class = Class::Cast(constructor->parent());
- body += TranslateInitializers(kernel_class, &constructor->initializers());
- }
-
- // The specification defines the result of `a == b` to be:
- //
- // a) if either side is `null` then the result is `identical(a, b)`.
- // b) else the result is `a.operator==(b)`
- //
- // For user-defined implementations of `operator==` we need therefore
- // implement the handling of a).
- //
- // The default `operator==` implementation in `Object` is implemented in terms
- // of identical (which we assume here!) which means that case a) is actually
- // included in b). So we just use the normal implementation in the body.
- if ((dart_function.NumParameters() == 2) &&
- (dart_function.name() == Symbols::EqualOperator().raw()) &&
- (dart_function.Owner() != I->object_store()->object_class())) {
- LocalVariable* parameter =
- LookupVariable(function->positional_parameters()[0]);
-
- TargetEntryInstr* null_entry;
- TargetEntryInstr* non_null_entry;
-
- body += LoadLocal(parameter);
- body += BranchIfNull(&null_entry, &non_null_entry);
-
- // The argument was `null` and the receiver is not the null class (we only
- // go into this branch for user-defined == operators) so we can return
- // false.
- Fragment null_fragment(null_entry);
- null_fragment += Constant(Bool::False());
- null_fragment += Return(dart_function.end_token_pos());
-
- body = Fragment(body.entry, non_null_entry);
- }
-
- // If we run in checked mode, we have to check the type of the passed
- // arguments.
- if (I->type_checks()) {
- List<VariableDeclaration>& positional = function->positional_parameters();
- List<VariableDeclaration>& named = function->named_parameters();
-
- for (intptr_t i = 0; i < positional.length(); i++) {
- VariableDeclaration* variable = positional[i];
- body += LoadLocal(LookupVariable(variable));
- body += CheckVariableTypeInCheckedMode(variable);
- body += Drop();
- }
- for (intptr_t i = 0; i < named.length(); i++) {
- VariableDeclaration* variable = named[i];
- body += LoadLocal(LookupVariable(variable));
- body += CheckVariableTypeInCheckedMode(variable);
- body += Drop();
- }
- }
-
- if (FLAG_causal_async_stacks &&
- (dart_function.IsAsyncFunction() || dart_function.IsAsyncGenerator())) {
- LocalScope* scope = parsed_function_->node_sequence()->scope();
- // :async_stack_trace = _asyncStackTraceHelper(:async_op);
- const dart::Library& async_lib =
- dart::Library::Handle(dart::Library::AsyncLibrary());
- const Function& target = Function::ZoneHandle(
- Z,
- async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper()));
- ASSERT(!target.IsNull());
-
- // TODO(johnmccutchan): Why does this have the null value?
- LocalVariable* async_op =
- scope->child()->LookupVariable(Symbols::AsyncOperation(), false);
- ASSERT(async_op != NULL);
- ASSERT(async_op->is_captured());
- body += LoadLocal(async_op);
- body += PushArgument();
- body += StaticCall(TokenPosition::kNoSource, target, 1);
- LocalVariable* async_stack_trace_var =
- scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
- ASSERT(async_stack_trace_var != NULL);
- body += StoreLocal(TokenPosition::kNoSource, async_stack_trace_var);
- body += Drop();
- }
-
- if (dart_function.is_native()) {
- body += NativeFunctionBody(function, dart_function);
- } else if (function->body() != NULL) {
- body += TranslateStatement(function->body());
- }
- if (body.is_open()) {
- body += NullConstant();
- body += Return(dart_function.end_token_pos());
- }
-
- // If functions body contains any yield points build switch statement that
- // selects a continuation point based on the value of :await_jump_var.
- if (!yield_continuations_.is_empty()) {
- // The code we are building will be executed right after we enter
- // the function and before any nested contexts are allocated.
- // Reset current context_depth_ to match this.
- const intptr_t current_context_depth = context_depth_;
- context_depth_ = scopes_->yield_jump_variable->owner()->context_level();
-
- // Prepend an entry corresponding to normal entry to the function.
- yield_continuations_.InsertAt(
- 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL),
- CatchClauseNode::kInvalidTryIndex));
- yield_continuations_[0].entry->LinkTo(body.entry);
-
- // Build a switch statement.
- Fragment dispatch;
-
- // Load :await_jump_var into a temporary.
- dispatch += LoadLocal(scopes_->yield_jump_variable);
- dispatch += StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable);
- dispatch += Drop();
-
- BlockEntryInstr* block = NULL;
- for (intptr_t i = 0; i < yield_continuations_.length(); i++) {
- if (i == 1) {
- // This is not a normal entry but a resumption. Restore
- // :current_context_var from :await_ctx_var.
- // Note: after this point context_depth_ does not match current context
- // depth so we should not access any local variables anymore.
- dispatch += LoadLocal(scopes_->yield_context_variable);
- dispatch += StoreLocal(TokenPosition::kNoSource,
- parsed_function_->current_context_var());
- dispatch += Drop();
- }
- if (i == (yield_continuations_.length() - 1)) {
- // We reached the last possility, no need to build more ifs.
- // Continue to the last continuation.
- // Note: continuations start with nop DropTemps instruction
- // which acts like an anchor, so we need to skip it.
- block->set_try_index(yield_continuations_[i].try_index);
- dispatch <<= yield_continuations_[i].entry->next();
- break;
- }
-
- // Build comparison:
- //
- // if (:await_ctx_var == i) {
- // -> yield_continuations_[i]
- // } else ...
- //
- TargetEntryInstr* then;
- TargetEntryInstr* otherwise;
- dispatch += LoadLocal(scopes_->switch_variable);
- dispatch += IntConstant(i);
- dispatch += BranchIfStrictEqual(&then, &otherwise);
-
- // True branch is linked to appropriate continuation point.
- // Note: continuations start with nop DropTemps instruction
- // which acts like an anchor, so we need to skip it.
- then->LinkTo(yield_continuations_[i].entry->next());
- then->set_try_index(yield_continuations_[i].try_index);
- // False branch will contain the next comparison.
- dispatch = Fragment(dispatch.entry, otherwise);
- block = otherwise;
- }
- body = dispatch;
-
- context_depth_ = current_context_depth;
- }
-
- if (FLAG_causal_async_stacks &&
- (dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) {
- // The code we are building will be executed right after we enter
- // the function and before any nested contexts are allocated.
- // Reset current context_depth_ to match this.
- const intptr_t current_context_depth = context_depth_;
- context_depth_ = scopes_->yield_jump_variable->owner()->context_level();
-
- Fragment instructions;
- LocalScope* scope = parsed_function_->node_sequence()->scope();
-
- const Function& target = Function::ZoneHandle(
- Z, I->object_store()->async_set_thread_stack_trace());
- ASSERT(!target.IsNull());
-
- // Fetch and load :async_stack_trace
- LocalVariable* async_stack_trace_var =
- scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
- ASSERT((async_stack_trace_var != NULL) &&
- async_stack_trace_var->is_captured());
- instructions += LoadLocal(async_stack_trace_var);
- instructions += PushArgument();
-
- // Call _asyncSetThreadStackTrace
- instructions += StaticCall(TokenPosition::kNoSource, target, 1);
- instructions += Drop();
-
- // TODO(29737): This sequence should be generated in order.
- body = instructions + body;
- context_depth_ = current_context_depth;
- }
-
- if (NeedsDebugStepCheck(dart_function, function->position())) {
- const intptr_t current_context_depth = context_depth_;
- context_depth_ = 0;
-
- // If a switch was added above: Start the switch by injecting a debuggable
- // safepoint so stepping over an await works.
- // If not, still start the body with a debuggable safepoint to ensure
- // breaking on a method always happens, even if there are no
- // assignments/calls/runtimecalls in the first basic block.
- // Place this check at the last parameter to ensure parameters
- // are in scope in the debugger at method entry.
- const int num_params = dart_function.NumParameters();
- TokenPosition check_pos = TokenPosition::kNoSource;
- if (num_params > 0) {
- LocalScope* scope = parsed_function_->node_sequence()->scope();
- const LocalVariable& parameter = *scope->VariableAt(num_params - 1);
- check_pos = parameter.token_pos();
- }
- if (!check_pos.IsDebugPause()) {
- // No parameters or synthetic parameters.
- check_pos = function->position();
- ASSERT(check_pos.IsDebugPause());
- }
-
- // TODO(29737): This sequence should be generated in order.
- body = DebugStepCheck(check_pos) + body;
- context_depth_ = current_context_depth;
- }
-
- normal_entry->LinkTo(body.entry);
-
- // When compiling for OSR, use a depth first search to prune instructions
- // unreachable from the OSR entry. Catch entries are always considered
- // reachable, even if they become unreachable after OSR.
- if (osr_id_ != Compiler::kNoOSRDeoptId) {
- BitVector* block_marks = new (Z) BitVector(Z, next_block_id_);
- bool found = graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_,
- block_marks);
- ASSERT(found);
- }
- return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
-}
-
-
-Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
+Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset,
const Function& function) {
ASSERT(function.is_native());
// We explicitly build the graph for native functions in the same way that the
@@ -2817,8 +1815,7 @@
switch (kind) {
case MethodRecognizer::kObjectEquals:
body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += StrictCompare(Token::kEQ_STRICT);
break;
case MethodRecognizer::kStringBaseLength:
@@ -2856,8 +1853,7 @@
Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true);
break;
case MethodRecognizer::kClassIDgetID:
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += LoadClassId();
break;
case MethodRecognizer::kGrowableArrayCapacity:
@@ -2869,8 +1865,7 @@
break;
case MethodRecognizer::kObjectArrayAllocate:
body += LoadLocal(scopes_->type_arguments_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += CreateArray();
break;
case MethodRecognizer::kBigint_getDigits:
@@ -2890,8 +1885,7 @@
break;
case MethodRecognizer::kLinkedHashMap_setIndex:
body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += StoreInstanceField(TokenPosition::kNoSource,
LinkedHashMap::index_offset());
body += NullConstant();
@@ -2903,8 +1897,7 @@
break;
case MethodRecognizer::kLinkedHashMap_setData:
body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += StoreInstanceField(TokenPosition::kNoSource,
LinkedHashMap::data_offset());
body += NullConstant();
@@ -2916,8 +1909,7 @@
break;
case MethodRecognizer::kLinkedHashMap_setHashMask:
body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += StoreInstanceField(TokenPosition::kNoSource,
LinkedHashMap::hash_mask_offset(),
kNoStoreBarrier);
@@ -2930,8 +1922,7 @@
break;
case MethodRecognizer::kLinkedHashMap_setUsedData:
body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += StoreInstanceField(TokenPosition::kNoSource,
LinkedHashMap::used_data_offset(),
kNoStoreBarrier);
@@ -2944,8 +1935,7 @@
break;
case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(
- LookupVariable(kernel_function->positional_parameters()[0]));
+ body += LoadLocal(LookupVariable(first_positional_offset));
body += StoreInstanceField(TokenPosition::kNoSource,
LinkedHashMap::deleted_keys_offset(),
kNoStoreBarrier);
@@ -2966,82 +1956,6 @@
}
-FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor(
- Field* kernel_field,
- LocalVariable* setter_value) {
- const Function& function = parsed_function_->function();
-
- bool is_setter = function.IsImplicitSetterFunction();
- bool is_method = !function.IsStaticFunction();
- dart::Field& field = dart::Field::ZoneHandle(
- Z, H.LookupFieldByKernelField(kernel_field->canonical_name()));
-
- TargetEntryInstr* normal_entry = BuildTargetEntry();
- graph_entry_ = new (Z)
- GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
-
- Fragment body(normal_entry);
- if (is_setter) {
- if (is_method) {
- body += LoadLocal(scopes_->this_variable);
- body += LoadLocal(setter_value);
- body += StoreInstanceFieldGuarded(field, false);
- } else {
- body += LoadLocal(setter_value);
- body += StoreStaticField(TokenPosition::kNoSource, field);
- }
- body += NullConstant();
- } else if (is_method) {
- body += LoadLocal(scopes_->this_variable);
- body += LoadField(field);
- } else if (field.is_const()) {
- // If the parser needs to know the value of an uninitialized constant field
- // it will set the value to the transition sentinel (used to detect circular
- // initialization) and then call the implicit getter. Thus, the getter
- // cannot contain the InitStaticField instruction that normal static getters
- // contain because it would detect spurious circular initialization when it
- // checks for the transition sentinel.
- Expression* initializer = kernel_field->initializer();
- ASSERT(initializer != NULL);
- body += Constant(constant_evaluator_.EvaluateExpression(initializer));
- } else {
- // The field always has an initializer because static fields without
- // initializers are initialized eagerly and do not have implicit getters.
- ASSERT(field.has_initializer());
- body += Constant(field);
- body += InitStaticField(field);
- body += Constant(field);
- body += LoadStaticField();
- }
- body += Return(TokenPosition::kNoSource);
-
- return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
-}
-
-
-FlowGraph* FlowGraphBuilder::BuildGraphOfStaticFieldInitializer(
- Field* kernel_field) {
- ASSERT(kernel_field->IsStatic());
-
- Expression* initializer = kernel_field->initializer();
-
- TargetEntryInstr* normal_entry = BuildTargetEntry();
- graph_entry_ = new (Z)
- GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
-
- Fragment body(normal_entry);
- body += CheckStackOverflowInPrologue();
- if (kernel_field->IsConst()) {
- body += Constant(constant_evaluator_.EvaluateExpression(initializer));
- } else {
- body += TranslateExpression(initializer);
- }
- body += Return(TokenPosition::kNoSource);
-
- return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
-}
-
-
Fragment FlowGraphBuilder::BuildImplicitClosureCreation(
const Function& target) {
Fragment fragment;
@@ -3101,19 +2015,6 @@
Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
- VariableDeclaration* variable) {
- if (I->type_checks()) {
- const AbstractType& dst_type = T.TranslateType(variable->type());
- if (dst_type.IsMalformed()) {
- return ThrowTypeError();
- }
- return CheckAssignableInCheckedMode(dst_type,
- H.DartSymbol(variable->name()));
- }
- return Fragment();
-}
-
-Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
const AbstractType& dst_type,
const dart::String& name_symbol) {
if (I->type_checks()) {
@@ -3257,58 +2158,6 @@
}
-FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
- FunctionNode* kernel_function,
- const Function& function) {
- const Function& target = Function::ZoneHandle(Z, function.parent_function());
-
- TargetEntryInstr* normal_entry = BuildTargetEntry();
- graph_entry_ = new (Z)
- GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
- SetupDefaultParameterValues(kernel_function);
-
- Fragment body(normal_entry);
- body += CheckStackOverflowInPrologue();
-
- // Load all the arguments.
- if (!target.is_static()) {
- // The context has a fixed shape: a single variable which is the
- // closed-over receiver.
- body += LoadLocal(parsed_function_->current_context_var());
- body += LoadField(Context::variable_offset(0));
- body += PushArgument();
- }
- intptr_t positional_argument_count =
- kernel_function->positional_parameters().length();
- for (intptr_t i = 0; i < positional_argument_count; i++) {
- body +=
- LoadLocal(LookupVariable(kernel_function->positional_parameters()[i]));
- body += PushArgument();
- }
- intptr_t named_argument_count = kernel_function->named_parameters().length();
- Array& argument_names = Array::ZoneHandle(Z);
- if (named_argument_count > 0) {
- argument_names = Array::New(named_argument_count);
- for (intptr_t i = 0; i < named_argument_count; i++) {
- VariableDeclaration* variable = kernel_function->named_parameters()[i];
- body += LoadLocal(LookupVariable(variable));
- body += PushArgument();
- argument_names.SetAt(i, H.DartSymbol(variable->name()));
- }
- }
- // Forward them to the target.
- intptr_t argument_count = positional_argument_count + named_argument_count;
- if (!target.is_static()) ++argument_count;
- body += StaticCall(TokenPosition::kNoSource, target, argument_count,
- argument_names);
-
- // Return the result.
- body += Return(kernel_function->end_position());
-
- return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
-}
-
-
FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
const Function& function) {
// This function is specialized for a receiver class, a method name, and
@@ -3500,47 +2349,6 @@
}
-void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) {
- intptr_t num_optional_parameters =
- parsed_function_->function().NumOptionalParameters();
- if (num_optional_parameters > 0) {
- ZoneGrowableArray<const Instance*>* default_values =
- new ZoneGrowableArray<const Instance*>(Z, num_optional_parameters);
-
- if (parsed_function_->function().HasOptionalNamedParameters()) {
- ASSERT(!parsed_function_->function().HasOptionalPositionalParameters());
- for (intptr_t i = 0; i < num_optional_parameters; i++) {
- VariableDeclaration* variable = function->named_parameters()[i];
- Instance* default_value;
- if (variable->initializer() != NULL) {
- default_value =
- &constant_evaluator_.EvaluateExpression(variable->initializer());
- } else {
- default_value = &Instance::ZoneHandle(Z, Instance::null());
- }
- default_values->Add(default_value);
- }
- } else {
- ASSERT(parsed_function_->function().HasOptionalPositionalParameters());
- intptr_t required = function->required_parameter_count();
- for (intptr_t i = 0; i < num_optional_parameters; i++) {
- VariableDeclaration* variable =
- function->positional_parameters()[required + i];
- Instance* default_value;
- if (variable->initializer() != NULL) {
- default_value =
- &constant_evaluator_.EvaluateExpression(variable->initializer());
- } else {
- default_value = &Instance::ZoneHandle(Z, Instance::null());
- }
- default_values->Add(default_value);
- }
- }
- parsed_function_->set_default_parameter_values(default_values);
- }
-}
-
-
TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() {
return new (Z)
TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
@@ -3557,171 +2365,6 @@
JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
}
-
-Fragment FlowGraphBuilder::TranslateFieldInitializer(NameIndex canonical_name,
- Expression* init) {
- dart::Field& field =
- dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name));
- if (init->IsNullLiteral()) {
- field.RecordStore(Object::null_object());
- return Fragment();
- }
- Fragment instructions;
- instructions += LoadLocal(scopes_->this_variable);
- instructions += TranslateExpression(init);
- instructions += StoreInstanceFieldGuarded(field, true);
- return instructions;
-}
-
-
-Fragment FlowGraphBuilder::TranslateInitializers(
- Class* kernel_class,
- List<Initializer>* initializers) {
- Fragment instructions;
-
- // These come from:
- // class A {
- // var x = (expr);
- // }
- for (intptr_t i = 0; i < kernel_class->fields().length(); i++) {
- Field* kernel_field = kernel_class->fields()[i];
- Expression* init = kernel_field->initializer();
- if (!kernel_field->IsStatic() && init != NULL) {
- EnterScope(kernel_field);
- instructions +=
- TranslateFieldInitializer(kernel_field->canonical_name(), init);
- ExitScope(kernel_field);
- }
- }
-
- // These to come from:
- // class A {
- // var x;
- // var y;
- // A(this.x) : super(expr), y = (expr);
- // }
- for (intptr_t i = 0; i < initializers->length(); i++) {
- Initializer* initializer = (*initializers)[i];
- if (initializer->IsFieldInitializer()) {
- FieldInitializer* init = FieldInitializer::Cast(initializer);
- instructions += TranslateFieldInitializer(init->field(), init->value());
- } else if (initializer->IsSuperInitializer()) {
- SuperInitializer* init = SuperInitializer::Cast(initializer);
-
- instructions += LoadLocal(scopes_->this_variable);
- instructions += PushArgument();
-
- ASSERT(init->arguments()->types().length() == 0);
- Array& argument_names = Array::ZoneHandle(Z);
- instructions += TranslateArguments(init->arguments(), &argument_names);
-
- const Function& target = Function::ZoneHandle(
- Z, H.LookupConstructorByKernelConstructor(init->target()));
- intptr_t argument_count = init->arguments()->count() + 1;
- instructions += StaticCall(TokenPosition::kNoSource, target,
- argument_count, argument_names);
- instructions += Drop();
- } else if (initializer->IsRedirectingInitializer()) {
- RedirectingInitializer* init = RedirectingInitializer::Cast(initializer);
-
- instructions += LoadLocal(scopes_->this_variable);
- instructions += PushArgument();
-
- ASSERT(init->arguments()->types().length() == 0);
- Array& argument_names = Array::ZoneHandle(Z);
- instructions += TranslateArguments(init->arguments(), &argument_names);
-
- const Function& target = Function::ZoneHandle(
- Z, H.LookupConstructorByKernelConstructor(init->target()));
- intptr_t argument_count = init->arguments()->count() + 1;
- instructions += StaticCall(TokenPosition::kNoSource, target,
- argument_count, argument_names);
- instructions += Drop();
- } else if (initializer->IsLocalInitializer()) {
- // The other initializers following this one might read the variable. This
- // is used e.g. for evaluating the arguments to a super call first, run
- // normal field initializers next and then make the actual super call:
- //
- // The frontend converts
- //
- // class A {
- // var x;
- // A(a, b) : super(a + b), x = 2*b {}
- // }
- //
- // to
- //
- // class A {
- // var x;
- // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {}
- // }
- //
- // (This is strictly speaking not what one should do in terms of the
- // specification but that is how it is currently implemented.)
- LocalInitializer* init = LocalInitializer::Cast(initializer);
-
- VariableDeclaration* declaration = init->variable();
- LocalVariable* variable = LookupVariable(declaration);
- Expression* initializer = init->variable()->initializer();
- ASSERT(initializer != NULL);
- ASSERT(!declaration->IsConst());
-
- instructions += TranslateExpression(initializer);
- instructions += StoreLocal(TokenPosition::kNoSource, variable);
- instructions += Drop();
-
- fragment_ = instructions;
- } else {
- UNIMPLEMENTED();
- }
- }
- return instructions;
-}
-
-
-Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) {
-#ifdef DEBUG
- intptr_t original_context_depth = context_depth_;
-#endif
-
- // TODO(jensj): VariableDeclaration doesn't necessarily have a tag.
- if (statement->can_stream() &&
- statement->Type() != Node::kTypeVariableDeclaration) {
- fragment_ = streaming_flow_graph_builder_->BuildStatementAt(
- statement->kernel_offset());
- } else {
- statement->AcceptStatementVisitor(this);
- }
- DEBUG_ASSERT(context_depth_ == original_context_depth);
- return fragment_;
-}
-
-
-Fragment FlowGraphBuilder::TranslateCondition(Expression* expression,
- bool* negate) {
- *negate = expression->IsNot();
- Fragment instructions;
- if (*negate) {
- instructions += TranslateExpression(Not::Cast(expression)->expression());
- } else {
- instructions += TranslateExpression(expression);
- }
- instructions += CheckBooleanInCheckedMode();
- return instructions;
-}
-
-
-Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) {
- if (expression->can_stream()) {
- fragment_ = streaming_flow_graph_builder_->BuildExpressionAt(
- expression->kernel_offset());
- } else {
- expression->AcceptExpressionVisitor(this);
- }
- return fragment_;
-}
-
-
ArgumentArray FlowGraphBuilder::GetArguments(int count) {
ArgumentArray arguments =
new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count);
@@ -3746,54 +2389,6 @@
}
-void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
AbstractType& DartTypeTranslator::TranslateType(DartType* node) {
node->AcceptDartTypeVisitor(this);
@@ -4093,1923 +2688,11 @@
return type;
}
-void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- const AbstractType& type = T.TranslateType(node->type());
- if (type.IsMalformed()) H.ReportError("Malformed type literal");
-
- Fragment instructions;
- if (type.IsInstantiated()) {
- instructions += Constant(type);
- } else {
- if (!type.IsInstantiated(kCurrentClass)) {
- instructions += LoadInstantiatorTypeArguments();
- } else {
- instructions += NullConstant();
- }
- if (!type.IsInstantiated(kFunctions)) {
- instructions += LoadFunctionTypeArguments();
- } else {
- instructions += NullConstant();
- }
- instructions += InstantiateType(type);
- }
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitVariableGet(VariableGet* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->expression());
- if (NeedsDebugStepCheck(stack_, node->position())) {
- instructions = DebugStepCheck(node->position()) + instructions;
- }
- instructions += CheckVariableTypeInCheckedMode(node->variable());
- instructions +=
- StoreLocal(node->position(), LookupVariable(node->variable()));
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitStaticGet(StaticGet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- // A StaticGet will always have a kernel_offset, except for the StaticGet that
- // was manually created for _getMainClosure in dart:_builtin. Compile that
- // one specially here.
- const dart::Library& builtin =
- dart::Library::Handle(Z, I->object_store()->builtin_library());
- const Object& main =
- Object::Handle(Z, builtin.LookupObjectAllowPrivate(dart::String::Handle(
- Z, dart::String::New("main"))));
- if (main.IsField()) {
- UNIMPLEMENTED();
- } else if (main.IsFunction()) {
- const Function& function = Function::Cast(main);
- if (function.kind() == RawFunction::kRegularFunction) {
- const Function& closure_function =
- Function::Handle(Z, function.ImplicitClosureFunction());
- closure_function.set_kernel_function(function.kernel_function());
- const Instance& closure =
- Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure());
- fragment_ = Constant(closure);
- } else {
- UNIMPLEMENTED();
- }
- } else {
- UNIMPLEMENTED();
- }
-}
-
-
-void FlowGraphBuilder::VisitStaticSet(StaticSet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- NameIndex target = node->target();
- if (H.IsField(target)) {
- const dart::Field& field =
- dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
- const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
- Fragment instructions = TranslateExpression(node->expression());
- if (NeedsDebugStepCheck(stack_, node->position())) {
- instructions = DebugStepCheck(node->position()) + instructions;
- }
- instructions += CheckAssignableInCheckedMode(
- dst_type, dart::String::ZoneHandle(Z, field.name()));
- LocalVariable* variable = MakeTemporary();
- instructions += LoadLocal(variable);
- fragment_ = instructions + StoreStaticField(node->position(), field);
- } else {
- ASSERT(H.IsProcedure(target));
-
- // Evaluate the expression on the right hand side.
- Fragment instructions = TranslateExpression(node->expression());
- LocalVariable* variable = MakeTemporary();
-
- // Prepare argument.
- instructions += LoadLocal(variable);
- instructions += PushArgument();
-
- // Invoke the setter function.
- const Function& function =
- Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
- instructions += StaticCall(node->position(), function, 1);
-
- // Drop the unused result & leave the stored value on the stack.
- fragment_ = instructions + Drop();
- }
-}
-
-
-void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->receiver());
- instructions += PushArgument();
- const dart::String& getter_name = H.DartGetterName(node->name());
- fragment_ = instructions +
- InstanceCall(node->position(), getter_name, Token::kGET, 1);
-}
-
-
-void FlowGraphBuilder::VisitPropertySet(PropertySet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions(NullConstant());
- LocalVariable* variable = MakeTemporary();
- instructions += TranslateExpression(node->receiver());
- instructions += PushArgument();
- instructions += TranslateExpression(node->value());
- instructions += StoreLocal(TokenPosition::kNoSource, variable);
- instructions += PushArgument();
-
- const dart::String& setter_name = H.DartSetterName(node->name());
- instructions += InstanceCall(node->position(), setter_name, Token::kSET, 2);
- fragment_ = instructions + Drop();
-}
-
-
-void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Function& target = Function::ZoneHandle(Z);
- NameIndex kernel_name = node->target();
- if (H.IsProcedure(kernel_name)) {
- if (H.IsGetter(kernel_name)) {
- target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name));
- } else {
- target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name));
- target = target.ImplicitClosureFunction();
- ASSERT(!target.IsNull());
- fragment_ = BuildImplicitClosureCreation(target);
- return;
- }
- } else {
- ASSERT(H.IsField(kernel_name));
- const dart::String& getter_name = H.DartGetterName(kernel_name);
- target = LookupMethodByMember(kernel_name, getter_name);
- ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction());
- }
-
- Fragment instructions = TranslateExpression(node->receiver());
- instructions += PushArgument();
- fragment_ = instructions + StaticCall(node->position(), target, 1);
-}
-
-
-void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- const dart::String& method_name = H.DartSetterName(node->target());
- const Function& target = Function::ZoneHandle(
- Z, LookupMethodByMember(node->target(), method_name));
- ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
-
- Fragment instructions(NullConstant());
- LocalVariable* value = MakeTemporary();
- instructions += TranslateExpression(node->receiver());
- instructions += PushArgument();
- instructions += TranslateExpression(node->value());
- instructions += StoreLocal(TokenPosition::kNoSource, value);
- instructions += PushArgument();
- instructions += StaticCall(node->position(), target, 2);
-
- fragment_ = instructions + Drop();
-}
-
-
-void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- const Function& target = Function::ZoneHandle(
- Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
- const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner());
- intptr_t argument_count = node->arguments()->count();
- if (target.IsGenerativeConstructor() || target.IsFactory()) {
- // The VM requires a TypeArguments object as first parameter for
- // every factory constructor.
- ++argument_count;
- }
-
- List<NamedExpression>& named = node->arguments()->named();
- const Array& argument_names = H.ArgumentNames(&named);
-
- // The frontend ensures we the [StaticInvocation] has matching arguments.
- const intptr_t kTypeArgsLen = 0; // Generic functions not yet supported.
- ASSERT(target.AreValidArguments(kTypeArgsLen, argument_count, argument_names,
- NULL));
-
- Fragment instructions;
- LocalVariable* instance_variable = NULL;
-
- // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
- // can appear, but the thing we're calling is not a static method, but a
- // factory constructor.
- // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the
- // forwarded constructor.
- // In that case we'll make an instance and pass it as first argument.
- //
- // TODO(27590): Get rid of this after we're using core libraries compiled
- // into Kernel.
- if (target.IsGenerativeConstructor()) {
- if (klass.NumTypeArguments() > 0) {
- List<DartType>& kernel_type_arguments = node->arguments()->types();
- const TypeArguments& type_arguments =
- T.TranslateInstantiatedTypeArguments(
- klass, kernel_type_arguments.raw_array(),
- kernel_type_arguments.length());
- instructions += TranslateInstantiatedTypeArguments(type_arguments);
- instructions += PushArgument();
- instructions += AllocateObject(klass, 1);
- } else {
- instructions += AllocateObject(klass, 0);
- }
-
- instance_variable = MakeTemporary();
-
- instructions += LoadLocal(instance_variable);
- instructions += PushArgument();
- } else if (target.IsFactory()) {
- // The VM requires currently a TypeArguments object as first parameter for
- // every factory constructor :-/ !
- //
- // TODO(27590): Get rid of this after we're using core libraries compiled
- // into Kernel.
- List<DartType>& kernel_type_arguments = node->arguments()->types();
-
- const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
- klass, kernel_type_arguments.raw_array(),
- kernel_type_arguments.length());
-
- instructions += TranslateInstantiatedTypeArguments(type_arguments);
- instructions += PushArgument();
- } else {
- // TODO(28109) Support generic methods in the VM or reify them away.
- }
-
- // Special case identical(x, y) call.
- // TODO(27590) consider moving this into the inliner and force inline it
- // there.
- if (klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) &&
- (target.name() == Symbols::Identical().raw())) {
- ASSERT(argument_count == 2);
-
- List<Expression>& positional = node->arguments()->positional();
- for (intptr_t i = 0; i < positional.length(); ++i) {
- instructions += TranslateExpression(positional[i]);
- }
- instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
- } else {
- instructions += TranslateArguments(node->arguments(), NULL);
- instructions +=
- StaticCall(node->position(), target, argument_count, argument_names);
-
- if (target.IsGenerativeConstructor()) {
- // Drop the result of the constructor call and leave [instance_variable]
- // on top-of-stack.
- instructions += Drop();
- }
- }
-
- fragment_ = instructions;
-}
-
-
-static bool IsNumberLiteral(Node* node) {
- return node->IsIntLiteral() || node->IsDoubleLiteral();
-}
-
-template <class Invocation>
-bool FlowGraphBuilder::RecognizeComparisonWithNull(Token::Kind token_kind,
- Invocation* node) {
- if (token_kind == Token::kEQ || token_kind == Token::kNE) {
- if (node->arguments()->positional().length() != 1) return false;
- Fragment instructions;
- Expression* left = node->receiver();
- Expression* right = node->arguments()->positional()[0];
- if (left->IsNullLiteral() || right->IsNullLiteral()) {
- instructions += TranslateExpression(left);
- instructions += TranslateExpression(right);
- Token::Kind strict_cmp_kind =
- token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
- fragment_ = instructions + StrictCompare(strict_cmp_kind,
- /*number_check = */ true);
- return true;
- }
- }
- return false;
-}
-
-
-void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- const dart::String& name = H.DartMethodName(node->name());
- const intptr_t argument_count = node->arguments()->count() + 1;
- const Token::Kind token_kind = MethodKind(name);
- if (IsNumberLiteral(node->receiver())) {
- if ((argument_count == 1) && (token_kind == Token::kNEGATE)) {
- const Object& result = constant_evaluator_.EvaluateExpressionSafe(node);
- if (!result.IsError()) {
- fragment_ = Constant(result);
- return;
- }
- } else if ((argument_count == 2) &&
- Token::IsBinaryArithmeticOperator(token_kind) &&
- IsNumberLiteral(node->arguments()->positional()[0])) {
- const Object& result = constant_evaluator_.EvaluateExpressionSafe(node);
- if (!result.IsError()) {
- fragment_ = Constant(result);
- return;
- }
- }
- }
-
- if (RecognizeComparisonWithNull(token_kind, node)) return;
-
- Fragment instructions = TranslateExpression(node->receiver());
- instructions += PushArgument();
-
- // TODO(28109) Support generic methods in the VM or reify them away.
- Array& argument_names = Array::ZoneHandle(Z);
- instructions += TranslateArguments(node->arguments(), &argument_names);
-
- intptr_t num_args_checked = 1;
- // If we have a special operation (e.g. +/-/==) we mark both arguments as
- // to be checked.
- if (token_kind != Token::kILLEGAL) {
- ASSERT(argument_count <= 2);
- num_args_checked = argument_count;
- }
-
- fragment_ = instructions + InstanceCall(node->position(), name, token_kind,
- argument_count, argument_names,
- num_args_checked);
- // Later optimization passes assume that result of a x.[]=(...) call is not
- // used. We must guarantee this invariant because violation will lead to an
- // illegal IL once we replace x.[]=(...) with a sequence that does not
- // actually produce any value. See http://dartbug.com/29135 for more details.
- if (name.raw() == Symbols::AssignIndexToken().raw()) {
- fragment_ += Drop();
- fragment_ += NullConstant();
- }
-}
-
-
-void FlowGraphBuilder::VisitDirectMethodInvocation(
- DirectMethodInvocation* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- const dart::String& method_name = H.DartProcedureName(node->target());
- const Token::Kind token_kind = MethodKind(method_name);
-
- if (RecognizeComparisonWithNull(token_kind, node)) return;
-
- const Function& target = Function::ZoneHandle(
- Z, LookupMethodByMember(node->target(), method_name));
-
- intptr_t argument_count = node->arguments()->count() + 1;
- Array& argument_names = Array::ZoneHandle(Z);
-
- // TODO(28109) Support generic methods in the VM or reify them away.
- Fragment instructions = TranslateExpression(node->receiver());
- instructions += PushArgument();
- instructions += TranslateArguments(node->arguments(), &argument_names);
- fragment_ = instructions + StaticCall(node->position(), target,
- argument_count, argument_names);
-}
-
-
-void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- if (node->is_const()) {
- fragment_ =
- Constant(constant_evaluator_.EvaluateConstructorInvocation(node));
- return;
- }
-
- dart::Class& klass = dart::Class::ZoneHandle(
- Z, H.LookupClassByKernelClass(H.EnclosingName(node->target())));
-
- Fragment instructions;
-
- // Check for malbounded-ness of type.
- if (I->type_checks()) {
- List<DartType>& kernel_type_arguments = node->arguments()->types();
- const TypeArguments& type_arguments = T.TranslateTypeArguments(
- kernel_type_arguments.raw_array(), kernel_type_arguments.length());
-
- AbstractType& type = AbstractType::Handle(
- Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
- type = ClassFinalizer::FinalizeType(klass, type);
-
- if (type.IsMalbounded()) {
- // Evaluate expressions for correctness.
- List<Expression>& positional = node->arguments()->positional();
- List<NamedExpression>& named = node->arguments()->named();
- for (intptr_t i = 0; i < positional.length(); ++i) {
- instructions += TranslateExpression(positional[i]);
- instructions += Drop();
- }
- for (intptr_t i = 0; i < named.length(); ++i) {
- instructions += TranslateExpression(named[i]->expression());
- instructions += Drop();
- }
-
- // Throw an error & keep the [Value] on the stack.
- instructions += ThrowTypeError();
-
- // Bail out early.
- fragment_ = instructions;
- return;
- }
- }
-
- if (klass.NumTypeArguments() > 0) {
- List<DartType>& kernel_type_arguments = node->arguments()->types();
- const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
- klass, kernel_type_arguments.raw_array(),
- kernel_type_arguments.length());
- if (!klass.IsGeneric()) {
- Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw());
-
- // TODO(27590): Can we move this code into [ReceiverType]?
- type ^= ClassFinalizer::FinalizeType(*active_class_.klass, type,
- ClassFinalizer::kFinalize);
- ASSERT(!type.IsMalformedOrMalbounded());
-
- TypeArguments& canonicalized_type_arguments =
- TypeArguments::ZoneHandle(Z, type.arguments());
- canonicalized_type_arguments =
- canonicalized_type_arguments.Canonicalize();
- instructions += Constant(canonicalized_type_arguments);
- } else {
- instructions += TranslateInstantiatedTypeArguments(type_arguments);
- }
-
- instructions += PushArgument();
- instructions += AllocateObject(klass, 1);
- } else {
- instructions += AllocateObject(klass, 0);
- }
- LocalVariable* variable = MakeTemporary();
-
- instructions += LoadLocal(variable);
- instructions += PushArgument();
-
- Array& argument_names = Array::ZoneHandle(Z);
- instructions += TranslateArguments(node->arguments(), &argument_names);
-
- const Function& target = Function::ZoneHandle(
- Z, H.LookupConstructorByKernelConstructor(klass, node->target()));
- intptr_t argument_count = node->arguments()->count() + 1;
- instructions +=
- StaticCall(node->position(), target, argument_count, argument_names);
- fragment_ = instructions + Drop();
-}
-
-
-void FlowGraphBuilder::VisitIsExpression(IsExpression* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->operand());
-
- // The VM does not like an instanceOf call with a dynamic type. We need to
- // special case this situation.
- const Type& object_type = Type::Handle(Z, Type::ObjectType());
- const AbstractType& type = T.TranslateType(node->type());
- if (type.IsMalformed()) {
- instructions += Drop();
- instructions += ThrowTypeError();
- fragment_ = instructions;
- return;
- }
-
- if (type.IsInstantiated() &&
- object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
- // Evaluate the expression on the left but ignore it's result.
- instructions += Drop();
-
- // Let condition be always true.
- instructions += Constant(Bool::True());
- } else {
- instructions += PushArgument();
-
- // See if simple instanceOf is applicable.
- if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) {
- instructions += Constant(type);
- instructions += PushArgument(); // Type.
- instructions += InstanceCall(
- node->position(),
- dart::Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()),
- Token::kIS, 2, 2); // 2 checked arguments.
- fragment_ = instructions;
- return;
- }
-
- if (!type.IsInstantiated(kCurrentClass)) {
- instructions += LoadInstantiatorTypeArguments();
- } else {
- instructions += NullConstant();
- }
- instructions += PushArgument(); // Instantiator type arguments.
-
- if (!type.IsInstantiated(kFunctions)) {
- instructions += LoadFunctionTypeArguments();
- } else {
- instructions += NullConstant();
- }
- instructions += PushArgument(); // Function type arguments.
-
- instructions += Constant(type);
- instructions += PushArgument(); // Type.
-
- instructions +=
- InstanceCall(node->position(),
- dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
- Token::kIS, 4);
- }
-
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitAsExpression(AsExpression* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->operand());
-
- // The VM does not like an Object_as call with a dynamic type. We need to
- // special case this situation.
- const Type& object_type = Type::Handle(Z, Type::ObjectType());
- const AbstractType& type = T.TranslateType(node->type());
- if (type.IsMalformed()) {
- instructions += Drop();
- instructions += ThrowTypeError();
- fragment_ = instructions;
- return;
- }
-
- if (type.IsInstantiated() &&
- object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
- // We already evaluated the operand on the left and just leave it there as
- // the result of the `obj as dynamic` expression.
- } else {
- instructions += PushArgument();
-
- if (!type.IsInstantiated(kCurrentClass)) {
- instructions += LoadInstantiatorTypeArguments();
- } else {
- instructions += NullConstant();
- }
- instructions += PushArgument(); // Instantiator type arguments.
-
- if (!type.IsInstantiated(kFunctions)) {
- instructions += LoadFunctionTypeArguments();
- } else {
- instructions += NullConstant();
- }
- instructions += PushArgument(); // Function type arguments.
-
- instructions += Constant(type);
- instructions += PushArgument(); // Type.
-
- instructions += InstanceCall(
- node->position(), dart::Library::PrivateCoreLibName(Symbols::_as()),
- Token::kAS, 4);
- }
-
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- bool negate;
- Fragment instructions = TranslateCondition(node->condition(), &negate);
-
- TargetEntryInstr* then_entry;
- TargetEntryInstr* otherwise_entry;
- instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
-
- Value* top = stack_;
- Fragment then_fragment(then_entry);
- then_fragment += TranslateExpression(node->then());
- then_fragment += StoreLocal(TokenPosition::kNoSource,
- parsed_function_->expression_temp_var());
- then_fragment += Drop();
- ASSERT(stack_ == top);
-
- Fragment otherwise_fragment(otherwise_entry);
- otherwise_fragment += TranslateExpression(node->otherwise());
- otherwise_fragment += StoreLocal(TokenPosition::kNoSource,
- parsed_function_->expression_temp_var());
- otherwise_fragment += Drop();
- ASSERT(stack_ == top);
-
- JoinEntryInstr* join = BuildJoinEntry();
- then_fragment += Goto(join);
- otherwise_fragment += Goto(join);
-
- fragment_ = Fragment(instructions.entry, join) +
- LoadLocal(parsed_function_->expression_temp_var());
-}
-
-
-void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- bool negate;
- Fragment instructions = TranslateCondition(node->left(), &negate);
- TargetEntryInstr* right_entry;
- TargetEntryInstr* constant_entry;
-
- if (node->op() == LogicalExpression::kAnd) {
- instructions += BranchIfTrue(&right_entry, &constant_entry, negate);
- } else {
- instructions += BranchIfTrue(&constant_entry, &right_entry, negate);
- }
-
- Value* top = stack_;
- Fragment right_fragment(right_entry);
- right_fragment += TranslateCondition(node->right(), &negate);
- right_fragment += Constant(Bool::True());
- right_fragment +=
- StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT);
- right_fragment += StoreLocal(TokenPosition::kNoSource,
- parsed_function_->expression_temp_var());
- right_fragment += Drop();
-
- ASSERT(top == stack_);
- Fragment constant_fragment(constant_entry);
- constant_fragment +=
- Constant(Bool::Get(node->op() == LogicalExpression::kOr));
- constant_fragment += StoreLocal(TokenPosition::kNoSource,
- parsed_function_->expression_temp_var());
- constant_fragment += Drop();
-
- JoinEntryInstr* join = BuildJoinEntry();
- right_fragment += Goto(join);
- constant_fragment += Goto(join);
-
- fragment_ = Fragment(instructions.entry, join) +
- LoadLocal(parsed_function_->expression_temp_var());
-}
-
-
-void FlowGraphBuilder::VisitNot(Not* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->expression());
- instructions += CheckBooleanInCheckedMode();
- instructions += BooleanNegate();
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- List<Expression>& expressions = node->expressions();
-
- Fragment instructions;
-
- if (node->expressions().length() == 1) {
- instructions += TranslateExpression(node->expressions()[0]);
- instructions += StringInterpolateSingle(node->position());
- } else {
- // The type arguments for CreateArray.
- instructions += Constant(TypeArguments::ZoneHandle(Z));
- instructions += IntConstant(expressions.length());
- instructions += CreateArray();
- LocalVariable* array = MakeTemporary();
-
- for (intptr_t i = 0; i < node->expressions().length(); i++) {
- instructions += LoadLocal(array);
- instructions += IntConstant(i);
- instructions += TranslateExpression(node->expressions()[i]);
- instructions += StoreIndexed(kArrayCid);
- instructions += Drop();
- }
-
- instructions += StringInterpolate(node->position());
- }
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- if (node->is_const()) {
- fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node));
- return;
- }
-
- DartType* types[] = {node->type()};
- const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1);
-
- // The type argument for the factory call.
- Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
- instructions += PushArgument();
- List<Expression>& expressions = node->expressions();
- if (expressions.length() == 0) {
- instructions += Constant(Object::empty_array());
- } else {
- // The type arguments for CreateArray.
- instructions += Constant(TypeArguments::ZoneHandle(Z));
- instructions += IntConstant(expressions.length());
- instructions += CreateArray();
-
- LocalVariable* array = MakeTemporary();
- for (intptr_t i = 0; i < expressions.length(); ++i) {
- instructions += LoadLocal(array);
- instructions += IntConstant(i);
- instructions += TranslateExpression(expressions[i]);
- instructions += StoreIndexed(kArrayCid);
- instructions += Drop();
- }
- }
- instructions += PushArgument(); // The array.
-
- const dart::Class& factory_class =
- dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List()));
- const Function& factory_method = Function::ZoneHandle(
- Z, factory_class.LookupFactory(
- dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
- fragment_ = instructions + StaticCall(node->position(), factory_method, 2);
-}
-
-
-void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- if (node->is_const()) {
- fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node));
- return;
- }
-
- const dart::Class& map_class =
- dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map()));
- const Function& factory_method = Function::ZoneHandle(
- Z, map_class.LookupFactory(
- dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory())));
-
- DartType* types[] = {node->key_type(), node->value_type()};
- const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2);
-
- // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
- Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
- instructions += PushArgument();
-
- List<MapEntry>& entries = node->entries();
- if (entries.length() == 0) {
- instructions += Constant(Object::empty_array());
- } else {
- // The type arguments for `new List<X>(int len)`.
- instructions += Constant(TypeArguments::ZoneHandle(Z));
-
- // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
- instructions += IntConstant(2 * entries.length());
- instructions += CreateArray();
-
- LocalVariable* array = MakeTemporary();
- for (intptr_t i = 0; i < entries.length(); ++i) {
- instructions += LoadLocal(array);
- instructions += IntConstant(2 * i);
- instructions += TranslateExpression(entries[i]->key());
- instructions += StoreIndexed(kArrayCid);
- instructions += Drop();
-
- instructions += LoadLocal(array);
- instructions += IntConstant(2 * i + 1);
- instructions += TranslateExpression(entries[i]->value());
- instructions += StoreIndexed(kArrayCid);
- instructions += Drop();
- }
- }
- instructions += PushArgument(); // The array.
-
- fragment_ = instructions + StaticCall(node->position(), factory_method, 2);
-}
-
-
-void FlowGraphBuilder::VisitFunctionExpression(FunctionExpression* node) {
- fragment_ = TranslateFunctionNode(node->function(), node);
-}
-
-
-void FlowGraphBuilder::VisitLet(Let* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateStatement(node->variable());
- instructions += TranslateExpression(node->body());
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitThrow(Throw* node) {
- STREAM_EXPRESSION_IF_POSSIBLE(node);
-
- Fragment instructions;
-
- instructions += TranslateExpression(node->expression());
- if (NeedsDebugStepCheck(stack_, node->position())) {
- instructions = DebugStepCheck(node->position()) + instructions;
- }
- instructions += PushArgument();
- instructions += ThrowException(node->position());
- ASSERT(instructions.is_closed());
-
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitRethrow(Rethrow* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
-}
-
-
-Fragment FlowGraphBuilder::TranslateArguments(Arguments* node,
- Array* argument_names) {
- Fragment instructions;
-
- List<Expression>& positional = node->positional();
- for (intptr_t i = 0; i < positional.length(); ++i) {
- instructions += TranslateExpression(positional[i]);
- instructions += PushArgument();
- }
-
- List<NamedExpression>& named = node->named();
- if (argument_names != NULL) {
- *argument_names = H.ArgumentNames(&named).raw();
- }
- for (intptr_t i = 0; i < named.length(); ++i) {
- NamedExpression* named_expression = named[i];
- instructions += TranslateExpression(named_expression->expression());
- instructions += PushArgument();
- }
- return instructions;
-}
-
-#define STREAM_STATEMENT_IF_POSSIBLE(node) \
- if (node->can_stream()) { \
- fragment_ = streaming_flow_graph_builder_->BuildStatementAt( \
- node->kernel_offset()); \
- return; \
- }
-
-
-void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitBlock(Block* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- Fragment instructions;
-
- instructions += EnterScope(node);
- List<Statement>& statements = node->statements();
- for (intptr_t i = 0; (i < statements.length()) && instructions.is_open();
- ++i) {
- instructions += TranslateStatement(statements[i]);
- }
- instructions += ExitScope(node);
-
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- bool inside_try_finally = try_finally_block_ != NULL;
-
- Fragment instructions = node->expression() == NULL
- ? NullConstant()
- : TranslateExpression(node->expression());
- if (instructions.is_open()) {
- if (inside_try_finally) {
- ASSERT(scopes_->finally_return_variable != NULL);
- const Function& function = parsed_function_->function();
- if (NeedsDebugStepCheck(function, node->position())) {
- instructions += DebugStepCheck(node->position());
- }
- instructions +=
- StoreLocal(node->position(), scopes_->finally_return_variable);
- instructions += Drop();
- instructions += TranslateFinallyFinalizers(NULL, -1);
- if (instructions.is_open()) {
- instructions += LoadLocal(scopes_->finally_return_variable);
- instructions += Return(TokenPosition::kNoSource);
- }
- } else {
- instructions += Return(node->position());
- }
- } else {
- Pop();
- }
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->expression());
- instructions += Drop();
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) {
- LocalVariable* variable = LookupVariable(node);
- Expression* initializer = node->initializer();
-
- Fragment instructions;
- if (initializer == NULL) {
- instructions += NullConstant();
- } else {
- if (node->IsConst()) {
- const Instance& constant_value =
- constant_evaluator_.EvaluateExpression(initializer);
- variable->SetConstValue(constant_value);
- instructions += Constant(constant_value);
- } else {
- instructions += TranslateExpression(initializer);
- instructions += CheckVariableTypeInCheckedMode(node);
- }
- }
- // Use position of equal sign if it exists. If the equal sign does not exist
- // use the position of the identifier.
- TokenPosition debug_position =
- Utils::Maximum(node->position(), node->equals_position());
- if (NeedsDebugStepCheck(stack_, debug_position)) {
- instructions = DebugStepCheck(debug_position) + instructions;
- }
- instructions += StoreLocal(node->position(), variable);
- instructions += Drop();
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) {
- Fragment instructions = DebugStepCheck(node->position());
- instructions += TranslateFunctionNode(node->function(), node);
- instructions +=
- StoreLocal(node->position(), LookupVariable(node->variable()));
- instructions += Drop();
- fragment_ = instructions;
-}
-
-
-void FlowGraphBuilder::VisitIfStatement(IfStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- bool negate;
- Fragment instructions = TranslateCondition(node->condition(), &negate);
- TargetEntryInstr* then_entry;
- TargetEntryInstr* otherwise_entry;
- instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
-
- Fragment then_fragment(then_entry);
- then_fragment += TranslateStatement(node->then());
-
- Fragment otherwise_fragment(otherwise_entry);
- otherwise_fragment += TranslateStatement(node->otherwise());
-
- if (then_fragment.is_open()) {
- if (otherwise_fragment.is_open()) {
- JoinEntryInstr* join = BuildJoinEntry();
- then_fragment += Goto(join);
- otherwise_fragment += Goto(join);
- fragment_ = Fragment(instructions.entry, join);
- } else {
- fragment_ = Fragment(instructions.entry, then_fragment.current);
- }
- } else if (otherwise_fragment.is_open()) {
- fragment_ = Fragment(instructions.entry, otherwise_fragment.current);
- } else {
- fragment_ = instructions.closed();
- }
-}
-
-
-void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- ++loop_depth_;
- bool negate;
- Fragment condition = TranslateCondition(node->condition(), &negate);
- TargetEntryInstr* body_entry;
- TargetEntryInstr* loop_exit;
- condition += BranchIfTrue(&body_entry, &loop_exit, negate);
-
- Fragment body(body_entry);
- body += TranslateStatement(node->body());
-
- Instruction* entry;
- if (body.is_open()) {
- JoinEntryInstr* join = BuildJoinEntry();
- body += Goto(join);
-
- Fragment loop(join);
- loop += CheckStackOverflow();
- loop += condition;
- entry = new (Z) GotoInstr(join, GetNextDeoptId());
- } else {
- entry = condition.entry;
- }
-
-
- fragment_ = Fragment(entry, loop_exit);
- --loop_depth_;
-}
-
-
-void FlowGraphBuilder::VisitDoStatement(DoStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- ++loop_depth_;
- Fragment body = TranslateStatement(node->body());
-
- if (body.is_closed()) {
- fragment_ = body;
- --loop_depth_;
- return;
- }
-
- bool negate;
- JoinEntryInstr* join = BuildJoinEntry();
- Fragment loop(join);
- loop += CheckStackOverflow();
- loop += body;
- loop += TranslateCondition(node->condition(), &negate);
- TargetEntryInstr* loop_repeat;
- TargetEntryInstr* loop_exit;
- loop += BranchIfTrue(&loop_repeat, &loop_exit, negate);
-
- Fragment repeat(loop_repeat);
- repeat += Goto(join);
-
- fragment_ = Fragment(new (Z) GotoInstr(join, GetNextDeoptId()), loop_exit);
- --loop_depth_;
-}
-
-
-void FlowGraphBuilder::VisitForStatement(ForStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- Fragment declarations;
-
- bool new_context = false;
- declarations += EnterScope(node, &new_context);
-
- List<VariableDeclaration>& variables = node->variables();
- for (intptr_t i = 0; i < variables.length(); ++i) {
- declarations += TranslateStatement(variables[i]);
- }
-
- ++loop_depth_;
- bool negate = false;
- Fragment condition = node->condition() == NULL
- ? Constant(Bool::True())
- : TranslateCondition(node->condition(), &negate);
- TargetEntryInstr* body_entry;
- TargetEntryInstr* loop_exit;
- condition += BranchIfTrue(&body_entry, &loop_exit, negate);
-
- Fragment body(body_entry);
- body += TranslateStatement(node->body());
-
- if (body.is_open()) {
- // We allocated a fresh context before the loop which contains captured
- // [ForStatement] variables. Before jumping back to the loop entry we clone
- // the context object (at same depth) which ensures the next iteration of
- // the body gets a fresh set of [ForStatement] variables (with the old
- // (possibly updated) values).
- if (new_context) body += CloneContext();
-
- List<Expression>& updates = node->updates();
- for (intptr_t i = 0; i < updates.length(); ++i) {
- body += TranslateExpression(updates[i]);
- body += Drop();
- }
- JoinEntryInstr* join = BuildJoinEntry();
- declarations += Goto(join);
- body += Goto(join);
-
- Fragment loop(join);
- loop += CheckStackOverflow();
- loop += condition;
- } else {
- declarations += condition;
- }
-
- Fragment loop(declarations.entry, loop_exit);
- --loop_depth_;
-
- loop += ExitScope(node);
-
- fragment_ = loop;
-}
-
-
-void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- Fragment instructions = TranslateExpression(node->iterable());
- instructions += PushArgument();
-
- const dart::String& iterator_getter = dart::String::ZoneHandle(
- Z, dart::Field::GetterSymbol(Symbols::Iterator()));
- instructions += InstanceCall(node->iterable()->position(), iterator_getter,
- Token::kGET, 1);
- LocalVariable* iterator = scopes_->iterator_variables[for_in_depth_];
- instructions += StoreLocal(TokenPosition::kNoSource, iterator);
- instructions += Drop();
-
- ++for_in_depth_;
- ++loop_depth_;
- Fragment condition = LoadLocal(iterator);
- condition += PushArgument();
- condition += InstanceCall(node->iterable()->position(), Symbols::MoveNext(),
- Token::kILLEGAL, 1);
- TargetEntryInstr* body_entry;
- TargetEntryInstr* loop_exit;
- condition += BranchIfTrue(&body_entry, &loop_exit);
-
- Fragment body(body_entry);
- body += EnterScope(node);
- body += LoadLocal(iterator);
- body += PushArgument();
- const dart::String& current_getter = dart::String::ZoneHandle(
- Z, dart::Field::GetterSymbol(Symbols::Current()));
- body += InstanceCall(node->position(), current_getter, Token::kGET, 1);
- body +=
- StoreLocal(TokenPosition::kNoSource, LookupVariable(node->variable()));
- body += Drop();
- body += TranslateStatement(node->body());
- body += ExitScope(node);
-
- if (body.is_open()) {
- JoinEntryInstr* join = BuildJoinEntry();
- instructions += Goto(join);
- body += Goto(join);
-
- Fragment loop(join);
- loop += CheckStackOverflow();
- loop += condition;
- } else {
- instructions += condition;
- }
-
- fragment_ = Fragment(instructions.entry, loop_exit);
- --loop_depth_;
- --for_in_depth_;
-}
-
-
-void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- // There can be serveral cases:
- //
- // * the body contains a break
- // * the body doesn't contain a break
- //
- // * translating the body results in a closed fragment
- // * translating the body results in a open fragment
- //
- // => We will only know which case we are in after the body has been
- // traversed.
-
- BreakableBlock block(this);
- Fragment instructions = TranslateStatement(node->body());
- if (block.HadJumper()) {
- if (instructions.is_open()) {
- instructions += Goto(block.destination());
- }
- fragment_ = Fragment(instructions.entry, block.destination());
- } else {
- fragment_ = instructions;
- }
-}
-
-
-void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- SwitchBlock block(this, node->cases().length());
-
- // Instead of using a variable we should reuse the expression on the stack,
- // since it won't be assigned again, we don't need phi nodes.
- Fragment head_instructions = TranslateExpression(node->condition());
- head_instructions +=
- StoreLocal(TokenPosition::kNoSource, scopes_->switch_variable);
- head_instructions += Drop();
-
- // Phase 1: Generate bodies and try to find out whether a body will be target
- // of a jump due to:
- // * `continue case_label`
- // * `case e1: case e2: body`
- Fragment* body_fragments = new Fragment[node->cases().length()];
-
- intptr_t num_cases = node->cases().length();
- for (intptr_t i = 0; i < num_cases; i++) {
- SwitchCase* switch_case = node->cases()[i];
- Fragment& body_fragment = body_fragments[i] =
- TranslateStatement(switch_case->body());
-
- if (body_fragment.entry == NULL) {
- // Make a NOP in order to ensure linking works properly.
- body_fragment = NullConstant();
- body_fragment += Drop();
- }
-
- // The Dart language specification mandates fall-throughs in [SwitchCase]es
- // to be runtime errors.
- if (!switch_case->is_default() && body_fragment.is_open() &&
- (i < (node->cases().length() - 1))) {
- const dart::Class& klass = dart::Class::ZoneHandle(
- Z, dart::Library::LookupCoreClass(Symbols::FallThroughError()));
- ASSERT(!klass.IsNull());
- const Function& constructor = Function::ZoneHandle(
- Z, klass.LookupConstructorAllowPrivate(
- H.DartSymbol("FallThroughError._create")));
- ASSERT(!constructor.IsNull());
- const dart::String& url = H.DartString(
- parsed_function_->function().ToLibNamePrefixedQualifiedCString(),
- Heap::kOld);
-
- // Create instance of _FallThroughError
- body_fragment += AllocateObject(klass, 0);
- LocalVariable* instance = MakeTemporary();
-
- // Call _FallThroughError._create constructor.
- body_fragment += LoadLocal(instance);
- body_fragment += PushArgument(); // this
-
- body_fragment += Constant(url);
- body_fragment += PushArgument(); // url
-
- body_fragment += NullConstant();
- body_fragment += PushArgument(); // line
-
- body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3);
- body_fragment += Drop();
-
- // Throw the exception
- body_fragment += PushArgument();
- body_fragment += ThrowException(TokenPosition::kNoSource);
- body_fragment += Drop();
- }
-
- // If there is an implicit fall-through we have one [SwitchCase] and
- // multiple expressions, e.g.
- //
- // switch(expr) {
- // case a:
- // case b:
- // <stmt-body>
- // }
- //
- // This means that the <stmt-body> will have more than 1 incoming edge (one
- // from `a == expr` and one from `a != expr && b == expr`). The
- // `block.Destination()` records the additional jump.
- if (switch_case->expressions().length() > 1) {
- block.DestinationDirect(i);
- }
- }
-
- // Phase 2: Generate everything except the real bodies:
- // * jump directly to a body (if there is no jumper)
- // * jump to a wrapper block which jumps to the body (if there is a jumper)
- Fragment current_instructions = head_instructions;
- for (intptr_t i = 0; i < num_cases; i++) {
- SwitchCase* switch_case = node->cases()[i];
-
- if (switch_case->is_default()) {
- ASSERT(i == (node->cases().length() - 1));
-
- // Evaluate the conditions for the default [SwitchCase] just for the
- // purpose of potentially triggering a compile-time error.
- for (intptr_t k = 0; k < switch_case->expressions().length(); k++) {
- constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]);
- }
-
- if (block.HadJumper(i)) {
- // There are several branches to the body, so we will make a goto to
- // the join block (and prepend a join instruction to the real body).
- JoinEntryInstr* join = block.DestinationDirect(i);
- current_instructions += Goto(join);
-
- current_instructions = Fragment(current_instructions.entry, join);
- current_instructions += body_fragments[i];
- } else {
- current_instructions += body_fragments[i];
- }
- } else {
- JoinEntryInstr* body_join = NULL;
- if (block.HadJumper(i)) {
- body_join = block.DestinationDirect(i);
- body_fragments[i] = Fragment(body_join) + body_fragments[i];
- }
-
- for (intptr_t j = 0; j < switch_case->expressions().length(); j++) {
- TargetEntryInstr* then;
- TargetEntryInstr* otherwise;
-
- Expression* expression = switch_case->expressions()[j];
- current_instructions +=
- Constant(constant_evaluator_.EvaluateExpression(expression));
- current_instructions += PushArgument();
- current_instructions += LoadLocal(scopes_->switch_variable);
- current_instructions += PushArgument();
- current_instructions += InstanceCall(
- expression->position(), Symbols::EqualOperator(), Token::kEQ,
- /*argument_count=*/2,
- /*num_args_checked=*/2);
- current_instructions += BranchIfTrue(&then, &otherwise);
-
- Fragment then_fragment(then);
-
- if (body_join != NULL) {
- // There are several branches to the body, so we will make a goto to
- // the join block (the real body has already been prepended with a
- // join instruction).
- then_fragment += Goto(body_join);
- } else {
- // There is only a signle branch to the body, so we will just append
- // the body fragment.
- then_fragment += body_fragments[i];
- }
-
- current_instructions = Fragment(otherwise);
- }
- }
- }
-
- bool has_no_default =
- num_cases > 0 && !node->cases()[num_cases - 1]->is_default();
- if (has_no_default) {
- // There is no default, which means we have an open [current_instructions]
- // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
- //
- // Furthermore the last [SwitchCase] can be open as well. If so, we need
- // to join these two.
- Fragment& last_body = body_fragments[node->cases().length() - 1];
- if (last_body.is_open()) {
- ASSERT(current_instructions.is_open());
- ASSERT(current_instructions.current->IsTargetEntry());
-
- // Join the last "otherwise" branch and the last [SwitchCase] fragment.
- JoinEntryInstr* join = BuildJoinEntry();
- current_instructions += Goto(join);
- last_body += Goto(join);
-
- current_instructions = Fragment(join);
- }
- } else {
- // All non-default cases will be closed (i.e. break/continue/throw/return)
- // So it is fine to just let more statements after the switch append to the
- // default case.
- }
-
- delete[] body_fragments;
-
- fragment_ = Fragment(head_instructions.entry, current_instructions.current);
-}
-
-
-void FlowGraphBuilder::VisitContinueSwitchStatement(
- ContinueSwitchStatement* node) {
- fragment_ =
- streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
-}
-
-
-void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- if (!I->asserts()) {
- fragment_ = Fragment();
- return;
- }
-
- TargetEntryInstr* then;
- TargetEntryInstr* otherwise;
-
- Fragment instructions;
- // Asserts can be of the following two kinds:
- //
- // * `assert(expr)`
- // * `assert(() { ... })`
- //
- // The call to `_AssertionError._evaluateAssertion()` will take care of both
- // and returns a boolean.
- instructions += TranslateExpression(node->condition());
- instructions += PushArgument();
- instructions += EvaluateAssertion();
- instructions += CheckBooleanInCheckedMode();
- instructions += Constant(Bool::True());
- instructions += BranchIfEqual(&then, &otherwise, false);
-
- const dart::Class& klass = dart::Class::ZoneHandle(
- Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
- ASSERT(!klass.IsNull());
- const Function& constructor =
- Function::ZoneHandle(Z, klass.LookupConstructorAllowPrivate(
- H.DartSymbol("_AssertionError._create")));
- ASSERT(!constructor.IsNull());
-
- const dart::String& url = H.DartString(
- parsed_function_->function().ToLibNamePrefixedQualifiedCString(),
- Heap::kOld);
-
- // Create instance of _AssertionError
- Fragment otherwise_fragment(otherwise);
- otherwise_fragment += AllocateObject(klass, 0);
- LocalVariable* instance = MakeTemporary();
-
- // Call _AssertionError._create constructor.
- otherwise_fragment += LoadLocal(instance);
- otherwise_fragment += PushArgument(); // this
-
- otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
- otherwise_fragment += PushArgument(); // failedAssertion
-
- otherwise_fragment += Constant(url);
- otherwise_fragment += PushArgument(); // url
-
- otherwise_fragment += IntConstant(0);
- otherwise_fragment += PushArgument(); // line
-
- otherwise_fragment += IntConstant(0);
- otherwise_fragment += PushArgument(); // column
-
- otherwise_fragment +=
- node->message() != NULL
- ? TranslateExpression(node->message())
- : Constant(H.DartString("<no message>", Heap::kOld));
- otherwise_fragment += PushArgument(); // message
-
- otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6);
- otherwise_fragment += Drop();
-
- // Throw _AssertionError exception.
- otherwise_fragment += PushArgument();
- otherwise_fragment += ThrowException(TokenPosition::kNoSource);
- otherwise_fragment += Drop();
-
- fragment_ = Fragment(instructions.entry, then);
-}
-
-
-void FlowGraphBuilder::VisitTryFinally(TryFinally* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
-
- // There are 5 different cases where we need to execute the finally block:
- //
- // a) 1/2/3th case: Special control flow going out of `node->body()`:
- //
- // * [BreakStatement] transfers control to a [LabledStatement]
- // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
- // * [ReturnStatement] returns a value
- //
- // => All three cases will automatically append all finally blocks
- // between the branching point and the destination (so we don't need to
- // do anything here).
- //
- // b) 4th case: Translating the body resulted in an open fragment (i.e. body
- // executes without any control flow out of it)
- //
- // => We are responsible for jumping out of the body to a new block (with
- // different try index) and execute the finalizer.
- //
- // c) 5th case: An exception occured inside the body.
- //
- // => We are responsible for catching it, executing the finally block and
- // rethrowing the exception.
- intptr_t try_handler_index = AllocateTryIndex();
- Fragment try_body = TryCatch(try_handler_index);
- JoinEntryInstr* after_try = BuildJoinEntry();
-
- // Fill in the body of the try.
- ++try_depth_;
- {
- TryFinallyBlock tfb(this, node->finalizer(), -1);
- TryCatchBlock tcb(this, try_handler_index);
- try_body += TranslateStatement(node->body());
- }
- --try_depth_;
-
- if (try_body.is_open()) {
- // Please note: The try index will be on level out of this block,
- // thereby ensuring if there's an exception in the finally block we
- // won't run it twice.
- JoinEntryInstr* finally_entry = BuildJoinEntry();
-
- try_body += Goto(finally_entry);
-
- Fragment finally_body(finally_entry);
- finally_body += TranslateStatement(node->finalizer());
- finally_body += Goto(after_try);
- }
-
- // Fill in the body of the catch.
- ++catch_depth_;
- const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
- handler_types.SetAt(0, Object::dynamic_type());
- // Note: rethrow will actually force mark the handler as needing a stacktrace.
- Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index,
- /* needs_stacktrace = */ false);
- finally_body += TranslateStatement(node->finalizer());
- if (finally_body.is_open()) {
- finally_body += LoadLocal(CurrentException());
- finally_body += PushArgument();
- finally_body += LoadLocal(CurrentStackTrace());
- finally_body += PushArgument();
- finally_body +=
- RethrowException(TokenPosition::kNoSource, try_handler_index);
- Drop();
- }
- --catch_depth_;
-
- fragment_ = Fragment(try_body.entry, after_try);
-}
-
-
-void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
-
- intptr_t try_handler_index = AllocateTryIndex();
- Fragment try_body = TryCatch(try_handler_index);
- JoinEntryInstr* after_try = BuildJoinEntry();
-
- // Fill in the body of the try.
- ++try_depth_;
- {
- TryCatchBlock block(this, try_handler_index);
- try_body += TranslateStatement(node->body());
- try_body += Goto(after_try);
- }
- --try_depth_;
-
- ++catch_depth_;
- const Array& handler_types =
- Array::ZoneHandle(Z, Array::New(node->catches().length(), Heap::kOld));
- bool needs_stacktrace = false;
- for (intptr_t i = 0; i < node->catches().length(); i++) {
- if (node->catches()[i]->stack_trace() != NULL) {
- needs_stacktrace = true;
- break;
- }
- }
- Fragment catch_body =
- CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace);
- // Fill in the body of the catch.
- for (intptr_t i = 0; i < node->catches().length(); i++) {
- Catch* catch_clause = node->catches()[i];
-
- Fragment catch_handler_body;
-
- catch_handler_body += EnterScope(catch_clause);
-
- if (catch_clause->exception() != NULL) {
- catch_handler_body += LoadLocal(CurrentException());
- catch_handler_body += StoreLocal(
- TokenPosition::kNoSource, LookupVariable(catch_clause->exception()));
- catch_handler_body += Drop();
- }
- if (catch_clause->stack_trace() != NULL) {
- catch_handler_body += LoadLocal(CurrentStackTrace());
- catch_handler_body +=
- StoreLocal(TokenPosition::kNoSource,
- LookupVariable(catch_clause->stack_trace()));
- catch_handler_body += Drop();
- }
- AbstractType* type_guard = NULL;
- if (catch_clause->guard() != NULL &&
- !catch_clause->guard()->IsDynamicType()) {
- type_guard = &T.TranslateType(catch_clause->guard());
- handler_types.SetAt(i, *type_guard);
- } else {
- handler_types.SetAt(i, Object::dynamic_type());
- }
-
- {
- CatchBlock block(this, CurrentException(), CurrentStackTrace(),
- try_handler_index);
-
- catch_handler_body += TranslateStatement(catch_clause->body());
-
- // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
- // is closed we still need to execute ExitScope for its side effect.
- catch_handler_body += ExitScope(catch_clause);
- if (catch_handler_body.is_open()) {
- catch_handler_body += Goto(after_try);
- }
- }
-
- if (type_guard != NULL) {
- if (type_guard->IsMalformed()) {
- catch_body += ThrowTypeError();
- catch_body += Drop();
- } else {
- catch_body += LoadLocal(CurrentException());
- catch_body += PushArgument(); // exception
- catch_body += NullConstant();
- catch_body += PushArgument(); // instantiator type arguments
- catch_body += NullConstant();
- catch_body += PushArgument(); // function type arguments
- catch_body += Constant(*type_guard);
- catch_body += PushArgument(); // guard type
- catch_body += InstanceCall(
- TokenPosition::kNoSource,
- dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
- Token::kIS, 4);
-
- TargetEntryInstr* catch_entry;
- TargetEntryInstr* next_catch_entry;
- catch_body += BranchIfTrue(&catch_entry, &next_catch_entry);
-
- Fragment(catch_entry) + catch_handler_body;
- catch_body = Fragment(next_catch_entry);
- }
- } else {
- catch_body += catch_handler_body;
- }
- }
-
- // In case the last catch body was not handling the exception and branching to
- // after the try block, we will rethrow the exception (i.e. no default catch
- // handler).
- if (catch_body.is_open()) {
- catch_body += LoadLocal(CurrentException());
- catch_body += PushArgument();
- catch_body += LoadLocal(CurrentStackTrace());
- catch_body += PushArgument();
- catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
- Drop();
- }
- --catch_depth_;
-
- fragment_ = Fragment(try_body.entry, after_try);
-}
-
-
-void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) {
- STREAM_STATEMENT_IF_POSSIBLE(node);
-
- ASSERT(node->is_native()); // Must have been desugared.
- // Setup yield/continue point:
- //
- // ...
- // :await_jump_var = index;
- // :await_ctx_var = :current_context_var
- // return <expr>
- //
- // Continuation<index>:
- // Drop(1)
- // ...
- //
- // BuildGraphOfFunction will create a dispatch that jumps to
- // Continuation<:await_jump_var> upon entry to the function.
- //
- Fragment instructions = IntConstant(yield_continuations_.length() + 1);
- instructions +=
- StoreLocal(TokenPosition::kNoSource, scopes_->yield_jump_variable);
- instructions += Drop();
- instructions += LoadLocal(parsed_function_->current_context_var());
- instructions +=
- StoreLocal(TokenPosition::kNoSource, scopes_->yield_context_variable);
- instructions += Drop();
- instructions += TranslateExpression(node->expression());
- instructions += Return(TokenPosition::kNoSource);
-
- // Note: DropTempsInstr serves as an anchor instruction. It will not
- // be linked into the resulting graph.
- DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL);
- yield_continuations_.Add(YieldContinuation(anchor, CurrentTryIndex()));
-
- Fragment continuation(instructions.entry, anchor);
-
- if (parsed_function_->function().IsAsyncClosure() ||
- parsed_function_->function().IsAsyncGenClosure()) {
- // If function is async closure or async gen closure it takes three
- // parameters where the second and the third are exception and stack_trace.
- // Check if exception is non-null and rethrow it.
- //
- // :async_op([:result, :exception, :stack_trace]) {
- // ...
- // Continuation<index>:
- // if (:exception != null) rethrow(:exception, :stack_trace);
- // ...
- // }
- //
- LocalScope* scope = parsed_function_->node_sequence()->scope();
- LocalVariable* exception_var = scope->VariableAt(2);
- LocalVariable* stack_trace_var = scope->VariableAt(3);
- ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw());
- ASSERT(stack_trace_var->name().raw() ==
- Symbols::StackTraceParameter().raw());
-
- TargetEntryInstr* no_error;
- TargetEntryInstr* error;
-
- continuation += LoadLocal(exception_var);
- continuation += BranchIfNull(&no_error, &error);
-
- Fragment rethrow(error);
- rethrow += LoadLocal(exception_var);
- rethrow += PushArgument();
- rethrow += LoadLocal(stack_trace_var);
- rethrow += PushArgument();
- rethrow +=
- RethrowException(node->position(), CatchClauseNode::kInvalidTryIndex);
- Drop();
-
-
- continuation = Fragment(continuation.entry, no_error);
- }
-
- fragment_ = continuation;
-}
-
-
-Fragment FlowGraphBuilder::TranslateFunctionNode(FunctionNode* node,
- TreeNode* parent) {
- // The VM has a per-isolate table of functions indexed by the enclosing
- // function and token position.
- Function& function = Function::ZoneHandle(Z);
- for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) {
- if (scopes_->function_scopes[i].kernel_offset != node->kernel_offset()) {
- continue;
- }
-
- TokenPosition position = node->position();
- if (parent->IsFunctionDeclaration()) {
- position = FunctionDeclaration::Cast(parent)->position();
- }
- if (!position.IsReal()) {
- // Positions has to be unique in regards to the parent.
- // A non-real at this point is probably -1, we cannot blindly use that
- // as others might use it too. Create a new dummy non-real TokenPosition.
- position = TokenPosition(i).ToSynthetic();
- }
-
- // NOTE: This is not TokenPosition in the general sense!
- function = I->LookupClosureFunction(parsed_function_->function(), position);
- if (function.IsNull()) {
- const dart::String* name;
- if (parent->IsFunctionExpression()) {
- name = &Symbols::AnonymousClosure();
- } else {
- ASSERT(parent->IsFunctionDeclaration());
- name = &H.DartSymbol(
- FunctionDeclaration::Cast(parent)->variable()->name());
- }
- // NOTE: This is not TokenPosition in the general sense!
- function = Function::NewClosureFunction(
- *name, parsed_function_->function(), position);
-
- function.set_is_debuggable(node->dart_async_marker() ==
- FunctionNode::kSync);
- switch (node->dart_async_marker()) {
- case FunctionNode::kSyncStar:
- function.set_modifier(RawFunction::kSyncGen);
- break;
- case FunctionNode::kAsync:
- function.set_modifier(RawFunction::kAsync);
- function.set_is_inlinable(!FLAG_causal_async_stacks);
- break;
- case FunctionNode::kAsyncStar:
- function.set_modifier(RawFunction::kAsyncGen);
- function.set_is_inlinable(!FLAG_causal_async_stacks);
- break;
- default:
- // no special modifier
- break;
- }
- function.set_is_generated_body(node->async_marker() ==
- FunctionNode::kSyncYielding);
- if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
- function.set_is_inlinable(!FLAG_causal_async_stacks);
- }
-
- function.set_end_token_pos(node->end_position());
- LocalScope* scope = scopes_->function_scopes[i].scope;
- const ContextScope& context_scope =
- ContextScope::Handle(Z, scope->PreserveOuterScope(context_depth_));
- function.set_context_scope(context_scope);
- function.set_kernel_function(node);
- KernelReader::SetupFunctionParameters(H, T, dart::Class::Handle(Z),
- function, node,
- false, // is_method
- true); // is_closure
- // Finalize function type.
- Type& signature_type = Type::Handle(Z, function.SignatureType());
- signature_type ^=
- ClassFinalizer::FinalizeType(*active_class_.klass, signature_type);
- function.SetSignatureType(signature_type);
-
- I->AddClosureFunction(function);
- }
- break;
- }
-
- const dart::Class& closure_class =
- dart::Class::ZoneHandle(Z, I->object_store()->closure_class());
- ASSERT(!closure_class.IsNull());
- Fragment instructions = AllocateObject(closure_class, function);
- LocalVariable* closure = MakeTemporary();
-
- // The function signature can have uninstantiated class type parameters.
- //
- // TODO(regis): Also handle the case of a function signature that has
- // uninstantiated function type parameters.
- if (!function.HasInstantiatedSignature(kCurrentClass)) {
- instructions += LoadLocal(closure);
- instructions += LoadInstantiatorTypeArguments();
- instructions +=
- StoreInstanceField(TokenPosition::kNoSource,
- Closure::instantiator_type_arguments_offset());
- }
-
- // Store the function and the context in the closure.
- instructions += LoadLocal(closure);
- instructions += Constant(function);
- instructions +=
- StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset());
-
- instructions += LoadLocal(closure);
- instructions += LoadLocal(parsed_function_->current_context_var());
- instructions +=
- StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset());
-
- return instructions;
-}
-
-
RawObject* EvaluateMetadata(const dart::Field& metadata_field) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
Thread* thread = Thread::Current();
Zone* zone_ = thread->zone();
-
- TreeNode* kernel_node =
- reinterpret_cast<TreeNode*>(metadata_field.kernel_field());
- List<Expression>* metadata_expressions = NULL;
- if (kernel_node->IsClass()) {
- metadata_expressions = &Class::Cast(kernel_node)->annotations();
- } else if (kernel_node->IsProcedure()) {
- metadata_expressions = &Procedure::Cast(kernel_node)->annotations();
- } else if (kernel_node->IsField()) {
- metadata_expressions = &Field::Cast(kernel_node)->annotations();
- } else if (kernel_node->IsConstructor()) {
- metadata_expressions = &Constructor::Cast(kernel_node)->annotations();
- } else {
- FATAL1("No support for metadata on this type of kernel node %p\n",
- kernel_node);
- }
-
TranslationHelper helper(thread);
Script& script = Script::Handle(Z, metadata_field.Script());
helper.SetStringOffsets(
@@ -6017,20 +2700,11 @@
helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data()));
helper.SetCanonicalNames(
TypedData::Handle(Z, script.kernel_canonical_names()));
- DartTypeTranslator type_translator(&helper, NULL, true);
- ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z,
- &helper, &type_translator);
- const Array& metadata_values =
- Array::Handle(Z, Array::New(metadata_expressions->length()));
-
- for (intptr_t i = 0; i < metadata_expressions->length(); i++) {
- const Instance& value =
- constant_evaluator.EvaluateExpression((*metadata_expressions)[i]);
- metadata_values.SetAt(i, value);
- }
-
- return metadata_values.raw();
+ StreamingFlowGraphBuilder streaming_flow_graph_builder(
+ &helper, zone_, script.kernel_data(), script.kernel_data_size());
+ return streaming_flow_graph_builder.EvaluateMetadata(
+ metadata_field.kernel_offset());
} else {
Thread* thread = Thread::Current();
Error& error = Error::Handle();
@@ -6044,20 +2718,6 @@
RawObject* BuildParameterDescriptor(const Function& function) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- TreeNode* kernel_node =
- reinterpret_cast<TreeNode*>(function.kernel_function());
- FunctionNode* function_node = NULL;
- if (kernel_node->IsProcedure()) {
- function_node = Procedure::Cast(kernel_node)->function();
- } else if (kernel_node->IsConstructor()) {
- function_node = Constructor::Cast(kernel_node)->function();
- } else if (kernel_node->IsFunctionNode()) {
- function_node = FunctionNode::Cast(kernel_node);
- } else {
- UNIMPLEMENTED();
- return NULL;
- }
-
Thread* thread = Thread::Current();
Zone* zone_ = thread->zone();
TranslationHelper helper(thread);
@@ -6067,45 +2727,11 @@
helper.SetStringData(TypedData::Handle(Z, script.kernel_string_data()));
helper.SetCanonicalNames(
TypedData::Handle(Z, script.kernel_canonical_names()));
- DartTypeTranslator type_translator(&helper, NULL, true);
- ConstantEvaluator constant_evaluator(/* flow_graph_builder = */ NULL, Z,
- &helper, &type_translator);
- const intptr_t positional_count =
- function_node->positional_parameters().length();
- const intptr_t param_count =
- positional_count + function_node->named_parameters().length();
- const Array& param_descriptor = Array::Handle(
- Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld));
- for (intptr_t i = 0; i < param_count; ++i) {
- const intptr_t entry_start = i * Parser::kParameterEntrySize;
-
- VariableDeclaration* variable;
- if (i < positional_count) {
- variable = function_node->positional_parameters()[i];
- } else {
- variable = function_node->named_parameters()[i - positional_count];
- }
-
- param_descriptor.SetAt(
- entry_start + Parser::kParameterIsFinalOffset,
- variable->IsFinal() ? Bool::True() : Bool::False());
-
- if (variable->initializer() != NULL) {
- param_descriptor.SetAt(
- entry_start + Parser::kParameterDefaultValueOffset,
- constant_evaluator.EvaluateExpression(variable->initializer()));
- } else {
- param_descriptor.SetAt(
- entry_start + Parser::kParameterDefaultValueOffset,
- Object::null_instance());
- }
-
- param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset,
- /* Issue(28434): Missing parameter metadata. */
- Object::null_instance());
- }
- return param_descriptor.raw();
+ StreamingFlowGraphBuilder streaming_flow_graph_builder(
+ &helper, zone_, script.kernel_data(), script.kernel_data_size());
+ return streaming_flow_graph_builder.BuildParameterDescriptor(
+ function.kernel_offset());
} else {
Thread* thread = Thread::Current();
Error& error = Error::Handle();
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index 038e0e1..9591977 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -13,7 +13,6 @@
#include "vm/flow_graph.h"
#include "vm/flow_graph_builder.h"
#include "vm/intermediate_language.h"
-#include "vm/kernel.h"
namespace dart {
namespace kernel {
@@ -551,115 +550,6 @@
};
-// There are several cases when we are compiling constant expressions:
-//
-// * constant field initializers:
-// const FieldName = <expr>;
-//
-// * constant expressions:
-// const [<expr>, ...]
-// const {<expr> : <expr>, ...}
-// const Constructor(<expr>, ...)
-//
-// * constant default parameters:
-// f(a, [b = <expr>])
-// f(a, {b: <expr>})
-//
-// * constant values to compare in a [SwitchCase]
-// case <expr>:
-//
-// In all cases `<expr>` must be recursively evaluated and canonicalized at
-// compile-time.
-class ConstantEvaluator : public ExpressionVisitor {
- public:
- ConstantEvaluator(FlowGraphBuilder* builder,
- Zone* zone,
- TranslationHelper* h,
- DartTypeTranslator* type_translator);
- virtual ~ConstantEvaluator() {}
-
- Instance& EvaluateExpression(Expression* node);
- Object& EvaluateExpressionSafe(Expression* node);
- Instance& EvaluateConstructorInvocation(ConstructorInvocation* node);
- Instance& EvaluateListLiteral(ListLiteral* node);
- Instance& EvaluateMapLiteral(MapLiteral* node);
-
- virtual void VisitDefaultExpression(Expression* node) { UNREACHABLE(); }
-
- virtual void VisitBigintLiteral(BigintLiteral* node);
- virtual void VisitBoolLiteral(BoolLiteral* node);
- virtual void VisitDoubleLiteral(DoubleLiteral* node);
- virtual void VisitIntLiteral(IntLiteral* node);
- virtual void VisitNullLiteral(NullLiteral* node);
- virtual void VisitStringLiteral(StringLiteral* node);
- virtual void VisitSymbolLiteral(SymbolLiteral* node);
- virtual void VisitTypeLiteral(TypeLiteral* node);
-
- virtual void VisitListLiteral(ListLiteral* node);
- virtual void VisitMapLiteral(MapLiteral* node);
-
- virtual void VisitConstructorInvocation(ConstructorInvocation* node);
- virtual void VisitMethodInvocation(MethodInvocation* node);
- virtual void VisitStaticGet(StaticGet* node);
- virtual void VisitVariableGet(VariableGet* node);
- virtual void VisitLet(Let* node);
- virtual void VisitStaticInvocation(StaticInvocation* node);
- virtual void VisitStringConcatenation(StringConcatenation* node);
- virtual void VisitConditionalExpression(ConditionalExpression* node);
- virtual void VisitLogicalExpression(LogicalExpression* node);
- virtual void VisitNot(Not* node);
- virtual void VisitPropertyGet(PropertyGet* node);
-
- private:
- // This will translate type arguments form [kernel_arguments]. If no type
- // arguments are passed and the [target] is a factory then the null type
- // argument array will be returned.
- //
- // If none of these cases apply, NULL will be returned.
- const TypeArguments* TranslateTypeArguments(const Function& target,
- dart::Class* target_klass,
- Arguments* kernel_arguments);
-
- const Object& RunFunction(const Function& function,
- Arguments* arguments,
- const Instance* receiver = NULL,
- const TypeArguments* type_args = NULL);
-
- const Object& RunFunction(const Function& function,
- const Array& arguments,
- const Array& names);
-
- RawObject* EvaluateConstConstructorCall(const dart::Class& type_class,
- const TypeArguments& type_arguments,
- const Function& constructor,
- const Object& argument);
-
- void AssertBoolInCheckedMode() {
- if (isolate_->type_checks() && !result_.IsBool()) {
- translation_helper_.ReportError("Expected boolean expression.");
- }
- }
-
- bool EvaluateBooleanExpression(Expression* expression) {
- EvaluateExpression(expression);
- AssertBoolInCheckedMode();
- return result_.raw() == Bool::True().raw();
- }
-
- bool GetCachedConstant(TreeNode* node, Instance* value);
- void CacheConstantValue(TreeNode* node, const Instance& value);
-
- FlowGraphBuilder* builder_;
- Isolate* isolate_;
- Zone* zone_;
- TranslationHelper& translation_helper_;
- DartTypeTranslator& type_translator_;
-
- Script& script_;
- Instance& result_;
-};
-
-
struct FunctionScope {
intptr_t kernel_offset;
LocalScope* scope;
@@ -728,9 +618,9 @@
: entry(NULL), try_index(CatchClauseNode::kInvalidTryIndex) {}
};
-class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor {
+class FlowGraphBuilder {
public:
- FlowGraphBuilder(TreeNode* node,
+ FlowGraphBuilder(intptr_t kernel_offset,
ParsedFunction* parsed_function,
const ZoneGrowableArray<const ICData*>& ic_data_array,
ZoneGrowableArray<intptr_t>* context_level_array,
@@ -741,106 +631,24 @@
FlowGraph* BuildGraph();
- virtual void VisitDefaultExpression(Expression* node) { UNREACHABLE(); }
- virtual void VisitDefaultStatement(Statement* node) { UNREACHABLE(); }
-
- virtual void VisitInvalidExpression(InvalidExpression* node);
- virtual void VisitNullLiteral(NullLiteral* node);
- virtual void VisitBoolLiteral(BoolLiteral* node);
- virtual void VisitIntLiteral(IntLiteral* node);
- virtual void VisitBigintLiteral(BigintLiteral* node);
- virtual void VisitDoubleLiteral(DoubleLiteral* node);
- virtual void VisitStringLiteral(StringLiteral* node);
- virtual void VisitSymbolLiteral(SymbolLiteral* node);
- virtual void VisitTypeLiteral(TypeLiteral* node);
- virtual void VisitVariableGet(VariableGet* node);
- virtual void VisitVariableSet(VariableSet* node);
- virtual void VisitStaticGet(StaticGet* node);
- virtual void VisitStaticSet(StaticSet* node);
- virtual void VisitPropertyGet(PropertyGet* node);
- virtual void VisitPropertySet(PropertySet* node);
- virtual void VisitDirectPropertyGet(DirectPropertyGet* node);
- virtual void VisitDirectPropertySet(DirectPropertySet* node);
- virtual void VisitStaticInvocation(StaticInvocation* node);
- virtual void VisitMethodInvocation(MethodInvocation* node);
- virtual void VisitDirectMethodInvocation(DirectMethodInvocation* node);
- virtual void VisitConstructorInvocation(ConstructorInvocation* node);
- virtual void VisitIsExpression(IsExpression* node);
- virtual void VisitAsExpression(AsExpression* node);
- virtual void VisitConditionalExpression(ConditionalExpression* node);
- virtual void VisitLogicalExpression(LogicalExpression* node);
- virtual void VisitNot(Not* node);
- virtual void VisitThisExpression(ThisExpression* node);
- virtual void VisitStringConcatenation(StringConcatenation* node);
- virtual void VisitListLiteral(ListLiteral* node);
- virtual void VisitMapLiteral(MapLiteral* node);
- virtual void VisitFunctionExpression(FunctionExpression* node);
- virtual void VisitLet(Let* node);
- virtual void VisitThrow(Throw* node);
- virtual void VisitRethrow(Rethrow* node);
-
- virtual void VisitInvalidStatement(InvalidStatement* node);
- virtual void VisitEmptyStatement(EmptyStatement* node);
- virtual void VisitBlock(Block* node);
- virtual void VisitReturnStatement(ReturnStatement* node);
- virtual void VisitExpressionStatement(ExpressionStatement* node);
- virtual void VisitVariableDeclaration(VariableDeclaration* node);
- virtual void VisitFunctionDeclaration(FunctionDeclaration* node);
- virtual void VisitIfStatement(IfStatement* node);
- virtual void VisitWhileStatement(WhileStatement* node);
- virtual void VisitDoStatement(DoStatement* node);
- virtual void VisitForStatement(ForStatement* node);
- virtual void VisitForInStatement(ForInStatement* node);
- virtual void VisitLabeledStatement(LabeledStatement* node);
- virtual void VisitBreakStatement(BreakStatement* node);
- virtual void VisitSwitchStatement(SwitchStatement* node);
- virtual void VisitContinueSwitchStatement(ContinueSwitchStatement* node);
- virtual void VisitAssertStatement(AssertStatement* node);
- virtual void VisitTryFinally(TryFinally* node);
- virtual void VisitTryCatch(TryCatch* node);
- virtual void VisitYieldStatement(YieldStatement* node);
-
private:
- FlowGraph* BuildGraphOfFunction(FunctionNode* node,
- Constructor* constructor = NULL);
- FlowGraph* BuildGraphOfFieldAccessor(Field* node,
- LocalVariable* setter_value);
- FlowGraph* BuildGraphOfStaticFieldInitializer(Field* node);
FlowGraph* BuildGraphOfMethodExtractor(const Function& method);
- FlowGraph* BuildGraphOfImplicitClosureFunction(FunctionNode* kernel_function,
- const Function& function);
FlowGraph* BuildGraphOfNoSuchMethodDispatcher(const Function& function);
FlowGraph* BuildGraphOfInvokeFieldDispatcher(const Function& function);
- Fragment NativeFunctionBody(FunctionNode* kernel_function,
+ Fragment NativeFunctionBody(intptr_t first_positional_offset,
const Function& function);
- void SetupDefaultParameterValues(FunctionNode* function);
-
TargetEntryInstr* BuildTargetEntry();
JoinEntryInstr* BuildJoinEntry();
JoinEntryInstr* BuildJoinEntry(intptr_t try_index);
- Fragment TranslateArguments(Arguments* node, Array* argument_names);
ArgumentArray GetArguments(int count);
- Fragment TranslateInitializers(Class* kernel_class,
- List<Initializer>* initialiers);
- Fragment TranslateFieldInitializer(NameIndex canonical_name,
- Expression* init);
-
- Fragment TranslateStatement(Statement* statement);
- Fragment TranslateCondition(Expression* expression, bool* negate);
- Fragment TranslateExpression(Expression* expression);
-
Fragment TranslateFinallyFinalizers(TryFinallyBlock* outer_finally,
intptr_t target_context_depth);
- Fragment TranslateFunctionNode(FunctionNode* node, TreeNode* parent);
-
- Fragment EnterScope(TreeNode* node, bool* new_context = NULL);
Fragment EnterScope(intptr_t kernel_offset, bool* new_context = NULL);
- Fragment ExitScope(TreeNode* node);
Fragment ExitScope(intptr_t kernel_offset);
Fragment LoadContextAt(int depth);
@@ -943,7 +751,6 @@
Fragment EvaluateAssertion();
Fragment CheckReturnTypeInCheckedMode();
- Fragment CheckVariableTypeInCheckedMode(VariableDeclaration* variable);
Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type,
const dart::String& name_symbol);
Fragment CheckBooleanInCheckedMode();
@@ -954,9 +761,6 @@
Fragment AssertAssignable(const dart::AbstractType& dst_type,
const dart::String& dst_name);
- template <class Invocation>
- bool RecognizeComparisonWithNull(Token::Kind token_kind, Invocation* node);
-
bool NeedsDebugStepCheck(const Function& function, TokenPosition position);
bool NeedsDebugStepCheck(Value* value, TokenPosition position);
Fragment DebugStepCheck(TokenPosition position);
@@ -970,10 +774,6 @@
intptr_t CurrentTryIndex();
intptr_t AllocateTryIndex() { return next_used_try_index_++; }
- void AddVariable(VariableDeclaration* declaration, LocalVariable* variable);
- void AddParameter(VariableDeclaration* declaration,
- LocalVariable* variable,
- intptr_t pos);
dart::LocalVariable* LookupVariable(VariableDeclaration* var);
dart::LocalVariable* LookupVariable(intptr_t kernel_offset);
@@ -993,9 +793,7 @@
Thread* thread_;
Zone* zone_;
- // The node we are currently compiling (e.g. FunctionNode, Constructor,
- // Field)
- TreeNode* node_;
+ intptr_t kernel_offset_;
ParsedFunction* parsed_function_;
intptr_t osr_id_;
@@ -1025,7 +823,6 @@
intptr_t try_depth_;
intptr_t catch_depth_;
intptr_t for_in_depth_;
- Fragment fragment_;
Value* stack_;
intptr_t pending_argument_count_;
@@ -1069,7 +866,6 @@
ActiveClass active_class_;
DartTypeTranslator type_translator_;
- ConstantEvaluator constant_evaluator_;
StreamingFlowGraphBuilder* streaming_flow_graph_builder_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 62844ac..a1f636e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2740,7 +2740,7 @@
extractor.set_parameter_types(Object::extractor_parameter_types());
extractor.set_parameter_names(Object::extractor_parameter_names());
extractor.set_result_type(Object::dynamic_type());
- extractor.set_kernel_function(kernel_function());
+ extractor.set_kernel_offset(kernel_offset());
extractor.set_extracted_method_closure(closure_function);
extractor.set_is_debuggable(false);
@@ -6814,7 +6814,7 @@
NOT_IN_PRECOMPILED(result.set_deoptimization_counter(0));
NOT_IN_PRECOMPILED(result.set_optimized_instruction_count(0));
NOT_IN_PRECOMPILED(result.set_optimized_call_site_count(0));
- result.set_kernel_function(NULL);
+ result.set_kernel_offset(0);
result.set_is_optimizable(is_native ? false : true);
result.set_is_inlinable(true);
result.set_allows_hoisting_check_class(true);
@@ -6854,7 +6854,7 @@
clone.set_deoptimization_counter(0);
clone.set_optimized_instruction_count(0);
clone.set_optimized_call_site_count(0);
- clone.set_kernel_function(kernel_function());
+ clone.set_kernel_offset(kernel_offset());
if (new_owner.NumTypeParameters() > 0) {
// Adjust uninstantiated types to refer to type parameters of the new owner.
const TypeArguments& type_params =
@@ -7010,7 +7010,7 @@
param_name = ParameterNameAt(has_receiver - kClosure + i);
closure_function.SetParameterNameAt(i, param_name);
}
- closure_function.set_kernel_function(kernel_function());
+ closure_function.set_kernel_offset(kernel_offset());
const Type& signature_type =
Type::Handle(zone, closure_function.SignatureType());
@@ -7480,7 +7480,7 @@
bool Function::CheckSourceFingerprint(const char* prefix, int32_t fp) const {
- if ((kernel_function() == NULL) && (SourceFingerprint() != fp)) {
+ if ((kernel_offset() <= 0) && (SourceFingerprint() != fp)) {
const bool recalculatingFingerprints = false;
if (recalculatingFingerprints) {
// This output can be copied into a file, then used with sed
@@ -7864,7 +7864,7 @@
result.set_token_pos(token_pos);
result.set_has_initializer(false);
result.set_is_unboxing_candidate(true);
- result.set_kernel_field(NULL);
+ result.set_kernel_offset(0);
Isolate* isolate = Isolate::Current();
// Use field guards if they are enabled and the isolate has never reloaded.
@@ -7944,7 +7944,7 @@
Field& clone = Field::Handle();
clone ^= Object::Clone(*this, Heap::kOld);
clone.SetOriginal(original);
- clone.set_kernel_field(original.kernel_field());
+ clone.set_kernel_offset(original.kernel_offset());
return clone.raw();
}
@@ -9121,6 +9121,16 @@
}
+void Script::set_kernel_data(const uint8_t* kernel_data) const {
+ StoreNonPointer(&raw_ptr()->kernel_data_, kernel_data);
+}
+
+
+void Script::set_kernel_data_size(const intptr_t kernel_data_size) const {
+ StoreNonPointer(&raw_ptr()->kernel_data_size_, kernel_data_size);
+}
+
+
void Script::set_kernel_string_offsets(const TypedData& offsets) const {
StorePointer(&raw_ptr()->kernel_string_offsets_, offsets.raw());
}
@@ -10085,7 +10095,7 @@
void Library::AddMetadata(const Object& owner,
const String& name,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node) const {
+ intptr_t kernel_offset) const {
Thread* thread = Thread::Current();
ASSERT(thread->IsMutatorThread());
Zone* zone = thread->zone();
@@ -10098,7 +10108,7 @@
field.SetFieldType(Object::dynamic_type());
field.set_is_reflectable(false);
field.SetStaticValue(Array::empty_array(), true);
- field.set_kernel_field(kernel_node);
+ field.set_kernel_offset(kernel_offset);
GrowableObjectArray& metadata =
GrowableObjectArray::Handle(zone, this->metadata());
metadata.Add(field, Heap::kOld);
@@ -10108,36 +10118,36 @@
void Library::AddClassMetadata(const Class& cls,
const Object& tl_owner,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node) const {
+ intptr_t kernel_offset) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
// We use the toplevel class as the owner of a class's metadata field because
// a class's metadata is in scope of the library, not the class.
AddMetadata(tl_owner,
String::Handle(zone, MakeClassMetaName(thread, zone, cls)),
- token_pos, kernel_node);
+ token_pos, kernel_offset);
}
void Library::AddFieldMetadata(const Field& field,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node) const {
+ intptr_t kernel_offset) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
AddMetadata(Object::Handle(zone, field.RawOwner()),
String::Handle(zone, MakeFieldMetaName(thread, zone, field)),
- token_pos, kernel_node);
+ token_pos, kernel_offset);
}
void Library::AddFunctionMetadata(const Function& func,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node) const {
+ intptr_t kernel_offset) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
AddMetadata(Object::Handle(zone, func.RawOwner()),
String::Handle(zone, MakeFunctionMetaName(thread, zone, func)),
- token_pos, kernel_node);
+ token_pos, kernel_offset);
}
@@ -10213,7 +10223,7 @@
Object& metadata = Object::Handle();
metadata = field.StaticValue();
if (field.StaticValue() == Object::empty_array().raw()) {
- if (field.kernel_field() != NULL) {
+ if (field.kernel_offset() > 0) {
metadata = kernel::EvaluateMetadata(field);
} else {
metadata = Parser::ParseMetadata(field);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7419287..c6715d6 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2627,17 +2627,17 @@
#endif
}
- void* kernel_function() const {
+ intptr_t kernel_offset() const {
#if defined(DART_PRECOMPILED_RUNTIME)
- return NULL;
+ return 0;
#else
- return raw_ptr()->kernel_function_;
+ return raw_ptr()->kernel_offset_;
#endif
}
- void set_kernel_function(void* kernel_function) const {
+ void set_kernel_offset(intptr_t kernel_offset) const {
#if !defined(DART_PRECOMPILED_RUNTIME)
- StoreNonPointer(&raw_ptr()->kernel_function_, kernel_function);
+ StoreNonPointer(&raw_ptr()->kernel_offset_, kernel_offset);
#endif
}
@@ -3181,17 +3181,17 @@
set_kind_bits(DoubleInitializedBit::update(value, raw_ptr()->kind_bits_));
}
- void* kernel_field() const {
+ intptr_t kernel_offset() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return NULL;
#else
- return raw_ptr()->kernel_field_;
+ return raw_ptr()->kernel_offset_;
#endif
}
- void set_kernel_field(void* kernel_field) const {
+ void set_kernel_offset(intptr_t kernel_offset) const {
#if !defined(DART_PRECOMPILED_RUNTIME)
- StoreNonPointer(&raw_ptr()->kernel_field_, kernel_field);
+ StoreNonPointer(&raw_ptr()->kernel_offset_, kernel_offset);
#endif
}
@@ -3605,6 +3605,12 @@
}
void set_compile_time_constants(const Array& value) const;
+ const uint8_t* kernel_data() { return raw_ptr()->kernel_data_; }
+ void set_kernel_data(const uint8_t* kernel_data) const;
+
+ intptr_t kernel_data_size() { return raw_ptr()->kernel_data_size_; }
+ void set_kernel_data_size(const intptr_t kernel_data_size) const;
+
RawTypedData* kernel_string_offsets() const {
return raw_ptr()->kernel_string_offsets_;
}
@@ -3843,13 +3849,13 @@
void AddClassMetadata(const Class& cls,
const Object& tl_owner,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node = NULL) const;
+ intptr_t kernel_offset = 0) const;
void AddFieldMetadata(const Field& field,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node = NULL) const;
+ intptr_t kernel_offset = 0) const;
void AddFunctionMetadata(const Function& func,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node = NULL) const;
+ intptr_t kernel_offset = 0) const;
void AddLibraryMetadata(const Object& tl_owner,
TokenPosition token_pos) const;
void AddTypeParameterMetadata(const TypeParameter& param,
@@ -4018,7 +4024,7 @@
void AddMetadata(const Object& owner,
const String& name,
TokenPosition token_pos,
- kernel::TreeNode* kernel_node = NULL) const;
+ intptr_t kernel_offset = 0) const;
FINAL_HEAP_OBJECT_IMPLEMENTATION(Library, Object);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index c3f39cc..6f63938 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -235,47 +235,11 @@
kernel::ScopeBuildingResult* ParsedFunction::EnsureKernelScopes() {
if (kernel_scopes_ == NULL) {
- kernel::TreeNode* node = NULL;
- if (function().kernel_function() != NULL) {
- node = static_cast<kernel::TreeNode*>(function().kernel_function());
- }
-
- intptr_t kernel_offset = -1;
- const uint8_t* kernel_data = NULL;
- intptr_t kernel_data_size = 0;
- if (node != NULL) {
- kernel::TreeNode* library_node = node;
- if (node != NULL) {
- const Function* parent = &function();
- while (true) {
- library_node =
- static_cast<kernel::TreeNode*>(parent->kernel_function());
- while (library_node != NULL && !library_node->IsLibrary()) {
- if (library_node->IsMember()) {
- library_node = kernel::Member::Cast(library_node)->parent();
- } else if (library_node->IsClass()) {
- library_node = kernel::Class::Cast(library_node)->parent();
- break;
- } else {
- library_node = NULL;
- break;
- }
- }
- if (library_node != NULL) break;
- parent = &Function::Handle(parent->parent_function());
- }
- }
- if (library_node != NULL && library_node->IsLibrary()) {
- kernel::Library* library = kernel::Library::Cast(library_node);
- kernel_offset = node->kernel_offset();
- kernel_data = library->kernel_data();
- kernel_data_size = library->kernel_data_size();
- }
- }
-
- kernel::StreamingScopeBuilder builder2(this, kernel_offset, kernel_data,
- kernel_data_size);
- kernel_scopes_ = builder2.BuildScopes();
+ intptr_t kernel_offset = function().kernel_offset();
+ Script& script = Script::Handle(Z, function().script());
+ kernel::StreamingScopeBuilder builder(
+ this, kernel_offset, script.kernel_data(), script.kernel_data_size());
+ kernel_scopes_ = builder.BuildScopes();
}
return kernel_scopes_;
}
@@ -1664,7 +1628,7 @@
ASSERT(func.num_fixed_parameters() == 2); // closure, value.
} else if (!parent.IsGetterFunction() && !parent.IsImplicitGetterFunction()) {
// NOTE: For the `kernel -> flowgraph` we don't use the parser.
- if (parent.kernel_function() == NULL) {
+ if (parent.kernel_offset() <= 0) {
SkipFunctionPreamble();
const bool use_function_type_syntax = false;
const bool allow_explicit_default_values = true;
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 8b2ab13..a4297ba 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -1221,7 +1221,7 @@
ParsedFunction* parsed_function;
// Check if this field is coming from the Kernel binary.
- if (field.kernel_field() != NULL) {
+ if (field.kernel_offset() > 0) {
parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
} else {
parsed_function = Parser::ParseStaticFieldInitializer(field);
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index dec16dc..07dfed2 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -108,8 +108,8 @@
static inline intptr_t Hashcode(Key key) {
// We are using pointer hash for objects originating from Kernel because
// Fasta currently does not assign any position information to them.
- if (key->kernel_function() != NULL) {
- return SimplePointerHash(key->kernel_function());
+ if (key->kernel_offset() > 0) {
+ return key->kernel_offset();
} else {
return key->token_pos().value();
}
@@ -137,8 +137,8 @@
static inline intptr_t Hashcode(Key key) {
// We are using pointer hash for objects originating from Kernel because
// Fasta currently does not assign any position information to them.
- if (key->kernel_field() != NULL) {
- return SimplePointerHash(key->kernel_field());
+ if (key->kernel_offset() > 0) {
+ return key->kernel_offset();
} else {
return key->token_pos().value();
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index d9b73be..89e9999 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -893,7 +893,7 @@
uint32_t kind_tag_; // See Function::KindTagBits.
int16_t num_fixed_parameters_;
int16_t num_optional_parameters_; // > 0: positional; < 0: named.
- NOT_IN_PRECOMPILED(void* kernel_function_);
+ NOT_IN_PRECOMPILED(intptr_t kernel_offset_);
NOT_IN_PRECOMPILED(uint16_t optimized_instruction_count_);
NOT_IN_PRECOMPILED(uint16_t optimized_call_site_count_);
NOT_IN_PRECOMPILED(int8_t deoptimization_counter_);
@@ -1005,7 +1005,7 @@
int8_t guarded_list_length_in_object_offset_;
uint8_t kind_bits_; // static, final, const, has initializer....
- NOT_IN_PRECOMPILED(void* kernel_field_);
+ NOT_IN_PRECOMPILED(intptr_t kernel_offset_);
friend class CidRewriteVisitor;
};
@@ -1087,6 +1087,8 @@
int32_t col_offset_;
int8_t kind_; // Of type Kind.
int64_t load_timestamp_;
+ const uint8_t* kernel_data_;
+ intptr_t kernel_data_size_;
};
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index c610431..6317a72 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -757,7 +757,7 @@
func.set_deoptimization_counter(reader->Read<int8_t>());
func.set_optimized_instruction_count(reader->Read<uint16_t>());
func.set_optimized_call_site_count(reader->Read<uint16_t>());
- func.set_kernel_function(NULL);
+ func.set_kernel_offset(0);
func.set_was_compiled(false);
// Set all the object fields.
@@ -863,7 +863,7 @@
field.set_guarded_cid(reader->Read<int32_t>());
field.set_is_nullable(reader->Read<int32_t>());
field.set_kind_bits(reader->Read<uint8_t>());
- field.set_kernel_field(NULL);
+ field.set_kernel_offset(0);
// Set all the object fields.
READ_OBJECT_FIELDS(field, field.raw()->from(), field.raw()->to_snapshot(kind),