Debranching various Node::evaluate implementations
authoroliver <oliver@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 Oct 2007 03:14:00 +0000 (03:14 +0000)
committeroliver <oliver@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 Oct 2007 03:14:00 +0000 (03:14 +0000)
Reviewed by Maciej.

Split the read-modify-write assignment cases out of AssignResolveNode and into ReadModifyResolveNode
Split the increment and decrement cases for Prefix- and Postfix- ResolveNode, BracketNode, and DotNode

Gains 1.6% on SunSpider

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@27252 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp

index 2ab21a8946f65ecdc22e7878d520b0d841c07e1b..5adbc506b5d9096c228fb7ab69983ca0e00a7e8e 100644 (file)
@@ -1,3 +1,85 @@
+2007-10-29  Oliver Hunt  <oliver@apple.com>
+
+        Debranching various Node::evaluate implementations
+        
+        Reviewed by Maciej.
+        
+        Split the read-modify-write assignment cases out of AssignResolveNode and into ReadModifyResolveNode
+        Split the increment and decrement cases for Prefix- and Postfix- ResolveNode, BracketNode, and DotNode
+        
+        Gains 1.6% on SunSpider
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * kjs/grammar.y:
+        * kjs/nodes.cpp:
+        (KJS::PostIncResolveNode::optimizeVariableAccess):
+        (KJS::PostIncResolveNode::evaluate):
+        (KJS::PostIncLocalVarNode::evaluate):
+        (KJS::PostDecResolveNode::optimizeVariableAccess):
+        (KJS::PostDecResolveNode::evaluate):
+        (KJS::PostDecLocalVarNode::evaluate):
+        (KJS::PostIncBracketNode::evaluate):
+        (KJS::PostDecBracketNode::evaluate):
+        (KJS::PostIncDotNode::evaluate):
+        (KJS::PostDecDotNode::evaluate):
+        (KJS::PreIncResolveNode::optimizeVariableAccess):
+        (KJS::PreIncLocalVarNode::evaluate):
+        (KJS::PreIncResolveNode::evaluate):
+        (KJS::PreDecResolveNode::optimizeVariableAccess):
+        (KJS::PreDecLocalVarNode::evaluate):
+        (KJS::PreDecResolveNode::evaluate):
+        (KJS::PreIncBracketNode::evaluate):
+        (KJS::PreDecBracketNode::evaluate):
+        (KJS::PreIncDotNode::evaluate):
+        (KJS::PreDecDotNode::evaluate):
+        (KJS::ReadModifyResolveNode::optimizeVariableAccess):
+        (KJS::AssignResolveNode::optimizeVariableAccess):
+        (KJS::AssignLocalVarNode::evaluate):
+        (KJS::AssignResolveNode::evaluate):
+        * kjs/nodes.h:
+        (KJS::PostDecResolveNode::):
+        (KJS::PostDecResolveNode::precedence):
+        (KJS::PostDecLocalVarNode::):
+        (KJS::PostfixBracketNode::):
+        (KJS::PostfixBracketNode::precedence):
+        (KJS::PostIncBracketNode::):
+        (KJS::PostIncBracketNode::isIncrement):
+        (KJS::PostDecBracketNode::):
+        (KJS::PostDecBracketNode::isIncrement):
+        (KJS::PostfixDotNode::):
+        (KJS::PostfixDotNode::precedence):
+        (KJS::PostIncDotNode::):
+        (KJS::PostIncDotNode::isIncrement):
+        (KJS::PostDecDotNode::):
+        (KJS::PreIncResolveNode::):
+        (KJS::PreDecResolveNode::):
+        (KJS::PreDecResolveNode::precedence):
+        (KJS::PreDecLocalVarNode::):
+        (KJS::PrefixBracketNode::):
+        (KJS::PrefixBracketNode::precedence):
+        (KJS::PreIncBracketNode::):
+        (KJS::PreIncBracketNode::isIncrement):
+        (KJS::PreDecBracketNode::):
+        (KJS::PreDecBracketNode::isIncrement):
+        (KJS::PrefixDotNode::):
+        (KJS::PrefixDotNode::precedence):
+        (KJS::PreIncDotNode::):
+        (KJS::PreIncDotNode::isIncrement):
+        (KJS::PreDecDotNode::):
+        (KJS::ReadModifyResolveNode::):
+        (KJS::ReadModifyLocalVarNode::):
+        (KJS::AssignResolveNode::):
+        (KJS::AssignResolveNode::precedence):
+        * kjs/nodes2string.cpp:
+        (KJS::PostIncResolveNode::streamTo):
+        (KJS::PostDecResolveNode::streamTo):
+        (KJS::PostfixBracketNode::streamTo):
+        (KJS::PostfixDotNode::streamTo):
+        (KJS::PreIncResolveNode::streamTo):
+        (KJS::PreDecResolveNode::streamTo):
+        (KJS::ReadModifyResolveNode::streamTo):
+        (KJS::AssignResolveNode::streamTo):
+
 2007-10-29  Maciej Stachowiak  <mjs@apple.com>
 
         Not reviewed, build fix.
