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/ProfileNode.cpp

    r65305 r72160  
    5757}
    5858
    59 ProfileNode::ProfileNode(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
    60     : m_callIdentifier(callIdentifier)
     59ProfileNode::ProfileNode(ExecState* exec, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
     60    : m_exec(exec)
     61    , m_callIdentifier(callIdentifier)
    6162    , m_head(headNode)
    6263    , m_parent(parentNode)
     
    7374}
    7475
    75 ProfileNode::ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy)
    76     : m_callIdentifier(nodeToCopy->callIdentifier())
     76ProfileNode::ProfileNode(ExecState* exec, ProfileNode* headNode, ProfileNode* nodeToCopy)
     77    : m_exec(exec)
     78    , m_callIdentifier(nodeToCopy->callIdentifier())
    7779    , m_head(headNode)
    7880    , m_parent(nodeToCopy->parent())
     
    8890}
    8991
    90 ProfileNode* ProfileNode::willExecute(const CallIdentifier& callIdentifier)
     92ProfileNode* ProfileNode::willExecute(ExecState* exec, const CallIdentifier& callIdentifier)
    9193{
    9294    for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
     
    9799    }
    98100
    99     RefPtr<ProfileNode> newChild = ProfileNode::create(callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
     101    RefPtr<ProfileNode> newChild = ProfileNode::create(exec, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
    100102    if (m_children.size())
    101103        m_children.last()->setNextSibling(newChild.get());
Note: See TracChangeset for help on using the changeset viewer.