2007-11-07 Eric Seidel <eric@webkit.org>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Nov 2007 07:58:15 +0000 (07:58 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Nov 2007 07:58:15 +0000 (07:58 +0000)
        Reviewed by Darin and Oliver.

        Add evaluateToNumber parallel evaluation tree to speed up number operations.
        Make ImmediateNumberNode a subclass of NumberNode.
        Share evaluate logic between evaluate and evaluateToNumber using inline functions
        There is still a lot of improvement to be made here.

        SunSpider claims this is a 1.0% speedup overall (nbody 7.9%), base64 slowing 2.0%
        Given the huge win that this prepares us for with simple type inferencing I see the small
        regression in base64 being worth the substantial overall improvement.

        * kjs/grammar.y:
        * kjs/nodes.cpp:
        (KJS::Node::evaluateToNumber):
        (KJS::NumberNode::evaluate):
        (KJS::NumberNode::evaluateToNumber):
        (KJS::StringNode::evaluateToNumber):
        (KJS::LocalVarAccessNode::inlineEvaluate):
        (KJS::LocalVarAccessNode::evaluate):
        (KJS::LocalVarAccessNode::evaluateToNumber):
        (KJS::BracketAccessorNode::inlineEvaluate):
        (KJS::BracketAccessorNode::evaluate):
        (KJS::BracketAccessorNode::evaluateToNumber):
        (KJS::NegateNode::evaluate):
        (KJS::NegateNode::evaluateToNumber):
        (KJS::MultNode::inlineEvaluateToNumber):
        (KJS::MultNode::evaluate):
        (KJS::MultNode::evaluateToNumber):
        (KJS::DivNode::inlineEvaluateToNumber):
        (KJS::DivNode::evaluate):
        (KJS::DivNode::evaluateToNumber):
        (KJS::ModNode::inlineEvaluateToNumber):
        (KJS::ModNode::evaluate):
        (KJS::ModNode::evaluateToNumber):
        (KJS::throwOutOfMemoryErrorToNumber):
        (KJS::addSlowCaseToNumber):
        (KJS::add):
        (KJS::addToNumber):
        (KJS::AddNode::evaluateToNumber):
        (KJS::SubNode::inlineEvaluateToNumber):
        (KJS::SubNode::evaluate):
        (KJS::SubNode::evaluateToNumber):
        (KJS::valueForReadModifyAssignment):
        (KJS::ReadModifyLocalVarNode::evaluate):
        (KJS::ReadModifyResolveNode::evaluate):
        (KJS::ReadModifyDotNode::evaluate):
        (KJS::ReadModifyBracketNode::evaluate):
        * kjs/nodes.h:
        (KJS::Node::):
        (KJS::NumberNode::):
        (KJS::ImmediateNumberNode::):
        (KJS::AddNode::precedence):
        * kjs/nodes2string.cpp:
        (KJS::NumberNode::streamTo):

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

JavaScriptCore/ChangeLog
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp

index 52560b283d0c52995f237262615577dc40dd8421..9316fbfcddc67d20c6c07ccea51764b325e520f0 100644 (file)
@@ -1,3 +1,60 @@
+2007-11-07  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Darin and Oliver.
+        
+        Add evaluateToNumber parallel evaluation tree to speed up number operations.
+        Make ImmediateNumberNode a subclass of NumberNode.
+        Share evaluate logic between evaluate and evaluateToNumber using inline functions
+        There is still a lot of improvement to be made here.
+        
+        SunSpider claims this is a 1.0% speedup overall (nbody 7.9%), base64 slowing 2.0%
+        Given the huge win that this prepares us for with simple type inferencing I see the small
+        regression in base64 being worth the substantial overall improvement.
+
+        * kjs/grammar.y:
+        * kjs/nodes.cpp:
+        (KJS::Node::evaluateToNumber):
+        (KJS::NumberNode::evaluate):
+        (KJS::NumberNode::evaluateToNumber):
+        (KJS::StringNode::evaluateToNumber):
+        (KJS::LocalVarAccessNode::inlineEvaluate):
+        (KJS::LocalVarAccessNode::evaluate):
+        (KJS::LocalVarAccessNode::evaluateToNumber):
+        (KJS::BracketAccessorNode::inlineEvaluate):
+        (KJS::BracketAccessorNode::evaluate):
+        (KJS::BracketAccessorNode::evaluateToNumber):
+        (KJS::NegateNode::evaluate):
+        (KJS::NegateNode::evaluateToNumber):
+        (KJS::MultNode::inlineEvaluateToNumber):
+        (KJS::MultNode::evaluate):
+        (KJS::MultNode::evaluateToNumber):
+        (KJS::DivNode::inlineEvaluateToNumber):
+        (KJS::DivNode::evaluate):
+        (KJS::DivNode::evaluateToNumber):
+        (KJS::ModNode::inlineEvaluateToNumber):
+        (KJS::ModNode::evaluate):
+        (KJS::ModNode::evaluateToNumber):
+        (KJS::throwOutOfMemoryErrorToNumber):
+        (KJS::addSlowCaseToNumber):
+        (KJS::add):
+        (KJS::addToNumber):
+        (KJS::AddNode::evaluateToNumber):
+        (KJS::SubNode::inlineEvaluateToNumber):
+        (KJS::SubNode::evaluate):
+        (KJS::SubNode::evaluateToNumber):
+        (KJS::valueForReadModifyAssignment):
+        (KJS::ReadModifyLocalVarNode::evaluate):
+        (KJS::ReadModifyResolveNode::evaluate):
+        (KJS::ReadModifyDotNode::evaluate):
+        (KJS::ReadModifyBracketNode::evaluate):
+        * kjs/nodes.h:
+        (KJS::Node::):
+        (KJS::NumberNode::):
+        (KJS::ImmediateNumberNode::):
+        (KJS::AddNode::precedence):
+        * kjs/nodes2string.cpp:
+        (KJS::NumberNode::streamTo):
+
 2007-11-07  Mark Rowe  <mrowe@apple.com>
 
         Reviewed by Eric.
index 1baa7f9fbce797ca7a1422a731c615c3f239922c..aa9c9eee99ca62d54607640c067aaaf58a15f5af 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
  *  Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -1020,7 +1021,7 @@ static PropertyNode* makeGetterOrSetterPropertyNode(const Identifier& getOrSet,
     return new PropertyNode(name, new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, body, params), type);
 }
 
