]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - interpreter/StackVisitor.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / interpreter / StackVisitor.cpp
index 19f95b92b1ebfa7e7927a94a33fdd902100c3f39..6496fa4d4570e7f13d7f3a3d0528c80d35834172 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,8 +26,8 @@
 #include "config.h"
 #include "StackVisitor.h"
 
-#include "Arguments.h"
 #include "CallFrameInlines.h"
+#include "ClonedArguments.h"
 #include "Executable.h"
 #include "Interpreter.h"
 #include "JSCInlines.h"
@@ -38,7 +38,20 @@ namespace JSC {
 StackVisitor::StackVisitor(CallFrame* startFrame)
 {
     m_frame.m_index = 0;
-    readFrame(startFrame);
+    CallFrame* topFrame;
+    if (startFrame) {
+        m_frame.m_VMEntryFrame = startFrame->vm().topVMEntryFrame;
+        topFrame = startFrame->vm().topCallFrame;
+    } else {
+        m_frame.m_VMEntryFrame = 0;
+        topFrame = 0;
+    }
+    m_frame.m_callerIsVMEntryFrame = false;
+    readFrame(topFrame);
+
+    // Find the frame the caller wants to start unwinding from.
+    while (m_frame.callFrame() && m_frame.callFrame() != startFrame)
+        gotoNextFrame();
 }
 
 void StackVisitor::gotoNextFrame()
@@ -48,15 +61,15 @@ void StackVisitor::gotoNextFrame()
         InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
         CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
         readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
-
-    } else
+        return;
+    }
 #endif // ENABLE(DFG_JIT)
-        readFrame(m_frame.callerFrame());
+    m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
+    readFrame(m_frame.callerFrame());
 }
 
 void StackVisitor::readFrame(CallFrame* callFrame)
 {
-    ASSERT(!callFrame->isVMEntrySentinel());
     if (!callFrame) {
         m_frame.setToEnd();
         return;
@@ -104,9 +117,10 @@ void StackVisitor::readNonInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOri
 {
     m_frame.m_callFrame = callFrame;
     m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
-    m_frame.m_callerFrame = callFrame->callerFrameSkippingVMEntrySentinel();
+    m_frame.m_CallerVMEntryFrame = m_frame.m_VMEntryFrame;
+    m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_CallerVMEntryFrame);
+    m_frame.m_callerIsVMEntryFrame = m_frame.m_CallerVMEntryFrame != m_frame.m_VMEntryFrame;
     m_frame.m_callee = callFrame->callee();
-    m_frame.m_scope = callFrame->scope();
     m_frame.m_codeBlock = callFrame->codeBlock();
     m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
         : codeOrigin ? codeOrigin->bytecodeIndex
@@ -127,7 +141,6 @@ static int inlinedFrameOffset(CodeOrigin* codeOrigin)
 void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
 {
     ASSERT(codeOrigin);
-    ASSERT(!callFrame->isVMEntrySentinel());
 
     int frameOffset = inlinedFrameOffset(codeOrigin);
     bool isInlined = !!frameOffset;
@@ -136,14 +149,15 @@ void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin
 
         m_frame.m_callFrame = callFrame;
         m_frame.m_inlineCallFrame = inlineCallFrame;
-        m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
+        if (inlineCallFrame->argumentCountRegister.isValid())
+            m_frame.m_argumentCountIncludingThis = callFrame->r(inlineCallFrame->argumentCountRegister.offset()).unboxedInt32();
+        else
+            m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
         m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock();
         m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex;
 
         JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
-        m_frame.m_scope = callee->scope();
         m_frame.m_callee = callee;
-        ASSERT(m_frame.scope());
         ASSERT(m_frame.callee());
 
         // The callerFrame just needs to be non-null to indicate that we
@@ -182,7 +196,7 @@ String StackVisitor::Frame::functionName()
 
     switch (codeType()) {
     case CodeType::Eval:
-        traceLine = "eval code";
+        traceLine = ASCIILiteral("eval code");
         break;
     case CodeType::Native:
         if (callee)
@@ -192,7 +206,7 @@ String StackVisitor::Frame::functionName()
         traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
         break;
     case CodeType::Global:
-        traceLine = "global code";
+        traceLine = ASCIILiteral("global code");
         break;
     }
     return traceLine.isNull() ? emptyString() : traceLine;
@@ -212,7 +226,7 @@ String StackVisitor::Frame::sourceURL()
         break;
     }
     case CodeType::Native:
-        traceLine = "[native code]";
+        traceLine = ASCIILiteral("[native code]");
         break;
     }
     return traceLine.isNull() ? emptyString() : traceLine;
@@ -241,48 +255,26 @@ String StackVisitor::Frame::toString()
     return traceBuild.toString().impl();
 }
 
