Ignore:
Timestamp:
May 5, 2009, 4:34:23 AM (16 years ago)
Author:
[email protected]
Message:

Bug 25559: Improve native function call performance
<https://bugs.webkit.org/show_bug.cgi?id=25559>

Reviewed by Gavin Barraclough

In order to cache calls to native functions we now make the standard
prototype functions use a small assembly thunk that converts the JS
calling convention into the native calling convention. As this is
only beneficial in the JIT we use the NativeFunctionWrapper typedef
to alternate between PrototypeFunction and JSFunction to keep the
code sane. This change from PrototypeFunction to NativeFunctionWrapper
is the bulk of this patch.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/JSFunction.cpp

    r43122 r43220  
    4646const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 };
    4747
     48JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func)
     49    : Base(&exec->globalData(), structure, name)
     50#if ENABLE(JIT)
     51    , m_body(exec->globalData().nativeFunctionThunk())
     52#else
     53    , m_body(0)
     54#endif
     55{
     56#if ENABLE(JIT)
     57    setNativeFunction(func);
     58    putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
     59#else
     60    UNUSED_PARAM(length);
     61    UNUSED_PARAM(func);
     62    ASSERT_NOT_REACHED();
     63#endif
     64}
     65
    4866JSFunction::JSFunction(ExecState* exec, const Identifier& name, FunctionBodyNode* body, ScopeChainNode* scopeChainNode)
    4967    : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), name)
    5068    , m_body(body)
    51     , m_scopeChain(scopeChainNode)
    52 {
     69{
     70    setScopeChain(scopeChainNode);
    5371}
    5472
     
    5977    // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
    6078    // this memory is freed and may be reused (potentially for another, different JSFunction).
    61     if (m_body && m_body->isGenerated())
    62         m_body->generatedBytecode().unlinkCallers();
     79    if (!isHostFunction()) {
     80        if (m_body && m_body->isGenerated())
     81            m_body->generatedBytecode().unlinkCallers();
     82        scopeChain().~ScopeChain();
     83    }
     84   
    6385#endif
    6486}
     
    6789{
    6890    Base::mark();
    69     m_body->mark();
    70     m_scopeChain.mark();
     91    if (!isHostFunction()) {
     92        m_body->mark();
     93        scopeChain().mark();
     94    }
    7195}
    7296
    7397CallType JSFunction::getCallData(CallData& callData)
    7498{
     99    if (isHostFunction()) {
     100        callData.native.function = nativeFunction();
     101        return CallTypeHost;
     102    }
    75103    callData.js.functionBody = m_body.get();
    76     callData.js.scopeChain = m_scopeChain.node();
     104    callData.js.scopeChain = scopeChain().node();
    77105    return CallTypeJS;
    78106}
     
    80108JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args)
    81109{
    82     return exec->interpreter()->execute(m_body.get(), exec, this, thisValue.toThisObject(exec), args, m_scopeChain.node(), exec->exceptionSlot());
     110    ASSERT(!isHostFunction());
     111    return exec->interpreter()->execute(m_body.get(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot());
    83112}
    84113
     
    86115{
    87116    JSFunction* thisObj = asFunction(slot.slotBase());
     117    ASSERT(!thisObj->isHostFunction());
    88118    return exec->interpreter()->retrieveArguments(exec, thisObj);
    89119}
     
    92122{
    93123    JSFunction* thisObj = asFunction(slot.slotBase());
     124    ASSERT(!thisObj->isHostFunction());
    94125    return exec->interpreter()->retrieveCaller(exec, thisObj);
    95126}
     
    98129{
    99130    JSFunction* thisObj = asFunction(slot.slotBase());
     131    ASSERT(!thisObj->isHostFunction());
    100132    return jsNumber(exec, thisObj->m_body->parameterCount());
    101133}
     
    103135bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    104136{
     137    if (isHostFunction())
     138        return Base::getOwnPropertySlot(exec, propertyName, slot);
     139
    105140    if (propertyName == exec->propertyNames().prototype) {
    106141        JSValue* location = getDirectLocation(propertyName);
    107142
    108143        if (!location) {
    109             JSObject* prototype = new (exec) JSObject(m_scopeChain.globalObject()->emptyObjectStructure());
     144            JSObject* prototype = new (exec) JSObject(scopeChain().globalObject()->emptyObjectStructure());
    110145            prototype->putDirect(exec->propertyNames().constructor, this, DontEnum);
    111146            putDirect(exec->propertyNames().prototype, prototype, DontDelete);
     
    136171void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    137172{
     173    if (isHostFunction()) {
     174        Base::put(exec, propertyName, value, slot);
     175        return;
     176    }
    138177    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
    139178        return;
     
    143182bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)
    144183{
     184    if (isHostFunction())
     185        return Base::deleteProperty(exec, propertyName);
    145186    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
    146187        return false;
     
    151192ConstructType JSFunction::getConstructData(ConstructData& constructData)
    152193{
     194    if (isHostFunction())
     195        return ConstructTypeNone;
    153196    constructData.js.functionBody = m_body.get();
    154     constructData.js.scopeChain = m_scopeChain.node();
     197    constructData.js.scopeChain = scopeChain().node();
    155198    return ConstructTypeJS;
    156199}
     
    158201JSObject* JSFunction::construct(ExecState* exec, const ArgList& args)
    159202{
     203    ASSERT(!isHostFunction());
    160204    Structure* structure;
    161205    JSValue prototype = get(exec, exec->propertyNames().prototype);
     
    166210    JSObject* thisObj = new (exec) JSObject(structure);
    167211
    168     JSValue result = exec->interpreter()->execute(m_body.get(), exec, this, thisObj, args, m_scopeChain.node(), exec->exceptionSlot());
     212    JSValue result = exec->interpreter()->execute(m_body.get(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot());
    169213    if (exec->hadException() || !result.isObject())
    170214        return thisObj;
Note: See TracChangeset for help on using the changeset viewer.