-static Node* makeNegateNode(Node *n)
+static Node* makeNegateNode(Noden)
 {
     if (n->isNumber()) {
         NumberNode* number = static_cast<NumberNode*>(n);
@@ -1029,13 +1030,6 @@ static Node* makeNegateNode(Node *n)
             number->setValue(-number->value());
             return number;
         }
-    } else if (n->isImmediateValue()) {
-        ImmediateNumberNode* number = static_cast<ImmediateNumberNode*>(n);
-        double value = number->value();
-        if (value > 0.0) {
-            number->setValue(-value);
-            return number;
-        }
     }
 
     return new NegateNode(n);
@@ -1045,7 +1039,7 @@ static Node* makeNumberNode(double d)
 {
     JSValue* value = JSImmediate::fromDouble(d);
     if (value)
-        return new ImmediateNumberNode(value);
+        return new ImmediateNumberNode(value, d);
     return new NumberNode(d);
 }
 
index 6368152f74bcfaf778bce359ef1017638ea2b61d..fa88e8db77cc4ee364652c02279178e147039f63 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
  *  Copyright (C) 2007 Maks Orlovich
+ *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -55,6 +56,12 @@ namespace KJS {
     return jsUndefined(); \
   }
 
+#define KJS_CHECKEXCEPTIONNUMBER \
+  if (exec->hadException()) { \
+    handleException(exec); \
+    return 0.0; \
+  }
+
 #define KJS_CHECKEXCEPTIONLIST \
   if (exec->hadException()) { \
     handleException(exec); \
@@ -196,6 +203,14 @@ void Node::clearNewNodes()
     newNodes = 0;
 }
 
