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

fourthTier: Introducing the StackIterator class.

This was a non trivial merge as trunk has changed computation of line and column information

Introducing the StackIterator class.
https://bugs.webkit.org/show_bug.cgi?id=117390.

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

The StackIterator class is meant to unify the way we iterate the JS
stack. It also makes it so that we don't have to copy the frame data
into the intermediate StackFrame struct before processing it.
Unfortunately we still can't get rid of StackFrame because it is used
to record frame information for the Exception stack that is expected
to persist beyond when the frames have been popped off the JS stack.

The StackIterator will iterate over all "logical" frames (i.e. including
inlined frames). As it iterates the JS stack, if it encounters a DFG
frame that has inlined frames, the iterator will canonicalize the
inlined frames before returning. Once canonicalized, the frame can be
read like any other frame.

The StackIterator implements a Frame class that inherits from CallFrame.
The StackIterator::Frame serves as reader of the CallFrame that makes
it easier to access information about the frame. The StackIterator::Frame
only adds functions, and no additional data fields.

  • API/JSContextRef.cpp:

(JSContextCreateBacktrace):

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • interpreter/CallFrame.cpp:

(JSC::CallFrame::begin):
(JSC::CallFrame::beginAt):

  • interpreter/CallFrame.h:

(JSC::ExecState::setInlineCallFrame):
(ExecState):
(JSC::ExecState::end):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::dumpRegisters):
(JSC::Interpreter::unwindCallFrame):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::debug):

  • interpreter/Interpreter.h:

(Interpreter):

  • interpreter/StackIterator.cpp: Added.

(JSC::StackIterator::StackIterator):
(JSC::StackIterator::beginAt):
(JSC::StackIterator::gotoNextFrame):

  • Based on the deleted Interpreter::findFunctionCallFrameFromVMCode().

(JSC::StackIterator::findFrameForFunction):

  • Based on the deleted Interpreter::retrieveCallerFromVMCode().

(JSC::StackIterator::Frame::codeType):

  • Based on the deleted getStackFrameCodeType().

(JSC::StackIterator::Frame::functionName):

  • Based on StackFrame::friendlyFunctionName().

(JSC::StackIterator::Frame::sourceURL):

  • Based on StackFrame::friendlySourceURL().

(JSC::StackIterator::Frame::toString):

  • Based on StackFrame::toString().

(JSC::StackIterator::Frame::bytecodeOffset):
(JSC::StackIterator::Frame::line):

  • Based on StackFrame::line().

(JSC::StackIterator::Frame::column):

  • Based on StackFrame::column().

(JSC::StackIterator::Frame::arguments):

  • Based on the deleted Interpreter::retrieveArgumentsFromVMCode().

(JSC::StackIterator::Frame::retrieveExpressionInfo):

  • Based on StackFrame::expressionInfo().

(JSC::StackIterator::Frame::logicalFrame):

  • Based on the now deleted CallFrame::trueCallFrame().

(JSC::StackIterator::Frame::logicalCallerFrame):

  • Based on the now deleted CallFrame::trueCallerFrame().

(JSC::jitTypeName):
(JSC::printIndents):
(JSC::printif):
(JSC::StackIterator::Frame::print):
(debugPrintCallFrame):

  • Prints the contents of the frame for debugging purposes. There are 2 versions that can be used as follows:
  1. When you have a valid StackIterator, you can print the current frame's content using the print instance method:

iter->print(indentLevel);

  1. When you have a CallFrame* that you want to dump from a debugger console, you can print its content as follows:

(gdb) call debugPrintCallFrame(callFrame)

A sample of the output looks like this:

frame 0x1510c70b0 {

name 'shouldBe'
sourceURL 'testapi.js'
hostFlag 0
isInlinedFrame 0
callee 0x15154efb0
returnPC 0x10ed0786d
callerFrame 0x1510c7058
logicalCallerFrame 0x1510c7058
rawLocationBits 27 0x1b
codeBlock 0x7fe79b037200

bytecodeOffset 27 0x1b / 210
line 46
column 20
jitType 3 <BaselineJIT> isOptimizingJIT 0
hasCodeOrigins 0

}

  • interpreter/StackIterator.h: Added.

(StackIterator::Frame):
(JSC::StackIterator::Frame::create):
(JSC::StackIterator::Frame::isJSFrame):
(JSC::StackIterator::Frame::callFrame):

  • interpreter/StackIteratorPrivate.h: Added.

(StackIterator):
(JSC::StackIterator::operator*):
(JSC::StackIterator::operator->):
(JSC::StackIterator::operator==):
(JSC::StackIterator::operator!=):
(JSC::StackIterator::operator++):
(JSC::StackIterator::end):
(JSC::StackIterator::empty):

  • jsc.cpp:

(functionJSCStack):

  • profiler/ProfileGenerator.cpp:

(JSC::ProfileGenerator::addParentForConsoleStart):

  • profiler/ProfileNode.h:

(ProfileNode):

  • runtime/JSFunction.cpp:

