diff --git a/src/ast.cc b/src/ast.cc index 18eb90c710..397da5ab01 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -126,18 +126,7 @@ Assignment::Assignment(Isolate* isolate, assignment_id_(GetNextId(isolate)), block_start_(false), block_end_(false), - is_monomorphic_(false) { - ASSERT(Token::IsAssignmentOp(op)); - if (is_compound()) { - binary_operation_ = - new(isolate->zone()) BinaryOperation(isolate, - binary_op(), - target, - value, - pos + 1); - compound_load_id_ = GetNextId(isolate); - } -} + is_monomorphic_(false) { } Token::Value Assignment::binary_op() const { @@ -179,6 +168,11 @@ LanguageMode FunctionLiteral::language_mode() const { } +bool FunctionLiteral::ShouldSelfOptimize() { + return !flags()->Contains(kDontSelfOptimize); +} + + ObjectLiteral::Property::Property(Literal* key, Expression* value) { emit_store_ = true; key_ = key; @@ -197,9 +191,7 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) { ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { - Isolate* isolate = Isolate::Current(); emit_store_ = true; - key_ = new(isolate->zone()) Literal(isolate, value->name()); value_ = value; kind_ = is_getter ? GETTER : SETTER; } @@ -431,223 +423,6 @@ bool Declaration::IsInlineable() const { } -bool TargetCollector::IsInlineable() const { - UNREACHABLE(); - return false; -} - - -bool ForInStatement::IsInlineable() const { - return false; -} - - -bool WithStatement::IsInlineable() const { - return false; -} - - -bool SwitchStatement::IsInlineable() const { - return false; -} - - -bool TryStatement::IsInlineable() const { - return false; -} - - -bool TryCatchStatement::IsInlineable() const { - return false; -} - - -bool TryFinallyStatement::IsInlineable() const { - return false; -} - - -bool DebuggerStatement::IsInlineable() const { - return false; -} - - -bool Throw::IsInlineable() const { - return exception()->IsInlineable(); -} - - -bool MaterializedLiteral::IsInlineable() const { - // TODO(1322): Allow materialized literals. - return false; -} - - -bool FunctionLiteral::IsInlineable() const { - // TODO(1322): Allow materialized literals. - return false; -} - - -bool ThisFunction::IsInlineable() const { - return true; -} - - -bool SharedFunctionInfoLiteral::IsInlineable() const { - return false; -} - - -bool ForStatement::IsInlineable() const { - return (init() == NULL || init()->IsInlineable()) - && (cond() == NULL || cond()->IsInlineable()) - && (next() == NULL || next()->IsInlineable()) - && body()->IsInlineable(); -} - - -bool WhileStatement::IsInlineable() const { - return cond()->IsInlineable() - && body()->IsInlineable(); -} - - -bool DoWhileStatement::IsInlineable() const { - return cond()->IsInlineable() - && body()->IsInlineable(); -} - - -bool ContinueStatement::IsInlineable() const { - return true; -} - - -bool BreakStatement::IsInlineable() const { - return true; -} - - -bool EmptyStatement::IsInlineable() const { - return true; -} - - -bool Literal::IsInlineable() const { - return true; -} - - -bool Block::IsInlineable() const { - const int count = statements_.length(); - for (int i = 0; i < count; ++i) { - if (!statements_[i]->IsInlineable()) return false; - } - return true; -} - - -bool ExpressionStatement::IsInlineable() const { - return expression()->IsInlineable(); -} - - -bool IfStatement::IsInlineable() const { - return condition()->IsInlineable() - && then_statement()->IsInlineable() - && else_statement()->IsInlineable(); -} - - -bool ReturnStatement::IsInlineable() const { - return expression()->IsInlineable(); -} - - -bool Conditional::IsInlineable() const { - return condition()->IsInlineable() && then_expression()->IsInlineable() && - else_expression()->IsInlineable(); -} - - -bool VariableProxy::IsInlineable() const { - return var()->IsUnallocated() - || var()->IsStackAllocated() - || var()->IsContextSlot(); -} - - -bool Assignment::IsInlineable() const { - return target()->IsInlineable() && value()->IsInlineable(); -} - - -bool Property::IsInlineable() const { - return obj()->IsInlineable() && key()->IsInlineable(); -} - - -bool Call::IsInlineable() const { - if (!expression()->IsInlineable()) return false; - const int count = arguments()->length(); - for (int i = 0; i < count; ++i) { - if (!arguments()->at(i)->IsInlineable()) return false; - } - return true; -} - - -bool CallNew::IsInlineable() const { - if (!expression()->IsInlineable()) return false; - const int count = arguments()->length(); - for (int i = 0; i < count; ++i) { - if (!arguments()->at(i)->IsInlineable()) return false; - } - return true; -} - - -bool CallRuntime::IsInlineable() const { - // Don't try to inline JS runtime calls because we don't (currently) even - // optimize them. - if (is_jsruntime()) return false; - // Don't inline the %_ArgumentsLength or %_Arguments because their - // implementation will not work. There is no stack frame to get them - // from. - if (function()->intrinsic_type == Runtime::INLINE && - (name()->IsEqualTo(CStrVector("_ArgumentsLength")) || - name()->IsEqualTo(CStrVector("_Arguments")))) { - return false; - } - const int count = arguments()->length(); - for (int i = 0; i < count; ++i) { - if (!arguments()->at(i)->IsInlineable()) return false; - } - return true; -} - - -bool UnaryOperation::IsInlineable() const { - return expression()->IsInlineable(); -} - - -bool BinaryOperation::IsInlineable() const { - return left()->IsInlineable() && right()->IsInlineable(); -} - - -bool CompareOperation::IsInlineable() const { - return left()->IsInlineable() && right()->IsInlineable(); -} - - -bool CountOperation::IsInlineable() const { - return expression()->IsInlineable(); -} - - // ---------------------------------------------------------------------------- // Recording of type feedback @@ -1214,4 +989,164 @@ CaseClause::CaseClause(Isolate* isolate, entry_id_(AstNode::GetNextId(isolate)) { } + +#define INCREASE_NODE_COUNT(NodeType) \ + void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ + increase_node_count(); \ + } + +INCREASE_NODE_COUNT(Declaration) +INCREASE_NODE_COUNT(Block) +INCREASE_NODE_COUNT(ExpressionStatement) +INCREASE_NODE_COUNT(EmptyStatement) +INCREASE_NODE_COUNT(IfStatement) +INCREASE_NODE_COUNT(ContinueStatement) +INCREASE_NODE_COUNT(BreakStatement) +INCREASE_NODE_COUNT(ReturnStatement) +INCREASE_NODE_COUNT(Conditional) +INCREASE_NODE_COUNT(Literal) +INCREASE_NODE_COUNT(Assignment) +INCREASE_NODE_COUNT(Throw) +INCREASE_NODE_COUNT(Property) +INCREASE_NODE_COUNT(UnaryOperation) +INCREASE_NODE_COUNT(CountOperation) +INCREASE_NODE_COUNT(BinaryOperation) +INCREASE_NODE_COUNT(CompareOperation) +INCREASE_NODE_COUNT(ThisFunction) + +#undef INCREASE_NODE_COUNT + + +void AstConstructionVisitor::VisitWithStatement(WithStatement* node) { + increase_node_count(); + add_flag(kDontOptimize); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitSwitchStatement(SwitchStatement* node) { + increase_node_count(); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitDoWhileStatement(DoWhileStatement* node) { + increase_node_count(); + add_flag(kDontSelfOptimize); +} + + +void AstConstructionVisitor::VisitWhileStatement(WhileStatement* node) { + increase_node_count(); + add_flag(kDontSelfOptimize); +} + + +void AstConstructionVisitor::VisitForStatement(ForStatement* node) { + increase_node_count(); + add_flag(kDontSelfOptimize); +} + + +void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) { + increase_node_count(); + add_flag(kDontOptimize); + add_flag(kDontInline); + add_flag(kDontSelfOptimize); +} + + +void AstConstructionVisitor::VisitTryCatchStatement(TryCatchStatement* node) { + increase_node_count(); + add_flag(kDontOptimize); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitTryFinallyStatement( + TryFinallyStatement* node) { + increase_node_count(); + add_flag(kDontOptimize); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitDebuggerStatement(DebuggerStatement* node) { + increase_node_count(); + add_flag(kDontOptimize); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitFunctionLiteral(FunctionLiteral* node) { + increase_node_count(); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitSharedFunctionInfoLiteral( + SharedFunctionInfoLiteral* node) { + increase_node_count(); + add_flag(kDontOptimize); + add_flag(kDontInline); +} + + +void AstConstructionVisitor::VisitVariableProxy(VariableProxy* node) { + increase_node_count(); + // In theory, we'd have to add: + // if(node->var()->IsLookupSlot()) { add_flag(kDontInline); } + // However, node->var() is usually not bound yet at VariableProxy creation + // time, and LOOKUP variables only result from constructs that cannot + // be inlined anyway. +} + + +void AstConstructionVisitor::VisitRegExpLiteral(RegExpLiteral* node) { + increase_node_count(); + add_flag(kDontInline); // TODO(1322): Allow materialized literals. +} + + +void AstConstructionVisitor::VisitObjectLiteral(ObjectLiteral* node) { + increase_node_count(); + add_flag(kDontInline); // TODO(1322): Allow materialized literals. +} + + +void AstConstructionVisitor::VisitArrayLiteral(ArrayLiteral* node) { + increase_node_count(); + add_flag(kDontInline); // TODO(1322): Allow materialized literals. +} + + +void AstConstructionVisitor::VisitCall(Call* node) { + increase_node_count(); + add_flag(kDontSelfOptimize); +} + + +void AstConstructionVisitor::VisitCallNew(CallNew* node) { + increase_node_count(); + add_flag(kDontSelfOptimize); +} + + +void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { + increase_node_count(); + add_flag(kDontSelfOptimize); + if (node->is_jsruntime()) { + // Don't try to inline JS runtime calls because we don't (currently) even + // optimize them. + add_flag(kDontInline); + } else if (node->function()->intrinsic_type == Runtime::INLINE && + (node->name()->IsEqualTo(CStrVector("_ArgumentsLength")) || + node->name()->IsEqualTo(CStrVector("_Arguments")))) { + // Don't inline the %_ArgumentsLength or %_Arguments because their + // implementation will not work. There is no stack frame to get them + // from. + add_flag(kDontInline); + } +} + } } // namespace v8::internal diff --git a/src/ast.h b/src/ast.h index 34fadab62d..bc2c67e0e2 100644 --- a/src/ast.h +++ b/src/ast.h @@ -39,6 +39,7 @@ #include "small-pointer-list.h" #include "smart-array-pointer.h" #include "token.h" +#include "utils.h" #include "variables.h" #include "zone-inl.h" @@ -103,6 +104,8 @@ namespace internal { EXPRESSION_NODE_LIST(V) // Forward declarations +class AstConstructionVisitor; +template class AstNodeFactory; class AstVisitor; class BreakableStatement; class Expression; @@ -136,6 +139,35 @@ typedef ZoneList > ZoneStringList; typedef ZoneList > ZoneObjectList; +#define DECLARE_NODE_TYPE(type) \ + virtual void Accept(AstVisitor* v); \ + virtual AstNode::Type node_type() const { return AstNode::k##type; } \ + + +enum AstPropertiesFlag { + kDontInline, + kDontOptimize, + kDontSelfOptimize, + kDontSoftInline +}; + + +class AstProperties BASE_EMBEDDED { + public: + class Flags : public EnumSet {}; + + AstProperties() : node_count_(0) { } + + Flags* flags() { return &flags_; } + int node_count() { return node_count_; } + void add_node_count(int count) { node_count_ += count; } + + private: + Flags flags_; + int node_count_; +}; + + class AstNode: public ZoneObject { public: #define DECLARE_TYPE_ENUM(type) k##type, @@ -152,14 +184,11 @@ class AstNode: public ZoneObject { // that emit code (function declarations). static const int kDeclarationsId = 3; - // Override ZoneObject's new to count allocated AST nodes. void* operator new(size_t size, Zone* zone) { - Isolate* isolate = zone->isolate(); - isolate->set_ast_node_count(isolate->ast_node_count() + 1); return zone->New(static_cast(size)); } - AstNode() {} + AstNode() { } virtual ~AstNode() { } @@ -180,19 +209,15 @@ class AstNode: public ZoneObject { virtual IterationStatement* AsIterationStatement() { return NULL; } virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; } - // True if the node is simple enough for us to inline calls containing it. - virtual bool IsInlineable() const = 0; - - static int Count() { return Isolate::Current()->ast_node_count(); } static void ResetIds() { Isolate::Current()->set_ast_node_id(0); } protected: - static unsigned GetNextId(Isolate* isolate) { + static int GetNextId(Isolate* isolate) { return ReserveIdRange(isolate, 1); } - static unsigned ReserveIdRange(Isolate* isolate, int n) { - unsigned tmp = isolate->ast_node_id(); + static int ReserveIdRange(Isolate* isolate, int n) { + int tmp = isolate->ast_node_id(); isolate->set_ast_node_id(tmp + n); return tmp; } @@ -326,8 +351,8 @@ class Expression: public AstNode { unsigned test_id() const { return test_id_; } private: - unsigned id_; - unsigned test_id_; + int id_; + int test_id_; }; @@ -376,6 +401,19 @@ class BreakableStatement: public Statement { class Block: public BreakableStatement { public: + DECLARE_NODE_TYPE(Block) + + void AddStatement(Statement* statement) { statements_.Add(statement); } + + ZoneList* statements() { return &statements_; } + bool is_initializer_block() const { return is_initializer_block_; } + + Scope* block_scope() const { return block_scope_; } + void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; } + + protected: + template friend class AstNodeFactory; + Block(Isolate* isolate, ZoneStringList* labels, int capacity, @@ -386,19 +424,6 @@ class Block: public BreakableStatement { block_scope_(NULL) { } - - DECLARE_NODE_TYPE(Block) - - virtual bool IsInlineable() const; - - void AddStatement(Statement* statement) { statements_.Add(statement); } - - ZoneList* statements() { return &statements_; } - bool is_initializer_block() const { return is_initializer_block_; } - - Scope* block_scope() const { return block_scope_; } - void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; } - private: ZoneList statements_; bool is_initializer_block_; @@ -408,6 +433,17 @@ class Block: public BreakableStatement { class Declaration: public AstNode { public: + DECLARE_NODE_TYPE(Declaration) + + VariableProxy* proxy() const { return proxy_; } + VariableMode mode() const { return mode_; } + FunctionLiteral* fun() const { return fun_; } // may be NULL + bool IsInlineable() const; + Scope* scope() const { return scope_; } + + protected: + template friend class AstNodeFactory; + Declaration(VariableProxy* proxy, VariableMode mode, FunctionLiteral* fun, @@ -424,14 +460,6 @@ class Declaration: public AstNode { ASSERT(fun == NULL || mode == VAR || mode == LET); } - DECLARE_NODE_TYPE(Declaration) - - VariableProxy* proxy() const { return proxy_; } - VariableMode mode() const { return mode_; } - FunctionLiteral* fun() const { return fun_; } // may be NULL - virtual bool IsInlineable() const; - Scope* scope() const { return scope_; } - private: VariableProxy* proxy_; VariableMode mode_; @@ -477,14 +505,6 @@ class IterationStatement: public BreakableStatement { class DoWhileStatement: public IterationStatement { public: - DoWhileStatement(Isolate* isolate, ZoneStringList* labels) - : IterationStatement(isolate, labels), - cond_(NULL), - condition_position_(-1), - continue_id_(GetNextId(isolate)), - back_edge_id_(GetNextId(isolate)) { - } - DECLARE_NODE_TYPE(DoWhileStatement) void Initialize(Expression* cond, Statement* body) { @@ -504,7 +524,16 @@ class DoWhileStatement: public IterationStatement { virtual int StackCheckId() const { return back_edge_id_; } int BackEdgeId() const { return back_edge_id_; } - virtual bool IsInlineable() const; + protected: + template friend class AstNodeFactory; + + DoWhileStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), + cond_(NULL), + condition_position_(-1), + continue_id_(GetNextId(isolate)), + back_edge_id_(GetNextId(isolate)) { + } private: Expression* cond_; @@ -516,13 +545,6 @@ class DoWhileStatement: public IterationStatement { class WhileStatement: public IterationStatement { public: - WhileStatement(Isolate* isolate, ZoneStringList* labels) - : IterationStatement(isolate, labels), - cond_(NULL), - may_have_function_literal_(true), - body_id_(GetNextId(isolate)) { - } - DECLARE_NODE_TYPE(WhileStatement) void Initialize(Expression* cond, Statement* body) { @@ -537,13 +559,22 @@ class WhileStatement: public IterationStatement { void set_may_have_function_literal(bool value) { may_have_function_literal_ = value; } - virtual bool IsInlineable() const; // Bailout support. virtual int ContinueId() const { return EntryId(); } virtual int StackCheckId() const { return body_id_; } int BodyId() const { return body_id_; } + protected: + template friend class AstNodeFactory; + + WhileStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), + cond_(NULL), + may_have_function_literal_(true), + body_id_(GetNextId(isolate)) { + } + private: Expression* cond_; // True if there is a function literal subexpression in the condition. @@ -554,17 +585,6 @@ class WhileStatement: public IterationStatement { class ForStatement: public IterationStatement { public: - ForStatement(Isolate* isolate, ZoneStringList* labels) - : IterationStatement(isolate, labels), - init_(NULL), - cond_(NULL), - next_(NULL), - may_have_function_literal_(true), - loop_variable_(NULL), - continue_id_(GetNextId(isolate)), - body_id_(GetNextId(isolate)) { - } - DECLARE_NODE_TYPE(ForStatement) void Initialize(Statement* init, @@ -596,7 +616,20 @@ class ForStatement: public IterationStatement { bool is_fast_smi_loop() { return loop_variable_ != NULL; } Variable* loop_variable() { return loop_variable_; } void set_loop_variable(Variable* var) { loop_variable_ = var; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + ForStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), + init_(NULL), + cond_(NULL), + next_(NULL), + may_have_function_literal_(true), + loop_variable_(NULL), + continue_id_(GetNextId(isolate)), + body_id_(GetNextId(isolate)) { + } private: Statement* init_; @@ -612,13 +645,6 @@ class ForStatement: public IterationStatement { class ForInStatement: public IterationStatement { public: - ForInStatement(Isolate* isolate, ZoneStringList* labels) - : IterationStatement(isolate, labels), - each_(NULL), - enumerable_(NULL), - assignment_id_(GetNextId(isolate)) { - } - DECLARE_NODE_TYPE(ForInStatement) void Initialize(Expression* each, Expression* enumerable, Statement* body) { @@ -629,13 +655,22 @@ class ForInStatement: public IterationStatement { Expression* each() const { return each_; } Expression* enumerable() const { return enumerable_; } - virtual bool IsInlineable() const; // Bailout support. int AssignmentId() const { return assignment_id_; } virtual int ContinueId() const { return EntryId(); } virtual int StackCheckId() const { return EntryId(); } + protected: + template friend class AstNodeFactory; + + ForInStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), + each_(NULL), + enumerable_(NULL), + assignment_id_(GetNextId(isolate)) { + } + private: Expression* each_; Expression* enumerable_; @@ -645,16 +680,17 @@ class ForInStatement: public IterationStatement { class ExpressionStatement: public Statement { public: - explicit ExpressionStatement(Expression* expression) - : expression_(expression) { } - DECLARE_NODE_TYPE(ExpressionStatement) - virtual bool IsInlineable() const; - void set_expression(Expression* e) { expression_ = e; } Expression* expression() const { return expression_; } + protected: + template friend class AstNodeFactory; + + explicit ExpressionStatement(Expression* expression) + : expression_(expression) { } + private: Expression* expression_; }; @@ -662,13 +698,15 @@ class ExpressionStatement: public Statement { class ContinueStatement: public Statement { public: - explicit ContinueStatement(IterationStatement* target) - : target_(target) { } - DECLARE_NODE_TYPE(ContinueStatement) IterationStatement* target() const { return target_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + explicit ContinueStatement(IterationStatement* target) + : target_(target) { } private: IterationStatement* target_; @@ -677,13 +715,15 @@ class ContinueStatement: public Statement { class BreakStatement: public Statement { public: - explicit BreakStatement(BreakableStatement* target) - : target_(target) { } - DECLARE_NODE_TYPE(BreakStatement) BreakableStatement* target() const { return target_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + explicit BreakStatement(BreakableStatement* target) + : target_(target) { } private: BreakableStatement* target_; @@ -692,13 +732,15 @@ class BreakStatement: public Statement { class ReturnStatement: public Statement { public: - explicit ReturnStatement(Expression* expression) - : expression_(expression) { } - DECLARE_NODE_TYPE(ReturnStatement) Expression* expression() const { return expression_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + explicit ReturnStatement(Expression* expression) + : expression_(expression) { } private: Expression* expression_; @@ -707,15 +749,17 @@ class ReturnStatement: public Statement { class WithStatement: public Statement { public: - WithStatement(Expression* expression, Statement* statement) - : expression_(expression), statement_(statement) { } - DECLARE_NODE_TYPE(WithStatement) Expression* expression() const { return expression_; } Statement* statement() const { return statement_; } - virtual bool IsInlineable() const; + protected: + template friend class AstNodeFactory; + + WithStatement(Expression* expression, Statement* statement) + : expression_(expression), + statement_(statement) { } private: Expression* expression_; @@ -771,13 +815,6 @@ class CaseClause: public ZoneObject { class SwitchStatement: public BreakableStatement { public: - SwitchStatement(Isolate* isolate, ZoneStringList* labels) - : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS), - tag_(NULL), - cases_(NULL) { - } - - DECLARE_NODE_TYPE(SwitchStatement) void Initialize(Expression* tag, ZoneList* cases) { @@ -787,7 +824,14 @@ class SwitchStatement: public BreakableStatement { Expression* tag() const { return tag_; } ZoneList* cases() const { return cases_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + SwitchStatement(Isolate* isolate, ZoneStringList* labels) + : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS), + tag_(NULL), + cases_(NULL) { } private: Expression* tag_; @@ -802,22 +846,8 @@ class SwitchStatement: public BreakableStatement { // given if-statement has a then- or an else-part containing code. class IfStatement: public Statement { public: - IfStatement(Isolate* isolate, - Expression* condition, - Statement* then_statement, - Statement* else_statement) - : condition_(condition), - then_statement_(then_statement), - else_statement_(else_statement), - if_id_(GetNextId(isolate)), - then_id_(GetNextId(isolate)), - else_id_(GetNextId(isolate)) { - } - DECLARE_NODE_TYPE(IfStatement) - virtual bool IsInlineable() const; - bool HasThenStatement() const { return !then_statement()->IsEmpty(); } bool HasElseStatement() const { return !else_statement()->IsEmpty(); } @@ -829,6 +859,21 @@ class IfStatement: public Statement { int ThenId() const { return then_id_; } int ElseId() const { return else_id_; } + protected: + template friend class AstNodeFactory; + + IfStatement(Isolate* isolate, + Expression* condition, + Statement* then_statement, + Statement* else_statement) + : condition_(condition), + then_statement_(then_statement), + else_statement_(else_statement), + if_id_(GetNextId(isolate)), + then_id_(GetNextId(isolate)), + else_id_(GetNextId(isolate)) { + } + private: Expression* condition_; Statement* then_statement_; @@ -843,7 +888,7 @@ class IfStatement: public Statement { // stack in the compiler; this should probably be reworked. class TargetCollector: public AstNode { public: - TargetCollector(): targets_(0) { } + TargetCollector() : targets_(0) { } // Adds a jump target to the collector. The collector stores a pointer not // a copy of the target to make binding work, so make sure not to pass in @@ -855,7 +900,6 @@ class TargetCollector: public AstNode { virtual TargetCollector* AsTargetCollector() { return this; } ZoneList* targets() { return &targets_; } - virtual bool IsInlineable() const; private: ZoneList targets_; @@ -864,12 +908,6 @@ class TargetCollector: public AstNode { class TryStatement: public Statement { public: - explicit TryStatement(int index, Block* try_block) - : index_(index), - try_block_(try_block), - escaping_targets_(NULL) { - } - void set_escaping_targets(ZoneList* targets) { escaping_targets_ = targets; } @@ -877,7 +915,12 @@ class TryStatement: public Statement { int index() const { return index_; } Block* try_block() const { return try_block_; } ZoneList* escaping_targets() const { return escaping_targets_; } - virtual bool IsInlineable() const; + + protected: + TryStatement(int index, Block* try_block) + : index_(index), + try_block_(try_block), + escaping_targets_(NULL) { } private: // Unique (per-function) index of this handler. This is not an AST ID. @@ -890,6 +933,15 @@ class TryStatement: public Statement { class TryCatchStatement: public TryStatement { public: + DECLARE_NODE_TYPE(TryCatchStatement) + + Scope* scope() { return scope_; } + Variable* variable() { return variable_; } + Block* catch_block() const { return catch_block_; } + + protected: + template friend class AstNodeFactory; + TryCatchStatement(int index, Block* try_block, Scope* scope, @@ -901,13 +953,6 @@ class TryCatchStatement: public TryStatement { catch_block_(catch_block) { } - DECLARE_NODE_TYPE(TryCatchStatement) - - Scope* scope() { return scope_; } - Variable* variable() { return variable_; } - Block* catch_block() const { return catch_block_; } - virtual bool IsInlineable() const; - private: Scope* scope_; Variable* variable_; @@ -917,14 +962,16 @@ class TryCatchStatement: public TryStatement { class TryFinallyStatement: public TryStatement { public: - TryFinallyStatement(int index, Block* try_block, Block* finally_block) - : TryStatement(index, try_block), - finally_block_(finally_block) { } - DECLARE_NODE_TYPE(TryFinallyStatement) Block* finally_block() const { return finally_block_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + TryFinallyStatement(int index, Block* try_block, Block* finally_block) + : TryStatement(index, try_block), + finally_block_(finally_block) { } private: Block* finally_block_; @@ -934,7 +981,11 @@ class TryFinallyStatement: public TryStatement { class DebuggerStatement: public Statement { public: DECLARE_NODE_TYPE(DebuggerStatement) - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + DebuggerStatement() {} }; @@ -942,15 +993,15 @@ class EmptyStatement: public Statement { public: DECLARE_NODE_TYPE(EmptyStatement) - virtual bool IsInlineable() const; + protected: + template friend class AstNodeFactory; + + EmptyStatement() {} }; class Literal: public Expression { public: - Literal(Isolate* isolate, Handle handle) - : Expression(isolate), handle_(handle) { } - DECLARE_NODE_TYPE(Literal) // Check if this literal is identical to the other literal. @@ -989,7 +1040,13 @@ class Literal: public Expression { } Handle handle() const { return handle_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + Literal(Isolate* isolate, Handle handle) + : Expression(isolate), + handle_(handle) { } private: Handle handle_; @@ -999,15 +1056,6 @@ class Literal: public Expression { // Base class for literals that needs space in the corresponding JSFunction. class MaterializedLiteral: public Expression { public: - MaterializedLiteral(Isolate* isolate, - int literal_index, - bool is_simple, - int depth) - : Expression(isolate), - literal_index_(literal_index), - is_simple_(is_simple), - depth_(depth) {} - virtual MaterializedLiteral* AsMaterializedLiteral() { return this; } int literal_index() { return literal_index_; } @@ -1017,7 +1065,16 @@ class MaterializedLiteral: public Expression { bool is_simple() const { return is_simple_; } int depth() const { return depth_; } - virtual bool IsInlineable() const; + + protected: + MaterializedLiteral(Isolate* isolate, + int literal_index, + bool is_simple, + int depth) + : Expression(isolate), + literal_index_(literal_index), + is_simple_(is_simple), + depth_(depth) {} private: int literal_index_; @@ -1044,7 +1101,6 @@ class ObjectLiteral: public MaterializedLiteral { }; Property(Literal* key, Expression* value); - Property(bool is_getter, FunctionLiteral* value); Literal* key() { return key_; } Expression* value() { return value_; } @@ -1055,6 +1111,12 @@ class ObjectLiteral: public MaterializedLiteral { void set_emit_store(bool emit_store); bool emit_store(); + protected: + template friend class AstNodeFactory; + + Property(bool is_getter, FunctionLiteral* value); + void set_key(Literal* key) { key_ = key; } + private: Literal* key_; Expression* value_; @@ -1062,20 +1124,6 @@ class ObjectLiteral: public MaterializedLiteral { bool emit_store_; }; - ObjectLiteral(Isolate* isolate, - Handle constant_properties, - ZoneList* properties, - int literal_index, - bool is_simple, - bool fast_elements, - int depth, - bool has_function) - : MaterializedLiteral(isolate, literal_index, is_simple, depth), - constant_properties_(constant_properties), - properties_(properties), - fast_elements_(fast_elements), - has_function_(has_function) {} - DECLARE_NODE_TYPE(ObjectLiteral) Handle constant_properties() const { @@ -1098,6 +1146,23 @@ class ObjectLiteral: public MaterializedLiteral { kHasFunction = 1 << 1 }; + protected: + template friend class AstNodeFactory; + + ObjectLiteral(Isolate* isolate, + Handle constant_properties, + ZoneList* properties, + int literal_index, + bool is_simple, + bool fast_elements, + int depth, + bool has_function) + : MaterializedLiteral(isolate, literal_index, is_simple, depth), + constant_properties_(constant_properties), + properties_(properties), + fast_elements_(fast_elements), + has_function_(has_function) {} + private: Handle constant_properties_; ZoneList* properties_; @@ -1109,6 +1174,14 @@ class ObjectLiteral: public MaterializedLiteral { // Node for capturing a regexp literal. class RegExpLiteral: public MaterializedLiteral { public: + DECLARE_NODE_TYPE(RegExpLiteral) + + Handle pattern() const { return pattern_; } + Handle flags() const { return flags_; } + + protected: + template friend class AstNodeFactory; + RegExpLiteral(Isolate* isolate, Handle pattern, Handle flags, @@ -1117,11 +1190,6 @@ class RegExpLiteral: public MaterializedLiteral { pattern_(pattern), flags_(flags) {} - DECLARE_NODE_TYPE(RegExpLiteral) - - Handle pattern() const { return pattern_; } - Handle flags() const { return flags_; } - private: Handle pattern_; Handle flags_; @@ -1131,6 +1199,17 @@ class RegExpLiteral: public MaterializedLiteral { // for minimizing the work when constructing it at runtime. class ArrayLiteral: public MaterializedLiteral { public: + DECLARE_NODE_TYPE(ArrayLiteral) + + Handle constant_elements() const { return constant_elements_; } + ZoneList* values() const { return values_; } + + // Return an AST id for an element that is used in simulate instructions. + int GetIdForElement(int i) { return first_element_id_ + i; } + + protected: + template friend class AstNodeFactory; + ArrayLiteral(Isolate* isolate, Handle constant_elements, ZoneList* values, @@ -1142,14 +1221,6 @@ class ArrayLiteral: public MaterializedLiteral { values_(values), first_element_id_(ReserveIdRange(isolate, values->length())) {} - DECLARE_NODE_TYPE(ArrayLiteral) - - Handle constant_elements() const { return constant_elements_; } - ZoneList* values() const { return values_; } - - // Return an AST id for an element that is used in simulate instructions. - int GetIdForElement(int i) { return first_element_id_ + i; } - private: Handle constant_elements_; ZoneList* values_; @@ -1159,21 +1230,12 @@ class ArrayLiteral: public MaterializedLiteral { class VariableProxy: public Expression { public: - VariableProxy(Isolate* isolate, Variable* var); - - VariableProxy(Isolate* isolate, - Handle name, - bool is_this, - int position = RelocInfo::kNoPosition); - DECLARE_NODE_TYPE(VariableProxy) virtual bool IsValidLeftHandSide() { return var_ == NULL ? true : var_->IsValidLeftHandSide(); } - virtual bool IsInlineable() const; - bool IsVariable(Handle n) { return !is_this() && name().is_identical_to(n); } @@ -1196,6 +1258,15 @@ class VariableProxy: public Expression { void BindTo(Variable* var); protected: + template friend class AstNodeFactory; + + VariableProxy(Isolate* isolate, Variable* var); + + VariableProxy(Isolate* isolate, + Handle name, + bool is_this, + int position); + Handle name_; Variable* var_; // resolved variable, or NULL bool is_this_; @@ -1209,24 +1280,9 @@ class VariableProxy: public Expression { class Property: public Expression { public: - Property(Isolate* isolate, - Expression* obj, - Expression* key, - int pos) - : Expression(isolate), - obj_(obj), - key_(key), - pos_(pos), - is_monomorphic_(false), - is_array_length_(false), - is_string_length_(false), - is_string_access_(false), - is_function_prototype_(false) { } - DECLARE_NODE_TYPE(Property) virtual bool IsValidLeftHandSide() { return true; } - virtual bool IsInlineable() const; Expression* obj() const { return obj_; } Expression* key() const { return key_; } @@ -1242,6 +1298,23 @@ class Property: public Expression { virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; } bool IsArrayLength() { return is_array_length_; } + protected: + template friend class AstNodeFactory; + + Property(Isolate* isolate, + Expression* obj, + Expression* key, + int pos) + : Expression(isolate), + obj_(obj), + key_(key), + pos_(pos), + is_monomorphic_(false), + is_array_length_(false), + is_string_length_(false), + is_string_access_(false), + is_function_prototype_(false) { } + private: Expression* obj_; Expression* key_; @@ -1258,23 +1331,8 @@ class Property: public Expression { class Call: public Expression { public: - Call(Isolate* isolate, - Expression* expression, - ZoneList* arguments, - int pos) - : Expression(isolate), - expression_(expression), - arguments_(arguments), - pos_(pos), - is_monomorphic_(false), - check_type_(RECEIVER_MAP_CHECK), - return_id_(GetNextId(isolate)) { - } - DECLARE_NODE_TYPE(Call) - virtual bool IsInlineable() const; - Expression* expression() const { return expression_; } ZoneList* arguments() const { return arguments_; } virtual int position() const { return pos_; } @@ -1299,6 +1357,21 @@ class Call: public Expression { bool return_is_recorded_; #endif + protected: + template friend class AstNodeFactory; + + Call(Isolate* isolate, + Expression* expression, + ZoneList* arguments, + int pos) + : Expression(isolate), + expression_(expression), + arguments_(arguments), + pos_(pos), + is_monomorphic_(false), + check_type_(RECEIVER_MAP_CHECK), + return_id_(GetNextId(isolate)) { } + private: Expression* expression_; ZoneList* arguments_; @@ -1317,6 +1390,15 @@ class Call: public Expression { class CallNew: public Expression { public: + DECLARE_NODE_TYPE(CallNew) + + Expression* expression() const { return expression_; } + ZoneList* arguments() const { return arguments_; } + virtual int position() const { return pos_; } + + protected: + template friend class AstNodeFactory; + CallNew(Isolate* isolate, Expression* expression, ZoneList* arguments, @@ -1326,14 +1408,6 @@ class CallNew: public Expression { arguments_(arguments), pos_(pos) { } - DECLARE_NODE_TYPE(CallNew) - - virtual bool IsInlineable() const; - - Expression* expression() const { return expression_; } - ZoneList* arguments() const { return arguments_; } - virtual int position() const { return pos_; } - private: Expression* expression_; ZoneList* arguments_; @@ -1347,6 +1421,16 @@ class CallNew: public Expression { // implemented in JavaScript (see "v8natives.js"). class CallRuntime: public Expression { public: + DECLARE_NODE_TYPE(CallRuntime) + + Handle name() const { return name_; } + const Runtime::Function* function() const { return function_; } + ZoneList* arguments() const { return arguments_; } + bool is_jsruntime() const { return function_ == NULL; } + + protected: + template friend class AstNodeFactory; + CallRuntime(Isolate* isolate, Handle name, const Runtime::Function* function, @@ -1356,15 +1440,6 @@ class CallRuntime: public Expression { function_(function), arguments_(arguments) { } - DECLARE_NODE_TYPE(CallRuntime) - - virtual bool IsInlineable() const; - - Handle name() const { return name_; } - const Runtime::Function* function() const { return function_; } - ZoneList* arguments() const { return arguments_; } - bool is_jsruntime() const { return function_ == NULL; } - private: Handle name_; const Runtime::Function* function_; @@ -1374,6 +1449,20 @@ class CallRuntime: public Expression { class UnaryOperation: public Expression { public: + DECLARE_NODE_TYPE(UnaryOperation) + + virtual bool ResultOverwriteAllowed(); + + Token::Value op() const { return op_; } + Expression* expression() const { return expression_; } + virtual int position() const { return pos_; } + + int MaterializeTrueId() { return materialize_true_id_; } + int MaterializeFalseId() { return materialize_false_id_; } + + protected: + template friend class AstNodeFactory; + UnaryOperation(Isolate* isolate, Token::Value op, Expression* expression, @@ -1391,19 +1480,6 @@ class UnaryOperation: public Expression { } } - DECLARE_NODE_TYPE(UnaryOperation) - - virtual bool IsInlineable() const; - - virtual bool ResultOverwriteAllowed(); - - Token::Value op() const { return op_; } - Expression* expression() const { return expression_; } - virtual int position() const { return pos_; } - - int MaterializeTrueId() { return materialize_true_id_; } - int MaterializeFalseId() { return materialize_false_id_; } - private: Token::Value op_; Expression* expression_; @@ -1418,22 +1494,8 @@ class UnaryOperation: public Expression { class BinaryOperation: public Expression { public: - BinaryOperation(Isolate* isolate, - Token::Value op, - Expression* left, - Expression* right, - int pos) - : Expression(isolate), op_(op), left_(left), right_(right), pos_(pos) { - ASSERT(Token::IsBinaryOp(op)); - right_id_ = (op == Token::AND || op == Token::OR) - ? static_cast(GetNextId(isolate)) - : AstNode::kNoNumber; - } - DECLARE_NODE_TYPE(BinaryOperation) - virtual bool IsInlineable() const; - virtual bool ResultOverwriteAllowed(); Token::Value op() const { return op_; } @@ -1444,6 +1506,21 @@ class BinaryOperation: public Expression { // Bailout support. int RightId() const { return right_id_; } + protected: + template friend class AstNodeFactory; + + BinaryOperation(Isolate* isolate, + Token::Value op, + Expression* left, + Expression* right, + int pos) + : Expression(isolate), op_(op), left_(left), right_(right), pos_(pos) { + ASSERT(Token::IsBinaryOp(op)); + right_id_ = (op == Token::AND || op == Token::OR) + ? GetNextId(isolate) + : AstNode::kNoNumber; + } + private: Token::Value op_; Expression* left_; @@ -1457,19 +1534,6 @@ class BinaryOperation: public Expression { class CountOperation: public Expression { public: - CountOperation(Isolate* isolate, - Token::Value op, - bool is_prefix, - Expression* expr, - int pos) - : Expression(isolate), - op_(op), - is_prefix_(is_prefix), - expression_(expr), - pos_(pos), - assignment_id_(GetNextId(isolate)), - count_id_(GetNextId(isolate)) {} - DECLARE_NODE_TYPE(CountOperation) bool is_prefix() const { return is_prefix_; } @@ -1485,8 +1549,6 @@ class CountOperation: public Expression { virtual void MarkAsStatement() { is_prefix_ = true; } - virtual bool IsInlineable() const; - void RecordTypeFeedback(TypeFeedbackOracle* oracle); virtual bool IsMonomorphic() { return is_monomorphic_; } virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; } @@ -1495,6 +1557,22 @@ class CountOperation: public Expression { int AssignmentId() const { return assignment_id_; } int CountId() const { return count_id_; } + protected: + template friend class AstNodeFactory; + + CountOperation(Isolate* isolate, + Token::Value op, + bool is_prefix, + Expression* expr, + int pos) + : Expression(isolate), + op_(op), + is_prefix_(is_prefix), + expression_(expr), + pos_(pos), + assignment_id_(GetNextId(isolate)), + count_id_(GetNextId(isolate)) {} + private: Token::Value op_; bool is_prefix_; @@ -1509,6 +1587,26 @@ class CountOperation: public Expression { class CompareOperation: public Expression { public: + DECLARE_NODE_TYPE(CompareOperation) + + Token::Value op() const { return op_; } + Expression* left() const { return left_; } + Expression* right() const { return right_; } + virtual int position() const { return pos_; } + + // Type feedback information. + void RecordTypeFeedback(TypeFeedbackOracle* oracle); + bool IsSmiCompare() { return compare_type_ == SMI_ONLY; } + bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; } + + // Match special cases. + bool IsLiteralCompareTypeof(Expression** expr, Handle* check); + bool IsLiteralCompareUndefined(Expression** expr); + bool IsLiteralCompareNull(Expression** expr); + + protected: + template friend class AstNodeFactory; + CompareOperation(Isolate* isolate, Token::Value op, Expression* left, @@ -1523,25 +1621,6 @@ class CompareOperation: public Expression { ASSERT(Token::IsCompareOp(op)); } - DECLARE_NODE_TYPE(CompareOperation) - - Token::Value op() const { return op_; } - Expression* left() const { return left_; } - Expression* right() const { return right_; } - virtual int position() const { return pos_; } - - virtual bool IsInlineable() const; - - // Type feedback information. - void RecordTypeFeedback(TypeFeedbackOracle* oracle); - bool IsSmiCompare() { return compare_type_ == SMI_ONLY; } - bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; } - - // Match special cases. - bool IsLiteralCompareTypeof(Expression** expr, Handle* check); - bool IsLiteralCompareUndefined(Expression** expr); - bool IsLiteralCompareNull(Expression** expr); - private: Token::Value op_; Expression* left_; @@ -1555,6 +1634,21 @@ class CompareOperation: public Expression { class Conditional: 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_; } + + int then_expression_position() const { return then_expression_position_; } + int else_expression_position() const { return else_expression_position_; } + + int ThenId() const { return then_id_; } + int ElseId() const { return else_id_; } + + protected: + template friend class AstNodeFactory; + Conditional(Isolate* isolate, Expression* condition, Expression* then_expression, @@ -1568,22 +1662,7 @@ class Conditional: public Expression { then_expression_position_(then_expression_position), else_expression_position_(else_expression_position), then_id_(GetNextId(isolate)), - else_id_(GetNextId(isolate)) { - } - - DECLARE_NODE_TYPE(Conditional) - - virtual bool IsInlineable() const; - - Expression* condition() const { return condition_; } - Expression* then_expression() const { return then_expression_; } - Expression* else_expression() const { return else_expression_; } - - int then_expression_position() const { return then_expression_position_; } - int else_expression_position() const { return else_expression_position_; } - - int ThenId() const { return then_id_; } - int ElseId() const { return else_id_; } + else_id_(GetNextId(isolate)) { } private: Expression* condition_; @@ -1598,16 +1677,8 @@ class Conditional: public Expression { class Assignment: public Expression { public: - Assignment(Isolate* isolate, - Token::Value op, - Expression* target, - Expression* value, - int pos); - DECLARE_NODE_TYPE(Assignment) - virtual bool IsInlineable() const; - Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; } Token::Value binary_op() const; @@ -1639,6 +1710,25 @@ class Assignment: public Expression { int CompoundLoadId() const { return compound_load_id_; } int AssignmentId() const { return assignment_id_; } + protected: + template friend class AstNodeFactory; + + Assignment(Isolate* isolate, + Token::Value op, + Expression* target, + Expression* value, + int pos); + + template + void Init(Isolate* isolate, AstNodeFactory* factory) { + ASSERT(Token::IsAssignmentOp(op_)); + if (is_compound()) { + binary_operation_ = + factory->NewBinaryOperation(binary_op(), target_, value_, pos_ + 1); + compound_load_id_ = GetNextId(isolate); + } + } + private: Token::Value op_; Expression* target_; @@ -1658,14 +1748,16 @@ class Assignment: public Expression { class Throw: public Expression { public: - Throw(Isolate* isolate, Expression* exception, int pos) - : Expression(isolate), exception_(exception), pos_(pos) {} - DECLARE_NODE_TYPE(Throw) Expression* exception() const { return exception_; } virtual int position() const { return pos_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + Throw(Isolate* isolate, Expression* exception, int pos) + : Expression(isolate), exception_(exception), pos_(pos) {} private: Expression* exception_; @@ -1681,38 +1773,6 @@ class FunctionLiteral: public Expression { DECLARATION }; - FunctionLiteral(Isolate* isolate, - Handle name, - Scope* scope, - ZoneList* body, - int materialized_literal_count, - int expected_property_count, - int handler_count, - bool has_only_simple_this_property_assignments, - Handle this_property_assignments, - int parameter_count, - Type type, - bool has_duplicate_parameters) - : Expression(isolate), - name_(name), - scope_(scope), - body_(body), - this_property_assignments_(this_property_assignments), - inferred_name_(isolate->factory()->empty_string()), - materialized_literal_count_(materialized_literal_count), - expected_property_count_(expected_property_count), - handler_count_(handler_count), - parameter_count_(parameter_count), - function_token_position_(RelocInfo::kNoPosition) { - bitfield_ = - HasOnlySimpleThisPropertyAssignments::encode( - has_only_simple_this_property_assignments) | - IsExpression::encode(type != DECLARATION) | - IsAnonymous::encode(type == ANONYMOUS_EXPRESSION) | - Pretenure::encode(false) | - HasDuplicateParameters::encode(has_duplicate_parameters); - } - DECLARE_NODE_TYPE(FunctionLiteral) Handle name() const { return name_; } @@ -1752,18 +1812,61 @@ class FunctionLiteral: public Expression { bool pretenure() { return Pretenure::decode(bitfield_); } void set_pretenure() { bitfield_ |= Pretenure::encode(true); } - virtual bool IsInlineable() const; bool has_duplicate_parameters() { return HasDuplicateParameters::decode(bitfield_); } + bool ShouldSelfOptimize(); + + int ast_node_count() { return ast_properties_.node_count(); } + AstProperties::Flags* flags() { return ast_properties_.flags(); } + void set_ast_properties(AstProperties* ast_properties) { + ast_properties_ = *ast_properties; + } + + protected: + template friend class AstNodeFactory; + + FunctionLiteral(Isolate* isolate, + Handle name, + Scope* scope, + ZoneList* body, + int materialized_literal_count, + int expected_property_count, + int handler_count, + bool has_only_simple_this_property_assignments, + Handle this_property_assignments, + int parameter_count, + Type type, + bool has_duplicate_parameters) + : Expression(isolate), + name_(name), + scope_(scope), + body_(body), + this_property_assignments_(this_property_assignments), + inferred_name_(isolate->factory()->empty_string()), + materialized_literal_count_(materialized_literal_count), + expected_property_count_(expected_property_count), + handler_count_(handler_count), + parameter_count_(parameter_count), + function_token_position_(RelocInfo::kNoPosition) { + bitfield_ = + HasOnlySimpleThisPropertyAssignments::encode( + has_only_simple_this_property_assignments) | + IsExpression::encode(type != DECLARATION) | + IsAnonymous::encode(type == ANONYMOUS_EXPRESSION) | + Pretenure::encode(false) | + HasDuplicateParameters::encode(has_duplicate_parameters); + } + private: Handle name_; Scope* scope_; ZoneList* body_; Handle this_property_assignments_; Handle inferred_name_; + AstProperties ast_properties_; int materialized_literal_count_; int expected_property_count_; @@ -1782,17 +1885,20 @@ class FunctionLiteral: public Expression { class SharedFunctionInfoLiteral: public Expression { public: - SharedFunctionInfoLiteral( - Isolate* isolate, - Handle shared_function_info) - : Expression(isolate), shared_function_info_(shared_function_info) { } - DECLARE_NODE_TYPE(SharedFunctionInfoLiteral) Handle shared_function_info() const { return shared_function_info_; } - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + SharedFunctionInfoLiteral( + Isolate* isolate, + Handle shared_function_info) + : Expression(isolate), + shared_function_info_(shared_function_info) { } private: Handle shared_function_info_; @@ -1801,9 +1907,12 @@ class SharedFunctionInfoLiteral: public Expression { class ThisFunction: public Expression { public: - explicit ThisFunction(Isolate* isolate) : Expression(isolate) {} DECLARE_NODE_TYPE(ThisFunction) - virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + explicit ThisFunction(Isolate* isolate): Expression(isolate) {} }; @@ -2207,6 +2316,342 @@ class AstVisitor BASE_EMBEDDED { }; +// ---------------------------------------------------------------------------- +// Construction time visitor. + +class AstConstructionVisitor BASE_EMBEDDED { + public: + AstConstructionVisitor() { } + + AstProperties* ast_properties() { return &properties_; } + + private: + template friend class AstNodeFactory; + + // Node visitors. +#define DEF_VISIT(type) \ + void Visit##type(type* node); + AST_NODE_LIST(DEF_VISIT) +#undef DEF_VISIT + + void increase_node_count() { properties_.add_node_count(1); } + void add_flag(AstPropertiesFlag flag) { properties_.flags()->Add(flag); } + + AstProperties properties_; +}; + + +class AstNullVisitor BASE_EMBEDDED { + public: + // Node visitors. +#define DEF_VISIT(type) \ + void Visit##type(type* node) {} + AST_NODE_LIST(DEF_VISIT) +#undef DEF_VISIT +}; + + + +// ---------------------------------------------------------------------------- +// AstNode factory + +template +class AstNodeFactory BASE_EMBEDDED { + public: + explicit AstNodeFactory(Isolate* isolate) + : isolate_(isolate), + zone_(isolate_->zone()) { } + + Visitor* visitor() { return &visitor_; } + +#define VISIT_AND_RETURN(NodeType, node) \ + visitor_.Visit##NodeType((node)); \ + return node; + + Block* NewBlock(ZoneStringList* labels, + int capacity, + bool is_initializer_block) { + Block* block = new(zone_) Block( + isolate_, labels, capacity, is_initializer_block); + VISIT_AND_RETURN(Block, block) + } + + Declaration* NewDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* fun, + Scope* scope) { + Declaration* decl = new(zone_) Declaration(proxy, mode, fun, scope); + VISIT_AND_RETURN(Declaration, decl) + } + +#define STATEMENT_WITH_LABELS(NodeType) \ + NodeType* New##NodeType(ZoneStringList* labels) { \ + NodeType* stmt = new(zone_) NodeType(isolate_, labels); \ + VISIT_AND_RETURN(NodeType, stmt); \ + } + STATEMENT_WITH_LABELS(DoWhileStatement) + STATEMENT_WITH_LABELS(WhileStatement) + STATEMENT_WITH_LABELS(ForStatement) + STATEMENT_WITH_LABELS(ForInStatement) + STATEMENT_WITH_LABELS(SwitchStatement) +#undef STATEMENT_WITH_LABELS + + ExpressionStatement* NewExpressionStatement(Expression* expression) { + ExpressionStatement* stmt = new(zone_) ExpressionStatement(expression); + VISIT_AND_RETURN(ExpressionStatement, stmt) + } + + ContinueStatement* NewContinueStatement(IterationStatement* target) { + ContinueStatement* stmt = new(zone_) ContinueStatement(target); + VISIT_AND_RETURN(ContinueStatement, stmt) + } + + BreakStatement* NewBreakStatement(BreakableStatement* target) { + BreakStatement* stmt = new(zone_) BreakStatement(target); + VISIT_AND_RETURN(BreakStatement, stmt) + } + + ReturnStatement* NewReturnStatement(Expression* expression) { + ReturnStatement* stmt = new(zone_) ReturnStatement(expression); + VISIT_AND_RETURN(ReturnStatement, stmt) + } + + WithStatement* NewWithStatement(Expression* expression, + Statement* statement) { + WithStatement* stmt = new(zone_) WithStatement(expression, statement); + VISIT_AND_RETURN(WithStatement, stmt) + } + + IfStatement* NewIfStatement(Expression* condition, + Statement* then_statement, + Statement* else_statement) { + IfStatement* stmt = new(zone_) IfStatement( + isolate_, condition, then_statement, else_statement); + VISIT_AND_RETURN(IfStatement, stmt) + } + + TryCatchStatement* NewTryCatchStatement(int index, + Block* try_block, + Scope* scope, + Variable* variable, + Block* catch_block) { + TryCatchStatement* stmt = new(zone_) TryCatchStatement( + index, try_block, scope, variable, catch_block); + VISIT_AND_RETURN(TryCatchStatement, stmt) + } + + TryFinallyStatement* NewTryFinallyStatement(int index, + Block* try_block, + Block* finally_block) { + TryFinallyStatement* stmt = + new(zone_) TryFinallyStatement(index, try_block, finally_block); + VISIT_AND_RETURN(TryFinallyStatement, stmt) + } + + DebuggerStatement* NewDebuggerStatement() { + DebuggerStatement* stmt = new(zone_) DebuggerStatement(); + VISIT_AND_RETURN(DebuggerStatement, stmt) + } + + EmptyStatement* NewEmptyStatement() { + return new(zone_) EmptyStatement(); + } + + Literal* NewLiteral(Handle handle) { + Literal* lit = new(zone_) Literal(isolate_, handle); + VISIT_AND_RETURN(Literal, lit) + } + + Literal* NewNumberLiteral(double number) { + return NewLiteral(isolate_->factory()->NewNumber(number, TENURED)); + } + + ObjectLiteral* NewObjectLiteral( + Handle constant_properties, + ZoneList* properties, + int literal_index, + bool is_simple, + bool fast_elements, + int depth, + bool has_function) { + ObjectLiteral* lit = new(zone_) ObjectLiteral( + isolate_, constant_properties, properties, literal_index, + is_simple, fast_elements, depth, has_function); + VISIT_AND_RETURN(ObjectLiteral, lit) + } + + ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter, + FunctionLiteral* value) { + ObjectLiteral::Property* prop = + new(zone_) ObjectLiteral::Property(is_getter, value); + prop->set_key(NewLiteral(value->name())); + return prop; // Not an AST node, will not be visited. + } + + RegExpLiteral* NewRegExpLiteral(Handle pattern, + Handle flags, + int literal_index) { + RegExpLiteral* lit = + new(zone_) RegExpLiteral(isolate_, pattern, flags, literal_index); + VISIT_AND_RETURN(RegExpLiteral, lit); + } + + ArrayLiteral* NewArrayLiteral(Handle constant_elements, + ZoneList* values, + int literal_index, + bool is_simple, + int depth) { + ArrayLiteral* lit = new(zone_) ArrayLiteral( + isolate_, constant_elements, values, literal_index, is_simple, depth); + VISIT_AND_RETURN(ArrayLiteral, lit) + } + + VariableProxy* NewVariableProxy(Variable* var) { + VariableProxy* proxy = new(zone_) VariableProxy(isolate_, var); + VISIT_AND_RETURN(VariableProxy, proxy) + } + + VariableProxy* NewVariableProxy(Handle name, + bool is_this, + int position = RelocInfo::kNoPosition) { + VariableProxy* proxy = + new(zone_) VariableProxy(isolate_, name, is_this, position); + VISIT_AND_RETURN(VariableProxy, proxy) + } + + Property* NewProperty(Expression* obj, Expression* key, int pos) { + Property* prop = new(zone_) Property(isolate_, obj, key, pos); + VISIT_AND_RETURN(Property, prop) + } + + Call* NewCall(Expression* expression, + ZoneList* arguments, + int pos) { + Call* call = new(zone_) Call(isolate_, expression, arguments, pos); + VISIT_AND_RETURN(Call, call) + } + + CallNew* NewCallNew(Expression* expression, + ZoneList* arguments, + int pos) { + CallNew* call = new(zone_) CallNew(isolate_, expression, arguments, pos); + VISIT_AND_RETURN(CallNew, call) + } + + CallRuntime* NewCallRuntime(Handle name, + const Runtime::Function* function, + ZoneList* arguments) { + CallRuntime* call = + new(zone_) CallRuntime(isolate_, name, function, arguments); + VISIT_AND_RETURN(CallRuntime, call) + } + + UnaryOperation* NewUnaryOperation(Token::Value op, + Expression* expression, + int pos) { + UnaryOperation* node = + new(zone_) UnaryOperation(isolate_, op, expression, pos); + VISIT_AND_RETURN(UnaryOperation, node) + } + + BinaryOperation* NewBinaryOperation(Token::Value op, + Expression* left, + Expression* right, + int pos) { + BinaryOperation* node = + new(zone_) BinaryOperation(isolate_, op, left, right, pos); + VISIT_AND_RETURN(BinaryOperation, node) + } + + CountOperation* NewCountOperation(Token::Value op, + bool is_prefix, + Expression* expr, + int pos) { + CountOperation* node = + new(zone_) CountOperation(isolate_, op, is_prefix, expr, pos); + VISIT_AND_RETURN(CountOperation, node) + } + + CompareOperation* NewCompareOperation(Token::Value op, + Expression* left, + Expression* right, + int pos) { + CompareOperation* node = + new(zone_) CompareOperation(isolate_, op, left, right, pos); + VISIT_AND_RETURN(CompareOperation, node) + } + + Conditional* NewConditional(Expression* condition, + Expression* then_expression, + Expression* else_expression, + int then_expression_position, + int else_expression_position) { + Conditional* cond = new(zone_) Conditional( + isolate_, condition, then_expression, else_expression, + then_expression_position, else_expression_position); + VISIT_AND_RETURN(Conditional, cond) + } + + Assignment* NewAssignment(Token::Value op, + Expression* target, + Expression* value, + int pos) { + Assignment* assign = + new(zone_) Assignment(isolate_, op, target, value, pos); + assign->Init(isolate_, this); + VISIT_AND_RETURN(Assignment, assign) + } + + Throw* NewThrow(Expression* exception, int pos) { + Throw* t = new(zone_) Throw(isolate_, exception, pos); + VISIT_AND_RETURN(Throw, t) + } + + FunctionLiteral* NewFunctionLiteral( + Handle name, + Scope* scope, + ZoneList* body, + int materialized_literal_count, + int expected_property_count, + int handler_count, + bool has_only_simple_this_property_assignments, + Handle this_property_assignments, + int parameter_count, + bool has_duplicate_parameters, + FunctionLiteral::Type type, + bool visit_with_visitor) { + FunctionLiteral* lit = new(zone_) FunctionLiteral( + isolate_, name, scope, body, + materialized_literal_count, expected_property_count, handler_count, + has_only_simple_this_property_assignments, this_property_assignments, + parameter_count, type, has_duplicate_parameters); + if (visit_with_visitor) { + visitor_.VisitFunctionLiteral(lit); + } + return lit; + } + + SharedFunctionInfoLiteral* NewSharedFunctionInfoLiteral( + Handle shared_function_info) { + SharedFunctionInfoLiteral* lit = + new(zone_) SharedFunctionInfoLiteral(isolate_, shared_function_info); + VISIT_AND_RETURN(SharedFunctionInfoLiteral, lit) + } + + ThisFunction* NewThisFunction() { + ThisFunction* fun = new(zone_) ThisFunction(isolate_); + VISIT_AND_RETURN(ThisFunction, fun) + } + +#undef VISIT_AND_RETURN + + private: + Isolate* isolate_; + Zone* zone_; + Visitor visitor_; +}; + + } } // namespace v8::internal #endif // V8_AST_H_ diff --git a/src/compiler.cc b/src/compiler.cc index ba4d202174..9b8b1a4d03 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -652,6 +652,8 @@ bool Compiler::CompileLazy(CompilationInfo* info) { // Check the function has compiled code. ASSERT(shared->is_compiled()); shared->set_code_age(0); + shared->set_dont_crankshaft(lit->flags()->Contains(kDontOptimize)); + shared->set_dont_inline(lit->flags()->Contains(kDontInline)); if (info->AllowOptimize() && !shared->optimization_disabled()) { // If we're asked to always optimize, we compile the optimized @@ -750,6 +752,9 @@ void Compiler::SetFunctionInfo(Handle function_info, function_info->set_language_mode(lit->language_mode()); function_info->set_uses_arguments(lit->scope()->arguments() != NULL); function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); + function_info->set_ast_node_count(lit->ast_node_count()); + function_info->set_dont_crankshaft(lit->flags()->Contains(kDontOptimize)); + function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); } diff --git a/src/heap.cc b/src/heap.cc index 4cea9331b1..042069c15a 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2865,7 +2865,8 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER); share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER); share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER); - share->set_deopt_counter(Smi::FromInt(FLAG_deopt_every_n_times)); + share->set_deopt_counter(FLAG_deopt_every_n_times); + share->set_ast_node_count(0); // Set integer fields (smi or int, depending on the architecture). share->set_length(0); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index fdfadfaba7..d859c4cde6 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4796,8 +4796,8 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { // Do a quick check on source code length to avoid parsing large // inlining candidates. - if ((FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) - || target->shared()->SourceSize() > kUnlimitedMaxSourceSize) { + if ((FLAG_limit_inlining && target_shared->SourceSize() > kMaxSourceSize) + || target_shared->SourceSize() > kUnlimitedMaxSourceSize) { TraceInline(target, caller, "target text too big"); return false; } @@ -4807,6 +4807,17 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { TraceInline(target, caller, "target not inlineable"); return false; } + if (target_shared->dont_inline() || target_shared->dont_crankshaft()) { + TraceInline(target, caller, "target contains unsupported syntax [early]"); + return false; + } + + int nodes_added = target_shared->ast_node_count(); + if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) || + nodes_added > kUnlimitedMaxInlinedSize) { + TraceInline(target, caller, "target AST is too large [early]"); + return false; + } #if !defined(V8_TARGET_ARCH_IA32) // Target must be able to use caller's context. @@ -4851,8 +4862,6 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { return false; } - int count_before = AstNode::Count(); - // Parse and allocate variables. CompilationInfo target_info(target); if (!ParserApi::Parse(&target_info, kNoParsingFlags) || @@ -4872,11 +4881,17 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { } FunctionLiteral* function = target_info.function(); - // Count the number of AST nodes added by inlining this call. - int nodes_added = AstNode::Count() - count_before; + // The following conditions must be checked again after re-parsing, because + // earlier the information might not have been complete due to lazy parsing. + nodes_added = function->ast_node_count(); if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) || nodes_added > kUnlimitedMaxInlinedSize) { - TraceInline(target, caller, "target AST is too large"); + TraceInline(target, caller, "target AST is too large [late]"); + return false; + } + AstProperties::Flags* flags(function->flags()); + if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) { + TraceInline(target, caller, "target contains unsupported syntax [late]"); return false; } @@ -4895,13 +4910,6 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { return false; } } - // All statements in the body must be inlineable. - for (int i = 0, count = function->body()->length(); i < count; ++i) { - if (!function->body()->at(i)->IsInlineable()) { - TraceInline(target, caller, "target contains unsupported syntax"); - return false; - } - } // Generate the deoptimization data for the unoptimized version of // the target function if we don't already have it. diff --git a/src/isolate.h b/src/isolate.h index 295adca275..5612630c04 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -362,7 +362,7 @@ typedef List DebugObjectCache; /* Serializer state. */ \ V(ExternalReferenceTable*, external_reference_table, NULL) \ /* AstNode state. */ \ - V(unsigned, ast_node_id, 0) \ + V(int, ast_node_id, 0) \ V(unsigned, ast_node_count, 0) \ /* SafeStackFrameIterator activations count. */ \ V(int, safe_stack_iterator_counter, 0) \ diff --git a/src/objects-inl.h b/src/objects-inl.h index 6eeba20382..baaa5ab347 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3576,6 +3576,8 @@ SMI_ACCESSORS(SharedFunctionInfo, compiler_hints, SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count, kThisPropertyAssignmentsCountOffset) SMI_ACCESSORS(SharedFunctionInfo, opt_count, kOptCountOffset) +SMI_ACCESSORS(SharedFunctionInfo, ast_node_count, kAstNodeCountOffset) +SMI_ACCESSORS(SharedFunctionInfo, deopt_counter, kDeoptCounterOffset) #else #define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset) \ @@ -3626,6 +3628,9 @@ PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, this_property_assignments_count, kThisPropertyAssignmentsCountOffset) PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, opt_count, kOptCountOffset) + +PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, ast_node_count, kAstNodeCountOffset) +PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, deopt_counter, kDeoptCounterOffset) #endif @@ -3708,6 +3713,9 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, kNameShouldPrintAsAnonymous) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, bound, kBoundFunction) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_anonymous, kIsAnonymous) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_crankshaft, + kDontCrankshaft) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_inline, kDontInline) ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset) ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset) @@ -3777,16 +3785,6 @@ void SharedFunctionInfo::set_scope_info(ScopeInfo* value, } -Smi* SharedFunctionInfo::deopt_counter() { - return reinterpret_cast(READ_FIELD(this, kDeoptCounterOffset)); -} - - -void SharedFunctionInfo::set_deopt_counter(Smi* value) { - WRITE_FIELD(this, kDeoptCounterOffset, value); -} - - bool SharedFunctionInfo::is_compiled() { return code() != Isolate::Current()->builtins()->builtin(Builtins::kLazyCompile); diff --git a/src/objects.h b/src/objects.h index 97954cdcec..76ac347d32 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5203,8 +5203,11 @@ class SharedFunctionInfo: public HeapObject { // A counter used to determine when to stress the deoptimizer with a // deopt. - inline Smi* deopt_counter(); - inline void set_deopt_counter(Smi* counter); + inline int deopt_counter(); + inline void set_deopt_counter(int counter); + + inline int ast_node_count(); + inline void set_ast_node_count(int count); // Add information on assignments of the form this.x = ...; void SetThisPropertyAssignmentsInfo( @@ -5278,6 +5281,12 @@ class SharedFunctionInfo: public HeapObject { // through the API, which does not change this flag). DECL_BOOLEAN_ACCESSORS(is_anonymous) + // Indicates that the function cannot be crankshafted. + DECL_BOOLEAN_ACCESSORS(dont_crankshaft) + + // Indicates that the function cannot be inlined. + DECL_BOOLEAN_ACCESSORS(dont_inline) + // Indicates whether or not the code in the shared function support // deoptimization. inline bool has_deoptimization_support(); @@ -5372,12 +5381,10 @@ class SharedFunctionInfo: public HeapObject { kInferredNameOffset + kPointerSize; static const int kThisPropertyAssignmentsOffset = kInitialMapOffset + kPointerSize; - static const int kDeoptCounterOffset = - kThisPropertyAssignmentsOffset + kPointerSize; #if V8_HOST_ARCH_32_BIT // Smi fields. static const int kLengthOffset = - kDeoptCounterOffset + kPointerSize; + kThisPropertyAssignmentsOffset + kPointerSize; static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize; static const int kExpectedNofPropertiesOffset = kFormalParameterCountOffset + kPointerSize; @@ -5395,8 +5402,11 @@ class SharedFunctionInfo: public HeapObject { kCompilerHintsOffset + kPointerSize; static const int kOptCountOffset = kThisPropertyAssignmentsCountOffset + kPointerSize; + static const int kAstNodeCountOffset = kOptCountOffset + kPointerSize; + static const int kDeoptCounterOffset = + kAstNodeCountOffset + kPointerSize; // Total size. - static const int kSize = kOptCountOffset + kPointerSize; + static const int kSize = kDeoptCounterOffset + kPointerSize; #else // The only reason to use smi fields instead of int fields // is to allow iteration without maps decoding during @@ -5408,7 +5418,7 @@ class SharedFunctionInfo: public HeapObject { // word is not set and thus this word cannot be treated as pointer // to HeapObject during old space traversal. static const int kLengthOffset = - kDeoptCounterOffset + kPointerSize; + kThisPropertyAssignmentsOffset + kPointerSize; static const int kFormalParameterCountOffset = kLengthOffset + kIntSize; @@ -5432,8 +5442,11 @@ class SharedFunctionInfo: public HeapObject { static const int kOptCountOffset = kThisPropertyAssignmentsCountOffset + kIntSize; + static const int kAstNodeCountOffset = kOptCountOffset + kIntSize; + static const int kDeoptCounterOffset = kAstNodeCountOffset + kIntSize; + // Total size. - static const int kSize = kOptCountOffset + kIntSize; + static const int kSize = kDeoptCounterOffset + kIntSize; #endif @@ -5480,6 +5493,8 @@ class SharedFunctionInfo: public HeapObject { kBoundFunction, kIsAnonymous, kNameShouldPrintAsAnonymous, + kDontCrankshaft, + kDontInline, kCompilerHintsCount // Pseudo entry }; diff --git a/src/parser.cc b/src/parser.cc index c6a332d2a0..25a409d805 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -481,62 +481,6 @@ class Parser::BlockState BASE_EMBEDDED { }; -class Parser::FunctionState BASE_EMBEDDED { - public: - FunctionState(Parser* parser, Scope* scope, Isolate* isolate); - ~FunctionState(); - - int NextMaterializedLiteralIndex() { - return next_materialized_literal_index_++; - } - int materialized_literal_count() { - return next_materialized_literal_index_ - JSFunction::kLiteralsPrefixSize; - } - - int NextHandlerIndex() { return next_handler_index_++; } - int handler_count() { return next_handler_index_; } - - void SetThisPropertyAssignmentInfo( - bool only_simple_this_property_assignments, - Handle this_property_assignments) { - only_simple_this_property_assignments_ = - only_simple_this_property_assignments; - this_property_assignments_ = this_property_assignments; - } - bool only_simple_this_property_assignments() { - return only_simple_this_property_assignments_; - } - Handle this_property_assignments() { - return this_property_assignments_; - } - - void AddProperty() { expected_property_count_++; } - int expected_property_count() { return expected_property_count_; } - - private: - // Used to assign an index to each literal that needs materialization in - // the function. Includes regexp literals, and boilerplate for object and - // array literals. - int next_materialized_literal_index_; - - // Used to assign a per-function index to try and catch handlers. - int next_handler_index_; - - // Properties count estimation. - int expected_property_count_; - - // Keeps track of assignments to properties of this. Used for - // optimizing constructors. - bool only_simple_this_property_assignments_; - Handle this_property_assignments_; - - Parser* parser_; - FunctionState* outer_function_state_; - Scope* outer_scope_; - unsigned saved_ast_node_id_; -}; - - Parser::FunctionState::FunctionState(Parser* parser, Scope* scope, Isolate* isolate) @@ -548,7 +492,8 @@ Parser::FunctionState::FunctionState(Parser* parser, parser_(parser), outer_function_state_(parser->current_function_state_), outer_scope_(parser->top_scope_), - saved_ast_node_id_(isolate->ast_node_id()) { + saved_ast_node_id_(isolate->ast_node_id()), + factory_(isolate) { parser->top_scope_ = scope; parser->current_function_state_ = this; isolate->set_ast_node_id(AstNode::kDeclarationsId + 1); @@ -674,8 +619,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, } if (ok) { - result = new(zone()) FunctionLiteral( - isolate(), + result = factory()->NewFunctionLiteral( no_name, top_scope_, body, @@ -685,8 +629,10 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, function_state.only_simple_this_property_assignments(), function_state.this_property_assignments(), 0, + false, // Does not have duplicate parameters. FunctionLiteral::ANONYMOUS_EXPRESSION, - false); // Does not have duplicate parameters. + false); // Top-level literal doesn't count for the AST's properties. + result->set_ast_properties(factory()->visitor()->ast_properties()); } else if (stack_overflow_) { isolate()->StackOverflow(); } @@ -1274,7 +1220,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { case Token::SEMICOLON: Next(); - return EmptyStatement(); + return factory()->NewEmptyStatement(); case Token::IF: stmt = ParseIfStatement(labels, ok); @@ -1322,7 +1268,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // one must take great care not to treat it as a // fall-through. It is much easier just to wrap the entire // try-statement in a statement block and put the labels there - Block* result = new(zone()) Block(isolate(), labels, 1, false); + Block* result = factory()->NewBlock(labels, 1, false); Target target(&this->target_stack_, result); TryStatement* statement = ParseTryStatement(CHECK_OK); if (statement) { @@ -1454,9 +1400,9 @@ VariableProxy* Parser::Declare(Handle name, // a performance issue since it may lead to repeated // Runtime::DeclareContextSlot() calls. VariableProxy* proxy = declaration_scope->NewUnresolved( - name, scanner().location().beg_pos); + factory(), name, scanner().location().beg_pos); declaration_scope->AddDeclaration( - new(zone()) Declaration(proxy, mode, fun, top_scope_)); + factory()->NewDeclaration(proxy, mode, fun, top_scope_)); if ((mode == CONST || mode == CONST_HARMONY) && declaration_scope->is_global_scope()) { @@ -1564,10 +1510,11 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // introduced dynamically when we meet their declarations, whereas // other functions are set up when entering the surrounding scope. SharedFunctionInfoLiteral* lit = - new(zone()) SharedFunctionInfoLiteral(isolate(), shared); + factory()->NewSharedFunctionInfoLiteral(shared); VariableProxy* var = Declare(name, VAR, NULL, true, CHECK_OK); - return new(zone()) ExpressionStatement(new(zone()) Assignment( - isolate(), Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)); + return factory()->NewExpressionStatement( + factory()->NewAssignment( + Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)); } @@ -1589,7 +1536,7 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) { // initial value upon entering the corresponding scope. VariableMode mode = is_extended_mode() ? LET : VAR; Declare(name, mode, fun, true, CHECK_OK); - return EmptyStatement(); + return factory()->NewEmptyStatement(); } @@ -1603,7 +1550,7 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { // (ECMA-262, 3rd, 12.2) // // Construct block expecting 16 statements. - Block* result = new(zone()) Block(isolate(), labels, 16, false); + Block* result = factory()->NewBlock(labels, 16, false); Target target(&this->target_stack_, result); Expect(Token::LBRACE, CHECK_OK); InitializationBlockFinder block_finder(top_scope_, target_stack_); @@ -1626,7 +1573,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { // '{' SourceElement* '}' // Construct block expecting 16 statements. - Block* body = new(zone()) Block(isolate(), labels, 16, false); + Block* body = factory()->NewBlock(labels, 16, false); Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE); // Parse the statements and collect escaping labels. @@ -1786,7 +1733,7 @@ Block* Parser::ParseVariableDeclarations( // is inside an initializer block, it is ignored. // // Create new block with one expected declaration. - Block* block = new(zone()) Block(isolate(), NULL, 1, true); + Block* block = factory()->NewBlock(NULL, 1, true); int nvars = 0; // the number of variables declared Handle name; do { @@ -1907,7 +1854,7 @@ Block* Parser::ParseVariableDeclarations( // Compute the arguments for the runtime call. ZoneList* arguments = new(zone()) ZoneList(3); // We have at least 1 parameter. - arguments->Add(NewLiteral(name)); + arguments->Add(factory()->NewLiteral(name)); CallRuntime* initialize; if (is_const) { @@ -1918,17 +1865,15 @@ Block* Parser::ParseVariableDeclarations( // and add it to the initialization statement block. // Note that the function does different things depending on // the number of arguments (1 or 2). - initialize = - new(zone()) CallRuntime( - isolate(), - isolate()->factory()->InitializeConstGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeConstGlobal), - arguments); + initialize = factory()->NewCallRuntime( + isolate()->factory()->InitializeConstGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeConstGlobal), + arguments); } else { // Add strict mode. // We may want to pass singleton to avoid Literal allocations. LanguageMode language_mode = initialization_scope->language_mode(); - arguments->Add(NewNumberLiteral(language_mode)); + arguments->Add(factory()->NewNumberLiteral(language_mode)); // Be careful not to assign a value to the global variable if // we're in a with. The initialization value should not @@ -1943,15 +1888,13 @@ Block* Parser::ParseVariableDeclarations( // and add it to the initialization statement block. // Note that the function does different things depending on // the number of arguments (2 or 3). - initialize = - new(zone()) CallRuntime( - isolate(), - isolate()->factory()->InitializeVarGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeVarGlobal), - arguments); + initialize = factory()->NewCallRuntime( + isolate()->factory()->InitializeVarGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeVarGlobal), + arguments); } - block->AddStatement(new(zone()) ExpressionStatement(initialize)); + block->AddStatement(factory()->NewExpressionStatement(initialize)); } else if (needs_init) { // Constant initializations always assign to the declared constant which // is always at the function scope level. This is only relevant for @@ -1964,8 +1907,8 @@ Block* Parser::ParseVariableDeclarations( ASSERT(proxy->var() != NULL); ASSERT(value != NULL); Assignment* assignment = - new(zone()) Assignment(isolate(), init_op, proxy, value, position); - block->AddStatement(new(zone()) ExpressionStatement(assignment)); + factory()->NewAssignment(init_op, proxy, value, position); + block->AddStatement(factory()->NewExpressionStatement(assignment)); value = NULL; } @@ -1976,10 +1919,11 @@ Block* Parser::ParseVariableDeclarations( // 'var' initializations are simply assignments (with all the consequences // if they are inside a 'with' statement - they may change a 'with' object // property). - VariableProxy* proxy = initialization_scope->NewUnresolved(name); + VariableProxy* proxy = + initialization_scope->NewUnresolved(factory(), name); Assignment* assignment = - new(zone()) Assignment(isolate(), init_op, proxy, value, position); - block->AddStatement(new(zone()) ExpressionStatement(assignment)); + factory()->NewAssignment(init_op, proxy, value, position); + block->AddStatement(factory()->NewExpressionStatement(assignment)); } if (fni_ != NULL) fni_->Leave(); @@ -2059,7 +2003,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, // Parsed expression statement. ExpectSemicolon(CHECK_OK); - return new(zone()) ExpressionStatement(expr); + return factory()->NewExpressionStatement(expr); } @@ -2077,10 +2021,9 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) { Next(); else_statement = ParseStatement(labels, CHECK_OK); } else { - else_statement = EmptyStatement(); + else_statement = factory()->NewEmptyStatement(); } - return new(zone()) IfStatement( - isolate(), condition, then_statement, else_statement); + return factory()->NewIfStatement(condition, then_statement, else_statement); } @@ -2110,7 +2053,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) { return NULL; } ExpectSemicolon(CHECK_OK); - return new(zone()) ContinueStatement(target); + return factory()->NewContinueStatement(target); } @@ -2129,7 +2072,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { // empty statements, e.g. 'l1: l2: l3: break l2;' if (!label.is_null() && ContainsLabel(labels, label)) { ExpectSemicolon(CHECK_OK); - return EmptyStatement(); + return factory()->NewEmptyStatement(); } BreakableStatement* target = NULL; target = LookupBreakTarget(label, CHECK_OK); @@ -2146,7 +2089,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { return NULL; } ExpectSemicolon(CHECK_OK); - return new(zone()) BreakStatement(target); + return factory()->NewBreakStatement(target); } @@ -2166,11 +2109,11 @@ Statement* Parser::ParseReturnStatement(bool* ok) { tok == Token::RBRACE || tok == Token::EOS) { ExpectSemicolon(CHECK_OK); - result = new(zone()) ReturnStatement(GetLiteralUndefined()); + result = factory()->NewReturnStatement(GetLiteralUndefined()); } else { Expression* expr = ParseExpression(true, CHECK_OK); ExpectSemicolon(CHECK_OK); - result = new(zone()) ReturnStatement(expr); + result = factory()->NewReturnStatement(expr); } // An ECMAScript program is considered syntactically incorrect if it @@ -2183,7 +2126,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { declaration_scope->is_eval_scope()) { Handle type = isolate()->factory()->illegal_return_symbol(); Expression* throw_error = NewThrowSyntaxError(type, Handle::null()); - return new(zone()) ExpressionStatement(throw_error); + return factory()->NewExpressionStatement(throw_error); } return result; } @@ -2213,7 +2156,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { stmt = ParseStatement(labels, CHECK_OK); with_scope->set_end_position(scanner().location().end_pos); } - return new(zone()) WithStatement(expr, stmt); + return factory()->NewWithStatement(expr, stmt); } @@ -2255,7 +2198,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels, // SwitchStatement :: // 'switch' '(' Expression ')' '{' CaseClause* '}' - SwitchStatement* statement = new(zone()) SwitchStatement(isolate(), labels); + SwitchStatement* statement = factory()->NewSwitchStatement(labels); Target target(&this->target_stack_, statement); Expect(Token::SWITCH, CHECK_OK); @@ -2291,8 +2234,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) { Expression* exception = ParseExpression(true, CHECK_OK); ExpectSemicolon(CHECK_OK); - return new(zone()) ExpressionStatement( - new(zone()) Throw(isolate(), exception, pos)); + return factory()->NewExpressionStatement(factory()->NewThrow(exception, pos)); } @@ -2379,13 +2321,10 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { // If we have both, create an inner try/catch. ASSERT(catch_scope != NULL && catch_variable != NULL); int index = current_function_state_->NextHandlerIndex(); - TryCatchStatement* statement = new(zone()) TryCatchStatement(index, - try_block, - catch_scope, - catch_variable, - catch_block); + TryCatchStatement* statement = factory()->NewTryCatchStatement( + index, try_block, catch_scope, catch_variable, catch_block); statement->set_escaping_targets(try_collector.targets()); - try_block = new(zone()) Block(isolate(), NULL, 1, false); + try_block = factory()->NewBlock(NULL, 1, false); try_block->AddStatement(statement); catch_block = NULL; // Clear to indicate it's been handled. } @@ -2395,17 +2334,12 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ASSERT(finally_block == NULL); ASSERT(catch_scope != NULL && catch_variable != NULL); int index = current_function_state_->NextHandlerIndex(); - result = new(zone()) TryCatchStatement(index, - try_block, - catch_scope, - catch_variable, - catch_block); + result = factory()->NewTryCatchStatement( + index, try_block, catch_scope, catch_variable, catch_block); } else { ASSERT(finally_block != NULL); int index = current_function_state_->NextHandlerIndex(); - result = new(zone()) TryFinallyStatement(index, - try_block, - finally_block); + result = factory()->NewTryFinallyStatement(index, try_block, finally_block); // Combine the jump targets of the try block and the possible catch block. try_collector.targets()->AddAll(*catch_collector.targets()); } @@ -2420,7 +2354,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels, // DoStatement :: // 'do' Statement 'while' '(' Expression ')' ';' - DoWhileStatement* loop = new(zone()) DoWhileStatement(isolate(), labels); + DoWhileStatement* loop = factory()->NewDoWhileStatement(labels); Target target(&this->target_stack_, loop); Expect(Token::DO, CHECK_OK); @@ -2451,7 +2385,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { // WhileStatement :: // 'while' '(' Expression ')' Statement - WhileStatement* loop = new(zone()) WhileStatement(isolate(), labels); + WhileStatement* loop = factory()->NewWhileStatement(labels); Target target(&this->target_stack_, loop); Expect(Token::WHILE, CHECK_OK); @@ -2486,8 +2420,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK); if (peek() == Token::IN && !name.is_null()) { - VariableProxy* each = top_scope_->NewUnresolved(name); - ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); + VariableProxy* each = top_scope_->NewUnresolved(factory(), name); + ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); @@ -2496,7 +2430,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Statement* body = ParseStatement(NULL, CHECK_OK); loop->Initialize(each, enumerable, body); - Block* result = new(zone()) Block(isolate(), NULL, 2, false); + Block* result = factory()->NewBlock(NULL, 2, false); result->AddStatement(variable_statement); result->AddStatement(loop); top_scope_ = saved_scope; @@ -2534,9 +2468,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { // TODO(keuchel): Move the temporary variable to the block scope, after // implementing stack allocated block scoped variables. Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name); - VariableProxy* temp_proxy = new(zone()) VariableProxy(isolate(), temp); - VariableProxy* each = top_scope_->NewUnresolved(name); - ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); + VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); + VariableProxy* each = top_scope_->NewUnresolved(factory(), name); + ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); @@ -2544,14 +2478,11 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Expect(Token::RPAREN, CHECK_OK); Statement* body = ParseStatement(NULL, CHECK_OK); - Block* body_block = new(zone()) Block(isolate(), NULL, 3, false); - Assignment* assignment = new(zone()) Assignment(isolate(), - Token::ASSIGN, - each, - temp_proxy, - RelocInfo::kNoPosition); + Block* body_block = factory()->NewBlock(NULL, 3, false); + Assignment* assignment = factory()->NewAssignment( + Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition); Statement* assignment_statement = - new(zone()) ExpressionStatement(assignment); + factory()->NewExpressionStatement(assignment); body_block->AddStatement(variable_statement); body_block->AddStatement(assignment_statement); body_block->AddStatement(body); @@ -2578,7 +2509,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { isolate()->factory()->invalid_lhs_in_for_in_symbol(); expression = NewThrowReferenceError(type); } - ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); + ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); @@ -2595,13 +2526,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { return loop; } else { - init = new(zone()) ExpressionStatement(expression); + init = factory()->NewExpressionStatement(expression); } } } // Standard 'for' loop - ForStatement* loop = new(zone()) ForStatement(isolate(), labels); + ForStatement* loop = factory()->NewForStatement(labels); Target target(&this->target_stack_, loop); // Parsed initializer at this point. @@ -2616,7 +2547,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Statement* next = NULL; if (peek() != Token::RPAREN) { Expression* exp = ParseExpression(true, CHECK_OK); - next = new(zone()) ExpressionStatement(exp); + next = factory()->NewExpressionStatement(exp); } Expect(Token::RPAREN, CHECK_OK); @@ -2636,7 +2567,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { // for (; c; n) b // } ASSERT(init != NULL); - Block* result = new(zone()) Block(isolate(), NULL, 2, false); + Block* result = factory()->NewBlock(NULL, 2, false); result->AddStatement(init); result->AddStatement(loop); result->set_block_scope(for_scope); @@ -2660,8 +2591,8 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) { Expect(Token::COMMA, CHECK_OK); int position = scanner().location().beg_pos; Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - result = new(zone()) BinaryOperation( - isolate(), Token::COMMA, result, right, position); + result = + factory()->NewBinaryOperation(Token::COMMA, result, right, position); } return result; } @@ -2736,7 +2667,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { fni_->Leave(); } - return new(zone()) Assignment(isolate(), op, expression, right, pos); + return factory()->NewAssignment(op, expression, right, pos); } @@ -2758,8 +2689,8 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) { Expect(Token::COLON, CHECK_OK); int right_position = scanner().peek_location().beg_pos; Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - return new(zone()) Conditional( - isolate(), expression, left, right, left_position, right_position); + return factory()->NewConditional( + expression, left, right, left_position, right_position); } @@ -2790,41 +2721,47 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { switch (op) { case Token::ADD: - x = NewNumberLiteral(x_val + y_val); + x = factory()->NewNumberLiteral(x_val + y_val); continue; case Token::SUB: - x = NewNumberLiteral(x_val - y_val); + x = factory()->NewNumberLiteral(x_val - y_val); continue; case Token::MUL: - x = NewNumberLiteral(x_val * y_val); + x = factory()->NewNumberLiteral(x_val * y_val); continue; case Token::DIV: - x = NewNumberLiteral(x_val / y_val); + x = factory()->NewNumberLiteral(x_val / y_val); continue; - case Token::BIT_OR: - x = NewNumberLiteral(DoubleToInt32(x_val) | DoubleToInt32(y_val)); + case Token::BIT_OR: { + int value = DoubleToInt32(x_val) | DoubleToInt32(y_val); + x = factory()->NewNumberLiteral(value); continue; - case Token::BIT_AND: - x = NewNumberLiteral(DoubleToInt32(x_val) & DoubleToInt32(y_val)); + } + case Token::BIT_AND: { + int value = DoubleToInt32(x_val) & DoubleToInt32(y_val); + x = factory()->NewNumberLiteral(value); continue; - case Token::BIT_XOR: - x = NewNumberLiteral(DoubleToInt32(x_val) ^ DoubleToInt32(y_val)); + } + case Token::BIT_XOR: { + int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val); + x = factory()->NewNumberLiteral(value); continue; + } case Token::SHL: { int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f); - x = NewNumberLiteral(value); + x = factory()->NewNumberLiteral(value); continue; } case Token::SHR: { uint32_t shift = DoubleToInt32(y_val) & 0x1f; uint32_t value = DoubleToUint32(x_val) >> shift; - x = NewNumberLiteral(value); + x = factory()->NewNumberLiteral(value); continue; } case Token::SAR: { uint32_t shift = DoubleToInt32(y_val) & 0x1f; int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift); - x = NewNumberLiteral(value); + x = factory()->NewNumberLiteral(value); continue; } default: @@ -2843,15 +2780,15 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { case Token::NE_STRICT: cmp = Token::EQ_STRICT; break; default: break; } - x = new(zone()) CompareOperation(isolate(), cmp, x, y, position); + x = factory()->NewCompareOperation(cmp, x, y, position); if (cmp != op) { // The comparison was negated - add a NOT. - x = new(zone()) UnaryOperation(isolate(), Token::NOT, x, position); + x = factory()->NewUnaryOperation(Token::NOT, x, position); } } else { // We have a "normal" binary operation. - x = new(zone()) BinaryOperation(isolate(), op, x, y, position); + x = factory()->NewBinaryOperation(op, x, y, position); } } } @@ -2884,7 +2821,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { // Convert the literal to a boolean condition and negate it. bool condition = literal->ToBoolean()->IsTrue(); Handle result(isolate()->heap()->ToBoolean(!condition)); - return NewLiteral(result); + return factory()->NewLiteral(result); } else if (literal->IsNumber()) { // Compute some expressions involving only number literals. double value = literal->Number(); @@ -2892,9 +2829,9 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { case Token::ADD: return expression; case Token::SUB: - return NewNumberLiteral(-value); + return factory()->NewNumberLiteral(-value); case Token::BIT_NOT: - return NewNumberLiteral(~DoubleToInt32(value)); + return factory()->NewNumberLiteral(~DoubleToInt32(value)); default: break; } @@ -2911,7 +2848,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { } } - return new(zone()) UnaryOperation(isolate(), op, expression, position); + return factory()->NewUnaryOperation(op, expression, position); } else if (Token::IsCountOp(op)) { op = Next(); @@ -2933,11 +2870,10 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { MarkAsLValue(expression); int position = scanner().location().beg_pos; - return new(zone()) CountOperation(isolate(), - op, - true /* prefix */, - expression, - position); + return factory()->NewCountOperation(op, + true /* prefix */, + expression, + position); } else { return ParsePostfixExpression(ok); @@ -2971,11 +2907,10 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { Token::Value next = Next(); int position = scanner().location().beg_pos; expression = - new(zone()) CountOperation(isolate(), - next, - false /* postfix */, - expression, - position); + factory()->NewCountOperation(next, + false /* postfix */, + expression, + position); } return expression; } @@ -2998,7 +2933,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::LBRACK); int pos = scanner().location().beg_pos; Expression* index = ParseExpression(true, CHECK_OK); - result = new(zone()) Property(isolate(), result, index, pos); + result = factory()->NewProperty(result, index, pos); Expect(Token::RBRACK, CHECK_OK); break; } @@ -3031,7 +2966,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { callee->IsVariable(isolate()->factory()->eval_symbol())) { top_scope_->DeclarationScope()->RecordEvalCall(); } - result = NewCall(result, args, pos); + result = factory()->NewCall(result, args, pos); break; } @@ -3039,10 +2974,8 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::PERIOD); int pos = scanner().location().beg_pos; Handle name = ParseIdentifierName(CHECK_OK); - result = new(zone()) Property(isolate(), - result, - NewLiteral(name), - pos); + result = + factory()->NewProperty(result, factory()->NewLiteral(name), pos); if (fni_ != NULL) fni_->PushLiteralName(name); break; } @@ -3078,10 +3011,8 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) { if (!stack->is_empty()) { int last = stack->pop(); - result = new(zone()) CallNew(isolate(), - result, - new(zone()) ZoneList(0), - last); + result = factory()->NewCallNew( + result, new(zone()) ZoneList(0), last); } return result; } @@ -3133,7 +3064,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::LBRACK); int pos = scanner().location().beg_pos; Expression* index = ParseExpression(true, CHECK_OK); - result = new(zone()) Property(isolate(), result, index, pos); + result = factory()->NewProperty(result, index, pos); if (fni_ != NULL) { if (index->IsPropertyName()) { fni_->PushLiteralName(index->AsLiteral()->AsPropertyName()); @@ -3149,10 +3080,8 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::PERIOD); int pos = scanner().location().beg_pos; Handle name = ParseIdentifierName(CHECK_OK); - result = new(zone()) Property(isolate(), - result, - NewLiteral(name), - pos); + result = + factory()->NewProperty(result, factory()->NewLiteral(name), pos); if (fni_ != NULL) fni_->PushLiteralName(name); break; } @@ -3161,7 +3090,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, // Consume one of the new prefixes (already parsed). ZoneList* args = ParseArguments(CHECK_OK); int last = stack->pop(); - result = new(zone()) CallNew(isolate(), result, args, last); + result = factory()->NewCallNew(result, args, last); break; } default: @@ -3180,7 +3109,7 @@ DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { Expect(Token::DEBUGGER, CHECK_OK); ExpectSemicolon(CHECK_OK); - return new(zone()) DebuggerStatement(); + return factory()->NewDebuggerStatement(); } @@ -3245,33 +3174,31 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { switch (peek()) { case Token::THIS: { Consume(Token::THIS); - result = new(zone()) VariableProxy(isolate(), top_scope_->receiver()); + result = factory()->NewVariableProxy(top_scope_->receiver()); break; } case Token::NULL_LITERAL: Consume(Token::NULL_LITERAL); - result = new(zone()) Literal( - isolate(), isolate()->factory()->null_value()); + result = factory()->NewLiteral(isolate()->factory()->null_value()); break; case Token::TRUE_LITERAL: Consume(Token::TRUE_LITERAL); - result = new(zone()) Literal( - isolate(), isolate()->factory()->true_value()); + result = factory()->NewLiteral(isolate()->factory()->true_value()); break; case Token::FALSE_LITERAL: Consume(Token::FALSE_LITERAL); - result = new(zone()) Literal( - isolate(), isolate()->factory()->false_value()); + result = factory()->NewLiteral(isolate()->factory()->false_value()); break; case Token::IDENTIFIER: case Token::FUTURE_STRICT_RESERVED_WORD: { Handle name = ParseIdentifier(CHECK_OK); if (fni_ != NULL) fni_->PushVariableName(name); - result = top_scope_->NewUnresolved(name, scanner().location().beg_pos); + result = top_scope_->NewUnresolved( + factory(), name, scanner().location().beg_pos); break; } @@ -3281,14 +3208,14 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { double value = StringToDouble(isolate()->unicode_cache(), scanner().literal_ascii_string(), ALLOW_HEX | ALLOW_OCTALS); - result = NewNumberLiteral(value); + result = factory()->NewNumberLiteral(value); break; } case Token::STRING: { Consume(Token::STRING); Handle symbol = GetSymbol(CHECK_OK); - result = NewLiteral(symbol); + result = factory()->NewLiteral(symbol); if (fni_ != NULL) fni_->PushLiteralName(symbol); break; } @@ -3482,8 +3409,8 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { literals->set(0, Smi::FromInt(elements_kind)); literals->set(1, *element_values); - return new(zone()) ArrayLiteral( - isolate(), literals, values, literal_index, is_simple, depth); + return factory()->NewArrayLiteral( + literals, values, literal_index, is_simple, depth); } @@ -3760,9 +3687,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter, CHECK_OK); // Allow any number of parameters for compatibilty with JSC. // Specification only allows zero parameters for get and one for set. - ObjectLiteral::Property* property = - new(zone()) ObjectLiteral::Property(is_getter, value); - return property; + return factory()->NewObjectLiteralProperty(is_getter, value); } else { ReportUnexpectedToken(next); *ok = false; @@ -3827,7 +3752,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { } // Failed to parse as get/set property, so it's just a property // called "get" or "set". - key = NewLiteral(id); + key = factory()->NewLiteral(id); break; } case Token::STRING: { @@ -3836,10 +3761,10 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { if (fni_ != NULL) fni_->PushLiteralName(string); uint32_t index; if (!string.is_null() && string->AsArrayIndex(&index)) { - key = NewNumberLiteral(index); + key = factory()->NewNumberLiteral(index); break; } - key = NewLiteral(string); + key = factory()->NewLiteral(string); break; } case Token::NUMBER: { @@ -3848,14 +3773,14 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { double value = StringToDouble(isolate()->unicode_cache(), scanner().literal_ascii_string(), ALLOW_HEX | ALLOW_OCTALS); - key = NewNumberLiteral(value); + key = factory()->NewNumberLiteral(value); break; } default: if (Token::IsKeyword(next)) { Consume(next); Handle string = GetSymbol(CHECK_OK); - key = NewLiteral(string); + key = factory()->NewLiteral(string); } else { // Unexpected token. Token::Value next = Next(); @@ -3910,14 +3835,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { &is_simple, &fast_elements, &depth); - return new(zone()) ObjectLiteral(isolate(), - constant_properties, - properties, - literal_index, - is_simple, - fast_elements, - depth, - has_function); + return factory()->NewObjectLiteral(constant_properties, + properties, + literal_index, + is_simple, + fast_elements, + depth, + has_function); } @@ -3936,8 +3860,7 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { Handle js_flags = NextLiteralString(TENURED); Next(); - return new(zone()) RegExpLiteral( - isolate(), js_pattern, js_flags, literal_index); + return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index); } @@ -3968,7 +3891,7 @@ ZoneList* Parser::ParseArguments(bool* ok) { class SingletonLogger : public ParserRecorder { public: SingletonLogger() : has_error_(false), start_(-1), end_(-1) { } - ~SingletonLogger() { } + virtual ~SingletonLogger() { } void Reset() { has_error_ = false; } @@ -4089,6 +4012,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, bool only_simple_this_property_assignments; Handle this_property_assignments; bool has_duplicate_parameters = false; + AstProperties ast_properties; // Parse function body. { FunctionState function_state(this, scope, isolate()); top_scope_->SetScopeName(function_name); @@ -4151,7 +4075,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, } else { fvar_mode = CONST; } - fvar = top_scope_->DeclareFunctionVar(function_name, fvar_mode); + fvar = + top_scope_->DeclareFunctionVar(function_name, fvar_mode, factory()); } // Determine whether the function will be lazily compiled. @@ -4238,14 +4163,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, if (!is_lazily_compiled) { body = new(zone()) ZoneList(8); if (fvar != NULL) { - VariableProxy* fproxy = top_scope_->NewUnresolved(function_name); + VariableProxy* fproxy = + top_scope_->NewUnresolved(factory(), function_name); fproxy->BindTo(fvar); - body->Add(new(zone()) ExpressionStatement( - new(zone()) Assignment(isolate(), - fvar_init_op, - fproxy, - new(zone()) ThisFunction(isolate()), - RelocInfo::kNoPosition))); + body->Add(factory()->NewExpressionStatement( + factory()->NewAssignment(fvar_init_op, + fproxy, + factory()->NewThisFunction(), + RelocInfo::kNoPosition))); } ParseSourceElements(body, Token::RBRACE, CHECK_OK); @@ -4306,6 +4231,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, scope->end_position(), CHECK_OK); } + ast_properties = *factory()->visitor()->ast_properties(); } if (is_extended_mode()) { @@ -4313,19 +4239,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, } FunctionLiteral* function_literal = - new(zone()) FunctionLiteral(isolate(), - function_name, - scope, - body, - materialized_literal_count, - expected_property_count, - handler_count, - only_simple_this_property_assignments, - this_property_assignments, - num_parameters, - type, - has_duplicate_parameters); + factory()->NewFunctionLiteral(function_name, + scope, + body, + materialized_literal_count, + expected_property_count, + handler_count, + only_simple_this_property_assignments, + this_property_assignments, + num_parameters, + has_duplicate_parameters, + type, + true); function_literal->set_function_token_position(function_token_position); + function_literal->set_ast_properties(&ast_properties); if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); return function_literal; @@ -4395,7 +4322,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { } // We have a valid intrinsics call or a call to a builtin. - return new(zone()) CallRuntime(isolate(), name, function, args); + return factory()->NewCallRuntime(name, function, args); } @@ -4451,17 +4378,12 @@ void Parser::ExpectSemicolon(bool* ok) { Literal* Parser::GetLiteralUndefined() { - return NewLiteral(isolate()->factory()->undefined_value()); + return factory()->NewLiteral(isolate()->factory()->undefined_value()); } Literal* Parser::GetLiteralTheHole() { - return NewLiteral(isolate()->factory()->the_hole_value()); -} - - -Literal* Parser::GetLiteralNumber(double value) { - return NewNumberLiteral(value); + return factory()->NewLiteral(isolate()->factory()->the_hole_value()); } @@ -4639,11 +4561,6 @@ void Parser::RegisterTargetUse(Label* target, Target* stop) { } -Literal* Parser::NewNumberLiteral(double number) { - return NewLiteral(isolate()->factory()->NewNumber(number, TENURED)); -} - - Expression* Parser::NewThrowReferenceError(Handle type) { return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(), type, HandleVector(NULL, 0)); @@ -4687,15 +4604,11 @@ Expression* Parser::NewThrowError(Handle constructor, elements, FAST_ELEMENTS, TENURED); ZoneList* args = new(zone()) ZoneList(2); - args->Add(NewLiteral(type)); - args->Add(NewLiteral(array)); - CallRuntime* call_constructor = new(zone()) CallRuntime(isolate(), - constructor, - NULL, - args); - return new(zone()) Throw(isolate(), - call_constructor, - scanner().location().beg_pos); + args->Add(factory()->NewLiteral(type)); + args->Add(factory()->NewLiteral(array)); + CallRuntime* call_constructor = + factory()->NewCallRuntime(constructor, NULL, args); + return factory()->NewThrow(call_constructor, scanner().location().beg_pos); } // ---------------------------------------------------------------------------- @@ -5667,7 +5580,7 @@ bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) { parsing_flags |= EXTENDED_MODE; } if (FLAG_allow_natives_syntax || info->is_native()) { - // We requre %identifier(..) syntax. + // We require %identifier(..) syntax. parsing_flags |= kAllowNativesSyntax; } if (info->is_lazy()) { diff --git a/src/parser.h b/src/parser.h index 16c2eff6d3..bc2af61d41 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -435,9 +435,8 @@ class Parser { v8::Extension* extension, ScriptDataImpl* pre_data); virtual ~Parser() { - if (reusable_preparser_ != NULL) { - delete reusable_preparser_; - } + delete reusable_preparser_; + reusable_preparser_ = NULL; } // Returns NULL if parsing failed. @@ -477,7 +476,69 @@ class Parser { }; class BlockState; - class FunctionState; + + class FunctionState BASE_EMBEDDED { + public: + FunctionState(Parser* parser, + Scope* scope, + Isolate* isolate); + ~FunctionState(); + + int NextMaterializedLiteralIndex() { + return next_materialized_literal_index_++; + } + int materialized_literal_count() { + return next_materialized_literal_index_ - JSFunction::kLiteralsPrefixSize; + } + + int NextHandlerIndex() { return next_handler_index_++; } + int handler_count() { return next_handler_index_; } + + void SetThisPropertyAssignmentInfo( + bool only_simple_this_property_assignments, + Handle this_property_assignments) { + only_simple_this_property_assignments_ = + only_simple_this_property_assignments; + this_property_assignments_ = this_property_assignments; + } + bool only_simple_this_property_assignments() { + return only_simple_this_property_assignments_; + } + Handle this_property_assignments() { + return this_property_assignments_; + } + + void AddProperty() { expected_property_count_++; } + int expected_property_count() { return expected_property_count_; } + + AstNodeFactory* factory() { return &factory_; } + + private: + // Used to assign an index to each literal that needs materialization in + // the function. Includes regexp literals, and boilerplate for object and + // array literals. + int next_materialized_literal_index_; + + // Used to assign a per-function index to try and catch handlers. + int next_handler_index_; + + // Properties count estimation. + int expected_property_count_; + + // Keeps track of assignments to properties of this. Used for + // optimizing constructors. + bool only_simple_this_property_assignments_; + Handle this_property_assignments_; + + Parser* parser_; + FunctionState* outer_function_state_; + Scope* outer_scope_; + int saved_ast_node_id_; + AstNodeFactory factory_; + }; + + + FunctionLiteral* ParseLazy(CompilationInfo* info, UC16CharacterStream* source, @@ -651,7 +712,6 @@ class Parser { // Get odd-ball literals. Literal* GetLiteralUndefined(); Literal* GetLiteralTheHole(); - Literal* GetLiteralNumber(double value); Handle ParseIdentifier(bool* ok); Handle ParseIdentifierOrStrictReservedWord( @@ -699,31 +759,12 @@ class Parser { // Factory methods. - Statement* EmptyStatement() { - static v8::internal::EmptyStatement* empty = - ::new v8::internal::EmptyStatement(); - return empty; - } - Scope* NewScope(Scope* parent, ScopeType type); Handle LookupSymbol(int symbol_id); Handle LookupCachedSymbol(int symbol_id); - Expression* NewCall(Expression* expression, - ZoneList* arguments, - int pos) { - return new(zone()) Call(isolate(), expression, arguments, pos); - } - - inline Literal* NewLiteral(Handle handle) { - return new(zone()) Literal(isolate(), handle); - } - - // Create a number literal. - Literal* NewNumberLiteral(double value); - // Generate AST node that throw a ReferenceError with the given type. Expression* NewThrowReferenceError(Handle type); @@ -746,6 +787,10 @@ class Parser { preparser::PreParser::PreParseResult LazyParseFunctionLiteral( SingletonLogger* logger); + AstNodeFactory* factory() { + return current_function_state_->factory(); + } + Isolate* isolate_; ZoneList > symbol_cache_; diff --git a/src/rewriter.cc b/src/rewriter.cc index a70cd82a72..8e0c6376ae 100644 --- a/src/rewriter.cc +++ b/src/rewriter.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -42,12 +42,18 @@ class Processor: public AstVisitor { : result_(result), result_assigned_(false), is_set_(false), - in_try_(false) { - } + in_try_(false), + factory_(isolate()) { } + + virtual ~Processor() { } void Process(ZoneList* statements); bool result_assigned() const { return result_assigned_; } + AstNodeFactory* factory() { + return &factory_; + } + private: Variable* result_; @@ -64,15 +70,13 @@ class Processor: public AstVisitor { bool is_set_; bool in_try_; + AstNodeFactory factory_; + Expression* SetResult(Expression* value) { result_assigned_ = true; - Zone* zone = isolate()->zone(); - VariableProxy* result_proxy = new(zone) VariableProxy(isolate(), result_); - return new(zone) Assignment(isolate(), - Token::ASSIGN, - result_proxy, - value, - RelocInfo::kNoPosition); + VariableProxy* result_proxy = factory()->NewVariableProxy(result_); + return factory()->NewAssignment( + Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition); } // Node visitors. @@ -237,8 +241,6 @@ bool Rewriter::Rewrite(CompilationInfo* info) { if (processor.result_assigned()) { ASSERT(function->end_position() != RelocInfo::kNoPosition); - Isolate* isolate = info->isolate(); - Zone* zone = isolate->zone(); // Set the position of the assignment statement one character past the // source code, such that it definitely is not in the source code range // of an immediate inner scope. For example in @@ -246,10 +248,11 @@ bool Rewriter::Rewrite(CompilationInfo* info) { // the end position of the function generated for executing the eval code // coincides with the end of the with scope which is the position of '1'. int position = function->end_position(); - VariableProxy* result_proxy = new(zone) VariableProxy( - isolate, result->name(), false, position); + VariableProxy* result_proxy = processor.factory()->NewVariableProxy( + result->name(), false, position); result_proxy->BindTo(result); - Statement* result_statement = new(zone) ReturnStatement(result_proxy); + Statement* result_statement = + processor.factory()->NewReturnStatement(result_proxy); result_statement->set_statement_pos(position); body->Add(result_statement); } diff --git a/src/scopes.cc b/src/scopes.cc index a7ff28789f..35d804dff6 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -272,8 +272,11 @@ bool Scope::Analyze(CompilationInfo* info) { top = top->outer_scope(); } - // Allocated the variables. - top->AllocateVariables(info->global_scope()); + // Allocate the variables. + { + AstNodeFactory ast_node_factory(info->isolate()); + top->AllocateVariables(info->global_scope(), &ast_node_factory); + } #ifdef DEBUG if (info->isolate()->bootstrapper()->IsActive() @@ -415,7 +418,8 @@ Variable* Scope::LocalLookup(Handle name) { } -Variable* Scope::LookupFunctionVar(Handle name) { +Variable* Scope::LookupFunctionVar(Handle name, + AstNodeFactory* factory) { if (function_ != NULL && function_->name().is_identical_to(name)) { return function_->var(); } else if (!scope_info_.is_null()) { @@ -423,7 +427,7 @@ Variable* Scope::LookupFunctionVar(Handle name) { VariableMode mode; int index = scope_info_->FunctionContextSlotIndex(*name, &mode); if (index < 0) return NULL; - Variable* var = DeclareFunctionVar(name, mode); + Variable* var = DeclareFunctionVar(name, mode, factory); var->AllocateTo(Variable::CONTEXT, index); return var; } else { @@ -443,15 +447,6 @@ Variable* Scope::Lookup(Handle name) { } -Variable* Scope::DeclareFunctionVar(Handle name, VariableMode mode) { - ASSERT(is_function_scope() && function_ == NULL); - Variable* function_var = new Variable( - this, name, mode, true, Variable::NORMAL, kCreatedInitialized); - function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var); - return function_var; -} - - void Scope::DeclareParameter(Handle name, VariableMode mode) { ASSERT(!already_resolved()); ASSERT(is_function_scope()); @@ -489,18 +484,6 @@ Variable* Scope::DeclareGlobal(Handle name) { } -VariableProxy* Scope::NewUnresolved(Handle name, int position) { - // Note that we must not share the unresolved variables with - // the same name because they may be removed selectively via - // RemoveUnresolved(). - ASSERT(!already_resolved()); - VariableProxy* proxy = new(isolate_->zone()) VariableProxy( - isolate_, name, false, position); - unresolved_.Add(proxy); - return proxy; -} - - void Scope::RemoveUnresolved(VariableProxy* var) { // Most likely (always?) any variable we want to remove // was just added before, so we search backwards. @@ -623,7 +606,8 @@ void Scope::CollectStackAndContextLocals(ZoneList* stack_locals, } -void Scope::AllocateVariables(Scope* global_scope) { +void Scope::AllocateVariables(Scope* global_scope, + AstNodeFactory* factory) { // 1) Propagate scope information. bool outer_scope_calls_non_strict_eval = false; if (outer_scope_ != NULL) { @@ -634,7 +618,7 @@ void Scope::AllocateVariables(Scope* global_scope) { PropagateScopeInfo(outer_scope_calls_non_strict_eval); // 2) Resolve variables. - ResolveVariablesRecursively(global_scope); + ResolveVariablesRecursively(global_scope, factory); // 3) Allocate variables. AllocateVariablesRecursively(); @@ -897,7 +881,8 @@ Variable* Scope::NonLocal(Handle name, VariableMode mode) { Variable* Scope::LookupRecursive(Handle name, - BindingKind* binding_kind) { + BindingKind* binding_kind, + AstNodeFactory* factory) { ASSERT(binding_kind != NULL); // Try to find the variable in this scope. Variable* var = LocalLookup(name); @@ -914,11 +899,11 @@ Variable* Scope::LookupRecursive(Handle name, // if any. We can do this for all scopes, since the function variable is // only present - if at all - for function scopes. *binding_kind = UNBOUND; - var = LookupFunctionVar(name); + var = LookupFunctionVar(name, factory); if (var != NULL) { *binding_kind = BOUND; } else if (outer_scope_ != NULL) { - var = outer_scope_->LookupRecursive(name, binding_kind); + var = outer_scope_->LookupRecursive(name, binding_kind, factory); if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { var->ForceContextAllocation(); } @@ -951,7 +936,8 @@ Variable* Scope::LookupRecursive(Handle name, void Scope::ResolveVariable(Scope* global_scope, - VariableProxy* proxy) { + VariableProxy* proxy, + AstNodeFactory* factory) { ASSERT(global_scope == NULL || global_scope->is_global_scope()); // If the proxy is already resolved there's nothing to do @@ -960,7 +946,7 @@ void Scope::ResolveVariable(Scope* global_scope, // Otherwise, try to resolve the variable. BindingKind binding_kind; - Variable* var = LookupRecursive(proxy->name(), &binding_kind); + Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory); switch (binding_kind) { case BOUND: // We found a variable binding. @@ -1001,17 +987,19 @@ void Scope::ResolveVariable(Scope* global_scope, } -void Scope::ResolveVariablesRecursively(Scope* global_scope) { +void Scope::ResolveVariablesRecursively( + Scope* global_scope, + AstNodeFactory* factory) { ASSERT(global_scope == NULL || global_scope->is_global_scope()); // Resolve unresolved variables for this scope. for (int i = 0; i < unresolved_.length(); i++) { - ResolveVariable(global_scope, unresolved_[i]); + ResolveVariable(global_scope, unresolved_[i], factory); } // Resolve unresolved variables for inner scopes. for (int i = 0; i < inner_scopes_.length(); i++) { - inner_scopes_[i]->ResolveVariablesRecursively(global_scope); + inner_scopes_[i]->ResolveVariablesRecursively(global_scope, factory); } } diff --git a/src/scopes.h b/src/scopes.h index af0449e93c..06202c493b 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -115,7 +115,8 @@ class Scope: public ZoneObject { // between this scope and the outer scope. (ECMA-262, 3rd., requires that // the name of named function literal is kept in an intermediate scope // in between this scope and the next outer scope.) - Variable* LookupFunctionVar(Handle name); + Variable* LookupFunctionVar(Handle name, + AstNodeFactory* factory); // Lookup a variable in this scope or outer scopes. // Returns the variable or NULL if not found. @@ -124,7 +125,16 @@ class Scope: public ZoneObject { // Declare the function variable for a function literal. This variable // is in an intermediate scope between this function scope and the the // outer scope. Only possible for function scopes; at most one variable. - Variable* DeclareFunctionVar(Handle name, VariableMode mode); + template + Variable* DeclareFunctionVar(Handle name, + VariableMode mode, + AstNodeFactory* factory) { + ASSERT(is_function_scope() && function_ == NULL); + Variable* function_var = new Variable( + this, name, mode, true, Variable::NORMAL, kCreatedInitialized); + function_ = factory->NewVariableProxy(function_var); + return function_var; + } // Declare a parameter in this scope. When there are duplicated // parameters the rightmost one 'wins'. However, the implementation @@ -144,8 +154,18 @@ class Scope: public ZoneObject { Variable* DeclareGlobal(Handle name); // Create a new unresolved variable. - VariableProxy* NewUnresolved(Handle name, - int position = RelocInfo::kNoPosition); + template + VariableProxy* NewUnresolved(AstNodeFactory* factory, + Handle name, + int position = RelocInfo::kNoPosition) { + // Note that we must not share the unresolved variables with + // the same name because they may be removed selectively via + // RemoveUnresolved(). + ASSERT(!already_resolved()); + VariableProxy* proxy = factory->NewVariableProxy(name, false, position); + unresolved_.Add(proxy); + return proxy; + } // Remove a unresolved variable. During parsing, an unresolved variable // may have been added optimistically, but then only the variable name @@ -332,7 +352,8 @@ class Scope: public ZoneObject { // In the case of code compiled and run using 'eval', the context // parameter is the context in which eval was called. In all other // cases the context parameter is an empty handle. - void AllocateVariables(Scope* global_scope); + void AllocateVariables(Scope* global_scope, + AstNodeFactory* factory); // Current number of var or const locals. int num_var_or_const() { return num_var_or_const_; } @@ -519,10 +540,13 @@ class Scope: public ZoneObject { // scope. If the code is executed because of a call to 'eval', the context // parameter should be set to the calling context of 'eval'. Variable* LookupRecursive(Handle name, - BindingKind* binding_kind); + BindingKind* binding_kind, + AstNodeFactory* factory); void ResolveVariable(Scope* global_scope, - VariableProxy* proxy); - void ResolveVariablesRecursively(Scope* global_scope); + VariableProxy* proxy, + AstNodeFactory* factory); + void ResolveVariablesRecursively(Scope* global_scope, + AstNodeFactory* factory); // Scope analysis. bool PropagateScopeInfo(bool outer_scope_calls_non_strict_eval); diff --git a/test/cctest/test-ast.cc b/test/cctest/test-ast.cc index 2aa72078af..80c7fdff78 100644 --- a/test/cctest/test-ast.cc +++ b/test/cctest/test-ast.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -40,7 +40,8 @@ TEST(List) { CHECK_EQ(0, list->length()); ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT); - AstNode* node = new(ZONE) EmptyStatement(); + AstNodeFactory factory(Isolate::Current()); + AstNode* node = factory.NewEmptyStatement(); list->Add(node); CHECK_EQ(1, list->length()); CHECK_EQ(node, list->at(0));