+double Node::evaluateToNumber(ExecState* exec)
+{
+    JSValue* value = evaluate(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    // No need to check exception after toNumber, caller will do so right after evaluateToNumber() call
+    return value->toNumber(exec);
+}
+
 static void substitute(UString &string, const UString &substring) KJS_FAST_CALL;
 static void substitute(UString &string, const UString &substring)
 {
@@ -360,10 +375,15 @@ JSValue *BooleanNode::evaluate(ExecState *)
 
 // ------------------------------ NumberNode -----------------------------------
 
-JSValue *NumberNode::evaluate(ExecState *)
+JSValue* NumberNode::evaluate(ExecState*)
 {
     // Number nodes are only created when the number can't fit in a JSImmediate, so no need to check again.
-    return jsNumberCell(val);
+    return jsNumberCell(m_double);
+}
+    
+double NumberNode::evaluateToNumber(ExecState*)
+{
+    return m_double;
 }
 
 JSValue* ImmediateNumberNode::evaluate(ExecState*)
@@ -377,7 +397,12 @@ JSValue *StringNode::evaluate(ExecState *)
 {
   return jsOwnedString(value);
 }
-
+    
+double StringNode::evaluateToNumber(ExecState*)
+{
+    return value.toDouble();
+}
+    
 // ------------------------------ RegExpNode -----------------------------------
 
 JSValue *RegExpNode::evaluate(ExecState *exec)
@@ -433,13 +458,23 @@ void ResolveNode::optimizeVariableAccess(FunctionBodyNode* functionBody, Declara
         new (this) LocalVarAccessNode(index);
 }
 
-JSValue* LocalVarAccessNode::evaluate(ExecState* exec)
+JSValue* LocalVarAccessNode::inlineEvaluate(ExecState* exec)
 {
     ASSERT(static_cast<ActivationImp*>(exec->variableObject())->isActivation());
     ASSERT(static_cast<ActivationImp*>(exec->variableObject()) == exec->scopeChain().top());
     return exec->localStorage()[index].value;
 }
 
+JSValue* LocalVarAccessNode::evaluate(ExecState* exec)
+{
+    return inlineEvaluate(exec);
+}
+
+double LocalVarAccessNode::evaluateToNumber(ExecState* exec)
+{
+    return inlineEvaluate(exec)->toNumber(exec);
+}
+
 // ------------------------------ ElementNode ----------------------------------
 
 void ElementNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
@@ -571,19 +606,29 @@ void BracketAccessorNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationS
 }
 
 // ECMA 11.2.1a
-JSValue *BracketAccessorNode::evaluate(ExecState *exec)
+JSValue* BracketAccessorNode::inlineEvaluate(ExecState* exec)
 {
-  JSValue *v1 = expr1->evaluate(exec);
+  JSValuev1 = expr1->evaluate(exec);
   KJS_CHECKEXCEPTIONVALUE
-  JSValue *v2 = expr2->evaluate(exec);
+  JSValuev2 = expr2->evaluate(exec);
   KJS_CHECKEXCEPTIONVALUE
-  JSObject *o = v1->toObject(exec);
+  JSObjecto = v1->toObject(exec);
   uint32_t i;
   if (v2->getUInt32(i))
     return o->get(exec, i);
   return o->get(exec, Identifier(v2->toString(exec)));
 }
 
+JSValue* BracketAccessorNode::evaluate(ExecState* exec)
+{
+    return inlineEvaluate(exec);
+}
+
+double BracketAccessorNode::evaluateToNumber(ExecState* exec)
+{
+    return inlineEvaluate(exec)->toNumber(exec);
+}
+
 // ------------------------------ DotAccessorNode --------------------------------
 
 void DotAccessorNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
@@ -1579,11 +1624,14 @@ void NegateNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::No
 // ECMA 11.4.7
 JSValue *NegateNode::evaluate(ExecState *exec)
 {
-  JSValue *v = expr->evaluate(exec);
-  KJS_CHECKEXCEPTIONVALUE
+    // No need to check exception, caller will do so right after evaluate()
+    return jsNumber(-expr->evaluateToNumber(exec));
+}
 
-  double n = v->toNumber(exec);
-  return jsNumber(-n);
+double NegateNode::evaluateToNumber(ExecState* exec)
+{
+    // No need to check exception, caller will do so right after evaluateToNumber()
+    return -expr->evaluateToNumber(exec);
 }
 
 // ------------------------------ BitwiseNotNode -------------------------------
@@ -1625,15 +1673,25 @@ void MultNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::Node
 }
 
 // ECMA 11.5.1