index 161dfdf0df7f9016f0ffbe412ab841d67c5bbe5e..ae8db5274b8e2a029395392aee051fa68ea631d1 100644 (file)
                0867D690FE84028FC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 149C277108902AFE008A9EFC /* Build configuration list for PBXProject "JavaScriptCore" */;
-                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 0867D691FE84028FC02AAC07 /* JavaScriptCore */;
                        productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
                        projectDirPath = "";
-                       projectRoot = "";
                        targets = (
                                932F5BE30822A1C700736975 /* All */,
                                932F5B3E0822A1C700736975 /* JavaScriptCore */,
index 279df7a28049984f643c50d91f2e828be86ff5f3..b2c75f9952b43aca9354d1e9ca141969009ba53c 100644 (file)
@@ -891,7 +891,10 @@ static Node* makeAssignNode(Node* loc, Operator op, Node* expr)
 
     if (loc->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(loc);
-        return new AssignResolveNode(resolve->identifier(), op, expr);
+        if (op == OpEqual)
+            return new AssignResolveNode(resolve->identifier(), expr);
+        else
+            return new ReadModifyResolveNode(resolve->identifier(), op, expr);
     }
     if (loc->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
@@ -909,15 +912,23 @@ static Node* makePrefixNode(Node* expr, Operator op)
     
     if (expr->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(expr);
-        return new PrefixResolveNode(resolve->identifier(), op);
+        if (op == OpPlusPlus)
+            return new PreIncResolveNode(resolve->identifier());
+        else
+            return new PreDecResolveNode(resolve->identifier());
     }
     if (expr->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
-        return new PrefixBracketNode(bracket->base(), bracket->subscript(), op);
+        if (op == OpPlusPlus)
+            return new PreIncBracketNode(bracket->base(), bracket->subscript());
+        else
+            return new PreDecBracketNode(bracket->base(), bracket->subscript());
     }
     ASSERT(expr->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
-    return new PrefixDotNode(dot->base(), dot->identifier(), op);
+    if (op == OpPlusPlus)
+        return new PreIncDotNode(dot->base(), dot->identifier());
+    return new PreDecDotNode(dot->base(), dot->identifier());
 }
 
 static Node* makePostfixNode(Node* expr, Operator op)
@@ -927,15 +938,24 @@ static Node* makePostfixNode(Node* expr, Operator op)
     
     if (expr->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(expr);
-        return new PostfixResolveNode(resolve->identifier(), op);
+        if (op == OpPlusPlus)
+            return new PostIncResolveNode(resolve->identifier());
+        else
+            return new PostDecResolveNode(resolve->identifier());
     }
     if (expr->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
-        return new PostfixBracketNode(bracket->base(), bracket->subscript(), op);
+        if (op == OpPlusPlus)
+            return new PostIncBracketNode(bracket->base(), bracket->subscript());
+        else
+            return new PostDecBracketNode(bracket->base(), bracket->subscript());
     }
     ASSERT(expr->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
-    return new PostfixDotNode(dot->base(), dot->identifier(), op);
+    
+    if (op == OpPlusPlus)
+        return new PostIncDotNode(dot->base(), dot->identifier());
+    return new PostDecDotNode(dot->base(), dot->identifier());
 }
 
 static Node* makeFunctionCallNode(Node* func, ArgumentsNode* args)
index 656d320428a791ac3b9a26af0693426161501338..c6310b96549c81d167d82adc84cb34dc31a983b5 100644 (file)
@@ -892,14 +892,15 @@ JSValue *FunctionCallDotNode::evaluate(ExecState *exec)
 
 // ------------------------------ PostfixResolveNode ----------------------------------
 
-void PostfixResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack&)
+// Increment
+void PostIncResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack&)
 {
     size_t index = functionBody->symbolTable().get(m_ident.ustring().rep());
     if (index != missingSymbolMarker())
-        new (this) LocalVarPostfixNode(index);
+        new (this) PostIncLocalVarNode(index);
 }
 
