Changeset 31119 in webkit


Ignore:
Timestamp:
Mar 17, 2008 10:36:26 PM (16 years ago)
Author:
oliver@apple.com
Message:

Optimise multi-scope function call resolution

Reviewed by Geoff

Refactor multiscope variable resolution and use to add
optimised FunctionCallResolveNode subclasses.

2.6% gain in sunspider performance, *25%* gain in controlflow-recursive

Location:
trunk/JavaScriptCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r31115 r31119  
     12008-03-17  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Geoff.
     4
     5        Optimise multi-scope function call resolution
     6
     7        Refactor multiscope variable resolution and use to add
     8        optimised FunctionCallResolveNode subclasses. 
     9
     10        2.6% gain in sunspider performance, *25%* gain in controlflow-recursive
     11
     12        * kjs/nodes.cpp:
     13        (KJS::getSymbolTableEntry):
     14        (KJS::ResolveNode::optimizeVariableAccess):
     15        (KJS::getNonLocalSymbol):
     16        (KJS::ExpressionNode::resolveAndCall):
     17        (KJS::FunctionCallResolveNode::optimizeVariableAccess):
     18        (KJS::FunctionCallResolveNode::inlineEvaluate):
     19        (KJS::ScopedVarFunctionCallNode::inlineEvaluate):
     20        (KJS::ScopedVarFunctionCallNode::evaluate):
     21        (KJS::ScopedVarFunctionCallNode::evaluateToNumber):
     22        (KJS::ScopedVarFunctionCallNode::evaluateToBoolean):
     23        (KJS::ScopedVarFunctionCallNode::evaluateToInt32):
     24        (KJS::ScopedVarFunctionCallNode::evaluateToUInt32):
     25        (KJS::NonLocalVarFunctionCallNode::inlineEvaluate):
     26        (KJS::NonLocalVarFunctionCallNode::evaluate):
     27        (KJS::NonLocalVarFunctionCallNode::evaluateToNumber):
     28        (KJS::NonLocalVarFunctionCallNode::evaluateToBoolean):
     29        (KJS::NonLocalVarFunctionCallNode::evaluateToInt32):
     30        (KJS::NonLocalVarFunctionCallNode::evaluateToUInt32):
     31        * kjs/nodes.h:
     32        (KJS::ScopedVarFunctionCallNode::):
     33        (KJS::NonLocalVarFunctionCallNode::):
     34
    1352008-03-17  David Kilzer  <ddkilzer@apple.com>
    236
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r31114 r31119  
    594594}
    595595
    596 void ResolveNode::optimizeVariableAccess(ExecState* exec, const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
    597 {
    598     size_t index = symbolTable.get(m_ident.ustring().rep());
     596static size_t getSymbolTableEntry(ExecState* exec, const Identifier& ident, const SymbolTable& symbolTable, size_t& stackDepth)
     597{
     598    size_t index = symbolTable.get(ident.ustring().rep());
    599599    if (index != missingSymbolMarker()) {
    600         new (this) LocalVarAccessNode(index);
    601         return;
     600        stackDepth = 0;
     601        return index;
    602602    }
    603603   
    604     if (m_ident == exec->propertyNames().arguments)
    605         return;
     604    if (ident == exec->propertyNames().arguments) {
     605        stackDepth = 0;
     606        return missingSymbolMarker();
     607    }
     608   
    606609    const ScopeChain& chain = exec->scopeChain();
    607610    ScopeChainIterator iter = chain.begin();
     
    613616            break;
    614617        JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
    615         index = currentVariableObject->symbolTable().get(m_ident.ustring().rep());
     618        index = currentVariableObject->symbolTable().get(ident.ustring().rep());
    616619        if (index != missingSymbolMarker()) {
    617             new (this) ScopedVarAccessNode(index, depth);
    618             return;
     620            stackDepth = depth;
     621            return index;
    619622        }
    620623        if (currentVariableObject->isDynamicScope())
    621624            break;
    622625    }
    623     if (depth > 0)
    624         new (this) NonLocalVarAccessNode(depth);
     626    stackDepth = depth;
     627    return missingSymbolMarker();
     628}
     629
     630void ResolveNode::optimizeVariableAccess(ExecState* exec, const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
     631{
     632    size_t depth = 0;
     633    size_t index = getSymbolTableEntry(exec, m_ident, symbolTable, depth);
     634    if (index != missingSymbolMarker()) {
     635        if (!depth)
     636            new (this) LocalVarAccessNode(index);
     637        else
     638            new (this) ScopedVarAccessNode(index, depth);
     639        return;
     640    }
     641
     642    if (!depth)
     643        return;
     644
     645    new (this) NonLocalVarAccessNode(depth);
    625646}
    626647
     
    656677}
    657678
    658 JSValue* ScopedVarAccessNode::inlineEvaluate(ExecState* exec)
     679static inline JSValue* getNonLocalSymbol(ExecState* exec, size_t index, size_t scopeDepth)
    659680{
    660681    const ScopeChain& chain = exec->scopeChain();
    661682    ScopeChainIterator iter = chain.begin();
    662     for (size_t i = 0; i < m_scopeDepth; ++iter, ++i)
     683    for (size_t i = 0; i < scopeDepth; ++iter, ++i)
    663684        ASSERT(iter != chain.end());
    664685    JSObject* scope = *iter;
    665     ASSERT(scope->isActivationObject() || scope->isGlobalObject());
     686    ASSERT(scope->isVariableObject());
    666687    JSVariableObject* variableObject = static_cast<JSVariableObject*>(scope);
    667     return variableObject->localStorage()[m_index].value;
     688    return variableObject->localStorage()[index].value;
     689}
     690
     691JSValue* ScopedVarAccessNode::inlineEvaluate(ExecState* exec)
     692{
     693    return getNonLocalSymbol(exec, m_index, m_scopeDepth);
    668694}
    669695
     
    10621088}
    10631089
    1064 template <ExpressionNode::CallerType callerType>
    1065 inline JSValue* ExpressionNode::resolveAndCall(ExecState* exec, const Identifier& ident, ArgumentsNode* args)
     1090template <ExpressionNode::CallerType callerType, bool scopeDepthIsZero>
     1091inline JSValue* ExpressionNode::resolveAndCall(ExecState* exec, const Identifier& ident, ArgumentsNode* args, size_t scopeDepth)
    10661092{
    10671093    const ScopeChain& chain = exec->scopeChain();
     
    10691095    ScopeChainIterator end = chain.end();
    10701096
     1097    if (!scopeDepthIsZero) {
     1098        for (size_t i = 0; i < scopeDepth; ++iter, ++i)
     1099            ASSERT(iter != chain.end());
     1100    }
     1101   
    10711102    // we must always have something in the scope chain
    10721103    ASSERT(iter != end);
     
    11231154JSValue* EvalFunctionCallNode::evaluate(ExecState* exec)
    11241155{
    1125     return resolveAndCall<EvalOperator>(exec, exec->propertyNames().eval, m_args.get());
     1156    return resolveAndCall<EvalOperator, true>(exec, exec->propertyNames().eval, m_args.get());
    11261157}
    11271158
     
    11571188}
    11581189
    1159 void FunctionCallResolveNode::optimizeVariableAccess(ExecState*, const SymbolTable& symbolTable, const LocalStorage&, NodeStack& nodeStack)
     1190void FunctionCallResolveNode::optimizeVariableAccess(ExecState* exec, const SymbolTable& symbolTable, const LocalStorage&, NodeStack& nodeStack)
    11601191{
    11611192    nodeStack.append(m_args.get());
    11621193
    1163     size_t index = symbolTable.get(m_ident.ustring().rep());
    1164     if (index != missingSymbolMarker())
    1165         new (this) LocalVarFunctionCallNode(index);
     1194    size_t depth = 0;
     1195    size_t index = getSymbolTableEntry(exec, m_ident, symbolTable, depth);
     1196    if (index != missingSymbolMarker()) {
     1197        if (!depth)
     1198            new (this) LocalVarFunctionCallNode(index);
     1199        else
     1200            new (this) ScopedVarFunctionCallNode(index, depth);
     1201        return;
     1202    }
     1203   
     1204    if (!depth)
     1205        return;
     1206   
     1207    new (this) NonLocalVarFunctionCallNode(depth);
    11661208}
    11671209
     
    11721214    ASSERT(!canSkipLookup(exec, m_ident));
    11731215
    1174     return resolveAndCall<FunctionCall>(exec, m_ident, m_args.get());
     1216    return resolveAndCall<FunctionCall, true>(exec, m_ident, m_args.get());
    11751217}
    11761218
     
    12551297
    12561298uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
     1299{
     1300    JSValue* v = inlineEvaluate(exec);
     1301    KJS_CHECKEXCEPTIONNUMBER
     1302    return v->toUInt32(exec);
     1303}
     1304
     1305JSValue* ScopedVarFunctionCallNode::inlineEvaluate(ExecState* exec)
     1306{
     1307    ASSERT(exec->variableObject() == exec->scopeChain().top());
     1308   
     1309    JSValue* v = getNonLocalSymbol(exec, m_index, m_scopeDepth);
     1310   
     1311    if (!v->isObject())
     1312        return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
     1313   
     1314    JSObject* func = static_cast<JSObject*>(v);
     1315    if (!func->implementsCall())
     1316        return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_ident);
     1317   
     1318    List argList;
     1319    m_args->evaluateList(exec, argList);
     1320    KJS_CHECKEXCEPTIONVALUE
     1321   
     1322    return func->call(exec, exec->dynamicGlobalObject(), argList);
     1323}
     1324
     1325JSValue* ScopedVarFunctionCallNode::evaluate(ExecState* exec)
     1326{
     1327    return inlineEvaluate(exec);
     1328}
     1329
     1330double ScopedVarFunctionCallNode::evaluateToNumber(ExecState* exec)
     1331{
     1332    JSValue* v = inlineEvaluate(exec);
     1333    KJS_CHECKEXCEPTIONNUMBER
     1334    return v->toNumber(exec);
     1335}
     1336
     1337bool ScopedVarFunctionCallNode::evaluateToBoolean(ExecState* exec)
     1338{
     1339    JSValue* v = inlineEvaluate(exec);
     1340    KJS_CHECKEXCEPTIONBOOLEAN
     1341    return v->toBoolean(exec);
     1342}
     1343
     1344int32_t ScopedVarFunctionCallNode::evaluateToInt32(ExecState* exec)
     1345{
     1346    JSValue* v = inlineEvaluate(exec);
     1347    KJS_CHECKEXCEPTIONNUMBER
     1348    return v->toInt32(exec);
     1349}
     1350
     1351uint32_t ScopedVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
     1352{
     1353    JSValue* v = inlineEvaluate(exec);
     1354    KJS_CHECKEXCEPTIONNUMBER
     1355    return v->toUInt32(exec);
     1356}
     1357
     1358JSValue* NonLocalVarFunctionCallNode::inlineEvaluate(ExecState* exec)
     1359{
     1360    // Check for missed optimization opportunity.
     1361    ASSERT(!canSkipLookup(exec, m_ident));
     1362   
     1363    return resolveAndCall<FunctionCall, false>(exec, m_ident, m_args.get(), m_scopeDepth);
     1364}
     1365
     1366JSValue* NonLocalVarFunctionCallNode::evaluate(ExecState* exec)
     1367{
     1368    return inlineEvaluate(exec);
     1369}
     1370
     1371double NonLocalVarFunctionCallNode::evaluateToNumber(ExecState* exec)
     1372{
     1373    JSValue* v = inlineEvaluate(exec);
     1374    KJS_CHECKEXCEPTIONNUMBER
     1375    return v->toNumber(exec);
     1376}
     1377
     1378bool NonLocalVarFunctionCallNode::evaluateToBoolean(ExecState* exec)
     1379{
     1380    JSValue* v = inlineEvaluate(exec);
     1381    KJS_CHECKEXCEPTIONBOOLEAN
     1382    return v->toBoolean(exec);
     1383}
     1384
     1385int32_t NonLocalVarFunctionCallNode::evaluateToInt32(ExecState* exec)
     1386{
     1387    JSValue* v = inlineEvaluate(exec);
     1388    KJS_CHECKEXCEPTIONNUMBER
     1389    return v->toInt32(exec);
     1390}
     1391
     1392uint32_t NonLocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
    12571393{
    12581394    JSValue* v = inlineEvaluate(exec);
  • trunk/JavaScriptCore/kjs/nodes.h

    r31114 r31119  
    210210    protected:
    211211        typedef enum { EvalOperator, FunctionCall } CallerType;
    212         template <CallerType> inline JSValue* resolveAndCall(ExecState*, const Identifier&, ArgumentsNode*);
     212        template <CallerType, bool> inline JSValue* resolveAndCall(ExecState*, const Identifier&, ArgumentsNode*, size_t = 0);
    213213    };
    214214
     
    792792        RefPtr<ArgumentsNode> m_args;
    793793        size_t m_index; // Used by LocalVarFunctionCallNode.
    794     };
    795 
     794        size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode
     795    };
     796   
    796797    class LocalVarFunctionCallNode : public FunctionCallResolveNode {
    797798    public:
     
    802803            m_index = i;
    803804        }
    804 
     805       
    805806        virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
    806807        virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     
    808809        virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
    809810        virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
    810 
     811       
     812    private:
     813        ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
     814    };
     815   
     816    class ScopedVarFunctionCallNode : public FunctionCallResolveNode {
     817    public:
     818        ScopedVarFunctionCallNode(size_t i, size_t depth) KJS_FAST_CALL
     819            : FunctionCallResolveNode(PlacementNewAdopt)
     820        {
     821            ASSERT(i != missingSymbolMarker());
     822            m_index = i;
     823            m_scopeDepth = depth;
     824        }
     825       
     826        virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     827        virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     828        virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     829        virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
     830        virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
     831       
     832    private:
     833        ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
     834    };
     835   
     836    class NonLocalVarFunctionCallNode : public FunctionCallResolveNode {
     837    public:
     838        NonLocalVarFunctionCallNode(size_t depth) KJS_FAST_CALL
     839            : FunctionCallResolveNode(PlacementNewAdopt)
     840        {
     841            m_scopeDepth = depth;
     842        }
     843       
     844        virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     845        virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     846        virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     847        virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
     848        virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
     849       
    811850    private:
    812851        ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
Note: See TracChangeset for help on using the changeset viewer.