[vm, compiler] Remove ASTs and AST flow graph builder.

Change-Id: I4d3c6500577d5285ced327954040dab42ba92341
Reviewed-on: https://dart-review.googlesource.com/c/78823
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
Ryan Macnak 2018-10-10 18:00:21 +00:00 committed by commit-bot@chromium.org
parent 340e74629f
commit b8760fed67
56 changed files with 90 additions and 10861 deletions

View file

@ -325,7 +325,6 @@ dart/data_uri*test: Skip # Data uri's not supported by dart2js or the analyzer.
# Tests that use functionality not supported in Dart 2.
[ ($compiler == dartk || $compiler == dartkb) || $compiler == dartkp ]
cc/CanonicalizationInScriptSnapshots: SkipByDesign # Script snapshots unsupported.
cc/DartAPI_IsolateSetCheckedMode: SkipByDesign # Checked mode is not relevant for dart 2?
cc/DartAPI_LazyLoadDeoptimizes: SkipByDesign # Issue 33043, Dart_LoadSource unsupported.
cc/DartAPI_LoadLibraryPatch_Error1: SkipByDesign # Dart_LibraryLoadPatch unsupported.
@ -337,57 +336,16 @@ cc/DartAPI_LoadSource: SkipByDesign # Dart_LoadSource unsupported.
cc/DartAPI_LoadSource_LateLoad: SkipByDesign
cc/DartAPI_ParsePatchLibrary: SkipByDesign
cc/GenerateSource: Skip # Cannot generate source from a kernel binary.
cc/Parser_AllocateVariables_CaptureLoopVar: SkipByDesign # VM parser tests.
cc/Parser_AllocateVariables_CapturedVar: SkipByDesign
cc/Parser_AllocateVariables_Issue7681: SkipByDesign
cc/Parser_AllocateVariables_MiddleChain: SkipByDesign
cc/Parser_AllocateVariables_NestedCapturedVar: SkipByDesign
cc/Parser_AllocateVariables_TwoChains: SkipByDesign
cc/ScriptSnapshot: SkipByDesign # Script snapshots unsupported.
cc/ScriptSnapshot2: SkipByDesign
cc/SourcePosition_Async: SkipByDesign # VM parser tests (Issue 32704)
cc/SourcePosition_BitwiseOperations: SkipByDesign
cc/SourcePosition_ForLoop: SkipByDesign
cc/SourcePosition_If: SkipByDesign
cc/SourcePosition_IfElse: SkipByDesign
cc/SourcePosition_InstanceCalls: SkipByDesign
cc/SourcePosition_InstanceFields: SkipByDesign
cc/SourcePosition_LoadIndexed: SkipByDesign
cc/SourcePosition_StoreIndexed: SkipByDesign
cc/SourcePosition_Switch: SkipByDesign
cc/SourcePosition_TryCatchFinally: SkipByDesign
cc/SourcePosition_While: SkipByDesign
cc/SourcePosition_WhileContinueBreak: SkipByDesign
cc/CompileFunctionOnHelperThread: SkipByDesign
cc/CompileFunction: SkipByDesign
cc/InvokeDynamic_CompileError: SkipByDesign
cc/InvokeStatic_CompileError: SkipByDesign
cc/DartEntry: SkipByDesign
cc/FindCodeObject: SkipByDesign
cc/Parser_TopLevel: SkipByDesign
cc/DartDynamicResolve: SkipByDesign
cc/DartStaticResolve: SkipByDesign
cc/AllocateNewObjectCodegen: SkipByDesign
cc/InstanceCallCodegen: SkipByDesign
cc/StaticCallCodegen: SkipByDesign
cc/SimpleReturnCodegen: SkipByDesign
cc/SmiReturnCodegen: SkipByDesign
cc/SimpleStaticCallCodegen: SkipByDesign
cc/StaticCallReturnParameterCodegen: SkipByDesign
cc/StaticCallReturnParameterCodegen: SkipByDesign
cc/StaticCallSmiParamSumCodegen: SkipByDesign
cc/SmiAddCodegen: SkipByDesign
cc/GenericAddCodegen: SkipByDesign
cc/SmiBinaryOpCodegen: SkipByDesign
cc/BoolNotCodegen: SkipByDesign
cc/BoolAndCodegen: SkipByDesign
cc/BinaryOpCodegen: SkipByDesign
cc/SmiUnaryOpCodegen: SkipByDesign
cc/DoubleUnaryOpCodegen: SkipByDesign
cc/ParseClassDefinition: SkipByDesign
cc/CompileScript: SkipByDesign
cc/DartAPI_LoadLibraryPatch_1: SkipByDesign
cc/StackMapCodegen: SkipByDesign
[ $compiler == precompiler || $mode == product ]
cc/CoreSnapshotSize: SkipByDesign # Imports dart:mirrors

View file

@ -1,757 +0,0 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/ast.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_entry.h"
#include "vm/isolate.h"
#include "vm/log.h"
#include "vm/object_store.h"
#include "vm/resolver.h"
namespace dart {
#define DEFINE_VISIT_FUNCTION(BaseName) \
void BaseName##Node::Visit(AstNodeVisitor* visitor) { \
visitor->Visit##BaseName##Node(this); \
}
FOR_EACH_NODE(DEFINE_VISIT_FUNCTION)
#undef DEFINE_VISIT_FUNCTION
#define DEFINE_NAME_FUNCTION(BaseName) \
const char* BaseName##Node::Name() const { return #BaseName; }
FOR_EACH_NODE(DEFINE_NAME_FUNCTION)
#undef DEFINE_NAME_FUNCTION
const Field* AstNode::MayCloneField(const Field& value) {
if (Compiler::IsBackgroundCompilation() ||
FLAG_force_clone_compiler_objects) {
return &Field::ZoneHandle(value.CloneFromOriginal());
} else {
ASSERT(value.IsZoneHandle());
return &value;
}
}
// A visitor class to collect all the nodes (including children) into an
// array.
class AstNodeCollector : public AstNodeVisitor {
public:
explicit AstNodeCollector(GrowableArray<AstNode*>* nodes) : nodes_(nodes) {}
#define DEFINE_VISITOR_FUNCTION(BaseName) \
virtual void Visit##BaseName##Node(BaseName##Node* node) { \
nodes_->Add(node); \
node->VisitChildren(this); \
}
FOR_EACH_NODE(DEFINE_VISITOR_FUNCTION)
#undef DEFINE_VISITOR_FUNCTION
private:
GrowableArray<AstNode*>* nodes_;
DISALLOW_COPY_AND_ASSIGN(AstNodeCollector);
};
void SequenceNode::CollectAllNodes(GrowableArray<AstNode*>* nodes) {
AstNodeCollector node_collector(nodes);
this->Visit(&node_collector);
}
void SequenceNode::VisitChildren(AstNodeVisitor* visitor) const {
for (intptr_t i = 0; i < this->length(); i++) {
NodeAt(i)->Visit(visitor);
}
}
void SequenceNode::Add(AstNode* node) {
if (node->IsReturnNode()) {
node->AsReturnNode()->set_scope(scope());
}
nodes_.Add(node);
}
void PrimaryNode::VisitChildren(AstNodeVisitor* visitor) const {}
void ArgumentListNode::VisitChildren(AstNodeVisitor* visitor) const {
for (intptr_t i = 0; i < this->length(); i++) {
NodeAt(i)->Visit(visitor);
}
}
LetNode::LetNode(TokenPosition token_pos)
: AstNode(token_pos), vars_(1), initializers_(1), nodes_(1) {}
LocalVariable* LetNode::AddInitializer(AstNode* node) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
initializers_.Add(node);
char name[64];
Utils::SNPrint(name, sizeof(name), ":lt%s_%" Pd "", token_pos().ToCString(),
vars_.length());
LocalVariable* temp_var =
new LocalVariable(TokenPosition::kNoSource, token_pos(),
String::ZoneHandle(zone, Symbols::New(thread, name)),
Object::dynamic_type());
vars_.Add(temp_var);
return temp_var;
}
void LetNode::VisitChildren(AstNodeVisitor* visitor) const {
for (intptr_t i = 0; i < num_temps(); ++i) {
initializers_[i]->Visit(visitor);
}
for (intptr_t i = 0; i < nodes_.length(); ++i) {
nodes_[i]->Visit(visitor);
}
}
bool LetNode::IsPotentiallyConst() const {
for (intptr_t i = 0; i < num_temps(); i++) {
if (!initializers_[i]->IsPotentiallyConst()) {
return false;
}
}
for (intptr_t i = 0; i < nodes_.length(); i++) {
if (!nodes_[i]->IsPotentiallyConst()) {
return false;
}
}
return true;
}
const Instance* LetNode::EvalConstExpr() const {
for (intptr_t i = 0; i < num_temps(); i++) {
if (initializers_[i]->EvalConstExpr() == NULL) {
return NULL;
}
}
const Instance* last = NULL;
for (intptr_t i = 0; i < nodes_.length(); i++) {
last = nodes_[i]->EvalConstExpr();
if (last == NULL) {
return NULL;
}
}
return last;
}
void ArrayNode::VisitChildren(AstNodeVisitor* visitor) const {
for (intptr_t i = 0; i < this->length(); i++) {
ElementAt(i)->Visit(visitor);
}
}
bool StringInterpolateNode::IsPotentiallyConst() const {
for (int i = 0; i < value_->length(); i++) {
if (!value_->ElementAt(i)->IsPotentiallyConst()) {
return false;
}
}
return true;
}
bool LiteralNode::IsPotentiallyConst() const {
return true;
}
AstNode* LiteralNode::ApplyUnaryOp(Token::Kind unary_op_kind) {
if (unary_op_kind == Token::kNEGATE) {
if (literal().IsSmi()) {
const Smi& smi = Smi::Cast(literal());
const Instance& literal =
Instance::ZoneHandle(Integer::New(-smi.Value(), Heap::kOld));
return new LiteralNode(this->token_pos(), literal);
}
if (literal().IsMint()) {
const Mint& mint = Mint::Cast(literal());
const Instance& literal =
Instance::ZoneHandle(Integer::New(-mint.value(), Heap::kOld));
return new LiteralNode(this->token_pos(), literal);
}
if (literal().IsDouble()) {
const Double& dbl = Double::Cast(literal());
// Preserve negative zero.
double new_value = (dbl.value() == 0.0) ? -0.0 : (0.0 - dbl.value());
const Double& double_instance =
Double::ZoneHandle(Double::NewCanonical(new_value));
return new LiteralNode(this->token_pos(), double_instance);
}
} else if (unary_op_kind == Token::kBIT_NOT) {
if (literal().IsSmi()) {
const Smi& smi = Smi::Cast(literal());
const Instance& literal =
Instance::ZoneHandle(Integer::New(~smi.Value(), Heap::kOld));
return new LiteralNode(this->token_pos(), literal);
}
if (literal().IsMint()) {
const Mint& mint = Mint::Cast(literal());
const Instance& literal =
Instance::ZoneHandle(Integer::New(~mint.value(), Heap::kOld));
return new LiteralNode(this->token_pos(), literal);
}
} else if (unary_op_kind == Token::kNOT) {
if (literal().IsBool()) {
const Bool& boolean = Bool::Cast(literal());
return new LiteralNode(this->token_pos(), Bool::Get(!boolean.value()));
}
}
return NULL;
}
const char* TypeNode::TypeName() const {
return String::Handle(type().UserVisibleName()).ToCString();
}
bool ComparisonNode::IsKindValid() const {
return Token::IsRelationalOperator(kind_) ||
Token::IsEqualityOperator(kind_) || Token::IsTypeTestOperator(kind_) ||
Token::IsTypeCastOperator(kind_);
}
const char* ComparisonNode::TokenName() const {
return (kind_ == Token::kAS) ? "as" : Token::Str(kind_);
}
bool ComparisonNode::IsPotentiallyConst() const {
switch (kind_) {
case Token::kLT:
case Token::kGT:
case Token::kLTE:
case Token::kGTE:
case Token::kEQ:
case Token::kNE:
case Token::kEQ_STRICT:
case Token::kNE_STRICT:
return this->left()->IsPotentiallyConst() &&
this->right()->IsPotentiallyConst();
default:
return false;
}
}
const Instance* ComparisonNode::EvalConstExpr() const {
const Instance* left_val = this->left()->EvalConstExpr();
if (left_val == NULL) {
return NULL;
}
const Instance* right_val = this->right()->EvalConstExpr();
if (right_val == NULL) {
return NULL;
}
switch (kind_) {
case Token::kLT:
case Token::kGT:
case Token::kLTE:
case Token::kGTE:
if ((left_val->IsNumber() || left_val->IsNull()) &&
(right_val->IsNumber() || right_val->IsNull())) {
return &Bool::False();
}
return NULL;
case Token::kEQ:
case Token::kNE:
// The comparison is a compile time const if both operands are either a
// number, string, or boolean value (but not necessarily the same type).
if ((left_val->IsNumber() || left_val->IsString() || left_val->IsBool() ||
left_val->IsNull()) &&
(right_val->IsNumber() || right_val->IsString() ||
right_val->IsBool() || right_val->IsNull())) {
return &Bool::False();
}
return NULL;
case Token::kEQ_STRICT:
case Token::kNE_STRICT:
// identical(a, b) is a compile time const if both operands are
// compile time constants, regardless of their type.
return &Bool::True();
default:
return NULL;
}
return NULL;
}
bool BinaryOpNode::IsKindValid() const {
switch (kind_) {
case Token::kADD:
case Token::kSUB:
case Token::kMUL:
case Token::kDIV:
case Token::kTRUNCDIV:
case Token::kMOD:
case Token::kOR:
case Token::kAND:
case Token::kIFNULL:
case Token::kBIT_OR:
case Token::kBIT_XOR:
case Token::kBIT_AND:
case Token::kSHL:
case Token::kSHR:
return true;
default:
return false;
}
}
const char* BinaryOpNode::TokenName() const {
return Token::Str(kind_);
}
bool BinaryOpNode::IsPotentiallyConst() const {
switch (kind_) {
case Token::kOR:
case Token::kAND:
if (this->left()->IsLiteralNode() &&
this->left()->AsLiteralNode()->literal().IsNull()) {
return false;
}
if (this->right()->IsLiteralNode() &&
this->right()->AsLiteralNode()->literal().IsNull()) {
return false;
}
/* Falls through */
case Token::kADD:
case Token::kSUB:
case Token::kMUL:
case Token::kDIV:
case Token::kMOD:
case Token::kTRUNCDIV:
case Token::kBIT_OR:
case Token::kBIT_XOR:
case Token::kBIT_AND:
case Token::kSHL:
case Token::kSHR:
case Token::kIFNULL:
return this->left()->IsPotentiallyConst() &&
this->right()->IsPotentiallyConst();
default:
UNREACHABLE();
return false;
}
}
const Instance* BinaryOpNode::EvalConstExpr() const {
const Instance* left_val = this->left()->EvalConstExpr();
if (left_val == NULL) {
return NULL;
}
if (!left_val->IsNumber() && !left_val->IsBool() && !left_val->IsString() &&
kind_ != Token::kIFNULL) {
return NULL;
}
const Instance* right_val = this->right()->EvalConstExpr();
if (right_val == NULL) {
return NULL;
}
switch (kind_) {
case Token::kADD:
if (left_val->IsString()) {
return right_val->IsString() ? left_val : NULL;
}
/* Falls through */
case Token::kSUB:
case Token::kMUL:
case Token::kDIV:
case Token::kMOD:
case Token::kTRUNCDIV:
if (left_val->IsInteger()) {
if (right_val->IsInteger()) {
return left_val;
} else if (right_val->IsNumber()) {
return right_val;
}
} else if (left_val->IsNumber() && right_val->IsNumber()) {
return left_val;
}
return NULL;
case Token::kBIT_OR:
case Token::kBIT_XOR:
case Token::kBIT_AND:
case Token::kSHL:
case Token::kSHR:
if (left_val->IsInteger() && right_val->IsInteger()) {
return right_val;
}
return NULL;
case Token::kOR:
case Token::kAND:
if (left_val->IsBool() && right_val->IsBool()) {
return left_val;
}
return NULL;
case Token::kIFNULL:
if (left_val->IsNull()) {
return right_val;
}
return left_val;
default:
UNREACHABLE();
return NULL;
}
return NULL;
}
AstNode* UnaryOpNode::UnaryOpOrLiteral(TokenPosition token_pos,
Token::Kind kind,
AstNode* operand) {
AstNode* new_operand = operand->ApplyUnaryOp(kind);
if (new_operand != NULL) {
return new_operand;
}
return new UnaryOpNode(token_pos, kind, operand);
}
bool UnaryOpNode::IsKindValid() const {
switch (kind_) {
case Token::kNEGATE:
case Token::kNOT:
case Token::kBIT_NOT:
return true;
default:
return false;
}
}
bool UnaryOpNode::IsPotentiallyConst() const {
if (this->operand()->IsLiteralNode() &&
this->operand()->AsLiteralNode()->literal().IsNull()) {
return false;
}
return this->operand()->IsPotentiallyConst();
}
const Instance* UnaryOpNode::EvalConstExpr() const {
const Instance* val = this->operand()->EvalConstExpr();
if (val == NULL) {
return NULL;
}
switch (kind_) {
case Token::kNEGATE:
return val->IsNumber() ? val : NULL;
case Token::kNOT:
return val->IsBool() ? val : NULL;
case Token::kBIT_NOT:
return val->IsInteger() ? val : NULL;
default:
return NULL;
}
}
bool ConditionalExprNode::IsPotentiallyConst() const {
return this->condition()->IsPotentiallyConst() &&
this->true_expr()->IsPotentiallyConst() &&
this->false_expr()->IsPotentiallyConst();
}
const Instance* ConditionalExprNode::EvalConstExpr() const {
const Instance* cond = this->condition()->EvalConstExpr();
if ((cond != NULL) && cond->IsBool() &&
(this->true_expr()->EvalConstExpr() != NULL) &&
(this->false_expr()->EvalConstExpr() != NULL)) {
return cond;
}
return NULL;
}
bool ClosureNode::IsPotentiallyConst() const {
if (function().IsImplicitStaticClosureFunction()) {
return true;
}
return false;
}
const Instance* ClosureNode::EvalConstExpr() const {
if (!is_deferred_reference_ && function().IsImplicitStaticClosureFunction()) {
// Return a value that represents an instance. Only the type is relevant.
return &Instance::Handle();
}
return NULL;
}
AstNode* ClosureNode::MakeAssignmentNode(AstNode* rhs) {
if (scope() == NULL) {
// This is an implicit closure node created because a static getter was not
// found. Change the getter into a setter. If it does not exist,
// noSuchMethod will be called.
return new StaticSetterNode(token_pos(), receiver(),
Class::ZoneHandle(function().Owner()),
String::ZoneHandle(function().name()), rhs,
StaticGetterSetter::kNoRebind);
}
return NULL;
}
const char* UnaryOpNode::TokenName() const {
return Token::Str(kind_);
}
const char* JumpNode::TokenName() const {
return Token::Str(kind_);
}
bool LoadLocalNode::IsPotentiallyConst() const {
// Parameters of const constructors are implicitly final and can be
// used in initializer expressions.
// We can't check here whether the local variable is indeed a parameter,
// but this code is executed before any other local variables are
// added to the scope.
return local().is_final();
}
const Instance* LoadLocalNode::EvalConstExpr() const {
if (local().IsConst()) {
return local().ConstValue();
}
return NULL;
}
AstNode* LoadLocalNode::MakeAssignmentNode(AstNode* rhs) {
if (local().is_final()) {
return NULL;
}
return new StoreLocalNode(token_pos(), &local(), rhs);
}
AstNode* LoadStaticFieldNode::MakeAssignmentNode(AstNode* rhs) {
if (field().is_final()) {
return NULL;
}
if (Isolate::Current()->type_checks()) {
rhs = new AssignableNode(field().token_pos(), rhs,
AbstractType::ZoneHandle(field().type()),
String::ZoneHandle(field().name()));
}
return new StoreStaticFieldNode(token_pos(),
Field::ZoneHandle(field().Original()), rhs);
}
AstNode* InstanceGetterNode::MakeAssignmentNode(AstNode* rhs) {
return new InstanceSetterNode(token_pos(), receiver(), field_name(), rhs,
is_conditional());
}
bool InstanceGetterNode::IsPotentiallyConst() const {
return field_name().Equals(Symbols::Length()) && !is_conditional() &&
receiver()->IsPotentiallyConst();
}
const Instance* InstanceGetterNode::EvalConstExpr() const {
if (field_name().Equals(Symbols::Length()) && !is_conditional()) {
const Instance* receiver_val = receiver()->EvalConstExpr();
if ((receiver_val != NULL) && receiver_val->IsString()) {
return &Instance::ZoneHandle(Smi::New(1));
}
}
return NULL;
}
AstNode* LoadIndexedNode::MakeAssignmentNode(AstNode* rhs) {
return new StoreIndexedNode(token_pos(), array(), index_expr(), rhs,
super_class());
}
AstNode* StaticGetterNode::MakeAssignmentNode(AstNode* rhs) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
if (is_super_getter()) {
ASSERT(receiver() != NULL);
const String& setter_name =
String::ZoneHandle(zone, Field::LookupSetterSymbol(field_name_));
Function& setter = Function::ZoneHandle(zone);
if (!setter_name.IsNull()) {
setter = Resolver::ResolveDynamicAnyArgs(zone, cls(), setter_name);
}
if (setter.IsNull() || setter.is_abstract()) {
// No instance setter found in super class chain,
// noSuchMethod will be called at runtime.
return new StaticSetterNode(token_pos(), receiver(), cls(), field_name_,
rhs, StaticGetterSetter::kSuper);
}
return new StaticSetterNode(token_pos(), receiver(), field_name_, setter,
rhs, StaticGetterSetter::kSuper);
}
if (owner().IsLibraryPrefix()) {
const LibraryPrefix& prefix = LibraryPrefix::Cast(owner_);
// The parser has already dealt with the pathological case where a
// library imports itself. See Parser::ResolveIdentInPrefixScope()
ASSERT(field_name_.CharAt(0) != Library::kPrivateIdentifierStart);
// If the prefix is not yet loaded, the getter doesn't exist. Return a
// setter that will throw a NSME at runtime.
if (!prefix.is_loaded()) {
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs,
StaticGetterSetter::kStatic);
}
Object& obj = Object::Handle(zone, prefix.LookupObject(field_name_));
if (obj.IsField()) {
const Field& field = Field::ZoneHandle(zone, Field::Cast(obj).raw());
if (!field.is_final()) {
if (isolate->type_checks()) {
rhs = new AssignableNode(field.token_pos(), rhs,
AbstractType::ZoneHandle(zone, field.type()),
field_name_);
}
return new StoreStaticFieldNode(token_pos(), field, rhs);
}
}
// No field found in prefix. Look for a setter function.
const String& setter_name =
String::Handle(zone, Field::LookupSetterSymbol(field_name_));
if (!setter_name.IsNull()) {
obj = prefix.LookupObject(setter_name);
if (obj.IsFunction()) {
const Function& setter =
Function::ZoneHandle(zone, Function::Cast(obj).raw());
ASSERT(setter.is_static() && setter.IsSetterFunction());
return new StaticSetterNode(token_pos(), NULL, field_name_, setter, rhs,
StaticGetterSetter::kStatic);
}
}
// No writeable field and no setter found in the prefix. Return a
// non-existing setter that will throw an NSM error.
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs,
StaticGetterSetter::kStatic);
}
if (owner().IsLibrary()) {
const Library& library = Library::Cast(owner());
Object& obj = Object::Handle(zone, library.ResolveName(field_name_));
if (obj.IsField()) {
const Field& field = Field::ZoneHandle(zone, Field::Cast(obj).raw());
if (!field.is_final()) {
if (isolate->type_checks()) {
rhs = new AssignableNode(field.token_pos(), rhs,
AbstractType::ZoneHandle(zone, field.type()),
field_name_);
}
return new StoreStaticFieldNode(token_pos(), field, rhs);
}
}
// No field found in library. Look for a setter function.
const String& setter_name =
String::Handle(zone, Field::LookupSetterSymbol(field_name_));
if (!setter_name.IsNull()) {
obj = library.ResolveName(setter_name);
if (obj.IsFunction()) {
const Function& setter =
Function::ZoneHandle(zone, Function::Cast(obj).raw());
ASSERT(setter.is_static() && setter.IsSetterFunction());
return new StaticSetterNode(token_pos(), NULL, field_name_, setter, rhs,
StaticGetterSetter::kStatic);
}
}
// No writeable field and no setter found in the library. Return a
// non-existing setter that will throw an NSM error.
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs,
StaticGetterSetter::kStatic);
}
const Function& setter =
Function::ZoneHandle(zone, cls().LookupSetterFunction(field_name_));
if (!setter.IsNull() && setter.IsStaticFunction()) {
return new StaticSetterNode(token_pos(), NULL, field_name_, setter, rhs,
StaticGetterSetter::kStatic);
}
// Could not find a static setter. Look for a field.
// Access to a lazily initialized static field that has not yet been
// initialized is compiled to a static implicit getter.
// A setter may not exist for such a field.
const Field& field =
Field::ZoneHandle(zone, cls().LookupStaticField(field_name_));
if (!field.IsNull()) {
if (field.is_final()) {
// Attempting to assign to a final variable will cause a NoSuchMethodError
// to be thrown. Change static getter to non-existent static setter in
// order to trigger the throw at runtime.
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs,
StaticGetterSetter::kStatic);
}
#if defined(DEBUG)
const String& getter_name =
String::Handle(zone, Field::LookupGetterSymbol(field_name_));
ASSERT(!getter_name.IsNull());
const Function& getter =
Function::Handle(zone, cls().LookupStaticFunction(getter_name));
ASSERT(!getter.IsNull() &&
(getter.kind() == RawFunction::kImplicitStaticFinalGetter));
#endif
if (isolate->type_checks()) {
rhs = new AssignableNode(field.token_pos(), rhs,
AbstractType::ZoneHandle(zone, field.type()),
String::ZoneHandle(zone, field.name()));
}
return new StoreStaticFieldNode(token_pos(), field, rhs);
}
// Didn't find a static setter or a static field. Make a call to
// the non-existent setter to trigger a NoSuchMethodError at runtime.
return new StaticSetterNode(token_pos(), NULL, cls(), field_name_, rhs,
StaticGetterSetter::kStatic);
}
AstNode* StaticCallNode::MakeAssignmentNode(AstNode* rhs) {
// Return this node if it represents a 'throw NoSuchMethodError' indicating
// that a getter was not found, otherwise return null.
const Class& cls = Class::Handle(function().Owner());
const String& cls_name = String::Handle(cls.Name());
const String& func_name = String::Handle(function().name());
if (cls_name.Equals(Symbols::NoSuchMethodError()) &&
func_name.StartsWith(Symbols::ThrowNew())) {
return this;
}
return NULL;
}
bool StaticGetterNode::IsPotentiallyConst() const {
if (is_deferred_reference_) {
return false;
}
const String& getter_name =
String::Handle(Field::GetterName(this->field_name()));
const Function& getter_func =
Function::Handle(this->cls().LookupStaticFunction(getter_name));
if (getter_func.IsNull() || !getter_func.is_const()) {
return false;
}
return true;
}
const Instance* StaticGetterNode::EvalConstExpr() const {
if (is_deferred_reference_) {
return NULL;
}
const String& getter_name =
String::Handle(Field::LookupGetterSymbol(this->field_name()));
if (getter_name.IsNull()) {
return NULL;
}
const Function& getter_func =
Function::Handle(this->cls().LookupStaticFunction(getter_name));
if (getter_func.IsNull() || !getter_func.is_const()) {
return NULL;
}
const Object& result = Object::Handle(
DartEntry::InvokeFunction(getter_func, Object::empty_array()));
if (result.IsError() || result.IsNull()) {
// TODO(turnidge): We could get better error messages by returning
// the Error object directly to the parser. This will involve
// replumbing all of the EvalConstExpr methods.
return NULL;
}
return &Instance::ZoneHandle(Instance::Cast(result).raw());
}
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)