(JSC::retrieveArguments):
(JSC::JSFunction::argumentsGetter):
(JSC::skipOverBoundFunctions):
(JSC::retrieveCallerFunction):
(JSC::JSFunction::callerGetter):
(JSC::JSFunction::getOwnPropertyDescriptor):
(JSC::JSFunction::defineOwnProperty):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):

  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorGetPrototypeOf):

  • runtime/Operations.h:

Source/WebCore:

No new tests.

  • ForwardingHeaders/interpreter/StackIterator.h: Added.
  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::send):

  • bindings/js/ScriptCallStackFactory.cpp:

(WebCore::createScriptCallStack):

File:
1 edited

Legend:

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

    r153215 r153218  
    6868   
    6969#if ENABLE(DFG_JIT)
    70 CallFrame* CallFrame::trueCallFrame()
    71 {
    72     // Am I an inline call frame? If so, we're done.
    73     if (isInlinedFrame())
    74         return this;
    75    
    76     // If I don't have a code block, then I'm not DFG code, so I'm the true call frame.
    77     CodeBlock* machineCodeBlock = codeBlock();
    78     if (!machineCodeBlock)
    79         return this;
    80    
    81     // If the code block does not have any code origins, then there was no inlining, so
    82     // I'm done.
    83     if (!machineCodeBlock->hasCodeOrigins())
    84         return this;
    85    
    86     // Try to determine the CodeOrigin. If we don't have a pc set then the only way
    87     // that this makes sense is if the CodeOrigin index was set in the call frame.
    88     CodeOrigin codeOrigin;
    89     unsigned index = locationAsCodeOriginIndex();
    90     ASSERT(machineCodeBlock->canGetCodeOrigin(index));
    91     if (!machineCodeBlock->canGetCodeOrigin(index)) {
    92         // See above. In release builds, we try to protect ourselves from crashing even
    93         // though stack walking will be goofed up.
    94         return 0;
    95     }
    96     codeOrigin = machineCodeBlock->codeOrigin(index);
    97 
    98     if (!codeOrigin.inlineCallFrame)
    99         return this; // Not currently in inlined code.
    100 
    101     CodeOrigin innerMostCodeOrigin = codeOrigin;
    102 
    103     for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
    104         InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame;
    105        
    106         CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset;
    107        
    108         JSFunction* calleeAsFunction = inlineCallFrame->callee.get();
    109        
    110         // Fill in the inlinedCaller
    111         inlinedCaller->setCodeBlock(inlineCallFrame->baselineCodeBlock());
    112         if (calleeAsFunction)
    113             inlinedCaller->setScope(calleeAsFunction->scope());
    114         if (nextInlineCallFrame)
    115             inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset);
    116         else
    117             inlinedCaller->setCallerFrame(this);
    118        
    119         inlinedCaller->setInlineCallFrame(inlineCallFrame);
    120         inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
    121         inlinedCaller->setLocationAsBytecodeOffset(codeOrigin.bytecodeIndex);
    122         inlinedCaller->setIsInlinedFrame();
    123         if (calleeAsFunction)
    124             inlinedCaller->setCallee(calleeAsFunction);
    125        
    126         codeOrigin = inlineCallFrame->caller;
    127         inlineCallFrame = nextInlineCallFrame;
    128     }
    129    
    130     return this + innerMostCodeOrigin.inlineCallFrame->stackOffset;
    131 }
    132        
    133 CallFrame* CallFrame::trueCallerFrame()
    134 {
    135     CallFrame* callerFrame = this->callerFrame()->removeHostCallFrameFlag();
    136     if (!codeBlock())
    137         return callerFrame;
    138 
    139     // this -> The callee; this is either an inlined callee in which case it already has
    140     //    a pointer to the true caller. Otherwise it contains current PC in the machine
    141     //    caller.
    142     //
    143     // machineCaller -> The caller according to the machine, which may be zero or
    144     //    more frames above the true caller due to inlining.
    145 
    146     // Am I an inline call frame? If so, we're done.
    147     if (isInlinedFrame())
    148         return callerFrame;
    149    
    150     // I am a machine call frame, so the question is: is my caller a machine call frame
    151     // that has inlines or a machine call frame that doesn't?
    152     if (!callerFrame)
    153         return 0;
    154 
    155     if (!callerFrame->codeBlock())
    156         return callerFrame;
    157     ASSERT(!callerFrame->isInlinedFrame());
    158    
    159     return callerFrame->trueCallFrame()->removeHostCallFrameFlag();
    160 }
    161 
    16270unsigned CallFrame::bytecodeOffsetFromCodeOriginIndex()
    16371{
     
    19098}
    19199
     100StackIterator CallFrame::begin(StackIterator::FrameFilter filter)
     101{
     102    ASSERT(this);
     103    return StackIterator(this, filter);
    192104}
     105
     106StackIterator CallFrame::find(JSFunction* calleeFunctionObj, StackIterator::FrameFilter filter)
     107{
     108    ASSERT(this);
     109    StackIterator iter = StackIterator(this, filter);
     110    iter.find(calleeFunctionObj);
     111    return iter;
     112}
     113
     114StackIterator::Frame* CallFrame::end()
     115{
     116    return StackIterator::end();
     117}
     118
     119}
Note: See TracChangeset for help on using the changeset viewer.