+2007-12-24 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ - Optimize variable declarations
+ http://bugs.webkit.org/show_bug.cgi?id=16585
+
+ 3.5% speedup on SunSpider.
+
+ var statements now result in either assignments or empty statements.
+
+ This allows a couple of optimization opportunities:
+ - No need to branch at runtime to check if there is an initializer
+ - EmptyStatementNodes can be removed entirely (also done in this patch)
+ - Assignment expressions get properly optimized for local variables
+
+ This patch also includes some code cleanup:
+ - Most of the old VarStatement/VarDecl logic is now only used for const declarations,
+ thus it is renamed appropriately
+ - AssignExprNode is gone
+
+ * JavaScriptCore.exp:
+ * kjs/NodeInfo.h:
+ * kjs/grammar.y:
+ * kjs/nodes.cpp:
+ (KJS::SourceElements::append):
+ (KJS::ConstDeclNode::ConstDeclNode):
+ (KJS::ConstDeclNode::optimizeVariableAccess):
+ (KJS::ConstDeclNode::handleSlowCase):
+ (KJS::ConstDeclNode::evaluateSingle):
+ (KJS::ConstDeclNode::evaluate):
+ (KJS::ConstStatementNode::optimizeVariableAccess):
+ (KJS::ConstStatementNode::execute):
+ (KJS::VarStatementNode::optimizeVariableAccess):
+ (KJS::VarStatementNode::execute):
+ (KJS::ForInNode::ForInNode):
+ (KJS::ForInNode::optimizeVariableAccess):
+ (KJS::ForInNode::execute):
+ (KJS::FunctionBodyNode::initializeSymbolTable):
+ (KJS::ProgramNode::initializeSymbolTable):
+ (KJS::FunctionBodyNode::processDeclarations):
+ (KJS::ProgramNode::processDeclarations):
+ (KJS::EvalNode::processDeclarations):
+ * kjs/nodes.h:
+ (KJS::DeclarationStacks::):
+ (KJS::StatementNode::):
+ (KJS::ConstDeclNode::):
+ (KJS::ConstStatementNode::):
+ (KJS::EmptyStatementNode::):
+ (KJS::VarStatementNode::):
+ (KJS::ForNode::):
+ * kjs/nodes2string.cpp:
+ (KJS::ConstDeclNode::streamTo):
+ (KJS::ConstStatementNode::streamTo):
+ (KJS::ScopeNode::streamTo):
+ (KJS::VarStatementNode::streamTo):
+ (KJS::ForNode::streamTo):
+ (KJS::ForInNode::streamTo):
+
2007-12-21 Mark Rowe <mrowe@apple.com>
Reviewed by Oliver Hunt.
__ZN3KJS11JSImmediate4typeEPKNS_7JSValueE
__ZN3KJS11JSImmediate8toObjectEPKNS_7JSValueEPNS_9ExecStateE
__ZN3KJS11JSImmediate8toStringEPKNS_7JSValueE
-__ZN3KJS11ProgramNodeC1EPNS_14SourceElementsEPN3WTF6VectorIPNS_11VarDeclNodeELm16EEEPNS4_IPNS_12FuncDeclNodeELm16EEE
+__ZN3KJS11ProgramNodeC1EPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS4_IPNS_12FuncDeclNodeELm16EEE
__ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierE
__ZN3KJS11PropertyMap5clearEv
__ZN3KJS11PropertyMap7restoreERKNS_15SavedPropertiesE
typedef NodeInfo<CaseClauseNode*> CaseClauseNodeInfo;
typedef NodeInfo<SourceElements*> SourceElementsInfo;
typedef NodeInfo<ClauseList> ClauseListInfo;
-typedef NodeInfo<VarDeclList> VarDeclListInfo;
+typedef NodeInfo<ExpressionNode*> VarDeclListInfo;
+typedef NodeInfo<ConstDeclList> ConstDeclListInfo;
} // namespace KJS
static ExpressionNode* makeDeleteNode(ExpressionNode*);
static ExpressionNode* makeNegateNode(ExpressionNode*);
static NumberNode* makeNumberNode(double);
+static StatementNode* makeVarStatementNode(ExpressionNode*);
+static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init);
+
#if COMPILER(MSVC)
return decls1;
}
-static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, VarDeclNode* decl)
+static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs)
{
if (!varDecls)
varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>;
- varDecls->data.append(decl);
+
+ varDecls->data.append(make_pair(ident, attrs));
+
+}
+
+static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl)
+{
+ unsigned attrs = DeclarationStacks::IsConstant;
+ if (decl->init)
+ attrs |= DeclarationStacks::HasInitializer;
+ appendToVarDeclarationList(varDecls, decl->ident, attrs);
}
%}
FuncDeclNode* funcDeclNode;
PropertyNode* propertyNode;
ArgumentsNode* argumentsNode;
- VarDeclNode* varDeclNode;
+ ConstDeclNode* constDeclNode;
CaseBlockNodeInfo caseBlockNode;
CaseClauseNodeInfo caseClauseNode;
FuncExprNode* funcExprNode;
- AssignExprNode* assignExprNode;
// statement nodes
StatementNodeInfo statementNode;
PropertyList propertyList;
ArgumentList argumentList;
VarDeclListInfo varDeclList;
+ ConstDeclListInfo constDeclList;
ClauseListInfo clauseList;
ElementList elementList;
ParameterList parameterList;
%type <statementNode> DebuggerStatement
%type <statementNode> SourceElement
-%type <assignExprNode> Initializer InitializerNoIn
+%type <expressionNode> Initializer InitializerNoIn
%type <funcDeclNode> FunctionDeclaration
%type <funcExprNode> FunctionExpr
%type <functionBodyNode> FunctionBody
%type <op> AssignmentOperator
%type <argumentsNode> Arguments
%type <argumentList> ArgumentList
-%type <varDeclList> VariableDeclarationList VariableDeclarationListNoIn ConstDeclarationList
-%type <varDeclNode> VariableDeclaration VariableDeclarationNoIn ConstDeclaration
+%type <varDeclList> VariableDeclarationList VariableDeclarationListNoIn
+%type <constDeclList> ConstDeclarationList
+%type <constDeclNode> ConstDeclaration
%type <caseBlockNode> CaseBlock
%type <caseClauseNode> CaseClause DefaultClause
%type <clauseList> CaseClauses CaseClausesOpt
;
VariableStatement:
- VAR VariableDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ VAR VariableDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
DBG($$.m_node, @1, @3); }
- | VAR VariableDeclarationList error { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ | VAR VariableDeclarationList error { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
DBG($$.m_node, @1, @2);
AUTO_SEMICOLON; }
;
VariableDeclarationList:
- VariableDeclaration { $$.m_node.head = $1;
- $$.m_node.tail = $$.m_node.head;
+ IDENT { $$.m_node = 0;
$$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- $$.m_varDeclarations->data.append($1);
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
$$.m_funcDeclarations = 0;
}
- | VariableDeclarationList ',' VariableDeclaration
- { $$.m_node.head = $1.m_node.head;
- $1.m_node.tail->next = $3;
- $$.m_node.tail = $3;
+ | IDENT Initializer { $$.m_node = new AssignResolveNode(*$1, $2);
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationList ',' IDENT
+ { $$.m_node = $1.m_node;
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationList ',' IDENT Initializer
+ { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
$$.m_varDeclarations = $1.m_varDeclarations;
- $$.m_varDeclarations->data.append($3);
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
$$.m_funcDeclarations = 0;
}
;
VariableDeclarationListNoIn:
- VariableDeclarationNoIn { $$.m_node.head = $1;
- $$.m_node.tail = $$.m_node.head;
+ IDENT { $$.m_node = 0;
$$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- $$.m_varDeclarations->data.append($1);
- $$.m_funcDeclarations = 0; }
- | VariableDeclarationListNoIn ',' VariableDeclarationNoIn
- { $$.m_node.head = $1.m_node.head;
- $1.m_node.tail->next = $3;
- $$.m_node.tail = $3;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | IDENT InitializerNoIn { $$.m_node = new AssignResolveNode(*$1, $2);
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationListNoIn ',' IDENT
+ { $$.m_node = $1.m_node;
$$.m_varDeclarations = $1.m_varDeclarations;
- $$.m_varDeclarations->data.append($3);
- $$.m_funcDeclarations = 0; }
-;
-
-VariableDeclaration:
- IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
- | IDENT Initializer { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
-;
-
-VariableDeclarationNoIn:
- IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
- | IDENT InitializerNoIn { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationListNoIn ',' IDENT InitializerNoIn
+ { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
;
ConstStatement:
- CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
DBG($$.m_node, @1, @3); }
| CONSTTOKEN ConstDeclarationList error
- { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
;
ConstDeclaration { $$.m_node.head = $1;
$$.m_node.tail = $$.m_node.head;
$$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- $$.m_varDeclarations->data.append($1);
+ appendToVarDeclarationList($$.m_varDeclarations, $1);
$$.m_funcDeclarations = 0; }
| ConstDeclarationList ',' ConstDeclaration
{ $$.m_node.head = $1.m_node.head;
$1.m_node.tail->next = $3;
$$.m_node.tail = $3;
$$.m_varDeclarations = $1.m_varDeclarations;
- $$.m_varDeclarations->data.append($3);
+ appendToVarDeclarationList($$.m_varDeclarations, $3);
$$.m_funcDeclarations = 0; }
;
ConstDeclaration:
- IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Constant); }
- | IDENT Initializer { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Constant); }
+ IDENT { $$ = new ConstDeclNode(*$1, 0); }
+ | IDENT Initializer { $$ = new ConstDeclNode(*$1, $2); }
;
Initializer:
- '=' AssignmentExpr { $$ = new AssignExprNode($2); }
+ '=' AssignmentExpr { $$ = $2; }
;
InitializerNoIn:
- '=' AssignmentExprNoIn { $$ = new AssignExprNode($2); }
+ '=' AssignmentExprNoIn { $$ = $2; }
;
EmptyStatement:
| WHILE '(' Expr ')' Statement { $$ = createNodeInfo<StatementNode*>(new WhileNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
DBG($$.m_node, @1, @4); }
| FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement
- { $$ = createNodeInfo<StatementNode*>(new ForNode($3, $5, $7, $9.m_node), $9.m_varDeclarations, $9.m_funcDeclarations);
+ { $$ = createNodeInfo<StatementNode*>(new ForNode($3, $5, $7, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations);
DBG($$.m_node, @1, @8);
}
| FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
- { $$ = createNodeInfo<StatementNode*>(new ForNode($4.m_node.head, $6, $8, $10.m_node),
+ { $$ = createNodeInfo<StatementNode*>(new ForNode($4.m_node, $6, $8, $10.m_node, true),
mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations),
mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations));
DBG($$.m_node, @1, @9); }
}
| FOR '(' VAR IDENT INTOKEN Expr ')' Statement
{ ForInNode *forIn = new ForInNode(*$4, 0, $6, $8.m_node);
- appendToVarDeclarationList($8.m_varDeclarations, forIn->getVarDecl());
+ appendToVarDeclarationList($8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
$$ = createNodeInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations);
DBG($$.m_node, @1, @7); }
| FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
{ ForInNode *forIn = new ForInNode(*$4, $5, $7, $9.m_node);
- appendToVarDeclarationList($9.m_varDeclarations, forIn->getVarDecl());
+ appendToVarDeclarationList($9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
$$ = createNodeInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations);
DBG($$.m_node, @1, @8); }
;
FunctionBody:
/* not in spec */ { $$ = new FunctionBodyNode(0, 0, 0); }
| SourceElements { $$ = new FunctionBodyNode($1.m_node, $1.m_varDeclarations ? &$1.m_varDeclarations->data : 0,
- $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0);
+ $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0);
// As in mergeDeclarationLists() we have to ref/deref to safely get rid of
// the declaration lists.
if ($1.m_varDeclarations) {
{
return yychar == '}' || yychar == 0 || lexer().prevTerminator();
}
+
+static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init)
+{
+ if (!list)
+ return init;
+ return new CommaNode(list, init);
+}
+
+// We turn variable declarations into either assignments or empty
+// statements (which later get stripped out), because the actual
+// declaration work is hoisted up to the start of the function body
+static StatementNode* makeVarStatementNode(ExpressionNode* expr)
+{
+ if (!expr)
+ return new EmptyStatementNode();
+ return new VarStatementNode(expr);
+}
+
void SourceElements::append(PassRefPtr<StatementNode> statement)
{
+ if (statement->isEmptyStatement())
+ return;
+
if (Debugger::debuggersPresent)
m_statements.append(new BreakpointCheckStatement(statement));
else
return expr2->evaluate(exec);
}
-// ------------------------------ AssignExprNode -------------------------------
-
-void AssignExprNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
-{
- nodeStack.append(expr.get());
-}
+// ------------------------------ ConstDeclNode ----------------------------------
-// ECMA 12.2
-JSValue* AssignExprNode::evaluate(ExecState* exec)
-{
- return expr->evaluate(exec);
-}
-
-bool AssignExprNode::evaluateToBoolean(ExecState* exec)
-{
- return expr->evaluateToBoolean(exec);
-}
-
-double AssignExprNode::evaluateToNumber(ExecState* exec)
-{
- return expr->evaluateToNumber(exec);
-}
-
-int32_t AssignExprNode::evaluateToInt32(ExecState* exec)
-{
- return expr->evaluateToInt32(exec);
-}
-
-uint32_t AssignExprNode::evaluateToUInt32(ExecState* exec)
-{
- return expr->evaluateToInt32(exec);
-}
-
-// ------------------------------ VarDeclNode ----------------------------------
-
-VarDeclNode::VarDeclNode(const Identifier &id, AssignExprNode *in, Type t)
- : varType(t)
- , ident(id)
+ConstDeclNode::ConstDeclNode(const Identifier& id, ExpressionNode* in)
+ : ident(id)
, init(in)
{
}
-void VarDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConstDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
{
if (next)
nodeStack.append(next.get());
nodeStack.append(init.get());
}
-void VarDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
+void ConstDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
{
ScopeChainIterator iter = chain.begin();
ScopeChainIterator end = chain.end();
unsigned flags = 0;
base->getPropertyAttributes(ident, flags);
- if (varType == VarDeclNode::Constant)
- flags |= ReadOnly;
+ flags |= ReadOnly;
base->put(exec, ident, val, flags);
}
// ECMA 12.2
-inline void VarDeclNode::evaluateSingle(ExecState* exec)
+inline void ConstDeclNode::evaluateSingle(ExecState* exec)
{
ASSERT(exec->variableObject()->hasOwnProperty(exec, ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
const ScopeChain& chain = exec->scopeChain();
int flags = Internal;
if (exec->codeType() != EvalCode)
flags |= DontDelete;
- if (varType == VarDeclNode::Constant)
- flags |= ReadOnly;
+ flags |= ReadOnly;
variableObject->put(exec, ident, val, flags);
} else {
JSValue* val = init->evaluate(exec);
unsigned flags = 0;
variableObject->getPropertyAttributes(ident, flags);
- if (varType == VarDeclNode::Constant)
- flags |= ReadOnly;
+ flags |= ReadOnly;
variableObject->put(exec, ident, val, flags);
}
}
}
-JSValue* VarDeclNode::evaluate(ExecState* exec)
+JSValue* ConstDeclNode::evaluate(ExecState* exec)
{
evaluateSingle(exec);
- if (VarDeclNode* n = next.get()) {
+ if (ConstDeclNode* n = next.get()) {
do {
n->evaluateSingle(exec);
KJS_CHECKEXCEPTIONVALUE
return jsUndefined();
}
-// ------------------------------ VarStatementNode -----------------------------
+// ------------------------------ ConstStatementNode -----------------------------
-void VarStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConstStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
{
ASSERT(next);
nodeStack.append(next.get());
}
// ECMA 12.2
-JSValue* VarStatementNode::execute(ExecState* exec)
+JSValue* ConstStatementNode::execute(ExecState* exec)
{
next->evaluate(exec);
KJS_CHECKEXCEPTION
return exec->setNormalCompletion(value);
}
+// ------------------------------ VarStatementNode ----------------------------
+
+void VarStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+{
+ ASSERT(expr);
+ nodeStack.append(expr.get());
+}
+
+JSValue* VarStatementNode::execute(ExecState* exec)
+{
+ expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ return exec->setNormalCompletion();
+}
+
// ------------------------------ IfNode ---------------------------------------
void IfNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
// ------------------------------ ForInNode ------------------------------------
ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* e, StatementNode* s)
- : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
+ : init(0L), lexpr(l), expr(e), statement(s), identIsVarDecl(false)
{
}
-ForInNode::ForInNode(const Identifier& i, AssignExprNode* in, ExpressionNode* e, StatementNode* s)
- : ident(i), init(in), expr(e), statement(s)
+ForInNode::ForInNode(const Identifier& i, ExpressionNode* in, ExpressionNode* e, StatementNode* s)
+ : ident(i), lexpr(new ResolveNode(i)), expr(e), statement(s), identIsVarDecl(true)
{
+ if (in)
+ init = new AssignResolveNode(i, in);
// for( var foo = bar in baz )
- varDecl = new VarDeclNode(ident, init.get(), VarDeclNode::Variable);
- lexpr = new ResolveNode(ident);
}
void ForInNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
nodeStack.append(statement.get());
nodeStack.append(expr.get());
nodeStack.append(lexpr.get());
- if (varDecl)
- nodeStack.append(varDecl.get());
+ if (init)
+ nodeStack.append(init.get());
}
// ECMA 12.6.4
{
JSValue* value = 0;
- if (varDecl) {
- varDecl->evaluate(exec);
+ if (init) {
+ init->evaluate(exec);
KJS_CHECKEXCEPTION
}
}
for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
- Identifier& ident = m_varStack[i]->ident;
+ Identifier& ident = m_varStack[i].first;
if (ident == exec->propertyNames().arguments)
continue;
symbolTable.add(ident.ustring().rep(), localStorageIndex);
size = m_varStack.size();
m_varIndexes.resize(size);
for (size_t i = 0; i < size; ++i) {
- const Identifier& ident = m_varStack[i]->ident;
+ const Identifier& ident = m_varStack[i].first;
if (variableObject->getDirect(ident)) {
m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
continue;
}
for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
- VarDeclNode* node = m_varStack[i];
+ bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
int attributes = minAttributes;
- if (node->varType == VarDeclNode::Constant)
+ if (isConstant)
attributes |= ReadOnly;
localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
}
if (index == missingSymbolMarker())
continue;
- VarDeclNode* node = m_varStack[i];
+ bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
int attributes = minAttributes;
- if (node->varType == VarDeclNode::Constant)
+ if (isConstant)
attributes |= ReadOnly;
LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
int minAttributes = Internal;
for (i = 0, size = m_varStack.size(); i < size; ++i) {
- VarDeclNode* node = m_varStack[i];
- if (variableObject->hasOwnProperty(exec, node->ident))
+ Identifier& ident = m_varStack[i].first;
+ bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
+ if (variableObject->hasOwnProperty(exec, ident))
continue;
int attributes = minAttributes;
- if (node->varType == VarDeclNode::Constant)
+ if (isConstant)
attributes |= ReadOnly;
- variableObject->put(exec, node->ident, jsUndefined(), attributes);
+ variableObject->put(exec, ident, jsUndefined(), attributes);
}
for (i = 0, size = m_functionStack.size(); i < size; ++i) {
class Node;
class PropertyListNode;
class SourceStream;
- class VarDeclNode;
+ class ConstDeclNode;
enum Operator {
OpEqual,
struct DeclarationStacks {
typedef Vector<Node*, 16> NodeStack;
- typedef Vector<VarDeclNode*, 16> VarStack;
+ enum { IsConstant, HasInitializer } VarAttrs;
+ typedef Vector<std::pair<Identifier, unsigned>, 16> VarStack;
typedef Vector<FuncDeclNode*, 16> FunctionStack;
DeclarationStacks(ExecState* e, NodeStack& n, VarStack& v, FunctionStack& f)
virtual JSValue* execute(ExecState *exec) KJS_FAST_CALL = 0;
void pushLabel(const Identifier &id) KJS_FAST_CALL { ls.push(id); }
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+ virtual bool isEmptyStatement() const KJS_FAST_CALL { return false; }
protected:
LabelStack ls;
private:
RefPtr<ExpressionNode> expr2;
};
- class AssignExprNode : public ExpressionNode {
+ class ConstDeclNode : public ExpressionNode {
public:
- AssignExprNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) {}
- virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
- virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
- virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
- virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
- virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
- private:
- RefPtr<ExpressionNode> expr;
- };
-
- class VarDeclNode : public ExpressionNode {
- public:
- enum Type { Variable, Constant };
- VarDeclNode(const Identifier &id, AssignExprNode *in, Type t) KJS_FAST_CALL;
+ ConstDeclNode(const Identifier& id, ExpressionNode* in) KJS_FAST_CALL;
virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual KJS::JSValue* evaluate(ExecState*) KJS_FAST_CALL;
void evaluateSingle(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
- PassRefPtr<VarDeclNode> releaseNext() KJS_FAST_CALL { return next.release(); }
+ PassRefPtr<ConstDeclNode> releaseNext() KJS_FAST_CALL { return next.release(); }
- Type varType;
Identifier ident;
- ListRefPtr<VarDeclNode> next;
+ ListRefPtr<ConstDeclNode> next;
+ RefPtr<ExpressionNode> init;
private:
void handleSlowCase(ExecState*, const ScopeChain&, JSValue*) KJS_FAST_CALL NEVER_INLINE;
- RefPtr<AssignExprNode> init;
};
- class VarStatementNode : public StatementNode {
+ class ConstStatementNode : public StatementNode {
public:
- VarStatementNode(VarDeclNode* l) KJS_FAST_CALL : next(l) { }
+ ConstStatementNode(ConstDeclNode* l) KJS_FAST_CALL : next(l) { }
virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
private:
- RefPtr<VarDeclNode> next;
+ RefPtr<ConstDeclNode> next;
};
typedef Vector<RefPtr<StatementNode> > StatementVector;
EmptyStatementNode() KJS_FAST_CALL { } // debug
virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual bool isEmptyStatement() const KJS_FAST_CALL { return true; }
};
class ExprStatementNode : public StatementNode {
RefPtr<ExpressionNode> expr;
};
+ class VarStatementNode : public StatementNode {
+ public:
+ VarStatementNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
+ virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ private:
+ RefPtr<ExpressionNode> expr;
+ };
+
class IfNode : public StatementNode {
public:
IfNode(ExpressionNode* e, StatementNode *s) KJS_FAST_CALL
class ForNode : public StatementNode {
public:
- ForNode(ExpressionNode* e1, ExpressionNode* e2, ExpressionNode* e3, StatementNode* s) KJS_FAST_CALL
+ ForNode(ExpressionNode* e1, ExpressionNode* e2, ExpressionNode* e3, StatementNode* s, bool e1WasVarDecl) KJS_FAST_CALL
: expr1(e1 ? e1 : new TrueNode)
, expr2(e2 ? e2 : new TrueNode)
, expr3(e3 ? e3 : new TrueNode)
, statement(s)
+ , expr1WasVarDecl(e1WasVarDecl)
{
ASSERT(expr1);
ASSERT(expr2);
RefPtr<ExpressionNode> expr2;
RefPtr<ExpressionNode> expr3;
RefPtr<StatementNode> statement;
+ bool expr1WasVarDecl;
};
class ForInNode : public StatementNode {
public:
ForInNode(ExpressionNode* l, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
- ForInNode(const Identifier &i, AssignExprNode *in, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
+ ForInNode(const Identifier &i, ExpressionNode *in, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
- VarDeclNode* getVarDecl() { return varDecl.get(); }
private:
Identifier ident;
- RefPtr<AssignExprNode> init;
+ RefPtr<ExpressionNode> init;
RefPtr<ExpressionNode> lexpr;
RefPtr<ExpressionNode> expr;
- RefPtr<VarDeclNode> varDecl;
RefPtr<StatementNode> statement;
+ bool identIsVarDecl;
};
class ContinueNode : public StatementNode {
int sourceId() const KJS_FAST_CALL { return m_sourceId; }
const UString& sourceURL() const KJS_FAST_CALL { return m_sourceURL; }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
protected:
void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
ArgumentListNode* tail;
};
- struct VarDeclList {
- VarDeclNode* head;
- VarDeclNode* tail;
+ struct ConstDeclList {
+ ConstDeclNode* head;
+ ConstDeclNode* tail;
};
struct ParameterList {
s << PrecAssignment << expr1 << ", " << PrecAssignment << expr2;
}
-void AssignExprNode::streamTo(SourceStream& s) const
+void ConstDeclNode::streamTo(SourceStream& s) const
{
- s << " = " << PrecAssignment << expr;
-}
-
-void VarDeclNode::streamTo(SourceStream& s) const
-{
- s << "var " << ident << init;
- for (VarDeclNode* n = next.get(); n; n = n->next.get())
- s << ", " << ident << init;
+ s << ident;
+ if (init)
+ s << " = " << init;
+ for (ConstDeclNode* n = next.get(); n; n = n->next.get()) {
+ s << ", " << ident;
+ if (init)
+ s << " = " << init;
+ }
}
-void VarStatementNode::streamTo(SourceStream& s) const
+void ConstStatementNode::streamTo(SourceStream& s) const
{
- s << Endl << next << ';';
+ s << Endl << "const " << next << ';';
}
static inline void statementListStreamTo(const Vector<RefPtr<StatementNode> >& nodes, SourceStream& s)
s << Unindent << Endl << "}";
}
+void ScopeNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "{" << Indent;
+
+ bool printedVar = false;
+ for (size_t i = 0; i < m_varStack.size(); ++i) {
+ if (m_varStack[i].second == 0) {
+ if (!printedVar) {
+ s << Endl << "var ";
+ printedVar = true;
+ } else
+ s << ", ";
+ s << m_varStack[i].first;
+ }
+ }
+ if (printedVar)
+ s << ';';
+
+ statementListStreamTo(m_children, s);
+ s << Unindent << Endl << "}";
+}
+
void EmptyStatementNode::streamTo(SourceStream& s) const
{
s << Endl << ';';
s << Endl << expr << ';';
}
+void VarStatementNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "var " << expr << ';';
+}
+
void IfNode::streamTo(SourceStream& s) const
{
s << Endl << "if (" << m_condition << ')' << Indent << m_ifBlock << Unindent;
void ForNode::streamTo(SourceStream& s) const
{
s << Endl << "for ("
+ << (expr1WasVarDecl ? "var " : "")
<< expr1
<< "; " << expr2
<< "; " << expr3
void ForInNode::streamTo(SourceStream& s) const
{
s << Endl << "for (";
- if (varDecl)
- s << varDecl;
- else
+ if (identIsVarDecl) {
+ s << "var ";
+ if (init)
+ s << init;
+ else
+ s << PrecLeftHandSide << lexpr;
+ } else
s << PrecLeftHandSide << lexpr;
s << " in " << expr << ')' << Indent << statement << Unindent;