]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - debugger/DebuggerCallFrame.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / debugger / DebuggerCallFrame.cpp
index 08fba4a6b4cb8a00991d55749907f5e2f8076155..663fc03cdf93ff10421a8ab4b7b5683d635016cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
  * 2.  Redistributions in binary form must reproduce the above copyright
  *     notice, this list of conditions and the following disclaimer in the
  *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
  *     its contributors may be used to endorse or promote products derived
  *     from this software without specific prior written permission.
  *
 #include "config.h"
 #include "DebuggerCallFrame.h"
 
-#include "JSFunction.h"
 #include "CodeBlock.h"
+#include "DebuggerEvalEnabler.h"
+#include "DebuggerScope.h"
 #include "Interpreter.h"
+#include "JSFunction.h"
+#include "JSLexicalEnvironment.h"
+#include "JSCInlines.h"
 #include "Parser.h"
+#include "StackVisitor.h"
+#include "StrongInlines.h"
 
 namespace JSC {
 
-const UString* DebuggerCallFrame::functionName() const
+class LineAndColumnFunctor {
+public:
+    StackVisitor::Status operator()(StackVisitor& visitor)
+    {
+        visitor->computeLineAndColumn(m_line, m_column);
+        return StackVisitor::Done;
+    }
+
+    unsigned line() const { return m_line; }
+    unsigned column() const { return m_column; }
+
+private:
+    unsigned m_line;
+    unsigned m_column;
+};
+
+class FindCallerMidStackFunctor {
+public:
+    FindCallerMidStackFunctor(CallFrame* callFrame)
+        : m_callFrame(callFrame)
+        , m_callerFrame(nullptr)
+    { }
+
+    StackVisitor::Status operator()(StackVisitor& visitor)
+    {
+        if (visitor->callFrame() == m_callFrame) {
+            m_callerFrame = visitor->callerFrame();
+            return StackVisitor::Done;
+        }
+        return StackVisitor::Continue;
+    }
+
+    CallFrame* getCallerFrame() const { return m_callerFrame; }
+
+private:
+    CallFrame* m_callFrame;
+    CallFrame* m_callerFrame;
+};
+
+DebuggerCallFrame::DebuggerCallFrame(CallFrame* callFrame)
+    : m_callFrame(callFrame)
 {
-    if (!m_callFrame->codeBlock())
-        return 0;
+    m_position = positionForCallFrame(m_callFrame);
+}
 
-    if (!m_callFrame->callee())
+RefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame()
+{
+    ASSERT(isValid());
+    if (!isValid())
         return 0;
 
-    JSObject* function = m_callFrame->callee();
-    if (!function || !function->inherits(&JSFunction::s_info))
+    if (m_caller)
+        return m_caller;
+
+    FindCallerMidStackFunctor functor(m_callFrame);
+    m_callFrame->vm().topCallFrame->iterate(functor);
+
+    CallFrame* callerFrame = functor.getCallerFrame();
+    if (!callerFrame)
+        return nullptr;
+
+    m_caller = DebuggerCallFrame::create(callerFrame);
+    return m_caller;
+}
+
+JSC::JSGlobalObject* DebuggerCallFrame::vmEntryGlobalObject() const
+{
+    ASSERT(isValid());
+    if (!isValid())
         return 0;
-    return &asFunction(function)->name(m_callFrame);
+    return m_callFrame->vmEntryGlobalObject();
 }
-    
-UString DebuggerCallFrame::calculatedFunctionName() const
+
+SourceID DebuggerCallFrame::sourceID() const
 {
-    if (!m_callFrame->codeBlock())
-        return UString();
+    ASSERT(isValid());
+    if (!isValid())
+        return noSourceID;
+    return sourceIDForCallFrame(m_callFrame);
+}
 
-    JSObject* function = m_callFrame->callee();
-    if (!function || !function->inherits(&JSFunction::s_info))
-        return UString();
+String DebuggerCallFrame::functionName() const
+{
+    ASSERT(isValid());
+    if (!isValid())
+        return String();
+    JSFunction* function = jsDynamicCast<JSFunction*>(m_callFrame->callee());
+    if (!function)
+        return String();
 
-    return asFunction(function)->calculatedDisplayName(m_callFrame);
+    return getCalculatedDisplayName(m_callFrame, function);
+}
+
+DebuggerScope* DebuggerCallFrame::scope()
+{
+    ASSERT(isValid());
+    if (!isValid())
+        return 0;
+
+    if (!m_scope) {
+        VM& vm = m_callFrame->vm();
+        JSScope* scope;
+        CodeBlock* codeBlock = m_callFrame->codeBlock();
+        if (codeBlock && codeBlock->scopeRegister().isValid())
+            scope = m_callFrame->scope(codeBlock->scopeRegister().offset());
+        else if (JSCallee* callee = jsDynamicCast<JSCallee*>(m_callFrame->callee()))
+            scope = callee->scope();
+        else
+            scope = m_callFrame->lexicalGlobalObject();
+
+        m_scope.set(vm, DebuggerScope::create(vm, scope));
+    }
+    return m_scope.get();
 }
 
 DebuggerCallFrame::Type DebuggerCallFrame::type() const
 {
-    if (m_callFrame->callee())
+    ASSERT(isValid());
+    if (!isValid())
+        return ProgramType;
+
+    if (jsDynamicCast<JSFunction*>(m_callFrame->callee()))
         return FunctionType;
 
     return ProgramType;
 }
 
-JSObject* DebuggerCallFrame::thisObject() const
+JSValue DebuggerCallFrame::thisValue() const
 {
-    CodeBlock* codeBlock = m_callFrame->codeBlock();
-    if (!codeBlock)
-        return 0;
-
-    JSValue thisValue = m_callFrame->uncheckedR(codeBlock->thisRegister()).jsValue();
-    if (!thisValue.isObject())
-        return 0;
-
-    return asObject(thisValue);
+    ASSERT(isValid());
+    return thisValueForCallFrame(m_callFrame);
 }
 
-JSValue DebuggerCallFrame::evaluate(const UString& script, JSValue& exception) const
+// Evaluate some JavaScript code in the scope of this frame.
+JSValue DebuggerCallFrame::evaluate(const String& script, NakedPtr<Exception>& exception)
 {
-    if (!m_callFrame->codeBlock())
+    ASSERT(isValid());
+    CallFrame* callFrame = m_callFrame;
+    if (!callFrame)
+        return jsNull();
+
+    JSLockHolder lock(callFrame);
+
+    if (!callFrame->codeBlock())
         return JSValue();
     
-    JSGlobalData& globalData = m_callFrame->globalData();
-    EvalExecutable* eval = EvalExecutable::create(m_callFrame, makeSource(script), m_callFrame->codeBlock()->isStrictMode());
-    if (globalData.exception) {
-        exception = globalData.exception;
-        globalData.exception = JSValue();
+    DebuggerEvalEnabler evalEnabler(callFrame);
+    VM& vm = callFrame->vm();
+    auto& codeBlock = *callFrame->codeBlock();
+    ThisTDZMode thisTDZMode = codeBlock.unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
+    EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode);
+    if (vm.exception()) {
+        exception = vm.exception();
+        vm.clearException();
+        return jsUndefined();
     }
 
-    JSValue result = globalData.interpreter->execute(eval, m_callFrame, thisObject(), m_callFrame->scopeChain());
-    if (globalData.exception) {
-        exception = globalData.exception;
-        globalData.exception = JSValue();
+    JSValue thisValue = thisValueForCallFrame(callFrame);
+    JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope());
+    if (vm.exception()) {
+        exception = vm.exception();
+        vm.clearException();
     }
     ASSERT(result);
     return result;
 }
 
+void DebuggerCallFrame::invalidate()
+{
+    RefPtr<DebuggerCallFrame> frame = this;
+    while (frame) {
+        frame->m_callFrame = nullptr;
+        if (frame->m_scope) {
+            frame->m_scope->invalidateChain();
+            frame->m_scope.clear();
+        }
+        frame = frame->m_caller.release();
+    }
+}
+
+TextPosition DebuggerCallFrame::positionForCallFrame(CallFrame* callFrame)
+{
+    if (!callFrame)
+        return TextPosition();
+
+    LineAndColumnFunctor functor;
+    callFrame->iterate(functor);
+    return TextPosition(OrdinalNumber::fromOneBasedInt(functor.line()), OrdinalNumber::fromOneBasedInt(functor.column()));
+}
+
+SourceID DebuggerCallFrame::sourceIDForCallFrame(CallFrame* callFrame)
+{
+    ASSERT(callFrame);
+    CodeBlock* codeBlock = callFrame->codeBlock();
+    if (!codeBlock)
+        return noSourceID;
+    return codeBlock->ownerExecutable()->sourceID();
+}
+
+JSValue DebuggerCallFrame::thisValueForCallFrame(CallFrame* callFrame)
+{
+    if (!callFrame)
+        return jsNull();
+
+    ECMAMode ecmaMode = NotStrictMode;
+    CodeBlock* codeBlock = callFrame->codeBlock();
+    if (codeBlock && codeBlock->isStrictMode())
+        ecmaMode = StrictMode;
+    JSValue thisValue = callFrame->thisValue().toThis(callFrame, ecmaMode);
+    return thisValue;
+}
+
 } // namespace JSC