summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/v4/moth/qv4isel_moth.cpp2
-rw-r--r--src/v4/moth/qv4isel_moth_p.h2
-rw-r--r--src/v4/moth/qv4vme_moth.cpp47
-rw-r--r--src/v4/moth/qv4vme_moth_p.h11
-rw-r--r--src/v4/qmljs_runtime.cpp2
-rw-r--r--src/v4/qmljs_runtime.h3
-rw-r--r--src/v4/qv4codegen.cpp5
-rw-r--r--src/v4/qv4isel_llvm.cpp2
-rw-r--r--src/v4/qv4isel_llvm_p.h2
-rw-r--r--src/v4/qv4isel_masm.cpp65
-rw-r--r--src/v4/qv4isel_masm_p.h9
-rw-r--r--src/v4/qv4isel_p.cpp3
-rw-r--r--src/v4/qv4isel_p.h2
-rw-r--r--tools/v4/main.cpp40
14 files changed, 129 insertions, 66 deletions
diff --git a/src/v4/moth/qv4isel_moth.cpp b/src/v4/moth/qv4isel_moth.cpp
index 125014a1..d8d70401 100644
--- a/src/v4/moth/qv4isel_moth.cpp
+++ b/src/v4/moth/qv4isel_moth.cpp
@@ -829,7 +829,7 @@ void InstructionSelection::callBuiltinThrow(IR::Temp *arg)
addInstruction(call);
}
-void InstructionSelection::callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *)
+void InstructionSelection::callBuiltinCreateExceptionHandler(IR::Temp *result)
{
Instruction::CallBuiltinCreateExceptionHandler call;
call.result = getResultParam(result);
diff --git a/src/v4/moth/qv4isel_moth_p.h b/src/v4/moth/qv4isel_moth_p.h
index af60ca4f..6eaee6dd 100644
--- a/src/v4/moth/qv4isel_moth_p.h
+++ b/src/v4/moth/qv4isel_moth_p.h
@@ -43,7 +43,7 @@ protected:
virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result);
virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result);
virtual void callBuiltinThrow(IR::Temp *arg);
- virtual void callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *contextTemp);
+ virtual void callBuiltinCreateExceptionHandler(IR::Temp *result);
virtual void callBuiltinDeleteExceptionHandler();
virtual void callBuiltinGetException(IR::Temp *result);
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
diff --git a/src/v4/moth/qv4vme_moth.cpp b/src/v4/moth/qv4vme_moth.cpp
index ffade960..aea4fce8 100644
--- a/src/v4/moth/qv4vme_moth.cpp
+++ b/src/v4/moth/qv4vme_moth.cpp
@@ -139,7 +139,8 @@ static inline VM::Value *getValueRef(QQmlJS::VM::ExecutionContext *context,
# define VALUEPTR(param) getValueRef(context, stack, param, stackSize)
#endif
-VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *code
+VM::Value VME::run(QQmlJS::VM::ExecutionContext *context, const uchar *&code,
+ VM::Value *stack, unsigned stackSize
#ifdef MOTH_THREADED_INTERPRETER
, void ***storeJumpTable
#endif
@@ -161,8 +162,6 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
}
#endif
- VM::Value *stack = 0;
- unsigned stackSize = 0;
FunctionState state(context, &code);
#ifdef MOTH_THREADED_INTERPRETER
@@ -260,31 +259,35 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
MOTH_END_INSTR(CallBuiltinThrow)
MOTH_BEGIN_INSTR(CallBuiltinCreateExceptionHandler)
- void *buf = __qmljs_create_exception_handler(context);
- // The result is the only value we need from the instr to
- // continue execution when an exception is caught.
+ __qmljs_create_exception_handler(context);
VM::Value *result = getValueRef(context, stack, instr.result
#if !defined(QT_NO_DEBUG)
, stackSize
#endif
);
- VM::ExecutionContext *oldContext = context;
- int didThrow = setjmp(* static_cast<jmp_buf *>(buf));
- context = oldContext;
- // Two ways to come here: after a create, or after a throw.
- if (didThrow)
- // At this point, the interpreter state can be anything but
- // valid, so first restore the state.
- restoreState(context, result, code);
- else
- // Save the state and any variables we need when catching an
- // exception, so we can restore the state at that point.
- saveState(context, result, code);
- *result = VM::Value::fromInt32(didThrow);
+ try {
+ *result = VM::Value::fromInt32(0);
+ const uchar *tryCode = code;
+ run(context, tryCode, stack, stackSize);
+ code = tryCode;
+ } catch (const VM::Exception &) {
+ try {
+ *result = VM::Value::fromInt32(1);
+ const uchar *catchCode = code;
+ run(context, catchCode, stack, stackSize);
+ code = catchCode;
+ } catch (const VM::Exception &) {
+ *result = VM::Value::fromInt32(1);
+ const uchar *catchCode = code;
+ run(context, catchCode, stack, stackSize);
+ code = catchCode;
+ }
+ }
MOTH_END_INSTR(CallBuiltinCreateExceptionHandler)
MOTH_BEGIN_INSTR(CallBuiltinDeleteExceptionHandler)
__qmljs_delete_exception_handler(context);
+ return VM::Value();
MOTH_END_INSTR(CallBuiltinDeleteExceptionHandler)
MOTH_BEGIN_INSTR(CallBuiltinGetException)
@@ -473,8 +476,8 @@ void **VME::instructionJumpTable()
{
static void **jumpTable = 0;
if (!jumpTable) {
- VME dummy;
- dummy(0, 0, &jumpTable);
+ const uchar *code = 0;
+ VME().run(0, code, 0, 0, &jumpTable);
}
return jumpTable;
}
@@ -483,7 +486,7 @@ void **VME::instructionJumpTable()
VM::Value VME::exec(VM::ExecutionContext *ctxt, const uchar *code)
{
VME vme;
- return vme(ctxt, code);
+ return vme.run(ctxt, code);
}
void VME::restoreState(VM::ExecutionContext *context, VM::Value *&target, const uchar *&code)
diff --git a/src/v4/moth/qv4vme_moth_p.h b/src/v4/moth/qv4vme_moth_p.h
index 2fd877f7..0b7fc9b7 100644
--- a/src/v4/moth/qv4vme_moth_p.h
+++ b/src/v4/moth/qv4vme_moth_p.h
@@ -16,17 +16,18 @@ class VME
public:
static VM::Value exec(VM::ExecutionContext *, const uchar *);
- VM::Value operator()(QQmlJS::VM::ExecutionContext *, const uchar *code
#ifdef MOTH_THREADED_INTERPRETER
- , void ***storeJumpTable = 0
+ static void **instructionJumpTable();
#endif
- );
+private:
+ VM::Value run(QQmlJS::VM::ExecutionContext *, const uchar *&code,
+ VM::Value *stack = 0, unsigned stackSize = 0
#ifdef MOTH_THREADED_INTERPRETER
- static void **instructionJumpTable();
+ , void ***storeJumpTable = 0
#endif
+ );
-private:
static void restoreState(VM::ExecutionContext *context, VM::Value *&target, const uchar *&code);
static void saveState(VM::ExecutionContext *context, VM::Value *target, const uchar *code);
};
diff --git a/src/v4/qmljs_runtime.cpp b/src/v4/qmljs_runtime.cpp
index 76361c0c..43940e68 100644
--- a/src/v4/qmljs_runtime.cpp
+++ b/src/v4/qmljs_runtime.cpp
@@ -964,7 +964,7 @@ void __qmljs_throw(ExecutionContext *context, const Value &value)
context->engine->exception = value;
- longjmp(handler.stackFrame, 1);
+ throw Exception();
}
Q_V4_EXPORT void * __qmljs_create_exception_handler(ExecutionContext *context)
diff --git a/src/v4/qmljs_runtime.h b/src/v4/qmljs_runtime.h
index e649debe..4da9015a 100644
--- a/src/v4/qmljs_runtime.h
+++ b/src/v4/qmljs_runtime.h
@@ -89,6 +89,9 @@ struct ArrayObject;
struct ErrorObject;
struct ExecutionEngine;
+struct Exception {
+};
+
extern "C" {
// context
diff --git a/src/v4/qv4codegen.cpp b/src/v4/qv4codegen.cpp
index 7ad09ca3..ad390dfb 100644
--- a/src/v4/qv4codegen.cpp
+++ b/src/v4/qv4codegen.cpp
@@ -2454,10 +2454,7 @@ bool Codegen::visit(TryStatement *ast)
}
int hasException = _block->newTemp();
- int contextTemp = _block->newTemp();
- IR::ExprList *createExceptionArgs = _function->New<IR::ExprList>();
- createExceptionArgs->init(_block->TEMP(contextTemp));
- move(_block->TEMP(hasException), _block->CALL(_block->NAME(IR::Name::builtin_create_exception_handler, 0, 0), createExceptionArgs));
+ move(_block->TEMP(hasException), _block->CALL(_block->NAME(IR::Name::builtin_create_exception_handler, 0, 0), 0));
// Pass the hidden "inCatch" and "hasException" TEMPs to the
// builtin_delete_exception_handler, in order to have those TEMPs alive for
diff --git a/src/v4/qv4isel_llvm.cpp b/src/v4/qv4isel_llvm.cpp
index 57175320..e6010cfd 100644
--- a/src/v4/qv4isel_llvm.cpp
+++ b/src/v4/qv4isel_llvm.cpp
@@ -427,7 +427,7 @@ void InstructionSelection::callBuiltinThrow(IR::Temp *arg)
Q_UNREACHABLE();
}
-void InstructionSelection::callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *contextTemp)
+void InstructionSelection::callBuiltinCreateExceptionHandler(IR::Temp *result)
{
// TODO
assert(!"TODO!");
diff --git a/src/v4/qv4isel_llvm_p.h b/src/v4/qv4isel_llvm_p.h
index 43e3dfc0..fb28456b 100644
--- a/src/v4/qv4isel_llvm_p.h
+++ b/src/v4/qv4isel_llvm_p.h
@@ -88,7 +88,7 @@ public: // methods from InstructionSelection:
virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result);
virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result);
virtual void callBuiltinThrow(IR::Temp *arg);
- virtual void callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *contextTemp);
+ virtual void callBuiltinCreateExceptionHandler(IR::Temp *result);
virtual void callBuiltinDeleteExceptionHandler();
virtual void callBuiltinGetException(IR::Temp *result);
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
diff --git a/src/v4/qv4isel_masm.cpp b/src/v4/qv4isel_masm.cpp
index 82b0634a..16592760 100644
--- a/src/v4/qv4isel_masm.cpp
+++ b/src/v4/qv4isel_masm.cpp
@@ -123,6 +123,14 @@ void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
_patches[targetBlock].append(targetJump);
}
+void Assembler::addPatch(DataLabelPtr patch, Label target)
+{
+ DataLabelPatch p;
+ p.dataLabel = patch;
+ p.target = target;
+ _dataLabelPatches.append(p);
+}
+
Assembler::Pointer Assembler::loadTempAddress(RegisterID reg, IR::Temp *t)
{
int32_t offset = 0;
@@ -420,6 +428,9 @@ void Assembler::link(VM::Function *vmFunc)
functions[ctl.externalFunction.value()] = ctl.functionName;
}
+ foreach (const DataLabelPatch &p, _dataLabelPatches)
+ linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
+
static bool showCode = !qgetenv("SHOW_CODE").isNull();
if (showCode) {
#if OS(LINUX)
@@ -630,22 +641,64 @@ void InstructionSelection::callBuiltinThrow(IR::Temp *arg)
generateFunctionCall(Assembler::Void, __qmljs_builtin_throw, Assembler::ContextRegister, Assembler::Reference(arg));
}
-void InstructionSelection::callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *contextTemp)
+static void *tryWrapper(ExecutionContext *context, void *localsPtr, void *(*exceptionEntryPointInCallingFunction)(ExecutionContext*, void*, int))
+{
+ void *addressToContinueAt = 0;
+ try {
+ addressToContinueAt = exceptionEntryPointInCallingFunction(context, localsPtr, 0);
+ } catch (const Exception&) {
+ try {
+ addressToContinueAt = exceptionEntryPointInCallingFunction(context, localsPtr, 1);
+ } catch (const Exception&) {
+ addressToContinueAt = exceptionEntryPointInCallingFunction(context, localsPtr, 1);
+ }
+ }
+ return addressToContinueAt;
+}
+
+void InstructionSelection::callBuiltinCreateExceptionHandler(IR::Temp *result)
{
- Address contextAddr = _as->loadTempAddress(Assembler::ScratchRegister, contextTemp);
- _as->storePtr(Assembler::ContextRegister, contextAddr);
- generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_create_exception_handler, Assembler::ContextRegister);
- generateFunctionCall(Assembler::ReturnValueRegister, setjmp, Assembler::ReturnValueRegister);
- _as->loadPtr(contextAddr, Assembler::ContextRegister);
+ generateFunctionCall(Assembler::Void, __qmljs_create_exception_handler, Assembler::ContextRegister);
+
+ // Call tryWrapper, which is going to re-enter the same function again below.
+ // When tryWrapper returns, it returns the with address of where to continue.
+ Assembler::DataLabelPtr movePatch = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ScratchRegister);
+ generateFunctionCall(Assembler::ReturnValueRegister, tryWrapper, Assembler::ContextRegister, Assembler::LocalsRegister, Assembler::ScratchRegister);
+ _as->jump(Assembler::ReturnValueRegister);
+
+ // tryWrapper calls us at this place with arg3 == 0 if we're supposed to execute the try block
+ // and arg == 1 if we caught an exception. The generated IR takes care of returning from this
+ // call when deleteExceptionHandler is called.
+ _as->addPatch(movePatch, _as->label());
+ _as->enterStandardStackFrame(/*locals*/0);
+#ifdef ARGUMENTS_IN_REGISTERS
+ _as->move(Assembler::registerForArgument(0), Assembler::ContextRegister);
+ _as->move(Assembler::registerForArgument(1), Assembler::LocalsRegister);
+#else
+ _as->loadPtr(addressForArgument(0), Assembler::ContextRegister);
+ _as->loadPtr(addressForArgument(1), Assembler::LocalsRegister);
+#endif
+
Address addr = _as->loadTempAddress(Assembler::ScratchRegister, result);
+#ifdef ARGUMENTS_IN_REGISTERS
+ _as->store32(Assembler::registerForArgument(2), addr);
+#else
+ _as->load32(addressForArgument(2), Assembler::ReturnValueRegister);
_as->store32(Assembler::ReturnValueRegister, addr);
+#endif
addr.offset += 4;
_as->store32(Assembler::TrustedImm32(Value::Boolean_Type), addr);
}
void InstructionSelection::callBuiltinDeleteExceptionHandler()
{
+ // This assumes that we're in code that was called by tryWrapper, so we return to try wrapper
+ // with the address that we'd like to continue at, which is right after the ret below.
generateFunctionCall(Assembler::Void, __qmljs_delete_exception_handler, Assembler::ContextRegister);
+ Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister);
+ _as->leaveStandardStackFrame(/*locals*/0);
+ _as->ret();
+ _as->addPatch(continuation, _as->label());
}
void InstructionSelection::callBuiltinGetException(IR::Temp *result)
diff --git a/src/v4/qv4isel_masm_p.h b/src/v4/qv4isel_masm_p.h
index 4a12351b..d850246a 100644
--- a/src/v4/qv4isel_masm_p.h
+++ b/src/v4/qv4isel_masm_p.h
@@ -216,6 +216,7 @@ public:
void registerBlock(IR::BasicBlock*);
void jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target);
void addPatch(IR::BasicBlock* targetBlock, Jump targetJump);
+ void addPatch(DataLabelPtr patch, Label target);
Pointer loadTempAddress(RegisterID reg, IR::Temp *t);
@@ -723,6 +724,12 @@ private:
QHash<IR::BasicBlock *, Label> _addrs;
QHash<IR::BasicBlock *, QVector<Jump> > _patches;
QList<CallToLink> _callsToLink;
+
+ struct DataLabelPatch {
+ DataLabelPtr dataLabel;
+ Label target;
+ };
+ QList<DataLabelPatch> _dataLabelPatches;
};
class Q_V4_EXPORT InstructionSelection:
@@ -754,7 +761,7 @@ protected:
virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result);
virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result);
virtual void callBuiltinThrow(IR::Temp *arg);
- virtual void callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *contextTemp);
+ virtual void callBuiltinCreateExceptionHandler(IR::Temp *result);
virtual void callBuiltinDeleteExceptionHandler();
virtual void callBuiltinGetException(IR::Temp *result);
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
diff --git a/src/v4/qv4isel_p.cpp b/src/v4/qv4isel_p.cpp
index b4360153..03fa0745 100644
--- a/src/v4/qv4isel_p.cpp
+++ b/src/v4/qv4isel_p.cpp
@@ -311,8 +311,7 @@ void InstructionSelection::callBuiltin(IR::Call *call, IR::Temp *result)
} return;
case IR::Name::builtin_create_exception_handler: {
- IR::Temp *arg = call->args->expr->asTemp();
- callBuiltinCreateExceptionHandler(result, arg);
+ callBuiltinCreateExceptionHandler(result);
return;
}
diff --git a/src/v4/qv4isel_p.h b/src/v4/qv4isel_p.h
index 9c15829d..40cf86ed 100644
--- a/src/v4/qv4isel_p.h
+++ b/src/v4/qv4isel_p.h
@@ -103,7 +103,7 @@ public: // to implement by subclasses:
virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result) = 0;
virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result) = 0;
virtual void callBuiltinThrow(IR::Temp *arg) = 0;
- virtual void callBuiltinCreateExceptionHandler(IR::Temp *result, IR::Temp *contextTemp) = 0;
+ virtual void callBuiltinCreateExceptionHandler(IR::Temp *result) = 0;
virtual void callBuiltinDeleteExceptionHandler() = 0;
virtual void callBuiltinGetException(IR::Temp *result) = 0;
virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result) = 0;
diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp
index f6997eb7..d73fa480 100644
--- a/tools/v4/main.cpp
+++ b/tools/v4/main.cpp
@@ -369,30 +369,30 @@ int main(int argc, char *argv[])
const QString code = QString::fromUtf8(file.readAll());
file.close();
- void * buf = __qmljs_create_exception_handler(ctx);
- if (setjmp(*(jmp_buf *)buf)) {
+ __qmljs_create_exception_handler(ctx);
+ try {
+ QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode,
+ /*strictMode =*/ false, /*inheritContext =*/ false);
+ if (!f)
+ continue;
+ vm.globalCode = f;
+
+ ctx->strictMode = f->isStrict;
+ ctx->lookups = f->lookups;
+ if (debugger)
+ debugger->aboutToCall(0, ctx);
+ QQmlJS::VM::Value result = f->code(ctx, f->codeData);
+ if (debugger)
+ debugger->justLeft(ctx);
+ if (!result.isUndefined()) {
+ if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
+ std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl;
+ }
+ } catch (const QQmlJS::VM::Exception&) {
showException(ctx);
return EXIT_FAILURE;
}
- QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode,
- /*strictMode =*/ false, /*inheritContext =*/ false);
- if (!f)
- continue;
- vm.globalCode = f;
-
- ctx->strictMode = f->isStrict;
- ctx->lookups = f->lookups;
- if (debugger)
- debugger->aboutToCall(0, ctx);
- QQmlJS::VM::Value result = f->code(ctx, f->codeData);
- if (debugger)
- debugger->justLeft(ctx);
- if (!result.isUndefined()) {
- if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
- std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl;
- }
-
} else {
std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
return EXIT_FAILURE;