-JSValue *PostfixResolveNode::evaluate(ExecState *exec)
+JSValue *PostIncResolveNode::evaluate(ExecState *exec)
 {
   // Check for missed optimization opportunity.
   ASSERT(!canSkipLookup(exec, m_ident));
@@ -919,10 +920,58 @@ JSValue *PostfixResolveNode::evaluate(ExecState *exec)
         JSValue *v = slot.getValue(exec, base, m_ident);
 
         double n = v->toNumber(exec);
-        
-        double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-        base->put(exec, m_ident, jsNumber(newValue));
-        
+        base->put(exec, m_ident, jsNumber(n + 1));
+        return jsNumber(n);
+    }
+
+    ++iter;
+  } while (iter != end);
+
+  return throwUndefinedVariableError(exec, m_ident);
+}
+
+JSValue* PostIncLocalVarNode::evaluate(ExecState* exec)
+{
+    ActivationImp* variableObject = static_cast<ActivationImp*>(exec->variableObject());
+    ASSERT(variableObject->isActivation());
+    ASSERT(variableObject == exec->scopeChain().top());
+
+    JSValue** slot = &variableObject->localStorage()[index].value;
+    double n = (*slot)->toNumber(exec);
+    *slot = jsNumber(n + 1);
+    return jsNumber(n);
+}
+
+
+// Decrement
+void PostDecResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack&)
+{
+    size_t index = functionBody->symbolTable().get(m_ident.ustring().rep());
+    if (index != missingSymbolMarker())
+        new (this) PostDecLocalVarNode(index);
+}
+
+JSValue *PostDecResolveNode::evaluate(ExecState *exec)
+{
+  // Check for missed optimization opportunity.
+  ASSERT(!canSkipLookup(exec, m_ident));
+
+  const ScopeChain& chain = exec->scopeChain();
+  ScopeChainIterator iter = chain.begin();
+  ScopeChainIterator end = chain.end();
+  
+  // we must always have something in the scope chain
+  ASSERT(iter != end);
+
+  PropertySlot slot;
+  JSObject *base;
+  do { 
+    base = *iter;
+    if (base->getPropertySlot(exec, m_ident, slot)) {
+        JSValue *v = slot.getValue(exec, base, m_ident);
+
+        double n = v->toNumber(exec);
+        base->put(exec, m_ident, jsNumber(n - 1));
         return jsNumber(n);
     }
 
@@ -932,7 +981,7 @@ JSValue *PostfixResolveNode::evaluate(ExecState *exec)
   return throwUndefinedVariableError(exec, m_ident);
 }
 
-JSValue* LocalVarPostfixNode::evaluate(ExecState* exec)
+JSValue* PostDecLocalVarNode::evaluate(ExecState* exec)
 {
     ActivationImp* variableObject = static_cast<ActivationImp*>(exec->variableObject());
     ASSERT(variableObject->isActivation());
@@ -940,8 +989,7 @@ JSValue* LocalVarPostfixNode::evaluate(ExecState* exec)
 
     JSValue** slot = &variableObject->localStorage()[index].value;
     double n = (*slot)->toNumber(exec);
-    double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-    *slot = jsNumber(newValue);
+    *slot = jsNumber(n - 1);
     return jsNumber(n);
 }
 
@@ -953,7 +1001,7 @@ void PostfixBracketNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationSt
     nodeStack.append(m_base.get());
 }
 
-JSValue *PostfixBracketNode::evaluate(ExecState *exec)
+JSValue *PostIncBracketNode::evaluate(ExecState *exec)
 {
   JSValue *baseValue = m_base->evaluate(exec);
   KJS_CHECKEXCEPTIONVALUE
@@ -970,8 +1018,7 @@ JSValue *PostfixBracketNode::evaluate(ExecState *exec)
 
     double n = v->toNumber(exec);
 
-    double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-    base->put(exec, propertyIndex, jsNumber(newValue));
+    base->put(exec, propertyIndex, jsNumber(n + 1));
         
     return jsNumber(n);
   }
@@ -983,8 +1030,41 @@ JSValue *PostfixBracketNode::evaluate(ExecState *exec)
 
   double n = v->toNumber(exec);
   
-  double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-  base->put(exec, propertyName, jsNumber(newValue));
+  base->put(exec, propertyName, jsNumber(n + 1));
+        
+  return jsNumber(n);
+}
+
+JSValue *PostDecBracketNode::evaluate(ExecState *exec)
+{
+  JSValue *baseValue = m_base->evaluate(exec);
+  KJS_CHECKEXCEPTIONVALUE
+  JSValue *subscript = m_subscript->evaluate(exec);
+  KJS_CHECKEXCEPTIONVALUE
+
+  JSObject *base = baseValue->toObject(exec);
+
+  uint32_t propertyIndex;
+  if (subscript->getUInt32(propertyIndex)) {
+    PropertySlot slot;
+    JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+    KJS_CHECKEXCEPTIONVALUE
+
+    double n = v->toNumber(exec);
+
+    base->put(exec, propertyIndex, jsNumber(n - 1));
+        
+    return jsNumber(n);
+  }
+
+  Identifier propertyName(subscript->toString(exec));
+  PropertySlot slot;
+  JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+  KJS_CHECKEXCEPTIONVALUE
+
+  double n = v->toNumber(exec);
+  
+  base->put(exec, propertyName, jsNumber(n - 1));
         
   return jsNumber(n);
 }
@@ -996,7 +1076,7 @@ void PostfixDotNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks
     nodeStack.append(m_base.get());
 }
 
-JSValue *PostfixDotNode::evaluate(ExecState *exec)
+JSValue *PostIncDotNode::evaluate(ExecState *exec)
 {
   JSValue *baseValue = m_base->evaluate(exec);
   KJS_CHECKEXCEPTIONVALUE
@@ -1008,8 +1088,24 @@ JSValue *PostfixDotNode::evaluate(ExecState *exec)
 
   double n = v->toNumber(exec);
   
-  double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-  base->put(exec, m_ident, jsNumber(newValue));
+  base->put(exec, m_ident, jsNumber(n + 1));
+        
+  return jsNumber(n);
+}
+
+JSValue *PostDecDotNode::evaluate(ExecState *exec)
+{
+  JSValue *baseValue = m_base->evaluate(exec);
+  KJS_CHECKEXCEPTIONVALUE
+  JSObject *base = baseValue->toObject(exec);
+
+  PropertySlot slot;
+  JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+  KJS_CHECKEXCEPTIONVALUE
+
+  double n = v->toNumber(exec);
+  
+  base->put(exec, m_ident, jsNumber(n - 1));
         
   return jsNumber(n);
 }
