Ignore:
Timestamp:
Nov 16, 2010, 7:03:34 PM (15 years ago)
Author:
[email protected]
Message:

Bug 49635 - Profiler implementation is fragile

Reviewed by Sam Weinig.

The profile presently requires the exception handling mechanism to explicitly
remove all stack frames that are exited during the exception unwind mechanism.
This is fragile in a number of ways:

  • We have to change bytecode register allocation when compiling code to run when profiling, to preserve the callee function (this is also required to call did_call after the call has returned).
  • In the JIT we have to maintain additional data structures (CodeBlock::RareData::m_functionRegisterInfos) to map back to the register containing the callee.
  • In the interpreter we use 'magic values' to offset into the instruction stream to rediscover the register containing the function.

Instead, move profiling into the head and tail of functions.

  • This correctly accounts the cost of the call itself to the caller.
  • This allows us to access the callee function object from the callframe.
  • This means that at the point a call is made we can track the stack depth on the ProfileNode.
  • When unwinding we can simply report the depth at which the exception is being handled - all call frames above this level are freed.

(JSC::CodeBlock::dump):
(JSC::CodeBlock::shrinkToFit):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::bytecodeOffset):
(JSC::CodeBlock::methodCallLinkInfo):

  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitCallVarargs):
(JSC::BytecodeGenerator::emitReturn):
(JSC::BytecodeGenerator::emitConstruct):

  • bytecompiler/BytecodeGenerator.h:

(JSC::CallArguments::count):

  • bytecompiler/NodesCodegen.cpp:

(JSC::CallArguments::CallArguments):

  • interpreter/Interpreter.cpp:

(JSC::ProfileHostCall::ProfileHostCall):
(JSC::ProfileHostCall::~ProfileHostCall):
(JSC::Interpreter::unwindCallFrame):
(JSC::Interpreter::throwException):
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::privateExecute):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_profile_has_called):
(JSC::JIT::emit_op_profile_will_return):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_profile_has_called):
(JSC::JIT::emit_op_profile_will_return):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jit/JITStubs.h:
  • profiler/Profile.cpp:

(JSC::Profile::Profile):

  • profiler/ProfileGenerator.cpp:

(JSC::ProfileGenerator::addParentForConsoleStart):
(JSC::ProfileGenerator::willExecute):
(JSC::ProfileGenerator::didExecute):
(JSC::ProfileGenerator::exceptionUnwind):
(JSC::ProfileGenerator::stopProfiling):

  • profiler/ProfileGenerator.h:
  • profiler/ProfileNode.cpp:

(JSC::ProfileNode::ProfileNode):
(JSC::ProfileNode::willExecute):

  • profiler/ProfileNode.h:

(JSC::ProfileNode::create):
(JSC::ProfileNode::operator==):
(JSC::ProfileNode::exec):

  • profiler/Profiler.cpp:

(JSC::dispatchFunctionToProfiles):
(JSC::Profiler::hasCalled):
(JSC::Profiler::willEvaluate):
(JSC::Profiler::willReturn):
(JSC::Profiler::didEvaluate):
(JSC::Profiler::exceptionUnwind):

  • profiler/Profiler.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/profiler/ProfileGenerator.cpp

    r65305 r72160  
    6464
    6565    exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
    66     m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
     66    m_currentNode = ProfileNode::create(exec, Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
    6767    m_head->insertNode(m_currentNode.get());
    6868}
     
    7373}
    7474
    75 void ProfileGenerator::willExecute(const CallIdentifier& callIdentifier)
     75void ProfileGenerator::willExecute(ExecState* exec, const CallIdentifier& callIdentifier)
    7676{
    7777    if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
     
    8484        return;
    8585
    86     ASSERT_ARG(m_currentNode, m_currentNode);
    87     m_currentNode = m_currentNode->willExecute(callIdentifier);
     86    ASSERT(m_currentNode);
     87    m_currentNode = m_currentNode->willExecute(exec, callIdentifier);
    8888}
    8989
    90 void ProfileGenerator::didExecute(const CallIdentifier& callIdentifier)
     90void ProfileGenerator::didExecute(ExecState* exec, const CallIdentifier& callIdentifier)
    9191{
    9292    if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
     
    9999        return;
    100100
    101     ASSERT_ARG(m_currentNode, m_currentNode);
     101    ASSERT(m_currentNode);
    102102    if (m_currentNode->callIdentifier() != callIdentifier) {
    103         RefPtr<ProfileNode> returningNode = ProfileNode::create(callIdentifier, m_head.get(), m_currentNode.get());
     103        RefPtr<ProfileNode> returningNode = ProfileNode::create(exec, callIdentifier, m_head.get(), m_currentNode.get());
    104104        returningNode->setStartTime(m_currentNode->startTime());
    105105        returningNode->didExecute();
     
    111111}
    112112
     113void ProfileGenerator::exceptionUnwind(ExecState* exec, const CallIdentifier&)
     114{
     115    ASSERT(m_currentNode);
     116    while (m_currentNode->exec() > exec) {
     117        didExecute(exec, m_currentNode->callIdentifier());
     118        ASSERT(m_currentNode);
     119    }
     120}
     121
    113122void ProfileGenerator::stopProfiling()
    114123{
     
    118127    removeProfileEnd();
    119128
    120     ASSERT_ARG(m_currentNode, m_currentNode);
     129    ASSERT(m_currentNode);
    121130
    122131    // Set the current node to the parent, because we are in a call that
     
    125134
    126135   if (double headSelfTime = m_head->selfTime()) {
    127         RefPtr<ProfileNode> idleNode = ProfileNode::create(CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
     136        RefPtr<ProfileNode> idleNode = ProfileNode::create(0, CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
    128137
    129138        idleNode->setTotalTime(headSelfTime);
Note: See TracChangeset for help on using the changeset viewer.