Changeset 37730 in webkit for trunk/JavaScriptCore/VM/Machine.cpp


Ignore:
Timestamp:
Oct 20, 2008, 9:48:30 AM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-10-20 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.


Fixed https://bugs.webkit.org/show_bug.cgi?id=21735
Emit profiling instrumentation only if the Web Inspector's profiling
feature is enabled

22.2% speedup on empty function call benchmark.
2.9% speedup on v8 benchmark.
0.7% speedup on SunSpider.


Lesser but similar speedups in bytecode.

  • VM/CTI.cpp: (JSC::CTI::compileOpCall): (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompileSlowCases): Nixed JITed profiler hooks. Profiler hooks now have their own opcodes. Added support for compiling profiler hook opcodes.


(JSC::CodeBlock::dump): Dump support for the new profiling opcodes.

  • VM/CodeGenerator.h:
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::CodeGenerator): (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitConstruct): Conditionally emit profiling hooks around call and construct, at the call site. (It's easier to get things right this way, if you have profiled code calling non-profiled code. Also, you get a slightly more accurate profile, since you charge the full cost of the call / construct operation to the callee.)


Also, fixed a bug where construct would fetch the ".prototype" property
from the constructor before evaluating the arguments to the constructor,
incorrectly allowing an "invalid constructor" exception to short-circuit
argument evaluation. I encountered this bug when trying to make
constructor exceptions work with profiling.

  • VM/Machine.cpp: (JSC::Machine::callEval): Removed obsolete profiler hooks.

(JSC::Machine::throwException): Added a check for an exception thrown
within a call instruction. We didn't need this before because the call
instruction would check for a valid call before involing the profiler.
(JSC::Machine::execute): Added a didExecute hook at the end of top-level
function invocation, since op_ret no longer does this for us.

(JSC::Machine::privateExecute): Removed obsolete profiler hooks. Added
profiler opcodes. Changed some ++vPC to vPC[x] notation, since the
latter is better for performance, and it makes reasoning about the
current opcode in exception handling much simpler.

(JSC::Machine::cti_op_call_NotJSFunction): Removed obsolete profiler
hooks.

(JSC::Machine::cti_op_create_arguments_no_params): Added missing
CTI_STACK_HACK that I noticed when adding CTI_STACK_HACK to the new
profiler opcode functions.

(JSC::Machine::cti_op_profile_will_call):
(JSC::Machine::cti_op_profile_did_call): The new profiler opcode
functions.

(JSC::Machine::cti_op_construct_NotJSConstruct): Removed obsolete profiler
hooks.

  • VM/Machine.h: (JSC::Machine::isCallOpcode): Helper for exception handling.
  • VM/Opcode.h: Declare new opcodes.
  • kjs/JSGlobalObject.h: (JSC::JSGlobalObject::supportsProfiling): Added virtual interface that allows WebCore to specify whether the target global object has the Web Inspector's profiling feature enabled.
  • profiler/Profiler.cpp: (JSC::Profiler::willExecute): (JSC::Profiler::didExecute): (JSC::Profiler::createCallIdentifier):
  • profiler/Profiler.h: Added support for invoking the profiler with an arbitrary JSValue*, and not a known object. We didn't need this before because the call instruction would check for a valid call before involing the profiler.

WebCore:

2008-10-18 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

Fixed https://bugs.webkit.org/show_bug.cgi?id=21735
Emit profiling instrumentation only if the Web Inspector's profiling
feature is enabled

  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::supportsProfiling):
  • bindings/js/JSDOMWindowBase.h: Implemented the interface for specifying whether a target global object has the Web Inspector's profiling feature enabled.
  • inspector/JavaScriptDebugServer.cpp: (WebCore::JavaScriptDebugServer::recompileAllJSFunctionsSoon): (WebCore::JavaScriptDebugServer::didAddListener): (WebCore::JavaScriptDebugServer::didRemoveListener):
  • inspector/JavaScriptDebugServer.h: Exported an API for recompiling, used by the Settings object.
  • page/Settings.cpp: (WebCore::Settings::Settings): (WebCore::Settings::setDeveloperExtrasEnabled):
  • page/Settings.h: Recompile when the developer menu is enabled/disabled for the first time, to add/remove profiling hooks. In the future, with better Web Inspector UI, we can do this on a page-by-page basis, instead of a global basis.

LayoutTests:

2008-10-18 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

