Further refactoring of declarations in the AST:

Define modules as module declarations.
Separate function declarations from var declarations.

R=jkummerow@chromium.org
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9460064

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10854 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rossberg@chromium.org 2012-02-28 10:12:39 +00:00
parent ddaf909f82
commit d809d17f5d
9 changed files with 171 additions and 109 deletions

View File

@ -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)

View File

@ -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<class> 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<class> 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<class> 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) {

View File

@ -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<SharedFunctionInfo> 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<SharedFunctionInfo> 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);
}

View File

@ -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<Declaration*>* 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<Declaration*>* declarations) {
Handle<FixedArray> 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<Declaration*>* declarations) {
}
} else {
Handle<SharedFunctionInfo> 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<Declaration*>* 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)
}

View File

@ -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);

View File

@ -1221,13 +1221,14 @@ Block* Parser::ParseModuleDeclaration(bool* ok) {
// Create new block with one expected declaration.
Block* block = factory()->NewBlock(NULL, 1, true);
Handle<String> 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<String> name,
VariableMode mode,
FunctionLiteral* fun,
bool resolve,
bool* ok) {
Variable* var = NULL;
VariableProxy* Parser::NewUnresolved(Handle<String> 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<String> 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<String> 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<String> name,
Vector<const char*> 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<String> 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<String> name,
mode,
true,
kind,
init_flag);
declaration->initialization());
var->AllocateTo(Variable::LOOKUP, -1);
resolve = true;
}
@ -1644,9 +1644,7 @@ VariableProxy* Parser::Declare(Handle<String> 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<v8::FunctionTemplate> 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",

View File

@ -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> string);
@ -756,10 +760,8 @@ class Parser {
void CheckConflictingVarDeclarations(Scope* scope, bool* ok);
// Parser support
VariableProxy* Declare(Handle<String> name, VariableMode mode,
FunctionLiteral* fun,
bool resolve,
bool* ok);
VariableProxy* NewUnresolved(Handle<String> name, VariableMode mode);
void Declare(Declaration* declaration, bool resolve, bool* ok);
bool TargetStackContainsLabel(Handle<String> label);
BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok);

View File

@ -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");
}

View File

@ -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) {}