/*
- * 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
* 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 "Interpreter.h"
+#include "JSActivation.h"
+#include "JSFunction.h"
+#include "JSCInlines.h"
#include "Parser.h"
+#include "StackVisitor.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;
+};
+
+DebuggerCallFrame::DebuggerCallFrame(CallFrame* callFrame)
+ : m_callFrame(callFrame)
{
- if (!m_callFrame->codeBlock())
+ m_position = positionForCallFrame(m_callFrame);
+}
+
+PassRefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame()
+{
+ ASSERT(isValid());
+ if (!isValid())
return 0;
- if (!m_callFrame->callee())
+ if (m_caller)
+ return m_caller;
+
+ CallFrame* callerFrame = m_callFrame->callerFrameSkippingVMEntrySentinel();
+ if (!callerFrame)
return 0;
- JSObject* function = m_callFrame->callee();
- if (!function || !function->inherits(&JSFunction::s_info))
+ m_caller = DebuggerCallFrame::create(callerFrame);
+ return m_caller;
+}
+
+JSC::JSGlobalObject* DebuggerCallFrame::vmEntryGlobalObject() const
+{
+ ASSERT(isValid());
+ if (!isValid())
return 0;
- return &jsCast<JSFunction*>(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);
+}
+String DebuggerCallFrame::functionName() const
+{
+ ASSERT(isValid());
+ if (!isValid())
+ return String();
JSObject* function = m_callFrame->callee();
-
if (!function)
- return UString();
+ return String();
return getCalculatedDisplayName(m_callFrame, function);
}
+JSScope* DebuggerCallFrame::scope() const
+{
+ ASSERT(isValid());
+ if (!isValid())
+ return 0;
+
+ CodeBlock* codeBlock = m_callFrame->codeBlock();
+ if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) {
+ JSActivation* activation = JSActivation::create(*codeBlock->vm(), m_callFrame, codeBlock);
+ m_callFrame->setActivation(activation);
+ m_callFrame->setScope(activation);
+ }
+
+ return m_callFrame->scope();
+}
+
DebuggerCallFrame::Type DebuggerCallFrame::type() const
{
+ ASSERT(isValid());
+ if (!isValid())
+ return ProgramType;
+
if (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, JSValue& 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();
+ VM& vm = callFrame->vm();
+ EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), callFrame->codeBlock()->isStrictMode());
+ 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());
+ if (vm.exception()) {
+ exception = vm.exception();
+ vm.clearException();
}
ASSERT(result);
return result;
}
+void DebuggerCallFrame::invalidate()
+{
+ m_callFrame = nullptr;
+ RefPtr<DebuggerCallFrame> frame = m_caller.release();
+ while (frame) {
+ frame->m_callFrame = nullptr;
+ 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