2  * Copyright (C) 2013 Apple Inc. All rights reserved. 
   4  * Redistribution and use in source and binary forms, with or without 
   5  * modification, are permitted provided that the following conditions 
   7  * 1. Redistributions of source code must retain the above copyright 
   8  *    notice, this list of conditions and the following disclaimer. 
   9  * 2. Redistributions in binary form must reproduce the above copyright 
  10  *    notice, this list of conditions and the following disclaimer in the 
  11  *    documentation and/or other materials provided with the distribution. 
  13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 
  14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR 
  17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
  21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  27 #include "StackVisitor.h" 
  29 #include "Arguments.h" 
  30 #include "CallFrameInlines.h" 
  31 #include "Executable.h" 
  32 #include "Interpreter.h" 
  33 #include "JSCInlines.h" 
  34 #include <wtf/DataLog.h> 
  38 StackVisitor::StackVisitor(CallFrame
* startFrame
) 
  41     readFrame(startFrame
); 
  44 void StackVisitor::gotoNextFrame() 
  47     if (m_frame
.isInlinedFrame()) { 
  48         InlineCallFrame
* inlineCallFrame 
= m_frame
.inlineCallFrame(); 
  49         CodeOrigin
* callerCodeOrigin 
= &inlineCallFrame
->caller
; 
  50         readInlinedFrame(m_frame
.callFrame(), callerCodeOrigin
); 
  53 #endif // ENABLE(DFG_JIT) 
  54         readFrame(m_frame
.callerFrame()); 
  57 void StackVisitor::readFrame(CallFrame
* callFrame
) 
  59     ASSERT(!callFrame
->isVMEntrySentinel()); 
  66     readNonInlinedFrame(callFrame
); 
  68 #else // !ENABLE(DFG_JIT) 
  69     // If the frame doesn't have a code block, then it's not a DFG frame. 
  70     // Hence, we're not at an inlined frame. 
  71     CodeBlock
* codeBlock 
= callFrame
->codeBlock(); 
  73         readNonInlinedFrame(callFrame
); 
  77     // If the code block does not have any code origins, then there's no 
  78     // inlining. Hence, we're not at an inlined frame. 
  79     if (!codeBlock
->hasCodeOrigins()) { 
  80         readNonInlinedFrame(callFrame
); 
  84     unsigned index 
= callFrame
->locationAsCodeOriginIndex(); 
  85     ASSERT(codeBlock
->canGetCodeOrigin(index
)); 
  86     if (!codeBlock
->canGetCodeOrigin(index
)) { 
  87         // See assertion above. In release builds, we try to protect ourselves 
  88         // from crashing even though stack walking will be goofed up. 
  93     CodeOrigin codeOrigin 
= codeBlock
->codeOrigin(index
); 
  94     if (!codeOrigin
.inlineCallFrame
) { 
  95         readNonInlinedFrame(callFrame
, &codeOrigin
); 
  99     readInlinedFrame(callFrame
, &codeOrigin
); 
 100 #endif // !ENABLE(DFG_JIT) 
 103 void StackVisitor::readNonInlinedFrame(CallFrame
* callFrame
, CodeOrigin
* codeOrigin
) 
 105     m_frame
.m_callFrame 
= callFrame
; 
 106     m_frame
.m_argumentCountIncludingThis 
= callFrame
->argumentCountIncludingThis(); 
 107     m_frame
.m_callerFrame 
= callFrame
->callerFrameSkippingVMEntrySentinel(); 
 108     m_frame
.m_callee 
= callFrame
->callee(); 
 109     m_frame
.m_scope 
= callFrame
->scope(); 
 110     m_frame
.m_codeBlock 
= callFrame
->codeBlock(); 
 111     m_frame
.m_bytecodeOffset 
= !m_frame
.codeBlock() ? 0 
 112         : codeOrigin 
? codeOrigin
->bytecodeIndex
 
 113         : callFrame
->locationAsBytecodeOffset(); 
 115     m_frame
.m_inlineCallFrame 
= 0; 
 120 static int inlinedFrameOffset(CodeOrigin
* codeOrigin
) 
 122     InlineCallFrame
* inlineCallFrame 
= codeOrigin
->inlineCallFrame
; 
 123     int frameOffset 
= inlineCallFrame 
? inlineCallFrame
->stackOffset 
: 0; 
 127 void StackVisitor::readInlinedFrame(CallFrame
* callFrame
, CodeOrigin
* codeOrigin
) 
 130     ASSERT(!callFrame
->isVMEntrySentinel()); 
 132     int frameOffset 
= inlinedFrameOffset(codeOrigin
); 
 133     bool isInlined 
= !!frameOffset
; 
 135         InlineCallFrame
* inlineCallFrame 
= codeOrigin
->inlineCallFrame
; 
 137         m_frame
.m_callFrame 
= callFrame
; 
 138         m_frame
.m_inlineCallFrame 
= inlineCallFrame
; 
 139         m_frame
.m_argumentCountIncludingThis 
= inlineCallFrame
->arguments
.size(); 
 140         m_frame
.m_codeBlock 
= inlineCallFrame
->baselineCodeBlock(); 
 141         m_frame
.m_bytecodeOffset 
= codeOrigin
->bytecodeIndex
; 
 143         JSFunction
* callee 
= inlineCallFrame
->calleeForCallFrame(callFrame
); 
 144         m_frame
.m_scope 
= callee
->scope(); 
 145         m_frame
.m_callee 
= callee
; 
 146         ASSERT(m_frame
.scope()); 
 147         ASSERT(m_frame
.callee()); 
 149         // The callerFrame just needs to be non-null to indicate that we 
 150         // haven't reached the last frame yet. Setting it to the root 
 151         // frame (i.e. the callFrame that this inlined frame is called from) 
 152         // would work just fine. 
 153         m_frame
.m_callerFrame 
= callFrame
; 
 157     readNonInlinedFrame(callFrame
, codeOrigin
); 
 159 #endif // ENABLE(DFG_JIT) 
 161 StackVisitor::Frame::CodeType 
StackVisitor::Frame::codeType() const 
 164         return CodeType::Native
; 
 166     switch (codeBlock()->codeType()) { 
 168         return CodeType::Eval
; 
 170         return CodeType::Function
; 
 172         return CodeType::Global
; 
 174     RELEASE_ASSERT_NOT_REACHED(); 
 175     return CodeType::Global
; 
 178 String 
StackVisitor::Frame::functionName() 
 181     JSObject
* callee 
= this->callee(); 
 183     switch (codeType()) { 
 185         traceLine 
= "eval code"; 
 187     case CodeType::Native
: 
 189             traceLine 
= getCalculatedDisplayName(callFrame(), callee
).impl(); 
 191     case CodeType::Function
: 
 192         traceLine 
= getCalculatedDisplayName(callFrame(), callee
).impl(); 
 194     case CodeType::Global
: 
 195         traceLine 
= "global code"; 
 198     return traceLine
.isNull() ? emptyString() : traceLine
; 
 201 String 
StackVisitor::Frame::sourceURL() 
 205     switch (codeType()) { 
 207     case CodeType::Function
: 
 208     case CodeType::Global
: { 
 209         String sourceURL 
= codeBlock()->ownerExecutable()->sourceURL(); 
 210         if (!sourceURL
.isEmpty()) 
 211             traceLine 
= sourceURL
.impl(); 
 214     case CodeType::Native
: 
 215         traceLine 
= "[native code]"; 
 218     return traceLine
.isNull() ? emptyString() : traceLine
; 
 221 String 
StackVisitor::Frame::toString() 
 223     StringBuilder traceBuild
; 
 224     String functionName 
= this->functionName(); 
 225     String sourceURL 
= this->sourceURL(); 
 226     traceBuild
.append(functionName
); 
 227     if (!sourceURL
.isEmpty()) { 
 228         if (!functionName
.isEmpty()) 
 229             traceBuild
.append('@'); 
 230         traceBuild
.append(sourceURL
); 
 234             computeLineAndColumn(line
, column
); 
 235             traceBuild
.append(':'); 
 236             traceBuild
.appendNumber(line
); 
 237             traceBuild
.append(':'); 
 238             traceBuild
.appendNumber(column
); 
 241     return traceBuild
.toString().impl(); 
 244 Arguments
* StackVisitor::Frame::createArguments() 
 247     CallFrame
* physicalFrame 
= m_callFrame
; 
 248     VM
& vm 
= physicalFrame
->vm(); 
 249     Arguments
* arguments
; 
 251     if (isInlinedFrame()) { 
 252         ASSERT(m_inlineCallFrame
); 
 253         arguments 
= Arguments::create(vm
, physicalFrame
, m_inlineCallFrame
); 
 254         arguments
->tearOff(physicalFrame
, m_inlineCallFrame
); 
 258         arguments 
= Arguments::create(vm
, physicalFrame
); 
 259         arguments
->tearOff(physicalFrame
); 
 264 Arguments
* StackVisitor::Frame::existingArguments() 
 266     if (codeBlock()->codeType() != FunctionCode
) 
 268     if (!codeBlock()->usesArguments()) 
 274     if (isInlinedFrame()) 
 275         reg 
= inlineCallFrame()->argumentsRegister
; 
 277 #endif // ENABLE(DFG_JIT) 
 278         reg 
= codeBlock()->argumentsRegister(); 
 280     JSValue result 
= callFrame()->r(unmodifiedArgumentsRegister(reg
).offset()).jsValue(); 
 281     if (!result 
|| !result
.isCell()) // Protect against Undefined in case we throw in op_enter. 
 283     return jsCast
<Arguments
*>(result
); 
 286 void StackVisitor::Frame::computeLineAndColumn(unsigned& line
, unsigned& column
) 
 288     CodeBlock
* codeBlock 
= this->codeBlock(); 
 296     int unusedStartOffset 
= 0; 
 297     int unusedEndOffset 
= 0; 
 298     unsigned divotLine 
= 0; 
 299     unsigned divotColumn 
= 0; 
 300     retrieveExpressionInfo(divot
, unusedStartOffset
, unusedEndOffset
, divotLine
, divotColumn
); 
 302     line 
= divotLine 
+ codeBlock
->ownerExecutable()->lineNo(); 
 303     column 
= divotColumn 
+ (divotLine 
? 1 : codeBlock
->firstLineColumnOffset()); 
 306 void StackVisitor::Frame::retrieveExpressionInfo(int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
) 
 308     CodeBlock
* codeBlock 
= this->codeBlock(); 
 309     codeBlock
->unlinkedCodeBlock()->expressionRangeForBytecodeOffset(bytecodeOffset(), divot
, startOffset
, endOffset
, line
, column
); 
 310     divot 
+= codeBlock
->sourceOffset(); 
 313 void StackVisitor::Frame::setToEnd() 
 317     m_inlineCallFrame 
= 0; 
 323 static const char* jitTypeName(JITCode::JITType jitType
) 
 326     case JITCode::None
: return "None"; 
 327     case JITCode::HostCallThunk
: return "HostCallThunk"; 
 328     case JITCode::InterpreterThunk
: return "InterpreterThunk"; 
 329     case JITCode::BaselineJIT
: return "BaselineJIT"; 
 330     case JITCode::DFGJIT
: return "DFGJIT"; 
 331     case JITCode::FTLJIT
: return "FTLJIT"; 
 336 static void printIndents(int levels
) 
 342 static void printif(int indentLevels
, const char* format
, ...) 
 345     va_start(argList
, format
); 
 348         printIndents(indentLevels
); 
 350 #if COMPILER(CLANG) || COMPILER(GCC) 
 351 #pragma GCC diagnostic push 
 352 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 
 353 #pragma GCC diagnostic ignored "-Wmissing-format-attribute" 
 356     WTF::dataLogFV(format
, argList
); 
 358 #if COMPILER(CLANG) || COMPILER(GCC) 
 359 #pragma GCC diagnostic pop 
 365 void StackVisitor::Frame::print(int indentLevel
) 
 369     if (!this->callFrame()) { 
 370         printif(i
, "frame 0x0\n"); 
 374     CodeBlock
* codeBlock 
= this->codeBlock(); 
 375     printif(i
, "frame %p {\n", this->callFrame()); 
 377     CallFrame
* callFrame 
= m_callFrame
; 
 378     CallFrame
* callerFrame 
= this->callerFrame(); 
 379     void* returnPC 
= callFrame
->hasReturnPC() ? callFrame
->returnPC().value() : nullptr; 
 381     printif(i
, "   name '%s'\n", functionName().utf8().data()); 
 382     printif(i
, "   sourceURL '%s'\n", sourceURL().utf8().data()); 
 383     printif(i
, "   isVMEntrySentinel %d\n", callerFrame
->isVMEntrySentinel()); 
 386     printif(i
, "   isInlinedFrame %d\n", isInlinedFrame()); 
 387     if (isInlinedFrame()) 
 388         printif(i
, "   InlineCallFrame %p\n", m_inlineCallFrame
); 
 391     printif(i
, "   callee %p\n", callee()); 
 392     printif(i
, "   returnPC %p\n", returnPC
); 
 393     printif(i
, "   callerFrame %p\n", callerFrame
); 
 394     unsigned locationRawBits 
= callFrame
->locationAsRawBits(); 
 395     printif(i
, "   rawLocationBits %u 0x%x\n", locationRawBits
, locationRawBits
); 
 396     printif(i
, "   codeBlock %p\n", codeBlock
); 
 398         JITCode::JITType jitType 
= codeBlock
->jitType(); 
 399         if (callFrame
->hasLocationAsBytecodeOffset()) { 
 400             unsigned bytecodeOffset 
= callFrame
->locationAsBytecodeOffset(); 
 401             printif(i
, "      bytecodeOffset %u %p / %zu\n", bytecodeOffset
, reinterpret_cast<void*>(bytecodeOffset
), codeBlock
->instructions().size()); 
 404             unsigned codeOriginIndex 
= callFrame
->locationAsCodeOriginIndex(); 
 405             printif(i
, "      codeOriginIdex %u %p / %zu\n", codeOriginIndex
, reinterpret_cast<void*>(codeOriginIndex
), codeBlock
->codeOrigins().size()); 
 410         computeLineAndColumn(line
, column
); 
 411         printif(i
, "      line %d\n", line
); 
 412         printif(i
, "      column %d\n", column
); 
 413         printif(i
, "      jitType %d <%s> isOptimizingJIT %d\n", jitType
, jitTypeName(jitType
), JITCode::isOptimizingJIT(jitType
)); 
 415         printif(i
, "      hasCodeOrigins %d\n", codeBlock
->hasCodeOrigins()); 
 416         if (codeBlock
->hasCodeOrigins()) { 
 417             JITCode
* jitCode 
= codeBlock
->jitCode().get(); 
 418             printif(i
, "         jitCode %p start %p end %p\n", jitCode
, jitCode
->start(), jitCode
->end()); 
 430 using JSC::StackVisitor
; 
 433 JS_EXPORT_PRIVATE 
void debugPrintCallFrame(JSC::CallFrame
*); 
 434 JS_EXPORT_PRIVATE 
void debugPrintStack(JSC::CallFrame
* topCallFrame
); 
 436 class DebugPrintFrameFunctor 
{ 
 443     DebugPrintFrameFunctor(Action action
) 
 448     StackVisitor::Status 
operator()(StackVisitor
& visitor
) 
 451         return m_action 
== PrintAll 
? StackVisitor::Continue 
: StackVisitor::Done
; 
 458 void debugPrintCallFrame(JSC::CallFrame
* callFrame
) 
 462     DebugPrintFrameFunctor 
functor(DebugPrintFrameFunctor::PrintOne
); 
 463     callFrame
->iterate(functor
); 
 466 void debugPrintStack(JSC::CallFrame
* topCallFrame
) 
 470     DebugPrintFrameFunctor 
functor(DebugPrintFrameFunctor::PrintAll
); 
 471     topCallFrame
->iterate(functor
);