-JSValue *MultNode::evaluate(ExecState *exec)
+double MultNode::inlineEvaluateToNumber(ExecState* exec)
 {
-    JSValue *v1 = term1->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
-        
-    JSValue *v2 = term2->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
+    double n1 = term1->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    double n2 = term2->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    return n1 * n2;
+}
 
-    return jsNumber(v1->toNumber(exec) * v2->toNumber(exec));
+JSValue *MultNode::evaluate(ExecState* exec)
+{
+    return jsNumber(inlineEvaluateToNumber(exec));
+}
+    
+double MultNode::evaluateToNumber(ExecState* exec)
+{
+    return inlineEvaluateToNumber(exec);
 }
 
 void DivNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
@@ -1643,15 +1701,25 @@ void DivNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeS
 }
 
 // ECMA 11.5.2
-JSValue *DivNode::evaluate(ExecState *exec)
+double DivNode::inlineEvaluateToNumber(ExecState* exec)
 {
-    JSValue *v1 = term1->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
-        
-    JSValue *v2 = term2->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
+    double n1 = term1->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    double n2 = term2->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    return n1 / n2;
+}
 
-    return jsNumber(v1->toNumber(exec) / v2->toNumber(exec));
+JSValue* DivNode::evaluate(ExecState* exec)
+{
+    return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double DivNode::evaluateToNumber(ExecState* exec)
+{
+    return inlineEvaluateToNumber(exec);
 }
 
 void ModNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
@@ -1661,15 +1729,25 @@ void ModNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeS
 }
 
 // ECMA 11.5.3
-JSValue *ModNode::evaluate(ExecState *exec)
+double ModNode::inlineEvaluateToNumber(ExecState* exec)
 {
-    JSValue *v1 = term1->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
-        
-    JSValue *v2 = term2->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
+    double n1 = term1->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    double n2 = term2->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    return fmod(n1, n2);
+}
+
+JSValue* ModNode::evaluate(ExecState* exec)
+{
+    return jsNumber(inlineEvaluateToNumber(exec));
+}
 
-    return jsNumber(fmod(v1->toNumber(exec), v2->toNumber(exec)));
+double ModNode::evaluateToNumber(ExecState* exec)
+{
+    return inlineEvaluateToNumber(exec);
 }
 
 // ------------------------------ Additive Nodes --------------------------------------
@@ -1681,6 +1759,13 @@ static JSValue* throwOutOfMemoryError(ExecState* exec)
     return error;
 }
 
+static double throwOutOfMemoryErrorToNumber(ExecState* exec)
+{
+    JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+    exec->setException(error);
+    return 0.0;
+}    
+
 // ECMA 11.6
 static JSValue* addSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
 {
@@ -1698,6 +1783,22 @@ static JSValue* addSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
     return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
 }
 