-Arguments* StackVisitor::Frame::createArguments()
+ClonedArguments* StackVisitor::Frame::createArguments()
 {
     ASSERT(m_callFrame);
     CallFrame* physicalFrame = m_callFrame;
-    VM& vm = physicalFrame->vm();
-    Arguments* arguments;
+    ClonedArguments* arguments;
+    ArgumentsMode mode;
+    if (Options::enableFunctionDotArguments())
+        mode = ArgumentsMode::Cloned;
+    else
+        mode = ArgumentsMode::FakeValues;
 #if ENABLE(DFG_JIT)
     if (isInlinedFrame()) {
         ASSERT(m_inlineCallFrame);
-        arguments = Arguments::create(vm, physicalFrame, m_inlineCallFrame);
-        arguments->tearOff(physicalFrame, m_inlineCallFrame);
+        arguments = ClonedArguments::createWithInlineFrame(physicalFrame, physicalFrame, m_inlineCallFrame, mode);
     } else 
 #endif
-    {
-        arguments = Arguments::create(vm, physicalFrame);
-        arguments->tearOff(physicalFrame);
-    }
+        arguments = ClonedArguments::createWithMachineFrame(physicalFrame, physicalFrame, mode);
     return arguments;
 }
 
-Arguments* StackVisitor::Frame::existingArguments()
-{
-    if (codeBlock()->codeType() != FunctionCode)
-        return 0;
-    if (!codeBlock()->usesArguments())
-        return 0;
-    
-    VirtualRegister reg;
-        
-#if ENABLE(DFG_JIT)
-    if (isInlinedFrame())
-        reg = inlineCallFrame()->argumentsRegister;
-    else
-#endif // ENABLE(DFG_JIT)
-        reg = codeBlock()->argumentsRegister();
-    
-    JSValue result = callFrame()->r(unmodifiedArgumentsRegister(reg).offset()).jsValue();
-    if (!result || !result.isCell()) // Protect against Undefined in case we throw in op_enter.
-        return 0;
-    return jsCast<Arguments*>(result);
-}
-
 void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
 {
     CodeBlock* codeBlock = this->codeBlock();
@@ -299,8 +291,11 @@ void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
     unsigned divotColumn = 0;
     retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
 
-    line = divotLine + codeBlock->ownerExecutable()->lineNo();
+    line = divotLine + codeBlock->ownerExecutable()->firstLine();
     column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
+
+    if (codeBlock->ownerExecutable()->hasOverrideLineNumber())
+        line = codeBlock->ownerExecutable()->overrideLineNumber();
 }
 
 void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
@@ -318,34 +313,23 @@ void StackVisitor::Frame::setToEnd()
 #endif
 }
 
-#ifndef NDEBUG
-
-static const char* jitTypeName(JITCode::JITType jitType)
-{
-    switch (jitType) {
-    case JITCode::None: return "None";
-    case JITCode::HostCallThunk: return "HostCallThunk";
-    case JITCode::InterpreterThunk: return "InterpreterThunk";
-    case JITCode::BaselineJIT: return "BaselineJIT";
-    case JITCode::DFGJIT: return "DFGJIT";
-    case JITCode::FTLJIT: return "FTLJIT";
-    }
-    return "<unknown>";
-}
-
 static void printIndents(int levels)
 {
     while (levels--)
         dataLogFString("   ");
 }
 
-static void printif(int indentLevels, const char* format, ...)
+template<typename... Types>
+void log(unsigned indent, const Types&... values)
 {
-    va_list argList;
-    va_start(argList, format);
+    printIndents(indent);
+    dataLog(values...);
+}
 
-    if (indentLevels)
-        printIndents(indentLevels);
+template<typename... Types>
+void logF(unsigned indent, const char* format, const Types&... values)
+{
+    printIndents(indent);
 
 #if COMPILER(CLANG) || COMPILER(GCC)
 #pragma GCC diagnostic push
@@ -353,122 +337,82 @@ static void printif(int indentLevels, const char* format, ...)
 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
 #endif
 
-    WTF::dataLogFV(format, argList);
+    dataLogF(format, values...);
 
 #if COMPILER(CLANG) || COMPILER(GCC)
 #pragma GCC diagnostic pop
 #endif
-
-    va_end(argList);
 }
 