Test for bugs fixed while working on https://bugs.webkit.org/show_bug.cgi?id=21735
Emit profiling instrumentation only if the Web Inspector's profiling
feature is enabled

  • fast/js/exception-thrown-from-new-expected.txt: Added.
  • fast/js/exception-thrown-from-new.html: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/Machine.cpp

    r37728 r37730  
    590590        return program;
    591591
    592     Profiler** profiler = Profiler::enabledProfilerReference();
    593     if (*profiler)
    594         (*profiler)->willExecute(callFrame, scopeChain->globalObject()->evalFunction());
    595 
    596592    UString programSource = asString(program)->value();
    597593
     
    602598    if (evalNode)
    603599        result = callFrame->globalData().machine->execute(evalNode.get(), callFrame, thisObj, callFrame->registers() - registerFile->start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
    604 
    605     if (*profiler)
    606         (*profiler)->didExecute(callFrame, scopeChain->globalObject()->evalFunction());
    607600
    608601    return result;
     
    845838    }
    846839
     840    // If we throw in the middle of a call instruction, we need to notify
     841    // the profiler manually that the call instruction has returned, since
     842    // we'll never reach the relevant op_profile_did_call.
     843    if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
     844        if (isCallOpcode(vPC[0].u.opcode))
     845            profiler->didExecute(callFrame, callFrame[vPC[2].u.operand].jsValue(callFrame));
     846        else if (vPC[8].u.opcode == getOpcode(op_construct))
     847            profiler->didExecute(callFrame, callFrame[vPC[10].u.operand].jsValue(callFrame));
     848    }
     849
    847850    // Calculate an exception handler vPC, unwinding call frames as necessary.
    848851
     
    993996#endif
    994997    m_reentryDepth--;
     998
     999    if (*profiler)
     1000        (*profiler)->didExecute(newCallFrame, function);
    9951001
    9961002    MACHINE_SAMPLING_privateExecuteReturned();
     
    21492155           object.
    21502156        */
    2151         int dst = (++vPC)->u.operand;
    2152         int value = (++vPC)->u.operand;
    2153         int base = (++vPC)->u.operand;
    2154         int baseProto = (++vPC)->u.operand;
     2157        int dst = vPC[1].u.operand;
     2158        int value = vPC[2].u.operand;
     2159        int base = vPC[3].u.operand;
     2160        int baseProto = vPC[4].u.operand;
    21552161
    21562162        JSValuePtr baseVal = callFrame[base].jsValue(callFrame);
     
    21622168        callFrame[dst] = jsBoolean(baseObj->structureID()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(callFrame, callFrame[value].jsValue(callFrame), callFrame[baseProto].jsValue(callFrame)) : false);
    21632169
    2164         ++vPC;
     2170        vPC += 5;
    21652171        NEXT_OPCODE;
    21662172    }
     
    32093215         */
    32103216
    3211         int dst = (++vPC)->u.operand;
    3212         int func = (++vPC)->u.operand;
    3213         int thisVal = (++vPC)->u.operand;
    3214         int firstArg = (++vPC)->u.operand;
    3215         int argCount = (++vPC)->u.operand;
    3216         ++vPC; // registerOffset
     3217        int dst = vPC[1].u.operand;
     3218        int func = vPC[2].u.operand;
     3219        int thisVal = vPC[3].u.operand;
     3220        int firstArg = vPC[4].u.operand;
     3221        int argCount = vPC[5].u.operand;
    32173222
    32183223        JSValuePtr funcVal = callFrame[func].jsValue(callFrame);
     
    32283233            callFrame[dst] = result;
    32293234
    3230             ++vPC;
     3235            vPC += 7;
    32313236            NEXT_OPCODE;
    32323237        }
     
    32353240        // this instruction as a normal function call, supplying the proper 'this'
    32363241        // value.
    3237         vPC -= 6;
    32383242        callFrame[thisVal] = baseVal->toThisObject(callFrame);
    32393243
     
    32833287         */
    32843288
    3285         int dst = (++vPC)->u.operand;
    3286         int func = (++vPC)->u.operand;
    3287         int thisVal = (++vPC)->u.operand;
    3288         int firstArg = (++vPC)->u.operand;
    3289         int argCount = (++vPC)->u.operand;
    3290         int registerOffset = (++vPC)->u.operand;
     3289        int dst = vPC[1].u.operand;
     3290        int func = vPC[2].u.operand;
     3291        int thisVal = vPC[3].u.operand;
     3292        int firstArg = vPC[4].u.operand;
     3293        int argCount = vPC[5].u.operand;
     3294        int registerOffset = vPC[6].u.operand;
    32913295
    32923296        JSValuePtr v = callFrame[func].jsValue(callFrame);
     
    33113315            }
    33123316
    3313             callFrame->init(newCodeBlock, vPC + 1, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
    3314    
    3315             if (*enabledProfilerReference)
    3316                 (*enabledProfilerReference)->willExecute(callFrame, asObject(v));
    3317 
     3317            callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
    33183318            vPC = newCodeBlock->instructions.begin();
    33193319
     
    33313331            ScopeChainNode* scopeChain = callFrame->scopeChain();
    33323332            CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
    3333             newCallFrame->init(0, vPC + 1, scopeChain, callFrame, dst, argCount, 0);
    3334 
    3335             if (*enabledProfilerReference)
    3336                 (*enabledProfilerReference)->willExecute(newCallFrame, asObject(v));
     3333            newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
    33373334
    33383335            MACHINE_SAMPLING_callingHostFunction();
     
    33433340            callFrame[dst] = returnValue;
    33443341
    3345             if (*enabledProfilerReference)
    3346                 (*enabledProfilerReference)->didExecute(callFrame, asObject(v));
    3347 
    3348             ++vPC;
     3342            vPC += 7;
    33493343            NEXT_OPCODE;
    33503344        }
     
    33843378        int result = (++vPC)->u.operand;
    33853379
    3386         if (*enabledProfilerReference)
    3387             (*enabledProfilerReference)->didExecute(callFrame, callFrame->callee());
    3388 
    33893380        if (callFrame->codeBlock()->needsFullScopeChain)
    33903381            callFrame->scopeChain()->deref();
     
    34983489        */
    34993490
    3500         int dst = (++vPC)->u.operand;
    3501         int constr = (++vPC)->u.operand;
    3502         int constrProto = (++vPC)->u.operand;
    3503         int firstArg = (++vPC)->u.operand;
    3504         int argCount = (++vPC)->u.operand;
    3505         int registerOffset = (++vPC)->u.operand;
     3491        int dst = vPC[1].u.operand;
     3492        int constr = vPC[2].u.operand;
     3493        int constrProto = vPC[3].u.operand;
     3494        int firstArg = vPC[4].u.operand;
     3495        int argCount = vPC[5].u.operand;
     3496        int registerOffset = vPC[6].u.operand;
    35063497
    35073498        JSValuePtr v = callFrame[constr].jsValue(callFrame);
     
    35113502
    35123503        if (constructType == ConstructTypeJS) {
    3513             if (*enabledProfilerReference)
    3514                 (*enabledProfilerReference)->willExecute(callFrame, asObject(v));
    3515 
    35163504            ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
    35173505            FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
     
    35373525            }
    35383526
    3539             callFrame->init(newCodeBlock, vPC + 1, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
    3540    
    3541             if (*enabledProfilerReference)
    3542                 (*enabledProfilerReference)->didExecute(callFrame, asObject(v));
    3543 
     3527            callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
    35443528            vPC = newCodeBlock->instructions.begin();
    35453529
     
    35553539
    35563540            ScopeChainNode* scopeChain = callFrame->scopeChain();
    3557             CallFrame::create(callFrame->registers() + registerOffset)->init(0, vPC + 1, scopeChain, callFrame, dst, argCount, 0);
    3558             callFrame = CallFrame::create(callFrame->registers() + registerOffset);
    3559 
    3560             if (*enabledProfilerReference)
    3561                 (*enabledProfilerReference)->willExecute(callFrame, asObject(v));
     3541            CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
     3542            newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
    35623543
    35633544            MACHINE_SAMPLING_callingHostFunction();
    35643545
    3565             JSValuePtr returnValue = constructData.native.function(callFrame, asObject(v), args);
    3566             callFrame = CallFrame::create(callFrame->registers() - registerOffset);
     3546            JSValuePtr returnValue = constructData.native.function(newCallFrame, asObject(v), args);
    35673547
    35683548            VM_CHECK_EXCEPTION();
    35693549            callFrame[dst] = returnValue;
    35703550
    3571             if (*enabledProfilerReference)
    3572                 (*enabledProfilerReference)->didExecute(callFrame, asObject(v));
    3573 
    3574             ++vPC;
     3551            vPC += 7;
    35753552            NEXT_OPCODE;
    35763553        }
     
    38813858
    38823859        ++vPC;
     3860        NEXT_OPCODE;
     3861    }
     3862    BEGIN_OPCODE(op_profile_will_call) {
     3863        /* op_profile_will_call function(r)
     3864
     3865         Notifies the profiler of the beginning of a function call. This opcode
     3866         is only generated if developer tools are enabled.
     3867        */
     3868        int function = vPC[1].u.operand;
     3869
     3870        if (*enabledProfilerReference)
     3871            (*enabledProfilerReference)->willExecute(callFrame, callFrame[function].jsValue(callFrame));
     3872
     3873        vPC += 2;
     3874        NEXT_OPCODE;
     3875    }
     3876    BEGIN_OPCODE(op_profile_did_call) {
     3877        /* op_profile_did_call function(r)
     3878
     3879         Notifies the profiler of the end of a function call. This opcode
     3880         is only generated if developer tools are enabled.
     3881        */
     3882        int function = vPC[1].u.operand;
     3883
     3884        if (*enabledProfilerReference)
     3885            (*enabledProfilerReference)->didExecute(callFrame, callFrame[function].jsValue(callFrame));
     3886
     3887        vPC += 2;
    38833888        NEXT_OPCODE;
    38843889    }
     
    46124617}
    46134618
    4614 void Machine::cti_op_call_profiler(CTI_ARGS)
    4615 {
    4616     CTI_STACK_HACK();
    4617 
    4618     ASSERT(*ARG_profilerReference);
    4619     (*ARG_profilerReference)->willExecute(ARG_callFrame, asFunction(ARG_src1));
    4620 }
    4621 
    46224619VoidPtrPair Machine::cti_op_call_JSFunction(CTI_ARGS)
    46234620{
     
    47274724        ARG_setCallFrame(callFrame);
    47284725
    4729         if (*ARG_profilerReference)
    4730             (*ARG_profilerReference)->willExecute(callFrame, asObject(funcVal));
    4731 
    47324726        Register* argv = ARG_callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
    47334727        ArgList argList(argv + 1, argCount - 1);
     
    47394733        VM_CHECK_EXCEPTION();
    47404734
    4741         if (*ARG_profilerReference)
    4742             (*ARG_profilerReference)->didExecute(previousCallFrame, asObject(funcVal));
    4743 
    47444735        return returnValue.payload();
    47454736    }
     
    47624753void Machine::cti_op_create_arguments_no_params(CTI_ARGS)
    47634754{
     4755    CTI_STACK_HACK();
     4756
    47644757    Arguments* arguments = new (ARG_globalData) Arguments(ARG_callFrame, Arguments::ArgumentsNoParameters);
    47654758    ARG_callFrame->setCalleeArguments(arguments);
     
    47834776}
    47844777
    4785 void Machine::cti_op_ret_profiler(CTI_ARGS)
     4778void Machine::cti_op_profile_will_call(CTI_ARGS)
    47864779{
    47874780    CTI_STACK_HACK();
    47884781
    47894782    ASSERT(*ARG_profilerReference);
    4790     (*ARG_profilerReference)->didExecute(ARG_callFrame, ARG_callFrame->callee());
     4783    (*ARG_profilerReference)->willExecute(ARG_callFrame, ARG_src1);
     4784}
     4785
     4786void Machine::cti_op_profile_did_call(CTI_ARGS)
     4787{
     4788    CTI_STACK_HACK();
     4789
     4790    ASSERT(*ARG_profilerReference);
     4791    (*ARG_profilerReference)->didExecute(ARG_callFrame, ARG_src1);
    47914792}
    47924793
     
    49294930
    49304931    if (constructType == ConstructTypeHost) {
    4931         JSObject* constructor = asObject(constrVal);
    4932 
    4933         if (*ARG_profilerReference)
    4934             (*ARG_profilerReference)->willExecute(callFrame, constructor);
    4935 
    49364932        ArgList argList(callFrame->registers() + firstArg + 1, argCount - 1);
    49374933
    49384934        CTI_MACHINE_SAMPLING_callingHostFunction();
    49394935
    4940         JSValuePtr returnValue = constructData.native.function(callFrame, constructor, argList);
     4936        JSValuePtr returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
    49414937        VM_CHECK_EXCEPTION();
    4942 
    4943         if (*ARG_profilerReference)
    4944             (*ARG_profilerReference)->didExecute(callFrame, constructor);
    49454938
    49464939        return returnValue.payload();
Note: See TracChangeset for help on using the changeset viewer.