+static double addSlowCaseToNumber(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+    // exception for the Date exception in defaultValue()
+    JSValue *p1 = v1->toPrimitive(exec, UnspecifiedType);
+    JSValue *p2 = v2->toPrimitive(exec, UnspecifiedType);
+    
+    if (p1->isString() || p2->isString()) {
+        UString value = p1->toString(exec) + p2->toString(exec);
+        if (value.isNull())
+            return throwOutOfMemoryErrorToNumber(exec);
+        return value.toDouble();
+    }
+    
+    return p1->toNumber(exec) + p2->toNumber(exec);
+}
+
 // Fast-path choices here are based on frequency data from SunSpider:
 //    <times> Add case: <t1> <t2>
 //    ---------------------------
@@ -1716,7 +1817,7 @@ static inline JSValue* add(ExecState* exec, JSValue* v1, JSValue *v2)
     
     if (bothTypes == ((NumberType << 3) | NumberType))
         return jsNumber(v1->toNumber(exec) + v2->toNumber(exec));
-    else if (bothTypes == ((StringType << 3) | StringType)) {
+    if (bothTypes == ((StringType << 3) | StringType)) {
         UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
         if (value.isNull())
             return throwOutOfMemoryError(exec);
@@ -1727,6 +1828,25 @@ static inline JSValue* add(ExecState* exec, JSValue* v1, JSValue *v2)
     return addSlowCase(exec, v1, v2);
 }
 
+static inline double addToNumber(ExecState* exec, JSValue* v1, JSValue *v2)
+{
+    JSType t1 = v1->type();
+    JSType t2 = v2->type();
+    const unsigned bothTypes = (t1 << 3) | t2;
+    
+    if (bothTypes == ((NumberType << 3) | NumberType))
+        return v1->toNumber(exec) + v2->toNumber(exec);
+    if (bothTypes == ((StringType << 3) | StringType)) {
+        UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
+        if (value.isNull())
+            return throwOutOfMemoryErrorToNumber(exec);
+        return value.toDouble();
+    }
+    
+    // All other cases are pretty uncommon
+    return addSlowCaseToNumber(exec, v1, v2);
+}
+
 void AddNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
@@ -1745,6 +1865,17 @@ JSValue *AddNode::evaluate(ExecState *exec)
   return add(exec, v1, v2);
 }
 