@@ -1229,14 +1325,14 @@ JSValue *TypeOfValueNode::evaluate(ExecState *exec)
 
 // ------------------------------ PrefixResolveNode ----------------------------------
 
-void PrefixResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack&)
+void PreIncResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack&)
 {
     size_t index = functionBody->symbolTable().get(m_ident.ustring().rep());
     if (index != missingSymbolMarker())
-        new (this) LocalVarPrefixNode(index);
+        new (this) PreIncLocalVarNode(index);
 }
 
-JSValue* LocalVarPrefixNode::evaluate(ExecState* exec)
+JSValue* PreIncLocalVarNode::evaluate(ExecState* exec)
 {
     ActivationImp* variableObject = static_cast<ActivationImp*>(exec->variableObject());
     ASSERT(variableObject->isActivation());
@@ -1244,14 +1340,12 @@ JSValue* LocalVarPrefixNode::evaluate(ExecState* exec)
     JSValue* v = variableObject->localStorage()[m_index].value;
 
     double n = v->toNumber(exec);
-        
-    double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-    JSValue* n2 = jsNumber(newValue);
+    JSValue* n2 = jsNumber(n + 1);
     variableObject->localStorage()[m_index].value = n2;
     return n2;
 }
 
-JSValue *PrefixResolveNode::evaluate(ExecState *exec)
+JSValue *PreIncResolveNode::evaluate(ExecState *exec)
 {
   const ScopeChain& chain = exec->scopeChain();
   ScopeChainIterator iter = chain.begin();
@@ -1268,9 +1362,56 @@ JSValue *PrefixResolveNode::evaluate(ExecState *exec)
         JSValue *v = slot.getValue(exec, base, m_ident);
 
         double n = v->toNumber(exec);
-        
-        double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-        JSValue *n2 = jsNumber(newValue);
+        JSValue *n2 = jsNumber(n + 1);
+        base->put(exec, m_ident, n2);
+
+        return n2;
+    }
+
+    ++iter;
+  } while (iter != end);
+
+  return throwUndefinedVariableError(exec, m_ident);
+}
+
+void PreDecResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack&)
+{
+    size_t index = functionBody->symbolTable().get(m_ident.ustring().rep());
+    if (index != missingSymbolMarker())
+        new (this) PreDecLocalVarNode(index);
+}
+
+JSValue* PreDecLocalVarNode::evaluate(ExecState* exec)
+{
+    ActivationImp* variableObject = static_cast<ActivationImp*>(exec->variableObject());
+    ASSERT(variableObject->isActivation());
+    ASSERT(variableObject == exec->scopeChain().top());
+    JSValue* v = variableObject->localStorage()[m_index].value;
+
+    double n = v->toNumber(exec);
+    JSValue* n2 = jsNumber(n - 1);
+    variableObject->localStorage()[m_index].value = n2;
+    return n2;
+}
+
+JSValue *PreDecResolveNode::evaluate(ExecState *exec)
+{
+  const ScopeChain& chain = exec->scopeChain();
+  ScopeChainIterator iter = chain.begin();
+  ScopeChainIterator end = chain.end();
+  
+  // we must always have something in the scope chain
+  ASSERT(iter != end);
+
+  PropertySlot slot;
+  JSObject *base;
+  do { 
+    base = *iter;
+    if (base->getPropertySlot(exec, m_ident, slot)) {
+        JSValue *v = slot.getValue(exec, base, m_ident);
+
+        double n = v->toNumber(exec);
+        JSValue *n2 = jsNumber(n - 1);
         base->put(exec, m_ident, n2);
 
         return n2;
@@ -1290,7 +1431,7 @@ void PrefixBracketNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationSta
     nodeStack.append(m_base.get());
 }
 
-JSValue *PrefixBracketNode::evaluate(ExecState *exec)
+JSValue *PreIncBracketNode::evaluate(ExecState *exec)
 {
   JSValue *baseValue = m_base->evaluate(exec);
   KJS_CHECKEXCEPTIONVALUE
@@ -1305,10 +1446,39 @@ JSValue *PrefixBracketNode::evaluate(ExecState *exec)
     JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
     KJS_CHECKEXCEPTIONVALUE
 
-    double n = v->toNumber(exec);
+    JSValue *n2 = jsNumber(v->toNumber(exec) + 1);
+    base->put(exec, propertyIndex, n2);
 
-    double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-    JSValue *n2 = jsNumber(newValue);
+    return n2;
+  }
+
+  Identifier propertyName(subscript->toString(exec));
+  PropertySlot slot;
+  JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+  KJS_CHECKEXCEPTIONVALUE
+
+  JSValue *n2 = jsNumber(v->toNumber(exec) + 1);
+  base->put(exec, propertyName, n2);
+
+  return n2;
+}
+
+JSValue *PreDecBracketNode::evaluate(ExecState *exec)
+{
+  JSValue *baseValue = m_base->evaluate(exec);
+  KJS_CHECKEXCEPTIONVALUE
+  JSValue *subscript = m_subscript->evaluate(exec);
+  KJS_CHECKEXCEPTIONVALUE
+
+  JSObject *base = baseValue->toObject(exec);
+
+  uint32_t propertyIndex;
+  if (subscript->getUInt32(propertyIndex)) {
+    PropertySlot slot;
+    JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+    KJS_CHECKEXCEPTIONVALUE
+
+    JSValue *n2 = jsNumber(v->toNumber(exec) - 1);
     base->put(exec, propertyIndex, n2);
 
     return n2;
@@ -1319,10 +1489,7 @@ JSValue *PrefixBracketNode::evaluate(ExecState *exec)
   JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
 
-  double n = v->toNumber(exec);
-  
-  double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-  JSValue *n2 = jsNumber(newValue);
+  JSValue *n2 = jsNumber(v->toNumber(exec) - 1);
   base->put(exec, propertyName, n2);
 
   return n2;
@@ -1335,7 +1502,7 @@ void PrefixDotNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks:
     nodeStack.append(m_base.get());
 }
 
-JSValue *PrefixDotNode::evaluate(ExecState *exec)
+JSValue *PreIncDotNode::evaluate(ExecState *exec)
 {
   JSValue *baseValue = m_base->evaluate(exec);
   KJS_CHECKEXCEPTIONVALUE
@@ -1346,9 +1513,24 @@ JSValue *PrefixDotNode::evaluate(ExecState *exec)
   KJS_CHECKEXCEPTIONVALUE
 
   double n = v->toNumber(exec);
-  
-  double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
-  JSValue *n2 = jsNumber(newValue);
+  JSValue *n2 = jsNumber(n + 1);
+  base->put(exec, m_ident, n2);
+
+  return n2;
+}
+
+JSValue *PreDecDotNode::evaluate(ExecState *exec)
+{
+  JSValue *baseValue = m_base->evaluate(exec);
+  KJS_CHECKEXCEPTIONVALUE
+  JSObject *base = baseValue->toObject(exec);
+
+  PropertySlot slot;
+  JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+  KJS_CHECKEXCEPTIONVALUE
+
+  double n = v->toNumber(exec);
+  JSValue *n2 = jsNumber(n - 1);
   base->put(exec, m_ident, n2);
 
   return n2;
@@ -1998,17 +2180,25 @@ static ALWAYS_INLINE JSValue *valueForReadModifyAssignment(ExecState * exec, JSV
   return v;
 }
 
-// ------------------------------ AssignResolveNode -----------------------------------
+// ------------------------------ ReadModifyResolveNode -----------------------------------
+
+void ReadModifyResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack& nodeStack)
+{
+    nodeStack.append(m_right.get());
+    size_t index = functionBody->symbolTable().get(m_ident.ustring().rep());
+    if (index != missingSymbolMarker())
+        new (this) ReadModifyLocalVarNode(index);
+}
 
 void AssignResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, DeclarationStacks::NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     size_t index = functionBody->symbolTable().get(m_ident.ustring().rep());
     if (index != missingSymbolMarker())
-        new (this) LocalVarAssignNode(index);
+        new (this) AssignLocalVarNode(index);
 }
 
-JSValue* LocalVarAssignNode::evaluate(ExecState* exec)
+JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
 {
     ActivationImp* variableObject = static_cast<ActivationImp*>(exec->variableObject());
     ASSERT(variableObject->isActivation());
@@ -2029,7 +2219,21 @@ JSValue* LocalVarAssignNode::evaluate(ExecState* exec)
     return v;
 }
 
-JSValue *AssignResolveNode::evaluate(ExecState *exec)
+JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
+{
+    ActivationImp* variableObject = static_cast<ActivationImp*>(exec->variableObject());
+    ASSERT(variableObject->isActivation());
+    ASSERT(variableObject == exec->scopeChain().top());
+    JSValue* v = m_right->evaluate(exec);
+
+    KJS_CHECKEXCEPTIONVALUE
+
+    variableObject->localStorage()[m_index].value = v;
+    
+    return v;
+}
+
+JSValue *ReadModifyResolveNode::evaluate(ExecState *exec)
 {
   const ScopeChain& chain = exec->scopeChain();
   ScopeChainIterator iter = chain.begin();
@@ -2069,6 +2273,34 @@ JSValue *AssignResolveNode::evaluate(ExecState *exec)
   return v;
 }
 
+JSValue *AssignResolveNode::evaluate(ExecState *exec)
+{
+  const ScopeChain& chain = exec->scopeChain();
+  ScopeChainIterator iter = chain.begin();
+  ScopeChainIterator end = chain.end();
+  
+  // we must always have something in the scope chain
+  ASSERT(iter != end);
+
+  PropertySlot slot;
+  JSObject *base;
+  do { 
+    base = *iter;
+    if (base->getPropertySlot(exec, m_ident, slot))
+      goto found;
+
+    ++iter;
+  } while (iter != end);
+
+ found:
+  JSValue *v = m_right->evaluate(exec);
+
+  KJS_CHECKEXCEPTIONVALUE
+
+  base->put(exec, m_ident, v);
+  return v;
+}
+
 // ------------------------------ AssignDotNode -----------------------------------
 
 void AssignDotNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
index 58b24f66405570e001cede5832ec1309d5cd8ab1..534a79118a36b339c2c1b110248e04ef450d902c 100644 (file)
@@ -538,11 +538,11 @@ namespace KJS {
     RefPtr<ArgumentsNode> args;
   };
 
-  class PostfixResolveNode : public Node {
+  class PostIncResolveNode : public Node {
   public:
-    PostfixResolveNode(const Identifier& i, Operator o) KJS_FAST_CALL : m_ident(i), m_oper(o) {}
+    PostIncResolveNode(const Identifier& i) KJS_FAST_CALL : m_ident(i) {}
 
-    PostfixResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
+    PostIncResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
         : Node(PlacementNewAdopt)
         , m_ident(PlacementNewAdopt)
     {
@@ -555,14 +555,13 @@ namespace KJS {
 
   protected:
     Identifier m_ident;
-    Operator m_oper;
     size_t index; // Used by LocalVarPostfixNode.
   };
 
-  class LocalVarPostfixNode : public PostfixResolveNode {
+  class PostIncLocalVarNode : public PostIncResolveNode {
   public:
-    LocalVarPostfixNode(size_t i) KJS_FAST_CALL
-        : PostfixResolveNode(PlacementNewAdopt)
+    PostIncLocalVarNode(size_t i) KJS_FAST_CALL
+        : PostIncResolveNode(PlacementNewAdopt)
     {
         ASSERT(i != missingSymbolMarker());
         index = i;
@@ -571,30 +570,92 @@ namespace KJS {
     JSValue* evaluate(ExecState*) KJS_FAST_CALL;
   };
 
-  class PostfixBracketNode : public Node {
+  class PostDecResolveNode : public Node {
   public:
-    PostfixBracketNode(Node *b, Node *s, Operator o) KJS_FAST_CALL : m_base(b), m_subscript(s), m_oper(o) {}
+    PostDecResolveNode(const Identifier& i) KJS_FAST_CALL : m_ident(i) {}
+
+    PostDecResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
+        : Node(PlacementNewAdopt)
+        , m_ident(PlacementNewAdopt)
+    {
+    }
+
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
     JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
-  private:
+
+  protected:
+    Identifier m_ident;
+    size_t index; // Used by LocalVarPostfixNode.
+  };
+
+  class PostDecLocalVarNode : public PostDecResolveNode {
+  public:
+    PostDecLocalVarNode(size_t i) KJS_FAST_CALL
+        : PostDecResolveNode(PlacementNewAdopt)
+    {
+        ASSERT(i != missingSymbolMarker());
+        index = i;
+    }
+
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
+  class PostfixBracketNode : public Node {
+  public:
+    PostfixBracketNode(Node *b, Node *s) KJS_FAST_CALL : m_base(b), m_subscript(s) {}
+    virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+    virtual Precedence precedence() const { return PrecPostfix; }
+  protected:
+    virtual bool isIncrement() const = 0;
     RefPtr<Node> m_base;
     RefPtr<Node> m_subscript;
-    Operator m_oper;
+  };
+
+  class PostIncBracketNode : public PostfixBracketNode {
+  public:
+    PostIncBracketNode(Node *b, Node *s) KJS_FAST_CALL : PostfixBracketNode(b, s) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    virtual bool isIncrement() const { return true; }
+  };
+
+  class PostDecBracketNode : public PostfixBracketNode {
+  public:
+    PostDecBracketNode(Node *b, Node *s) KJS_FAST_CALL : PostfixBracketNode(b, s) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    virtual bool isIncrement() const { return false; }
   };
 
   class PostfixDotNode : public Node {
   public:
-    PostfixDotNode(Node *b, const Identifier& i, Operator o) KJS_FAST_CALL : m_base(b), m_ident(i), m_oper(o) {}
+    PostfixDotNode(Node *b, const Identifier& i) KJS_FAST_CALL : m_base(b), m_ident(i) {}
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
-  private:
+  protected:
+    virtual bool isIncrement() const = 0;
     RefPtr<Node> m_base;
     Identifier m_ident;
-    Operator m_oper;
+  };
+
+  class PostIncDotNode : public PostfixDotNode {
+  public:
+    PostIncDotNode(Node *b, const Identifier& i) KJS_FAST_CALL : PostfixDotNode(b, i) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    virtual bool isIncrement() const { return true; }
+  };
+
+  class PostDecDotNode : public PostfixDotNode {
+  public:
+    PostDecDotNode(Node *b, const Identifier& i) KJS_FAST_CALL : PostfixDotNode(b, i) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    virtual bool isIncrement() const { return false; }
   };
 
   class PostfixErrorNode : public Node {
@@ -730,15 +791,14 @@ namespace KJS {
     RefPtr<Node> m_expr;
   };
 
-  class PrefixResolveNode : public Node {
+  class PreIncResolveNode : public Node {
   public:
-    PrefixResolveNode(const Identifier &s, Operator o) KJS_FAST_CALL 
+    PreIncResolveNode(const Identifier &s) KJS_FAST_CALL 
         : m_ident(s) 
-        , m_oper(o) 
     { 
     }
     
-    PrefixResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
+    PreIncResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
         : Node(PlacementNewAdopt)
         , m_ident(PlacementNewAdopt) 
     {
@@ -752,14 +812,13 @@ namespace KJS {
 
   protected:
     Identifier m_ident;
-    Operator m_oper;
     size_t m_index; // Used by LocalVarPrefixNode.
   };
 
-  class LocalVarPrefixNode : public PrefixResolveNode {
+  class PreIncLocalVarNode : public PreIncResolveNode {
   public:
-    LocalVarPrefixNode(size_t i) KJS_FAST_CALL 
-        : PrefixResolveNode(PlacementNewAdopt)
+    PreIncLocalVarNode(size_t i) KJS_FAST_CALL 
+        : PreIncResolveNode(PlacementNewAdopt)
     { 
         ASSERT(i != missingSymbolMarker());
         m_index = i;
@@ -767,31 +826,98 @@ namespace KJS {
     
     JSValue* evaluate(ExecState*) KJS_FAST_CALL;
   };
+  
+  class PreDecResolveNode : public Node {
+  public:
+    PreDecResolveNode(const Identifier &s) KJS_FAST_CALL 
+        : m_ident(s) 
+    { 
+    }
+    
+    PreDecResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
+        : Node(PlacementNewAdopt)
+        , m_ident(PlacementNewAdopt) 
+    {
+    }
+    
+    virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+    virtual Precedence precedence() const { return PrecUnary; }
 
+  protected:
+    Identifier m_ident;
+    size_t m_index; // Used by LocalVarPrefixNode.
+  };
+
+  class PreDecLocalVarNode : public PreDecResolveNode {
+  public:
+    PreDecLocalVarNode(size_t i) KJS_FAST_CALL 
+        : PreDecResolveNode(PlacementNewAdopt)
+    { 
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+  
   class PrefixBracketNode : public Node {
   public:
-    PrefixBracketNode(Node *b, Node *s, Operator o) KJS_FAST_CALL : m_base(b), m_subscript(s), m_oper(o) {}
+    PrefixBracketNode(Node *b, Node *s) KJS_FAST_CALL : m_base(b), m_subscript(s) {}
+    
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
-  private:
+  protected:
+    virtual bool isIncrement() const = 0;
     RefPtr<Node> m_base;
     RefPtr<Node> m_subscript;
-    Operator m_oper;
+  };
+  
+  class PreIncBracketNode : public PrefixBracketNode {
+  public:
+    PreIncBracketNode(Node *b, Node *s) KJS_FAST_CALL : PrefixBracketNode(b, s) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    bool isIncrement() const { return true; }
+  };
+  
+  class PreDecBracketNode : public PrefixBracketNode {
+  public:
+    PreDecBracketNode(Node *b, Node *s) KJS_FAST_CALL : PrefixBracketNode(b, s) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    bool isIncrement() const { return false; }
   };
 
   class PrefixDotNode : public Node {
   public:
-    PrefixDotNode(Node *b, const Identifier& i, Operator o) KJS_FAST_CALL : m_base(b), m_ident(i), m_oper(o) {}
+    PrefixDotNode(Node *b, const Identifier& i) KJS_FAST_CALL : m_base(b), m_ident(i) {}
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-    virtual Precedence precedence() const { return PrecUnary; }
-  private:
+    virtual Precedence precedence() const { return PrecPostfix; }
+  protected:
+    virtual bool isIncrement() const = 0;
     RefPtr<Node> m_base;
     Identifier m_ident;
-    Operator m_oper;
+  };
+
+  class PreIncDotNode : public PrefixDotNode {
+  public:
+    PreIncDotNode(Node *b, const Identifier& i) KJS_FAST_CALL : PrefixDotNode(b, i) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    virtual bool isIncrement() const { return true; }
+  };
+
+  class PreDecDotNode : public PrefixDotNode {
+  public:
+    PreDecDotNode(Node *b, const Identifier& i) KJS_FAST_CALL : PrefixDotNode(b, i) {}
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  protected:
+    virtual bool isIncrement() const { return false; }
   };
 
   class PrefixErrorNode : public Node {
@@ -1163,16 +1289,16 @@ namespace KJS {
     RefPtr<Node> expr2;
   };
 
-  class AssignResolveNode : public Node {
+  class ReadModifyResolveNode : public Node {
   public:
-    AssignResolveNode(const Identifier &ident, Operator oper, Node *right) KJS_FAST_CALL
+    ReadModifyResolveNode(const Identifier &ident, Operator oper, Node *right) KJS_FAST_CALL
       : m_ident(ident)
       , m_oper(oper)
       , m_right(right) 
       {
       }
 
-    AssignResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
+    ReadModifyResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
       : Node(PlacementNewAdopt)
       , m_ident(PlacementNewAdopt) 
       , m_right(PlacementNewAdopt) 
@@ -1187,12 +1313,49 @@ namespace KJS {
     Identifier m_ident;
     Operator m_oper;
     RefPtr<Node> m_right;
-    size_t m_index; // Used by LocalVarAssignNode.
+    size_t m_index; // Used by ReadModifyLocalVarNode.
+  };
+
+  class ReadModifyLocalVarNode : public ReadModifyResolveNode {
+  public:
+    ReadModifyLocalVarNode(size_t i) KJS_FAST_CALL 
+        : ReadModifyResolveNode(PlacementNewAdopt)
+    { 
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
+  class AssignResolveNode : public Node {
+  public:
+     AssignResolveNode(const Identifier &ident, Node *right) KJS_FAST_CALL
+      : m_ident(ident)
+      , m_right(right) 
+      {
+      }
+
+    AssignResolveNode(PlacementNewAdoptType) KJS_FAST_CALL 
+      : Node(PlacementNewAdopt)
+      , m_ident(PlacementNewAdopt) 
+      , m_right(PlacementNewAdopt) 
+    {
+    }
+
+    virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+    virtual Precedence precedence() const { return PrecAssignment; }
+  protected:
+    Identifier m_ident;
+    RefPtr<Node> m_right;
+    size_t m_index; // Used by ReadModifyLocalVarNode.
   };
 
-  class LocalVarAssignNode : public AssignResolveNode {
+  class AssignLocalVarNode : public AssignResolveNode {
   public:
-    LocalVarAssignNode(size_t i) KJS_FAST_CALL 
+    AssignLocalVarNode(size_t i) KJS_FAST_CALL 
         : AssignResolveNode(PlacementNewAdopt)
     { 
         ASSERT(i != missingSymbolMarker());
index 8c4f86b77531680af6d05594ec74200250233e91..41a87a03233a176aa7f20300a6060d12e466ee07 100644 (file)
@@ -413,19 +413,20 @@ void FunctionCallDotNode::streamTo(SourceStream& s) const
     s << DotExpr << PrecCall << base << "." << ident << args;
 }
 
-void PostfixResolveNode::streamTo(SourceStream& s) const
+void PostIncResolveNode::streamTo(SourceStream& s) const
 {
-    s << m_ident;
-    if (m_oper == OpPlusPlus)
-        s << "++";
-    else
-        s << "--";
+    s << m_ident << "++";
+}
+
+void PostDecResolveNode::streamTo(SourceStream& s) const
+{
+    s << m_ident << "--";
 }
 
 void PostfixBracketNode::streamTo(SourceStream& s) const
 {
     s << PrecCall << m_base << "[" << m_subscript << "]";
-    if (m_oper == OpPlusPlus)
+    if (isIncrement())
         s << "++";
     else
         s << "--";
@@ -434,7 +435,7 @@ void PostfixBracketNode::streamTo(SourceStream& s) const
 void PostfixDotNode::streamTo(SourceStream& s) const
 {
     s << DotExpr << PrecCall << m_base << "." << m_ident;
-    if (m_oper == OpPlusPlus)
+    if (isIncrement())
         s << "++";
     else
         s << "--";
@@ -484,18 +485,19 @@ void TypeOfResolveNode::streamTo(SourceStream& s) const
     s << "typeof " << m_ident;
 }
 
-void PrefixResolveNode::streamTo(SourceStream& s) const
+void PreIncResolveNode::streamTo(SourceStream& s) const
 {
-    if (m_oper == OpPlusPlus)
-        s << "++";
-    else
-        s << "--";
-    s << m_ident;
+    s << "++" << m_ident;
+}
+
+void PreDecResolveNode::streamTo(SourceStream& s) const
+{
+    s << "--" << m_ident;
 }
 
 void PrefixBracketNode::streamTo(SourceStream& s) const
 {
-    if (m_oper == OpPlusPlus)
+    if (isIncrement())
         s << "++";
     else
         s << "--";
@@ -504,7 +506,7 @@ void PrefixBracketNode::streamTo(SourceStream& s) const
 
 void PrefixDotNode::streamTo(SourceStream& s) const
 {
-    if (m_oper == OpPlusPlus)
+    if (isIncrement())
         s << "++";
     else
         s << "--";
@@ -661,11 +663,16 @@ void ConditionalNode::streamTo(SourceStream& s) const
         << " : " << PrecAssignment << expr2;
 }
 
-void AssignResolveNode::streamTo(SourceStream& s) const
+void ReadModifyResolveNode::streamTo(SourceStream& s) const
 {
     s << m_ident << ' ' << operatorString(m_oper) << ' ' << PrecAssignment << m_right;
 }
 
+void AssignResolveNode::streamTo(SourceStream& s) const
+{
+    s << m_ident << " = " << PrecAssignment << m_right;
+}
+
 void AssignBracketNode::streamTo(SourceStream& s) const
 {
     s << PrecCall << m_base << '[' << m_subscript << "] "