diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 39668c6981..2adddef111 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -286,11 +286,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - int ignored = 0; VariableProxy* proxy = scope()->function(); ASSERT(proxy->var()->mode() == CONST || proxy->var()->mode() == CONST_HARMONY); - EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); + ASSERT(proxy->var()->location() != Variable::UNALLOCATED); + EmitDeclaration(proxy, proxy->var()->mode(), NULL); } VisitDeclarations(scope()->declarations()); } @@ -727,8 +727,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, VariableMode mode, - FunctionLiteral* function, - int* global_count) { + FunctionLiteral* function) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. @@ -737,7 +736,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: - ++(*global_count); + ++global_count_; break; case Variable::PARAMETER: @@ -822,9 +821,6 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } -void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } - - void FullCodeGenerator::DeclareGlobals(Handle pairs) { // Call the runtime to declare the globals. // The context is the first argument. diff --git a/src/ast.cc b/src/ast.cc index 236d8708f3..cb1aca5db7 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -414,7 +414,11 @@ bool CompareOperation::IsLiteralCompareNull(Expression** expr) { // Inlining support bool Declaration::IsInlineable() const { - return proxy()->var()->IsStackAllocated() && fun() == NULL; + return proxy()->var()->IsStackAllocated(); +} + +bool VariableDeclaration::IsInlineable() const { + return Declaration::IsInlineable() && fun() == NULL; } @@ -990,7 +994,7 @@ CaseClause::CaseClause(Isolate* isolate, increase_node_count(); \ } -INCREASE_NODE_COUNT(Declaration) +INCREASE_NODE_COUNT(VariableDeclaration) INCREASE_NODE_COUNT(Block) INCREASE_NODE_COUNT(ExpressionStatement) INCREASE_NODE_COUNT(EmptyStatement) diff --git a/src/ast.h b/src/ast.h index 45e9123141..d2dd5e661d 100644 --- a/src/ast.h +++ b/src/ast.h @@ -59,6 +59,9 @@ namespace internal { // Nodes of the abstract syntax tree. Only concrete classes are // enumerated here. +#define DECLARATION_NODE_LIST(V) \ + V(VariableDeclaration) \ + #define STATEMENT_NODE_LIST(V) \ V(Block) \ V(ExpressionStatement) \ @@ -99,7 +102,7 @@ namespace internal { V(ThisFunction) #define AST_NODE_LIST(V) \ - V(Declaration) \ + DECLARATION_NODE_LIST(V) \ STATEMENT_NODE_LIST(V) \ EXPRESSION_NODE_LIST(V) @@ -107,6 +110,7 @@ namespace internal { class AstConstructionVisitor; template class AstNodeFactory; class AstVisitor; +class Declaration; class BreakableStatement; class Expression; class IterationStatement; @@ -202,6 +206,7 @@ class AstNode: public ZoneObject { AST_NODE_LIST(DECLARE_NODE_FUNCTIONS) #undef DECLARE_NODE_FUNCTIONS + virtual Declaration* AsDeclaration() { return NULL; } virtual Statement* AsStatement() { return NULL; } virtual Expression* AsExpression() { return NULL; } virtual TargetCollector* AsTargetCollector() { return NULL; } @@ -433,43 +438,63 @@ 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_; } + virtual bool IsInlineable() const; + + virtual Declaration* AsDeclaration() { return this; } + virtual VariableDeclaration* AsVariableDeclaration() { return NULL; } protected: - template friend class AstNodeFactory; - Declaration(VariableProxy* proxy, VariableMode mode, - FunctionLiteral* fun, Scope* scope) : proxy_(proxy), mode_(mode), - fun_(fun), scope_(scope) { ASSERT(mode == VAR || mode == CONST || mode == CONST_HARMONY || mode == LET); - // At the moment there are no "const functions"'s in JavaScript... - ASSERT(fun == NULL || mode == VAR || mode == LET); } private: VariableProxy* proxy_; VariableMode mode_; - FunctionLiteral* fun_; // Nested scope from which the declaration originated. Scope* scope_; }; +class VariableDeclaration: public Declaration { + public: + DECLARE_NODE_TYPE(VariableDeclaration) + + virtual VariableDeclaration* AsVariableDeclaration() { return this; } + + FunctionLiteral* fun() const { return fun_; } // may be NULL + virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + VariableDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* fun, + Scope* scope) + : Declaration(proxy, mode, scope), + fun_(fun) { + // At the moment there are no "const functions"'s in JavaScript... + ASSERT(fun == NULL || mode == VAR || mode == LET); + } + + private: + FunctionLiteral* fun_; +}; + + class IterationStatement: public BreakableStatement { public: // Type testing & conversion. @@ -2366,6 +2391,15 @@ class AstNodeFactory BASE_EMBEDDED { visitor_.Visit##NodeType((node)); \ return node; + VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* fun, + Scope* scope) { + VariableDeclaration* decl = + new(zone_) VariableDeclaration(proxy, mode, fun, scope); + VISIT_AND_RETURN(VariableDeclaration, decl) + } + Block* NewBlock(ZoneStringList* labels, int capacity, bool is_initializer_block) { @@ -2374,14 +2408,6 @@ class AstNodeFactory BASE_EMBEDDED { 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); \ diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 95ad2010af..02776aa828 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -51,7 +51,8 @@ void BreakableStatementChecker::Check(Expression* expr) { } -void BreakableStatementChecker::VisitDeclaration(Declaration* decl) { +void BreakableStatementChecker::VisitVariableDeclaration( + VariableDeclaration* decl) { } @@ -526,41 +527,47 @@ void FullCodeGenerator::DoTest(const TestContext* context) { } +void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { + EmitDeclaration(decl->proxy(), decl->mode(), decl->fun()); +} + + void FullCodeGenerator::VisitDeclarations( ZoneList* declarations) { - int length = declarations->length(); - int global_count = 0; - for (int i = 0; i < length; i++) { - Declaration* decl = declarations->at(i); - EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count); - } + int save_global_count = global_count_; + global_count_ = 0; + + AstVisitor::VisitDeclarations(declarations); // Batch declare global functions and variables. - if (global_count > 0) { + if (global_count_ > 0) { Handle array = - isolate()->factory()->NewFixedArray(2 * global_count, TENURED); + isolate()->factory()->NewFixedArray(2 * global_count_, TENURED); + int length = declarations->length(); for (int j = 0, i = 0; i < length; i++) { - Declaration* decl = declarations->at(i); - Variable* var = decl->proxy()->var(); + VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration(); + if (decl != NULL) { + Variable* var = decl->proxy()->var(); - if (var->IsUnallocated()) { - array->set(j++, *(var->name())); - if (decl->fun() == NULL) { - if (var->binding_needs_init()) { - // In case this binding needs initialization use the hole. - array->set_the_hole(j++); + if (var->IsUnallocated()) { + array->set(j++, *(var->name())); + if (decl->fun() == NULL) { + if (var->binding_needs_init()) { + // In case this binding needs initialization use the hole. + array->set_the_hole(j++); + } else { + array->set_undefined(j++); + } } else { - array->set_undefined(j++); + Handle function = + Compiler::BuildFunctionInfo(decl->fun(), script()); + // Check for stack-overflow exception. + if (function.is_null()) { + SetStackOverflow(); + return; + } + array->set(j++, *function); } - } else { - Handle function = - Compiler::BuildFunctionInfo(decl->fun(), script()); - // Check for stack-overflow exception. - if (function.is_null()) { - SetStackOverflow(); - return; - } - array->set(j++, *function); } } } @@ -568,6 +575,8 @@ void FullCodeGenerator::VisitDeclarations( // declaration the global functions and variables. DeclareGlobals(array); } + + global_count_ = save_global_count; } diff --git a/src/full-codegen.h b/src/full-codegen.h index 02f18d33a4..f9b7c3842a 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -83,6 +83,7 @@ class FullCodeGenerator: public AstVisitor { scope_(NULL), nesting_stack_(NULL), loop_depth_(0), + global_count_(0), context_(NULL), bailout_entries_(0), stack_checks_(2), // There's always at least one. @@ -416,10 +417,10 @@ class FullCodeGenerator: public AstVisitor { // Platform-specific code for a variable, constant, or function // declaration. Functions have an initial value. + // Increments global_count_ for unallocated variables. void EmitDeclaration(VariableProxy* proxy, VariableMode mode, - FunctionLiteral* function, - int* global_count); + FunctionLiteral* function); // Platform-specific code for checking the stack limit at the back edge of // a loop. @@ -767,6 +768,7 @@ class FullCodeGenerator: public AstVisitor { Label return_label_; NestedStatement* nesting_stack_; int loop_depth_; + int global_count_; const ExpressionContext* context_; ZoneList bailout_entries_; ZoneList stack_checks_; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 7ec1f5bf95..8b5baffcb3 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -2443,7 +2443,7 @@ HGraph* HGraphBuilder::CreateGraph() { // Handle implicit declaration of the function name in named function // expressions before other declarations. if (scope->is_function_scope() && scope->function() != NULL) { - HandleDeclaration(scope->function(), CONST, NULL); + HandleVariableDeclaration(scope->function(), CONST, NULL); } VisitDeclarations(scope->declarations()); AddSimulate(AstNode::kDeclarationsId); @@ -6540,14 +6540,14 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { } -void HGraphBuilder::VisitDeclaration(Declaration* decl) { - HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); +void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { + HandleVariableDeclaration(decl->proxy(), decl->mode(), decl->fun()); } -void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function) { +void HGraphBuilder::HandleVariableDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* function) { Variable* var = proxy->var(); bool binding_needs_init = (mode == CONST || mode == CONST_HARMONY || mode == LET); diff --git a/src/hydrogen.h b/src/hydrogen.h index 47b569146b..bbd4841f7a 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -839,9 +839,9 @@ class HGraphBuilder: public AstVisitor { INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) #undef INLINE_FUNCTION_GENERATOR_DECLARATION - void HandleDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function); + void HandleVariableDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* function); void VisitDelete(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 27b42ba875..7bb4cffad0 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -281,11 +281,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - int ignored = 0; VariableProxy* proxy = scope()->function(); ASSERT(proxy->var()->mode() == CONST || proxy->var()->mode() == CONST_HARMONY); - EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); + ASSERT(proxy->var()->location() != Variable::UNALLOCATED); + EmitDeclaration(proxy, proxy->var()->mode(), NULL); } VisitDeclarations(scope()->declarations()); } @@ -701,8 +701,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, VariableMode mode, - FunctionLiteral* function, - int* global_count) { + FunctionLiteral* function) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. @@ -711,7 +710,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: - ++(*global_count); + ++global_count_; break; case Variable::PARAMETER: @@ -791,9 +790,6 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } -void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } - - void FullCodeGenerator::DeclareGlobals(Handle pairs) { // Call the runtime to declare the globals. __ push(esi); // The context is the first argument. diff --git a/src/parser.cc b/src/parser.cc index d3eb069516..c02cad93e1 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1406,7 +1406,7 @@ VariableProxy* Parser::Declare(Handle name, VariableProxy* proxy = declaration_scope->NewUnresolved( factory(), name, scanner().location().beg_pos); declaration_scope->AddDeclaration( - factory()->NewDeclaration(proxy, mode, fun, top_scope_)); + factory()->NewVariableDeclaration(proxy, mode, fun, top_scope_)); if ((mode == CONST || mode == CONST_HARMONY) && declaration_scope->is_global_scope()) { @@ -1627,8 +1627,8 @@ bool Parser::IsEvalOrArguments(Handle string) { // If the variable declaration declares exactly one non-const -// variable, then *var is set to that variable. In all other cases, -// *var is untouched; in particular, it is the caller's responsibility +// variable, then *out is set to that variable. In all other cases, +// *out is untouched; in particular, it is the caller's responsibility // to initialize it properly. This mechanism is used for the parsing // of 'for-in' loops. Block* Parser::ParseVariableDeclarations( diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc index 9969b07f1f..d940704973 100644 --- a/src/prettyprinter.cc +++ b/src/prettyprinter.cc @@ -58,7 +58,7 @@ void PrettyPrinter::VisitBlock(Block* node) { } -void PrettyPrinter::VisitDeclaration(Declaration* node) { +void PrettyPrinter::VisitVariableDeclaration(VariableDeclaration* node) { Print("var "); PrintLiteral(node->proxy()->name(), false); if (node->fun() != NULL) { @@ -711,7 +711,7 @@ void AstPrinter::VisitBlock(Block* node) { } -void AstPrinter::VisitDeclaration(Declaration* node) { +void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { if (node->fun() == NULL) { // var or const declarations PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), diff --git a/src/rewriter.cc b/src/rewriter.cc index 8e0c6376ae..b08fed34e1 100644 --- a/src/rewriter.cc +++ b/src/rewriter.cc @@ -209,7 +209,7 @@ void Processor::VisitWithStatement(WithStatement* node) { // Do nothing: -void Processor::VisitDeclaration(Declaration* node) {} +void Processor::VisitVariableDeclaration(VariableDeclaration* node) {} void Processor::VisitEmptyStatement(EmptyStatement* node) {} void Processor::VisitReturnStatement(ReturnStatement* node) {} void Processor::VisitDebuggerStatement(DebuggerStatement* node) {} diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index def8aa15f5..292c7b4698 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -277,11 +277,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - int ignored = 0; VariableProxy* proxy = scope()->function(); ASSERT(proxy->var()->mode() == CONST || proxy->var()->mode() == CONST_HARMONY); - EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); + ASSERT(proxy->var()->location() != Variable::UNALLOCATED); + EmitDeclaration(proxy, proxy->var()->mode(), NULL); } VisitDeclarations(scope()->declarations()); } @@ -699,8 +699,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, VariableMode mode, - FunctionLiteral* function, - int* global_count) { + FunctionLiteral* function) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. @@ -709,7 +708,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: - ++(*global_count); + ++global_count_; break; case Variable::PARAMETER: @@ -790,9 +789,6 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } -void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } - - void FullCodeGenerator::DeclareGlobals(Handle pairs) { // Call the runtime to declare the globals. __ push(rsi); // The context is the first argument.