File diff suppressed because it is too large Load diff

View file

@ -1,515 +0,0 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/ast_printer.h"
#include "vm/handles.h"
#include "vm/log.h"
#include "vm/object.h"
#include "vm/os.h"
#include "vm/parser.h"
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
AstPrinter::AstPrinter(bool log)
: indent_(0), logger_(log ? Log::Current() : Log::NoOpLog()) {}
AstPrinter::~AstPrinter() {}
void AstPrinter::VisitGenericAstNode(AstNode* node) {
logger_->Print("(%s ", node->Name());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitSequenceNode(SequenceNode* node) {
indent_++;
LocalScope* scope = node->scope();
logger_->Print("(%s (scope \"%p\"", node->Name(), scope);
if (scope != NULL) {
logger_->Print(" (%s-%s) loop %d", scope->begin_token_pos().ToCString(),
scope->end_token_pos().ToCString(), scope->loop_level());
if (scope->HasContextLevel()) {
logger_->Print(" context %d captures %d", scope->context_level(),
scope->num_context_variables());
} else {
ASSERT(scope->num_context_variables() == 0);
}
}
logger_->Print(")");
for (int i = 0; i < node->length(); ++i) {
PrintNewlineAndIndent();
node->NodeAt(i)->Visit(this);
}
logger_->Print(")");
indent_--;
}
void AstPrinter::VisitCloneContextNode(CloneContextNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitArgumentListNode(ArgumentListNode* arguments) {
VisitGenericAstNode(arguments);
}
void AstPrinter::VisitReturnNode(ReturnNode* node) {
const char* kind;
switch (node->return_type()) {
case ReturnNode::kContinuation:
kind = "continuation ";
break;
case ReturnNode::kContinuationTarget:
kind = "continuation-target ";
break;
case ReturnNode::kRegular:
kind = "";
break;
default:
kind = "";
UNREACHABLE();
}
logger_->Print("(%s %s", node->Name(), kind);
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitGenericLocalNode(AstNode* node,
const LocalVariable& variable) {
logger_->Print("(%s ", node->Name());
PrintLocalVariable(&variable);
logger_->Print(" ");
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitLoadLocalNode(LoadLocalNode* node) {
VisitGenericLocalNode(node, node->local());
}
void AstPrinter::VisitStoreLocalNode(StoreLocalNode* node) {
VisitGenericLocalNode(node, node->local());
}
void AstPrinter::VisitGenericFieldNode(AstNode* node, const Field& field) {
logger_->Print(
"(%s %s%s \"%s\" ", node->Name(), field.is_final() ? "final " : "",
String::Handle(AbstractType::Handle(field.type()).Name()).ToCString(),
String::Handle(field.name()).ToCString());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) {
VisitGenericFieldNode(node, node->field());
}
void AstPrinter::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) {
VisitGenericFieldNode(node, Field::ZoneHandle(node->field().Original()));
}
void AstPrinter::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
VisitGenericFieldNode(node, node->field());
}
void AstPrinter::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
VisitGenericFieldNode(node, node->field());
}
void AstPrinter::PrintLocalVariable(const LocalVariable* variable) {
logger_->Print("%s%s \"%s\"", variable->is_final() ? "final " : "",
String::Handle(variable->type().Name()).ToCString(),
variable->name().ToCString());
if (variable->HasIndex()) {
const int index = variable->index().value();
if (variable->is_captured()) {
logger_->Print(" (context %d %d)", variable->owner()->context_level(),
index);
} else {
logger_->Print(" (stack %d)", index);
}
}
}
void AstPrinter::PrintNewlineAndIndent() {
logger_->Print("\n");
for (intptr_t p = 0; p < indent_; ++p) {
logger_->Print(" ");
}
}
void AstPrinter::VisitLetNode(LetNode* node) {
logger_->Print("(Let (");
// Indent the variables and initializers by two.
indent_ += 2;
for (intptr_t i = 0; i < node->num_temps(); ++i) {
if (i != 0) PrintNewlineAndIndent();
logger_->Print("(");
PrintLocalVariable(node->TempAt(i));
logger_->Print(" ");
node->InitializerAt(i)->Visit(this);
logger_->Print(")");
}
logger_->Print(")");
// Indent the body nodes by one.
--indent_;
for (intptr_t i = 0; i < node->nodes().length(); ++i) {
PrintNewlineAndIndent();
node->nodes()[i]->Visit(this);
}
logger_->Print(")");
--indent_;
}
void AstPrinter::VisitArrayNode(ArrayNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitStringInterpolateNode(StringInterpolateNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitLiteralNode(LiteralNode* node) {
const Instance& literal = node->literal();
logger_->Print("(%s \"%s\")", node->Name(), literal.ToCString());
}
void AstPrinter::VisitTypeNode(TypeNode* node) {
const AbstractType& type = node->type();
logger_->Print("(%s \"%s\")", node->Name(),
String::Handle(type.Name()).ToCString());
}
void AstPrinter::VisitAssignableNode(AssignableNode* node) {
const AbstractType& type = node->type();
const String& dst_name = node->dst_name();
logger_->Print("(%s (type \"%s\") (of \"%s\") ", node->Name(),
String::Handle(type.Name()).ToCString(), dst_name.ToCString());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitAwaitNode(AwaitNode* node) {
logger_->Print("(*****%s***** (scope \"%p\") ", node->Name(), node->scope());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
logger_->Print("(%s (async_scope \"%p\" await_scope \"%p\"))", node->Name(),
node->async_scope(), node->await_scope());
}
void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
logger_->Print("(*****%s***** \"%s\")", node->Name(),
node->primary().ToCString());
}
void AstPrinter::VisitComparisonNode(ComparisonNode* node) {
logger_->Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) {
logger_->Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
logger_->Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitConditionalExprNode(ConditionalExprNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitIfNode(IfNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitCaseNode(CaseNode* node) {
logger_->Print("(%s (", node->Name());
for (int i = 0; i < node->case_expressions()->length(); i++) {
node->case_expressions()->NodeAt(i)->Visit(this);
}
if (node->contains_default()) {
logger_->Print(" default");
}
logger_->Print(")");
node->statements()->Visit(this);
logger_->Print(")");
}
void AstPrinter::VisitSwitchNode(SwitchNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitWhileNode(WhileNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitForNode(ForNode* node) {
// Complicated because the condition is optional and so we clearly want to
// indicate the subparts.
logger_->Print("(%s (init ", node->Name());
node->initializer()->Visit(this);
if (node->condition() != NULL) {
logger_->Print(") (cond ");
node->condition()->Visit(this);
}
logger_->Print(") (update ");
node->increment()->Visit(this);
logger_->Print(") ");
node->body()->Visit(this);
logger_->Print(")");
}
void AstPrinter::VisitDoWhileNode(DoWhileNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitJumpNode(JumpNode* node) {
logger_->Print("(%s %s %s (scope \"%p\"))", node->Name(), node->TokenName(),
node->label()->name().ToCString(), node->label()->owner());
}
void AstPrinter::VisitInstanceCallNode(InstanceCallNode* node) {
logger_->Print("(%s \"%s\" ", node->Name(),
node->function_name().ToCString());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitStaticCallNode(StaticCallNode* node) {
const char* function_fullname = node->function().ToFullyQualifiedCString();
logger_->Print("(%s \"%s\" ", node->Name(), function_fullname);
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitClosureNode(ClosureNode* node) {
const char* function_fullname = node->function().ToFullyQualifiedCString();
logger_->Print("(%s \"%s\")", node->Name(), function_fullname);
}
void AstPrinter::VisitClosureCallNode(ClosureCallNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitConstructorCallNode(ConstructorCallNode* node) {
const char* kind = node->constructor().IsFactory() ? "factory " : "";
const char* constructor_name = node->constructor().ToFullyQualifiedCString();
logger_->Print("(%s %s \"%s\" ", node->Name(), kind, constructor_name);
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitInstanceGetterNode(InstanceGetterNode* node) {
logger_->Print("(%s \"%s\" ", node->Name(), node->field_name().ToCString());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitInstanceSetterNode(InstanceSetterNode* node) {
logger_->Print("(%s \"%s\" ", node->Name(), node->field_name().ToCString());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitInitStaticFieldNode(InitStaticFieldNode* node) {
logger_->Print("(%s \"%s\")", node->Name(),
String::Handle(node->field().name()).ToCString());
}
void AstPrinter::VisitStaticGetterNode(StaticGetterNode* node) {
String& class_name = String::Handle(node->cls().Name());
logger_->Print("(%s \"%s.%s\")", node->Name(), class_name.ToCString(),
node->field_name().ToCString());
}
void AstPrinter::VisitStaticSetterNode(StaticSetterNode* node) {
String& class_name = String::Handle(node->cls().Name());
logger_->Print("(%s \"%s.%s\" ", node->Name(), class_name.ToCString(),
node->field_name().ToCString());
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitLoadIndexedNode(LoadIndexedNode* node) {
logger_->Print("(%s%s ", node->Name(), node->IsSuperLoad() ? " super" : "");
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitStoreIndexedNode(StoreIndexedNode* node) {
logger_->Print("(%s%s ", node->Name(), node->IsSuperStore() ? " super" : "");
node->VisitChildren(this);
logger_->Print(")");
}
void AstPrinter::VisitNativeBodyNode(NativeBodyNode* node) {
logger_->Print(
"(%s \"%s\" (%" Pd " args))", node->Name(),
node->native_c_function_name().ToCString(),
NativeArguments::ParameterCountForResolution(node->function()));
}
void AstPrinter::VisitCatchClauseNode(CatchClauseNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitTryCatchNode(TryCatchNode* node) {
logger_->Print("(%s ", node->Name());
node->try_block()->Visit(this);
node->catch_block()->Visit(this);
if (node->finally_block() != NULL) {
logger_->Print("(finally ");
node->finally_block()->Visit(this);
logger_->Print(")");
}
logger_->Print(")");
}
void AstPrinter::VisitThrowNode(ThrowNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::VisitStopNode(StopNode* node) {
logger_->Print("(%s %s)", node->Name(), node->message());
}
void AstPrinter::VisitInlinedFinallyNode(InlinedFinallyNode* node) {
VisitGenericAstNode(node);
}
void AstPrinter::PrintNode(AstNode* node) {
ASSERT(node != NULL);
AstPrinter ast_printer;
node->Visit(&ast_printer);
logger_->Print("\n");
}
void AstPrinter::IndentN(int count) {
for (int i = 0; i < count; i++) {
logger_->Print(" ");
}
}
void AstPrinter::PrintLocalScopeVariable(const LocalScope* scope,
LocalVariable* var,
int indent) {
ASSERT(scope != NULL);
ASSERT(var != NULL);
IndentN(indent);
logger_->Print("(%s%s '%s'", var->is_final() ? "final " : "",
String::Handle(var->type().Name()).ToCString(),
var->name().ToCString());
if (var->owner() != scope) {
logger_->Print(" alias");
}
if (var->HasIndex()) {
logger_->Print(" @%d", var->index().value());
if (var->is_captured()) {
logger_->Print(" ctx %d", var->owner()->context_level());
}
} else if (var->owner()->function_level() != 0) {
logger_->Print(" lev %d", var->owner()->function_level());
}
logger_->Print(" valid %s-%s)\n", var->token_pos().ToCString(),
scope->end_token_pos().ToCString());
}
void AstPrinter::PrintLocalScope(const LocalScope* scope,
int start_index,
int indent) {
ASSERT(scope != NULL);
for (int i = start_index; i < scope->num_variables(); i++) {
LocalVariable* var = scope->VariableAt(i);
PrintLocalScopeVariable(scope, var, indent);
}
const LocalScope* child = scope->child();
while (child != NULL) {
IndentN(indent);
logger_->Print("{scope %p ", child);
if (child->HasContextLevel()) {
logger_->Print("ctx %d numctxvar %d ", child->context_level(),
child->num_context_variables());
}
logger_->Print("llev %d\n", child->loop_level());
PrintLocalScope(child, 0, indent + kScopeIndent);
IndentN(indent);
logger_->Print("}\n");
child = child->sibling();
}
}
void AstPrinter::PrintFunctionScope(const ParsedFunction& parsed_function) {
HANDLESCOPE(parsed_function.thread());
const Function& function = parsed_function.function();
SequenceNode* node_sequence = parsed_function.node_sequence();
ASSERT(node_sequence != NULL);
const LocalScope* scope = node_sequence->scope();
ASSERT(scope != NULL);
const char* function_name = function.ToFullyQualifiedCString();
logger_->Print("Scope for function '%s'\n{scope %p ", function_name, scope);
if (scope->HasContextLevel()) {
logger_->Print("ctx %d numctxvar %d ", scope->context_level(),
scope->num_context_variables());
}
logger_->Print("llev %d\n", scope->loop_level());
const int num_fixed_params = function.num_fixed_parameters();
const int num_params = num_fixed_params + function.NumOptionalParameters();
// Parameters must be listed first and must all appear in the top scope.
ASSERT(num_params <= scope->num_variables());
int pos = 0; // Current position of variable in scope.
int indent = kScopeIndent;
while (pos < num_params) {
LocalVariable* param = scope->VariableAt(pos);
ASSERT(param->owner() == scope); // No aliases should precede parameters.
IndentN(indent);
logger_->Print("(param %s%s '%s'", param->is_final() ? "final " : "",
String::Handle(param->type().Name()).ToCString(),
param->name().ToCString());
// Print the default value if the parameter is optional.
if (pos >= num_fixed_params && pos < num_params) {
const Instance& default_parameter_value =
parsed_function.DefaultParameterValueAt(pos - num_fixed_params);
logger_->Print(" =%s", default_parameter_value.ToCString());
}
if (param->HasIndex()) {
logger_->Print(" @%d", param->index().value());
if (param->is_captured()) {
logger_->Print(" ctx %d", param->owner()->context_level());
}
}
logger_->Print(" valid %s-%s)\n", param->token_pos().ToCString(),
scope->end_token_pos().ToCString());
pos++;
}
// Visit remaining non-parameter variables and children scopes.
PrintLocalScope(scope, pos, indent);
logger_->Print("}\n");
}
void AstPrinter::PrintFunctionNodes(const ParsedFunction& parsed_function) {
HANDLESCOPE(parsed_function.thread());
SequenceNode* node_sequence = parsed_function.node_sequence();
ASSERT(node_sequence != NULL);
const char* function_name =
parsed_function.function().ToFullyQualifiedCString();
logger_->Print("Ast for function '%s' {\n", function_name);
node_sequence->Visit(this);
logger_->Print("}\n");
}
} // namespace dart
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -1,58 +0,0 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_AST_PRINTER_H_
#define RUNTIME_VM_AST_PRINTER_H_
#include "vm/ast.h"
#include "vm/growable_array.h"
namespace dart {
// Forward declaration.
class ParsedFunction;
class Log;
class AstPrinter : public AstNodeVisitor {
public:
explicit AstPrinter(bool log = true);
~AstPrinter();
void PrintNode(AstNode* node);
void PrintFunctionScope(const ParsedFunction& parsed_function);
void PrintFunctionNodes(const ParsedFunction& parsed_function);
#define DECLARE_VISITOR_FUNCTION(BaseName) \
virtual void Visit##BaseName##Node(BaseName##Node* node);
FOR_EACH_NODE(DECLARE_VISITOR_FUNCTION)
#undef DECLARE_VISITOR_FUNCTION
private:
static const int kScopeIndent = 2;
void IndentN(int count);
void PrintLocalScopeVariable(const LocalScope* scope,
LocalVariable* var,
int indent = 0);
void PrintLocalScope(const LocalScope* scope,
int variable_index,
int indent = 0);
void VisitGenericAstNode(AstNode* node);
void VisitGenericLocalNode(AstNode* node, const LocalVariable& local);
void VisitGenericFieldNode(AstNode* node, const Field& field);
void PrintLocalVariable(const LocalVariable* variable);
void PrintNewlineAndIndent();
intptr_t indent_;
Log* logger_;
DISALLOW_COPY_AND_ASSIGN(AstPrinter);
};
} // namespace dart
#endif // RUNTIME_VM_AST_PRINTER_H_

View file

@ -1,40 +0,0 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/ast_printer.h"
#include "platform/assert.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/unit_test.h"
namespace dart {
#ifndef PRODUCT
ISOLATE_UNIT_TEST_CASE(AstPrinter) {
const TokenPosition kPos = TokenPosition::kNoSource;
LocalVariable* v = new LocalVariable(
kPos, kPos, String::ZoneHandle(Symbols::New(thread, "wurscht")),
Type::ZoneHandle(Type::DynamicType()));
v->set_index(VariableIndex(5));
AstPrinter ast_printer;
LoadLocalNode* ll = new LoadLocalNode(kPos, v);
ReturnNode* r = new ReturnNode(kPos, ll);
ast_printer.PrintNode(r);
AstNode* l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
ReturnNode* rl = new ReturnNode(kPos, l);
ast_printer.PrintNode(rl);
ast_printer.PrintNode(new ReturnNode(kPos));
ast_printer.PrintNode(new BinaryOpNode(
kPos, Token::kADD, new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))),
new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(5)))));
ast_printer.PrintNode(new UnaryOpNode(kPos, Token::kNEGATE, ll));
}
#endif // !PRODUCT
} // namespace dart

View file

@ -1,64 +0,0 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/ast.h"
#include "platform/assert.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/unit_test.h"
namespace dart {
TEST_CASE(Ast) {
LocalVariable* v =
new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
String::ZoneHandle(Symbols::New(thread, "v")),
Type::ZoneHandle(Type::DynamicType()));
AstNode* ll = new LoadLocalNode(TokenPosition::kNoSource, v);
EXPECT(ll->IsLoadLocalNode());
EXPECT(!ll->IsLiteralNode());
LoadLocalNode* lln = ll->AsLoadLocalNode();
EXPECT(NULL != lln);
v->set_index(VariableIndex(1));
EXPECT_EQ(1, v->index().value());
LocalVariable* p =
new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
String::ZoneHandle(Symbols::New(thread, "p")),
Type::ZoneHandle(Type::DynamicType()));
EXPECT(!p->HasIndex());
p->set_index(VariableIndex(-1));
EXPECT(p->HasIndex());
EXPECT_EQ(-1, p->index().value());
ReturnNode* r = new ReturnNode(TokenPosition::kNoSource, lln);
EXPECT_EQ(lln, r->value());
LiteralNode* l =
new LiteralNode(TokenPosition::kNoSource, Smi::ZoneHandle(Smi::New(3)));
EXPECT(l->literal().IsSmi());
EXPECT_EQ(Smi::New(3), l->literal().raw());
BinaryOpNode* b =
new BinaryOpNode(TokenPosition::kNoSource, Token::kADD, l, lln);
EXPECT_EQ(Token::kADD, b->kind());
EXPECT_EQ(l, b->left());
EXPECT_EQ(lln, b->right());
UnaryOpNode* u = new UnaryOpNode(TokenPosition::kNoSource, Token::kNEGATE, b);
EXPECT_EQ(Token::kNEGATE, u->kind());
EXPECT_EQ(b, u->operand());
SequenceNode* sequence_node =
new SequenceNode(TokenPosition(1), new LocalScope(NULL, 0, 0));
LiteralNode* literal_node =
new LiteralNode(TokenPosition(2), Smi::ZoneHandle(Smi::New(3)));
ReturnNode* return_node = new ReturnNode(TokenPosition(3), literal_node);
sequence_node->Add(return_node);
GrowableArray<AstNode*> nodes;
sequence_node->CollectAllNodes(&nodes);
EXPECT_EQ(3, nodes.length());
}
} // namespace dart

View file

@ -1,505 +0,0 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/ast_transformer.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/thread.h"
namespace dart {
// Quick access to the current thread.
#define T (thread())
// Quick access to the current zone.
#define Z (thread()->zone())
// Quick synthetic token position.
#define ST(token_pos) ((token_pos).ToSynthetic())
// Nodes that are unreachable from already parsed expressions.
#define FOR_EACH_UNREACHABLE_NODE(V) \
V(AwaitMarker) \
V(Case) \
V(CatchClause) \
V(CloneContext) \
V(ClosureCall) \
V(DoWhile) \
V(If) \
V(InitStaticField) \
V(InlinedFinally) \
V(For) \
V(Jump) \
V(Stop) \
V(LoadInstanceField) \
V(NativeBody) \
V(Primary) \
V(Return) \
V(Sequence) \
V(StoreInstanceField) \
V(Switch) \
V(TryCatch) \
V(While)
#define DEFINE_UNREACHABLE(BaseName) \
void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \
UNREACHABLE(); \
}
FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE)
#undef DEFINE_UNREACHABLE
AwaitTransformer::AwaitTransformer(SequenceNode* preamble,
LocalScope* async_temp_scope)
: preamble_(preamble),
temp_cnt_(0),
async_temp_scope_(async_temp_scope),
thread_(Thread::Current()) {
ASSERT(async_temp_scope_ != NULL);
}
AstNode* AwaitTransformer::Transform(AstNode* expr) {
expr->Visit(this);
return result_;
}
LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
String& symbol =
String::ZoneHandle(Z, Symbols::NewFormatted(T, "%d", temp_cnt_));
symbol = Symbols::FromConcat(T, Symbols::AwaitTempVarPrefix(), symbol);
ASSERT(!symbol.IsNull());
// Look up the variable in the scope used for async temp variables.
LocalVariable* await_tmp = async_temp_scope_->LocalLookupVariable(symbol);
if (await_tmp == NULL) {
// We need a new temp variable; add it to the function's top scope.
await_tmp = new (Z)
LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
symbol, Object::dynamic_type());
async_temp_scope_->AddVariable(await_tmp);
// After adding it to the top scope, we can look it up from the preamble.
// The following call includes an ASSERT check.
await_tmp = GetVariableInScope(preamble_->scope(), symbol);
}
return await_tmp;
}
LocalVariable* AwaitTransformer::GetVariableInScope(LocalScope* scope,
const String& symbol) {
LocalVariable* var = scope->LookupVariable(symbol, false);
ASSERT(var != NULL);
return var;
}
LocalVariable* AwaitTransformer::AddNewTempVarToPreamble(
AstNode* node,
TokenPosition token_pos) {
LocalVariable* tmp_var = EnsureCurrentTempVar();
ASSERT(token_pos.IsSynthetic() || token_pos.IsNoSource());
preamble_->Add(new (Z) StoreLocalNode(token_pos, tmp_var, node));
NextTempVar();
return tmp_var;
}
LoadLocalNode* AwaitTransformer::MakeName(AstNode* node) {
LocalVariable* temp = AddNewTempVarToPreamble(node, ST(node->token_pos()));
return new (Z) LoadLocalNode(ST(node->token_pos()), temp);
}
void AwaitTransformer::VisitLiteralNode(LiteralNode* node) {
result_ = node;
}
void AwaitTransformer::VisitTypeNode(TypeNode* node) {
if (node->is_deferred_reference()) {
// Deferred references must use a temporary even after loading
// happened, so that the number of await temps is the same as
// before the loading.
result_ = MakeName(node);
} else {
result_ = node;
}
}
void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
// Await transformation:
//
// :await_temp_var_X = <expr>;
// AwaitMarker(kNewContinuationState);
// :result_param = _awaitHelper(
// :await_temp_var_X,
// :async_then_callback,
// :async_catch_error_callback,
// :async_op);
// return; // (return_type() == kContinuationTarget)
//
// :saved_try_ctx_var = :await_saved_try_ctx_var_y;
// :await_temp_var_(X+1) = :result_param;
const TokenPosition token_pos = ST(node->token_pos());
LocalVariable* async_op =
GetVariableInScope(preamble_->scope(), Symbols::AsyncOperation());
LocalVariable* async_then_callback =
GetVariableInScope(preamble_->scope(), Symbols::AsyncThenCallback());
LocalVariable* async_catch_error_callback = GetVariableInScope(
preamble_->scope(), Symbols::AsyncCatchErrorCallback());
LocalVariable* result_param =
GetVariableInScope(preamble_->scope(), Symbols::AsyncOperationParam());
LocalVariable* error_param = GetVariableInScope(
preamble_->scope(), Symbols::AsyncOperationErrorParam());
LocalVariable* stack_trace_param = GetVariableInScope(
preamble_->scope(), Symbols::AsyncOperationStackTraceParam());
AstNode* transformed_expr = Transform(node->expr());
LocalVariable* await_temp =
AddNewTempVarToPreamble(transformed_expr, ST(node->token_pos()));
AwaitMarkerNode* await_marker =
new (Z) AwaitMarkerNode(async_temp_scope_, node->scope(), token_pos);
preamble_->Add(await_marker);
// :result_param = _awaitHelper(
// :await_temp,
// :async_then_callback,
// :async_catch_error_callback,
// :async_op)
const Library& async_lib = Library::Handle(Library::AsyncLibrary());
const Function& async_await_helper = Function::ZoneHandle(
Z, async_lib.LookupFunctionAllowPrivate(Symbols::AsyncAwaitHelper()));
ASSERT(!async_await_helper.IsNull());
ArgumentListNode* async_await_helper_args =
new (Z) ArgumentListNode(token_pos);
async_await_helper_args->Add(new (Z) LoadLocalNode(token_pos, await_temp));
async_await_helper_args->Add(
new (Z) LoadLocalNode(token_pos, async_then_callback));
async_await_helper_args->Add(
new (Z) LoadLocalNode(token_pos, async_catch_error_callback));
async_await_helper_args->Add(new (Z) LoadLocalNode(token_pos, async_op));
StaticCallNode* await_helper_call =
new (Z) StaticCallNode(node->token_pos(), async_await_helper,
async_await_helper_args, StaticCallNode::kStatic);
preamble_->Add(
new (Z) StoreLocalNode(token_pos, result_param, await_helper_call));
ReturnNode* continuation_return = new (Z) ReturnNode(token_pos);
continuation_return->set_return_type(ReturnNode::kContinuationTarget);
preamble_->Add(continuation_return);
// If this expression is part of a try block, also append the code for
// restoring the saved try context that lives on the stack and possibly the
// saved try context of the outer try block.
if (node->saved_try_ctx() != NULL) {
preamble_->Add(new (Z) StoreLocalNode(
token_pos, node->saved_try_ctx(),
new (Z) LoadLocalNode(token_pos, node->async_saved_try_ctx())));
if (node->outer_saved_try_ctx() != NULL) {
preamble_->Add(new (Z) StoreLocalNode(
token_pos, node->outer_saved_try_ctx(),
new (Z) LoadLocalNode(token_pos, node->outer_async_saved_try_ctx())));
}
} else {
ASSERT(node->outer_saved_try_ctx() == NULL);
}
// Load the async_op variable. It is unused, but the observatory uses it
// to determine if a breakpoint is inside an asynchronous function.
LoadLocalNode* load_async_op = new (Z) LoadLocalNode(token_pos, async_op);
preamble_->Add(load_async_op);
LoadLocalNode* load_error_param =
new (Z) LoadLocalNode(token_pos, error_param);
LoadLocalNode* load_stack_trace_param =
new (Z) LoadLocalNode(token_pos, stack_trace_param);
SequenceNode* error_ne_null_branch =
new (Z) SequenceNode(token_pos, ChainNewScope(preamble_->scope()));
error_ne_null_branch->Add(
new (Z) ThrowNode(token_pos, load_error_param, load_stack_trace_param));
preamble_->Add(new (Z) IfNode(
token_pos,
new (Z) ComparisonNode(
token_pos, Token::kNE, load_error_param,
new (Z) LiteralNode(token_pos, Object::null_instance())),
error_ne_null_branch, NULL));
result_ = MakeName(new (Z) LoadLocalNode(token_pos, result_param));
}
// Transforms boolean expressions into a sequence of evaluations that only
// lazily evaluate subexpressions.
//
// Example:
//
// (a || b) only evaluates b if a is false
//
// Transformation (roughly):
//
// t_1 = a;
// if (!t_1) {
// t_2 = b;
// }
// t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place
// on this level.
AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op,
AstNode* new_left,
AstNode* right) {
ASSERT(logical_op == Token::kAND || logical_op == Token::kOR);
AstNode* result = NULL;
const Token::Kind compare_logical_op =
(logical_op == Token::kAND) ? Token::kEQ : Token::kNE;
SequenceNode* eval = new (Z) SequenceNode(ST(new_left->token_pos()),
ChainNewScope(preamble_->scope()));
SequenceNode* saved_preamble = preamble_;
preamble_ = eval;
result = Transform(right);
preamble_ = saved_preamble;
IfNode* right_body = new (Z)
IfNode(ST(new_left->token_pos()),
new (Z) ComparisonNode(
ST(new_left->token_pos()), compare_logical_op, new_left,
new (Z) LiteralNode(ST(new_left->token_pos()), Bool::True())),
eval, NULL);
preamble_->Add(right_body);
return result;
}
LocalScope* AwaitTransformer::ChainNewScope(LocalScope* parent) {
return new (Z)
LocalScope(parent, parent->function_level(), parent->loop_level());
}
void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) {
AstNode* new_left = Transform(node->left());
AstNode* new_right = NULL;
// Preserve lazy evaluation.
if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
new_right = LazyTransform(node->kind(), new_left, node->right());
} else {
new_right = Transform(node->right());
}
result_ = MakeName(new (Z) BinaryOpNode(node->token_pos(), node->kind(),
new_left, new_right));
}
void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) {
AstNode* new_left = Transform(node->left());
AstNode* new_right = Transform(node->right());
result_ = MakeName(new (Z) ComparisonNode(node->token_pos(), node->kind(),
new_left, new_right));
}
void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
AstNode* new_operand = Transform(node->operand());
result_ = MakeName(
new (Z) UnaryOpNode(node->token_pos(), node->kind(), new_operand));
}
// ::= (<condition>) ? <true-branch> : <false-branch>
//
void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
AstNode* new_condition = Transform(node->condition());
SequenceNode* new_true = new (Z) SequenceNode(
ST(node->true_expr()->token_pos()), ChainNewScope(preamble_->scope()));
SequenceNode* saved_preamble = preamble_;
preamble_ = new_true;
AstNode* new_true_result = Transform(node->true_expr());
SequenceNode* new_false = new (Z) SequenceNode(
ST(node->false_expr()->token_pos()), ChainNewScope(preamble_->scope()));
preamble_ = new_false;
AstNode* new_false_result = Transform(node->false_expr());
preamble_ = saved_preamble;
IfNode* new_if =
new (Z) IfNode(ST(node->token_pos()), new_condition, new_true, new_false);
preamble_->Add(new_if);
result_ = MakeName(new (Z) ConditionalExprNode(
ST(node->token_pos()), new_condition, new_true_result, new_false_result));
}
void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) {
ArgumentListNode* new_args =
new (Z) ArgumentListNode(node->token_pos(), node->type_arguments());
for (intptr_t i = 0; i < node->length(); i++) {
new_args->Add(Transform(node->NodeAt(i)));
}
new_args->set_names(node->names());
result_ = new_args;
}
void AwaitTransformer::VisitArrayNode(ArrayNode* node) {
GrowableArray<AstNode*> new_elements;
for (intptr_t i = 0; i < node->length(); i++) {
new_elements.Add(Transform(node->ElementAt(i)));
}
result_ = new (Z) ArrayNode(node->token_pos(), node->type(), new_elements);
}
void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) {
ArrayNode* new_value = Transform(node->value())->AsArrayNode();
result_ =
MakeName(new (Z) StringInterpolateNode(node->token_pos(), new_value));
}
void AwaitTransformer::VisitClosureNode(ClosureNode* node) {
AstNode* new_receiver = node->receiver();
if (new_receiver != NULL) {
new_receiver = Transform(new_receiver);
}
result_ = MakeName(new (Z) ClosureNode(node->token_pos(), node->function(),
new_receiver, node->scope()));
}
void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) {
AstNode* new_receiver = Transform(node->receiver());
ArgumentListNode* new_args =
Transform(node->arguments())->AsArgumentListNode();
result_ = MakeName(new (Z) InstanceCallNode(node->token_pos(), new_receiver,
node->function_name(), new_args,
node->is_conditional()));
}
void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) {
ArgumentListNode* new_args =
Transform(node->arguments())->AsArgumentListNode();
result_ = MakeName(new (Z) StaticCallNode(node->token_pos(), node->function(),
new_args, node->rebind_rule()));
}
void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) {
ArgumentListNode* new_args =
Transform(node->arguments())->AsArgumentListNode();
result_ = MakeName(
new (Z) ConstructorCallNode(node->token_pos(), node->type_arguments(),
node->constructor(), new_args));
}
void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) {
AstNode* new_receiver = Transform(node->receiver());
result_ = MakeName(new (Z) InstanceGetterNode(node->token_pos(), new_receiver,
node->field_name(),
node->is_conditional()));
}
void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) {
AstNode* new_receiver = node->receiver();
if (new_receiver != NULL) {
new_receiver = Transform(new_receiver);
}
AstNode* new_value = Transform(node->value());
result_ = MakeName(new (Z) InstanceSetterNode(node->token_pos(), new_receiver,
node->field_name(), new_value,
node->is_conditional()));
}
void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) {
AstNode* new_receiver = node->receiver();
if (new_receiver != NULL) {
new_receiver = Transform(new_receiver);
}
StaticGetterNode* new_getter =
new (Z) StaticGetterNode(node->token_pos(), new_receiver, node->cls(),
node->field_name(), node->rebind_rule());
new_getter->set_owner(node->owner());
result_ = MakeName(new_getter);
}
void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) {
AstNode* new_receiver = node->receiver();
if (new_receiver != NULL) {
new_receiver = Transform(new_receiver);
}
AstNode* new_value = Transform(node->value());
StaticSetterNode* new_setter =
node->function().IsNull()
? new (Z) StaticSetterNode(node->token_pos(), new_receiver,
node->cls(), node->field_name(), new_value,
node->rebind_rule())
: new (Z) StaticSetterNode(node->token_pos(), new_receiver,
node->field_name(), node->function(),
new_value, node->rebind_rule());
result_ = MakeName(new_setter);
}
void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) {
result_ = MakeName(node);
}
void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) {
AstNode* new_value = Transform(node->value());
result_ = MakeName(
new (Z) StoreLocalNode(node->token_pos(), &node->local(), new_value));
}
void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
result_ = MakeName(node);
}
void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
AstNode* new_value = Transform(node->value());
result_ = MakeName(new (Z) StoreStaticFieldNode(
node->token_pos(), Field::ZoneHandle(Z, node->field().Original()),
new_value));
}
void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) {
AstNode* new_array = Transform(node->array());
AstNode* new_index = Transform(node->index_expr());
result_ = MakeName(new (Z) LoadIndexedNode(node->token_pos(), new_array,
new_index, node->super_class()));
}
void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) {
AstNode* new_array = Transform(node->array());
AstNode* new_index = Transform(node->index_expr());
AstNode* new_value = Transform(node->value());
result_ = MakeName(new (Z) StoreIndexedNode(
node->token_pos(), new_array, new_index, new_value, node->super_class()));
}
void AwaitTransformer::VisitAssignableNode(AssignableNode* node) {
AstNode* new_expr = Transform(node->expr());
result_ = MakeName(new (Z) AssignableNode(node->token_pos(), new_expr,
node->type(), node->dst_name()));
}
void AwaitTransformer::VisitLetNode(LetNode* node) {
// Add all the initializer nodes to the preamble and the
// temporary variables to the scope for async temporary variables.
// The temporary variables will be captured as a side effect of being
// added to a scope, and the subsequent nodes that are added to the
// preample can access them.
for (intptr_t i = 0; i < node->num_temps(); i++) {
async_temp_scope_->AddVariable(node->TempAt(i));
AstNode* new_init_val = Transform(node->InitializerAt(i));
preamble_->Add(new (Z) StoreLocalNode(node->token_pos(), node->TempAt(i),
new_init_val));
}
// Add all expressions but the last to the preamble. We must do
// this because subexpressions of the awaitable expression we
// are currently transforming may depend on each other,
// e.g. await foo(a++, a++). Thus we must preserve the order of the
// transformed subexpressions.
for (intptr_t i = 0; i < node->nodes().length() - 1; i++) {
preamble_->Add(Transform(node->nodes()[i]));
}
// The last expression in the let node is the value of the node.
// The result of the transformed let node is this expression.
ASSERT(node->nodes().length() > 0);
const intptr_t last_node_index = node->nodes().length() - 1;
result_ = Transform(node->nodes()[last_node_index]);
}
void AwaitTransformer::VisitThrowNode(ThrowNode* node) {
AstNode* new_exception = Transform(node->exception());
result_ = MakeName(
new (Z) ThrowNode(node->token_pos(), new_exception, node->stacktrace()));
}
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -1,80 +0,0 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_AST_TRANSFORMER_H_
#define RUNTIME_VM_AST_TRANSFORMER_H_
#include "platform/assert.h"
#include "vm/ast.h"
namespace dart {
class Thread;
// Translate an AstNode containing an expression (that itself contains one or
// more awaits) into a sequential representation where subexpressions are
// evaluated sequentially into intermediates. Those intermediates are stored
// within a context.
//
// This allows a function to be suspended and resumed from within evaluating an
// expression. The evaluation is split among a so-called preamble and the
// evaluation of the resulting expression (which is only a single load).
//
// Example (minimalistic):
//
// var a = (await bar()) + foo();
//
// This translates to a premable similar to:
//
// var t_1, t_2, t_3, t_4; // All stored in a context.
// t_1 = bar();
// :result_param = t_1;
// <continuation logic>
// t_2 = :result_param;
// t_3 = foo();
// t_4 = t_2.operator+(t_3);
//
// and a resulting expression of a load of t_4.
//
class AwaitTransformer : public AstNodeVisitor {
public:
AwaitTransformer(SequenceNode* preamble, LocalScope* async_temp_scope);
#define DECLARE_VISIT(BaseName) \
virtual void Visit##BaseName##Node(BaseName##Node* node);
FOR_EACH_NODE(DECLARE_VISIT)
#undef DECLARE_VISIT
AstNode* Transform(AstNode* expr);
private:
LocalVariable* EnsureCurrentTempVar();
LocalVariable* AddNewTempVarToPreamble(AstNode* node,
TokenPosition token_pos);
LoadLocalNode* MakeName(AstNode* node);
ArgumentListNode* TransformArguments(ArgumentListNode* node);
AstNode* LazyTransform(const Token::Kind kind,
AstNode* new_left,
AstNode* right);
LocalScope* ChainNewScope(LocalScope* parent);
LocalVariable* GetVariableInScope(LocalScope* scope, const String& symbol);
void NextTempVar() { temp_cnt_++; }
Thread* thread() const { return thread_; }
SequenceNode* preamble_;
int32_t temp_cnt_;
AstNode* result_;
LocalScope* async_temp_scope_;
Thread* thread_;
DISALLOW_COPY_AND_ASSIGN(AwaitTransformer);
};
} // namespace dart
#endif // RUNTIME_VM_AST_TRANSFORMER_H_

