diff --git a/src/ast.cc b/src/ast.cc index 61923bb1ad..9425d6a248 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -417,8 +417,8 @@ bool Declaration::IsInlineable() const { return proxy()->var()->IsStackAllocated(); } -bool VariableDeclaration::IsInlineable() const { - return Declaration::IsInlineable() && fun() == NULL; +bool FunctionDeclaration::IsInlineable() const { + return false; } @@ -1003,6 +1003,7 @@ CaseClause::CaseClause(Isolate* isolate, } INCREASE_NODE_COUNT(VariableDeclaration) +INCREASE_NODE_COUNT(FunctionDeclaration) INCREASE_NODE_COUNT(ModuleDeclaration) INCREASE_NODE_COUNT(ModuleLiteral) INCREASE_NODE_COUNT(ModuleVariable) diff --git a/src/ast.h b/src/ast.h index 74c4c61fe7..7a46ac930d 100644 --- a/src/ast.h +++ b/src/ast.h @@ -61,6 +61,7 @@ namespace internal { #define DECLARATION_NODE_LIST(V) \ V(VariableDeclaration) \ + V(FunctionDeclaration) \ V(ModuleDeclaration) \ #define MODULE_NODE_LIST(V) \ @@ -444,10 +445,10 @@ class Declaration: public AstNode { VariableProxy* proxy() const { return proxy_; } VariableMode mode() const { return mode_; } Scope* scope() const { return scope_; } + virtual InitializationFlag initialization() const = 0; virtual bool IsInlineable() const; virtual Declaration* AsDeclaration() { return this; } - virtual VariableDeclaration* AsVariableDeclaration() { return NULL; } protected: Declaration(VariableProxy* proxy, @@ -475,22 +476,43 @@ 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; + virtual InitializationFlag initialization() const { + return mode() == VAR ? kCreatedInitialized : kNeedsInitialization; + } protected: template friend class AstNodeFactory; VariableDeclaration(VariableProxy* proxy, + VariableMode mode, + Scope* scope) + : Declaration(proxy, mode, scope) { + } +}; + + +class FunctionDeclaration: public Declaration { + public: + DECLARE_NODE_TYPE(FunctionDeclaration) + + FunctionLiteral* fun() const { return fun_; } + virtual InitializationFlag initialization() const { + return kCreatedInitialized; + } + virtual bool IsInlineable() const; + + protected: + template friend class AstNodeFactory; + + FunctionDeclaration(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); + // At the moment there are no "const functions" in JavaScript... + ASSERT(mode == VAR || mode == LET); + ASSERT(fun != NULL); } private: @@ -503,6 +525,9 @@ class ModuleDeclaration: public Declaration { DECLARE_NODE_TYPE(ModuleDeclaration) Module* module() const { return module_; } + virtual InitializationFlag initialization() const { + return kCreatedInitialized; + } protected: template friend class AstNodeFactory; @@ -2532,13 +2557,21 @@ class AstNodeFactory BASE_EMBEDDED { VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy, VariableMode mode, - FunctionLiteral* fun, Scope* scope) { VariableDeclaration* decl = - new(zone_) VariableDeclaration(proxy, mode, fun, scope); + new(zone_) VariableDeclaration(proxy, mode, scope); VISIT_AND_RETURN(VariableDeclaration, decl) } + FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* fun, + Scope* scope) { + FunctionDeclaration* decl = + new(zone_) FunctionDeclaration(proxy, mode, fun, scope); + VISIT_AND_RETURN(FunctionDeclaration, decl) + } + ModuleDeclaration* NewModuleDeclaration(VariableProxy* proxy, Module* module, Scope* scope) { diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 9639542740..a37b3e4342 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -55,6 +55,10 @@ void BreakableStatementChecker::VisitVariableDeclaration( VariableDeclaration* decl) { } +void BreakableStatementChecker::VisitFunctionDeclaration( + FunctionDeclaration* decl) { +} + void BreakableStatementChecker::VisitModuleDeclaration( ModuleDeclaration* decl) { } @@ -569,29 +573,28 @@ void FullCodeGenerator::VisitDeclarations( isolate()->factory()->NewFixedArray(2 * global_count_, TENURED); int length = declarations->length(); for (int j = 0, i = 0; i < length; i++) { - VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration(); - if (decl != NULL) { - Variable* var = decl->proxy()->var(); + Declaration* decl = declarations->at(i); + 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++); - } else { - array->set_undefined(j++); - } + if (var->IsUnallocated()) { + array->set(j++, *(var->name())); + FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration(); + if (fun_decl == NULL) { + if (var->binding_needs_init()) { + // In case this binding needs initialization use the hole. + array->set_the_hole(j++); } else { - Handle function = - Compiler::BuildFunctionInfo(decl->fun(), script()); - // Check for stack-overflow exception. - if (function.is_null()) { - SetStackOverflow(); - return; - } - array->set(j++, *function); + array->set_undefined(j++); } + } else { + Handle function = + Compiler::BuildFunctionInfo(fun_decl->fun(), script()); + // Check for stack-overflow exception. + if (function.is_null()) { + SetStackOverflow(); + return; + } + array->set(j++, *function); } } } @@ -605,12 +608,17 @@ void FullCodeGenerator::VisitDeclarations( void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { + EmitDeclaration(decl->proxy(), decl->mode(), NULL); +} + + +void FullCodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { EmitDeclaration(decl->proxy(), decl->mode(), decl->fun()); } void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) { - // TODO(rossberg) + EmitDeclaration(decl->proxy(), decl->mode(), NULL); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 4307a0ddf6..6bf082d86c 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -2466,7 +2466,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) { - HandleVariableDeclaration(scope->function(), CONST, NULL, NULL); + HandleDeclaration(scope->function(), CONST, NULL, NULL); } VisitDeclarations(scope->declarations()); AddSimulate(AstNode::kDeclarationsId); @@ -6826,20 +6826,16 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { } -void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { - UNREACHABLE(); -} - void HGraphBuilder::VisitDeclarations(ZoneList* declarations) { int length = declarations->length(); int global_count = 0; for (int i = 0; i < declarations->length(); i++) { - VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration(); - if (decl == NULL) continue; - HandleVariableDeclaration(decl->proxy(), - decl->mode(), - decl->fun(), - &global_count); + Declaration* decl = declarations->at(i); + FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration(); + HandleDeclaration(decl->proxy(), + decl->mode(), + fun_decl != NULL ? fun_decl->fun() : NULL, + &global_count); } // Batch declare global functions and variables. @@ -6847,13 +6843,13 @@ void HGraphBuilder::VisitDeclarations(ZoneList* declarations) { Handle array = isolate()->factory()->NewFixedArray(2 * global_count, TENURED); for (int j = 0, i = 0; i < length; i++) { - VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration(); - if (decl == NULL) continue; + Declaration* decl = declarations->at(i); Variable* var = decl->proxy()->var(); if (var->IsUnallocated()) { array->set(j++, *(var->name())); - if (decl->fun() == NULL) { + FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration(); + if (fun_decl == NULL) { if (var->binding_needs_init()) { // In case this binding needs initialization use the hole. array->set_the_hole(j++); @@ -6862,7 +6858,7 @@ void HGraphBuilder::VisitDeclarations(ZoneList* declarations) { } } else { Handle function = - Compiler::BuildFunctionInfo(decl->fun(), info()->script()); + Compiler::BuildFunctionInfo(fun_decl->fun(), info()->script()); // Check for stack-overflow exception. if (function.is_null()) { SetStackOverflow(); @@ -6884,10 +6880,10 @@ void HGraphBuilder::VisitDeclarations(ZoneList* declarations) { } -void HGraphBuilder::HandleVariableDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function, - int* global_count) { +void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* function, + int* global_count) { Variable* var = proxy->var(); bool binding_needs_init = (mode == CONST || mode == CONST_HARMONY || mode == LET); @@ -6923,6 +6919,16 @@ void HGraphBuilder::HandleVariableDeclaration(VariableProxy* proxy, } +void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { + UNREACHABLE(); +} + + +void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { + UNREACHABLE(); +} + + void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) { // TODO(rossberg) } diff --git a/src/hydrogen.h b/src/hydrogen.h index 50c76cb69b..b0d67ebb66 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -870,10 +870,10 @@ class HGraphBuilder: public AstVisitor { INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) #undef INLINE_FUNCTION_GENERATOR_DECLARATION - void HandleVariableDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function, - int* global_count); + void HandleDeclaration(VariableProxy* proxy, + VariableMode mode, + FunctionLiteral* function, + int* global_count); void VisitDelete(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr); diff --git a/src/parser.cc b/src/parser.cc index f0556cb355..1bab4a6179 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1221,13 +1221,14 @@ Block* Parser::ParseModuleDeclaration(bool* ok) { // Create new block with one expected declaration. Block* block = factory()->NewBlock(NULL, 1, true); Handle name = ParseIdentifier(CHECK_OK); - // top_scope_->AddDeclaration( - // factory()->NewModuleDeclaration(proxy, module, top_scope_)); - VariableProxy* proxy = Declare(name, LET, NULL, true, CHECK_OK); - Module* module = ParseModule(ok); + Module* module = ParseModule(CHECK_OK); + VariableProxy* proxy = NewUnresolved(name, LET); + Declaration* declaration = + factory()->NewModuleDeclaration(proxy, module, top_scope_); + Declare(declaration, true, CHECK_OK); + // TODO(rossberg): Add initialization statement to block. - USE(proxy); - USE(module); + return block; } @@ -1497,21 +1498,22 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { } -VariableProxy* Parser::Declare(Handle name, - VariableMode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok) { - Variable* var = NULL; +VariableProxy* Parser::NewUnresolved(Handle name, VariableMode mode) { // If we are inside a function, a declaration of a var/const variable is a // truly local variable, and the scope of the variable is always the function // scope. // Let/const variables in harmony mode are always added to the immediately // enclosing scope. - Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY) - ? top_scope_ : top_scope_->DeclarationScope(); - InitializationFlag init_flag = (fun != NULL || mode == VAR) - ? kCreatedInitialized : kNeedsInitialization; + return DeclarationScope(mode)->NewUnresolved( + factory(), name, scanner().location().beg_pos); +} + + +void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { + Handle name = declaration->proxy()->name(); + VariableMode mode = declaration->mode(); + Scope* declaration_scope = DeclarationScope(mode); + Variable* var = NULL; // If a function scope exists, then we can statically declare this // variable and also set its mode. In any case, a Declaration node @@ -1531,7 +1533,8 @@ VariableProxy* Parser::Declare(Handle name, var = declaration_scope->LocalLookup(name); if (var == NULL) { // Declare the name. - var = declaration_scope->DeclareLocal(name, mode, init_flag); + var = declaration_scope->DeclareLocal( + name, mode, declaration->initialization()); } else { // The name was declared in this scope before; check for conflicting // re-declarations. We have a conflict if either of the declarations is @@ -1558,7 +1561,7 @@ VariableProxy* Parser::Declare(Handle name, Vector args(elms, 2); ReportMessage("redeclaration", args); *ok = false; - return NULL; + return; } const char* type = (var->mode() == VAR) ? "var" : var->is_const_mode() ? "const" : "let"; @@ -1588,10 +1591,7 @@ VariableProxy* Parser::Declare(Handle name, // semantic issue as long as we keep the source order, but it may be // a performance issue since it may lead to repeated // Runtime::DeclareContextSlot() calls. - VariableProxy* proxy = declaration_scope->NewUnresolved( - factory(), name, scanner().location().beg_pos); - declaration_scope->AddDeclaration( - factory()->NewVariableDeclaration(proxy, mode, fun, top_scope_)); + declaration_scope->AddDeclaration(declaration); if ((mode == CONST || mode == CONST_HARMONY) && declaration_scope->is_global_scope()) { @@ -1615,7 +1615,7 @@ VariableProxy* Parser::Declare(Handle name, mode, true, kind, - init_flag); + declaration->initialization()); var->AllocateTo(Variable::LOOKUP, -1); resolve = true; } @@ -1644,9 +1644,7 @@ VariableProxy* Parser::Declare(Handle name, // initialization code. Thus, inside the 'with' statement, we need // both access to the static and the dynamic context chain; the // runtime needs to provide both. - if (resolve && var != NULL) proxy->BindTo(var); - - return proxy; + if (resolve && var != NULL) declaration->proxy()->BindTo(var); } @@ -1673,7 +1671,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // isn't lazily compiled. The extension structures are only // accessible while parsing the first time not when reparsing // because of lazy compilation. - top_scope_->DeclarationScope()->ForceEagerCompilation(); + DeclarationScope(VAR)->ForceEagerCompilation(); // Compute the function template for the native function. v8::Handle fun_template = @@ -1698,12 +1696,15 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // TODO(1240846): It's weird that native function declarations are // introduced dynamically when we meet their declarations, whereas // other functions are set up when entering the surrounding scope. + VariableProxy* proxy = NewUnresolved(name, VAR); + Declaration* declaration = + factory()->NewVariableDeclaration(proxy, VAR, top_scope_); + Declare(declaration, true, CHECK_OK); SharedFunctionInfoLiteral* lit = factory()->NewSharedFunctionInfoLiteral(shared); - VariableProxy* var = Declare(name, VAR, NULL, true, CHECK_OK); return factory()->NewExpressionStatement( factory()->NewAssignment( - Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)); + Token::INIT_VAR, proxy, lit, RelocInfo::kNoPosition)); } @@ -1724,7 +1725,10 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) { // scope, we treat is as such and introduce the function with it's // initial value upon entering the corresponding scope. VariableMode mode = is_extended_mode() ? LET : VAR; - Declare(name, mode, fun, true, CHECK_OK); + VariableProxy* proxy = NewUnresolved(name, mode); + Declaration* declaration = + factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_); + Declare(declaration, true, CHECK_OK); return factory()->NewEmptyStatement(); } @@ -1902,8 +1906,8 @@ Block* Parser::ParseVariableDeclarations( UNREACHABLE(); // by current callers } - Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY) - ? top_scope_ : top_scope_->DeclarationScope(); + Scope* declaration_scope = DeclarationScope(mode); + // The scope of a var/const declared variable anywhere inside a function // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can // transform a source-level var/const declaration into a (Function) @@ -1950,7 +1954,10 @@ Block* Parser::ParseVariableDeclarations( // For let/const declarations in harmony mode, we can also immediately // pre-resolve the proxy because it resides in the same scope as the // declaration. - VariableProxy* proxy = Declare(name, mode, NULL, mode != VAR, CHECK_OK); + VariableProxy* proxy = NewUnresolved(name, mode); + Declaration* declaration = + factory()->NewVariableDeclaration(proxy, mode, top_scope_); + Declare(declaration, mode != VAR, CHECK_OK); nvars++; if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { ReportMessageAt(scanner().location(), "too_many_variables", diff --git a/src/parser.h b/src/parser.h index 66c801d981..4c18fe930d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -566,6 +566,10 @@ class Parser { ASSERT(top_scope_ != NULL); return top_scope_->is_extended_mode(); } + Scope* DeclarationScope(VariableMode mode) { + return (mode == LET || mode == CONST_HARMONY) + ? top_scope_ : top_scope_->DeclarationScope(); + } // Check if the given string is 'eval' or 'arguments'. bool IsEvalOrArguments(Handle string); @@ -756,10 +760,8 @@ class Parser { void CheckConflictingVarDeclarations(Scope* scope, bool* ok); // Parser support - VariableProxy* Declare(Handle name, VariableMode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok); + VariableProxy* NewUnresolved(Handle name, VariableMode mode); + void Declare(Declaration* declaration, bool resolve, bool* ok); bool TargetStackContainsLabel(Handle label); BreakableStatement* LookupBreakTarget(Handle label, bool* ok); diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc index f3ec75adcf..d879da15d8 100644 --- a/src/prettyprinter.cc +++ b/src/prettyprinter.cc @@ -61,10 +61,15 @@ void PrettyPrinter::VisitBlock(Block* node) { void PrettyPrinter::VisitVariableDeclaration(VariableDeclaration* node) { Print("var "); PrintLiteral(node->proxy()->name(), false); - if (node->fun() != NULL) { - Print(" = "); - PrintFunctionLiteral(node->fun()); - } + Print(";"); +} + + +void PrettyPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { + Print("function "); + PrintLiteral(node->proxy()->name(), false); + Print(" = "); + PrintFunctionLiteral(node->fun()); Print(";"); } @@ -744,19 +749,18 @@ void AstPrinter::VisitBlock(Block* node) { void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { - if (node->fun() == NULL) { - // var or const declarations - PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), - node->proxy()->var(), - node->proxy()->name()); - } else { - // function declarations - PrintIndented("FUNCTION "); - PrintLiteral(node->proxy()->name(), true); - Print(" = function "); - PrintLiteral(node->fun()->name(), false); - Print("\n"); - } + PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), + node->proxy()->var(), + node->proxy()->name()); +} + + +void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { + PrintIndented("FUNCTION "); + PrintLiteral(node->proxy()->name(), true); + Print(" = function "); + PrintLiteral(node->fun()->name(), false); + Print("\n"); } diff --git a/src/rewriter.cc b/src/rewriter.cc index 8308792baa..a92c3c3ae2 100644 --- a/src/rewriter.cc +++ b/src/rewriter.cc @@ -210,6 +210,7 @@ void Processor::VisitWithStatement(WithStatement* node) { // Do nothing: void Processor::VisitVariableDeclaration(VariableDeclaration* node) {} +void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {} void Processor::VisitModuleDeclaration(ModuleDeclaration* node) {} void Processor::VisitModuleLiteral(ModuleLiteral* node) {} void Processor::VisitModuleVariable(ModuleVariable* node) {}