Ignore:
Timestamp:
Jul 24, 2013, 9:02:07 PM (12 years ago)
Author:
[email protected]
Message:

fourthTier: CallFrame::trueCallFrame() should populate the bytecodeOffset field
when reifying inlined frames..
https://bugs.webkit.org/show_bug.cgi?id=117209.

Reviewed by Geoffrey Garen.

When reifying an inlined frame, we fill in its CodeBlock, and
bytecodeOffset. We also set the InlinedFrame bit in the location field.
This is needed in order to iterate the stack correctly. Here's why:

Let's say we have the following stack trace:

X calls A inlines B inlines C calls D

Based on the above scenario,

  1. D's callerFrame points to A (not C).
  2. A has a codeOriginIndex that points to C.

When iterating the stack (from D back towards X), we will encounter A
twice:

t1. when trying to find C as D's caller.

This is the time when we reify B and C using the
codeOriginIndex in A, and return C as the caller frame of D.

t2. when getting's the reified B's caller.

This time, we don't run the reification process, and
just take A as the caller frame of B.

To discern which treatment of the DFG frame (i.e. A) we need to apply,
we check if the callee is an inlined frame:

If callee is NOT an inlined frame (e.g. frame D), apply treatment t1.
If callee is an inlined frame (e.g. frame B), apply treatment t2.

Why not just reify A by replacing its codeOriginIndex with A's
bytecodeOffset?

We can't do this because D's callerFrame pointer still points to A, and
needs to remain that way because we did not deopt A. It remains a DFG
frame which inlined B and C.

If we replace the codeOriginIndex in A with A's bytecodeOffset, we will
only get to iterate the stack correctly once. If we try to iterate the
stack a second time, we will not have the information from the
codeOriginIndex to tell us that D's caller is actually the inlined C,
and not A.

To recap, when reifying frames for stack iteration purposes, the DFG
frame needs to hold on to its codeOriginIndex. This in turn means the
DFG frame will need to be treated in 2 possible ways, and we need to
know if a callee frame is an inlined frame in order to choose the
correct treatment for the DFG frame.

Other changes:

  • Simplified Interpreter::getCallerInfo().
  • Removed CodeBlock::codeOriginForReturn() and supporting code which is now unneeded.
  • Moved CallFrame location bit encoding from the CodeOrigin to the new CallFrame::Location class.
  • Explicitly tagged inlined frames. This is necessary in order to iterate the stack correctly as explained above.
  • bytecode/CodeBlock.cpp:
  • bytecode/CodeBlock.h:

(JSC::CodeBlock::codeOrigins):
(CodeBlock):
(JSC::CodeBlock::codeOrigin):
(RareData):

  • bytecode/CodeOrigin.h:

(CodeOrigin):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::beginCall):

  • interpreter/CallFrame.cpp:

(JSC::CallFrame::trueCallFrame):
(JSC::CallFrame::trueCallerFrame):
(JSC::CallFrame::bytecodeOffsetFromCodeOriginIndex):

  • interpreter/CallFrame.h:

(Location):
(ExecState):
(JSC::ExecState::trueCallerFrame):
(JSC::ExecState::callerFrameNoFlags):

  • interpreter/CallFrameInlines.h:

(JSC::CallFrame::Location::encode):
(JSC::CallFrame::Location::decode):
(JSC::CallFrame::Location::isBytecodeOffset):
(JSC::CallFrame::Location::isCodeOriginIndex):
(JSC::CallFrame::Location::isInlinedFrame):
(JSC::CallFrame::isInlinedFrame):
(JSC::CallFrame::setIsInlinedFrame):
(JSC::CallFrame::hasLocationAsBytecodeOffset):
(JSC::CallFrame::hasLocationAsCodeOriginIndex):
(JSC::CallFrame::locationAsBytecodeOffset):
(JSC::CallFrame::setLocationAsBytecodeOffset):
(JSC::CallFrame::locationAsCodeOriginIndex):

  • interpreter/Interpreter.cpp:

(JSC::getCallerInfo):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::findFunctionCallFrameFromVMCode):

  • runtime/Arguments.cpp:

