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

    r153216 r153218  
    6464#include "Register.h"
    6565#include "SamplingTool.h"
     66#include "StackIterator.h"
    6667#include "StrictEvalActivation.h"
    6768#include "StrongInlines.h"
     
    100101        m_interpreter.stack().disableErrorStackReserve();
    101102}
    102 
    103 static CallFrame* getCallerInfo(VM*, CallFrame*, unsigned& bytecodeOffset, CodeBlock*& callerOut);
    104103
    105104// Returns the depth of the scope chain within a given call frame.
     
    322321        dataLogF("[ReturnJITPC]              | %10p | %p \n", it, pc.jitReturnAddress().value());
    323322#endif
    324     unsigned bytecodeOffset = 0;
    325     int line = 0;
    326     CodeBlock* callerCodeBlock = 0;
    327     getCallerInfo(&callFrame->vm(), callFrame, bytecodeOffset, callerCodeBlock);
    328     line = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
    329     dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", it, bytecodeOffset, line);
    330     ++it;
     323    StackIterator iter = callFrame->begin();
     324    ++iter;
     325    if (iter != callFrame->end()) {
     326        unsigned line = 0;
     327        unsigned unusedColumn = 0;
     328        iter->computeLineAndColumn(line, unusedColumn);
     329        dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", it, iter->bytecodeOffset(), line);
     330        ++it;
     331    }
    331332    dataLogF("[CodeBlock]                | %10p | %p \n", it, callFrame->codeBlock());
    332333    ++it;
     
    377378}
    378379
    379 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
    380 {
     380NEVER_INLINE bool Interpreter::unwindCallFrame(StackIterator& iter, JSValue exceptionValue)
     381{
     382    CallFrame* callFrame = iter->callFrame();
     383    CodeBlock* codeBlock = iter->codeBlock();
    381384    CodeBlock* oldCodeBlock = codeBlock;
    382385    JSScope* scope = callFrame->scope();
     
    408411    CallFrame* callerFrame = callFrame->callerFrame();
    409412    callFrame->vm().topCallFrame = callerFrame;
    410     if (callerFrame->hasHostCallFrameFlag())
    411         return false;
    412     callFrame = getCallerInfo(&callFrame->vm(), callFrame, bytecodeOffset, codeBlock);
    413     return true;
     413    return !callerFrame->hasHostCallFrameFlag();
    414414}
    415415
     
    468468}
    469469
    470 static unsigned getBytecodeOffsetForCallFrame(CallFrame* callFrame)
    471 {
    472     callFrame = callFrame->removeHostCallFrameFlag();
    473     CodeBlock* codeBlock = callFrame->codeBlock();
    474     if (!codeBlock)
    475         return 0;
    476 #if ENABLE(DFG_JIT)
    477     if (JITCode::isOptimizingJIT(codeBlock->jitType()))
    478         return codeBlock->codeOrigin(callFrame->locationAsCodeOriginIndex()).bytecodeIndex;
    479 #endif
    480     return callFrame->locationAsBytecodeOffset();
    481 }
    482 
    483 static CallFrame* getCallerInfo(VM* vm, CallFrame* callFrame, unsigned& bytecodeOffset, CodeBlock*& caller)
    484 {
    485     ASSERT_UNUSED(vm, vm);
    486     bytecodeOffset = 0;
    487     ASSERT(!callFrame->hasHostCallFrameFlag());
    488     CallFrame* trueCallerFrame = callFrame->trueCallerFrame();
    489     ASSERT(!trueCallerFrame->hasHostCallFrameFlag());
    490 
    491     if (trueCallerFrame == CallFrame::noCaller() || !trueCallerFrame || !trueCallerFrame->codeBlock()) {
    492         caller = 0;
    493         return trueCallerFrame;
    494     }
    495    
    496     CodeBlock* callerCodeBlock = trueCallerFrame->codeBlock();
    497 #if ENABLE(DFG_JIT)
    498     if (trueCallerFrame->hasLocationAsCodeOriginIndex())
    499         bytecodeOffset = trueCallerFrame->bytecodeOffsetFromCodeOriginIndex();
    500     else
    501 #endif // ENABLE(DFG_JIT)
    502         bytecodeOffset = trueCallerFrame->locationAsBytecodeOffset();
    503 
    504     caller = callerCodeBlock;
    505     return trueCallerFrame;
    506 }
    507 
    508470static ALWAYS_INLINE const String getSourceURLFromCallFrame(CallFrame* callFrame)
    509471{
     
    512474}
    513475
    514 static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame)
    515 {
    516     ASSERT(!callFrame->hasHostCallFrameFlag());
    517 
    518     switch (callFrame->codeBlock()->codeType()) {
    519     case EvalCode:
     476static StackFrameCodeType getStackFrameCodeType(StackIterator iter)
     477{
     478    switch (iter->codeType()) {
     479    case StackIterator::Frame::Eval:
    520480        return StackFrameEvalCode;
    521     case FunctionCode:
     481    case StackIterator::Frame::Function:
    522482        return StackFrameFunctionCode;
    523     case GlobalCode:
     483    case StackIterator::Frame::Global:
    524484        return StackFrameGlobalCode;
     485    case StackIterator::Frame::Native:
     486        ASSERT_NOT_REACHED();
     487        return StackFrameNativeCode;
    525488    }
    526489    RELEASE_ASSERT_NOT_REACHED();
     
    577540}
    578541
    579 void Interpreter::getStackTrace(VM* vm, Vector<StackFrame>& results, size_t maxStackSize)
    580 {
    581     CallFrame* callFrame = vm->topCallFrame->removeHostCallFrameFlag();
    582     if (!callFrame || callFrame == CallFrame::noCaller())
    583         return;
    584     unsigned bytecodeOffset = getBytecodeOffsetForCallFrame(callFrame);
    585     callFrame = callFrame->trueCallFrame();
     542void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
     543{
     544    VM& vm = m_vm;
     545    CallFrame* callFrame = vm.topCallFrame->removeHostCallFrameFlag();
    586546    if (!callFrame)
    587547        return;
    588     CodeBlock* callerCodeBlock = callFrame->codeBlock();
    589 
    590     while (callFrame && callFrame != CallFrame::noCaller() && maxStackSize--) {
    591         String sourceURL;
    592         if (callerCodeBlock) {
    593             sourceURL = getSourceURLFromCallFrame(callFrame);
     548    StackIterator iter = callFrame->begin();
     549    for (; iter != callFrame->end() && maxStackSize--; ++iter) {
     550        if (iter->isJSFrame()) {
     551            CodeBlock* codeBlock = iter->codeBlock();
    594552            StackFrame s = {
    595                 Strong<JSObject>(*vm, callFrame->callee()),
    596                 getStackFrameCodeType(callFrame),
    597                 Strong<ExecutableBase>(*vm, callerCodeBlock->ownerExecutable()),
    598                 Strong<UnlinkedCodeBlock>(*vm, callerCodeBlock->unlinkedCodeBlock()),
    599                 callerCodeBlock->source(),
    600                 callerCodeBlock->ownerExecutable()->lineNo(),
    601                 callerCodeBlock->firstLineColumnOffset(),
    602                 callerCodeBlock->sourceOffset(),
    603                 bytecodeOffset,
    604                 sourceURL
     553                Strong<JSObject>(vm, iter->callee()),
     554                getStackFrameCodeType(iter),
     555                Strong<ExecutableBase>(vm, codeBlock->ownerExecutable()),
     556                Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()),
     557                codeBlock->source(),
     558                codeBlock->ownerExecutable()->lineNo(),
     559                codeBlock->firstLineColumnOffset(),
     560                codeBlock->sourceOffset(),
     561                iter->bytecodeOffset(),
     562                iter->sourceURL()
    605563            };
    606 
    607564            results.append(s);
    608565        } else {
    609             StackFrame s = { Strong<JSObject>(*vm, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
     566            StackFrame s = { Strong<JSObject>(vm, iter->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
    610567            results.append(s);
    611568        }
    612         callFrame = getCallerInfo(vm, callFrame, bytecodeOffset, callerCodeBlock);
    613569    }
    614570}
     
    625581   
    626582    Vector<StackFrame> stackTrace;
    627     getStackTrace(&callFrame->vm(), stackTrace);
     583    vm->interpreter->getStackTrace(stackTrace);
    628584    vm->exceptionStack() = RefCountedArray<StackFrame>(stackTrace);
    629585    if (stackTrace.isEmpty() || !error.isObject())
     
    677633        if (!callFrame->vm().exceptionStack().size()) {
    678634            Vector<StackFrame> stack;
    679             Interpreter::getStackTrace(&callFrame->vm(), stack);
     635            callFrame->vm().interpreter->getStackTrace(stack);
    680636            callFrame->vm().exceptionStack() = RefCountedArray<StackFrame>(stack);
    681637        }
     
    690646    // Calculate an exception handler vPC, unwinding call frames as necessary.
    691647    HandlerInfo* handler = 0;
    692     while (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
    693         if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
    694             if (LegacyProfiler* profiler = callFrame->vm().enabledProfiler())
    695                 profiler->exceptionUnwind(callFrame);
    696             return 0;
    697         }
     648    VM& vm = callFrame->vm();
     649    ASSERT(callFrame == vm.topCallFrame);
     650    for (StackIterator iter = callFrame->begin(); iter != callFrame->end(); ++iter) {
     651        callFrame = iter->callFrame();
     652        codeBlock = iter->codeBlock();
     653        bytecodeOffset = iter->bytecodeOffset();
     654
     655        if (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
     656            if (!unwindCallFrame(iter, exceptionValue)) {
     657                if (LegacyProfiler* profiler = vm.enabledProfiler())
     658                    profiler->exceptionUnwind(callFrame);
     659                return 0;
     660            }
     661        } else
     662            break;
    698663    }
    699664
     
    12881253            return;
    12891254    }
    1290 }
    1291    
    1292 JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunction* function) const
    1293 {
    1294     CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function);
    1295     if (!functionCallFrame)
    1296         return jsNull();
    1297 
    1298     Arguments* arguments = Arguments::create(functionCallFrame->vm(), functionCallFrame);
    1299     arguments->tearOff(functionCallFrame);
    1300     return JSValue(arguments);
    1301 }
    1302 
    1303 JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction* function) const
    1304 {
    1305     CallFrame* functionCallFrame = findFunctionCallFrameFromVMCode(callFrame, function);
    1306 
    1307     if (!functionCallFrame)
    1308         return jsNull();
    1309    
    1310     unsigned bytecodeOffset;
    1311     CodeBlock* unusedCallerCodeBlock = 0;
    1312     CallFrame* callerFrame = getCallerInfo(&callFrame->vm(), functionCallFrame, bytecodeOffset, unusedCallerCodeBlock);
    1313     if (!callerFrame)
    1314         return jsNull();
    1315     JSValue caller = callerFrame->callee();
    1316     if (!caller)
    1317         return jsNull();
    1318 
    1319     // Skip over function bindings.
    1320     ASSERT(caller.isObject());
    1321     while (asObject(caller)->inherits(&JSBoundFunction::s_info)) {
    1322         callerFrame = getCallerInfo(&callFrame->vm(), callerFrame, bytecodeOffset, unusedCallerCodeBlock);
    1323         if (!callerFrame)
    1324             return jsNull();
    1325         caller = callerFrame->callee();
    1326         if (!caller)
    1327             return jsNull();
    1328     }
    1329 
    1330     return caller;
    1331 }
    1332 
    1333 CallFrame* Interpreter::findFunctionCallFrameFromVMCode(CallFrame* callFrame, JSFunction* function)
    1334 {
    1335     for (CallFrame* candidate = callFrame->trueCallFrame(); candidate; candidate = candidate->trueCallerFrame()) {
    1336         if (candidate->callee() == function)
    1337             return candidate;
    1338     }
    1339     return 0;
    1340 }
     1255}   
    13411256
    13421257void Interpreter::enableSampler()
Note: See TracChangeset for help on using the changeset viewer.