Permalink
Browse files

support for backtraces (part 1).

Mostly plumbing in WebKit and Qt bridge.

http://code.google.com/p/phantomjs/issues/detail?id=166
  • Loading branch information...
1 parent c6091b4 commit afe570484fe90c4a8dab3080edf2ebfa00ac14f5 @jonleighton jonleighton committed with ariya Mar 17, 2012
@@ -154,9 +154,6 @@ ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode
return ScriptValue(exec->globalData(), comp.value());
}
- if (comp.complType() == Throw || comp.complType() == Interrupted)
- reportException(exec, comp.value());
-
m_sourceURL = savedSourceURL;
return ScriptValue();
}
@@ -49,6 +49,13 @@ class ScriptSourceCode {
{
}
+ ScriptSourceCode(const String& source, const String& url, const TextPosition1& startPosition = TextPosition1::minimumPosition())
+ : m_provider(StringSourceProvider::create(source, url, startPosition))
+ , m_code(m_provider, startPosition.m_line.oneBasedInt())
+ , m_url(KURL(ParsedURLString, url))
+ {
+ }
+
ScriptSourceCode(CachedScript* cs)
: m_provider(CachedScriptSourceProvider::create(cs))
, m_code(m_provider)
@@ -1529,14 +1529,14 @@ void QWebFrame::print(QPrinter *printer) const
\sa addToJavaScriptWindowObject(), javaScriptWindowObjectCleared()
*/
-QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource)
+QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource, const QString& location)
{
ScriptController *proxy = d->frame->script();
QVariant rc;
if (proxy) {
#if USE(JSC)
int distance = 0;
- JSC::JSValue v = d->frame->script()->executeScript(ScriptSourceCode(scriptSource)).jsValue();
+ JSC::JSValue v = d->frame->script()->executeScript(ScriptSourceCode(scriptSource, WTF::String(location))).jsValue();
rc = JSC::Bindings::convertValueToQVariant(proxy->globalObject(mainThreadNormalWorld())->globalExec(), v, QMetaType::Void, &distance);
#elif USE(V8)
@@ -200,7 +200,7 @@ class QWEBKIT_EXPORT QWebFrame : public QObject {
QWebSecurityOrigin securityOrigin() const;
public Q_SLOTS:
- QVariant evaluateJavaScript(const QString& scriptSource);
+ QVariant evaluateJavaScript(const QString& scriptSource, const QString& file = QString());
#ifndef QT_NO_PRINTER
void print(QPrinter *printer) const;
#endif
@@ -116,6 +116,9 @@
#include "WorkerThread.h"
#include "runtime/InitializeThreading.h"
#include "wtf/Threading.h"
+#include "DebuggerCallFrame.h"
+#include "JavaScriptCallFrame.h"
+#include "SourceProvider.h"
#include <QApplication>
#include <QBasicTimer>
@@ -290,6 +293,105 @@ static inline Qt::DropAction dragOpToDropAction(unsigned actions)
return result;
}
+QWebPagePrivateDebugger::QWebPagePrivateDebugger(QWebPage* page)
+ : m_webPage(page)
+{
+}
+
+QWebPagePrivateDebugger::~QWebPagePrivateDebugger()
+{
+}
+
+void QWebPagePrivateDebugger::detach(JSC::JSGlobalObject*)
+{
+}
+
+void QWebPagePrivateDebugger::sourceParsed(JSC::ExecState*, JSC::SourceProvider*, int errorLineNumber, const JSC::UString& errorMessage)
+{
+}
+
+void QWebPagePrivateDebugger::exception(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber, bool hasHandler)
+{
+ if (!hasHandler) {
+ reportError(frame.exception());
+ }
+}
+
+void QWebPagePrivateDebugger::reportError(const JSC::JSValue& exception)
+{
+ WTF::RefPtr<WebCore::JavaScriptCallFrame> frame = m_callFrame;
+
+ JSC::ExecState* exec = frame->dynamicGlobalObject()->globalExec();
+ JSC::UString message = exception.toString(exec);
+
+ QString qmessage = QString::fromUtf8(message.utf8().data());
+ QList<QWebPage::JavaScriptFrame> qbacktrace;
+
+ JSC::SourceProvider* provider;
+
+ QString file;
+ int line;
+ QString function;
+
+ while (frame) {
+ provider = reinterpret_cast<JSC::SourceProvider*>(frame->sourceID());
+
+ line = frame->line();
+ file = QString::fromUtf8(provider->url().utf8().data());
+ function = QString::fromUtf8(frame->functionName().utf8().data());
+
+ qbacktrace << QWebPage::JavaScriptFrame(file, line + 1, function);
+ frame = frame->caller();
+ }
+
+ m_webPage->javaScriptError(QWebPage::JavaScriptError(qmessage, qbacktrace));
+}
+
+void QWebPagePrivateDebugger::atStatement(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber)
+{
+ stepOver(frame, sourceID, lineNumber);
+}
+
+void QWebPagePrivateDebugger::callEvent(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber)
+{
+ stepIn(frame, sourceID, lineNumber);
+}
+
+void QWebPagePrivateDebugger::returnEvent(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber)
+{
+ stepOut();
+}
+
+void QWebPagePrivateDebugger::willExecuteProgram(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber)
+{
+ stepIn(frame, sourceID, lineNumber);
+}
+
+void QWebPagePrivateDebugger::didExecuteProgram(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber)
+{
+ stepOut();
+}
+
+void QWebPagePrivateDebugger::didReachBreakpoint(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber)
+{
+}
+
+void QWebPagePrivateDebugger::stepIn(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber)
+{
+ m_callFrame = WebCore::JavaScriptCallFrame::create(frame, m_callFrame, sourceID, textPosition(lineNumber));
+}
+
+void QWebPagePrivateDebugger::stepOver(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber)
+{
+ m_callFrame->update(frame, sourceID, textPosition(lineNumber));
+}
+
+void QWebPagePrivateDebugger::stepOut()
+{
+ m_callFrame = m_callFrame->caller();
+}
+
+
QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
: q(qq)
, page(0)
@@ -370,6 +472,9 @@ QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
#if ENABLE(NOTIFICATIONS)
NotificationPresenterClientQt::notificationPresenter()->addClient();
#endif
+
+ debugger = new QWebPagePrivateDebugger(q);
+ page->setDebugger(debugger);
}
QWebPagePrivate::~QWebPagePrivate()
@@ -387,6 +492,7 @@ QWebPagePrivate::~QWebPagePrivate()
#endif
delete settings;
delete page;
+ delete debugger;
if (inspector)
inspector->setPage(0);
@@ -2100,6 +2206,12 @@ void QWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber,
}
}
+/* Subclasses should reimplement this to add error handling. */
+void QWebPage::javaScriptError(const QWebPage::JavaScriptError& error)
+{
+ Q_UNUSED(error)
+}
+
/*!
This function is called whenever a JavaScript program running inside \a frame calls the alert() function with
the message \a msg.
@@ -244,6 +244,40 @@ class QWEBKIT_EXPORT QWebPage : public QObject {
friend class QWebPage;
};
+ class QWEBKIT_EXPORT JavaScriptFrame {
+ public:
+ JavaScriptFrame(const QString& file, int line, const QString& function)
+ : m_file(file)
+ , m_line(line)
+ , m_function(function)
+ {
+ }
+
+ QString file() const { return m_file; };
+ int line() const { return m_line; };
+ QString function() const { return m_function; };
+
+ private:
+ QString m_file;
+ int m_line;
+ QString m_function;
+ };
+
+ class QWEBKIT_EXPORT JavaScriptError {
+ public:
+ JavaScriptError(const QString& message, const QList<JavaScriptFrame>& backtrace)
+ : m_message(message)
+ , m_backtrace(backtrace)
+ {
+ }
+
+ QString message() const { return m_message; };
+ QList<JavaScriptFrame> backtrace() const { return m_backtrace; };
+
+ private:
+ QString m_message;
+ QList<JavaScriptFrame> m_backtrace;
+ };
explicit QWebPage(QObject *parent = 0);
~QWebPage();
@@ -414,6 +448,7 @@ public Q_SLOTS:
virtual bool javaScriptConfirm(QWebFrame *originatingFrame, const QString& msg);
virtual bool javaScriptPrompt(QWebFrame *originatingFrame, const QString& msg, const QString& defaultValue, QString* result);
virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID);
+ virtual void javaScriptError(const JavaScriptError& error);
virtual QString userAgentForUrl(const QUrl& url) const;
@@ -428,6 +463,7 @@ public Q_SLOTS:
friend class QWebFrame;
friend class QWebPagePrivate;
+ friend class QWebPagePrivateDebugger;
friend class QWebView;
friend class QWebViewPrivate;
friend class QGraphicsWebView;
@@ -35,8 +35,11 @@
#include "KURL.h"
#include "PlatformString.h"
+#include <debugger/Debugger.h>
+
#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
+#include <wtf/text/TextPosition.h>
#include "ViewportArguments.h"
@@ -54,6 +57,15 @@ namespace WebCore {
class NodeList;
class Page;
class Frame;
+ class JavaScriptCallFrame;
+}
+
+namespace JSC {
+ class JSGlobalObject;
+ class ExecState;
+ class SourceProvider;
+ class DebuggerCallFrame;
+ class UString;
}
QT_BEGIN_NAMESPACE
@@ -74,6 +86,39 @@ class QtViewportAttributesPrivate : public QSharedData {
QWebPage::ViewportAttributes* q;
};
+class QWebPagePrivateDebugger : public JSC::Debugger {
+public:
+ QWebPagePrivateDebugger(QWebPage*);
+ ~QWebPagePrivateDebugger();
+
+ void detach(JSC::JSGlobalObject*);
+
+ void sourceParsed(JSC::ExecState*, JSC::SourceProvider*, int errorLineNumber, const JSC::UString& errorMessage);
+ void exception(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber, bool hasHandler);
+ void atStatement(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber);
+ void callEvent(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber);
+ void returnEvent(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber);
+
+ void willExecuteProgram(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber);
+ void didExecuteProgram(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber);
+ void didReachBreakpoint(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber);
+
+private:
+ void stepIn(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber);
+ void stepOver(const JSC::DebuggerCallFrame& frame, intptr_t sourceID, int lineNumber);
+ void stepOut();
+ void reportError(const JSC::JSValue& exception);
+
+ WTF::TextPosition0 textPosition(int lineNumber)
+ {
+ WTF::ZeroBasedNumber zeroBasedNumber = WTF::OneBasedNumber::fromOneBasedInt(lineNumber).convertToZeroBased();
+ return WTF::TextPosition0(zeroBasedNumber, WTF::ZeroBasedNumber::base());
+ }
+
+ RefPtr<WebCore::JavaScriptCallFrame> m_callFrame;
+ QWebPage* m_webPage;
+};
+
class QWebPagePrivate {
public:
QWebPagePrivate(QWebPage*);
@@ -210,6 +255,7 @@ class QWebPagePrivate {
QWebInspector* inspector;
bool inspectorIsInternalOnly; // True if created through the Inspect context menu action
Qt::DropAction m_lastDropAction;
+ QWebPagePrivateDebugger* debugger;
static bool drtRun;
};

0 comments on commit afe5704

Please sign in to comment.