+double AddNode::evaluateToNumber(ExecState* exec)
+{
+    JSValue *v1 = term1->evaluate(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    JSValue *v2 = term2->evaluate(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    return addToNumber(exec, v1, v2);
+}
+
 void SubNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
@@ -1752,15 +1883,25 @@ void SubNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeS
 }
 
 // ECMA 11.6.2
-JSValue *SubNode::evaluate(ExecState *exec)
+double SubNode::inlineEvaluateToNumber(ExecState* exec)
 {
-    JSValue *v1 = term1->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
-        
-    JSValue *v2 = term2->evaluate(exec);
-    KJS_CHECKEXCEPTIONVALUE
-        
-    return jsNumber(v1->toNumber(exec) - v2->toNumber(exec));
+    double n1 = term1->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    double n2 = term2->evaluateToNumber(exec);
+    KJS_CHECKEXCEPTIONNUMBER
+    
+    return n1 - n2;
+}
+
+JSValue* SubNode::evaluate(ExecState* exec)
+{
+    return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double SubNode::evaluateToNumber(ExecState* exec)
+{
+    return inlineEvaluateToNumber(exec);
 }
 
 // ------------------------------ Shift Nodes ------------------------------------
@@ -2155,8 +2296,8 @@ JSValue *ConditionalNode::evaluate(ExecState *exec)
 
 // ECMA 11.13
 
-static ALWAYS_INLINE JSValue *valueForReadModifyAssignment(ExecState * exec, JSValue *v1, JSValue *v2, Operator oper) KJS_FAST_CALL;
-static ALWAYS_INLINE JSValue *valueForReadModifyAssignment(ExecState * exec, JSValue *v1, JSValue *v2, Operator oper)
+static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, Node* right, Operator oper) KJS_FAST_CALL;
+static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, Node* right, Operator oper)
 {
   JSValue *v;
   int i1;
@@ -2164,55 +2305,55 @@ static ALWAYS_INLINE JSValue *valueForReadModifyAssignment(ExecState * exec, JSV
   unsigned int ui;
   switch (oper) {
   case OpMultEq:
-    v = jsNumber(v1->toNumber(exec) * v2->toNumber(exec));
+    v = jsNumber(current->toNumber(exec) * right->evaluateToNumber(exec));
     break;
   case OpDivEq:
-    v = jsNumber(v1->toNumber(exec) / v2->toNumber(exec));
+    v = jsNumber(current->toNumber(exec) / right->evaluateToNumber(exec));
     break;
   case OpPlusEq:
-    v = add(exec, v1, v2);
+    v = add(exec, current, right->evaluate(exec));
     break;
   case OpMinusEq:
-    v = jsNumber(v1->toNumber(exec) - v2->toNumber(exec));
+    v = jsNumber(current->toNumber(exec) - right->evaluateToNumber(exec));
     break;
   case OpLShift:
-    i1 = v1->toInt32(exec);
-    i2 = v2->toInt32(exec);
+    i1 = current->toInt32(exec);
+    i2 = right->evaluate(exec)->toInt32(exec);
     v = jsNumber(i1 << i2);
     break;
   case OpRShift:
-    i1 = v1->toInt32(exec);
-    i2 = v2->toInt32(exec);
+    i1 = current->toInt32(exec);
+    i2 = right->evaluate(exec)->toInt32(exec);
     v = jsNumber(i1 >> i2);
     break;
   case OpURShift:
-    ui = v1->toUInt32(exec);
-    i2 = v2->toInt32(exec);
+    ui = current->toUInt32(exec);
+    i2 = right->evaluate(exec)->toInt32(exec);
     v = jsNumber(ui >> i2);
     break;
   case OpAndEq:
-    i1 = v1->toInt32(exec);
-    i2 = v2->toInt32(exec);
+    i1 = current->toInt32(exec);
+    i2 = right->evaluate(exec)->toInt32(exec);
     v = jsNumber(i1 & i2);
     break;
   case OpXOrEq:
-    i1 = v1->toInt32(exec);
-    i2 = v2->toInt32(exec);
+    i1 = current->toInt32(exec);
+    i2 = right->evaluate(exec)->toInt32(exec);
     v = jsNumber(i1 ^ i2);
     break;
   case OpOrEq:
-    i1 = v1->toInt32(exec);
-    i2 = v2->toInt32(exec);
+    i1 = current->toInt32(exec);
+    i2 = right->evaluate(exec)->toInt32(exec);
     v = jsNumber(i1 | i2);
     break;
   case OpModEq: {
-    double d1 = v1->toNumber(exec);
-    double d2 = v2->toNumber(exec);
+    double d1 = current->toNumber(exec);
+    double d2 = right->evaluateToNumber(exec);
     v = jsNumber(fmod(d1, d2));
   }
     break;
   default:
-    ASSERT(0);
+    ASSERT_NOT_REACHED();
     v = jsUndefined();
   }
   
@@ -2244,8 +2385,7 @@ JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
     JSValue** slot = &exec->localStorage()[m_index].value;
 
     ASSERT(m_oper != OpEqual);
-    JSValue* v2 = m_right->evaluate(exec);
-    JSValue* v = valueForReadModifyAssignment(exec, *slot, v2, m_oper);
+    JSValue* v = valueForReadModifyAssignment(exec, *slot, m_right.get(), m_oper);
 
     KJS_CHECKEXCEPTIONVALUE
 
@@ -2295,8 +2435,7 @@ JSValue *ReadModifyResolveNode::evaluate(ExecState *exec)
   ASSERT(m_oper != OpEqual);
   JSValue *v1 = slot.getValue(exec, base, m_ident);
   KJS_CHECKEXCEPTIONVALUE
-  JSValue *v2 = m_right->evaluate(exec);
-  v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
+  v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
 
   KJS_CHECKEXCEPTIONVALUE
 
@@ -2372,8 +2511,7 @@ JSValue *ReadModifyDotNode::evaluate(ExecState *exec)
   PropertySlot slot;
   JSValue *v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
-  JSValue *v2 = m_right->evaluate(exec);
-  v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
+  v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
 
   KJS_CHECKEXCEPTIONVALUE
 
@@ -2447,8 +2585,7 @@ JSValue *ReadModifyBracketNode::evaluate(ExecState *exec)
     PropertySlot slot;
     JSValue *v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
     KJS_CHECKEXCEPTIONVALUE
-    JSValue *v2 = m_right->evaluate(exec);
-    v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
+    v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
 
     KJS_CHECKEXCEPTIONVALUE
 
@@ -2463,8 +2600,7 @@ JSValue *ReadModifyBracketNode::evaluate(ExecState *exec)
   PropertySlot slot;
   JSValue *v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
   KJS_CHECKEXCEPTIONVALUE
-  JSValue *v2 = m_right->evaluate(exec);
-  v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
+  v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
 
   KJS_CHECKEXCEPTIONVALUE
 
index 0a7a6c4c035dd573d98588e5d97faaa4f30b80f4..48e4aade0cb1ed49d203dd6cf12e41396402f1be 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
  *  Copyright (C) 2007 Maks Orlovich
+ *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -116,7 +117,8 @@ namespace KJS {
     Node(PlacementNewAdoptType) KJS_FAST_CALL { }
     virtual ~Node();
 
-    virtual JSValue *evaluate(ExecState *exec) KJS_FAST_CALL = 0;
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL = 0;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     UString toString() const KJS_FAST_CALL;
     int lineNo() const KJS_FAST_CALL { return m_line; }
     void ref() KJS_FAST_CALL;
@@ -125,7 +127,6 @@ namespace KJS {
     static void clearNewNodes() KJS_FAST_CALL;
 
     virtual bool isNumber() const KJS_FAST_CALL { return false; }
-    virtual bool isImmediateValue() const KJS_FAST_CALL { return false; }
     virtual bool isLocation() const KJS_FAST_CALL { return false; }
     virtual bool isResolveNode() const KJS_FAST_CALL { return false; }
     virtual bool isBracketAccessorNode() const KJS_FAST_CALL { return false; }
@@ -209,28 +210,25 @@ namespace KJS {
 
   class NumberNode : public Node {
   public:
-    NumberNode(double v) KJS_FAST_CALL : val(v) {}
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    NumberNode(double v) KJS_FAST_CALL : m_double(v) {}
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPrimary; }
 
     virtual bool isNumber() const KJS_FAST_CALL { return true; }
-    double value() const KJS_FAST_CALL { return val; }
-    void setValue(double v) KJS_FAST_CALL { val = v; }
-  private:
-    double val;
+    double value() const KJS_FAST_CALL { return m_double; }
+    virtual void setValue(double d) KJS_FAST_CALL { m_double = d; }
+  protected:
+    double m_double;
   };
   
-  class ImmediateNumberNode : public Node {
+  class ImmediateNumberNode : public NumberNode {
   public:
-      ImmediateNumberNode(JSValue* v) KJS_FAST_CALL : m_value(v) {}
-      JSValue* evaluate(ExecState*) KJS_FAST_CALL;
-      virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-      virtual Precedence precedence() const { return PrecPrimary; }
+      ImmediateNumberNode(JSValue* v, double d) KJS_FAST_CALL : NumberNode(d), m_value(v) { ASSERT(v == JSImmediate::fromDouble(d)); }
+      virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
       
-      virtual bool isImmediateValue() const KJS_FAST_CALL { return true; }
-      double value() const KJS_FAST_CALL { return JSImmediate::toDouble(m_value); }
-      void setValue(double v) KJS_FAST_CALL { m_value = JSImmediate::fromDouble(v); ASSERT(m_value); }
+      virtual void setValue(double d) KJS_FAST_CALL { m_double = d; m_value = JSImmediate::fromDouble(d); ASSERT(m_value); }
   private:
       JSValue* m_value;
   };
@@ -238,7 +236,8 @@ namespace KJS {
   class StringNode : public Node {
   public:
     StringNode(const UString *v) KJS_FAST_CALL { value = *v; }
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPrimary; }
   private:
@@ -303,6 +302,9 @@ namespace KJS {
         index = i;
     }
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+  private:
+    ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
   };
 
   class ElementNode : public Node {
@@ -389,7 +391,8 @@ namespace KJS {
   public:
     BracketAccessorNode(Node *e1, Node *e2) KJS_FAST_CALL : expr1(e1), expr2(e2) {}
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecMember; }
 
@@ -399,6 +402,7 @@ namespace KJS {
     Node *subscript() KJS_FAST_CALL { return expr2.get(); }
 
   private:
+    ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
     RefPtr<Node> expr1;
     RefPtr<Node> expr2;
   };
@@ -949,7 +953,8 @@ namespace KJS {
   public:
     NegateNode(Node *e) KJS_FAST_CALL : expr(e) {}
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
   private:
@@ -982,10 +987,12 @@ namespace KJS {
   public:
       MultNode(Node *t1, Node *t2) KJS_FAST_CALL : term1(t1), term2(t2) {}
       virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-      JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
       virtual Precedence precedence() const { return PrecMultiplicitave; }
   private:
+      ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
       RefPtr<Node> term1;
       RefPtr<Node> term2;
   };
@@ -994,10 +1001,12 @@ namespace KJS {
   public:
       DivNode(Node *t1, Node *t2) KJS_FAST_CALL : term1(t1), term2(t2) {}
       virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-      JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
       virtual Precedence precedence() const { return PrecMultiplicitave; }
   private:
+      ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
       RefPtr<Node> term1;
       RefPtr<Node> term2;
   };
@@ -1006,10 +1015,12 @@ namespace KJS {
   public:
       ModNode(Node *t1, Node *t2) KJS_FAST_CALL : term1(t1), term2(t2) {}
       virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-      JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
       virtual Precedence precedence() const { return PrecMultiplicitave; }
   private:
+      ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
       RefPtr<Node> term1;
       RefPtr<Node> term2;
   };
@@ -1018,9 +1029,10 @@ namespace KJS {
   public:
     AddNode(Node *t1, Node *t2) KJS_FAST_CALL : term1(t1), term2(t2) {}
     virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-      virtual Precedence precedence() const { return PrecAdditive; }
+    virtual Precedence precedence() const { return PrecAdditive; }
   private:
     RefPtr<Node> term1;
     RefPtr<Node> term2;
@@ -1030,10 +1042,12 @@ namespace KJS {
   public:
       SubNode(Node *t1, Node *t2) KJS_FAST_CALL : term1(t1), term2(t2) {}
       virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-      JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+      virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
       virtual Precedence precedence() const { return PrecAdditive; }
   private:
+      ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
       RefPtr<Node> term1;
       RefPtr<Node> term2;
   };
index 9ccaeab0ef0114aebb4459b3c7f8c1a0546df7a9..4c0c2494a18a1452710db28e1a0845d22367def7 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  Copyright (C) 2002 Harri Porten (porten@kde.org)
  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -273,11 +274,6 @@ void BooleanNode::streamTo(SourceStream& s) const
 }
 
 void NumberNode::streamTo(SourceStream& s) const
-{
-    s << val;
-}
-
-void ImmediateNumberNode::streamTo(SourceStream& s) const
 {
     s << value();
 }