ba0f59d1bc
The optimizing compiler currently recognizes a certain frequent native methods like array length or string length and provides an inlined implementation. Inlining does currently not work for polymorphic call sites of these methods. This CL enables also polymorphic inlining in the case of .length getters for arrays and strings. 1. The method is recognized at flow graph build time. The builder creates the body of the method for both compilers (non-optimizing and optimizing). Native methods that are not recognized, are translated as before using a NativeCall IL instruction. 2. The flow graph inliner handles recognized methods in the same manner as normal methods. Until now intrinsic and recognized method could not be inlined. This CL enables it. 3. There is no need for an intrinsic assembly implementation because recognized methods have an IL implementation that does not call into the C++ runtime. I left the intrinsics in for now, but they can be removed if there is not noticable performance benefit anymore. 4. The inlining heuristics are tweaked in a way that enables more aggressive inlining of recognized methods: +1 level of inlining depths, call sites of recognized methods are not counted in the inlining heuristic. R=kmillikin@google.com, srdjan@google.com Review URL: https://codereview.chromium.org//22839003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@26429 260f80e4-7a28-3924-810f-c04153c831b5
1762 lines
51 KiB
C++
1762 lines
51 KiB
C++
// 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.
|
|
|
|
#ifndef VM_AST_H_
|
|
#define VM_AST_H_
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/allocation.h"
|
|
#include "vm/growable_array.h"
|
|
#include "vm/scopes.h"
|
|
#include "vm/object.h"
|
|
#include "vm/native_entry.h"
|
|
#include "vm/token.h"
|
|
|
|
namespace dart {
|
|
|
|
#define NODE_LIST(V) \
|
|
V(ReturnNode, "return") \
|
|
V(LiteralNode, "literal") \
|
|
V(TypeNode, "type") \
|
|
V(AssignableNode, "assignable") \
|
|
V(BinaryOpNode, "binop") \
|
|
V(BinaryOpWithMask32Node, "binop with mask 32") \
|
|
V(ComparisonNode, "compare") \
|
|
V(UnaryOpNode, "unaryop") \
|
|
V(ConditionalExprNode, "?:") \
|
|
V(IfNode, "if") \
|
|
V(SwitchNode, "switch") \
|
|
V(CaseNode, "case") \
|
|
V(WhileNode, "while") \
|
|
V(DoWhileNode, "dowhile") \
|
|
V(ForNode, "for") \
|
|
V(JumpNode, "jump") \
|
|
V(ArgumentListNode, "args") \
|
|
V(ArrayNode, "array") \
|
|
V(ClosureNode, "closure") \
|
|
V(InstanceCallNode, "instance call") \
|
|
V(StaticCallNode, "static call") \
|
|
V(ClosureCallNode, "closure call") \
|
|
V(CloneContextNode, "clone context") \
|
|
V(ConstructorCallNode, "constructor call") \
|
|
V(InstanceGetterNode, "instance getter call") \
|
|
V(InstanceSetterNode, "instance setter call") \
|
|
V(StaticGetterNode, "static getter") \
|
|
V(StaticSetterNode, "static setter") \
|
|
V(NativeBodyNode, "native body") \
|
|
V(PrimaryNode, "primary") \
|
|
V(LoadLocalNode, "load local") \
|
|
V(StoreLocalNode, "store local") \
|
|
V(LoadInstanceFieldNode, "load field") \
|
|
V(StoreInstanceFieldNode, "store field") \
|
|
V(LoadStaticFieldNode, "load static field") \
|
|
V(StoreStaticFieldNode, "store static field") \
|
|
V(LoadIndexedNode, "load indexed") \
|
|
V(StoreIndexedNode, "store indexed") \
|
|
V(SequenceNode, "seq") \
|
|
V(LetNode, "let") \
|
|
V(CatchClauseNode, "catch clause block") \
|
|
V(TryCatchNode, "try catch block") \
|
|
V(ThrowNode, "throw") \
|
|
V(InlinedFinallyNode, "inlined finally") \
|
|
|
|
|
|
#define DEFINE_FORWARD_DECLARATION(type, name) class type;
|
|
NODE_LIST(DEFINE_FORWARD_DECLARATION)
|
|
#undef DEFINE_FORWARD_DECLARATION
|
|
|
|
|
|
// Abstract class to implement an AST node visitor. An example is AstPrinter.
|
|
class AstNodeVisitor : public ValueObject {
|
|
public:
|
|
AstNodeVisitor() {}
|
|
virtual ~AstNodeVisitor() {}
|
|
|
|
#define DEFINE_VISITOR_FUNCTION(type, name) \
|
|
virtual void Visit##type(type* node) { }
|
|
NODE_LIST(DEFINE_VISITOR_FUNCTION)
|
|
#undef DEFINE_VISITOR_FUNCTION
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(AstNodeVisitor);
|
|
};
|
|
|
|
|
|
#define DECLARE_COMMON_NODE_FUNCTIONS(type) \
|
|
virtual void Visit(AstNodeVisitor* visitor); \
|
|
virtual const char* ShortName() const; \
|
|
virtual bool Is##type() const { return true; } \
|
|
virtual type* As##type() { return this; }
|
|
|
|
|
|
class AstNode : public ZoneAllocated {
|
|
public:
|
|
explicit AstNode(intptr_t token_pos)
|
|
: token_pos_(token_pos) {
|
|
ASSERT(token_pos_ >= 0);
|
|
}
|
|
|
|
intptr_t token_pos() const { return token_pos_; }
|
|
|
|
#define AST_TYPE_CHECK(type, name) \
|
|
virtual bool Is##type() const { return false; } \
|
|
virtual type* As##type() { return NULL; }
|
|
NODE_LIST(AST_TYPE_CHECK)
|
|
#undef AST_TYPE_CHECK
|
|
|
|
virtual void Visit(AstNodeVisitor* visitor) = 0;
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const = 0;
|
|
virtual const char* ShortName() const = 0;
|
|
|
|
// 'ShortName' is predefined for each AstNode and is the default
|
|
// implementation of "Name()". Each AST node can override the function
|
|
// "Name" to do more complex name composition.
|
|
virtual const char* Name() const {
|
|
return ShortName();
|
|
}
|
|
|
|
// Convert the node into an assignment node using the rhs which is passed in,
|
|
// this is typically used for converting nodes like LoadLocalNode,
|
|
// LoadStaticFieldNode, InstanceGetterNode etc. which were created during
|
|
// parsing as the assignment context was not known yet at that time.
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs) {
|
|
return NULL; // By default all nodes are not assignable.
|
|
}
|
|
|
|
// Return NULL if 'unary_op_kind' can't be applied.
|
|
virtual AstNode* ApplyUnaryOp(Token::Kind unary_op_kind) {
|
|
return NULL;
|
|
}
|
|
|
|
virtual bool IsPotentiallyConst() const { return false; }
|
|
|
|
// Analyzes an expression to determine whether it is a compile time
|
|
// constant or not. Returns NULL if the expression is not a compile time
|
|
// constant. Otherwise, the return value is an approximation of the
|
|
// actual value of the const expression. The type of the returned value
|
|
// corresponds to the type of the const expression and is either
|
|
// Number, Integer, String, Bool, or anything else (not a subtype of
|
|
// the former).
|
|
virtual const Instance* EvalConstExpr() const { return NULL; }
|
|
|
|
protected:
|
|
friend class ParsedFunction;
|
|
|
|
private:
|
|
const intptr_t token_pos_;
|
|
DISALLOW_COPY_AND_ASSIGN(AstNode);
|
|
};
|
|
|
|
|
|
class SequenceNode : public AstNode {
|
|
public:
|
|
SequenceNode(intptr_t token_pos, LocalScope* scope)
|
|
: AstNode(token_pos),
|
|
scope_(scope),
|
|
nodes_(4),
|
|
label_(NULL) {
|
|
}
|
|
|
|
LocalScope* scope() const { return scope_; }
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
void set_label(SourceLabel* value) { label_ = value; }
|
|
|
|
void VisitChildren(AstNodeVisitor* visitor) const;
|
|
|
|
void Add(AstNode* node) { nodes_.Add(node); }
|
|
intptr_t length() const { return nodes_.length(); }
|
|
AstNode* NodeAt(intptr_t index) const { return nodes_[index]; }
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(SequenceNode);
|
|
|
|
// Collects all nodes accessible from this sequence node into array 'nodes'.
|
|
void CollectAllNodes(GrowableArray<AstNode*>* nodes);
|
|
|
|
private:
|
|
LocalScope* scope_;
|
|
GrowableArray<AstNode*> nodes_;
|
|
SourceLabel* label_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SequenceNode);
|
|
};
|
|
|
|
|
|
class CloneContextNode : public AstNode {
|
|
public:
|
|
explicit CloneContextNode(intptr_t token_pos)
|
|
: AstNode(token_pos) {
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(CloneContextNode);
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(CloneContextNode);
|
|
};
|
|
|
|
|
|
class ArgumentListNode : public AstNode {
|
|
public:
|
|
explicit ArgumentListNode(intptr_t token_pos)
|
|
: AstNode(token_pos),
|
|
nodes_(4),
|
|
names_(Array::ZoneHandle()) {
|
|
}
|
|
|
|
void VisitChildren(AstNodeVisitor* visitor) const;
|
|
|
|
void Add(AstNode* node) {
|
|
nodes_.Add(node);
|
|
}
|
|
intptr_t length() const { return nodes_.length(); }
|
|
AstNode* NodeAt(intptr_t index) const { return nodes_[index]; }
|
|
void SetNodeAt(intptr_t index, AstNode* node) { nodes_[index] = node; }
|
|
const Array& names() const {
|
|
return names_;
|
|
}
|
|
void set_names(const Array& names) {
|
|
names_ = names.raw();
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ArgumentListNode);
|
|
|
|
private:
|
|
GrowableArray<AstNode*> nodes_;
|
|
Array& names_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ArgumentListNode);
|
|
};
|
|
|
|
|
|
class LetNode : public AstNode {
|
|
public:
|
|
explicit LetNode(intptr_t token_pos);
|
|
|
|
LocalVariable* TempAt(intptr_t i) const { return vars_[i]; }
|
|
AstNode* InitializerAt(intptr_t i) const { return initializers_[i]; }
|
|
|
|
LocalVariable* AddInitializer(AstNode* node);
|
|
|
|
const GrowableArray<AstNode*>& nodes() const { return nodes_; }
|
|
|
|
void AddNode(AstNode* node) { nodes_.Add(node); }
|
|
|
|
intptr_t num_temps() const {
|
|
return vars_.length();
|
|
}
|
|
|
|
void VisitChildren(AstNodeVisitor* visitor) const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(LetNode);
|
|
|
|
private:
|
|
GrowableArray<LocalVariable*> vars_;
|
|
GrowableArray<AstNode*> initializers_;
|
|
GrowableArray<AstNode*> nodes_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(LetNode);
|
|
};
|
|
|
|
|
|
class ArrayNode : public AstNode {
|
|
public:
|
|
ArrayNode(intptr_t token_pos, const AbstractType& type)
|
|
: AstNode(token_pos),
|
|
type_(type),
|
|
elements_() {
|
|
CheckFields();
|
|
}
|
|
ArrayNode(intptr_t token_pos,
|
|
const AbstractType& type,
|
|
const GrowableArray<AstNode*>& elements)
|
|
: AstNode(token_pos),
|
|
type_(type),
|
|
elements_(elements.length()) {
|
|
CheckFields();
|
|
for (intptr_t i = 0; i < elements.length(); i++) {
|
|
elements_.Add(elements[i]);
|
|
}
|
|
}
|
|
|
|
void VisitChildren(AstNodeVisitor* visitor) const;
|
|
|
|
intptr_t length() const { return elements_.length(); }
|
|
|
|
AstNode* ElementAt(intptr_t index) const { return elements_[index]; }
|
|
void SetElementAt(intptr_t index, AstNode* value) {
|
|
elements_[index] = value;
|
|
}
|
|
void AddElement(AstNode* expr) { elements_.Add(expr); }
|
|
|
|
const AbstractType& type() const { return type_; }
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ArrayNode);
|
|
|
|
private:
|
|
const AbstractType& type_;
|
|
GrowableArray<AstNode*> elements_;
|
|
|
|
void CheckFields() {
|
|
ASSERT(type_.IsZoneHandle());
|
|
ASSERT(!type_.IsNull());
|
|
ASSERT(type_.IsFinalized());
|
|
// Type may be uninstantiated when creating a generic list literal.
|
|
ASSERT((type_.arguments() == AbstractTypeArguments::null()) ||
|
|
((AbstractTypeArguments::Handle(type_.arguments()).Length() == 1)));
|
|
}
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ArrayNode);
|
|
};
|
|
|
|
|
|
class LiteralNode : public AstNode {
|
|
public:
|
|
LiteralNode(intptr_t token_pos, const Instance& literal)
|
|
: AstNode(token_pos), literal_(literal) {
|
|
ASSERT(literal_.IsNotTemporaryScopedHandle());
|
|
ASSERT(literal_.IsSmi() || literal_.IsOld());
|
|
#if defined(DEBUG)
|
|
if (literal_.IsString()) {
|
|
ASSERT(String::Cast(literal_).IsSymbol());
|
|
}
|
|
#endif // defined(DEBUG)
|
|
ASSERT(literal_.IsNull() ||
|
|
Class::Handle(literal_.clazz()).is_finalized() ||
|
|
Class::Handle(literal_.clazz()).is_prefinalized());
|
|
}
|
|
|
|
const Instance& literal() const { return literal_; }
|
|
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual const Instance* EvalConstExpr() const {
|
|
return &literal();
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
virtual AstNode* ApplyUnaryOp(Token::Kind unary_op_kind);
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(LiteralNode);
|
|
|
|
private:
|
|
const Instance& literal_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LiteralNode);
|
|
};
|
|
|
|
|
|
class TypeNode : public AstNode {
|
|
public:
|
|
TypeNode(intptr_t token_pos, const AbstractType& type)
|
|
: AstNode(token_pos), type_(type) {
|
|
ASSERT(type_.IsZoneHandle());
|
|
ASSERT(!type_.IsNull());
|
|
ASSERT(type_.IsFinalized());
|
|
}
|
|
|
|
const AbstractType& type() const { return type_; }
|
|
|
|
virtual const char* Name() const;
|
|
|
|
virtual const Instance* EvalConstExpr() const {
|
|
if (!type_.IsInstantiated() || type_.IsMalformed()) {
|
|
return NULL;
|
|
}
|
|
return &type();
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(TypeNode);
|
|
|
|
private:
|
|
const AbstractType& type_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(TypeNode);
|
|
};
|
|
|
|
|
|
class AssignableNode : public AstNode {
|
|
public:
|
|
AssignableNode(intptr_t token_pos,
|
|
AstNode* expr,
|
|
const AbstractType& type,
|
|
const String& dst_name)
|
|
: AstNode(token_pos), expr_(expr), type_(type), dst_name_(dst_name) {
|
|
ASSERT(expr_ != NULL);
|
|
ASSERT(type_.IsZoneHandle());
|
|
ASSERT(!type_.IsNull());
|
|
ASSERT(type_.IsFinalized());
|
|
ASSERT(dst_name_.IsNotTemporaryScopedHandle());
|
|
}
|
|
|
|
AstNode* expr() const { return expr_; }
|
|
const AbstractType& type() const { return type_; }
|
|
const String& dst_name() const { return dst_name_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
expr()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(AssignableNode);
|
|
|
|
private:
|
|
AstNode* expr_;
|
|
const AbstractType& type_;
|
|
const String& dst_name_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(AssignableNode);
|
|
};
|
|
|
|
|
|
class ClosureNode : public AstNode {
|
|
public:
|
|
ClosureNode(intptr_t token_pos,
|
|
const Function& function,
|
|
AstNode* receiver, // Non-null for implicit instance closures.
|
|
LocalScope* scope) // Null for implicit closures.
|
|
: AstNode(token_pos),
|
|
function_(function),
|
|
receiver_(receiver),
|
|
scope_(scope) {
|
|
ASSERT(function_.IsZoneHandle());
|
|
ASSERT((function_.IsNonImplicitClosureFunction() &&
|
|
(receiver_ == NULL) && (scope_ != NULL)) ||
|
|
(function_.IsImplicitInstanceClosureFunction() &&
|
|
(receiver_ != NULL) && (scope_ == NULL)) ||
|
|
(function_.IsImplicitStaticClosureFunction() &&
|
|
(receiver_ == NULL) && (scope_ == NULL)));
|
|
}
|
|
|
|
const Function& function() const { return function_; }
|
|
AstNode* receiver() const { return receiver_; }
|
|
LocalScope* scope() const { return scope_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
if (receiver() != NULL) {
|
|
receiver()->Visit(visitor);
|
|
}
|
|
}
|
|
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual const Instance* EvalConstExpr() const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ClosureNode);
|
|
|
|
private:
|
|
const Function& function_;
|
|
AstNode* receiver_;
|
|
LocalScope* scope_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureNode);
|
|
};
|
|
|
|
|
|
// Primary nodes hold identifiers or values (library, class or function)
|
|
// resolved from an identifier. Primary nodes should not ever make it to the
|
|
// code generation phase as they will be transformed into the correct call or
|
|
// field access nodes.
|
|
class PrimaryNode : public AstNode {
|
|
public:
|
|
PrimaryNode(intptr_t token_pos, const Object& primary)
|
|
: AstNode(token_pos), primary_(primary) {
|
|
ASSERT(primary_.IsNotTemporaryScopedHandle());
|
|
}
|
|
|
|
const Object& primary() const { return primary_; }
|
|
|
|
bool IsSuper() const {
|
|
return primary().IsString() && (primary().raw() == Symbols::Super().raw());
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(PrimaryNode);
|
|
|
|
private:
|
|
const Object& primary_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(PrimaryNode);
|
|
};
|
|
|
|
|
|
class ReturnNode : public AstNode {
|
|
public:
|
|
// Return from a void function returns the null object.
|
|
explicit ReturnNode(intptr_t token_pos)
|
|
: AstNode(token_pos),
|
|
value_(new LiteralNode(token_pos, Instance::ZoneHandle())),
|
|
inlined_finally_list_() { }
|
|
// Return from a non-void function.
|
|
ReturnNode(intptr_t token_pos,
|
|
AstNode* value)
|
|
: AstNode(token_pos), value_(value), inlined_finally_list_() {
|
|
ASSERT(value_ != NULL);
|
|
}
|
|
|
|
AstNode* value() const { return value_; }
|
|
|
|
intptr_t inlined_finally_list_length() const {
|
|
return inlined_finally_list_.length();
|
|
}
|
|
InlinedFinallyNode* InlinedFinallyNodeAt(intptr_t index) const {
|
|
return inlined_finally_list_[index];
|
|
}
|
|
void AddInlinedFinallyNode(InlinedFinallyNode* finally_node) {
|
|
inlined_finally_list_.Add(finally_node);
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
if (value() != NULL) {
|
|
value()->Visit(visitor);
|
|
}
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ReturnNode);
|
|
|
|
private:
|
|
AstNode* value_;
|
|
GrowableArray<InlinedFinallyNode*> inlined_finally_list_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ReturnNode);
|
|
};
|
|
|
|
|
|
class ComparisonNode : public AstNode {
|
|
public:
|
|
ComparisonNode(intptr_t token_pos,
|
|
Token::Kind kind,
|
|
AstNode* left,
|
|
AstNode* right)
|
|
: AstNode(token_pos), kind_(kind), left_(left), right_(right) {
|
|
ASSERT(left_ != NULL);
|
|
ASSERT(right_ != NULL);
|
|
ASSERT(IsKindValid());
|
|
}
|
|
|
|
Token::Kind kind() const { return kind_; }
|
|
AstNode* left() const { return left_; }
|
|
AstNode* right() const { return right_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
left()->Visit(visitor);
|
|
right()->Visit(visitor);
|
|
}
|
|
|
|
virtual const char* Name() const;
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual const Instance* EvalConstExpr() const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ComparisonNode);
|
|
|
|
private:
|
|
const Token::Kind kind_;
|
|
AstNode* left_;
|
|
AstNode* right_;
|
|
|
|
bool IsKindValid() const;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ComparisonNode);
|
|
};
|
|
|
|
|
|
class BinaryOpNode : public AstNode {
|
|
public:
|
|
BinaryOpNode(intptr_t token_pos,
|
|
Token::Kind kind,
|
|
AstNode* left,
|
|
AstNode* right)
|
|
: AstNode(token_pos), kind_(kind), left_(left), right_(right) {
|
|
ASSERT(left_ != NULL);
|
|
ASSERT(right_ != NULL);
|
|
ASSERT(IsKindValid());
|
|
}
|
|
|
|
Token::Kind kind() const { return kind_; }
|
|
AstNode* left() const { return left_; }
|
|
AstNode* right() const { return right_; }
|
|
|
|
virtual bool has_mask32() const { return false; }
|
|
virtual int64_t mask32() const {
|
|
UNREACHABLE();
|
|
return 0;
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
left()->Visit(visitor);
|
|
right()->Visit(visitor);
|
|
}
|
|
|
|
virtual const char* Name() const;
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual const Instance* EvalConstExpr() const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(BinaryOpNode);
|
|
|
|
private:
|
|
const Token::Kind kind_;
|
|
AstNode* left_;
|
|
AstNode* right_;
|
|
|
|
bool IsKindValid() const;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryOpNode);
|
|
};
|
|
|
|
|
|
class BinaryOpWithMask32Node : public BinaryOpNode {
|
|
public:
|
|
BinaryOpWithMask32Node(intptr_t token_pos,
|
|
Token::Kind kind_value,
|
|
AstNode* left,
|
|
AstNode* right,
|
|
int64_t mask32)
|
|
: BinaryOpNode(token_pos, kind_value, left, right), mask32_(mask32) {
|
|
ASSERT(mask32 >= 0 && Utils::IsUint(32, mask32));
|
|
ASSERT((kind_value != Token::kAND) && (kind_value != Token::kOR));
|
|
}
|
|
|
|
// The optional 32-bit mask must be a an unsigned 32-bit value.
|
|
virtual bool has_mask32() const { return true; }
|
|
virtual int64_t mask32() const {
|
|
ASSERT(has_mask32());
|
|
return mask32_;
|
|
}
|
|
|
|
virtual const char* Name() const;
|
|
DECLARE_COMMON_NODE_FUNCTIONS(BinaryOpWithMask32Node);
|
|
|
|
private:
|
|
// Optional unsigned 32 bit mask applied on result. No mask: -1.
|
|
const int64_t mask32_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryOpWithMask32Node);
|
|
};
|
|
|
|
|
|
|
|
class UnaryOpNode : public AstNode {
|
|
public:
|
|
// Returns optimized version, e.g., for ('-' '1') ('-1') literal is returned.
|
|
static AstNode* UnaryOpOrLiteral(intptr_t token_pos,
|
|
Token::Kind kind,
|
|
AstNode* operand);
|
|
UnaryOpNode(intptr_t token_pos,
|
|
Token::Kind kind,
|
|
AstNode* operand)
|
|
: AstNode(token_pos), kind_(kind), operand_(operand) {
|
|
ASSERT(operand_ != NULL);
|
|
ASSERT(IsKindValid());
|
|
}
|
|
|
|
Token::Kind kind() const { return kind_; }
|
|
AstNode* operand() const { return operand_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
operand()->Visit(visitor);
|
|
}
|
|
|
|
virtual const char* Name() const;
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual const Instance* EvalConstExpr() const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(UnaryOpNode);
|
|
|
|
private:
|
|
const Token::Kind kind_;
|
|
AstNode* operand_;
|
|
|
|
bool IsKindValid() const;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(UnaryOpNode);
|
|
};
|
|
|
|
|
|
class ConditionalExprNode : public AstNode {
|
|
public:
|
|
ConditionalExprNode(intptr_t token_pos,
|
|
AstNode* condition,
|
|
AstNode* true_expr,
|
|
AstNode* false_expr)
|
|
: AstNode(token_pos),
|
|
condition_(condition),
|
|
true_expr_(true_expr),
|
|
false_expr_(false_expr) {
|
|
ASSERT(condition_ != NULL);
|
|
ASSERT(true_expr_ != NULL);
|
|
ASSERT(false_expr_ != NULL);
|
|
}
|
|
|
|
AstNode* condition() const { return condition_; }
|
|
AstNode* true_expr() const { return true_expr_; }
|
|
AstNode* false_expr() const { return false_expr_; }
|
|
|
|
void set_true_expr(AstNode* true_expr) {
|
|
ASSERT(true_expr != NULL);
|
|
true_expr_ = true_expr;
|
|
}
|
|
void set_false_expr(AstNode* false_expr) {
|
|
ASSERT(false_expr != NULL);
|
|
false_expr_ = false_expr;
|
|
}
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
condition()->Visit(visitor);
|
|
true_expr()->Visit(visitor);
|
|
false_expr()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ConditionalExprNode);
|
|
|
|
private:
|
|
AstNode* condition_;
|
|
AstNode* true_expr_;
|
|
AstNode* false_expr_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ConditionalExprNode);
|
|
};
|
|
|
|
|
|
class IfNode : public AstNode {
|
|
public:
|
|
IfNode(intptr_t token_pos,
|
|
AstNode* condition,
|
|
SequenceNode* true_branch,
|
|
SequenceNode* false_branch)
|
|
: AstNode(token_pos),
|
|
condition_(condition),
|
|
true_branch_(true_branch),
|
|
false_branch_(false_branch) {
|
|
ASSERT(condition_ != NULL);
|
|
}
|
|
|
|
AstNode* condition() const { return condition_; }
|
|
SequenceNode* true_branch() const { return true_branch_; }
|
|
SequenceNode* false_branch() const { return false_branch_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
condition()->Visit(visitor);
|
|
true_branch()->Visit(visitor);
|
|
if (false_branch() != NULL) {
|
|
false_branch()->Visit(visitor);
|
|
}
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(IfNode);
|
|
|
|
private:
|
|
AstNode* condition_;
|
|
SequenceNode* true_branch_;
|
|
SequenceNode* false_branch_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(IfNode);
|
|
};
|
|
|
|
|
|
class CaseNode : public AstNode {
|
|
public:
|
|
CaseNode(intptr_t token_pos,
|
|
SourceLabel* label,
|
|
SequenceNode* case_expressions,
|
|
bool contains_default,
|
|
LocalVariable* switch_expr_value,
|
|
SequenceNode* statements)
|
|
: AstNode(token_pos),
|
|
label_(label),
|
|
case_expressions_(case_expressions),
|
|
contains_default_(contains_default),
|
|
switch_expr_value_(switch_expr_value),
|
|
statements_(statements) {
|
|
// label may be NULL.
|
|
ASSERT(case_expressions_ != NULL);
|
|
ASSERT(switch_expr_value_ != NULL);
|
|
ASSERT(statements_ != NULL);
|
|
}
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
SequenceNode* case_expressions() const { return case_expressions_; }
|
|
bool contains_default() const { return contains_default_; }
|
|
LocalVariable* switch_expr_value() const { return switch_expr_value_; }
|
|
SequenceNode* statements() const { return statements_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
case_expressions()->Visit(visitor);
|
|
statements()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(CaseNode);
|
|
|
|
private:
|
|
SourceLabel* label_;
|
|
SequenceNode* case_expressions_;
|
|
bool contains_default_;
|
|
LocalVariable* switch_expr_value_;
|
|
SequenceNode* statements_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(CaseNode);
|
|
};
|
|
|
|
|
|
class SwitchNode : public AstNode {
|
|
public:
|
|
SwitchNode(intptr_t token_pos,
|
|
SourceLabel* label,
|
|
SequenceNode* body)
|
|
: AstNode(token_pos),
|
|
label_(label),
|
|
body_(body) {
|
|
ASSERT(label_ != NULL);
|
|
ASSERT(body_ != NULL);
|
|
}
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
AstNode* body() const { return body_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
body()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(SwitchNode);
|
|
|
|
private:
|
|
SourceLabel* label_;
|
|
AstNode* body_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(SwitchNode);
|
|
};
|
|
|
|
|
|
class WhileNode : public AstNode {
|
|
public:
|
|
WhileNode(intptr_t token_pos,
|
|
SourceLabel* label,
|
|
AstNode* condition,
|
|
SequenceNode* body)
|
|
: AstNode(token_pos),
|
|
label_(label),
|
|
condition_(condition),
|
|
body_(body) {
|
|
ASSERT(label_ != NULL);
|
|
ASSERT(condition_ != NULL);
|
|
ASSERT(body_ != NULL);
|
|
}
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
AstNode* condition() const { return condition_; }
|
|
SequenceNode* body() const { return body_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
condition()->Visit(visitor);
|
|
body()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(WhileNode);
|
|
|
|
private:
|
|
SourceLabel* label_;
|
|
AstNode* condition_;
|
|
SequenceNode* body_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(WhileNode);
|
|
};
|
|
|
|
|
|
class DoWhileNode : public AstNode {
|
|
public:
|
|
DoWhileNode(intptr_t token_pos,
|
|
SourceLabel* label,
|
|
AstNode* condition,
|
|
SequenceNode* body)
|
|
: AstNode(token_pos),
|
|
label_(label),
|
|
condition_(condition),
|
|
body_(body) {
|
|
ASSERT(label_ != NULL);
|
|
ASSERT(condition_ != NULL);
|
|
ASSERT(body_ != NULL);
|
|
}
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
AstNode* condition() const { return condition_; }
|
|
SequenceNode* body() const { return body_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
body()->Visit(visitor);
|
|
condition()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(DoWhileNode);
|
|
|
|
private:
|
|
SourceLabel* label_;
|
|
AstNode* condition_;
|
|
SequenceNode* body_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(DoWhileNode);
|
|
};
|
|
|
|
|
|
// initializer, condition, increment expressions can be NULL.
|
|
class ForNode : public AstNode {
|
|
public:
|
|
ForNode(intptr_t token_pos,
|
|
SourceLabel* label,
|
|
SequenceNode* initializer,
|
|
AstNode* condition,
|
|
SequenceNode* increment,
|
|
SequenceNode* body)
|
|
: AstNode(token_pos),
|
|
label_(label),
|
|
initializer_(initializer),
|
|
condition_(condition),
|
|
increment_(increment),
|
|
body_(body) {
|
|
ASSERT(label_ != NULL);
|
|
ASSERT(initializer_ != NULL);
|
|
ASSERT(increment_ != NULL);
|
|
ASSERT(body_ != NULL);
|
|
}
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
SequenceNode* initializer() const { return initializer_; }
|
|
AstNode* condition() const { return condition_; }
|
|
SequenceNode* increment() const { return increment_; }
|
|
SequenceNode* body() const { return body_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
initializer()->Visit(visitor);
|
|
if (condition() != NULL) {
|
|
condition()->Visit(visitor);
|
|
}
|
|
increment()->Visit(visitor);
|
|
body()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ForNode);
|
|
|
|
private:
|
|
SourceLabel* label_;
|
|
SequenceNode* initializer_;
|
|
AstNode* condition_;
|
|
SequenceNode* increment_;
|
|
SequenceNode* body_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ForNode);
|
|
};
|
|
|
|
|
|
class JumpNode : public AstNode {
|
|
public:
|
|
JumpNode(intptr_t token_pos,
|
|
Token::Kind kind,
|
|
SourceLabel* label)
|
|
: AstNode(token_pos),
|
|
kind_(kind),
|
|
label_(label),
|
|
inlined_finally_list_() {
|
|
ASSERT(label_ != NULL);
|
|
ASSERT(kind_ == Token::kBREAK || kind_ == Token::kCONTINUE);
|
|
if (kind_ == Token::kCONTINUE) {
|
|
label_->set_is_continue_target(true);
|
|
}
|
|
}
|
|
|
|
SourceLabel* label() const { return label_; }
|
|
Token::Kind kind() const { return kind_; }
|
|
|
|
intptr_t inlined_finally_list_length() const {
|
|
return inlined_finally_list_.length();
|
|
}
|
|
InlinedFinallyNode* InlinedFinallyNodeAt(intptr_t index) const {
|
|
return inlined_finally_list_[index];
|
|
}
|
|
void AddInlinedFinallyNode(InlinedFinallyNode* finally_node) {
|
|
inlined_finally_list_.Add(finally_node);
|
|
}
|
|
|
|
virtual const char* Name() const;
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(JumpNode);
|
|
|
|
private:
|
|
Token::Kind kind_;
|
|
SourceLabel* label_;
|
|
GrowableArray<InlinedFinallyNode*> inlined_finally_list_;
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(JumpNode);
|
|
};
|
|
|
|
|
|
class LoadLocalNode : public AstNode {
|
|
public:
|
|
LoadLocalNode(intptr_t token_pos, const LocalVariable* local)
|
|
: AstNode(token_pos), local_(*local) {
|
|
ASSERT(local != NULL);
|
|
}
|
|
|
|
const LocalVariable& local() const { return local_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
virtual const char* Name() const;
|
|
virtual const Instance* EvalConstExpr() const;
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(LoadLocalNode);
|
|
|
|
private:
|
|
const LocalVariable& local_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadLocalNode);
|
|
};
|
|
|
|
|
|
class StoreLocalNode : public AstNode {
|
|
public:
|
|
StoreLocalNode(intptr_t token_pos, const LocalVariable* local, AstNode* value)
|
|
: AstNode(token_pos), local_(*local), value_(value) {
|
|
ASSERT(local != NULL);
|
|
ASSERT(value_ != NULL);
|
|
}
|
|
|
|
const LocalVariable& local() const { return local_; }
|
|
AstNode* value() const { return value_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
value()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StoreLocalNode);
|
|
|
|
private:
|
|
const LocalVariable& local_;
|
|
AstNode* value_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StoreLocalNode);
|
|
};
|
|
|
|
|
|
|
|
class LoadInstanceFieldNode : public AstNode {
|
|
public:
|
|
LoadInstanceFieldNode(intptr_t token_pos,
|
|
AstNode* instance,
|
|
const Field& field)
|
|
: AstNode(token_pos), instance_(instance), field_(field) {
|
|
ASSERT(instance_ != NULL);
|
|
ASSERT(field_.IsZoneHandle());
|
|
}
|
|
|
|
AstNode* instance() const { return instance_; }
|
|
const Field& field() const { return field_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
instance()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(LoadInstanceFieldNode);
|
|
|
|
private:
|
|
AstNode* instance_;
|
|
const Field& field_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadInstanceFieldNode);
|
|
};
|
|
|
|
|
|
class StoreInstanceFieldNode : public AstNode {
|
|
public:
|
|
StoreInstanceFieldNode(intptr_t token_pos,
|
|
AstNode* instance,
|
|
const Field& field,
|
|
AstNode* value)
|
|
: AstNode(token_pos),
|
|
instance_(instance),
|
|
field_(field),
|
|
value_(value) {
|
|
ASSERT(instance_ != NULL);
|
|
ASSERT(field_.IsZoneHandle());
|
|
ASSERT(value_ != NULL);
|
|
}
|
|
|
|
AstNode* instance() const { return instance_; }
|
|
const Field& field() const { return field_; }
|
|
AstNode* value() const { return value_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
instance()->Visit(visitor);
|
|
value()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StoreInstanceFieldNode);
|
|
|
|
private:
|
|
AstNode* instance_;
|
|
const Field& field_;
|
|
AstNode* value_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StoreInstanceFieldNode);
|
|
};
|
|
|
|
|
|
class LoadStaticFieldNode : public AstNode {
|
|
public:
|
|
LoadStaticFieldNode(intptr_t token_pos, const Field& field)
|
|
: AstNode(token_pos), field_(field) {
|
|
ASSERT(field_.IsZoneHandle());
|
|
}
|
|
|
|
const Field& field() const { return field_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
|
|
virtual const Instance* EvalConstExpr() const {
|
|
ASSERT(field_.is_static());
|
|
return field_.is_const() ? &Instance::ZoneHandle(field_.value()) : NULL;
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(LoadStaticFieldNode);
|
|
|
|
private:
|
|
const Field& field_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadStaticFieldNode);
|
|
};
|
|
|
|
|
|
class StoreStaticFieldNode : public AstNode {
|
|
public:
|
|
StoreStaticFieldNode(intptr_t token_pos, const Field& field, AstNode* value)
|
|
: AstNode(token_pos), field_(field), value_(value) {
|
|
ASSERT(field_.IsZoneHandle());
|
|
ASSERT(value_ != NULL);
|
|
}
|
|
|
|
const Field& field() const { return field_; }
|
|
AstNode* value() const { return value_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
value()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StoreStaticFieldNode);
|
|
|
|
private:
|
|
const Field& field_;
|
|
AstNode* value_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StoreStaticFieldNode);
|
|
};
|
|
|
|
|
|
class LoadIndexedNode : public AstNode {
|
|
public:
|
|
LoadIndexedNode(intptr_t token_pos,
|
|
AstNode* array,
|
|
AstNode* index,
|
|
const Class& super_class)
|
|
: AstNode(token_pos),
|
|
array_(array),
|
|
index_expr_(index),
|
|
super_class_(super_class) {
|
|
ASSERT(array_ != NULL);
|
|
ASSERT(index_expr_ != NULL);
|
|
ASSERT(super_class_.IsZoneHandle());
|
|
}
|
|
|
|
AstNode* array() const { return array_; }
|
|
AstNode* index_expr() const { return index_expr_; }
|
|
const Class& super_class() const { return super_class_; }
|
|
bool IsSuperLoad() const { return !super_class_.IsNull(); }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
array()->Visit(visitor);
|
|
index_expr()->Visit(visitor);
|
|
}
|
|
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(LoadIndexedNode);
|
|
|
|
private:
|
|
AstNode* array_;
|
|
AstNode* index_expr_;
|
|
const Class& super_class_;
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadIndexedNode);
|
|
};
|
|
|
|
|
|
class StoreIndexedNode : public AstNode {
|
|
public:
|
|
StoreIndexedNode(intptr_t token_pos,
|
|
AstNode* array,
|
|
AstNode* index,
|
|
AstNode* value,
|
|
const Class& super_class)
|
|
: AstNode(token_pos),
|
|
array_(array),
|
|
index_expr_(index),
|
|
value_(value),
|
|
super_class_(super_class) {
|
|
ASSERT(array_ != NULL);
|
|
ASSERT(index_expr_ != NULL);
|
|
ASSERT(value_ != NULL);
|
|
ASSERT(super_class_.IsZoneHandle());
|
|
}
|
|
|
|
AstNode* array() const { return array_; }
|
|
AstNode* index_expr() const { return index_expr_; }
|
|
AstNode* value() const { return value_; }
|
|
const Class& super_class() const { return super_class_; }
|
|
bool IsSuperStore() const { return !super_class_.IsNull(); }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
array()->Visit(visitor);
|
|
index_expr()->Visit(visitor);
|
|
value()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StoreIndexedNode);
|
|
|
|
private:
|
|
AstNode* array_;
|
|
AstNode* index_expr_;
|
|
AstNode* value_;
|
|
const Class& super_class_;
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StoreIndexedNode);
|
|
};
|
|
|
|
|
|
class InstanceCallNode : public AstNode {
|
|
public:
|
|
InstanceCallNode(intptr_t token_pos,
|
|
AstNode* receiver,
|
|
const String& function_name,
|
|
ArgumentListNode* arguments)
|
|
: AstNode(token_pos),
|
|
receiver_(receiver),
|
|
function_name_(function_name),
|
|
arguments_(arguments) {
|
|
ASSERT(receiver_ != NULL);
|
|
ASSERT(function_name_.IsNotTemporaryScopedHandle());
|
|
ASSERT(function_name_.IsSymbol());
|
|
ASSERT(arguments_ != NULL);
|
|
}
|
|
|
|
AstNode* receiver() const { return receiver_; }
|
|
const String& function_name() const { return function_name_; }
|
|
ArgumentListNode* arguments() const { return arguments_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
receiver()->Visit(visitor);
|
|
arguments()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(InstanceCallNode);
|
|
|
|
private:
|
|
AstNode* receiver_;
|
|
const String& function_name_;
|
|
ArgumentListNode* arguments_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCallNode);
|
|
};
|
|
|
|
|
|
class InstanceGetterNode : public AstNode {
|
|
public:
|
|
InstanceGetterNode(intptr_t token_pos,
|
|
AstNode* receiver,
|
|
const String& field_name)
|
|
: AstNode(token_pos),
|
|
receiver_(receiver),
|
|
field_name_(field_name) {
|
|
ASSERT(receiver_ != NULL);
|
|
ASSERT(field_name_.IsNotTemporaryScopedHandle());
|
|
ASSERT(field_name_.IsSymbol());
|
|
}
|
|
|
|
AstNode* receiver() const { return receiver_; }
|
|
const String& field_name() const { return field_name_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
receiver()->Visit(visitor);
|
|
}
|
|
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(InstanceGetterNode);
|
|
|
|
private:
|
|
AstNode* receiver_;
|
|
const String& field_name_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceGetterNode);
|
|
};
|
|
|
|
|
|
class InstanceSetterNode : public AstNode {
|
|
public:
|
|
InstanceSetterNode(intptr_t token_pos,
|
|
AstNode* receiver,
|
|
const String& field_name,
|
|
AstNode* value)
|
|
: AstNode(token_pos),
|
|
receiver_(receiver),
|
|
field_name_(field_name),
|
|
value_(value) {
|
|
ASSERT(receiver_ != NULL);
|
|
ASSERT(value_ != NULL);
|
|
ASSERT(field_name_.IsZoneHandle());
|
|
ASSERT(field_name_.IsSymbol());
|
|
}
|
|
|
|
AstNode* receiver() const { return receiver_; }
|
|
const String& field_name() const { return field_name_; }
|
|
AstNode* value() const { return value_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
receiver()->Visit(visitor);
|
|
value()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(InstanceSetterNode);
|
|
|
|
private:
|
|
AstNode* receiver_;
|
|
const String& field_name_;
|
|
AstNode* value_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceSetterNode);
|
|
};
|
|
|
|
|
|
class StaticGetterNode : public AstNode {
|
|
public:
|
|
StaticGetterNode(intptr_t token_pos,
|
|
AstNode* receiver,
|
|
bool is_super_getter,
|
|
const Class& cls,
|
|
const String& field_name)
|
|
: AstNode(token_pos),
|
|
receiver_(receiver),
|
|
cls_(cls),
|
|
field_name_(field_name),
|
|
is_super_getter_(is_super_getter) {
|
|
ASSERT(cls_.IsZoneHandle());
|
|
ASSERT(field_name_.IsZoneHandle());
|
|
ASSERT(field_name_.IsSymbol());
|
|
}
|
|
|
|
// The receiver is required
|
|
// 1) for a super getter (an instance method that is resolved at compile
|
|
// time rather than at runtime).
|
|
// 2) when transforming this StaticGetterNode issued in a non-static
|
|
// context to an InstanceSetterNode. This may occurs when we find a
|
|
// static getter, but no field and no static setter are declared.
|
|
AstNode* receiver() const { return receiver_; }
|
|
const Class& cls() const { return cls_; }
|
|
const String& field_name() const { return field_name_; }
|
|
bool is_super_getter() const { return is_super_getter_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
|
|
virtual bool IsPotentiallyConst() const;
|
|
virtual const Instance* EvalConstExpr() const;
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StaticGetterNode);
|
|
|
|
private:
|
|
AstNode* receiver_;
|
|
const Class& cls_;
|
|
const String& field_name_;
|
|
const bool is_super_getter_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticGetterNode);
|
|
};
|
|
|
|
|
|
class StaticSetterNode : public AstNode {
|
|
public:
|
|
StaticSetterNode(intptr_t token_pos,
|
|
AstNode* receiver,
|
|
const Class& cls,
|
|
const String& field_name,
|
|
AstNode* value)
|
|
: AstNode(token_pos),
|
|
receiver_(receiver),
|
|
cls_(cls),
|
|
field_name_(field_name),
|
|
value_(value) {
|
|
ASSERT(cls_.IsZoneHandle());
|
|
ASSERT(field_name_.IsZoneHandle());
|
|
ASSERT(value_ != NULL);
|
|
}
|
|
|
|
// The receiver is required for a super setter (an instance method
|
|
// that is resolved at compile time rather than at runtime).
|
|
AstNode* receiver() const { return receiver_; }
|
|
const Class& cls() const { return cls_; }
|
|
const String& field_name() const { return field_name_; }
|
|
AstNode* value() const { return value_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
value()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StaticSetterNode);
|
|
|
|
private:
|
|
AstNode* receiver_;
|
|
const Class& cls_;
|
|
const String& field_name_;
|
|
AstNode* value_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticSetterNode);
|
|
};
|
|
|
|
|
|
class StaticCallNode : public AstNode {
|
|
public:
|
|
StaticCallNode(intptr_t token_pos,
|
|
const Function& function,
|
|
ArgumentListNode* arguments)
|
|
: AstNode(token_pos),
|
|
function_(function),
|
|
arguments_(arguments) {
|
|
ASSERT(function_.IsZoneHandle());
|
|
ASSERT(arguments_ != NULL);
|
|
}
|
|
|
|
const Function& function() const { return function_; }
|
|
ArgumentListNode* arguments() const { return arguments_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
arguments()->Visit(visitor);
|
|
}
|
|
|
|
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(StaticCallNode);
|
|
|
|
private:
|
|
const Function& function_;
|
|
ArgumentListNode* arguments_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCallNode);
|
|
};
|
|
|
|
|
|
class ClosureCallNode : public AstNode {
|
|
public:
|
|
ClosureCallNode(intptr_t token_pos,
|
|
AstNode* closure,
|
|
ArgumentListNode* arguments)
|
|
: AstNode(token_pos),
|
|
closure_(closure),
|
|
arguments_(arguments) {
|
|
ASSERT(closure_ != NULL);
|
|
ASSERT(arguments_ != NULL);
|
|
}
|
|
|
|
AstNode* closure() const { return closure_; }
|
|
ArgumentListNode* arguments() const { return arguments_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
closure()->Visit(visitor);
|
|
arguments()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ClosureCallNode);
|
|
|
|
private:
|
|
AstNode* closure_;
|
|
ArgumentListNode* arguments_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCallNode);
|
|
};
|
|
|
|
|
|
// There are two kinds of constructor calls: factory calls and constructor
|
|
// calls, distinguishable by constructor.IsFactory().
|
|
//
|
|
// Constructor calls implicitly allocate an object of class constructor.owner(),
|
|
// possibly parameterized by type_arguments, which may still be uninstantiated.
|
|
// For example, if the type argument T in 'new A<T>()' is not known at compile
|
|
// time, it needs to be instantiated at run time. The instantiator and its
|
|
// instantiator_class are used to instantiate uninstantiated type arguments
|
|
// at run time, as explained below.
|
|
//
|
|
// Factory calls do not implicitly allocate an object, but receive an implicit
|
|
// type argument vector as first parameter, which may still be uninstantiated.
|
|
// As in constructor calls, the instantiator and its instantiator_class are used
|
|
// to instantiate uninstantiated type arguments at run time.
|
|
//
|
|
// If the caller to the constructor or to the factory is an instance function,
|
|
// the instantiator is the receiver of this function. In order to instantiate T
|
|
// in the example above (which could for example be the first type parameter of
|
|
// the class of the caller), the code at run time extracts the type arguments of
|
|
// the receiver at an offset in the receiver specified by the provided
|
|
// instantiator_class.
|
|
//
|
|
// If the caller to the constructor or to the factory is a factory, then the
|
|
// instantiator is the first parameter of this factory, which is already a
|
|
// type argument vector. This case is identified by a null and unneeded
|
|
// instantiator_class.
|
|
class ConstructorCallNode : public AstNode {
|
|
public:
|
|
ConstructorCallNode(intptr_t token_pos,
|
|
const AbstractTypeArguments& type_arguments,
|
|
const Function& constructor,
|
|
ArgumentListNode* arguments)
|
|
: AstNode(token_pos),
|
|
type_arguments_(type_arguments),
|
|
constructor_(constructor),
|
|
arguments_(arguments) {
|
|
ASSERT(type_arguments_.IsZoneHandle());
|
|
ASSERT(constructor_.IsZoneHandle());
|
|
ASSERT(arguments_ != NULL);
|
|
}
|
|
|
|
const AbstractTypeArguments& type_arguments() const {
|
|
return type_arguments_;
|
|
}
|
|
const Function& constructor() const { return constructor_; }
|
|
ArgumentListNode* arguments() const { return arguments_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
arguments()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ConstructorCallNode);
|
|
|
|
private:
|
|
const AbstractTypeArguments& type_arguments_;
|
|
const Function& constructor_;
|
|
ArgumentListNode* arguments_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ConstructorCallNode);
|
|
};
|
|
|
|
|
|
// The body of a Dart function marked as 'native' consists of this node.
|
|
class NativeBodyNode : public AstNode {
|
|
public:
|
|
NativeBodyNode(intptr_t token_pos,
|
|
const Function& function,
|
|
const String& native_c_function_name,
|
|
NativeFunction native_c_function,
|
|
LocalScope* scope,
|
|
bool is_bootstrap_native)
|
|
: AstNode(token_pos),
|
|
function_(function),
|
|
native_c_function_name_(native_c_function_name),
|
|
native_c_function_(native_c_function),
|
|
scope_(scope),
|
|
is_bootstrap_native_(is_bootstrap_native) {
|
|
ASSERT(function_.IsZoneHandle());
|
|
ASSERT(native_c_function_ != NULL);
|
|
ASSERT(native_c_function_name_.IsZoneHandle());
|
|
ASSERT(native_c_function_name_.IsSymbol());
|
|
}
|
|
|
|
const Function& function() const { return function_; }
|
|
const String& native_c_function_name() const {
|
|
return native_c_function_name_;
|
|
}
|
|
NativeFunction native_c_function() const { return native_c_function_; }
|
|
LocalScope* scope() const { return scope_; }
|
|
bool is_bootstrap_native() const { return is_bootstrap_native_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const { }
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(NativeBodyNode);
|
|
|
|
private:
|
|
const Function& function_; // Native Dart function.
|
|
const String& native_c_function_name_;
|
|
NativeFunction native_c_function_; // Actual non-Dart implementation.
|
|
LocalScope* scope_;
|
|
const bool is_bootstrap_native_; // Is a bootstrap native method.
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(NativeBodyNode);
|
|
};
|
|
|
|
|
|
class CatchClauseNode : public AstNode {
|
|
public:
|
|
static const int kInvalidTryIndex = -1;
|
|
|
|
CatchClauseNode(intptr_t token_pos,
|
|
SequenceNode* catch_block,
|
|
const Array& handler_types,
|
|
const LocalVariable* context_var,
|
|
const LocalVariable* exception_var,
|
|
const LocalVariable* stacktrace_var,
|
|
intptr_t catch_handler_index)
|
|
: AstNode(token_pos),
|
|
catch_block_(catch_block),
|
|
handler_types_(handler_types),
|
|
context_var_(*context_var),
|
|
exception_var_(*exception_var),
|
|
stacktrace_var_(*stacktrace_var),
|
|
catch_handler_index_(catch_handler_index) {
|
|
ASSERT(catch_block_ != NULL);
|
|
ASSERT(handler_types.IsZoneHandle());
|
|
ASSERT(context_var != NULL);
|
|
ASSERT(exception_var != NULL);
|
|
ASSERT(stacktrace_var != NULL);
|
|
}
|
|
|
|
const Array& handler_types() const { return handler_types_; }
|
|
const LocalVariable& context_var() const { return context_var_; }
|
|
const LocalVariable& exception_var() const { return exception_var_; }
|
|
const LocalVariable& stacktrace_var() const { return stacktrace_var_; }
|
|
intptr_t catch_handler_index() const { return catch_handler_index_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
catch_block_->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(CatchClauseNode);
|
|
|
|
private:
|
|
SequenceNode* catch_block_;
|
|
const Array& handler_types_;
|
|
const LocalVariable& context_var_;
|
|
const LocalVariable& exception_var_;
|
|
const LocalVariable& stacktrace_var_;
|
|
const intptr_t catch_handler_index_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CatchClauseNode);
|
|
};
|
|
|
|
|
|
class TryCatchNode : public AstNode {
|
|
public:
|
|
TryCatchNode(intptr_t token_pos,
|
|
SequenceNode* try_block,
|
|
SourceLabel* end_catch_label,
|
|
const LocalVariable* context_var,
|
|
CatchClauseNode* catch_block,
|
|
SequenceNode* finally_block,
|
|
intptr_t try_index)
|
|
: AstNode(token_pos),
|
|
try_block_(try_block),
|
|
end_catch_label_(end_catch_label),
|
|
context_var_(*context_var),
|
|
catch_block_(catch_block),
|
|
finally_block_(finally_block),
|
|
try_index_(try_index) {
|
|
ASSERT(try_block_ != NULL);
|
|
ASSERT(context_var != NULL);
|
|
ASSERT(catch_block_ != NULL || finally_block_ != NULL);
|
|
ASSERT(end_catch_label_ != NULL);
|
|
}
|
|
|
|
SequenceNode* try_block() const { return try_block_; }
|
|
SourceLabel* end_catch_label() const { return end_catch_label_; }
|
|
CatchClauseNode* catch_block() const { return catch_block_; }
|
|
SequenceNode* finally_block() const { return finally_block_; }
|
|
const LocalVariable& context_var() const { return context_var_; }
|
|
intptr_t try_index() const { return try_index_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
try_block_->Visit(visitor);
|
|
if (catch_block_ != NULL) {
|
|
catch_block_->Visit(visitor);
|
|
}
|
|
if (finally_block_ != NULL) {
|
|
finally_block_->Visit(visitor);
|
|
}
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(TryCatchNode);
|
|
|
|
private:
|
|
SequenceNode* try_block_;
|
|
SourceLabel* end_catch_label_;
|
|
const LocalVariable& context_var_;
|
|
CatchClauseNode* catch_block_;
|
|
SequenceNode* finally_block_;
|
|
const intptr_t try_index_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(TryCatchNode);
|
|
};
|
|
|
|
|
|
class ThrowNode : public AstNode {
|
|
public:
|
|
ThrowNode(intptr_t token_pos, AstNode* exception, AstNode* stacktrace)
|
|
: AstNode(token_pos), exception_(exception), stacktrace_(stacktrace) {
|
|
ASSERT(exception_ != NULL);
|
|
}
|
|
|
|
AstNode* exception() const { return exception_; }
|
|
AstNode* stacktrace() const { return stacktrace_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
exception()->Visit(visitor);
|
|
if (stacktrace() != NULL) {
|
|
stacktrace()->Visit(visitor);
|
|
}
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(ThrowNode);
|
|
|
|
private:
|
|
AstNode* exception_;
|
|
AstNode* stacktrace_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ThrowNode);
|
|
};
|
|
|
|
|
|
class InlinedFinallyNode : public AstNode {
|
|
public:
|
|
InlinedFinallyNode(intptr_t token_pos,
|
|
AstNode* finally_block,
|
|
const LocalVariable* context_var,
|
|
intptr_t try_index)
|
|
: AstNode(token_pos),
|
|
finally_block_(finally_block),
|
|
context_var_(*context_var),
|
|
try_index_(try_index) {
|
|
ASSERT(finally_block_ != NULL);
|
|
ASSERT(context_var != NULL);
|
|
}
|
|
|
|
AstNode* finally_block() const { return finally_block_; }
|
|
const LocalVariable& context_var() const { return context_var_; }
|
|
intptr_t try_index() const { return try_index_; }
|
|
|
|
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
|
finally_block()->Visit(visitor);
|
|
}
|
|
|
|
DECLARE_COMMON_NODE_FUNCTIONS(InlinedFinallyNode);
|
|
|
|
private:
|
|
AstNode* finally_block_;
|
|
const LocalVariable& context_var_;
|
|
const intptr_t try_index_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(InlinedFinallyNode);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#undef DECLARE_COMMON_NODE_FUNCTIONS
|
|
|
|
#endif // VM_AST_H_
|