(JSC::Arguments::tearOff):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.cpp

    r153209 r153211  
    5353{
    5454    ASSERT(codeBlock());
    55     ASSERT(!CodeOrigin::isHandle(offset));
     55    ASSERT(Location::isBytecodeOffset(offset));
    5656    setCurrentVPC(codeBlock()->instructions().begin() + offset);
    5757    ASSERT(hasLocationAsBytecodeOffset());
     
    6969   
    7070#if ENABLE(DFG_JIT)
    71 bool CallFrame::isInlineCallFrameSlow()
    72 {
    73     if (!callee())
    74         return false;
    75     JSCell* calleeAsFunctionCell = getJSFunction(callee());
    76     if (!calleeAsFunctionCell)
    77         return false;
    78     JSFunction* calleeAsFunction = jsCast<JSFunction*>(calleeAsFunctionCell);
    79     return calleeAsFunction->executable() != codeBlock()->ownerExecutable();
    80 }
    81 
    82 CallFrame* CallFrame::trueCallFrame(AbstractPC pc)
     71CallFrame* CallFrame::trueCallFrame()
    8372{
    8473    // Am I an inline call frame? If so, we're done.
    85     if (isInlineCallFrame())
     74    if (isInlinedFrame())
    8675        return this;
    8776   
     
    9685        return this;
    9786   
    98     // At this point the PC must be due either to the DFG, or it must be unset.
    99     ASSERT(pc.hasJITReturnAddress() || !pc);
    100    
    10187    // Try to determine the CodeOrigin. If we don't have a pc set then the only way
    10288    // that this makes sense is if the CodeOrigin index was set in the call frame.
    103     // FIXME: Note that you will see "Not currently in inlined code" comments below.
    104     // Currently, we do not record code origins for code that is not inlined, because
    105     // the only thing that we use code origins for is determining the inline stack.
    106     // But in the future, we'll want to use this same functionality (having a code
    107     // origin mapping for any calls out of JIT code) to determine the PC at any point
    108     // in the stack even if not in inlined code. When that happens, the code below
    109     // will have to change the way it detects the presence of inlining: it will always
    110     // get a code origin, but sometimes, that code origin will not have an inline call
    111     // frame. In that case, this method should bail and return this.
    11289    CodeOrigin codeOrigin;
    113     if (pc.isSet()) {
    114         ReturnAddressPtr currentReturnPC = pc.jitReturnAddress();
    115        
    116         bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin);
    117         ASSERT(hasCodeOrigin);
    118         if (!hasCodeOrigin) {
    119             // In release builds, if we find ourselves in a situation where the return PC doesn't
    120             // correspond to a valid CodeOrigin, we return zero instead of continuing. Some of
    121             // the callers of trueCallFrame() will be able to recover and do conservative things,
    122             // while others will crash.
    123             return 0;
    124         }
    125     } else {
    126         unsigned index = locationAsCodeOriginIndex();
    127         ASSERT(machineCodeBlock->canGetCodeOrigin(index));
    128         if (!machineCodeBlock->canGetCodeOrigin(index)) {
    129             // See above. In release builds, we try to protect ourselves from crashing even
    130             // though stack walking will be goofed up.
    131             return 0;
    132         }
    133         codeOrigin = machineCodeBlock->codeOrigin(index);
     90    unsigned index = locationAsCodeOriginIndex();
     91    ASSERT(machineCodeBlock->canGetCodeOrigin(index));
     92    if (!machineCodeBlock->canGetCodeOrigin(index)) {
     93        // See above. In release builds, we try to protect ourselves from crashing even
     94        // though stack walking will be goofed up.
     95        return 0;
    13496    }
     97    codeOrigin = machineCodeBlock->codeOrigin(index);
    13598
    13699    if (!codeOrigin.inlineCallFrame)
    137100        return this; // Not currently in inlined code.
    138    
     101
     102    CodeOrigin innerMostCodeOrigin = codeOrigin;
     103
    139104    for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
    140105        InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
     
    145110       
    146111        // Fill in the inlinedCaller
    147         inlinedCaller->setCodeBlock(machineCodeBlock);
     112        inlinedCaller->setCodeBlock(inlineCallFrame->baselineCodeBlock());
    148113        if (calleeAsFunction)
    149114            inlinedCaller->setScope(calleeAsFunction->scope());
     
    155120        inlinedCaller->setInlineCallFrame(inlineCallFrame);
    156121        inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
     122        inlinedCaller->setLocationAsBytecodeOffset(codeOrigin.bytecodeIndex);
     123        inlinedCaller->setIsInlinedFrame();
    157124        if (calleeAsFunction)
    158125            inlinedCaller->setCallee(calleeAsFunction);
    159126       
     127        codeOrigin = inlineCallFrame->caller;
    160128        inlineCallFrame = nextInlineCallFrame;
    161129    }
    162130   
    163     return this + codeOrigin.inlineCallFrame->stackOffset;
     131    return this + innerMostCodeOrigin.inlineCallFrame->stackOffset;
    164132}
    165133       
    166134CallFrame* CallFrame::trueCallerFrame()
    167135{
     136    CallFrame* callerFrame = this->callerFrame()->removeHostCallFrameFlag();
    168137    if (!codeBlock())
    169         return callerFrame()->removeHostCallFrameFlag();
     138        return callerFrame;
    170139
    171140    // this -> The callee; this is either an inlined callee in which case it already has
     
    177146
    178147    // Am I an inline call frame? If so, we're done.
    179     if (isInlineCallFrame())
    180         return callerFrame()->removeHostCallFrameFlag();
     148    if (isInlinedFrame())
     149        return callerFrame;
    181150   
    182151    // I am a machine call frame, so the question is: is my caller a machine call frame
    183152    // that has inlines or a machine call frame that doesn't?
    184     CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag();
    185     if (!machineCaller)
     153    if (!callerFrame)
    186154        return 0;
    187     ASSERT(!machineCaller->isInlineCallFrame());
     155
     156    if (!callerFrame->codeBlock())
     157        return callerFrame;
     158    ASSERT(!callerFrame->isInlinedFrame());
    188159   
    189     // Figure out how we want to get the current code location.
    190     if (!hasReturnPC() || returnAddressIsInCtiTrampoline(returnPC()))
    191         return machineCaller->trueCallFrameFromVMCode()->removeHostCallFrameFlag();
    192    
    193     return machineCaller->trueCallFrame(returnPC())->removeHostCallFrameFlag();
     160    return callerFrame->trueCallFrame()->removeHostCallFrameFlag();
    194161}
    195162
    196 CodeBlock* CallFrame::someCodeBlockForPossiblyInlinedCode()
     163unsigned CallFrame::bytecodeOffsetFromCodeOriginIndex()
    197164{
    198     if (!isInlineCallFrame())
    199         return codeBlock();
    200    
    201     return jsCast<FunctionExecutable*>(inlineCallFrame()->executable.get())->baselineCodeBlockFor(
    202         inlineCallFrame()->isCall ? CodeForCall : CodeForConstruct);
     165    ASSERT(hasLocationAsCodeOriginIndex());
     166    CodeBlock* codeBlock = this->codeBlock();
     167    ASSERT(codeBlock);
     168
     169    CodeOrigin codeOrigin;
     170    unsigned index = locationAsCodeOriginIndex();
     171    ASSERT(codeBlock->canGetCodeOrigin(index));
     172    codeOrigin = codeBlock->codeOrigin(index);
     173
     174    for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
     175        if (inlineCallFrame->baselineCodeBlock() == codeBlock)
     176            return codeOrigin.bytecodeIndex;
     177
     178        codeOrigin = inlineCallFrame->caller;
     179        inlineCallFrame = codeOrigin.inlineCallFrame;
     180    }
     181    return codeOrigin.bytecodeIndex;
    203182}
    204183
    205 #endif
     184#endif // ENABLE(DFG_JIT)
    206185
    207186Register* CallFrame::frameExtentInternal()
Note: See TracChangeset for help on using the changeset viewer.