View file

@ -5,7 +5,6 @@
#ifndef RUNTIME_VM_CODE_DESCRIPTORS_H_
#define RUNTIME_VM_CODE_DESCRIPTORS_H_
#include "vm/ast.h"
#include "vm/datastream.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
@ -15,6 +14,8 @@
namespace dart {
static const intptr_t kInvalidTryIndex = -1;
class DescriptorList : public ZoneAllocated {
public:
explicit DescriptorList(intptr_t initial_capacity)
@ -118,7 +119,7 @@ class ExceptionHandlerList : public ZoneAllocated {
// Called by rethrows, to mark their enclosing handlers.
void SetNeedsStackTrace(intptr_t try_index) {
// Rethrows can be generated outside a try by the compiler.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
if (try_index == kInvalidTryIndex) {
return;
}
ASSERT(try_index >= 0);

View file

@ -5,7 +5,6 @@
#include "platform/assert.h"
#include "vm/globals.h"
#include "vm/ast.h"
#include "vm/code_descriptors.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/jit/compiler.h"
@ -18,153 +17,6 @@
namespace dart {
static const TokenPosition kPos = TokenPosition::kNoSource;
CODEGEN_TEST_GENERATE(StackMapCodegen, test) {
ParsedFunction* parsed_function =
new ParsedFunction(Thread::Current(), test->function());
LiteralNode* l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1)));
test->node_sequence()->Add(new ReturnNode(kPos, l));
l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
test->node_sequence()->Add(new ReturnNode(kPos, l));
l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
test->node_sequence()->Add(new ReturnNode(kPos, l));
parsed_function->SetNodeSequence(test->node_sequence());
parsed_function->EnsureExpressionTemp();
test->node_sequence()->scope()->AddVariable(
parsed_function->expression_temp_var());
test->node_sequence()->scope()->AddVariable(
parsed_function->current_context_var());
parsed_function->AllocateVariables();
bool retval;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
// Build a stackmap table and some stackmap table entries.
const intptr_t kStackSlotCount = 11;
StackMapTableBuilder* stackmap_table_builder = new StackMapTableBuilder();
EXPECT(stackmap_table_builder != NULL);
BitmapBuilder* stack_bitmap = new BitmapBuilder();
EXPECT(stack_bitmap != NULL);
EXPECT_EQ(0, stack_bitmap->Length());
stack_bitmap->Set(0, true);
EXPECT_EQ(1, stack_bitmap->Length());
stack_bitmap->SetLength(kStackSlotCount);
EXPECT_EQ(kStackSlotCount, stack_bitmap->Length());
bool expectation0[kStackSlotCount] = {true};
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation0[i], stack_bitmap->Get(i));
}
// Add a stack map entry at pc offset 0.
stackmap_table_builder->AddEntry(0, stack_bitmap, 0);
stack_bitmap = new BitmapBuilder();
EXPECT(stack_bitmap != NULL);
EXPECT_EQ(0, stack_bitmap->Length());
stack_bitmap->Set(0, true);
stack_bitmap->Set(1, false);
stack_bitmap->Set(2, true);
EXPECT_EQ(3, stack_bitmap->Length());
stack_bitmap->SetLength(kStackSlotCount);
EXPECT_EQ(kStackSlotCount, stack_bitmap->Length());
bool expectation1[kStackSlotCount] = {true, false, true};
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation1[i], stack_bitmap->Get(i));
}
// Add a stack map entry at pc offset 1.
stackmap_table_builder->AddEntry(1, stack_bitmap, 0);
stack_bitmap = new BitmapBuilder();
EXPECT(stack_bitmap != NULL);
EXPECT_EQ(0, stack_bitmap->Length());
stack_bitmap->Set(0, true);
stack_bitmap->Set(1, false);
stack_bitmap->Set(2, true);
stack_bitmap->SetRange(3, 5, true);
EXPECT_EQ(6, stack_bitmap->Length());
stack_bitmap->SetLength(kStackSlotCount);
EXPECT_EQ(kStackSlotCount, stack_bitmap->Length());
bool expectation2[kStackSlotCount] = {true, false, true, true, true, true};
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation2[i], stack_bitmap->Get(i));
}
// Add a stack map entry at pc offset 2.
stackmap_table_builder->AddEntry(2, stack_bitmap, 0);
stack_bitmap = new BitmapBuilder();
EXPECT(stack_bitmap != NULL);
EXPECT_EQ(0, stack_bitmap->Length());
stack_bitmap->Set(0, true);
stack_bitmap->Set(1, false);
stack_bitmap->Set(2, true);
stack_bitmap->SetRange(3, 5, true);
stack_bitmap->SetRange(6, 9, false);
stack_bitmap->Set(10, true);
EXPECT_EQ(11, stack_bitmap->Length());
stack_bitmap->SetLength(kStackSlotCount);
EXPECT_EQ(kStackSlotCount, stack_bitmap->Length());
bool expectation3[kStackSlotCount] = {
true, false, true, true, true, true, false, false, false, false, true};
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation3[i], stack_bitmap->Get(i));
}
// Add a stack map entry at pc offset 3.
stackmap_table_builder->AddEntry(3, stack_bitmap, 0);
const Error& error =
Error::Handle(Compiler::CompileParsedFunction(parsed_function));
EXPECT(error.IsNull());
const Code& code = Code::Handle(test->function().CurrentCode());
const Array& stack_maps =
Array::Handle(stackmap_table_builder->FinalizeStackMaps(code));
code.set_stackmaps(stack_maps);
const Array& stack_map_list = Array::Handle(code.stackmaps());
EXPECT(!stack_map_list.IsNull());
StackMap& stack_map = StackMap::Handle();
EXPECT_EQ(4, stack_map_list.Length());
// Validate the first stack map entry.
stack_map ^= stack_map_list.At(0);
EXPECT_EQ(kStackSlotCount, stack_map.Length());
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation0[i], stack_map.IsObject(i));
}
// Validate the second stack map entry.
stack_map ^= stack_map_list.At(1);
EXPECT_EQ(kStackSlotCount, stack_map.Length());
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation1[i], stack_map.IsObject(i));
}
// Validate the third stack map entry.
stack_map ^= stack_map_list.At(2);
EXPECT_EQ(kStackSlotCount, stack_map.Length());
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation2[i], stack_map.IsObject(i));
}
// Validate the fourth stack map entry.
stack_map ^= stack_map_list.At(3);
EXPECT_EQ(kStackSlotCount, stack_map.Length());
for (intptr_t i = 0; i < kStackSlotCount; ++i) {
EXPECT_EQ(expectation3[i], stack_map.IsObject(i));
}
retval = true;
} else {
retval = false;
}
EXPECT(retval);
}
CODEGEN_TEST_RUN(StackMapCodegen, Smi::New(1))
static void NativeFunc(Dart_NativeArguments args) {
Dart_Handle i = Dart_GetNativeArgument(args, 0);
Dart_Handle k = Dart_GetNativeArgument(args, 1);

View file

@ -4,7 +4,6 @@
#include "vm/compiler/aot/precompiler.h"
#include "vm/ast_printer.h"
#include "vm/class_finalizer.h"
#include "vm/code_patcher.h"
#include "vm/compiler/aot/aot_call_specializer.h"
@ -796,14 +795,8 @@ RawFunction* Precompiler::CompileStaticInitializer(const Field& field) {
Zone* zone = stack_zone.GetZone();
ASSERT(Error::Handle(zone, thread->sticky_error()).IsNull());
ParsedFunction* parsed_function;
// Check if this field is coming from the Kernel binary.
if (field.kernel_offset() > 0) {
parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
} else {
parsed_function = Parser::ParseStaticFieldInitializer(field);
parsed_function->AllocateVariables();
}
ParsedFunction* parsed_function =
kernel::ParseStaticFieldInitializer(zone, field);
DartCompilationPipeline pipeline;
PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
@ -861,11 +854,6 @@ RawObject* Precompiler::ExecuteOnce(SequenceNode* fragment) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
Thread* const thread = Thread::Current();
if (FLAG_support_ast_printer && FLAG_trace_compiler) {
THR_Print("compiling expression: ");
AstPrinter ast_printer;
ast_printer.PrintNode(fragment);
}
// Create a dummy function object for the code generator.
// The function needs to be associated with a named Class: the interface

View file

@ -8,6 +8,7 @@
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/compiler_state.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -414,11 +414,8 @@ void FlowGraphCompiler::RecordCatchEntryMoves(Environment* env,
intptr_t try_index) {
#if defined(DART_PRECOMPILER)
env = env ? env : pending_deoptimization_env_;
try_index = try_index != CatchClauseNode::kInvalidTryIndex
? try_index
: CurrentTryIndex();
if (is_optimizing() && env != nullptr &&
(try_index != CatchClauseNode::kInvalidTryIndex)) {
try_index = try_index != kInvalidTryIndex ? try_index : CurrentTryIndex();
if (is_optimizing() && env != nullptr && (try_index != kInvalidTryIndex)) {
env = env->Outermost();
CatchBlockEntryInstr* catch_block =
flow_graph().graph_entry()->GetCatchEntry(try_index);
@ -1261,7 +1258,7 @@ void FlowGraphCompiler::GenerateInstanceCall(intptr_t deopt_id,
const Array& arguments_descriptor =
Array::Handle(ic_data_in.arguments_descriptor());
EmitMegamorphicInstanceCall(name, arguments_descriptor, deopt_id, token_pos,
locs, CatchClauseNode::kInvalidTryIndex);
locs, kInvalidTryIndex);
return;
}
@ -2009,7 +2006,7 @@ void FlowGraphCompiler::EmitTestAndCall(const CallTargets& targets,
__ Bind(&next_test);
}
if (add_megamorphic_call) {
int try_index = CatchClauseNode::kInvalidTryIndex;
int try_index = kInvalidTryIndex;
EmitMegamorphicInstanceCall(function_name, arguments_descriptor, deopt_id,
token_index, locs, try_index);
}
@ -2268,8 +2265,8 @@ void ThrowErrorSlowPathCode::EmitNativeCode(FlowGraphCompiler* compiler) {
instruction()->token_pos(), try_index_);
AddMetadataForRuntimeCall(compiler);
compiler->RecordSafepoint(locs, num_args_);
if ((try_index_ != CatchClauseNode::kInvalidTryIndex) ||
(compiler->CurrentTryIndex() != CatchClauseNode::kInvalidTryIndex)) {
if ((try_index_ != kInvalidTryIndex) ||
(compiler->CurrentTryIndex() != kInvalidTryIndex)) {
Environment* env =
compiler->SlowPathEnvironmentFor(instruction(), num_args_);
compiler->RecordCatchEntryMoves(env, try_index_);

View file

@ -593,9 +593,8 @@ class FlowGraphCompiler : public ValueObject {
void EmitEdgeCounter(intptr_t edge_id);
#endif // !defined(TARGET_ARCH_DBC)
void RecordCatchEntryMoves(
Environment* env = NULL,
intptr_t try_index = CatchClauseNode::kInvalidTryIndex);
void RecordCatchEntryMoves(Environment* env = NULL,
intptr_t try_index = kInvalidTryIndex);
void EmitCallsiteMetadata(TokenPosition token_pos,
intptr_t deopt_id,
@ -689,7 +688,7 @@ class FlowGraphCompiler : public ValueObject {
intptr_t CurrentTryIndex() const {
if (current_block_ == NULL) {
return CatchClauseNode::kInvalidTryIndex;
return kInvalidTryIndex;
}
return current_block_->try_index();
}

View file

@ -7,7 +7,6 @@
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/ast_printer.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/jit/compiler.h"
@ -1052,7 +1051,7 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
if (try_index == kInvalidTryIndex) {
try_index = CurrentTryIndex();
}
AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),

View file

@ -7,7 +7,6 @@
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/ast_printer.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/jit/compiler.h"
@ -1025,7 +1024,7 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
if (try_index == kInvalidTryIndex) {
try_index = CurrentTryIndex();
}
AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),

View file

@ -7,7 +7,6 @@
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/ast_printer.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/jit/compiler.h"

View file

@ -7,7 +7,6 @@
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/ast_printer.h"
#include "vm/code_patcher.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/locations.h"

View file

@ -7,7 +7,6 @@
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/ast_printer.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/jit/compiler.h"
@ -1045,7 +1044,7 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
if (try_index == kInvalidTryIndex) {
try_index = CurrentTryIndex();
}
AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),

View file

@ -1021,8 +1021,7 @@ UnboxedConstantInstr::UnboxedConstantInstr(const Object& value,
constant_address_(0) {
if (representation_ == kUnboxedDouble) {
ASSERT(value.IsDouble());
constant_address_ =
FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value());
constant_address_ = FindDoubleConstant(Double::Cast(value).value());
}
}
@ -1048,7 +1047,7 @@ GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
TargetEntryInstr* normal_entry,
intptr_t osr_id)
: BlockEntryInstr(0,
CatchClauseNode::kInvalidTryIndex,
kInvalidTryIndex,
CompilerState::Current().GetNextDeoptId()),
parsed_function_(parsed_function),
normal_entry_(normal_entry),

View file

@ -6,12 +6,13 @@
#define RUNTIME_VM_COMPILER_BACKEND_IL_H_
#include "vm/allocation.h"
#include "vm/ast.h"
#include "vm/code_descriptors.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/compiler_state.h"
#include "vm/compiler/method_recognizer.h"
#include "vm/flags.h"
#include "vm/growable_array.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/parser.h"
#include "vm/token_position.h"
@ -1346,9 +1347,7 @@ class BlockEntryInstr : public Instruction {
void set_try_index(intptr_t index) { try_index_ = index; }
// True for blocks inside a try { } region.
bool InsideTryBlock() const {
return try_index_ != CatchClauseNode::kInvalidTryIndex;
}
bool InsideTryBlock() const { return try_index_ != kInvalidTryIndex; }
BitVector* loop_info() const { return loop_info_; }
void set_loop_info(BitVector* loop_info) { loop_info_ = loop_info; }
@ -2409,7 +2408,7 @@ class ThrowInstr : public TemplateInstruction<0, Throws> {
class ReThrowInstr : public TemplateInstruction<0, Throws> {
public:
// 'catch_try_index' can be CatchClauseNode::kInvalidTryIndex if the
// 'catch_try_index' can be kInvalidTryIndex if the
// rethrow has been artificially generated by the parser.
ReThrowInstr(TokenPosition token_pos,
intptr_t catch_try_index,
@ -3197,22 +3196,6 @@ class TemplateDartCall : public TemplateDefinition<kInputCount, Throws> {
class ClosureCallInstr : public TemplateDartCall<1> {
public:
ClosureCallInstr(Value* function,
ClosureCallNode* node,
PushArgumentsArray* arguments,
intptr_t deopt_id,
Code::EntryKind entry_kind = Code::EntryKind::kNormal)
: TemplateDartCall(deopt_id,
node->arguments()->type_args_len(),
node->arguments()->names(),
arguments,
node->token_pos()),
entry_kind_(entry_kind) {
ASSERT(entry_kind != Code::EntryKind::kMonomorphic);
ASSERT(!arguments->is_empty());
SetInputAt(0, function);
}
ClosureCallInstr(Value* function,
PushArgumentsArray* arguments,
intptr_t type_args_len,

View file

@ -197,7 +197,7 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
}
} else if (destination.IsFpuRegister()) {
const double value_as_double = Double::Cast(value_).value();
uword addr = FlowGraphBuilder::FindDoubleConstant(value_as_double);
uword addr = FindDoubleConstant(value_as_double);
if (addr == 0) {
__ pushl(EAX);
__ LoadObject(EAX, value_);
@ -211,7 +211,7 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
}
} else if (destination.IsDoubleStackSlot()) {
const double value_as_double = Double::Cast(value_).value();
uword addr = FlowGraphBuilder::FindDoubleConstant(value_as_double);
uword addr = FindDoubleConstant(value_as_double);
if (addr == 0) {
__ pushl(EAX);
__ LoadObject(EAX, value_);

View file

@ -863,7 +863,7 @@ void GraphEntryInstr::PrintTo(BufferFormatter* f) const {
}
void JoinEntryInstr::PrintTo(BufferFormatter* f) const {
if (try_index() != CatchClauseNode::kInvalidTryIndex) {
if (try_index() != kInvalidTryIndex) {
f->Print("B%" Pd "[join try_idx %" Pd "]:%" Pd " pred(", block_id(),
try_index(), GetDeoptId());
} else {
@ -890,7 +890,7 @@ void JoinEntryInstr::PrintTo(BufferFormatter* f) const {
}
void IndirectEntryInstr::PrintTo(BufferFormatter* f) const {
ASSERT(try_index() == CatchClauseNode::kInvalidTryIndex);
ASSERT(try_index() == kInvalidTryIndex);
f->Print("B%" Pd "[join indirect]:%" Pd " pred(", block_id(), GetDeoptId());
for (intptr_t i = 0; i < predecessors_.length(); ++i) {
if (i > 0) f->Print(", ");
@ -1007,7 +1007,7 @@ void CheckStackOverflowInstr::PrintOperandsTo(BufferFormatter* f) const {
}
void TargetEntryInstr::PrintTo(BufferFormatter* f) const {
if (try_index() != CatchClauseNode::kInvalidTryIndex) {
if (try_index() != kInvalidTryIndex) {
f->Print("B%" Pd "[target try_idx %" Pd "]:%" Pd, block_id(), try_index(),
GetDeoptId());
} else {

View file

@ -8,8 +8,8 @@
namespace dart {
TEST_CASE(InstructionTests) {
TargetEntryInstr* target_instr = new TargetEntryInstr(
1, CatchClauseNode::kInvalidTryIndex, DeoptId::kNone);
TargetEntryInstr* target_instr =
new TargetEntryInstr(1, kInvalidTryIndex, DeoptId::kNone);
EXPECT(target_instr->IsBlockEntry());
EXPECT(!target_instr->IsDefinition());
SpecialParameterInstr* context = new SpecialParameterInstr(
@ -21,7 +21,7 @@ TEST_CASE(InstructionTests) {
TEST_CASE(OptimizationTests) {
JoinEntryInstr* join =
new JoinEntryInstr(1, CatchClauseNode::kInvalidTryIndex, DeoptId::kNone);
new JoinEntryInstr(1, kInvalidTryIndex, DeoptId::kNone);
Definition* def1 = new PhiInstr(join, 0);
Definition* def2 = new PhiInstr(join, 0);

View file

@ -1,348 +0,0 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#include "platform/assert.h"
#include "vm/ast.h"
#include "vm/class_finalizer.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_entry.h"
#include "vm/globals.h"
#include "vm/native_entry.h"
#include "vm/native_entry_test.h"
#include "vm/runtime_entry.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
#include "vm/virtual_memory.h"
namespace dart {
static const TokenPosition kPos = TokenPosition::kMinSource;
CODEGEN_TEST_GENERATE(SimpleReturnCodegen, test) {
test->node_sequence()->Add(new ReturnNode(kPos));
}
CODEGEN_TEST_RUN(SimpleReturnCodegen, Instance::null())
CODEGEN_TEST_GENERATE(SmiReturnCodegen, test) {
LiteralNode* l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
test->node_sequence()->Add(new ReturnNode(kPos, l));
}
CODEGEN_TEST_RUN(SmiReturnCodegen, Smi::New(3))
CODEGEN_TEST2_GENERATE(SimpleStaticCallCodegen, function, test) {
// Wrap the SmiReturnCodegen test above as a static function and call it.
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
test->node_sequence()->Add(
new ReturnNode(kPos, new StaticCallNode(kPos, function, no_arguments,
StaticCallNode::kStatic)));
}
CODEGEN_TEST2_RUN(SimpleStaticCallCodegen, SmiReturnCodegen, Smi::New(3))
// Helper to allocate and return a LocalVariable.
static LocalVariable* NewTestLocalVariable(const char* name) {
const String& variable_name =
String::ZoneHandle(Symbols::New(Thread::Current(), name));
const Type& variable_type = Type::ZoneHandle(Type::DynamicType());
return new LocalVariable(kPos, kPos, variable_name, variable_type);
}
CODEGEN_TEST_GENERATE(ReturnParameterCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
const int num_params = 1;
LocalVariable* parameter = NewTestLocalVariable("parameter");
LocalScope* local_scope = node_seq->scope();
local_scope->InsertParameterAt(0, parameter);
ASSERT(local_scope->num_variables() == num_params);
const Function& function = test->function();
function.set_num_fixed_parameters(num_params);
ASSERT(!function.HasOptionalParameters());
node_seq->Add(new ReturnNode(kPos, new LoadLocalNode(kPos, parameter)));
}
CODEGEN_TEST2_GENERATE(StaticCallReturnParameterCodegen, function, test) {
// Wrap and call the ReturnParameterCodegen test above as a static function.
SequenceNode* node_seq = test->node_sequence();
ArgumentListNode* arguments = new ArgumentListNode(kPos);
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
node_seq->Add(new ReturnNode(
kPos,
new StaticCallNode(kPos, function, arguments, StaticCallNode::kStatic)));
}
CODEGEN_TEST2_RUN(StaticCallReturnParameterCodegen,
ReturnParameterCodegen,
Smi::New(3))
CODEGEN_TEST_GENERATE(SmiParamSumCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
const int num_params = 2;
LocalVariable* param1 = NewTestLocalVariable("param1");
LocalVariable* param2 = NewTestLocalVariable("param2");
const int num_locals = 1;
LocalVariable* sum = NewTestLocalVariable("sum");
LocalScope* local_scope = node_seq->scope();
local_scope->InsertParameterAt(0, param1);
local_scope->InsertParameterAt(1, param2);
local_scope->AddVariable(sum);
ASSERT(local_scope->num_variables() == num_params + num_locals);
const Function& function = test->function();
function.set_num_fixed_parameters(num_params);
ASSERT(!function.HasOptionalParameters());
BinaryOpNode* add =
new BinaryOpNode(kPos, Token::kADD, new LoadLocalNode(kPos, param1),
new LoadLocalNode(kPos, param2));
node_seq->Add(new StoreLocalNode(kPos, sum, add));
node_seq->Add(new ReturnNode(kPos, new LoadLocalNode(kPos, sum)));
}
CODEGEN_TEST2_GENERATE(StaticCallSmiParamSumCodegen, function, test) {
// Wrap and call the SmiParamSumCodegen test above as a static function.
SequenceNode* node_seq = test->node_sequence();
ArgumentListNode* arguments = new ArgumentListNode(kPos);
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2))));
node_seq->Add(new ReturnNode(
kPos,
new StaticCallNode(kPos, function, arguments, StaticCallNode::kStatic)));
}
CODEGEN_TEST2_RUN(StaticCallSmiParamSumCodegen, SmiParamSumCodegen, Smi::New(5))
CODEGEN_TEST_GENERATE(SmiAddCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
BinaryOpNode* add_node = new BinaryOpNode(kPos, Token::kADD, a, b);
node_seq->Add(new ReturnNode(kPos, add_node));
}
CODEGEN_TEST_RUN(SmiAddCodegen, Smi::New(5))
CODEGEN_TEST_GENERATE(GenericAddCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(12.2, Heap::kOld)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
BinaryOpNode* add_node_1 = new BinaryOpNode(kPos, Token::kADD, a, b);
LiteralNode* c =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(0.8, Heap::kOld)));
BinaryOpNode* add_node_2 = new BinaryOpNode(kPos, Token::kADD, add_node_1, c);
node_seq->Add(new ReturnNode(kPos, add_node_2));
}
CODEGEN_TEST_RUN(GenericAddCodegen, Double::New(15.0))
CODEGEN_TEST_GENERATE(SmiBinaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(4)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
LiteralNode* c = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
BinaryOpNode* sub_node =
new BinaryOpNode(kPos, Token::kSUB, a, b); // 4 - 2 -> 2.
BinaryOpNode* mul_node =
new BinaryOpNode(kPos, Token::kMUL, sub_node, c); // 2 * 3 -> 6.
BinaryOpNode* div_node =
new BinaryOpNode(kPos, Token::kTRUNCDIV, mul_node, b); // 6 ~/ 2 -> 3.
node_seq->Add(new ReturnNode(kPos, div_node));
}
CODEGEN_TEST_RUN(SmiBinaryOpCodegen, Smi::New(3))
CODEGEN_TEST_GENERATE(BoolNotCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* b = new LiteralNode(kPos, Bool::False());
UnaryOpNode* not_node = new UnaryOpNode(kPos, Token::kNOT, b);
node_seq->Add(new ReturnNode(kPos, not_node));
}
CODEGEN_TEST_RUN(BoolNotCodegen, Bool::True().raw())
CODEGEN_TEST_GENERATE(BoolAndCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Bool::True());
LiteralNode* b = new LiteralNode(kPos, Bool::False());
BinaryOpNode* and_node = new BinaryOpNode(kPos, Token::kAND, a, b);
node_seq->Add(new ReturnNode(kPos, and_node));
}
CODEGEN_TEST_RUN(BoolAndCodegen, Bool::False().raw())
CODEGEN_TEST_GENERATE(BinaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(12, Heap::kOld)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
LiteralNode* c =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(0.5, Heap::kOld)));
BinaryOpNode* sub_node = new BinaryOpNode(kPos, Token::kSUB, a, b);
BinaryOpNode* mul_node = new BinaryOpNode(kPos, Token::kMUL, sub_node, c);
BinaryOpNode* div_node = new BinaryOpNode(kPos, Token::kDIV, mul_node, b);
node_seq->Add(new ReturnNode(kPos, div_node));
}
CODEGEN_TEST_RUN(BinaryOpCodegen, Double::New(2.5));
CODEGEN_TEST_GENERATE(SmiUnaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(12)));
UnaryOpNode* neg_node = new UnaryOpNode(kPos, Token::kNEGATE, a);
node_seq->Add(new ReturnNode(kPos, neg_node));
}
CODEGEN_TEST_RUN(SmiUnaryOpCodegen, Smi::New(-12))
CODEGEN_TEST_GENERATE(DoubleUnaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(12.0, Heap::kOld)));
UnaryOpNode* neg_node = new UnaryOpNode(kPos, Token::kNEGATE, a);
node_seq->Add(new ReturnNode(kPos, neg_node));
}
CODEGEN_TEST_RUN(DoubleUnaryOpCodegen, Double::New(-12.0))
static Library& MakeTestLibrary(const char* url) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const String& lib_url = String::ZoneHandle(zone, Symbols::New(thread, url));
Library& lib = Library::ZoneHandle(zone, Library::New(lib_url));
lib.Register(thread);
Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
const Namespace& core_ns = Namespace::Handle(
zone, Namespace::New(core_lib, Array::Handle(zone), Array::Handle(zone)));
lib.AddImport(core_ns);
return lib;
}
static RawClass* LookupClass(const Library& lib, const char* name) {
const String& cls_name =
String::ZoneHandle(Symbols::New(Thread::Current(), name));
return lib.LookupClass(cls_name);
}
CODEGEN_TEST_GENERATE(StaticCallCodegen, test) {
const char* kScriptChars =
"class A {\n"
" static bar() { return 42; }\n"
" static fly() { return 5; }\n"
"}\n";
String& url = String::Handle(String::New("dart-test:CompileScript"));
String& source = String::Handle(String::New(kScriptChars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::ProcessPendingClasses());
Class& cls = Class::Handle(LookupClass(lib, "A"));
EXPECT(!cls.IsNull());
// 'bar' will not be compiled.
String& function_bar_name = String::Handle(String::New("bar"));
Function& function_bar =
Function::ZoneHandle(cls.LookupStaticFunction(function_bar_name));
EXPECT(!function_bar.IsNull());
EXPECT(!function_bar.HasCode());
// 'fly' will be compiled.
String& function_fly_name = String::Handle(String::New("fly"));
Function& function_fly =
Function::ZoneHandle(cls.LookupStaticFunction(function_fly_name));
EXPECT(!function_fly.IsNull());
EXPECT(CompilerTest::TestCompileFunction(function_fly));
EXPECT(function_fly.HasCode());
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
StaticCallNode* call_bar = new StaticCallNode(
kPos, function_bar, no_arguments, StaticCallNode::kStatic);
StaticCallNode* call_fly = new StaticCallNode(
kPos, function_fly, no_arguments, StaticCallNode::kStatic);
BinaryOpNode* add_node =
new BinaryOpNode(kPos, Token::kADD, call_bar, call_fly);
test->node_sequence()->Add(new ReturnNode(kPos, add_node));
}
CODEGEN_TEST_RUN(StaticCallCodegen, Smi::New(42 + 5))
CODEGEN_TEST_GENERATE(InstanceCallCodegen, test) {
const char* kScriptChars =
"class A {\n"
" A() {}\n"
" int bar() { return 42; }\n"
"}\n";
String& url = String::Handle(String::New("dart-test:CompileScript"));
String& source = String::Handle(String::New(kScriptChars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::ProcessPendingClasses());
Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
EXPECT(!cls.IsNull());
String& constructor_name = String::Handle(String::New("A."));
Function& constructor =
Function::ZoneHandle(cls.LookupConstructor(constructor_name));
EXPECT(!constructor.IsNull());
// The unit test creates an instance of class A and calls function 'bar'.
String& function_bar_name =
String::ZoneHandle(Symbols::New(Thread::Current(), "bar"));
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
const TypeArguments& no_type_arguments = TypeArguments::ZoneHandle();
InstanceCallNode* call_bar =
new InstanceCallNode(kPos,
new ConstructorCallNode(kPos, no_type_arguments,
constructor, no_arguments),
function_bar_name, no_arguments);
test->node_sequence()->Add(new ReturnNode(kPos, call_bar));
}
CODEGEN_TEST_RUN(InstanceCallCodegen, Smi::New(42))
// Test allocation of dart objects.
CODEGEN_TEST_GENERATE(AllocateNewObjectCodegen, test) {
const char* kScriptChars =
"class A {\n"
" A() {}\n"
" static bar() { return 42; }\n"
"}\n";
String& url = String::Handle(String::New("dart-test:CompileScript"));
String& source = String::Handle(String::New(kScriptChars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::ProcessPendingClasses());
Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
EXPECT(!cls.IsNull());
String& constructor_name = String::Handle(String::New("A."));
Function& constructor =
Function::ZoneHandle(cls.LookupConstructor(constructor_name));
EXPECT(!constructor.IsNull());
const TypeArguments& no_type_arguments = TypeArguments::ZoneHandle();
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
test->node_sequence()->Add(
new ReturnNode(kPos, new ConstructorCallNode(kPos, no_type_arguments,
constructor, no_arguments)));
}
CODEGEN_TEST_RAW_RUN(AllocateNewObjectCodegen, function) {
const Object& result = Object::Handle(
DartEntry::InvokeFunction(function, Object::empty_array()));
EXPECT(!result.IsError());
const GrowableObjectArray& libs = GrowableObjectArray::Handle(
Isolate::Current()->object_store()->libraries());
ASSERT(!libs.IsNull());
// App lib is the last one that was loaded.
intptr_t num_libs = libs.Length();
Library& app_lib = Library::Handle();
app_lib ^= libs.At(num_libs - 1);
ASSERT(!app_lib.IsNull());
const Class& cls = Class::Handle(app_lib.LookupClass(
String::Handle(Symbols::New(Thread::Current(), "A"))));
EXPECT_EQ(cls.raw(), result.clazz());
}
} // namespace dart

View file

@ -125,6 +125,4 @@ compiler_sources_tests = [
"backend/locations_helpers_test.cc",
"backend/range_analysis_test.cc",
"cha_test.cc",
"code_generator_test.cc",
"frontend/flow_graph_builder_test.cc",
]

View file

@ -125,7 +125,7 @@ class BaseFlowGraphBuilder {
context_level_array_(context_level_array),
context_depth_(0),
last_used_block_id_(last_used_block_id),
current_try_index_(CatchClauseNode::kInvalidTryIndex),
current_try_index_(kInvalidTryIndex),
next_used_try_index_(0),
stack_(NULL),
pending_argument_count_(0),

View file

@ -1127,8 +1127,7 @@ void BytecodeFlowGraphBuilder::BuildThrow() {
// rethrow
LoadStackSlots(2);
GetArguments(2);
code_ += Fragment(new (Z) ReThrowInstr(position_,
CatchClauseNode::kInvalidTryIndex,
code_ += Fragment(new (Z) ReThrowInstr(position_, kInvalidTryIndex,
B->GetNextDeoptId()))
.closed();
}
@ -1327,7 +1326,7 @@ intptr_t BytecodeFlowGraphBuilder::GetTryIndex(const PcDescriptors& descriptors,
const uword pc_offset =
KernelBytecode::BytecodePcToOffset(pc, /* is_return_address = */ true);
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
intptr_t try_index = CatchClauseNode::kInvalidTryIndex;
intptr_t try_index = kInvalidTryIndex;
while (iter.MoveNext()) {
const intptr_t current_try_index = iter.TryIndex();
const uword start_pc = iter.PcOffset();

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,6 @@
#include "platform/assert.h"
#include "platform/globals.h"
#include "vm/allocation.h"
#include "vm/ast.h"
#include "vm/compiler/backend/flow_graph.h"
#include "vm/compiler/backend/il.h"
#include "vm/growable_array.h"
@ -16,18 +15,6 @@
namespace dart {
class AbstractType;
class Array;
class Class;
class Field;
class LocalVariable;
class ParsedFunction;
class String;
class TypeArguments;
class NestedStatement;
class TestGraphVisitor;
// A class to collect the exits from an inlined function during graph
// construction so they can be plugged into the caller's flow graph.
class InlineExitCollector : public ZoneAllocated {
@ -90,479 +77,8 @@ class InlineExitCollector : public ZoneAllocated {
GrowableArray<Data> exits_;
};
// Build a flow graph from a parsed function's AST.
class FlowGraphBuilder : public ValueObject {
public:
// The inlining context is NULL if not inlining. The osr_id is the deopt
// id of the OSR entry or Compiler::kNoOSRDeoptId if not compiling for OSR.
FlowGraphBuilder(const ParsedFunction& parsed_function,
const ZoneGrowableArray<const ICData*>& ic_data_array,
ZoneGrowableArray<intptr_t>* context_level_array,
InlineExitCollector* exit_collector,
intptr_t osr_id);
FlowGraph* BuildGraph();
const ParsedFunction& parsed_function() const { return parsed_function_; }
const Function& function() const { return parsed_function_.function(); }
const ZoneGrowableArray<const ICData*>& ic_data_array() const {
return ic_data_array_;
}
void Bailout(const char* reason) const;
intptr_t AllocateBlockId() { return ++last_used_block_id_; }
void SetInitialBlockId(intptr_t id) { last_used_block_id_ = id; }
intptr_t GetNextDeoptId() const;
intptr_t context_level() const;
void IncrementLoopDepth() { ++loop_depth_; }
void DecrementLoopDepth() { --loop_depth_; }
intptr_t loop_depth() const { return loop_depth_; }
// Manage the currently active try index.
void set_try_index(intptr_t value) { try_index_ = value; }
intptr_t try_index() const { return try_index_; }
// Manage the currently active catch-handler try index.
void set_catch_try_index(intptr_t value) { catch_try_index_ = value; }
intptr_t catch_try_index() const { return catch_try_index_; }
intptr_t next_await_counter() { return jump_count_++; }
ZoneGrowableArray<JoinEntryInstr*>* await_joins() const {
return await_joins_;
}
void AddCatchEntry(CatchBlockEntryInstr* entry);
GraphEntryInstr* graph_entry() const { return graph_entry_; }
intptr_t num_stack_locals() const { return num_stack_locals_; }
bool IsInlining() const { return (exit_collector_ != NULL); }
InlineExitCollector* exit_collector() const { return exit_collector_; }
ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
return parsed_function_.deferred_prefixes();
}
intptr_t temp_count() const { return temp_count_; }
intptr_t AllocateTemp() { return temp_count_++; }
void DeallocateTemps(intptr_t count) {
ASSERT(temp_count_ >= count);
temp_count_ -= count;
}
intptr_t args_pushed() const { return args_pushed_; }
void add_args_pushed(intptr_t n) { args_pushed_ += n; }
NestedStatement* nesting_stack() const { return nesting_stack_; }
// When compiling for OSR, remove blocks that are not reachable from the
// OSR entry point.
void PruneUnreachable();
// Returns address where the constant 'value' is stored or 0 if not found.
static uword FindDoubleConstant(double value);
Thread* thread() const { return parsed_function().thread(); }
Isolate* isolate() const { return parsed_function().isolate(); }
Zone* zone() const { return parsed_function().zone(); }
void AppendAwaitTokenPosition(TokenPosition token_pos);
ZoneGrowableArray<TokenPosition>* await_token_positions() const {
return await_token_positions_;
}
static bool SimpleInstanceOfType(const AbstractType& type);
private:
friend class NestedStatement; // Explicit access to nesting_stack_.
friend class Intrinsifier;
intptr_t parameter_count() const {
return parsed_function_.function().NumParameters();
}
const ParsedFunction& parsed_function_;
const ZoneGrowableArray<const ICData*>& ic_data_array_;
// Contains (deopt_id, context_level) pairs.
ZoneGrowableArray<intptr_t>* context_level_array_;
const intptr_t num_stack_locals_;
InlineExitCollector* const exit_collector_;
intptr_t last_used_block_id_;
intptr_t try_index_;
intptr_t catch_try_index_;
intptr_t loop_depth_;
GraphEntryInstr* graph_entry_;
// The expression stack height.
intptr_t temp_count_;
// Outgoing argument stack height.
intptr_t args_pushed_;
// A stack of enclosing nested statements.
NestedStatement* nesting_stack_;
// The deopt id of the OSR entry orCompiler::kNoOSRDeoptId if not compiling
// for OSR.
const intptr_t osr_id_;
intptr_t jump_count_;
ZoneGrowableArray<JoinEntryInstr*>* await_joins_;
ZoneGrowableArray<TokenPosition>* await_token_positions_;
DISALLOW_IMPLICIT_CONSTRUCTORS(FlowGraphBuilder);
};
// Translate an AstNode to a control-flow graph fragment for its effects
// (e.g., a statement or an expression in an effect context). Implements a
// function from an AstNode and next temporary index to a graph fragment
// with a single entry and at most one exit. The fragment is represented by
// an (entry, exit) pair of Instruction pointers:
//
// - (NULL, NULL): an empty and open graph fragment
// - (i0, NULL): a closed graph fragment which has only non-local exits
// - (i0, i1): an open graph fragment
class EffectGraphVisitor : public AstNodeVisitor {
public:
explicit EffectGraphVisitor(FlowGraphBuilder* owner)
: owner_(owner), entry_(NULL), exit_(NULL) {}
#define DECLARE_VISIT(BaseName) \
virtual void Visit##BaseName##Node(BaseName##Node* node);
FOR_EACH_NODE(DECLARE_VISIT)
#undef DECLARE_VISIT
FlowGraphBuilder* owner() const { return owner_; }
Instruction* entry() const { return entry_; }
Instruction* exit() const { return exit_; }
bool is_empty() const { return entry_ == NULL; }
bool is_open() const { return is_empty() || exit_ != NULL; }
void Bailout(const char* reason) const;
void InlineBailout(const char* reason) const;
// Append a graph fragment to this graph. Assumes this graph is open.
void Append(const EffectGraphVisitor& other_fragment);
// Append a definition that can have uses. Assumes this graph is open.
Value* Bind(Definition* definition);
// Append a computation with no uses. Assumes this graph is open.
void Do(Definition* definition);
// Append a single (non-Definition, non-Entry) instruction. Assumes this
// graph is open.
void AddInstruction(Instruction* instruction);
// Append a Goto (unconditional control flow) instruction and close
// the graph fragment. Assumes this graph fragment is open.
void Goto(JoinEntryInstr* join);
// Append a 'diamond' branch and join to this graph, depending on which
// parts are reachable. Assumes this graph is open.
void Join(const TestGraphVisitor& test_fragment,
const EffectGraphVisitor& true_fragment,
const EffectGraphVisitor& false_fragment);
// Append a 'while loop' test and back edge to this graph, depending on
// which parts are reachable. Afterward, the graph exit is the false
// successor of the loop condition.
void TieLoop(TokenPosition token_pos,
const TestGraphVisitor& test_fragment,
const EffectGraphVisitor& body_fragment,
const EffectGraphVisitor& test_preamble_fragment);
// Wraps a value in a push-argument instruction and adds the result to the
// graph.
PushArgumentInstr* PushArgument(Value* value);
// This implementation shares state among visitors by using the builder.
// The implementation is incorrect if a visitor that hits a return is not
// actually added to the graph.
void AddReturnExit(TokenPosition token_pos, Value* value);
protected:
Definition* BuildStoreTemp(const LocalVariable& local,
Value* value,
TokenPosition token_pos);
Definition* BuildStoreExprTemp(Value* value, TokenPosition token_pos);
Definition* BuildLoadExprTemp(TokenPosition token_pos);
Definition* BuildStoreLocal(const LocalVariable& local,
Value* value,
TokenPosition token_pos);
Definition* BuildLoadLocal(const LocalVariable& local,
TokenPosition token_pos);
LoadLocalInstr* BuildLoadThisVar(LocalScope* scope, TokenPosition token_pos);
LoadFieldInstr* BuildNativeGetter(NativeBodyNode* node,
const NativeFieldDesc* native_field);
// Assumes setter parameter is named 'value'. Returns null constant.
ConstantInstr* DoNativeSetterStoreValue(NativeBodyNode* node,
intptr_t offset,
StoreBarrierType emit_store_barrier);
// Helpers for translating parts of the AST.
void BuildPushTypeArguments(const ArgumentListNode& node,
ZoneGrowableArray<PushArgumentInstr*>* values);
void BuildPushArguments(const ArgumentListNode& node,
ZoneGrowableArray<PushArgumentInstr*>* values);
// Creates an instantiated type argument vector used in preparation of an
// allocation call.
// May be called only if allocating an object of a parameterized class.
Value* BuildInstantiatedTypeArguments(TokenPosition token_pos,
const TypeArguments& type_arguments);
Value* BuildInstantiator(TokenPosition token_pos);
Value* BuildInstantiatorTypeArguments(TokenPosition token_pos);
Value* BuildFunctionTypeArguments(TokenPosition token_pos);
PushArgumentInstr* PushInstantiatorTypeArguments(const AbstractType& type,
TokenPosition token_pos);
PushArgumentInstr* PushFunctionTypeArguments(const AbstractType& type,
TokenPosition token_pos);
// Perform a type check on the given value.
AssertAssignableInstr* BuildAssertAssignable(TokenPosition token_pos,
Value* value,
const AbstractType& dst_type,
const String& dst_name);
// Perform a type check on the given value and return it.
Value* BuildAssignableValue(TokenPosition token_pos,
Value* value,
const AbstractType& dst_type,
const String& dst_name);
static const bool kResultNeeded = true;
static const bool kResultNotNeeded = false;
Definition* BuildStoreIndexedValues(StoreIndexedNode* node,
bool result_is_needed);
void BuildInstanceSetterArguments(
InstanceSetterNode* node,
ZoneGrowableArray<PushArgumentInstr*>* arguments,
bool result_is_needed);
StrictCompareInstr* BuildStrictCompare(AstNode* left,
AstNode* right,
Token::Kind kind,
TokenPosition token_pos);
virtual void BuildTypeTest(ComparisonNode* node);
virtual void BuildTypeCast(ComparisonNode* node);
bool HasContextScope() const;
// Moves the nth parent context into the context register.
void UnchainContexts(intptr_t n);
// Unchain the current context until its level matches the context level
// expected on entry at the target specified by its scope.
void AdjustContextLevel(LocalScope* target_scope);
void CloseFragment() { exit_ = NULL; }
// Returns a local variable index for a temporary local that is
// on top of the current expression stack.
intptr_t GetCurrentTempLocalIndex() const;
Value* BuildObjectAllocation(ConstructorCallNode* node);
void BuildConstructorCall(ConstructorCallNode* node,
PushArgumentInstr* alloc_value);
void BuildSaveContext(const LocalVariable& variable, TokenPosition token_pos);
void BuildRestoreContext(const LocalVariable& variable,
TokenPosition token_pos);
Definition* BuildStoreContext(Value* value, TokenPosition token_pos);
Definition* BuildCurrentContext(TokenPosition token_pos);
void BuildThrowNode(ThrowNode* node);
StaticCallInstr* BuildStaticNoSuchMethodCall(
const Class& target_class,
AstNode* receiver,
const String& method_name,
ArgumentListNode* method_arguments,
bool save_last_arg,
bool is_super_invocation);
StaticCallInstr* BuildThrowNoSuchMethodError(
TokenPosition token_pos,
const Class& function_class,
const String& function_name,
ArgumentListNode* function_arguments,
int invocation_type);
void BuildStaticSetter(StaticSetterNode* node, bool result_is_needed);
Definition* BuildStoreStaticField(StoreStaticFieldNode* node,
bool result_is_needed,
TokenPosition token_pos);
void BuildClosureCall(ClosureCallNode* node, bool result_needed);
Value* BuildNullValue(TokenPosition token_pos);
// Returns true if the run-time type check can be eliminated.
bool CanSkipTypeCheck(TokenPosition token_pos,
Value* value,
const AbstractType& dst_type,
const String& dst_name);
// Helpers for allocating and deallocating temporary locals on top of the
// expression stack.
LocalVariable* EnterTempLocalScope(Value* value);
Definition* ExitTempLocalScope(Value* value);
void BuildLetTempExpressions(LetNode* node);
void BuildInstanceGetterConditional(InstanceGetterNode* node);
void BuildInstanceCallConditional(InstanceCallNode* node);
Thread* thread() const { return owner()->thread(); }
Isolate* isolate() const { return owner()->isolate(); }
Zone* zone() const { return owner()->zone(); }
private:
friend class TempLocalScope; // For ReturnDefinition.
// Helper to drop the result value.
virtual void ReturnValue(Value* value) { Do(new DropTempsInstr(0, value)); }
// Specify a definition of the final result. Adds the definition to
// the graph, but normally overridden in subclasses.
virtual void ReturnDefinition(Definition* definition) {
// Constants have no effect, do not add them to graph otherwise SSA
// builder will get confused.
if (!definition->IsConstant()) {
Do(definition);
}
}
// Shared global state.
FlowGraphBuilder* owner_;
// Output parameters.
Instruction* entry_;
Instruction* exit_;
};
// Translate an AstNode to a control-flow graph fragment for both its effects
// and value (e.g., for an expression in a value context). Implements a
// function from an AstNode and next temporary index to a graph fragment (as
// in the EffectGraphVisitor), a next temporary index, and an intermediate
// language Value.
class ValueGraphVisitor : public EffectGraphVisitor {
public:
explicit ValueGraphVisitor(FlowGraphBuilder* owner)
: EffectGraphVisitor(owner), value_(NULL) {}
// Visit functions overridden by this class.
virtual void VisitAssignableNode(AssignableNode* node);
virtual void VisitConstructorCallNode(ConstructorCallNode* node);
virtual void VisitBinaryOpNode(BinaryOpNode* node);
virtual void VisitConditionalExprNode(ConditionalExprNode* node);
virtual void VisitLoadLocalNode(LoadLocalNode* node);
virtual void VisitStoreIndexedNode(StoreIndexedNode* node);
virtual void VisitInstanceSetterNode(InstanceSetterNode* node);
virtual void VisitInstanceGetterNode(InstanceGetterNode* node);
virtual void VisitThrowNode(ThrowNode* node);
virtual void VisitClosureCallNode(ClosureCallNode* node);
virtual void VisitStaticSetterNode(StaticSetterNode* node);
virtual void VisitStoreStaticFieldNode(StoreStaticFieldNode* node);
virtual void VisitTypeNode(TypeNode* node);
virtual void VisitLetNode(LetNode* node);
virtual void VisitInstanceCallNode(InstanceCallNode* node);
Value* value() const { return value_; }
protected:
// Output parameters.
Value* value_;
private:
friend class EffectGraphVisitor;
// Helper to set the output state to return a Value.
virtual void ReturnValue(Value* value) { value_ = value; }
// Specify a definition of the final result. Adds the definition to
// the graph and returns a use of it (i.e., set the visitor's output
// parameters).
virtual void ReturnDefinition(Definition* definition) {
ReturnValue(Bind(definition));
}
};
// Translate an AstNode to a control-flow graph fragment for both its
// effects and true/false control flow (e.g., for an expression in a test
// context). The resulting graph is always closed (even if it is empty)
// Successor control flow is explicitly set by a pair of pointers to
// TargetEntryInstr*.
//
// To distinguish between the graphs with only nonlocal exits and graphs
// with both true and false exits, there are a pair of TargetEntryInstr**:
//
// - Both NULL: only non-local exits, truly closed
// - Neither NULL: true and false successors at the given addresses
//
// We expect that AstNode in test contexts either have only nonlocal exits
// or else control flow has both true and false successors.
//
// The cis and token_pos are used in checked mode to verify that the
// condition of the test is of type bool.
class TestGraphVisitor : public ValueGraphVisitor {
public:
TestGraphVisitor(FlowGraphBuilder* owner, TokenPosition condition_token_pos)
: ValueGraphVisitor(owner),
true_successor_addresses_(1),
false_successor_addresses_(1),
condition_token_pos_(condition_token_pos) {}
void IfFalseGoto(JoinEntryInstr* join) const;
void IfTrueGoto(JoinEntryInstr* join) const;
BlockEntryInstr* CreateTrueSuccessor() const;
BlockEntryInstr* CreateFalseSuccessor() const;
virtual void VisitBinaryOpNode(BinaryOpNode* node);
TokenPosition condition_token_pos() const { return condition_token_pos_; }
private:
friend class EffectGraphVisitor;
// Construct and concatenate a Branch instruction to this graph fragment.
// Closes the fragment and sets the output parameters.
virtual void ReturnValue(Value* value);
// Either merges the definition into a BranchInstr (Comparison, BooleanNegate)
// or adds the definition to the graph and returns a use of its value.
virtual void ReturnDefinition(Definition* definition);
void MergeBranchWithStrictCompare(StrictCompareInstr* comp);
void MergeBranchWithNegate(BooleanNegateInstr* comp);
BlockEntryInstr* CreateSuccessorFor(
const GrowableArray<TargetEntryInstr**>& branches) const;
void ConnectBranchesTo(const GrowableArray<TargetEntryInstr**>& branches,
JoinEntryInstr* join) const;
// Output parameters.
GrowableArray<TargetEntryInstr**> true_successor_addresses_;
GrowableArray<TargetEntryInstr**> false_successor_addresses_;
TokenPosition condition_token_pos_;
};
bool SimpleInstanceOfType(const AbstractType& type);
uword FindDoubleConstant(double value);
} // namespace dart

View file

@ -1,780 +0,0 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/frontend/flow_graph_builder.h"
#include "vm/compiler/backend/il.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/unit_test.h"
namespace dart {
#ifndef PRODUCT
#define DUMP_ASSERT(condition) \
if (!(condition)) { \
dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \
THR_Print(">>> BEGIN source position table for `%s`\n", graph_name_); \
Dump(); \
THR_Print("<<< END source position table for `%s`\n", graph_name_); \
OS::Abort(); \
}
class SourcePositionTest : public ValueObject {
public:
SourcePositionTest(Thread* thread, const char* script)
: thread_(thread),
isolate_(thread->isolate()),
script_(script),
root_lib_(Library::Handle()),
root_script_(Script::Handle()),
graph_(NULL),
blocks_(NULL) {
EXPECT(thread_ != NULL);
EXPECT(isolate_ != NULL);
EXPECT(script_ != NULL);
{
TransitionVMToNative transition(thread);
Dart_Handle lib = TestCase::LoadTestScript(script, NULL);
EXPECT_VALID(lib);
root_lib_ ^= Api::UnwrapHandle(lib);
}
EXPECT(!root_lib_.IsNull());
root_script_ ^=
root_lib_.LookupScript(String::Handle(String::New(USER_TEST_URI)));
EXPECT(!root_script_.IsNull());
}
void BuildGraphFor(const char* function_name) {
graph_ = NULL;
blocks_ = NULL;
graph_name_ = NULL;
// Only support unoptimized code for now.
const bool optimized = false;
const Function& function =
Function::Handle(GetFunction(root_lib_, function_name));
ZoneGrowableArray<const ICData*>* ic_data_array =
new ZoneGrowableArray<const ICData*>();
ParsedFunction* parsed_function =
new ParsedFunction(thread_, Function::ZoneHandle(function.raw()));
Parser::ParseFunction(parsed_function);
parsed_function->AllocateVariables();
CompilerState state(thread_);
FlowGraphBuilder builder(*parsed_function, *ic_data_array,
/* not building var desc */ NULL,
/* not inlining */ NULL, Compiler::kNoOSRDeoptId);
graph_ = builder.BuildGraph();
EXPECT(graph_ != NULL);
blocks_ = graph_->CodegenBlockOrder(optimized);
EXPECT(blocks_ != NULL);
graph_name_ = function_name;
EXPECT(graph_name_ != NULL);
}
// Expect to find an instance call at |line| and |column|.
void InstanceCallAt(intptr_t line,
intptr_t column = -1,
Token::Kind kind = Token::kNumTokens) {
ZoneGrowableArray<Instruction*>* instructions =
FindInstructionsAt(line, column);
intptr_t count = 0;
for (intptr_t i = 0; i < instructions->length(); i++) {
Instruction* instr = instructions->At(i);
EXPECT(instr != NULL);
if (instr->IsInstanceCall()) {
if (kind != Token::kNumTokens) {
if (instr->AsInstanceCall()->token_kind() == kind) {
count++;
}
} else {
count++;
}
}
}
DUMP_ASSERT(count > 0);
}
// Expect to find an instance call at |line| and |column|.
void InstanceCallAt(const char* needle, intptr_t line, intptr_t column = -1) {
ZoneGrowableArray<Instruction*>* instructions =
FindInstructionsAt(line, column);
intptr_t count = 0;
for (intptr_t i = 0; i < instructions->length(); i++) {
Instruction* instr = instructions->At(i);
EXPECT(instr != NULL);
if (instr->IsInstanceCall()) {
const char* haystack = instr->ToCString();
if (strstr(haystack, needle) != NULL) {
count++;
}
}
}
DUMP_ASSERT(count > 0);
}
// Expect to find at least one static call at |line| and |column|. The
// static call will have |needle| in its |ToCString| representation.
void StaticCallAt(const char* needle, intptr_t line, intptr_t column = -1) {
ZoneGrowableArray<Instruction*>* instructions =
FindInstructionsAt(line, column);
intptr_t count = 0;
for (intptr_t i = 0; i < instructions->length(); i++) {
Instruction* instr = instructions->At(i);
EXPECT(instr != NULL);
if (instr->IsStaticCall()) {
const char* haystack = instr->ToCString();
if (strstr(haystack, needle) != NULL) {
count++;
}
}
}
DUMP_ASSERT(count > 0);
}
// Expect that at least one of the instructions found at |line| and |column|
// contain |needle| in their |ToCString| representation.
void FuzzyInstructionMatchAt(const char* needle,
intptr_t line,
intptr_t column = -1) {
ZoneGrowableArray<Instruction*>* instructions =
FindInstructionsAt(line, column);
intptr_t count = 0;
for (intptr_t i = 0; i < instructions->length(); i++) {
Instruction* instr = instructions->At(i);
const char* haystack = instr->ToCString();
if (strstr(haystack, needle) != NULL) {
count++;
}
}
DUMP_ASSERT(count > 0);
}
// Utility to dump the instructions with token positions or line numbers.
void Dump() {
for (intptr_t i = 0; i < blocks_->length(); i++) {
BlockEntryInstr* entry = (*blocks_)[i];
THR_Print("B%" Pd ":\n", entry->block_id());
DumpInstruction(entry);
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
DumpInstruction(it.Current());
}
}
}
// Fails if any of the IR nodes has a token position of
// TokenPosition::kNoSourcePos.
void EnsureSourcePositions() {
for (intptr_t i = 0; i < blocks_->length(); i++) {
BlockEntryInstr* entry = (*blocks_)[i];
DUMP_ASSERT(entry->token_pos() != TokenPosition::kNoSource);
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
DUMP_ASSERT(instr->token_pos() != TokenPosition::kNoSource);
}
}
}
private:
void DumpInstruction(Instruction* instr) {
TokenPosition token_pos = instr->token_pos();
bool synthetic = false;
if (token_pos.IsSynthetic()) {
synthetic = true;
token_pos = token_pos.FromSynthetic();
}
if (token_pos.IsClassifying()) {
const char* token_pos_string = token_pos.ToCString();
THR_Print("%12s -- %s\n", token_pos_string, instr->ToCString());
return;
}
intptr_t token_line = -1;
intptr_t token_column = -1;
root_script_.GetTokenLocation(token_pos, &token_line, &token_column, NULL);
if (synthetic) {
THR_Print(" *%02d:%02d -- %s\n", static_cast<int>(token_line),
static_cast<int>(token_column), instr->ToCString());
} else {
THR_Print(" %02d:%02d -- %s\n", static_cast<int>(token_line),
static_cast<int>(token_column), instr->ToCString());
}
}
Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) {
ZoneGrowableArray<Instruction*>* instructions =
FindInstructionsAt(line, column);
if (instructions->length() == 0) {
return NULL;
}
return instructions->At(0);
}
ZoneGrowableArray<Instruction*>* FindInstructionsAt(intptr_t line,
intptr_t column) {
ZoneGrowableArray<Instruction*>* instructions =
new ZoneGrowableArray<Instruction*>();
for (intptr_t i = 0; i < blocks_->length(); i++) {
BlockEntryInstr* entry = (*blocks_)[i];
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
const TokenPosition token_pos = instr->token_pos().SourcePosition();
if (!token_pos.IsReal()) {
continue;
}
intptr_t token_line = -1;
intptr_t token_column = -1;
root_script_.GetTokenLocation(token_pos, &token_line, &token_column,
NULL);
if (token_line == line) {
if ((column < 0) || (column == token_column)) {
instructions->Add(instr);
}
}
}
}
return instructions;
}
ZoneGrowableArray<Instruction*>* FindInstructionsAt(intptr_t token_pos) {
ZoneGrowableArray<Instruction*>* instructions =
new ZoneGrowableArray<Instruction*>();
for (intptr_t i = 0; i < blocks_->length(); i++) {
BlockEntryInstr* entry = (*blocks_)[i];
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
if (instr->token_pos().value() == token_pos) {
instructions->Add(instr);
}
}
}
return instructions;
}
RawFunction* GetFunction(const Library& lib, const char* name) {
const Function& result = Function::Handle(
lib.LookupFunctionAllowPrivate(String::Handle(String::New(name))));
EXPECT(!result.IsNull());
return result.raw();
}
RawFunction* GetFunction(const Class& cls, const char* name) {
const Function& result = Function::Handle(
cls.LookupFunctionAllowPrivate(String::Handle(String::New(name))));
EXPECT(!result.IsNull());
return result.raw();
}
RawClass* GetClass(const Library& lib, const char* name) {
const Class& cls = Class::Handle(
lib.LookupClass(String::Handle(Symbols::New(thread_, name))));
EXPECT(!cls.IsNull()); // No ambiguity error expected.
return cls.raw();
}
Thread* thread_;
Isolate* isolate_;
const char* script_;
Library& root_lib_;
Script& root_script_;
const char* graph_name_;
FlowGraph* graph_;
GrowableArray<BlockEntryInstr*>* blocks_;
};
ISOLATE_UNIT_TEST_CASE(SourcePosition_InstanceCalls) {
const char* kScript =
"var x = 5;\n"
"var y = 5;\n"
"main() {\n"
" var z = x + y;\n"
" return z;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.InstanceCallAt(4, 13, Token::kADD);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 3);
spt.FuzzyInstructionMatchAt("Return", 5, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_If) {
const char* kScript =
"var x = 5;\n"
"var y = 5;\n"
"main() {\n"
" if (x != 0) {\n"
" return x;\n"
" }\n"
" return y;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 7);
spt.InstanceCallAt(4, 9, Token::kEQ);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 9);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 12);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 5);
spt.FuzzyInstructionMatchAt("Return", 5, 5);
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3);
spt.FuzzyInstructionMatchAt("Return", 7, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_ForLoop) {
const char* kScript =
"var x = 0;\n"
"var y = 5;\n"
"main() {\n"
" for (var i = 0; i < 10; i++) {\n"
" x += i;\n"
" }\n"
" return x;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("StoreLocal", 4, 14);
spt.FuzzyInstructionMatchAt("LoadLocal", 4, 19);
spt.InstanceCallAt(4, 21, Token::kLT);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 21);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 5);
spt.FuzzyInstructionMatchAt("StoreStaticField", 5, 5);
spt.InstanceCallAt(5, 7, Token::kADD);
spt.FuzzyInstructionMatchAt("LoadLocal", 5, 10);
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3);
spt.FuzzyInstructionMatchAt("Return", 7, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_While) {
const char* kScript =
"var x = 0;\n"
"var y = 5;\n"
"main() {\n"
" while (x < 10) {\n"
" if (y == 5) {\n"
" return y;\n"
" }\n"
" x++;\n"
" }\n"
" return x;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 4, 3);
spt.FuzzyInstructionMatchAt("Constant", 4, 10);
spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 10);
spt.InstanceCallAt(4, 12, Token::kLT);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 12);
spt.FuzzyInstructionMatchAt("Constant", 5, 9);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 9);
spt.InstanceCallAt(5, 11, Token::kEQ);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 5, 11);
spt.FuzzyInstructionMatchAt("Constant", 6, 14);
spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 14);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 7);
spt.FuzzyInstructionMatchAt("Return", 6, 7);
spt.FuzzyInstructionMatchAt("Constant", 8, 5);
spt.FuzzyInstructionMatchAt("LoadStaticField", 8, 5);
spt.FuzzyInstructionMatchAt("Constant(#1)", 8, 6);
spt.InstanceCallAt(8, 6, Token::kADD);
spt.FuzzyInstructionMatchAt("StoreStaticField", 8, 5);
spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
spt.FuzzyInstructionMatchAt("Return", 10, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_WhileContinueBreak) {
const char* kScript =
"var x = 0;\n"
"var y = 5;\n"
"main() {\n"
" while (x < 10) {\n"
" if (y == 5) {\n"
" continue;\n"
" }\n"
" break;\n"
" }\n"
" return x;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 4, 3);
spt.FuzzyInstructionMatchAt("Constant(#Field", 4, 10);
spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 10);
spt.FuzzyInstructionMatchAt("Constant(#10", 4, 14);
spt.InstanceCallAt(4, 12, Token::kLT);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 12);
spt.FuzzyInstructionMatchAt("Constant(#Field", 5, 9);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 9);
spt.FuzzyInstructionMatchAt("Constant(#5", 5, 14);
spt.InstanceCallAt(5, 11, Token::kEQ);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 5, 11);
spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
spt.FuzzyInstructionMatchAt("Return", 10, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_LoadIndexed) {
const char* kScript =
"var x = 0;\n"
"var z = new List(3);\n"
"main() {\n"
" z[0];\n"
" var y = z[0] + z[1] + z[2];\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.StaticCallAt("get:z", 4, 3);
spt.FuzzyInstructionMatchAt("Constant(#0)", 4, 5);
spt.InstanceCallAt(4, 4, Token::kINDEX);
spt.FuzzyInstructionMatchAt("Constant(#0)", 5, 13);
spt.InstanceCallAt(5, 12, Token::kINDEX);
spt.FuzzyInstructionMatchAt("Constant(#1)", 5, 20);
spt.InstanceCallAt(5, 19, Token::kINDEX);
spt.InstanceCallAt(5, 16, Token::kADD);
spt.StaticCallAt("get:z", 5, 25);
spt.FuzzyInstructionMatchAt("Constant(#2)", 5, 27);
spt.InstanceCallAt(5, 26, Token::kINDEX);
spt.InstanceCallAt(5, 23, Token::kADD);
spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
spt.FuzzyInstructionMatchAt("Return", 6, 1);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_StoreIndexed) {
const char* kScript =
"var x = 0;\n"
"var z = new List(4);\n"
"main() {\n"
" z[0];\n"
" z[3] = z[0] + z[1] + z[2];\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.StaticCallAt("get:z", 4, 3);
spt.FuzzyInstructionMatchAt("Constant(#0)", 4, 5);
spt.InstanceCallAt(4, 4, Token::kINDEX);
spt.FuzzyInstructionMatchAt("Constant(#3)", 5, 5);
spt.StaticCallAt("get:z", 5, 10);
spt.FuzzyInstructionMatchAt("Constant(#0)", 5, 12);
spt.InstanceCallAt(5, 11, Token::kINDEX);
spt.InstanceCallAt(5, 15, Token::kADD);
spt.StaticCallAt("get:z", 5, 17);
spt.FuzzyInstructionMatchAt("Constant(#1)", 5, 19);
spt.InstanceCallAt(5, 18, Token::kINDEX);
spt.StaticCallAt("get:z", 5, 24);
spt.FuzzyInstructionMatchAt("Constant(#2)", 5, 26);
spt.InstanceCallAt(5, 25, Token::kINDEX);
spt.InstanceCallAt(5, 4, Token::kASSIGN_INDEX);
spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
spt.FuzzyInstructionMatchAt("Return", 6, 1);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_BitwiseOperations) {
const char* kScript =
"var x = 0;\n"
"var y = 1;\n"
"main() {\n"
" var z;\n"
" z = x & y;\n"
" z = x | y;\n"
" z = x ^ y;\n"
" z = ~z;\n"
" return z;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 4, 7);
spt.FuzzyInstructionMatchAt("Constant(#null", 4, 7);
spt.FuzzyInstructionMatchAt("StoreLocal(z", 4, 7);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 7);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 11);
spt.InstanceCallAt(5, 9, Token::kBIT_AND);
spt.FuzzyInstructionMatchAt("StoreLocal(z", 5, 3);
spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 7);
spt.FuzzyInstructionMatchAt("LoadStaticField", 6, 11);
spt.InstanceCallAt(6, 9, Token::kBIT_OR);
spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 3);
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 7);
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 11);
spt.InstanceCallAt(7, 9, Token::kBIT_XOR);
spt.FuzzyInstructionMatchAt("StoreLocal(z", 7, 3);
spt.FuzzyInstructionMatchAt("LoadLocal(z", 8, 8);
spt.InstanceCallAt(8, 7, Token::kBIT_NOT);
spt.FuzzyInstructionMatchAt("StoreLocal(z", 8, 3);
spt.FuzzyInstructionMatchAt("LoadLocal(z", 9, 10);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
spt.FuzzyInstructionMatchAt("Return", 9, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_IfElse) {
const char* kScript =
"var x = 5;\n"
"var y = 5;\n"
"main() {\n"
" if (x != 0) {\n"
" return x;\n"
" } else {\n"
" return y;\n"
" }\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 7);
spt.InstanceCallAt(4, 9, Token::kEQ);
spt.FuzzyInstructionMatchAt("Branch if StrictCompare", 4, 9);
spt.FuzzyInstructionMatchAt("LoadStaticField", 5, 12);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 5);
spt.FuzzyInstructionMatchAt("Return", 5, 5);
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 12);
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 5);
spt.FuzzyInstructionMatchAt("Return", 7, 5);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_Switch) {
const char* kScript =
"var x = 5;\n"
"var y = 5;\n"
"main() {\n"
" switch (x) {\n"
" case 1: return 3;\n"
" case 2: return 4;\n"
" default: return 5;\n"
" }\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("Constant(#Field", 4, 11);
spt.FuzzyInstructionMatchAt("LoadStaticField", 4, 11);
spt.FuzzyInstructionMatchAt("StoreLocal(:switch_expr", 4, 11);
spt.FuzzyInstructionMatchAt("Constant(#1", 5, 10);
spt.FuzzyInstructionMatchAt("LoadLocal(:switch_expr", 5, 5); // 'c'
spt.InstanceCallAt(5, 10, Token::kEQ); // '1'
spt.FuzzyInstructionMatchAt("Constant(#3", 5, 20); // '3'
spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 13);
spt.FuzzyInstructionMatchAt("Return", 5, 13);
spt.FuzzyInstructionMatchAt("Constant(#2", 6, 10);
spt.FuzzyInstructionMatchAt("LoadLocal(:switch_expr", 6, 5); // 'c'
spt.InstanceCallAt(6, 10, Token::kEQ); // '2'
spt.FuzzyInstructionMatchAt("Constant(#4", 6, 20); // '4'
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 13);
spt.FuzzyInstructionMatchAt("Return", 6, 13);
spt.FuzzyInstructionMatchAt("Constant(#5", 7, 21); // '5'
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 14);
spt.FuzzyInstructionMatchAt("Return", 7, 14);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_TryCatchFinally) {
const char* kScript =
"var x = 5;\n"
"var y = 5;\n"
"main() {\n"
" try {\n"
" throw 'A';\n"
" } catch (e) {\n"
" print(e);\n"
" return 77;\n"
" } finally {\n"
" return 99;\n"
" }\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("DebugStepCheck", 3, 5);
spt.FuzzyInstructionMatchAt("CheckStackOverflow", 3, 1);
spt.FuzzyInstructionMatchAt("LoadLocal(:current_context", 4, 3); // 't'
spt.FuzzyInstructionMatchAt("StoreLocal(:saved_try_context", 4, 3);
spt.FuzzyInstructionMatchAt("Constant(#A", 5, 11); // 'A'
spt.FuzzyInstructionMatchAt("Throw", 5, 5); // 't'
spt.FuzzyInstructionMatchAt("LoadLocal(:saved_try_context", 6, 5); // 'c'
spt.FuzzyInstructionMatchAt("StoreLocal(:current_context", 6, 5); // 'c'
spt.FuzzyInstructionMatchAt("LoadLocal(:exception_var", 6, 5); // 'c'
spt.FuzzyInstructionMatchAt("StoreLocal(e", 6, 5); // 'c'
spt.FuzzyInstructionMatchAt("LoadLocal(e", 7, 11); // 'e'
spt.FuzzyInstructionMatchAt("StaticCall", 7, 5); // 'p'
spt.FuzzyInstructionMatchAt("Constant(#77", 8, 12); // '7'
spt.FuzzyInstructionMatchAt("StoreLocal(:finally_ret_val", 8, 5); // 'r'
spt.FuzzyInstructionMatchAt("Constant(#99", 10, 12); // '9'
spt.FuzzyInstructionMatchAt("Return", 10, 5); // 'r'
spt.FuzzyInstructionMatchAt("LoadLocal(:saved_try_context", 9, 13); // '{'
spt.FuzzyInstructionMatchAt("StoreLocal(:current_context", 9, 13); // '{'
spt.FuzzyInstructionMatchAt("Constant(#99", 10, 12); // '9'
spt.FuzzyInstructionMatchAt("Return", 10, 5); // 'r'
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_InstanceFields) {
const char* kScript =
"class A {\n"
" var x;\n"
" var y;\n"
"}\n"
"main() {\n"
" var z = new A();\n"
" z.x = 99;\n"
" z.y = z.x;\n"
" return z.y;\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("main");
spt.FuzzyInstructionMatchAt("AllocateObject(A)", 6, 15); // 'A'
spt.FuzzyInstructionMatchAt("StaticCall", 6, 15); // 'A'
spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 9); // '='
spt.InstanceCallAt("set:x", 7, 5); // 'x'
spt.InstanceCallAt("get:x", 8, 11); // 'x'
spt.InstanceCallAt("set:y", 8, 5); // 'y'
spt.InstanceCallAt("get:y", 9, 12); // 'y'
spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
spt.FuzzyInstructionMatchAt("Return", 9, 3);
spt.EnsureSourcePositions();
}
ISOLATE_UNIT_TEST_CASE(SourcePosition_Async) {
const char* kScript =
"import 'dart:async';\n"
"var x = 5;\n"
"var y = 5;\n"
"foo(Future f1, Future f2) async {\n"
" await f1;\n"
" await f2;\n"
" return 55;\n"
"}\n"
"main() {\n"
" foo(new Future.value(33));\n"
"}\n";
SourcePositionTest spt(thread, kScript);
spt.BuildGraphFor("foo");
spt.EnsureSourcePositions();
spt.Dump();
}
#endif // !PRODUCT
static bool SyntheticRoundTripTest(TokenPosition token_pos) {
const TokenPosition synthetic_token_pos = token_pos.ToSynthetic();
return synthetic_token_pos.FromSynthetic() == token_pos;
}
VM_UNIT_TEST_CASE(SourcePosition_SyntheticTokens) {
EXPECT(TokenPosition::kNoSourcePos == -1);
EXPECT(TokenPosition::kMinSourcePos == 0);
EXPECT(TokenPosition::kMaxSourcePos > 0);
EXPECT(TokenPosition::kMaxSourcePos > TokenPosition::kMinSourcePos);
EXPECT(TokenPosition::kMinSource.value() == TokenPosition::kMinSourcePos);
EXPECT(TokenPosition::kMaxSource.value() == TokenPosition::kMaxSourcePos);
EXPECT(!TokenPosition(0).IsSynthetic());
EXPECT(TokenPosition(0).ToSynthetic().IsSynthetic());
EXPECT(TokenPosition(9).ToSynthetic().IsSynthetic());
EXPECT(!TokenPosition(-1).FromSynthetic().IsSynthetic());
EXPECT(!TokenPosition::kNoSource.IsSynthetic());
EXPECT(!TokenPosition::kLast.IsSynthetic());
EXPECT(SyntheticRoundTripTest(TokenPosition(0)));
EXPECT(SyntheticRoundTripTest(TokenPosition::kMaxSource));
EXPECT(SyntheticRoundTripTest(TokenPosition::kMinSource));
}
} // namespace dart

