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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@28973 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/kjs/nodes.cpp b/JavaScriptCore/kjs/nodes.cpp
index 8a63441..d805155 100644
--- a/JavaScriptCore/kjs/nodes.cpp
+++ b/JavaScriptCore/kjs/nodes.cpp
@@ -380,6 +380,9 @@
void SourceElements::append(PassRefPtr<StatementNode> statement)
{
+ if (statement->isEmptyStatement())
+ return;
+
if (Debugger::debuggersPresent)
m_statements.append(new BreakpointCheckStatement(statement));
else
@@ -3419,49 +3422,15 @@
return expr2->evaluate(exec);
}
-// ------------------------------ AssignExprNode -------------------------------
+// ------------------------------ ConstDeclNode ----------------------------------
-void AssignExprNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
-{
- nodeStack.append(expr.get());
-}
-
-// 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());
@@ -3469,7 +3438,7 @@
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();
@@ -3490,14 +3459,13 @@
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();
@@ -3513,8 +3481,7 @@
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);
@@ -3528,19 +3495,18 @@
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
@@ -3550,16 +3516,16 @@
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
@@ -3654,6 +3620,22 @@
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)
@@ -3826,16 +3808,16 @@
// ------------------------------ 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)
@@ -3843,8 +3825,8 @@
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
@@ -3852,8 +3834,8 @@
{
JSValue* value = 0;
- if (varDecl) {
- varDecl->evaluate(exec);
+ if (init) {
+ init->evaluate(exec);
KJS_CHECKEXCEPTION
}
@@ -4267,7 +4249,7 @@
}
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);
@@ -4301,7 +4283,7 @@
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;
@@ -4368,9 +4350,9 @@
}
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));
}
@@ -4420,9 +4402,9 @@
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);
@@ -4443,13 +4425,14 @@
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) {