// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_AST_AST_H_ #define V8_AST_AST_H_ #include "src/assembler.h" #include "src/ast/ast-value-factory.h" #include "src/ast/modules.h" #include "src/ast/variables.h" #include "src/bailout-reason.h" #include "src/base/flags.h" #include "src/base/smart-pointers.h" #include "src/factory.h" #include "src/isolate.h" #include "src/list.h" #include "src/parsing/token.h" #include "src/runtime/runtime.h" #include "src/small-pointer-list.h" #include "src/types.h" #include "src/utils.h" namespace v8 { namespace internal { // The abstract syntax tree is an intermediate, light-weight // representation of the parsed JavaScript code suitable for // compilation to native code. // Nodes are allocated in a separate zone, which allows faster // allocation and constant-time deallocation of the entire syntax // tree. // ---------------------------------------------------------------------------- // Nodes of the abstract syntax tree. Only concrete classes are // enumerated here. #define DECLARATION_NODE_LIST(V) \ V(VariableDeclaration) \ V(FunctionDeclaration) \ V(ImportDeclaration) \ V(ExportDeclaration) #define STATEMENT_NODE_LIST(V) \ V(Block) \ V(ExpressionStatement) \ V(EmptyStatement) \ V(SloppyBlockFunctionStatement) \ V(IfStatement) \ V(ContinueStatement) \ V(BreakStatement) \ V(ReturnStatement) \ V(WithStatement) \ V(SwitchStatement) \ V(DoWhileStatement) \ V(WhileStatement) \ V(ForStatement) \ V(ForInStatement) \ V(ForOfStatement) \ V(TryCatchStatement) \ V(TryFinallyStatement) \ V(DebuggerStatement) #define EXPRESSION_NODE_LIST(V) \ V(FunctionLiteral) \ V(ClassLiteral) \ V(NativeFunctionLiteral) \ V(Conditional) \ V(VariableProxy) \ V(Literal) \ V(RegExpLiteral) \ V(ObjectLiteral) \ V(ArrayLiteral) \ V(Assignment) \ V(Yield) \ V(Throw) \ V(Property) \ V(Call) \ V(CallNew) \ V(CallRuntime) \ V(UnaryOperation) \ V(CountOperation) \ V(BinaryOperation) \ V(CompareOperation) \ V(Spread) \ V(ThisFunction) \ V(SuperPropertyReference) \ V(SuperCallReference) \ V(CaseClause) \ V(EmptyParentheses) \ V(DoExpression) \ V(RewritableAssignmentExpression) #define AST_NODE_LIST(V) \ DECLARATION_NODE_LIST(V) \ STATEMENT_NODE_LIST(V) \ EXPRESSION_NODE_LIST(V) // Forward declarations class AstNodeFactory; class AstVisitor; class Declaration; class Module; class BreakableStatement; class Expression; class IterationStatement; class MaterializedLiteral; class Statement; class TypeFeedbackOracle; #define DEF_FORWARD_DECLARATION(type) class type; AST_NODE_LIST(DEF_FORWARD_DECLARATION) #undef DEF_FORWARD_DECLARATION // Typedef only introduced to avoid unreadable code. typedef ZoneList> ZoneStringList; typedef ZoneList> ZoneObjectList; #define DECLARE_NODE_TYPE(type) \ void Accept(AstVisitor* v) override; \ AstNode::NodeType node_type() const final { return AstNode::k##type; } \ friend class AstNodeFactory; class FeedbackVectorSlotCache { public: explicit FeedbackVectorSlotCache(Zone* zone) : zone_(zone), hash_map_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity, ZoneAllocationPolicy(zone)) {} void Put(Variable* variable, FeedbackVectorSlot slot) { ZoneHashMap::Entry* entry = hash_map_.LookupOrInsert( variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_)); entry->value = reinterpret_cast(slot.ToInt()); } ZoneHashMap::Entry* Get(Variable* variable) const { return hash_map_.Lookup(variable, ComputePointerHash(variable)); } private: Zone* zone_; ZoneHashMap hash_map_; }; class AstProperties final BASE_EMBEDDED { public: enum Flag { kNoFlags = 0, kDontSelfOptimize = 1 << 0, kDontCrankshaft = 1 << 1 }; typedef base::Flags Flags; explicit AstProperties(Zone* zone) : node_count_(0), spec_(zone) {} Flags& flags() { return flags_; } Flags flags() const { return flags_; } int node_count() { return node_count_; } void add_node_count(int count) { node_count_ += count; } const FeedbackVectorSpec* get_spec() const { return &spec_; } FeedbackVectorSpec* get_spec() { return &spec_; } private: Flags flags_; int node_count_; FeedbackVectorSpec spec_; }; DEFINE_OPERATORS_FOR_FLAGS(AstProperties::Flags) class AstNode: public ZoneObject { public: #define DECLARE_TYPE_ENUM(type) k##type, enum NodeType { AST_NODE_LIST(DECLARE_TYPE_ENUM) kInvalid = -1 }; #undef DECLARE_TYPE_ENUM void* operator new(size_t size, Zone* zone) { return zone->New(size); } explicit AstNode(int position): position_(position) {} virtual ~AstNode() {} virtual void Accept(AstVisitor* v) = 0; virtual NodeType node_type() const = 0; int position() const { return position_; } // Type testing & conversion functions overridden by concrete subclasses. #define DECLARE_NODE_FUNCTIONS(type) \ bool Is##type() const { return node_type() == AstNode::k##type; } \ type* As##type() { \ return Is##type() ? reinterpret_cast(this) : NULL; \ } \ const type* As##type() const { \ return Is##type() ? reinterpret_cast(this) : NULL; \ } AST_NODE_LIST(DECLARE_NODE_FUNCTIONS) #undef DECLARE_NODE_FUNCTIONS virtual BreakableStatement* AsBreakableStatement() { return NULL; } virtual IterationStatement* AsIterationStatement() { return NULL; } virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; } // The interface for feedback slots, with default no-op implementations for // node types which don't actually have this. Note that this is conceptually // not really nice, but multiple inheritance would introduce yet another // vtable entry per node, something we don't want for space reasons. virtual void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) {} private: // Hidden to prevent accidental usage. It would have to load the // current zone from the TLS. void* operator new(size_t size); friend class CaseClause; // Generates AST IDs. int position_; }; class Statement : public AstNode { public: explicit Statement(Zone* zone, int position) : AstNode(position) {} bool IsEmpty() { return AsEmptyStatement() != NULL; } virtual bool IsJump() const { return false; } virtual void MarkTail() {} }; class SmallMapList final { public: SmallMapList() {} SmallMapList(int capacity, Zone* zone) : list_(capacity, zone) {} void Reserve(int capacity, Zone* zone) { list_.Reserve(capacity, zone); } void Clear() { list_.Clear(); } void Sort() { list_.Sort(); } bool is_empty() const { return list_.is_empty(); } int length() const { return list_.length(); } void AddMapIfMissing(Handle map, Zone* zone) { if (!Map::TryUpdate(map).ToHandle(&map)) return; for (int i = 0; i < length(); ++i) { if (at(i).is_identical_to(map)) return; } Add(map, zone); } void FilterForPossibleTransitions(Map* root_map) { for (int i = list_.length() - 1; i >= 0; i--) { if (at(i)->FindRootMap() != root_map) { list_.RemoveElement(list_.at(i)); } } } void Add(Handle handle, Zone* zone) { list_.Add(handle.location(), zone); } Handle at(int i) const { return Handle(list_.at(i)); } Handle first() const { return at(0); } Handle last() const { return at(length() - 1); } private: // The list stores pointers to Map*, that is Map**, so it's GC safe. SmallPointerList list_; DISALLOW_COPY_AND_ASSIGN(SmallMapList); }; class Expression : public AstNode { public: enum Context { // Not assigned a context yet, or else will not be visited during // code generation. kUninitialized, // Evaluated for its side effects. kEffect, // Evaluated for its value (and side effects). kValue, // Evaluated for control flow (and side effects). kTest }; // Mark this expression as being in tail position. virtual void MarkTail() {} // True iff the expression is a valid reference expression. virtual bool IsValidReferenceExpression() const { return false; } // Helpers for ToBoolean conversion. virtual bool ToBooleanIsTrue() const { return false; } virtual bool ToBooleanIsFalse() const { return false; } // Symbols that cannot be parsed as array indices are considered property // names. We do not treat symbols that can be array indexes as property // names because [] for string objects is handled only by keyed ICs. virtual bool IsPropertyName() const { return false; } // True iff the expression is a literal represented as a smi. bool IsSmiLiteral() const; // True iff the expression is a string literal. bool IsStringLiteral() const; // True iff the expression is the null literal. bool IsNullLiteral() const; // True if we can prove that the expression is the undefined literal. bool IsUndefinedLiteral(Isolate* isolate) const; // True iff the expression is a valid target for an assignment. bool IsValidReferenceExpressionOrThis() const; // Expression type bounds Bounds bounds() const { return bounds_; } void set_bounds(Bounds bounds) { bounds_ = bounds; } // Type feedback information for assignments and properties. virtual bool IsMonomorphic() { UNREACHABLE(); return false; } virtual SmallMapList* GetReceiverTypes() { UNREACHABLE(); return NULL; } virtual KeyedAccessStoreMode GetStoreMode() const { UNREACHABLE(); return STANDARD_STORE; } virtual IcCheckType GetKeyType() const { UNREACHABLE(); return ELEMENT; } // TODO(rossberg): this should move to its own AST node eventually. virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle); uint16_t to_boolean_types() const { return ToBooleanTypesField::decode(bit_field_); } void set_base_id(int id) { base_id_ = id; } static int num_ids() { return parent_num_ids() + 2; } BailoutId id() const { return BailoutId(local_id(0)); } TypeFeedbackId test_id() const { return TypeFeedbackId(local_id(1)); } // Parenthesized expressions in the form `( Expression )`. void set_is_parenthesized() { bit_field_ = ParenthesizedField::update(bit_field_, true); } bool is_parenthesized() const { return ParenthesizedField::decode(bit_field_); } protected: Expression(Zone* zone, int pos) : AstNode(pos), base_id_(BailoutId::None().ToInt()), bounds_(Bounds::Unbounded()), bit_field_(0) {} static int parent_num_ids() { return 0; } void set_to_boolean_types(uint16_t types) { bit_field_ = ToBooleanTypesField::update(bit_field_, types); } int base_id() const { DCHECK(!BailoutId(base_id_).IsNone()); return base_id_; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } int base_id_; Bounds bounds_; class ToBooleanTypesField : public BitField16 {}; class ParenthesizedField : public BitField16 {}; uint16_t bit_field_; // Ends with 16-bit field; deriving classes in turn begin with // 16-bit fields for optimum packing efficiency. }; class BreakableStatement : public Statement { public: enum BreakableType { TARGET_FOR_ANONYMOUS, TARGET_FOR_NAMED_ONLY }; // The labels associated with this statement. May be NULL; // if it is != NULL, guaranteed to contain at least one entry. ZoneList* labels() const { return labels_; } // Type testing & conversion. BreakableStatement* AsBreakableStatement() final { return this; } // Code generation Label* break_target() { return &break_target_; } // Testers. bool is_target_for_anonymous() const { return breakable_type_ == TARGET_FOR_ANONYMOUS; } void set_base_id(int id) { base_id_ = id; } static int num_ids() { return parent_num_ids() + 2; } BailoutId EntryId() const { return BailoutId(local_id(0)); } BailoutId ExitId() const { return BailoutId(local_id(1)); } protected: BreakableStatement(Zone* zone, ZoneList* labels, BreakableType breakable_type, int position) : Statement(zone, position), labels_(labels), breakable_type_(breakable_type), base_id_(BailoutId::None().ToInt()) { DCHECK(labels == NULL || labels->length() > 0); } static int parent_num_ids() { return 0; } int base_id() const { DCHECK(!BailoutId(base_id_).IsNone()); return base_id_; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } ZoneList* labels_; BreakableType breakable_type_; Label break_target_; int base_id_; }; class Block final : public BreakableStatement { public: DECLARE_NODE_TYPE(Block) ZoneList* statements() { return &statements_; } bool ignore_completion_value() const { return ignore_completion_value_; } static int num_ids() { return parent_num_ids() + 1; } BailoutId DeclsId() const { return BailoutId(local_id(0)); } bool IsJump() const override { return !statements_.is_empty() && statements_.last()->IsJump() && labels() == NULL; // Good enough as an approximation... } void MarkTail() override { if (!statements_.is_empty()) statements_.last()->MarkTail(); } Scope* scope() const { return scope_; } void set_scope(Scope* scope) { scope_ = scope; } protected: Block(Zone* zone, ZoneList* labels, int capacity, bool ignore_completion_value, int pos) : BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos), statements_(capacity, zone), ignore_completion_value_(ignore_completion_value), scope_(NULL) {} static int parent_num_ids() { return BreakableStatement::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } ZoneList statements_; bool ignore_completion_value_; Scope* scope_; }; class DoExpression final : public Expression { public: DECLARE_NODE_TYPE(DoExpression) Block* block() { return block_; } void set_block(Block* b) { block_ = b; } VariableProxy* result() { return result_; } void set_result(VariableProxy* v) { result_ = v; } void MarkTail() override { block_->MarkTail(); } protected: DoExpression(Zone* zone, Block* block, VariableProxy* result, int pos) : Expression(zone, pos), block_(block), result_(result) { DCHECK_NOT_NULL(block_); DCHECK_NOT_NULL(result_); } static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Block* block_; VariableProxy* result_; }; class Declaration : public AstNode { public: VariableProxy* proxy() const { return proxy_; } VariableMode mode() const { return mode_; } Scope* scope() const { return scope_; } virtual InitializationFlag initialization() const = 0; virtual bool IsInlineable() const; protected: Declaration(Zone* zone, VariableProxy* proxy, VariableMode mode, Scope* scope, int pos) : AstNode(pos), mode_(mode), proxy_(proxy), scope_(scope) { DCHECK(IsDeclaredVariableMode(mode)); } private: VariableMode mode_; VariableProxy* proxy_; // Nested scope from which the declaration originated. Scope* scope_; }; class VariableDeclaration final : public Declaration { public: DECLARE_NODE_TYPE(VariableDeclaration) InitializationFlag initialization() const override { return mode() == VAR ? kCreatedInitialized : kNeedsInitialization; } bool is_class_declaration() const { return is_class_declaration_; } // VariableDeclarations can be grouped into consecutive declaration // groups. Each VariableDeclaration is associated with the start position of // the group it belongs to. The positions are used for strong mode scope // checks for classes and functions. int declaration_group_start() const { return declaration_group_start_; } protected: VariableDeclaration(Zone* zone, VariableProxy* proxy, VariableMode mode, Scope* scope, int pos, bool is_class_declaration = false, int declaration_group_start = -1) : Declaration(zone, proxy, mode, scope, pos), is_class_declaration_(is_class_declaration), declaration_group_start_(declaration_group_start) {} bool is_class_declaration_; int declaration_group_start_; }; class FunctionDeclaration final : public Declaration { public: DECLARE_NODE_TYPE(FunctionDeclaration) FunctionLiteral* fun() const { return fun_; } void set_fun(FunctionLiteral* f) { fun_ = f; } InitializationFlag initialization() const override { return kCreatedInitialized; } bool IsInlineable() const override; protected: FunctionDeclaration(Zone* zone, VariableProxy* proxy, VariableMode mode, FunctionLiteral* fun, Scope* scope, int pos) : Declaration(zone, proxy, mode, scope, pos), fun_(fun) { DCHECK(mode == VAR || mode == LET || mode == CONST); DCHECK(fun != NULL); } private: FunctionLiteral* fun_; }; class ImportDeclaration final : public Declaration { public: DECLARE_NODE_TYPE(ImportDeclaration) const AstRawString* import_name() const { return import_name_; } const AstRawString* module_specifier() const { return module_specifier_; } void set_module_specifier(const AstRawString* module_specifier) { DCHECK(module_specifier_ == NULL); module_specifier_ = module_specifier; } InitializationFlag initialization() const override { return kNeedsInitialization; } protected: ImportDeclaration(Zone* zone, VariableProxy* proxy, const AstRawString* import_name, const AstRawString* module_specifier, Scope* scope, int pos) : Declaration(zone, proxy, IMPORT, scope, pos), import_name_(import_name), module_specifier_(module_specifier) {} private: const AstRawString* import_name_; const AstRawString* module_specifier_; }; class ExportDeclaration final : public Declaration { public: DECLARE_NODE_TYPE(ExportDeclaration) InitializationFlag initialization() const override { return kCreatedInitialized; } protected: ExportDeclaration(Zone* zone, VariableProxy* proxy, Scope* scope, int pos) : Declaration(zone, proxy, LET, scope, pos) {} }; class Module : public AstNode { public: ModuleDescriptor* descriptor() const { return descriptor_; } Block* body() const { return body_; } protected: Module(Zone* zone, int pos) : AstNode(pos), descriptor_(ModuleDescriptor::New(zone)), body_(NULL) {} Module(Zone* zone, ModuleDescriptor* descriptor, int pos, Block* body = NULL) : AstNode(pos), descriptor_(descriptor), body_(body) {} private: ModuleDescriptor* descriptor_; Block* body_; }; class IterationStatement : public BreakableStatement { public: // Type testing & conversion. IterationStatement* AsIterationStatement() final { return this; } Statement* body() const { return body_; } void set_body(Statement* s) { body_ = s; } static int num_ids() { return parent_num_ids() + 1; } BailoutId OsrEntryId() const { return BailoutId(local_id(0)); } virtual BailoutId ContinueId() const = 0; virtual BailoutId StackCheckId() const = 0; // Code generation Label* continue_target() { return &continue_target_; } protected: IterationStatement(Zone* zone, ZoneList* labels, int pos) : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos), body_(NULL) {} static int parent_num_ids() { return BreakableStatement::num_ids(); } void Initialize(Statement* body) { body_ = body; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Statement* body_; Label continue_target_; }; class DoWhileStatement final : public IterationStatement { public: DECLARE_NODE_TYPE(DoWhileStatement) void Initialize(Expression* cond, Statement* body) { IterationStatement::Initialize(body); cond_ = cond; } Expression* cond() const { return cond_; } void set_cond(Expression* e) { cond_ = e; } static int num_ids() { return parent_num_ids() + 2; } BailoutId ContinueId() const override { return BailoutId(local_id(0)); } BailoutId StackCheckId() const override { return BackEdgeId(); } BailoutId BackEdgeId() const { return BailoutId(local_id(1)); } protected: DoWhileStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), cond_(NULL) {} static int parent_num_ids() { return IterationStatement::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* cond_; }; class WhileStatement final : public IterationStatement { public: DECLARE_NODE_TYPE(WhileStatement) void Initialize(Expression* cond, Statement* body) { IterationStatement::Initialize(body); cond_ = cond; } Expression* cond() const { return cond_; } void set_cond(Expression* e) { cond_ = e; } static int num_ids() { return parent_num_ids() + 1; } BailoutId ContinueId() const override { return EntryId(); } BailoutId StackCheckId() const override { return BodyId(); } BailoutId BodyId() const { return BailoutId(local_id(0)); } protected: WhileStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), cond_(NULL) {} static int parent_num_ids() { return IterationStatement::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* cond_; }; class ForStatement final : public IterationStatement { public: DECLARE_NODE_TYPE(ForStatement) void Initialize(Statement* init, Expression* cond, Statement* next, Statement* body) { IterationStatement::Initialize(body); init_ = init; cond_ = cond; next_ = next; } Statement* init() const { return init_; } Expression* cond() const { return cond_; } Statement* next() const { return next_; } void set_init(Statement* s) { init_ = s; } void set_cond(Expression* e) { cond_ = e; } void set_next(Statement* s) { next_ = s; } static int num_ids() { return parent_num_ids() + 2; } BailoutId ContinueId() const override { return BailoutId(local_id(0)); } BailoutId StackCheckId() const override { return BodyId(); } BailoutId BodyId() const { return BailoutId(local_id(1)); } protected: ForStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), init_(NULL), cond_(NULL), next_(NULL) {} static int parent_num_ids() { return IterationStatement::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Statement* init_; Expression* cond_; Statement* next_; }; class ForEachStatement : public IterationStatement { public: enum VisitMode { ENUMERATE, // for (each in subject) body; ITERATE // for (each of subject) body; }; void Initialize(Expression* each, Expression* subject, Statement* body) { IterationStatement::Initialize(body); each_ = each; subject_ = subject; } Expression* each() const { return each_; } Expression* subject() const { return subject_; } void set_each(Expression* e) { each_ = e; } void set_subject(Expression* e) { subject_ = e; } void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; FeedbackVectorSlot EachFeedbackSlot() const { return each_slot_; } protected: ForEachStatement(Zone* zone, ZoneList* labels, int pos) : IterationStatement(zone, labels, pos), each_(NULL), subject_(NULL) {} private: Expression* each_; Expression* subject_; FeedbackVectorSlot each_slot_; }; class ForInStatement final : public ForEachStatement { public: DECLARE_NODE_TYPE(ForInStatement) Expression* enumerable() const { return subject(); } // Type feedback information. void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override { ForEachStatement::AssignFeedbackVectorSlots(isolate, spec, cache); for_in_feedback_slot_ = spec->AddGeneralSlot(); } FeedbackVectorSlot ForInFeedbackSlot() { DCHECK(!for_in_feedback_slot_.IsInvalid()); return for_in_feedback_slot_; } enum ForInType { FAST_FOR_IN, SLOW_FOR_IN }; ForInType for_in_type() const { return for_in_type_; } void set_for_in_type(ForInType type) { for_in_type_ = type; } static int num_ids() { return parent_num_ids() + 6; } BailoutId BodyId() const { return BailoutId(local_id(0)); } BailoutId PrepareId() const { return BailoutId(local_id(1)); } BailoutId EnumId() const { return BailoutId(local_id(2)); } BailoutId ToObjectId() const { return BailoutId(local_id(3)); } BailoutId FilterId() const { return BailoutId(local_id(4)); } BailoutId AssignmentId() const { return BailoutId(local_id(5)); } BailoutId ContinueId() const override { return EntryId(); } BailoutId StackCheckId() const override { return BodyId(); } protected: ForInStatement(Zone* zone, ZoneList* labels, int pos) : ForEachStatement(zone, labels, pos), for_in_type_(SLOW_FOR_IN) {} static int parent_num_ids() { return ForEachStatement::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } ForInType for_in_type_; FeedbackVectorSlot for_in_feedback_slot_; }; class ForOfStatement final : public ForEachStatement { public: DECLARE_NODE_TYPE(ForOfStatement) void Initialize(Expression* each, Expression* subject, Statement* body, Expression* assign_iterator, Expression* next_result, Expression* result_done, Expression* assign_each) { ForEachStatement::Initialize(each, subject, body); assign_iterator_ = assign_iterator; next_result_ = next_result; result_done_ = result_done; assign_each_ = assign_each; } Expression* iterable() const { return subject(); } // iterator = subject[Symbol.iterator]() Expression* assign_iterator() const { return assign_iterator_; } // result = iterator.next() // with type check Expression* next_result() const { return next_result_; } // result.done Expression* result_done() const { return result_done_; } // each = result.value Expression* assign_each() const { return assign_each_; } void set_assign_iterator(Expression* e) { assign_iterator_ = e; } void set_next_result(Expression* e) { next_result_ = e; } void set_result_done(Expression* e) { result_done_ = e; } void set_assign_each(Expression* e) { assign_each_ = e; } BailoutId ContinueId() const override { return EntryId(); } BailoutId StackCheckId() const override { return BackEdgeId(); } static int num_ids() { return parent_num_ids() + 1; } BailoutId BackEdgeId() const { return BailoutId(local_id(0)); } protected: ForOfStatement(Zone* zone, ZoneList* labels, int pos) : ForEachStatement(zone, labels, pos), assign_iterator_(NULL), next_result_(NULL), result_done_(NULL), assign_each_(NULL) {} static int parent_num_ids() { return ForEachStatement::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* assign_iterator_; Expression* next_result_; Expression* result_done_; Expression* assign_each_; }; class ExpressionStatement final : public Statement { public: DECLARE_NODE_TYPE(ExpressionStatement) void set_expression(Expression* e) { expression_ = e; } Expression* expression() const { return expression_; } bool IsJump() const override { return expression_->IsThrow(); } void MarkTail() override { expression_->MarkTail(); } protected: ExpressionStatement(Zone* zone, Expression* expression, int pos) : Statement(zone, pos), expression_(expression) { } private: Expression* expression_; }; class JumpStatement : public Statement { public: bool IsJump() const final { return true; } protected: explicit JumpStatement(Zone* zone, int pos) : Statement(zone, pos) {} }; class ContinueStatement final : public JumpStatement { public: DECLARE_NODE_TYPE(ContinueStatement) IterationStatement* target() const { return target_; } protected: explicit ContinueStatement(Zone* zone, IterationStatement* target, int pos) : JumpStatement(zone, pos), target_(target) { } private: IterationStatement* target_; }; class BreakStatement final : public JumpStatement { public: DECLARE_NODE_TYPE(BreakStatement) BreakableStatement* target() const { return target_; } protected: explicit BreakStatement(Zone* zone, BreakableStatement* target, int pos) : JumpStatement(zone, pos), target_(target) { } private: BreakableStatement* target_; }; class ReturnStatement final : public JumpStatement { public: DECLARE_NODE_TYPE(ReturnStatement) Expression* expression() const { return expression_; } void set_expression(Expression* e) { expression_ = e; } protected: explicit ReturnStatement(Zone* zone, Expression* expression, int pos) : JumpStatement(zone, pos), expression_(expression) { } private: Expression* expression_; }; class WithStatement final : public Statement { public: DECLARE_NODE_TYPE(WithStatement) Scope* scope() { return scope_; } Expression* expression() const { return expression_; } void set_expression(Expression* e) { expression_ = e; } Statement* statement() const { return statement_; } void set_statement(Statement* s) { statement_ = s; } void set_base_id(int id) { base_id_ = id; } static int num_ids() { return parent_num_ids() + 2; } BailoutId ToObjectId() const { return BailoutId(local_id(0)); } BailoutId EntryId() const { return BailoutId(local_id(1)); } void MarkTail() override { statement_->MarkTail(); } protected: WithStatement(Zone* zone, Scope* scope, Expression* expression, Statement* statement, int pos) : Statement(zone, pos), scope_(scope), expression_(expression), statement_(statement), base_id_(BailoutId::None().ToInt()) {} static int parent_num_ids() { return 0; } int base_id() const { DCHECK(!BailoutId(base_id_).IsNone()); return base_id_; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Scope* scope_; Expression* expression_; Statement* statement_; int base_id_; }; class CaseClause final : public Expression { public: DECLARE_NODE_TYPE(CaseClause) bool is_default() const { return label_ == NULL; } Expression* label() const { CHECK(!is_default()); return label_; } void set_label(Expression* e) { label_ = e; } Label* body_target() { return &body_target_; } ZoneList* statements() const { return statements_; } static int num_ids() { return parent_num_ids() + 2; } BailoutId EntryId() const { return BailoutId(local_id(0)); } TypeFeedbackId CompareId() { return TypeFeedbackId(local_id(1)); } void MarkTail() override { if (!statements_->is_empty()) statements_->last()->MarkTail(); } Type* compare_type() { return compare_type_; } void set_compare_type(Type* type) { compare_type_ = type; } protected: static int parent_num_ids() { return Expression::num_ids(); } private: CaseClause(Zone* zone, Expression* label, ZoneList* statements, int pos); int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* label_; Label body_target_; ZoneList* statements_; Type* compare_type_; }; class SwitchStatement final : public BreakableStatement { public: DECLARE_NODE_TYPE(SwitchStatement) void Initialize(Expression* tag, ZoneList* cases) { tag_ = tag; cases_ = cases; } Expression* tag() const { return tag_; } ZoneList* cases() const { return cases_; } void set_tag(Expression* t) { tag_ = t; } void MarkTail() override { if (!cases_->is_empty()) cases_->last()->MarkTail(); } protected: SwitchStatement(Zone* zone, ZoneList* labels, int pos) : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos), tag_(NULL), cases_(NULL) {} private: Expression* tag_; ZoneList* cases_; }; // If-statements always have non-null references to their then- and // else-parts. When parsing if-statements with no explicit else-part, // the parser implicitly creates an empty statement. Use the // HasThenStatement() and HasElseStatement() functions to check if a // given if-statement has a then- or an else-part containing code. class IfStatement final : public Statement { public: DECLARE_NODE_TYPE(IfStatement) bool HasThenStatement() const { return !then_statement()->IsEmpty(); } bool HasElseStatement() const { return !else_statement()->IsEmpty(); } Expression* condition() const { return condition_; } Statement* then_statement() const { return then_statement_; } Statement* else_statement() const { return else_statement_; } void set_condition(Expression* e) { condition_ = e; } void set_then_statement(Statement* s) { then_statement_ = s; } void set_else_statement(Statement* s) { else_statement_ = s; } bool IsJump() const override { return HasThenStatement() && then_statement()->IsJump() && HasElseStatement() && else_statement()->IsJump(); } void MarkTail() override { then_statement_->MarkTail(); else_statement_->MarkTail(); } void set_base_id(int id) { base_id_ = id; } static int num_ids() { return parent_num_ids() + 3; } BailoutId IfId() const { return BailoutId(local_id(0)); } BailoutId ThenId() const { return BailoutId(local_id(1)); } BailoutId ElseId() const { return BailoutId(local_id(2)); } protected: IfStatement(Zone* zone, Expression* condition, Statement* then_statement, Statement* else_statement, int pos) : Statement(zone, pos), condition_(condition), then_statement_(then_statement), else_statement_(else_statement), base_id_(BailoutId::None().ToInt()) {} static int parent_num_ids() { return 0; } int base_id() const { DCHECK(!BailoutId(base_id_).IsNone()); return base_id_; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* condition_; Statement* then_statement_; Statement* else_statement_; int base_id_; }; class TryStatement : public Statement { public: Block* try_block() const { return try_block_; } void set_try_block(Block* b) { try_block_ = b; } void set_base_id(int id) { base_id_ = id; } static int num_ids() { return parent_num_ids() + 1; } BailoutId HandlerId() const { return BailoutId(local_id(0)); } protected: TryStatement(Zone* zone, Block* try_block, int pos) : Statement(zone, pos), try_block_(try_block), base_id_(BailoutId::None().ToInt()) {} static int parent_num_ids() { return 0; } int base_id() const { DCHECK(!BailoutId(base_id_).IsNone()); return base_id_; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Block* try_block_; int base_id_; }; class TryCatchStatement final : public TryStatement { public: DECLARE_NODE_TYPE(TryCatchStatement) Scope* scope() { return scope_; } Variable* variable() { return variable_; } Block* catch_block() const { return catch_block_; } void set_catch_block(Block* b) { catch_block_ = b; } void MarkTail() override { catch_block_->MarkTail(); } protected: TryCatchStatement(Zone* zone, Block* try_block, Scope* scope, Variable* variable, Block* catch_block, int pos) : TryStatement(zone, try_block, pos), scope_(scope), variable_(variable), catch_block_(catch_block) {} private: Scope* scope_; Variable* variable_; Block* catch_block_; }; class TryFinallyStatement final : public TryStatement { public: DECLARE_NODE_TYPE(TryFinallyStatement) Block* finally_block() const { return finally_block_; } void set_finally_block(Block* b) { finally_block_ = b; } void MarkTail() override { finally_block_->MarkTail(); } protected: TryFinallyStatement(Zone* zone, Block* try_block, Block* finally_block, int pos) : TryStatement(zone, try_block, pos), finally_block_(finally_block) {} private: Block* finally_block_; }; class DebuggerStatement final : public Statement { public: DECLARE_NODE_TYPE(DebuggerStatement) void set_base_id(int id) { base_id_ = id; } static int num_ids() { return parent_num_ids() + 1; } BailoutId DebugBreakId() const { return BailoutId(local_id(0)); } protected: explicit DebuggerStatement(Zone* zone, int pos) : Statement(zone, pos), base_id_(BailoutId::None().ToInt()) {} static int parent_num_ids() { return 0; } int base_id() const { DCHECK(!BailoutId(base_id_).IsNone()); return base_id_; } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } int base_id_; }; class EmptyStatement final : public Statement { public: DECLARE_NODE_TYPE(EmptyStatement) protected: explicit EmptyStatement(Zone* zone, int pos): Statement(zone, pos) {} }; // Delegates to another statement, which may be overwritten. // This was introduced to implement ES2015 Annex B3.3 for conditionally making // sloppy-mode block-scoped functions have a var binding, which is changed // from one statement to another during parsing. class SloppyBlockFunctionStatement final : public Statement { public: DECLARE_NODE_TYPE(SloppyBlockFunctionStatement) Statement* statement() const { return statement_; } void set_statement(Statement* statement) { statement_ = statement; } Scope* scope() const { return scope_; } private: SloppyBlockFunctionStatement(Zone* zone, Statement* statement, Scope* scope) : Statement(zone, RelocInfo::kNoPosition), statement_(statement), scope_(scope) {} Statement* statement_; Scope* const scope_; }; class Literal final : public Expression { public: DECLARE_NODE_TYPE(Literal) bool IsPropertyName() const override { return value_->IsPropertyName(); } Handle AsPropertyName() { DCHECK(IsPropertyName()); return Handle::cast(value()); } const AstRawString* AsRawPropertyName() { DCHECK(IsPropertyName()); return value_->AsString(); } bool ToBooleanIsTrue() const override { return value()->BooleanValue(); } bool ToBooleanIsFalse() const override { return !value()->BooleanValue(); } Handle value() const { return value_->value(); } const AstValue* raw_value() const { return value_; } // Support for using Literal as a HashMap key. NOTE: Currently, this works // only for string and number literals! uint32_t Hash(); static bool Match(void* literal1, void* literal2); static int num_ids() { return parent_num_ids() + 1; } TypeFeedbackId LiteralFeedbackId() const { return TypeFeedbackId(local_id(0)); } protected: Literal(Zone* zone, const AstValue* value, int position) : Expression(zone, position), value_(value) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } const AstValue* value_; }; class AstLiteralReindexer; // Base class for literals that needs space in the corresponding JSFunction. class MaterializedLiteral : public Expression { public: MaterializedLiteral* AsMaterializedLiteral() final { return this; } int literal_index() { return literal_index_; } int depth() const { // only callable after initialization. DCHECK(depth_ >= 1); return depth_; } bool is_strong() const { return is_strong_; } protected: MaterializedLiteral(Zone* zone, int literal_index, bool is_strong, int pos) : Expression(zone, pos), literal_index_(literal_index), is_simple_(false), is_strong_(is_strong), depth_(0) {} // A materialized literal is simple if the values consist of only // constants and simple object and array literals. bool is_simple() const { return is_simple_; } void set_is_simple(bool is_simple) { is_simple_ = is_simple; } friend class CompileTimeValue; void set_depth(int depth) { DCHECK(depth >= 1); depth_ = depth; } // Populate the constant properties/elements fixed array. void BuildConstants(Isolate* isolate); friend class ArrayLiteral; friend class ObjectLiteral; // If the expression is a literal, return the literal value; // if the expression is a materialized literal and is simple return a // compile time value as encoded by CompileTimeValue::GetValue(). // Otherwise, return undefined literal as the placeholder // in the object literal boilerplate. Handle GetBoilerplateValue(Expression* expression, Isolate* isolate); private: int literal_index_; bool is_simple_; bool is_strong_; int depth_; friend class AstLiteralReindexer; }; // Property is used for passing information // about an object literal's properties from the parser // to the code generator. class ObjectLiteralProperty final : public ZoneObject { public: enum Kind { CONSTANT, // Property with constant value (compile time). COMPUTED, // Property with computed value (execution time). MATERIALIZED_LITERAL, // Property value is a materialized literal. GETTER, SETTER, // Property is an accessor function. PROTOTYPE // Property is __proto__. }; Expression* key() { return key_; } Expression* value() { return value_; } Kind kind() { return kind_; } void set_key(Expression* e) { key_ = e; } void set_value(Expression* e) { value_ = e; } // Type feedback information. bool IsMonomorphic() { return !receiver_type_.is_null(); } Handle GetReceiverType() { return receiver_type_; } bool IsCompileTimeValue(); void set_emit_store(bool emit_store); bool emit_store(); bool is_static() const { return is_static_; } bool is_computed_name() const { return is_computed_name_; } FeedbackVectorSlot GetSlot(int offset = 0) const { DCHECK_LT(offset, static_cast(arraysize(slots_))); return slots_[offset]; } void SetSlot(FeedbackVectorSlot slot, int offset = 0) { DCHECK_LT(offset, static_cast(arraysize(slots_))); slots_[offset] = slot; } void set_receiver_type(Handle map) { receiver_type_ = map; } protected: friend class AstNodeFactory; ObjectLiteralProperty(Expression* key, Expression* value, Kind kind, bool is_static, bool is_computed_name); ObjectLiteralProperty(AstValueFactory* ast_value_factory, Expression* key, Expression* value, bool is_static, bool is_computed_name); private: Expression* key_; Expression* value_; FeedbackVectorSlot slots_[2]; Kind kind_; bool emit_store_; bool is_static_; bool is_computed_name_; Handle receiver_type_; }; // An object literal has a boilerplate object that is used // for minimizing the work when constructing it at runtime. class ObjectLiteral final : public MaterializedLiteral { public: typedef ObjectLiteralProperty Property; DECLARE_NODE_TYPE(ObjectLiteral) Handle constant_properties() const { return constant_properties_; } int properties_count() const { return constant_properties_->length() / 2; } ZoneList* properties() const { return properties_; } bool fast_elements() const { return fast_elements_; } bool may_store_doubles() const { return may_store_doubles_; } bool has_function() const { return has_function_; } bool has_elements() const { return has_elements_; } // Decide if a property should be in the object boilerplate. static bool IsBoilerplateProperty(Property* property); // Populate the constant properties fixed array. void BuildConstantProperties(Isolate* isolate); // Mark all computed expressions that are bound to a key that // is shadowed by a later occurrence of the same key. For the // marked expressions, no store code is emitted. void CalculateEmitStore(Zone* zone); // Assemble bitfield of flags for the CreateObjectLiteral helper. int ComputeFlags(bool disable_mementos = false) const { int flags = fast_elements() ? kFastElements : kNoFlags; flags |= has_function() ? kHasFunction : kNoFlags; if (depth() == 1 && !has_elements() && !may_store_doubles()) { flags |= kShallowProperties; } if (disable_mementos) { flags |= kDisableMementos; } if (is_strong()) { flags |= kIsStrong; } return flags; } enum Flags { kNoFlags = 0, kFastElements = 1, kHasFunction = 1 << 1, kShallowProperties = 1 << 2, kDisableMementos = 1 << 3, kIsStrong = 1 << 4 }; struct Accessors: public ZoneObject { Accessors() : getter(NULL), setter(NULL) {} ObjectLiteralProperty* getter; ObjectLiteralProperty* setter; }; BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); } // Return an AST id for a property that is used in simulate instructions. BailoutId GetIdForPropertyName(int i) { return BailoutId(local_id(2 * i + 1)); } BailoutId GetIdForPropertySet(int i) { return BailoutId(local_id(2 * i + 2)); } // Unlike other AST nodes, this number of bailout IDs allocated for an // ObjectLiteral can vary, so num_ids() is not a static method. int num_ids() const { return parent_num_ids() + 1 + 2 * properties()->length(); } // Object literals need one feedback slot for each non-trivial value, as well // as some slots for home objects. void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; protected: ObjectLiteral(Zone* zone, ZoneList* properties, int literal_index, int boilerplate_properties, bool has_function, bool is_strong, int pos) : MaterializedLiteral(zone, literal_index, is_strong, pos), properties_(properties), boilerplate_properties_(boilerplate_properties), fast_elements_(false), has_elements_(false), may_store_doubles_(false), has_function_(has_function) {} static int parent_num_ids() { return MaterializedLiteral::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Handle constant_properties_; ZoneList* properties_; int boilerplate_properties_; bool fast_elements_; bool has_elements_; bool may_store_doubles_; bool has_function_; FeedbackVectorSlot slot_; }; // A map from property names to getter/setter pairs allocated in the zone. class AccessorTable : public TemplateHashMap { public: explicit AccessorTable(Zone* zone) : TemplateHashMap(Literal::Match, ZoneAllocationPolicy(zone)), zone_(zone) {} Iterator lookup(Literal* literal) { Iterator it = find(literal, true, ZoneAllocationPolicy(zone_)); if (it->second == NULL) it->second = new (zone_) ObjectLiteral::Accessors(); return it; } private: Zone* zone_; }; // Node for capturing a regexp literal. class RegExpLiteral final : public MaterializedLiteral { public: DECLARE_NODE_TYPE(RegExpLiteral) Handle pattern() const { return pattern_->string(); } int flags() const { return flags_; } protected: RegExpLiteral(Zone* zone, const AstRawString* pattern, int flags, int literal_index, bool is_strong, int pos) : MaterializedLiteral(zone, literal_index, is_strong, pos), pattern_(pattern), flags_(flags) { set_depth(1); } private: const AstRawString* const pattern_; int const flags_; }; // An array literal has a literals object that is used // for minimizing the work when constructing it at runtime. class ArrayLiteral final : public MaterializedLiteral { public: DECLARE_NODE_TYPE(ArrayLiteral) Handle constant_elements() const { return constant_elements_; } ElementsKind constant_elements_kind() const { DCHECK_EQ(2, constant_elements_->length()); return static_cast( Smi::cast(constant_elements_->get(0))->value()); } ZoneList* values() const { return values_; } BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); } // Return an AST id for an element that is used in simulate instructions. BailoutId GetIdForElement(int i) { return BailoutId(local_id(i + 1)); } // Unlike other AST nodes, this number of bailout IDs allocated for an // ArrayLiteral can vary, so num_ids() is not a static method. int num_ids() const { return parent_num_ids() + 1 + values()->length(); } // Populate the constant elements fixed array. void BuildConstantElements(Isolate* isolate); // Assemble bitfield of flags for the CreateArrayLiteral helper. int ComputeFlags(bool disable_mementos = false) const { int flags = depth() == 1 ? kShallowElements : kNoFlags; if (disable_mementos) { flags |= kDisableMementos; } if (is_strong()) { flags |= kIsStrong; } return flags; } enum Flags { kNoFlags = 0, kShallowElements = 1, kDisableMementos = 1 << 1, kIsStrong = 1 << 2 }; void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; FeedbackVectorSlot LiteralFeedbackSlot() const { return literal_slot_; } protected: ArrayLiteral(Zone* zone, ZoneList* values, int first_spread_index, int literal_index, bool is_strong, int pos) : MaterializedLiteral(zone, literal_index, is_strong, pos), values_(values), first_spread_index_(first_spread_index) {} static int parent_num_ids() { return MaterializedLiteral::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Handle constant_elements_; ZoneList* values_; int first_spread_index_; FeedbackVectorSlot literal_slot_; }; class VariableProxy final : public Expression { public: DECLARE_NODE_TYPE(VariableProxy) bool IsValidReferenceExpression() const override { return !is_this() && !is_new_target(); } bool IsArguments() const { return is_resolved() && var()->is_arguments(); } Handle name() const { return raw_name()->string(); } const AstRawString* raw_name() const { return is_resolved() ? var_->raw_name() : raw_name_; } Variable* var() const { DCHECK(is_resolved()); return var_; } void set_var(Variable* v) { DCHECK(!is_resolved()); DCHECK_NOT_NULL(v); var_ = v; } bool is_this() const { return IsThisField::decode(bit_field_); } bool is_assigned() const { return IsAssignedField::decode(bit_field_); } void set_is_assigned() { bit_field_ = IsAssignedField::update(bit_field_, true); } bool is_resolved() const { return IsResolvedField::decode(bit_field_); } void set_is_resolved() { bit_field_ = IsResolvedField::update(bit_field_, true); } bool is_new_target() const { return IsNewTargetField::decode(bit_field_); } void set_is_new_target() { bit_field_ = IsNewTargetField::update(bit_field_, true); } int end_position() const { return end_position_; } // Bind this proxy to the variable var. void BindTo(Variable* var); bool UsesVariableFeedbackSlot() const { return var()->IsUnallocated() || var()->IsLookupSlot(); } void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; FeedbackVectorSlot VariableFeedbackSlot() { return variable_feedback_slot_; } static int num_ids() { return parent_num_ids() + 1; } BailoutId BeforeId() const { return BailoutId(local_id(0)); } protected: VariableProxy(Zone* zone, Variable* var, int start_position, int end_position); VariableProxy(Zone* zone, const AstRawString* name, Variable::Kind variable_kind, int start_position, int end_position); static int parent_num_ids() { return Expression::num_ids(); } int local_id(int n) const { return base_id() + parent_num_ids() + n; } class IsThisField : public BitField8 {}; class IsAssignedField : public BitField8 {}; class IsResolvedField : public BitField8 {}; class IsNewTargetField : public BitField8 {}; // Start with 16-bit (or smaller) field, which should get packed together // with Expression's trailing 16-bit field. uint8_t bit_field_; FeedbackVectorSlot variable_feedback_slot_; union { const AstRawString* raw_name_; // if !is_resolved_ Variable* var_; // if is_resolved_ }; // Position is stored in the AstNode superclass, but VariableProxy needs to // know its end position too (for error messages). It cannot be inferred from // the variable name length because it can contain escapes. int end_position_; }; // Left-hand side can only be a property, a global or a (parameter or local) // slot. enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY, NAMED_SUPER_PROPERTY, KEYED_SUPER_PROPERTY }; class Property final : public Expression { public: DECLARE_NODE_TYPE(Property) bool IsValidReferenceExpression() const override { return true; } Expression* obj() const { return obj_; } Expression* key() const { return key_; } void set_obj(Expression* e) { obj_ = e; } void set_key(Expression* e) { key_ = e; } static int num_ids() { return parent_num_ids() + 1; } BailoutId LoadId() const { return BailoutId(local_id(0)); } bool IsStringAccess() const { return IsStringAccessField::decode(bit_field_); } // Type feedback information. bool IsMonomorphic() override { return receiver_types_.length() == 1; } SmallMapList* GetReceiverTypes() override { return &receiver_types_; } KeyedAccessStoreMode GetStoreMode() const override { return STANDARD_STORE; } IcCheckType GetKeyType() const override { return KeyTypeField::decode(bit_field_); } bool IsUninitialized() const { return !is_for_call() && HasNoTypeInformation(); } bool HasNoTypeInformation() const { return GetInlineCacheState() == UNINITIALIZED; } InlineCacheState GetInlineCacheState() const { return InlineCacheStateField::decode(bit_field_); } void set_is_string_access(bool b) { bit_field_ = IsStringAccessField::update(bit_field_, b); } void set_key_type(IcCheckType key_type) { bit_field_ = KeyTypeField::update(bit_field_, key_type); } void set_inline_cache_state(InlineCacheState state) { bit_field_ = InlineCacheStateField::update(bit_field_, state); } void mark_for_call() { bit_field_ = IsForCallField::update(bit_field_, true); } bool is_for_call() const { return IsForCallField::decode(bit_field_); } bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); } void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override { FeedbackVectorSlotKind kind = key()->IsPropertyName() ? FeedbackVectorSlotKind::LOAD_IC : FeedbackVectorSlotKind::KEYED_LOAD_IC; property_feedback_slot_ = spec->AddSlot(kind); } FeedbackVectorSlot PropertyFeedbackSlot() const { return property_feedback_slot_; } static LhsKind GetAssignType(Property* property) { if (property == NULL) return VARIABLE; bool super_access = property->IsSuperAccess(); return (property->key()->IsPropertyName()) ? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY) : (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY); } protected: Property(Zone* zone, Expression* obj, Expression* key, int pos) : Expression(zone, pos), bit_field_(IsForCallField::encode(false) | IsStringAccessField::encode(false) | InlineCacheStateField::encode(UNINITIALIZED)), obj_(obj), key_(key) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } class IsForCallField : public BitField8 {}; class IsStringAccessField : public BitField8 {}; class KeyTypeField : public BitField8 {}; class InlineCacheStateField : public BitField8 {}; uint8_t bit_field_; FeedbackVectorSlot property_feedback_slot_; Expression* obj_; Expression* key_; SmallMapList receiver_types_; }; class Call final : public Expression { public: DECLARE_NODE_TYPE(Call) Expression* expression() const { return expression_; } ZoneList* arguments() const { return arguments_; } void set_expression(Expression* e) { expression_ = e; } // Type feedback information. void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; FeedbackVectorSlot CallFeedbackSlot() const { return stub_slot_; } FeedbackVectorSlot CallFeedbackICSlot() const { return ic_slot_; } SmallMapList* GetReceiverTypes() override { if (expression()->IsProperty()) { return expression()->AsProperty()->GetReceiverTypes(); } return NULL; } bool IsMonomorphic() override { if (expression()->IsProperty()) { return expression()->AsProperty()->IsMonomorphic(); } return !target_.is_null(); } bool global_call() const { VariableProxy* proxy = expression_->AsVariableProxy(); return proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot(); } bool known_global_function() const { return global_call() && !target_.is_null(); } Handle target() { return target_; } Handle allocation_site() { return allocation_site_; } void SetKnownGlobalTarget(Handle target) { target_ = target; set_is_uninitialized(false); } void set_target(Handle target) { target_ = target; } void set_allocation_site(Handle site) { allocation_site_ = site; } static int num_ids() { return parent_num_ids() + 4; } BailoutId ReturnId() const { return BailoutId(local_id(0)); } BailoutId EvalId() const { return BailoutId(local_id(1)); } BailoutId LookupId() const { return BailoutId(local_id(2)); } BailoutId CallId() const { return BailoutId(local_id(3)); } bool is_uninitialized() const { return IsUninitializedField::decode(bit_field_); } void set_is_uninitialized(bool b) { bit_field_ = IsUninitializedField::update(bit_field_, b); } bool is_tail() const { return IsTailField::decode(bit_field_); } void MarkTail() override { bit_field_ = IsTailField::update(bit_field_, true); } enum CallType { POSSIBLY_EVAL_CALL, GLOBAL_CALL, LOOKUP_SLOT_CALL, NAMED_PROPERTY_CALL, KEYED_PROPERTY_CALL, NAMED_SUPER_PROPERTY_CALL, KEYED_SUPER_PROPERTY_CALL, SUPER_CALL, OTHER_CALL }; // Helpers to determine how to handle the call. CallType GetCallType(Isolate* isolate) const; bool IsUsingCallFeedbackSlot(Isolate* isolate) const; bool IsUsingCallFeedbackICSlot(Isolate* isolate) const; #ifdef DEBUG // Used to assert that the FullCodeGenerator records the return site. bool return_is_recorded_; #endif protected: Call(Zone* zone, Expression* expression, ZoneList* arguments, int pos) : Expression(zone, pos), expression_(expression), arguments_(arguments), bit_field_(IsUninitializedField::encode(false)) { if (expression->IsProperty()) { expression->AsProperty()->mark_for_call(); } } static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } FeedbackVectorSlot ic_slot_; FeedbackVectorSlot stub_slot_; Expression* expression_; ZoneList* arguments_; Handle target_; Handle allocation_site_; class IsUninitializedField : public BitField8 {}; class IsTailField : public BitField8 {}; uint8_t bit_field_; }; class CallNew final : public Expression { public: DECLARE_NODE_TYPE(CallNew) Expression* expression() const { return expression_; } ZoneList* arguments() const { return arguments_; } void set_expression(Expression* e) { expression_ = e; } // Type feedback information. void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override { callnew_feedback_slot_ = spec->AddGeneralSlot(); } FeedbackVectorSlot CallNewFeedbackSlot() { DCHECK(!callnew_feedback_slot_.IsInvalid()); return callnew_feedback_slot_; } bool IsMonomorphic() override { return is_monomorphic_; } Handle target() const { return target_; } Handle allocation_site() const { return allocation_site_; } static int num_ids() { return parent_num_ids() + 1; } static int feedback_slots() { return 1; } BailoutId ReturnId() const { return BailoutId(local_id(0)); } void set_allocation_site(Handle site) { allocation_site_ = site; } void set_is_monomorphic(bool monomorphic) { is_monomorphic_ = monomorphic; } void set_target(Handle target) { target_ = target; } void SetKnownGlobalTarget(Handle target) { target_ = target; is_monomorphic_ = true; } protected: CallNew(Zone* zone, Expression* expression, ZoneList* arguments, int pos) : Expression(zone, pos), expression_(expression), arguments_(arguments), is_monomorphic_(false) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* expression_; ZoneList* arguments_; bool is_monomorphic_; Handle target_; Handle allocation_site_; FeedbackVectorSlot callnew_feedback_slot_; }; // The CallRuntime class does not represent any official JavaScript // language construct. Instead it is used to call a C or JS function // with a set of arguments. This is used from the builtins that are // implemented in JavaScript (see "v8natives.js"). class CallRuntime final : public Expression { public: DECLARE_NODE_TYPE(CallRuntime) ZoneList* arguments() const { return arguments_; } bool is_jsruntime() const { return function_ == NULL; } int context_index() const { DCHECK(is_jsruntime()); return context_index_; } const Runtime::Function* function() const { DCHECK(!is_jsruntime()); return function_; } static int num_ids() { return parent_num_ids() + 1; } BailoutId CallId() { return BailoutId(local_id(0)); } const char* debug_name() { return is_jsruntime() ? "(context function)" : function_->name; } protected: CallRuntime(Zone* zone, const Runtime::Function* function, ZoneList* arguments, int pos) : Expression(zone, pos), function_(function), arguments_(arguments) {} CallRuntime(Zone* zone, int context_index, ZoneList* arguments, int pos) : Expression(zone, pos), function_(NULL), context_index_(context_index), arguments_(arguments) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } const Runtime::Function* function_; int context_index_; ZoneList* arguments_; }; class UnaryOperation final : public Expression { public: DECLARE_NODE_TYPE(UnaryOperation) Token::Value op() const { return op_; } Expression* expression() const { return expression_; } void set_expression(Expression* e) { expression_ = e; } // For unary not (Token::NOT), the AST ids where true and false will // actually be materialized, respectively. static int num_ids() { return parent_num_ids() + 2; } BailoutId MaterializeTrueId() const { return BailoutId(local_id(0)); } BailoutId MaterializeFalseId() const { return BailoutId(local_id(1)); } void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) override; protected: UnaryOperation(Zone* zone, Token::Value op, Expression* expression, int pos) : Expression(zone, pos), op_(op), expression_(expression) { DCHECK(Token::IsUnaryOp(op)); } static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Token::Value op_; Expression* expression_; }; class BinaryOperation final : public Expression { public: DECLARE_NODE_TYPE(BinaryOperation) Token::Value op() const { return static_cast(op_); } Expression* left() const { return left_; } void set_left(Expression* e) { left_ = e; } Expression* right() const { return right_; } void set_right(Expression* e) { right_ = e; } Handle allocation_site() const { return allocation_site_; } void set_allocation_site(Handle allocation_site) { allocation_site_ = allocation_site; } void MarkTail() override { switch (op()) { case Token::COMMA: case Token::AND: case Token::OR: right_->MarkTail(); default: break; } } // The short-circuit logical operations need an AST ID for their // right-hand subexpression. static int num_ids() { return parent_num_ids() + 2; } BailoutId RightId() const { return BailoutId(local_id(0)); } TypeFeedbackId BinaryOperationFeedbackId() const { return TypeFeedbackId(local_id(1)); } Maybe fixed_right_arg() const { return has_fixed_right_arg_ ? Just(fixed_right_arg_value_) : Nothing(); } void set_fixed_right_arg(Maybe arg) { has_fixed_right_arg_ = arg.IsJust(); if (arg.IsJust()) fixed_right_arg_value_ = arg.FromJust(); } void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) override; protected: BinaryOperation(Zone* zone, Token::Value op, Expression* left, Expression* right, int pos) : Expression(zone, pos), op_(static_cast(op)), has_fixed_right_arg_(false), fixed_right_arg_value_(0), left_(left), right_(right) { DCHECK(Token::IsBinaryOp(op)); } static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } const byte op_; // actually Token::Value // TODO(rossberg): the fixed arg should probably be represented as a Constant // type for the RHS. Currenty it's actually a Maybe bool has_fixed_right_arg_; int fixed_right_arg_value_; Expression* left_; Expression* right_; Handle allocation_site_; }; class CountOperation final : public Expression { public: DECLARE_NODE_TYPE(CountOperation) bool is_prefix() const { return IsPrefixField::decode(bit_field_); } bool is_postfix() const { return !is_prefix(); } Token::Value op() const { return TokenField::decode(bit_field_); } Token::Value binary_op() { return (op() == Token::INC) ? Token::ADD : Token::SUB; } Expression* expression() const { return expression_; } void set_expression(Expression* e) { expression_ = e; } bool IsMonomorphic() override { return receiver_types_.length() == 1; } SmallMapList* GetReceiverTypes() override { return &receiver_types_; } IcCheckType GetKeyType() const override { return KeyTypeField::decode(bit_field_); } KeyedAccessStoreMode GetStoreMode() const override { return StoreModeField::decode(bit_field_); } Type* type() const { return type_; } void set_key_type(IcCheckType type) { bit_field_ = KeyTypeField::update(bit_field_, type); } void set_store_mode(KeyedAccessStoreMode mode) { bit_field_ = StoreModeField::update(bit_field_, mode); } void set_type(Type* type) { type_ = type; } static int num_ids() { return parent_num_ids() + 4; } BailoutId AssignmentId() const { return BailoutId(local_id(0)); } BailoutId ToNumberId() const { return BailoutId(local_id(1)); } TypeFeedbackId CountBinOpFeedbackId() const { return TypeFeedbackId(local_id(2)); } TypeFeedbackId CountStoreFeedbackId() const { return TypeFeedbackId(local_id(3)); } void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; FeedbackVectorSlot CountSlot() const { return slot_; } protected: CountOperation(Zone* zone, Token::Value op, bool is_prefix, Expression* expr, int pos) : Expression(zone, pos), bit_field_( IsPrefixField::encode(is_prefix) | KeyTypeField::encode(ELEMENT) | StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)), type_(NULL), expression_(expr) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } class IsPrefixField : public BitField16 {}; class KeyTypeField : public BitField16 {}; class StoreModeField : public BitField16 {}; class TokenField : public BitField16 {}; // Starts with 16-bit field, which should get packed together with // Expression's trailing 16-bit field. uint16_t bit_field_; Type* type_; Expression* expression_; SmallMapList receiver_types_; FeedbackVectorSlot slot_; }; class CompareOperation final : public Expression { public: DECLARE_NODE_TYPE(CompareOperation) Token::Value op() const { return op_; } Expression* left() const { return left_; } Expression* right() const { return right_; } void set_left(Expression* e) { left_ = e; } void set_right(Expression* e) { right_ = e; } // Type feedback information. static int num_ids() { return parent_num_ids() + 1; } TypeFeedbackId CompareOperationFeedbackId() const { return TypeFeedbackId(local_id(0)); } Type* combined_type() const { return combined_type_; } void set_combined_type(Type* type) { combined_type_ = type; } // Match special cases. bool IsLiteralCompareTypeof(Expression** expr, Handle* check); bool IsLiteralCompareUndefined(Expression** expr, Isolate* isolate); bool IsLiteralCompareNull(Expression** expr); protected: CompareOperation(Zone* zone, Token::Value op, Expression* left, Expression* right, int pos) : Expression(zone, pos), op_(op), left_(left), right_(right), combined_type_(Type::None(zone)) { DCHECK(Token::IsCompareOp(op)); } static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Token::Value op_; Expression* left_; Expression* right_; Type* combined_type_; }; class Spread final : public Expression { public: DECLARE_NODE_TYPE(Spread) Expression* expression() const { return expression_; } void set_expression(Expression* e) { expression_ = e; } static int num_ids() { return parent_num_ids(); } protected: Spread(Zone* zone, Expression* expression, int pos) : Expression(zone, pos), expression_(expression) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* expression_; }; class Conditional final : public Expression { public: DECLARE_NODE_TYPE(Conditional) Expression* condition() const { return condition_; } Expression* then_expression() const { return then_expression_; } Expression* else_expression() const { return else_expression_; } void set_condition(Expression* e) { condition_ = e; } void set_then_expression(Expression* e) { then_expression_ = e; } void set_else_expression(Expression* e) { else_expression_ = e; } void MarkTail() override { then_expression_->MarkTail(); else_expression_->MarkTail(); } static int num_ids() { return parent_num_ids() + 2; } BailoutId ThenId() const { return BailoutId(local_id(0)); } BailoutId ElseId() const { return BailoutId(local_id(1)); } protected: Conditional(Zone* zone, Expression* condition, Expression* then_expression, Expression* else_expression, int position) : Expression(zone, position), condition_(condition), then_expression_(then_expression), else_expression_(else_expression) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } Expression* condition_; Expression* then_expression_; Expression* else_expression_; }; class Assignment final : public Expression { public: DECLARE_NODE_TYPE(Assignment) Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; } Token::Value binary_op() const; Token::Value op() const { return TokenField::decode(bit_field_); } Expression* target() const { return target_; } Expression* value() const { return value_; } void set_target(Expression* e) { target_ = e; } void set_value(Expression* e) { value_ = e; } BinaryOperation* binary_operation() const { return binary_operation_; } // This check relies on the definition order of token in token.h. bool is_compound() const { return op() > Token::ASSIGN; } static int num_ids() { return parent_num_ids() + 2; } BailoutId AssignmentId() const { return BailoutId(local_id(0)); } // Type feedback information. TypeFeedbackId AssignmentFeedbackId() { return TypeFeedbackId(local_id(1)); } bool IsMonomorphic() override { return receiver_types_.length() == 1; } bool IsUninitialized() const { return IsUninitializedField::decode(bit_field_); } bool HasNoTypeInformation() { return IsUninitializedField::decode(bit_field_); } SmallMapList* GetReceiverTypes() override { return &receiver_types_; } IcCheckType GetKeyType() const override { return KeyTypeField::decode(bit_field_); } KeyedAccessStoreMode GetStoreMode() const override { return StoreModeField::decode(bit_field_); } void set_is_uninitialized(bool b) { bit_field_ = IsUninitializedField::update(bit_field_, b); } void set_key_type(IcCheckType key_type) { bit_field_ = KeyTypeField::update(bit_field_, key_type); } void set_store_mode(KeyedAccessStoreMode mode) { bit_field_ = StoreModeField::update(bit_field_, mode); } void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; FeedbackVectorSlot AssignmentSlot() const { return slot_; } protected: Assignment(Zone* zone, Token::Value op, Expression* target, Expression* value, int pos); static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } class IsUninitializedField : public BitField16 {}; class KeyTypeField : public BitField16 {}; class StoreModeField : public BitField16 {}; class TokenField : public BitField16 { }; // Starts with 16-bit field, which should get packed together with // Expression's trailing 16-bit field. uint16_t bit_field_; Expression* target_; Expression* value_; BinaryOperation* binary_operation_; SmallMapList receiver_types_; FeedbackVectorSlot slot_; }; class RewritableAssignmentExpression : public Expression { public: DECLARE_NODE_TYPE(RewritableAssignmentExpression) Expression* expression() { return expr_; } bool is_rewritten() const { return is_rewritten_; } void set_expression(Expression* e) { expr_ = e; } void Rewrite(Expression* new_expression) { DCHECK(!is_rewritten()); DCHECK_NOT_NULL(new_expression); expr_ = new_expression; is_rewritten_ = true; } static int num_ids() { return parent_num_ids(); } protected: RewritableAssignmentExpression(Zone* zone, Expression* expression) : Expression(zone, expression->position()), is_rewritten_(false), expr_(expression) {} private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } bool is_rewritten_; Expression* expr_; }; class Yield final : public Expression { public: DECLARE_NODE_TYPE(Yield) enum Kind { kInitial, // The initial yield that returns the unboxed generator object. kSuspend, // A normal yield: { value: EXPRESSION, done: false } kDelegating, // A yield*. kFinal // A return: { value: EXPRESSION, done: true } }; Expression* generator_object() const { return generator_object_; } Expression* expression() const { return expression_; } Kind yield_kind() const { return yield_kind_; } void set_generator_object(Expression* e) { generator_object_ = e; } void set_expression(Expression* e) { expression_ = e; } // Type feedback information. bool HasFeedbackSlots() const { return yield_kind() == kDelegating; } void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override { if (HasFeedbackSlots()) { yield_first_feedback_slot_ = spec->AddKeyedLoadICSlot(); keyed_load_feedback_slot_ = spec->AddLoadICSlot(); done_feedback_slot_ = spec->AddLoadICSlot(); } } FeedbackVectorSlot KeyedLoadFeedbackSlot() { DCHECK(!HasFeedbackSlots() || !yield_first_feedback_slot_.IsInvalid()); return yield_first_feedback_slot_; } FeedbackVectorSlot DoneFeedbackSlot() { return keyed_load_feedback_slot_; } FeedbackVectorSlot ValueFeedbackSlot() { return done_feedback_slot_; } protected: Yield(Zone* zone, Expression* generator_object, Expression* expression, Kind yield_kind, int pos) : Expression(zone, pos), generator_object_(generator_object), expression_(expression), yield_kind_(yield_kind) {} private: Expression* generator_object_; Expression* expression_; Kind yield_kind_; FeedbackVectorSlot yield_first_feedback_slot_; FeedbackVectorSlot keyed_load_feedback_slot_; FeedbackVectorSlot done_feedback_slot_; }; class Throw final : public Expression { public: DECLARE_NODE_TYPE(Throw) Expression* exception() const { return exception_; } void set_exception(Expression* e) { exception_ = e; } protected: Throw(Zone* zone, Expression* exception, int pos) : Expression(zone, pos), exception_(exception) {} private: Expression* exception_; }; class FunctionLiteral final : public Expression { public: enum FunctionType { kAnonymousExpression, kNamedExpression, kDeclaration, kGlobalOrEval }; enum ParameterFlag { kNoDuplicateParameters, kHasDuplicateParameters }; enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile }; enum ArityRestriction { kNormalArity, kGetterArity, kSetterArity }; DECLARE_NODE_TYPE(FunctionLiteral) Handle name() const { return raw_name_->string(); } const AstString* raw_name() const { return raw_name_; } void set_raw_name(const AstString* name) { raw_name_ = name; } Scope* scope() const { return scope_; } ZoneList* body() const { return body_; } void set_function_token_position(int pos) { function_token_position_ = pos; } int function_token_position() const { return function_token_position_; } int start_position() const; int end_position() const; int SourceSize() const { return end_position() - start_position(); } bool is_expression() const { return IsExpression::decode(bitfield_); } bool is_anonymous() const { return IsAnonymous::decode(bitfield_); } LanguageMode language_mode() const; static bool NeedsHomeObject(Expression* expr); int materialized_literal_count() { return materialized_literal_count_; } int expected_property_count() { return expected_property_count_; } int parameter_count() { return parameter_count_; } bool AllowsLazyCompilation(); bool AllowsLazyCompilationWithoutContext(); Handle debug_name() const { if (raw_name_ != NULL && !raw_name_->IsEmpty()) { return raw_name_->string(); } return inferred_name(); } Handle inferred_name() const { if (!inferred_name_.is_null()) { DCHECK(raw_inferred_name_ == NULL); return inferred_name_; } if (raw_inferred_name_ != NULL) { return raw_inferred_name_->string(); } UNREACHABLE(); return Handle(); } // Only one of {set_inferred_name, set_raw_inferred_name} should be called. void set_inferred_name(Handle inferred_name) { DCHECK(!inferred_name.is_null()); inferred_name_ = inferred_name; DCHECK(raw_inferred_name_== NULL || raw_inferred_name_->IsEmpty()); raw_inferred_name_ = NULL; } void set_raw_inferred_name(const AstString* raw_inferred_name) { DCHECK(raw_inferred_name != NULL); raw_inferred_name_ = raw_inferred_name; DCHECK(inferred_name_.is_null()); inferred_name_ = Handle(); } bool pretenure() const { return Pretenure::decode(bitfield_); } void set_pretenure() { bitfield_ = Pretenure::update(bitfield_, true); } bool has_duplicate_parameters() const { return HasDuplicateParameters::decode(bitfield_); } bool is_function() const { return IsFunction::decode(bitfield_); } // This is used as a heuristic on when to eagerly compile a function // literal. We consider the following constructs as hints that the // function will be called immediately: // - (function() { ... })(); // - var x = function() { ... }(); bool should_eager_compile() const { return ShouldEagerCompile::decode(bitfield_); } void set_should_eager_compile() { bitfield_ = ShouldEagerCompile::update(bitfield_, true); } // A hint that we expect this function to be called (exactly) once, // i.e. we suspect it's an initialization function. bool should_be_used_once_hint() const { return ShouldBeUsedOnceHint::decode(bitfield_); } void set_should_be_used_once_hint() { bitfield_ = ShouldBeUsedOnceHint::update(bitfield_, true); } FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); } int ast_node_count() { return ast_properties_.node_count(); } AstProperties::Flags flags() const { return ast_properties_.flags(); } void set_ast_properties(AstProperties* ast_properties) { ast_properties_ = *ast_properties; } const FeedbackVectorSpec* feedback_vector_spec() const { return ast_properties_.get_spec(); } bool dont_optimize() { return dont_optimize_reason_ != kNoReason; } BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } void set_dont_optimize_reason(BailoutReason reason) { dont_optimize_reason_ = reason; } protected: FunctionLiteral(Zone* zone, const AstString* name, AstValueFactory* ast_value_factory, Scope* scope, ZoneList* body, int materialized_literal_count, int expected_property_count, int parameter_count, FunctionType function_type, ParameterFlag has_duplicate_parameters, EagerCompileHint eager_compile_hint, FunctionKind kind, int position) : Expression(zone, position), raw_name_(name), scope_(scope), body_(body), raw_inferred_name_(ast_value_factory->empty_string()), ast_properties_(zone), dont_optimize_reason_(kNoReason), materialized_literal_count_(materialized_literal_count), expected_property_count_(expected_property_count), parameter_count_(parameter_count), function_token_position_(RelocInfo::kNoPosition) { bitfield_ = IsExpression::encode(function_type != kDeclaration) | IsAnonymous::encode(function_type == kAnonymousExpression) | Pretenure::encode(false) | HasDuplicateParameters::encode(has_duplicate_parameters == kHasDuplicateParameters) | IsFunction::encode(function_type != kGlobalOrEval) | ShouldEagerCompile::encode(eager_compile_hint == kShouldEagerCompile) | FunctionKindBits::encode(kind) | ShouldBeUsedOnceHint::encode(false); DCHECK(IsValidFunctionKind(kind)); } private: class IsExpression : public BitField16 {}; class IsAnonymous : public BitField16 {}; class Pretenure : public BitField16 {}; class HasDuplicateParameters : public BitField16 {}; class IsFunction : public BitField16 {}; class ShouldEagerCompile : public BitField16 {}; class FunctionKindBits : public BitField16 {}; class ShouldBeUsedOnceHint : public BitField16 {}; // Start with 16-bit field, which should get packed together // with Expression's trailing 16-bit field. uint16_t bitfield_; const AstString* raw_name_; Scope* scope_; ZoneList* body_; const AstString* raw_inferred_name_; Handle inferred_name_; AstProperties ast_properties_; BailoutReason dont_optimize_reason_; int materialized_literal_count_; int expected_property_count_; int parameter_count_; int function_token_position_; }; class ClassLiteral final : public Expression { public: typedef ObjectLiteralProperty Property; DECLARE_NODE_TYPE(ClassLiteral) Handle name() const { return raw_name_->string(); } const AstRawString* raw_name() const { return raw_name_; } void set_raw_name(const AstRawString* name) { DCHECK_NULL(raw_name_); raw_name_ = name; } Scope* scope() const { return scope_; } VariableProxy* class_variable_proxy() const { return class_variable_proxy_; } Expression* extends() const { return extends_; } void set_extends(Expression* e) { extends_ = e; } FunctionLiteral* constructor() const { return constructor_; } void set_constructor(FunctionLiteral* f) { constructor_ = f; } ZoneList* properties() const { return properties_; } int start_position() const { return position(); } int end_position() const { return end_position_; } BailoutId EntryId() const { return BailoutId(local_id(0)); } BailoutId DeclsId() const { return BailoutId(local_id(1)); } BailoutId ExitId() { return BailoutId(local_id(2)); } BailoutId CreateLiteralId() const { return BailoutId(local_id(3)); } // Return an AST id for a property that is used in simulate instructions. BailoutId GetIdForProperty(int i) { return BailoutId(local_id(i + 4)); } // Unlike other AST nodes, this number of bailout IDs allocated for an // ClassLiteral can vary, so num_ids() is not a static method. int num_ids() const { return parent_num_ids() + 4 + properties()->length(); } // Object literals need one feedback slot for each non-trivial value, as well // as some slots for home objects. void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) override; bool NeedsProxySlot() const { return class_variable_proxy() != nullptr && class_variable_proxy()->var()->IsUnallocated(); } FeedbackVectorSlot ProxySlot() const { return slot_; } protected: ClassLiteral(Zone* zone, const AstRawString* name, Scope* scope, VariableProxy* class_variable_proxy, Expression* extends, FunctionLiteral* constructor, ZoneList* properties, int start_position, int end_position) : Expression(zone, start_position), raw_name_(name), scope_(scope), class_variable_proxy_(class_variable_proxy), extends_(extends), constructor_(constructor), properties_(properties), end_position_(end_position) {} static int parent_num_ids() { return Expression::num_ids(); } private: int local_id(int n) const { return base_id() + parent_num_ids() + n; } const AstRawString* raw_name_; Scope* scope_; VariableProxy* class_variable_proxy_; Expression* extends_; FunctionLiteral* constructor_; ZoneList* properties_; int end_position_; FeedbackVectorSlot slot_; }; class NativeFunctionLiteral final : public Expression { public: DECLARE_NODE_TYPE(NativeFunctionLiteral) Handle name() const { return name_->string(); } v8::Extension* extension() const { return extension_; } protected: NativeFunctionLiteral(Zone* zone, const AstRawString* name, v8::Extension* extension, int pos) : Expression(zone, pos), name_(name), extension_(extension) {} private: const AstRawString* name_; v8::Extension* extension_; }; class ThisFunction final : public Expression { public: DECLARE_NODE_TYPE(ThisFunction) protected: ThisFunction(Zone* zone, int pos) : Expression(zone, pos) {} }; class SuperPropertyReference final : public Expression { public: DECLARE_NODE_TYPE(SuperPropertyReference) VariableProxy* this_var() const { return this_var_; } void set_this_var(VariableProxy* v) { this_var_ = v; } Expression* home_object() const { return home_object_; } void set_home_object(Expression* e) { home_object_ = e; } protected: SuperPropertyReference(Zone* zone, VariableProxy* this_var, Expression* home_object, int pos) : Expression(zone, pos), this_var_(this_var), home_object_(home_object) { DCHECK(this_var->is_this()); DCHECK(home_object->IsProperty()); } private: VariableProxy* this_var_; Expression* home_object_; }; class SuperCallReference final : public Expression { public: DECLARE_NODE_TYPE(SuperCallReference) VariableProxy* this_var() const { return this_var_; } void set_this_var(VariableProxy* v) { this_var_ = v; } VariableProxy* new_target_var() const { return new_target_var_; } void set_new_target_var(VariableProxy* v) { new_target_var_ = v; } VariableProxy* this_function_var() const { return this_function_var_; } void set_this_function_var(VariableProxy* v) { this_function_var_ = v; } protected: SuperCallReference(Zone* zone, VariableProxy* this_var, VariableProxy* new_target_var, VariableProxy* this_function_var, int pos) : Expression(zone, pos), this_var_(this_var), new_target_var_(new_target_var), this_function_var_(this_function_var) { DCHECK(this_var->is_this()); DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target")); DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function")); } private: VariableProxy* this_var_; VariableProxy* new_target_var_; VariableProxy* this_function_var_; }; // This class is produced when parsing the () in arrow functions without any // arguments and is not actually a valid expression. class EmptyParentheses final : public Expression { public: DECLARE_NODE_TYPE(EmptyParentheses) private: EmptyParentheses(Zone* zone, int pos) : Expression(zone, pos) {} }; #undef DECLARE_NODE_TYPE // ---------------------------------------------------------------------------- // Basic visitor // - leaf node visitors are abstract. class AstVisitor BASE_EMBEDDED { public: AstVisitor() {} virtual ~AstVisitor() {} // Stack overflow check and dynamic dispatch. virtual void Visit(AstNode* node) = 0; // Iteration left-to-right. virtual void VisitDeclarations(ZoneList* declarations); virtual void VisitStatements(ZoneList* statements); virtual void VisitExpressions(ZoneList* expressions); // Individual AST nodes. #define DEF_VISIT(type) \ virtual void Visit##type(type* node) = 0; AST_NODE_LIST(DEF_VISIT) #undef DEF_VISIT }; #define DEFINE_AST_VISITOR_SUBCLASS_MEMBERS() \ public: \ void Visit(AstNode* node) final { \ if (!CheckStackOverflow()) node->Accept(this); \ } \ \ void SetStackOverflow() { stack_overflow_ = true; } \ void ClearStackOverflow() { stack_overflow_ = false; } \ bool HasStackOverflow() const { return stack_overflow_; } \ \ bool CheckStackOverflow() { \ if (stack_overflow_) return true; \ if (GetCurrentStackPosition() < stack_limit_) { \ stack_overflow_ = true; \ return true; \ } \ return false; \ } \ \ private: \ void InitializeAstVisitor(Isolate* isolate) { \ stack_limit_ = isolate->stack_guard()->real_climit(); \ stack_overflow_ = false; \ } \ \ void InitializeAstVisitor(uintptr_t stack_limit) { \ stack_limit_ = stack_limit; \ stack_overflow_ = false; \ } \ \ uintptr_t stack_limit_; \ bool stack_overflow_ #define DEFINE_AST_REWRITER_SUBCLASS_MEMBERS() \ public: \ AstNode* Rewrite(AstNode* node) { \ DCHECK_NULL(replacement_); \ DCHECK_NOT_NULL(node); \ Visit(node); \ if (HasStackOverflow()) return node; \ if (replacement_ == nullptr) return node; \ AstNode* result = replacement_; \ replacement_ = nullptr; \ return result; \ } \ \ private: \ void InitializeAstRewriter(Isolate* isolate) { \ InitializeAstVisitor(isolate); \ replacement_ = nullptr; \ } \ \ void InitializeAstRewriter(uintptr_t stack_limit) { \ InitializeAstVisitor(stack_limit); \ replacement_ = nullptr; \ } \ \ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); \ \ protected: \ AstNode* replacement_ // Generic macro for rewriting things; `GET` is the expression to be // rewritten; `SET` is a command that should do the rewriting, i.e. // something sensible with the variable called `replacement`. #define AST_REWRITE(Type, GET, SET) \ do { \ DCHECK(!HasStackOverflow()); \ DCHECK_NULL(replacement_); \ Visit(GET); \ if (HasStackOverflow()) return; \ if (replacement_ == nullptr) break; \ Type* replacement = reinterpret_cast(replacement_); \ do { \ SET; \ } while (false); \ replacement_ = nullptr; \ } while (false) // Macro for rewriting object properties; it assumes that `object` has // `property` with a public getter and setter. #define AST_REWRITE_PROPERTY(Type, object, property) \ do { \ auto _obj = (object); \ AST_REWRITE(Type, _obj->property(), _obj->set_##property(replacement)); \ } while (false) // Macro for rewriting list elements; it assumes that `list` has methods // `at` and `Set`. #define AST_REWRITE_LIST_ELEMENT(Type, list, index) \ do { \ auto _list = (list); \ auto _index = (index); \ AST_REWRITE(Type, _list->at(_index), _list->Set(_index, replacement)); \ } while (false) // ---------------------------------------------------------------------------- // AstNode factory class AstNodeFactory final BASE_EMBEDDED { public: explicit AstNodeFactory(AstValueFactory* ast_value_factory) : local_zone_(ast_value_factory->zone()), parser_zone_(ast_value_factory->zone()), ast_value_factory_(ast_value_factory) {} AstValueFactory* ast_value_factory() const { return ast_value_factory_; } VariableDeclaration* NewVariableDeclaration( VariableProxy* proxy, VariableMode mode, Scope* scope, int pos, bool is_class_declaration = false, int declaration_group_start = -1) { return new (parser_zone_) VariableDeclaration(parser_zone_, proxy, mode, scope, pos, is_class_declaration, declaration_group_start); } FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy, VariableMode mode, FunctionLiteral* fun, Scope* scope, int pos) { return new (parser_zone_) FunctionDeclaration(parser_zone_, proxy, mode, fun, scope, pos); } ImportDeclaration* NewImportDeclaration(VariableProxy* proxy, const AstRawString* import_name, const AstRawString* module_specifier, Scope* scope, int pos) { return new (parser_zone_) ImportDeclaration( parser_zone_, proxy, import_name, module_specifier, scope, pos); } ExportDeclaration* NewExportDeclaration(VariableProxy* proxy, Scope* scope, int pos) { return new (parser_zone_) ExportDeclaration(parser_zone_, proxy, scope, pos); } Block* NewBlock(ZoneList* labels, int capacity, bool ignore_completion_value, int pos) { return new (local_zone_) Block(local_zone_, labels, capacity, ignore_completion_value, pos); } #define STATEMENT_WITH_LABELS(NodeType) \ NodeType* New##NodeType(ZoneList* labels, int pos) { \ return new (local_zone_) NodeType(local_zone_, labels, pos); \ } STATEMENT_WITH_LABELS(DoWhileStatement) STATEMENT_WITH_LABELS(WhileStatement) STATEMENT_WITH_LABELS(ForStatement) STATEMENT_WITH_LABELS(SwitchStatement) #undef STATEMENT_WITH_LABELS ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode, ZoneList* labels, int pos) { switch (visit_mode) { case ForEachStatement::ENUMERATE: { return new (local_zone_) ForInStatement(local_zone_, labels, pos); } case ForEachStatement::ITERATE: { return new (local_zone_) ForOfStatement(local_zone_, labels, pos); } } UNREACHABLE(); return NULL; } ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) { return new (local_zone_) ExpressionStatement(local_zone_, expression, pos); } ContinueStatement* NewContinueStatement(IterationStatement* target, int pos) { return new (local_zone_) ContinueStatement(local_zone_, target, pos); } BreakStatement* NewBreakStatement(BreakableStatement* target, int pos) { return new (local_zone_) BreakStatement(local_zone_, target, pos); } ReturnStatement* NewReturnStatement(Expression* expression, int pos) { return new (local_zone_) ReturnStatement(local_zone_, expression, pos); } WithStatement* NewWithStatement(Scope* scope, Expression* expression, Statement* statement, int pos) { return new (local_zone_) WithStatement(local_zone_, scope, expression, statement, pos); } IfStatement* NewIfStatement(Expression* condition, Statement* then_statement, Statement* else_statement, int pos) { return new (local_zone_) IfStatement(local_zone_, condition, then_statement, else_statement, pos); } TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope, Variable* variable, Block* catch_block, int pos) { return new (local_zone_) TryCatchStatement(local_zone_, try_block, scope, variable, catch_block, pos); } TryFinallyStatement* NewTryFinallyStatement(Block* try_block, Block* finally_block, int pos) { return new (local_zone_) TryFinallyStatement(local_zone_, try_block, finally_block, pos); } DebuggerStatement* NewDebuggerStatement(int pos) { return new (local_zone_) DebuggerStatement(local_zone_, pos); } EmptyStatement* NewEmptyStatement(int pos) { return new (local_zone_) EmptyStatement(local_zone_, pos); } SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement( Statement* statement, Scope* scope) { return new (parser_zone_) SloppyBlockFunctionStatement(parser_zone_, statement, scope); } CaseClause* NewCaseClause( Expression* label, ZoneList* statements, int pos) { return new (local_zone_) CaseClause(local_zone_, label, statements, pos); } Literal* NewStringLiteral(const AstRawString* string, int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewString(string), pos); } // A JavaScript symbol (ECMA-262 edition 6). Literal* NewSymbolLiteral(const char* name, int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewSymbol(name), pos); } Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) { return new (local_zone_) Literal( local_zone_, ast_value_factory_->NewNumber(number, with_dot), pos); } Literal* NewSmiLiteral(int number, int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewSmi(number), pos); } Literal* NewBooleanLiteral(bool b, int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewBoolean(b), pos); } Literal* NewNullLiteral(int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewNull(), pos); } Literal* NewUndefinedLiteral(int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewUndefined(), pos); } Literal* NewTheHoleLiteral(int pos) { return new (local_zone_) Literal(local_zone_, ast_value_factory_->NewTheHole(), pos); } ObjectLiteral* NewObjectLiteral( ZoneList* properties, int literal_index, int boilerplate_properties, bool has_function, bool is_strong, int pos) { return new (local_zone_) ObjectLiteral(local_zone_, properties, literal_index, boilerplate_properties, has_function, is_strong, pos); } ObjectLiteral::Property* NewObjectLiteralProperty( Expression* key, Expression* value, ObjectLiteralProperty::Kind kind, bool is_static, bool is_computed_name) { return new (local_zone_) ObjectLiteral::Property(key, value, kind, is_static, is_computed_name); } ObjectLiteral::Property* NewObjectLiteralProperty(Expression* key, Expression* value, bool is_static, bool is_computed_name) { return new (local_zone_) ObjectLiteral::Property( ast_value_factory_, key, value, is_static, is_computed_name); } RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags, int literal_index, bool is_strong, int pos) { return new (local_zone_) RegExpLiteral(local_zone_, pattern, flags, literal_index, is_strong, pos); } ArrayLiteral* NewArrayLiteral(ZoneList* values, int literal_index, bool is_strong, int pos) { return new (local_zone_) ArrayLiteral(local_zone_, values, -1, literal_index, is_strong, pos); } ArrayLiteral* NewArrayLiteral(ZoneList* values, int first_spread_index, int literal_index, bool is_strong, int pos) { return new (local_zone_) ArrayLiteral( local_zone_, values, first_spread_index, literal_index, is_strong, pos); } VariableProxy* NewVariableProxy(Variable* var, int start_position = RelocInfo::kNoPosition, int end_position = RelocInfo::kNoPosition) { return new (parser_zone_) VariableProxy(parser_zone_, var, start_position, end_position); } VariableProxy* NewVariableProxy(const AstRawString* name, Variable::Kind variable_kind, int start_position = RelocInfo::kNoPosition, int end_position = RelocInfo::kNoPosition) { DCHECK_NOT_NULL(name); return new (parser_zone_) VariableProxy(parser_zone_, name, variable_kind, start_position, end_position); } Property* NewProperty(Expression* obj, Expression* key, int pos) { return new (local_zone_) Property(local_zone_, obj, key, pos); } Call* NewCall(Expression* expression, ZoneList* arguments, int pos) { return new (local_zone_) Call(local_zone_, expression, arguments, pos); } CallNew* NewCallNew(Expression* expression, ZoneList* arguments, int pos) { return new (local_zone_) CallNew(local_zone_, expression, arguments, pos); } CallRuntime* NewCallRuntime(Runtime::FunctionId id, ZoneList* arguments, int pos) { return new (local_zone_) CallRuntime(local_zone_, Runtime::FunctionForId(id), arguments, pos); } CallRuntime* NewCallRuntime(const Runtime::Function* function, ZoneList* arguments, int pos) { return new (local_zone_) CallRuntime(local_zone_, function, arguments, pos); } CallRuntime* NewCallRuntime(int context_index, ZoneList* arguments, int pos) { return new (local_zone_) CallRuntime(local_zone_, context_index, arguments, pos); } UnaryOperation* NewUnaryOperation(Token::Value op, Expression* expression, int pos) { return new (local_zone_) UnaryOperation(local_zone_, op, expression, pos); } BinaryOperation* NewBinaryOperation(Token::Value op, Expression* left, Expression* right, int pos) { return new (local_zone_) BinaryOperation(local_zone_, op, left, right, pos); } CountOperation* NewCountOperation(Token::Value op, bool is_prefix, Expression* expr, int pos) { return new (local_zone_) CountOperation(local_zone_, op, is_prefix, expr, pos); } CompareOperation* NewCompareOperation(Token::Value op, Expression* left, Expression* right, int pos) { return new (local_zone_) CompareOperation(local_zone_, op, left, right, pos); } Spread* NewSpread(Expression* expression, int pos) { return new (local_zone_) Spread(local_zone_, expression, pos); } Conditional* NewConditional(Expression* condition, Expression* then_expression, Expression* else_expression, int position) { return new (local_zone_) Conditional( local_zone_, condition, then_expression, else_expression, position); } RewritableAssignmentExpression* NewRewritableAssignmentExpression( Expression* expression) { DCHECK_NOT_NULL(expression); DCHECK(expression->IsAssignment()); return new (local_zone_) RewritableAssignmentExpression(local_zone_, expression); } Assignment* NewAssignment(Token::Value op, Expression* target, Expression* value, int pos) { DCHECK(Token::IsAssignmentOp(op)); Assignment* assign = new (local_zone_) Assignment(local_zone_, op, target, value, pos); if (assign->is_compound()) { DCHECK(Token::IsAssignmentOp(op)); assign->binary_operation_ = NewBinaryOperation(assign->binary_op(), target, value, pos + 1); } return assign; } Yield* NewYield(Expression *generator_object, Expression* expression, Yield::Kind yield_kind, int pos) { if (!expression) expression = NewUndefinedLiteral(pos); return new (local_zone_) Yield(local_zone_, generator_object, expression, yield_kind, pos); } Throw* NewThrow(Expression* exception, int pos) { return new (local_zone_) Throw(local_zone_, exception, pos); } FunctionLiteral* NewFunctionLiteral( const AstRawString* name, Scope* scope, ZoneList* body, int materialized_literal_count, int expected_property_count, int parameter_count, FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::FunctionType function_type, FunctionLiteral::EagerCompileHint eager_compile_hint, FunctionKind kind, int position) { return new (parser_zone_) FunctionLiteral( parser_zone_, name, ast_value_factory_, scope, body, materialized_literal_count, expected_property_count, parameter_count, function_type, has_duplicate_parameters, eager_compile_hint, kind, position); } ClassLiteral* NewClassLiteral(const AstRawString* name, Scope* scope, VariableProxy* proxy, Expression* extends, FunctionLiteral* constructor, ZoneList* properties, int start_position, int end_position) { return new (parser_zone_) ClassLiteral(parser_zone_, name, scope, proxy, extends, constructor, properties, start_position, end_position); } NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name, v8::Extension* extension, int pos) { return new (parser_zone_) NativeFunctionLiteral(parser_zone_, name, extension, pos); } DoExpression* NewDoExpression(Block* block, Variable* result_var, int pos) { VariableProxy* result = NewVariableProxy(result_var, pos); return new (parser_zone_) DoExpression(parser_zone_, block, result, pos); } ThisFunction* NewThisFunction(int pos) { return new (local_zone_) ThisFunction(local_zone_, pos); } SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var, Expression* home_object, int pos) { return new (parser_zone_) SuperPropertyReference(parser_zone_, this_var, home_object, pos); } SuperCallReference* NewSuperCallReference(VariableProxy* this_var, VariableProxy* new_target_var, VariableProxy* this_function_var, int pos) { return new (parser_zone_) SuperCallReference( parser_zone_, this_var, new_target_var, this_function_var, pos); } EmptyParentheses* NewEmptyParentheses(int pos) { return new (local_zone_) EmptyParentheses(local_zone_, pos); } Zone* zone() const { return local_zone_; } // Handles use of temporary zones when parsing inner function bodies. class BodyScope { public: BodyScope(AstNodeFactory* factory, Zone* temp_zone, bool use_temp_zone) : factory_(factory), prev_zone_(factory->local_zone_) { if (use_temp_zone) { factory->local_zone_ = temp_zone; } } ~BodyScope() { factory_->local_zone_ = prev_zone_; } private: AstNodeFactory* factory_; Zone* prev_zone_; }; private: // This zone may be deallocated upon returning from parsing a function body // which we can guarantee is not going to be compiled or have its AST // inspected. // See ParseFunctionLiteral in parser.cc for preconditions. Zone* local_zone_; // ZoneObjects which need to persist until scope analysis must be allocated in // the parser-level zone. Zone* parser_zone_; AstValueFactory* ast_value_factory_; }; } // namespace internal } // namespace v8 #endif // V8_AST_AST_H_