View file

@ -1376,8 +1376,7 @@ Fragment StreamingFlowGraphBuilder::CompleteBodyWithYieldContinuations(
// Prepend an entry corresponding to normal entry to the function.
yield_continuations().InsertAt(
0, YieldContinuation(new (Z) DropTempsInstr(0, NULL),
CatchClauseNode::kInvalidTryIndex));
0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), kInvalidTryIndex));
yield_continuations()[0].entry->LinkTo(body.entry);
// Load :await_jump_var into a temporary.
@ -4377,7 +4376,7 @@ Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) {
instructions += PushArgument();
// See if simple instanceOf is applicable.
if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) {
if (dart::SimpleInstanceOfType(type)) {
instructions += Constant(type);
instructions += PushArgument(); // Type.
instructions += InstanceCall(
@ -5761,7 +5760,7 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement() {
rethrow += PushArgument();
rethrow += LoadLocal(stack_trace_var);
rethrow += PushArgument();
rethrow += RethrowException(position, CatchClauseNode::kInvalidTryIndex);
rethrow += RethrowException(position, kInvalidTryIndex);
Drop();
continuation = Fragment(continuation.entry, no_error);

View file

@ -1372,9 +1372,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
void FlowGraphBuilder::SetCurrentTryCatchBlock(TryCatchBlock* try_catch_block) {
try_catch_block_ = try_catch_block;
SetCurrentTryIndex(try_catch_block == nullptr
? CatchClauseNode::kInvalidTryIndex
: try_catch_block->try_index());
SetCurrentTryIndex(try_catch_block == nullptr ? kInvalidTryIndex
: try_catch_block->try_index());
}
} // namespace kernel

View file

@ -38,8 +38,7 @@ struct YieldContinuation {
YieldContinuation(Instruction* entry, intptr_t try_index)
: entry(entry), try_index(try_index) {}
YieldContinuation()
: entry(NULL), try_index(CatchClauseNode::kInvalidTryIndex) {}
YieldContinuation() : entry(NULL), try_index(kInvalidTryIndex) {}
};
class FlowGraphBuilder : public BaseFlowGraphBuilder {

View file

@ -218,16 +218,9 @@ bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
ASSERT(!parsed_function.function().HasOptionalParameters());
PrologueInfo prologue_info(-1, -1);
ZoneGrowableArray<const ICData*>* ic_data_array =
new ZoneGrowableArray<const ICData*>();
FlowGraphBuilder builder(parsed_function, *ic_data_array,
/* not building var desc */ NULL,
/* not inlining */ NULL, Compiler::kNoOSRDeoptId);
intptr_t block_id = builder.AllocateBlockId();
TargetEntryInstr* normal_entry =
new TargetEntryInstr(block_id, CatchClauseNode::kInvalidTryIndex,
CompilerState::Current().GetNextDeoptId());
intptr_t block_id = 1; // 0 is GraphEntry.
TargetEntryInstr* normal_entry = new TargetEntryInstr(
block_id, kInvalidTryIndex, CompilerState::Current().GetNextDeoptId());
GraphEntryInstr* graph_entry = new GraphEntryInstr(
parsed_function, normal_entry, Compiler::kNoOSRDeoptId);
FlowGraph* graph =

View file

@ -6,7 +6,6 @@
#include "vm/compiler/assembler/assembler.h"
#include "vm/ast_printer.h"
#include "vm/code_patcher.h"
#include "vm/compiler/aot/precompiler.h"
#include "vm/compiler/assembler/disassembler.h"
@ -1115,17 +1114,6 @@ static RawError* ParseFunctionHelper(CompilationPipeline* pipeline,
ParsedFunction* parsed_function = new (zone)
ParsedFunction(thread, Function::ZoneHandle(zone, function.raw()));
pipeline->ParseFunction(parsed_function);
// For now we just walk thru the AST nodes and in DEBUG mode we print
// them otherwise just skip through them, this will be need to be
// wired to generate the IR format.
#if !defined(PRODUCT)
#if defined(DEBUG)
AstPrinter ast_printer(true);
#else
AstPrinter ast_printer(false);
#endif // defined(DEBUG).
ast_printer.PrintFunctionNodes(*parsed_function);
#endif // !defined(PRODUCT).
return Error::null();
} else {
Thread* const thread = Thread::Current();
@ -1511,14 +1499,6 @@ RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
// Don't allow reload requests to come in.
NoReloadScope no_reload_scope(thread->isolate(), thread);
if (FLAG_trace_compiler) {
THR_Print("compiling expression: ");
if (FLAG_support_ast_printer) {
AstPrinter ast_printer;
ast_printer.PrintNode(fragment);
}
}
// Create a dummy function object for the code generator.
// The function needs to be associated with a named Class: the interface
// Function fits the bill.

View file

@ -337,4 +337,35 @@ Token::Kind MethodTokenRecognizer::RecognizeTokenKind(const String& name) {
return Token::kILLEGAL;
}
#define RECOGNIZE_FACTORY(symbol, class_name, constructor_name, cid, fp) \
{Symbols::k##symbol##Id, cid, fp, #symbol ", " #cid}, // NOLINT
static struct {
intptr_t symbol_id;
intptr_t cid;
intptr_t finger_print;
const char* name;
} factory_recognizer_list[] = {RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY){
Symbols::kIllegal, -1, -1, NULL}};
#undef RECOGNIZE_FACTORY
intptr_t FactoryRecognizer::ResultCid(const Function& factory) {
ASSERT(factory.IsFactory());
const Class& function_class = Class::Handle(factory.Owner());
const Library& lib = Library::Handle(function_class.library());
ASSERT((lib.raw() == Library::CoreLibrary()) ||
(lib.raw() == Library::TypedDataLibrary()));
const String& factory_name = String::Handle(factory.name());
for (intptr_t i = 0;
factory_recognizer_list[i].symbol_id != Symbols::kIllegal; i++) {
if (String::EqualsIgnoringPrivateKey(
factory_name,
Symbols::Symbol(factory_recognizer_list[i].symbol_id))) {
return factory_recognizer_list[i].cid;
}
}
return kDynamicCid;
}
} // namespace dart

View file

@ -863,7 +863,7 @@ bool ActivationFrame::HandlesException(const Instance& exc_obj) {
handlers = code().exception_handlers();
ASSERT(!handlers.IsNull());
intptr_t num_handlers_checked = 0;
while (try_index != CatchClauseNode::kInvalidTryIndex) {
while (try_index != kInvalidTryIndex) {
// Detect circles in the exception handler data.
num_handlers_checked++;
ASSERT(num_handlers_checked <= handlers.num_entries());
@ -971,7 +971,7 @@ void ActivationFrame::ExtractTokenPositionFromAsyncClosure() {
if (iter.TokenPos() == token_pos_) {
// Match the lowest try index at this token position.
// TODO(johnmccutchan): Is this heuristic precise enough?
if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) {
if (iter.TryIndex() != kInvalidTryIndex) {
if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) {
try_index_ = iter.TryIndex();
}

View file

@ -163,7 +163,6 @@ constexpr bool kDartPrecompiledRuntime = false;
"Stress test async stack traces") \
P(strong, bool, true, "Enable strong mode.") \
P(sync_async, bool, true, "Start `async` functions synchronously.") \
R(support_ast_printer, false, bool, true, "Support the AST printer.") \
R(support_compiler_stats, false, bool, true, "Support compiler stats.") \
R(support_disassembler, false, bool, true, "Support the disassembler.") \
R(support_il_printer, false, bool, true, "Support the IL printer.") \

View file

@ -4,6 +4,7 @@
#include "vm/growable_array.h"
#include "platform/assert.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -5,6 +5,7 @@
#include "vm/dart_api_impl.h"
#include "vm/dart_api_state.h"
#include "vm/object.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -9,6 +9,7 @@
#include "vm/globals.h"
#include "vm/heap/become.h"
#include "vm/heap/heap.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -11342,7 +11342,7 @@ RawObject* Library::GetMetadata(const Object& obj) const {
metadata = kernel::EvaluateMetadata(
field, /* is_annotations_offset = */ obj.IsLibrary());
} else {
metadata = Parser::ParseMetadata(field);
UNREACHABLE();
}
if (metadata.IsArray()) {
ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
@ -13087,7 +13087,7 @@ RawObject* Namespace::GetMetadata() const {
metadata =
kernel::EvaluateMetadata(field, /* is_annotations_offset = */ true);
} else {
metadata = Parser::ParseMetadata(field);
UNREACHABLE();
}
if (metadata.IsArray()) {
ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());

View file

@ -7,6 +7,7 @@
#include "vm/dart_api_impl.h"
#include "vm/dart_api_state.h"
#include "vm/globals.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -9,7 +9,6 @@
#include "lib/invocation_mirror.h"
#include "platform/utils.h"
#include "vm/ast_transformer.h"
#include "vm/bootstrap.h"
#include "vm/class_finalizer.h"
#include "vm/compiler/aot/precompiler.h"
@ -44,31 +43,11 @@
namespace dart {
DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\".");
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
// TODO(floitsch): remove the conditional-directive flag, once we publicly
// committed to the current version.
DEFINE_FLAG(bool,
conditional_directives,
true,
"Enable conditional directives");
DEFINE_FLAG(
bool,
await_is_keyword,
false,
"await and yield are treated as proper keywords in synchronous code.");
DECLARE_FLAG(bool, profile_vm);
DECLARE_FLAG(bool, trace_service);
// Quick access to the current thread, isolate and zone.
#define T (thread())
#define I (isolate())
#define Z (zone())
// Quick synthetic token position.
#define ST(token_pos) ((token_pos).ToSynthetic())
ParsedFunction::ParsedFunction(Thread* thread, const Function& function)
: thread_(thread),
function_(function),
@ -342,45 +321,6 @@ void ParsedFunction::AllocateBytecodeVariables(intptr_t num_stack_locals) {
num_stack_locals_ = num_stack_locals;
}
void Parser::ParseCompilationUnit(const Library& library,
const Script& script) {
UNREACHABLE();
}
void Parser::ParseClass(const Class& cls) {
UNREACHABLE();
}
RawObject* Parser::ParseFunctionParameters(const Function& func) {
UNREACHABLE();
return Object::null();
}
void Parser::ParseFunction(ParsedFunction* parsed_function) {
UNREACHABLE();
}
RawObject* Parser::ParseMetadata(const Field& meta_data) {
UNREACHABLE();
return Object::null();
}
ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) {
UNREACHABLE();
return NULL;
}
ArgumentListNode* Parser::BuildNoSuchMethodArguments(
TokenPosition call_pos,
const String& function_name,
const ArgumentListNode& function_args,
const LocalVariable* temp_for_last_arg,
bool is_super_invocation) {
UNREACHABLE();
return NULL;
}
} // namespace dart
#endif // DART_PRECOMPILED_RUNTIME

View file

@ -18,6 +18,7 @@
#include "vm/kernel.h"
#include "vm/object.h"
#include "vm/raw_object.h"
#include "vm/scopes.h"
#include "vm/token.h"
namespace dart {
@ -48,44 +49,6 @@ struct QualIdent;
class TopLevel;
class RecursionChecker;
// We cache compile time constants during compilation. This allows us
// to look them up when the same code gets compiled again. During
// background compilation, we are not able to evaluate the constants
// so this cache is necessary to support background compilation.
//
// We cache the constants with the script itself. This is helpful during isolate
// reloading, as it allows us to reference the compile time constants associated
// with a particular version of a script. The map key is simply the
// TokenPosition where the constant is defined.
class ConstMapKeyEqualsTraits {
public:
static const char* Name() { return "ConstMapKeyEqualsTraits"; }
static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
const Smi& key1 = Smi::Cast(a);
const Smi& key2 = Smi::Cast(b);
return (key1.Value() == key2.Value());
}
static bool IsMatch(const TokenPosition& key1, const Object& b) {
const Smi& key2 = Smi::Cast(b);
return (key1.value() == key2.Value());
}
static uword Hash(const Object& obj) {
const Smi& key = Smi::Cast(obj);
return HashValue(key.Value());
}
static uword Hash(const TokenPosition& key) { return HashValue(key.value()); }
// Used by CacheConstantValue if a new constant is added to the map.
static RawObject* NewKey(const TokenPosition& key) {
return Smi::New(key.value());
}
private:
static uword HashValue(intptr_t pos) { return pos % (Smi::kMaxValue - 13); }
};
typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
// The class ParsedFunction holds the result of parsing a function.
class ParsedFunction : public ZoneAllocated {
public:
@ -276,29 +239,6 @@ class ParsedFunction : public ZoneAllocated {
class Parser : public ValueObject {
public:
// Parse the top level of a whole script file and register declared classes
// in the given library.
static void ParseCompilationUnit(const Library& library,
const Script& script);
// Parse top level of a class and register all functions/fields.
static void ParseClass(const Class& cls);
static void ParseFunction(ParsedFunction* parsed_function);
// Parse and evaluate the metadata expressions at token_pos in the
// class namespace of class cls (which can be the implicit toplevel
// class if the metadata is at the top-level).
static RawObject* ParseMetadata(const Field& meta_data);
// Build a function containing the initializer expression of the
// given static field.
static ParsedFunction* ParseStaticFieldInitializer(const Field& field);
static void InsertCachedConstantValue(const Script& script,
TokenPosition token_pos,
const Instance& value);
// Parse a function to retrieve parameter information that is not retained in
// the Function object. Returns either an error if the parse fails (which
// could be the case for local functions), or a flat array of entries for each
@ -311,20 +251,8 @@ class Parser : public ValueObject {
kParameterMetadataOffset,
kParameterEntrySize,
};
static RawObject* ParseFunctionParameters(const Function& func);
private:
friend class EffectGraphVisitor; // For BuildNoSuchMethodArguments.
// Build arguments for a NoSuchMethodCall. If LocalVariable temp is not NULL,
// the last argument is stored in temp.
static ArgumentListNode* BuildNoSuchMethodArguments(
TokenPosition call_pos,
const String& function_name,
const ArgumentListNode& function_args,
const LocalVariable* temp,
bool is_super_invocation);
DISALLOW_COPY_AND_ASSIGN(Parser);
};

View file

@ -1,583 +0,0 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/parser.h"
#include "vm/ast_printer.h"
#include "vm/class_finalizer.h"
#include "vm/debugger.h"
#include "vm/debugger_api_impl_test.h"
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/symbols.h"
#include "vm/thread.h"
#include "vm/unit_test.h"
namespace dart {
DECLARE_FLAG(bool, show_invisible_frames);
static void DumpFunction(const Library& lib,
const char* cname,
const char* fname) {
const String& classname =
String::Handle(Symbols::New(Thread::Current(), cname));
String& funcname = String::Handle(String::New(fname));
bool retval;
EXPECT(Isolate::Current() != NULL);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
Class& cls = Class::Handle(lib.LookupClass(classname));
EXPECT(!cls.IsNull());
Function& function =
Function::ZoneHandle(cls.LookupStaticFunction(funcname));
EXPECT(!function.IsNull());
ParsedFunction* parsed_function =
new ParsedFunction(Thread::Current(), function);
Parser::ParseFunction(parsed_function);
EXPECT(parsed_function->node_sequence() != NULL);
printf("Class %s function %s:\n", cname, fname);
if (FLAG_support_ast_printer) {
AstPrinter ast_printer;
ast_printer.PrintFunctionNodes(*parsed_function);
} else {
OS::PrintErr("AST printer not supported.");
}
retval = true;
} else {
retval = false;
}
EXPECT(retval);
}
void CheckField(const Library& lib,
const char* class_name,
const char* field_name,
bool expect_static,
bool is_final) {
const String& classname =
String::Handle(Symbols::New(Thread::Current(), class_name));
Class& cls = Class::Handle(lib.LookupClass(classname));
EXPECT(!cls.IsNull());
String& fieldname = String::Handle(String::New(field_name));
String& functionname = String::Handle();
Function& function = Function::Handle();
Field& field = Field::Handle();
if (expect_static) {
field ^= cls.LookupStaticFieldAllowPrivate(fieldname);
functionname ^= Field::GetterName(fieldname);
function ^= cls.LookupStaticFunction(functionname);
EXPECT(function.IsNull());
functionname ^= Field::SetterName(fieldname);
function ^= cls.LookupStaticFunction(functionname);
EXPECT(function.IsNull());
} else {
field ^= cls.LookupInstanceFieldAllowPrivate(fieldname);
functionname ^= Field::GetterName(fieldname);
function ^= cls.LookupDynamicFunction(functionname);
EXPECT(!function.IsNull());
functionname ^= Field::SetterName(fieldname);
function ^= cls.LookupDynamicFunction(functionname);
EXPECT(is_final ? function.IsNull() : !function.IsNull());
}
EXPECT(!field.IsNull());
EXPECT_EQ(field.is_static(), expect_static);
}
void CheckFunction(const Library& lib,
const char* class_name,
const char* function_name,
bool expect_static) {
const String& classname =
String::Handle(Symbols::New(Thread::Current(), class_name));
Class& cls = Class::Handle(lib.LookupClass(classname));
EXPECT(!cls.IsNull());
String& functionname = String::Handle(String::New(function_name));
Function& function = Function::Handle();
if (expect_static) {
function ^= cls.LookupStaticFunction(functionname);
} else {
function ^= cls.LookupDynamicFunction(functionname);
}
EXPECT(!function.IsNull());
}
ISOLATE_UNIT_TEST_CASE(ParseClassDefinition) {
const char* script_chars =
"class C { } \n"
"class A { \n"
" var f0; \n"
" int f1; \n"
" final f2; \n"
" final int f3, f4; \n"
" static String s1, s2; \n"
" static const int s3 = 8675309; \n"
" static bar(i, [var d = 5]) { return 77; } \n"
" static foo() native \"native_function_name\"; \n"
"} \n";
String& url = String::Handle(String::New("dart-test:Parser_TopLevel"));
String& source = String::Handle(String::New(script_chars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = Library::ZoneHandle(Library::CoreLibrary());
script.Tokenize(String::Handle(String::New("")));
Parser::ParseCompilationUnit(lib, script);
EXPECT(ClassFinalizer::ProcessPendingClasses());
CheckField(lib, "A", "f1", false, false);
CheckField(lib, "A", "f2", false, true);
CheckField(lib, "A", "f3", false, true);
CheckField(lib, "A", "f4", false, true);
CheckField(lib, "A", "s1", true, false);
CheckField(lib, "A", "s2", true, false);
CheckField(lib, "A", "s3", true, true);
CheckFunction(lib, "A", "bar", true);
CheckFunction(lib, "A", "foo", true);
}
ISOLATE_UNIT_TEST_CASE(Parser_TopLevel) {
const char* script_chars =
"class A extends B { \n"
" static bar(var i, [var d = 5]) { return 77; } \n"
" static foo() { return 42; } \n"
" static baz(var i) { var q = 5; return i + q; } \n"
"} \n"
" \n"
"class B { \n"
" static bam(k) { return A.foo(); } \n"
"} \n";
String& url = String::Handle(String::New("dart-test:Parser_TopLevel"));
String& source = String::Handle(String::New(script_chars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = Library::ZoneHandle(Library::CoreLibrary());
script.Tokenize(String::Handle(String::New("")));
Parser::ParseCompilationUnit(lib, script);
EXPECT(ClassFinalizer::ProcessPendingClasses());
DumpFunction(lib, "A", "foo");
DumpFunction(lib, "A", "bar");
DumpFunction(lib, "A", "baz");
DumpFunction(lib, "B", "bam");
}
#ifndef PRODUCT
static char* saved_vars = NULL;
static char* SkipIndex(const char* input) {
char* output_buffer = new char[strlen(input)];
char* output = output_buffer;
while (input[0] != '\0') {
const char* index_pos = strstr(input, "index=");
if (index_pos == NULL) {
while (input[0] != '\0') {
*output++ = *input++;
}
break;
}
// Copy prefix until "index="
while (input < index_pos) {
*output++ = *input++;
}
// Skip until space.
input += strcspn(input, " ");
// Skip until next non-space.
input += strspn(input, " ");
}
output[0] = '\0';
return output_buffer;
}
// Saves the var descriptors for all frames on the stack as a string.
static void SaveVars(Dart_IsolateId isolate_id,
intptr_t bp_id,
const Dart_CodeLocation& loc) {
TransitionNativeToVM transition(Thread::Current());
DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace();
intptr_t num_frames = stack->Length();
const int kBufferLen = 2048;
char* buffer = reinterpret_cast<char*>(malloc(kBufferLen));
char* pos = buffer;
LocalVarDescriptors& var_desc = LocalVarDescriptors::Handle();
for (intptr_t i = 0; i < num_frames; i++) {
ActivationFrame* frame = stack->FrameAt(i);
var_desc = frame->code().GetLocalVarDescriptors();
const char* var_str = SkipIndex(var_desc.ToCString());
const char* function_str =
String::Handle(frame->function().QualifiedUserVisibleName())
.ToCString();
pos += Utils::SNPrint(pos, (kBufferLen - (pos - buffer)), "%s\n%s",
function_str, var_str);
delete[] var_str;
}
pos[0] = '\0';
if (saved_vars != NULL) {
free(saved_vars);
}
saved_vars = buffer;
}
// Uses the debugger to pause the program and capture the variable
// descriptors for all frames on the stack.
static char* CaptureVarsAtLine(Dart_Handle lib, const char* entry, int line) {
EXPECT(ClassFinalizer::ProcessPendingClasses());
bool saved_flag = FLAG_show_invisible_frames;
FLAG_show_invisible_frames = true;
Dart_SetPausedEventHandler(SaveVars);
EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), line));
saved_vars = NULL;
EXPECT_VALID(Dart_Invoke(lib, NewString(entry), 0, NULL));
char* tmp = saved_vars;
saved_vars = NULL;
FLAG_show_invisible_frames = saved_flag;
return tmp;
}
TEST_CASE(Parser_AllocateVariables_CapturedVar) {
const char* kScriptChars =
"int main() {\n"
" var value = 11;\n"
" int f(var param) {\n"
" return param + value;\n" // line 4
" }\n"
" return f(22);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
char* vars = CaptureVarsAtLine(lib, "main", 4);
EXPECT_STREQ(
// function f uses one ctx var at (0); doesn't save ctx.
"main.f\n"
" 0 ContextLevel level=0 begin=0 end=56\n"
" 1 ContextVar level=0 begin=14 end=28 name=value\n"
" 2 StackVar scope=1 begin=16 end=28 name=param\n"
" 3 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// function main uses one ctx var at (1); saves caller ctx.
"main\n"
" 0 ContextLevel level=0 begin=0 end=10\n"
" 1 ContextLevel level=1 begin=12 end=20\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 3 ContextVar level=1 begin=10 end=38 name=value\n"
" 4 StackVar scope=2 begin=12 end=38 name=f\n",
vars);
free(vars);
}
TEST_CASE(Parser_AllocateVariables_NestedCapturedVar) {
const char* kScriptChars =
"int a() {\n"
" int b() {\n"
" var value = 11;\n"
" int c() {\n"
" return value;\n" // line 5
" }\n"
" return c();\n"
" }\n"
" return b();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
char* vars = CaptureVarsAtLine(lib, "a", 5);
EXPECT_STREQ(
// Innermost function uses captured variable 'value' from middle
// function.
"a.b.c\n"
" 0 ContextLevel level=0 begin=0 end=54\n"
" 1 ContextVar level=0 begin=20 end=30 name=value\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Middle function saves the entry context. Notice that this
// happens here and not in the outermost function. We always
// save the entry context at the last possible moment.
"a.b\n"
" 0 ContextLevel level=0 begin=0 end=50\n"
" 1 ContextLevel level=1 begin=52 end=60\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 3 ContextVar level=1 begin=16 end=38 name=value\n"
" 4 StackVar scope=2 begin=18 end=38 name=c\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Outermost function neglects to save the entry context. We
// don't save the entry context if the function has no captured
// variables.
"a\n"
" 0 ContextLevel level=0 begin=0 end=18\n"
" 1 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 2 StackVar scope=2 begin=6 end=46 name=b\n",
vars);
free(vars);
}
TEST_CASE(Parser_AllocateVariables_TwoChains) {
const char* kScriptChars =
"int a() {\n"
" var value1 = 11;\n"
" int b() {\n"
" int aa() {\n"
" var value2 = 12;\n"
" int bb() {\n"
" return value2;\n" // line 7
" }\n"
" return bb();\n"
" }\n"
" return value1 + aa();\n"
" }\n"
" return b();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
char* vars = CaptureVarsAtLine(lib, "a", 7);
EXPECT_STREQ(
// bb captures only value2 from aa. No others.
"a.b.aa.bb\n"
" 0 ContextLevel level=0 begin=0 end=54\n"
" 1 ContextVar level=0 begin=35 end=46 name=value2\n"
" 2 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
// aa shares value2. Notice that we save the entry ctx instead
// of chaining from b. This keeps us from holding onto closures
// that we would never access.
"a.b.aa\n"
" 0 ContextLevel level=0 begin=0 end=50\n"
" 1 ContextLevel level=1 begin=52 end=60\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 3 ContextVar level=1 begin=30 end=55 name=value2\n"
" 4 StackVar scope=2 begin=32 end=55 name=bb\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
// b captures value1 from a.
"a.b\n"
" 0 ContextLevel level=0 begin=0 end=60\n"
" 1 ContextVar level=0 begin=14 end=65 name=value1\n"
" 2 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 3 StackVar scope=2 begin=18 end=65 name=aa\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
// a shares value1, saves entry ctx.
"a\n"
" 0 ContextLevel level=0 begin=0 end=10\n"
" 1 ContextLevel level=1 begin=12 end=20\n"
" 2 CurrentCtx scope=0 begin=0 end=0"
" name=:current_context_var\n"
" 3 ContextVar level=1 begin=10 end=73 name=value1\n"
" 4 StackVar scope=2 begin=12 end=73 name=b\n",
vars);
free(vars);
}
TEST_CASE(Parser_AllocateVariables_Issue7681) {
// This is a distilled version of the program from Issue 7681.
//
// When we create the closure at line 11, we need to make sure to
// save the entry context instead of chaining to the parent context.
//
// This test is somewhat redundant with CapturedVarChain but
// included for good measure.
const char* kScriptChars =
"class X {\n"
" Function onX;\n"
"}\n"
"\n"
"class Y {\n"
" Function onY;\n"
"}\n"
"\n"
"void doIt() {\n"
" var x = new X();\n"
" x.onX = (y) {\n"
" y.onY = () {\n" // line 12
" return y;\n"
" };\n"
" };\n"
" x.onX(new Y());\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
char* vars = CaptureVarsAtLine(lib, "doIt", 12);
EXPECT_STREQ(
// This frame saves the entry context instead of chaining. Good.
"doIt.<anonymous closure>\n"
" 0 ContextLevel level=0 begin=0 end=0\n"
" 1 ContextLevel level=1 begin=48 end=56\n"
" 2 ContextVar level=1 begin=44 end=67 name=y\n"
" 3 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
"X.onX\n"
" 0 ContextLevel level=0 begin=0 end=14\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// No context is saved here since no vars are captured.
"doIt\n"
" 0 ContextLevel level=0 begin=0 end=22\n"
" 1 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 2 StackVar scope=2 begin=36 end=83 name=x\n",
vars);
free(vars);
}
TEST_CASE(Parser_AllocateVariables_CaptureLoopVar) {
// This test verifies that...
//
// https://code.google.com/p/dart/issues/detail?id=18561
//
// ...stays fixed.
const char* kScriptChars =
"int outer() {\n"
" for(int i = 0; i < 1; i++) {\n"
" var value = 11 + i;\n"
" int inner() {\n"
" return value;\n" // line 5
" }\n"
" return inner();\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
char* vars = CaptureVarsAtLine(lib, "outer", 5);
EXPECT_STREQ(
// inner function captures variable value. That's fine.
"outer.inner\n"
" 0 ContextLevel level=0 begin=0 end=54\n"
" 1 ContextVar level=0 begin=34 end=44 name=value\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Closure call saves current context.
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// The outer function saves the entry context, even though the
// captured variable is in a loop. Good.
"outer\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 ContextLevel level=1 begin=14 end=22\n"
" 2 ContextLevel level=0 begin=24 end=38\n"
" 3 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 4 StackVar scope=3 begin=12 end=53 name=i\n"
" 5 ContextVar level=1 begin=29 end=53 name=value\n"
" 6 StackVar scope=4 begin=31 end=53 name=inner\n",
vars);
free(vars);
}
TEST_CASE(Parser_AllocateVariables_MiddleChain) {
const char* kScriptChars =
"a() {\n"
" int x = 11;\n"
" b() {\n"
" for (int i = 0; i < 1; i++) {\n"
" int d() {\n"
" return i;\n"
" }\n"
" }\n"
" int c() {\n"
" return x + 1;\n" // line 10
" }\n"
" return c();\n"
" }\n"
" return b();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
char* vars = CaptureVarsAtLine(lib, "a", 10);
EXPECT_STREQ(
"a.b.c\n"
" 0 ContextLevel level=0 begin=0 end=56\n"
" 1 ContextVar level=0 begin=52 end=65 name=x\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
// Doesn't save the entry context. Chains to parent instead.
"a.b\n"
" 0 ContextLevel level=0 begin=0 end=50\n"
" 1 ContextLevel level=1 begin=52 end=76\n"
" 2 ContextLevel level=0 begin=78 end=84\n"
" 3 ContextVar level=0 begin=12 end=74 name=x\n"
" 4 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 5 StackVar scope=2 begin=49 end=74 name=c\n"
" 6 ContextVar level=1 begin=23 end=49 name=i\n"
" 7 StackVar scope=4 begin=34 end=49 name=d\n"
"_Closure.call\n"
" 0 ContextLevel level=0 begin=0 end=12\n"
" 1 StackVar scope=1 begin=-1 end=0 name=this\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
"a\n"
" 0 ContextLevel level=0 begin=0 end=10\n"
" 1 ContextLevel level=1 begin=12 end=20\n"
" 2 CurrentCtx scope=0 begin=0 end=0 name=:current_context_var\n"
" 3 ContextVar level=1 begin=9 end=82 name=x\n"
" 4 StackVar scope=2 begin=11 end=82 name=b\n",
vars);
free(vars);
}
#endif // !PRODUCT
} // namespace dart

View file

@ -10,6 +10,7 @@
#include "vm/profiler.h"
#include "vm/profiler_service.h"
#include "vm/source_report.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -39,7 +39,6 @@
namespace dart {
static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex;
static const intptr_t kMinStackSize = 512;
/*

View file

@ -4,7 +4,6 @@
#include "vm/runtime_entry.h"
#include "vm/ast.h"
#include "vm/code_patcher.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/frontend/bytecode_reader.h"

View file

@ -4,7 +4,6 @@
#include "vm/scopes.h"
#include "platform/assert.h"
#include "vm/ast.h"
#include "vm/unit_test.h"
namespace dart {

View file

@ -349,9 +349,6 @@ class SnapshotReader : public BaseReader {
// Get an object from the backward references list.
Object* GetBackRef(intptr_t id);
// Read a script snapshot.
RawObject* ReadScriptSnapshot();
// Read version number of snapshot and verify.
RawApiError* VerifyVersionAndFeatures(Isolate* isolate);

View file

@ -12,7 +12,6 @@
#include "platform/globals.h"
#include "vm/ast_printer.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/assembler/disassembler.h"
#include "vm/compiler/jit/compiler.h"
@ -821,44 +820,6 @@ void AssemblerTest::Assemble() {
#endif // !PRODUCT
}
CodeGenTest::CodeGenTest(const char* name)
: function_(Function::ZoneHandle()),
node_sequence_(new SequenceNode(TokenPosition::kMinSource,
new LocalScope(NULL, 0, 0))),
default_parameter_values_(new ZoneGrowableArray<const Instance*>()) {
ASSERT(name != NULL);
const String& function_name =
String::ZoneHandle(Symbols::New(Thread::Current(), name));
// Add function to a class and that class to the class dictionary so that
// frame walking can be used.
Library& lib = Library::Handle(Library::CoreLibrary());
const Class& cls = Class::ZoneHandle(Class::New(
lib, function_name, Script::Handle(), TokenPosition::kMinSource));
function_ =
Function::New(function_name, RawFunction::kRegularFunction, true, false,
false, false, false, cls, TokenPosition::kMinSource);
function_.set_result_type(Type::Handle(Type::DynamicType()));
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function_);
cls.SetFunctions(functions);
lib.AddClass(cls);
}
void CodeGenTest::Compile() {
if (function_.HasCode()) return;
ParsedFunction* parsed_function =
new ParsedFunction(Thread::Current(), function_);
parsed_function->SetNodeSequence(node_sequence_);
parsed_function->set_default_parameter_values(default_parameter_values_);
node_sequence_->scope()->AddVariable(parsed_function->current_context_var());
parsed_function->EnsureExpressionTemp();
node_sequence_->scope()->AddVariable(parsed_function->expression_temp_var());
parsed_function->AllocateVariables();
const Error& error =
Error::Handle(Compiler::CompileParsedFunction(parsed_function));
EXPECT(error.IsNull());
}
bool CompilerTest::TestCompileScript(const Library& library,
const Script& script) {
Isolate* isolate = Isolate::Current();

View file

@ -9,9 +9,9 @@
#include "platform/globals.h"
#include "vm/ast.h"
#include "vm/dart.h"
#include "vm/dart_api_state.h"
#include "vm/dart_entry.h"
#include "vm/globals.h"
#include "vm/heap/heap.h"
#include "vm/isolate.h"
@ -115,70 +115,6 @@
} \
static void AssemblerTestRun##name(AssemblerTest* test)
// Populate node list with AST nodes.
#define CODEGEN_TEST_GENERATE(name, test) \
static void CodeGenTestGenerate##name(CodeGenTest* test)
// Populate node list with AST nodes, possibly using the provided function
// object built by a previous CODEGEN_TEST_GENERATE.
#define CODEGEN_TEST2_GENERATE(name, function, test) \
static void CodeGenTestGenerate##name(const Function& function, \
CodeGenTest* test)
// Pass the name of test and the expected results as RawObject.
#define CODEGEN_TEST_RUN(name, expected) \
static void CodeGenTestRun##name(const Function& function); \
ISOLATE_UNIT_TEST_CASE(name) { \
CodeGenTest __test__("" #name); \
CodeGenTestGenerate##name(&__test__); \
__test__.Compile(); \
CodeGenTestRun##name(__test__.function()); \
} \
static void CodeGenTestRun##name(const Function& function) { \
Object& result = Object::Handle(); \
result = DartEntry::InvokeFunction(function, Object::empty_array()); \
EXPECT(!result.IsError()); \
Instance& actual = Instance::Handle(); \
actual ^= result.raw(); \
EXPECT(actual.CanonicalizeEquals(Instance::Handle(expected))); \
}
// Pass the name of test, and use the generated function to call it
// and evaluate its result.
#define CODEGEN_TEST_RAW_RUN(name, function) \
static void CodeGenTestRun##name(const Function& function); \
ISOLATE_UNIT_TEST_CASE(name) { \
CodeGenTest __test__("" #name); \
CodeGenTestGenerate##name(&__test__); \
__test__.Compile(); \
CodeGenTestRun##name(__test__.function()); \
} \
static void CodeGenTestRun##name(const Function& function)
// Generate code for two sequences of AST nodes and execute the first one.
// The first one may reference the Function object generated by the second one.
#define CODEGEN_TEST2_RUN(name1, name2, expected) \
static void CodeGenTestRun##name1(const Function& function); \
ISOLATE_UNIT_TEST_CASE(name1) { \
/* Generate code for name2 */ \
CodeGenTest __test2__("" #name2); \
CodeGenTestGenerate##name2(&__test2__); \
__test2__.Compile(); \
/* Generate code for name1, providing function2 */ \
CodeGenTest __test1__("" #name1); \
CodeGenTestGenerate##name1(__test2__.function(), &__test1__); \
__test1__.Compile(); \
CodeGenTestRun##name1(__test1__.function()); \
} \
static void CodeGenTestRun##name1(const Function& function) { \
Object& result = Object::Handle(); \
result = DartEntry::InvokeFunction(function, Object::empty_array()); \
EXPECT(!result.IsError()); \
Instance& actual = Instance::Handle(); \
actual ^= result.raw(); \
EXPECT(actual.CanonicalizeEquals(Instance::Handle(expected))); \
}
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
#if defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
// Running on actual ARM hardware, execute code natively.
@ -639,31 +575,6 @@ class AssemblerTest {
DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
};
class CodeGenTest {
public:
explicit CodeGenTest(const char* name);
~CodeGenTest() {}
// Accessors.
const Function& function() const { return function_; }
SequenceNode* node_sequence() const { return node_sequence_; }
void set_default_parameter_values(ZoneGrowableArray<const Instance*>* value) {
default_parameter_values_ = value;
}
// Compile test and set code in function.
void Compile();
private:
Function& function_;
SequenceNode* node_sequence_;
ZoneGrowableArray<const Instance*>* default_parameter_values_;
DISALLOW_COPY_AND_ASSIGN(CodeGenTest);
};
class CompilerTest : public AllStatic {
public:
// Test the Compiler::CompileScript functionality by checking the return

View file

@ -7,12 +7,7 @@
vm_sources = [
"allocation.cc",
"allocation.h",
"ast.cc",
"ast.h",
"ast_printer.cc",
"ast_printer.h",
"ast_transformer.cc",
"ast_transformer.h",
"base64.cc",
"base64.h",
"base_isolate.h",
@ -359,8 +354,6 @@ vm_sources = [
vm_sources_tests = [
"allocation_test.cc",
"assert_test.cc",
"ast_printer_test.cc",
"ast_test.cc",
"atomic_test.cc",
"base64_test.cc",
"benchmark_test.cc",
@ -419,7 +412,6 @@ vm_sources_tests = [
"object_test.cc",
"object_x64_test.cc",
"os_test.cc",
"parser_test.cc",
"port_test.cc",
"profiler_test.cc",
"regexp_test.cc",