From 94ac212f2202276be8a99fa9af65c5f1b5af8c35 Mon Sep 17 00:00:00 2001 From: "eric@webkit.org" Date: Thu, 8 Nov 2007 07:58:15 +0000 Subject: [PATCH] 2007-11-07 Eric Seidel 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 | 57 ++++++ JavaScriptCore/kjs/grammar.y | 12 +- JavaScriptCore/kjs/nodes.cpp | 282 +++++++++++++++++++++------- JavaScriptCore/kjs/nodes.h | 64 ++++--- JavaScriptCore/kjs/nodes2string.cpp | 6 +- 5 files changed, 309 insertions(+), 112 deletions(-) diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 52560b283d0c..9316fbfcddc6 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,60 @@ +2007-11-07 Eric Seidel + + 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 Reviewed by Eric. diff --git a/JavaScriptCore/kjs/grammar.y b/JavaScriptCore/kjs/grammar.y index 1baa7f9fbce7..aa9c9eee99ca 100644 --- a/JavaScriptCore/kjs/grammar.y +++ b/JavaScriptCore/kjs/grammar.y @@ -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 * * 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(Node* n) { if (n->isNumber()) { NumberNode* number = static_cast(n); @@ -1029,13 +1030,6 @@ static Node* makeNegateNode(Node *n) number->setValue(-number->value()); return number; } - } else if (n->isImmediateValue()) { - ImmediateNumberNode* number = static_cast(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); } diff --git a/JavaScriptCore/kjs/nodes.cpp b/JavaScriptCore/kjs/nodes.cpp index 6368152f74bc..fa88e8db77cc 100644 --- a/JavaScriptCore/kjs/nodes.cpp +++ b/JavaScriptCore/kjs/nodes.cpp @@ -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 * * 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(exec->variableObject())->isActivation()); ASSERT(static_cast(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); + JSValue* v1 = expr1->evaluate(exec); KJS_CHECKEXCEPTIONVALUE - JSValue *v2 = expr2->evaluate(exec); + JSValue* v2 = expr2->evaluate(exec); KJS_CHECKEXCEPTIONVALUE - JSObject *o = v1->toObject(exec); + JSObject* o = 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: // Add case: // --------------------------- @@ -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(v1)->value() + static_cast(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(v1)->value() + static_cast(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 diff --git a/JavaScriptCore/kjs/nodes.h b/JavaScriptCore/kjs/nodes.h index 0a7a6c4c035d..48e4aade0cb1 100644 --- a/JavaScriptCore/kjs/nodes.h +++ b/JavaScriptCore/kjs/nodes.h @@ -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 * * 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 expr1; RefPtr 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 term1; RefPtr 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 term1; RefPtr 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 term1; RefPtr 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 term1; RefPtr 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 term1; RefPtr term2; }; diff --git a/JavaScriptCore/kjs/nodes2string.cpp b/JavaScriptCore/kjs/nodes2string.cpp index 9ccaeab0ef01..4c0c2494a18a 100644 --- a/JavaScriptCore/kjs/nodes2string.cpp +++ b/JavaScriptCore/kjs/nodes2string.cpp @@ -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 * * 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(); } -- 2.36.0