-void StackVisitor::Frame::print(int indentLevel)
+void StackVisitor::Frame::print(int indent)
 {
-    int i = indentLevel;
-
     if (!this->callFrame()) {
-        printif(i, "frame 0x0\n");
+        log(indent, "frame 0x0\n");
         return;
     }
 
     CodeBlock* codeBlock = this->codeBlock();
-    printif(i, "frame %p {\n", this->callFrame());
+    logF(indent, "frame %p {\n", this->callFrame());
 
-    CallFrame* callFrame = m_callFrame;
-    CallFrame* callerFrame = this->callerFrame();
-    void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
+    {
+        indent++;
+
+        CallFrame* callFrame = m_callFrame;
+        CallFrame* callerFrame = this->callerFrame();
+        void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
 
-    printif(i, "   name '%s'\n", functionName().utf8().data());
-    printif(i, "   sourceURL '%s'\n", sourceURL().utf8().data());
-    printif(i, "   isVMEntrySentinel %d\n", callerFrame->isVMEntrySentinel());
+        log(indent, "name: ", functionName(), "\n");
+        log(indent, "sourceURL: ", sourceURL(), "\n");
 
+        bool isInlined = false;
 #if ENABLE(DFG_JIT)
-    printif(i, "   isInlinedFrame %d\n", isInlinedFrame());
-    if (isInlinedFrame())
-        printif(i, "   InlineCallFrame %p\n", m_inlineCallFrame);
+        isInlined = isInlinedFrame();
+        log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
+        if (isInlinedFrame())
+            logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame);
 #endif
 
-    printif(i, "   callee %p\n", callee());
-    printif(i, "   returnPC %p\n", returnPC);
-    printif(i, "   callerFrame %p\n", callerFrame);
-    unsigned locationRawBits = callFrame->locationAsRawBits();
-    printif(i, "   rawLocationBits %u 0x%x\n", locationRawBits, locationRawBits);
-    printif(i, "   codeBlock %p\n", codeBlock);
-    if (codeBlock) {
-        JITCode::JITType jitType = codeBlock->jitType();
-        if (callFrame->hasLocationAsBytecodeOffset()) {
-            unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
-            printif(i, "      bytecodeOffset %u %p / %zu\n", bytecodeOffset, reinterpret_cast<void*>(bytecodeOffset), codeBlock->instructions().size());
+        logF(indent, "callee: %p\n", callee());
+        logF(indent, "returnPC: %p\n", returnPC);
+        logF(indent, "callerFrame: %p\n", callerFrame);
+        unsigned locationRawBits = callFrame->locationAsRawBits();
+        logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits);
+        logF(indent, "codeBlock: %p ", codeBlock);
+        if (codeBlock)
+            dataLog(*codeBlock);
+        dataLog("\n");
+        if (codeBlock && !isInlined) {
+            indent++;
+
+            if (callFrame->hasLocationAsBytecodeOffset()) {
+                unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
+                log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
 #if ENABLE(DFG_JIT)
-        } else {
-            unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
-            printif(i, "      codeOriginIdex %u %p / %zu\n", codeOriginIndex, reinterpret_cast<void*>(codeOriginIndex), codeBlock->codeOrigins().size());
+            } else {
+                log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
+                if (codeBlock->hasCodeOrigins()) {
+                    unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
+                    log(indent, "codeOriginIndex: ", codeOriginIndex, " of ", codeBlock->codeOrigins().size(), "\n");
+
+                    JITCode::JITType jitType = codeBlock->jitType();
+                    if (jitType != JITCode::FTLJIT) {
+                        JITCode* jitCode = codeBlock->jitCode().get();
+                        logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
+                    }
+                }
 #endif
+            }
+            unsigned line = 0;
+            unsigned column = 0;
+            computeLineAndColumn(line, column);
+            log(indent, "line: ", line, "\n");
+            log(indent, "column: ", column, "\n");
+
+            indent--;
         }
-        unsigned line = 0;
-        unsigned column = 0;
-        computeLineAndColumn(line, column);
-        printif(i, "      line %d\n", line);
-        printif(i, "      column %d\n", column);
-        printif(i, "      jitType %d <%s> isOptimizingJIT %d\n", jitType, jitTypeName(jitType), JITCode::isOptimizingJIT(jitType));
-#if ENABLE(DFG_JIT)
-        printif(i, "      hasCodeOrigins %d\n", codeBlock->hasCodeOrigins());
-        if (codeBlock->hasCodeOrigins()) {
-            JITCode* jitCode = codeBlock->jitCode().get();
-            printif(i, "         jitCode %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
-        }
-#endif
+        indent--;
     }
-    printif(i, "}\n");
+    log(indent, "}\n");
 }
 
-#endif // NDEBUG
-
 } // namespace JSC
-
-#ifndef NDEBUG
-using JSC::StackVisitor;
-
-// For debugging use
-JS_EXPORT_PRIVATE void debugPrintCallFrame(JSC::CallFrame*);
-JS_EXPORT_PRIVATE void debugPrintStack(JSC::CallFrame* topCallFrame);
-
-class DebugPrintFrameFunctor {
-public:
-    enum Action {
-        PrintOne,
-        PrintAll
-    };
-
-    DebugPrintFrameFunctor(Action action)
-        : m_action(action)
-    {
-    }
-
-    StackVisitor::Status operator()(StackVisitor& visitor)
-    {
-        visitor->print(2);
-        return m_action == PrintAll ? StackVisitor::Continue : StackVisitor::Done;
-    }
-
-private:
-    Action m_action;
-};
-
-void debugPrintCallFrame(JSC::CallFrame* callFrame)
-{
-    if (!callFrame)
-        return;
-    DebugPrintFrameFunctor functor(DebugPrintFrameFunctor::PrintOne);
-    callFrame->iterate(functor);
-}
-
-void debugPrintStack(JSC::CallFrame* topCallFrame)
-{
-    if (!topCallFrame)
-        return;
-    DebugPrintFrameFunctor functor(DebugPrintFrameFunctor::PrintAll);
-    topCallFrame->iterate(functor);
-}
-
-#endif // !NDEBUG