aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-16 10:50:08 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-16 16:03:54 +0200
commitc1c526aafb2fc70ac6155eb775b3784f1e2e6504 (patch)
tree824bf1c301d24d51d3197f01400c55ec8b4e17ea /src
parentddd9c93b084c5168d7b12396450125e7a0929c28 (diff)
Speed up stack trace generation for the JIT
It turns out that in QML it is not unusual that during early binding evaluations due to the undefined order, the evaluation tries to look up properties in objects that aren't initialized yet and thus exceptions are thrown. Eeach thrown exception saves a stack trace, which is expensive to generate when using the JIT, as it does full stack unwinding. This patch implements a more light-weight approach by storing the instruction pointer in the context before leaving JIT generated code. Change-Id: I95e1cfd01179247dfc2c1df949828f474a23161b Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86.h5
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86_64.h5
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h20
-rw-r--r--src/qml/jsruntime/jsruntime.pri2
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp19
-rw-r--r--src/qml/jsruntime/qv4stacktrace.cpp182
-rw-r--r--src/qml/jsruntime/qv4stacktrace_p.h75
8 files changed, 38 insertions, 272 deletions
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
index 7a01e41e11..9a33fe870e 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
@@ -197,6 +197,11 @@ public:
return Call(m_assembler.call(), Call::Linkable);
}
+ void callToRetrieveIP()
+ {
+ m_assembler.call();
+ }
+
// Address is a memory location containing the address to jump to
void jump(AbsoluteAddress address)
{
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
index db0e880cb9..9e74f1c29f 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
@@ -136,6 +136,11 @@ public:
return result;
}
+ void callToRetrieveIP()
+ {
+ m_assembler.call();
+ }
+
// Address is a memory location containing the address to jump to
void jump(AbsoluteAddress address)
{
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 4d1114e756..02ddd158a9 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -430,7 +430,25 @@ public:
V4IR::BasicBlock *block;
};
+ void saveInstructionPointer(RegisterID freeScratchRegister) {
+ Address ipAddr(ContextRegister, qOffsetOf(QV4::ExecutionContext, jitInstructionPointer));
+ RegisterID sourceRegister = freeScratchRegister;
+
+#if CPU(X86_64) || CPU(X86)
+ callToRetrieveIP();
+ peek(sourceRegister);
+ pop();
+#elif CPU(ARM)
+ move(JSC::ARMRegisters::pc, sourceRegister);
+#else
+#error "Port me!"
+#endif
+
+ storePtr(sourceRegister, ipAddr);
+ }
+
void callAbsolute(const char* functionName, FunctionPtr function) {
+ saveInstructionPointer(ScratchRegister);
CallToLink ctl;
ctl.call = call();
ctl.externalFunction = function;
@@ -439,11 +457,13 @@ public:
}
void callAbsolute(const char* /*functionName*/, Address addr) {
+ saveInstructionPointer(ScratchRegister);
call(addr);
}
void callAbsolute(const char* /*functionName*/, const RelativeCall &relativeCall)
{
+ saveInstructionPointer(ScratchRegister);
call(relativeCall.addr);
}
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 14701feeb5..e2880c0972 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -45,7 +45,6 @@ SOURCES += \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4qmlextensions.cpp \
- $$PWD/qv4stacktrace.cpp \
$$PWD/qv4vme_moth.cpp
HEADERS += \
@@ -96,7 +95,6 @@ HEADERS += \
$$PWD/qv4include_p.h \
$$PWD/qv4qobjectwrapper_p.h \
$$PWD/qv4qmlextensions_p.h \
- $$PWD/qv4stacktrace_p.h \
$$PWD/qv4vme_moth_p.h
# Use SSE2 floating point math on 32 bit instead of the default
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 2535161713..d44c7d25f9 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -97,6 +97,7 @@ struct Q_QML_EXPORT ExecutionContext
EvalCode *currentEvalCode;
const uchar **interpreterInstructionPointer;
+ char *jitInstructionPointer;
void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
{
@@ -110,6 +111,7 @@ struct Q_QML_EXPORT ExecutionContext
compilationUnit = 0;
currentEvalCode = 0;
interpreterInstructionPointer = 0;
+ jitInstructionPointer = 0;
}
CallContext *newCallContext(void *stackSpace, SafeValue *locals, FunctionObject *f, CallData *callData);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 2ddc07d63c..23faa43ac7 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -66,7 +66,6 @@
#include "qv4sequenceobject_p.h"
#include "qv4qobjectwrapper_p.h"
#include "qv4qmlextensions_p.h"
-#include "qv4stacktrace_p.h"
#ifdef V4_ENABLE_JIT
#include "qv4isel_masm_p.h"
@@ -568,7 +567,6 @@ Returned<Object> *ExecutionEngine::qmlContextObject() const
namespace {
struct LineNumberResolver {
const ExecutionEngine* engine;
- QScopedPointer<QV4::NativeStackTrace> nativeTrace;
LineNumberResolver(const ExecutionEngine *engine)
: engine(engine)
@@ -577,17 +575,12 @@ namespace {
void resolve(StackFrame *frame, ExecutionContext *context, Function *function)
{
- if (context->interpreterInstructionPointer) {
- qptrdiff offset = *context->interpreterInstructionPointer - 1 - function->codeData;
- frame->line = function->lineNumberForProgramCounter(offset);
- } else {
- if (!nativeTrace)
- nativeTrace.reset(new QV4::NativeStackTrace(engine->current));
-
- NativeFrame nativeFrame = nativeTrace->nextFrame();
- if (nativeFrame.function == function)
- frame->line = nativeFrame.line;
- }
+ qptrdiff offset;
+ if (context->interpreterInstructionPointer)
+ offset = *context->interpreterInstructionPointer - 1 - function->codeData;
+ else
+ offset = context->jitInstructionPointer - (char*)function->codePtr;
+ frame->line = function->lineNumberForProgramCounter(offset);
}
};
}
diff --git a/src/qml/jsruntime/qv4stacktrace.cpp b/src/qml/jsruntime/qv4stacktrace.cpp
deleted file mode 100644
index 905111a23e..0000000000
--- a/src/qml/jsruntime/qv4stacktrace.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#if defined(_WIN32) && !(defined(WINCE) || defined(_WIN32_WCE))
-#include <windows.h>
-#include <DbgHelp.h>
-#endif
-
-#include "qv4stacktrace_p.h"
-#include "qv4function_p.h"
-#include "qv4engine_p.h"
-#include "qv4unwindhelper_p.h"
-
-#if defined(V4_CXX_ABI_EXCEPTION) || (defined(Q_OS_DARWIN) && !defined(Q_PROCESSOR_ARM_32))
-#define USE_UNWIND_BACKTRACE
-#endif
-
-#if defined(USE_UNWIND_BACKTRACE)
-#include <unwind.h>
-
-struct BacktraceHelper
-{
- void **array;
- int maximumSize;
- int frameCount;
-};
-
-static _Unwind_Reason_Code bt_helper(struct _Unwind_Context *ctx, void *data)
-{
- BacktraceHelper *helper = reinterpret_cast<BacktraceHelper*>(data);
-
- if (helper->frameCount != -1) {
- helper->array[helper->frameCount] = (void*)_Unwind_GetIP(ctx);
-
- if (helper->frameCount > 0 && helper->array[helper->frameCount] == helper->array[helper->frameCount - 1])
- return _URC_END_OF_STACK;
- }
- ++helper->frameCount;
- if (helper->frameCount == helper->maximumSize)
- return _URC_END_OF_STACK;
- return _URC_NO_REASON;
-}
-
-static int get_backtrace_from_libunwind(void **array, int size)
-{
- BacktraceHelper helper;
- helper.array = array;
- helper.maximumSize = size;
- helper.frameCount = -1; // To skip this function
- _Unwind_Backtrace(&bt_helper, &helper);
- return helper.frameCount;
-}
-#endif
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-NativeStackTrace::NativeStackTrace(ExecutionContext *context)
-{
- engine = context->engine;
- currentNativeFrame = 0;
-
-#if defined(USE_UNWIND_BACKTRACE)
- UnwindHelper::prepareForUnwind(context);
-
- nativeFrameCount = get_backtrace_from_libunwind(&trace[0], sizeof(trace) / sizeof(trace[0]));
-#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
-
- int machineType = 0;
-
- CONTEXT winContext;
- memset(&winContext, 0, sizeof(winContext));
- winContext.ContextFlags = CONTEXT_FULL;
- RtlCaptureContext(&winContext);
-
- STACKFRAME64 sf64;
- memset(&sf64, 0, sizeof(sf64));
-
-#if defined(Q_PROCESSOR_X86_32)
- machineType = IMAGE_FILE_MACHINE_I386;
-
- sf64.AddrFrame.Offset = winContext.Ebp;
- sf64.AddrFrame.Mode = AddrModeFlat;
- sf64.AddrPC.Offset = winContext.Eip;
- sf64.AddrPC.Mode = AddrModeFlat;
- sf64.AddrStack.Offset = winContext.Esp;
- sf64.AddrStack.Mode = AddrModeFlat;
-
-#elif defined(Q_PROCESSOR_X86_64)
- machineType = IMAGE_FILE_MACHINE_AMD64;
-
- sf64.AddrFrame.Offset = winContext.Rbp;
- sf64.AddrFrame.Mode = AddrModeFlat;
- sf64.AddrPC.Offset = winContext.Rip;
- sf64.AddrPC.Mode = AddrModeFlat;
- sf64.AddrStack.Offset = winContext.Rsp;
- sf64.AddrStack.Mode = AddrModeFlat;
-
-#else
-#error "Platform unsupported!"
-#endif
-
- nativeFrameCount = 0;
-
- while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
-
- if (sf64.AddrReturn.Offset == 0)
- break;
-
- trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
- nativeFrameCount++;
- if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
- break;
- }
-
-#else
- nativeFrameCount = 0;
-#endif
- }
-
-NativeFrame NativeStackTrace::nextFrame() {
- NativeFrame frame;
- frame.function = 0;
- frame.line = -1;
-
- for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
- quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
- // The pointers from the back trace point to the return address, but we are interested in
- // the caller site.
- pc = pc - 1;
-
- Function *f = engine->functionForProgramCounter(pc);
- if (!f)
- continue;
-
- frame.function = f;
- frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->codePtr));
- }
-
- return frame;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4stacktrace_p.h b/src/qml/jsruntime/qv4stacktrace_p.h
deleted file mode 100644
index 79cb4d1813..0000000000
--- a/src/qml/jsruntime/qv4stacktrace_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QV4STACKTRACE_P_H
-#define QV4STACKTRACE_P_H
-
-#include <qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-struct Function;
-struct ExecutionEngine;
-struct ExecutionContext;
-
-struct NativeFrame {
- Function *function;
- int line;
-};
-
-struct NativeStackTrace
-{
- void *trace[100];
- int nativeFrameCount;
- int currentNativeFrame;
- ExecutionEngine *engine;
-
- NativeStackTrace(ExecutionContext *context);
-
- NativeFrame nextFrame();
-};
-
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4STACKTRACE_P_H