aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4isel_masm.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-10-18 15:42:17 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-29 10:38:45 +0100
commit5229a8b259286c9ea61036fd6b4bd0039104a206 (patch)
tree277d62ecedeaf703ce778d86f8cbcb94b9a57fe2 /src/qml/compiler/qv4isel_masm.cpp
parent570686d42176af193b15abfe4b7bc17d831f4cf6 (diff)
Rework exception handling
Start the work to remove c++ exceptions from our JS exception handling. Rather rely on engine->hasException. Check the flag after we return from any runtime call in the JIT. Implement new try/catch handling code in qv4codegen and for the JIT that doesn't rely on exceptions. As an added bonus, we can remove the Try statement in the IR. Change-Id: Ic95addd6ae03371c43c47e04cac26afdce23a061 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/compiler/qv4isel_masm.cpp')
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp78
1 files changed, 13 insertions, 65 deletions
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index d5e67d91c3..6fe0f27ec3 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -166,7 +166,6 @@ protected:
virtual void visitJump(V4IR::Jump *) {}
virtual void visitCJump(V4IR::CJump *s) { s->cond->accept(this); }
virtual void visitRet(V4IR::Ret *s) { s->expr->accept(this); }
- virtual void visitTry(V4IR::Try *s) { s->exceptionVar->accept(this); }
virtual void visitPhi(V4IR::Phi *) { Q_UNREACHABLE(); }
};
@@ -236,6 +235,7 @@ Assembler::Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::
void Assembler::registerBlock(V4IR::BasicBlock* block, V4IR::BasicBlock *nextBlock)
{
_addrs[block] = label();
+ catchBlock = block->catchBlock;
_nextBlock = nextBlock;
}
@@ -557,6 +557,10 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
foreach (const DataLabelPatch &p, _dataLabelPatches)
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
+ // link exception handlers
+ foreach(Jump jump, exceptionPropagationJumps)
+ linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel));
+
{
QHashIterator<V4IR::BasicBlock *, QVector<DataLabelPtr> > it(_labelPatches);
while (it.hasNext()) {
@@ -648,9 +652,7 @@ void InstructionSelection::run(int functionIndex)
{
V4IR::Function *function = irModule->functions[functionIndex];
QVector<Lookup> lookups;
- QSet<V4IR::BasicBlock*> reentryBlocks;
qSwap(_function, function);
- qSwap(_reentryBlocks, reentryBlocks);
V4IR::Optimizer opt(_function);
opt.run();
@@ -714,17 +716,6 @@ void InstructionSelection::run(int functionIndex)
_block = _function->basicBlocks[i];
_as->registerBlock(_block, nextBlock);
- if (_reentryBlocks.contains(_block)) {
- _as->enterStandardStackFrame();
-#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
- }
-
foreach (V4IR::Stmt *s, _block->statements) {
if (s->location.isValid())
_as->recordLineNumber(s->location.startLine);
@@ -736,7 +727,6 @@ void InstructionSelection::run(int functionIndex)
compilationUnit->codeRefs[functionIndex] = codeRef;
qSwap(_function, function);
- qSwap(_reentryBlocks, reentryBlocks);
delete _as;
_as = oldAssembler;
qSwap(_removableJumps, removableJumps);
@@ -830,62 +820,18 @@ void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
{
generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister,
Assembler::PointerToValue(arg));
+ _as->jumpToExceptionHandler();
}
-typedef void *(*MiddleOfFunctionEntryPoint(ExecutionContext *, void *localsPtr));
-static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunctionEntryPoint tryBody, MiddleOfFunctionEntryPoint catchBody,
- QV4::StringRef exceptionVarName, ValueRef exceptionVar)
-{
- exceptionVar = Primitive::undefinedValue();
- void *addressToContinueAt = 0;
- SafeValue *jsStackTop = context->engine->jsStackTop;
- bool caughtException = false;
- try {
- addressToContinueAt = tryBody(context, localsPtr);
- } catch (...) {
- context->engine->jsStackTop = jsStackTop;
- exceptionVar = context->catchException();
- caughtException = true;
- }
- // Can't nest try { ... } catch (...) {} due to inability of nesting foreign exceptions
- // with common CXX ABI.
- if (caughtException) {
- try {
- ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, exceptionVar, context);
- addressToContinueAt = catchBody(catchContext, localsPtr);
- context = __qmljs_builtin_pop_scope(catchContext);
- } catch (...) {
- context->engine->jsStackTop = jsStackTop;
- exceptionVar = context->catchException();
- addressToContinueAt = catchBody(context, localsPtr);
- }
- }
- return addressToContinueAt;
-}
-
-void InstructionSelection::visitTry(V4IR::Try *t)
+void InstructionSelection::callBuiltinReThrow()
{
- // Call tryWrapper, which is going to re-enter the same function at the address of the try block. At then end
- // of the try function the JIT code will return with the address of the sub-sequent instruction, which tryWrapper
- // returns and to which we jump to.
-
- _reentryBlocks.insert(t->tryBlock);
- _reentryBlocks.insert(t->catchBlock);
-
- generateFunctionCall(Assembler::ReturnValueRegister, tryWrapper, Assembler::ContextRegister, Assembler::LocalsRegister,
- Assembler::ReentryBlock(t->tryBlock), Assembler::ReentryBlock(t->catchBlock),
- Assembler::PointerToString(*t->exceptionVarName), Assembler::PointerToValue(t->exceptionVar));
- _as->jump(Assembler::ReturnValueRegister);
+ _as->jumpToExceptionHandler();
}
-void InstructionSelection::callBuiltinFinishTry()
+void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
{
- // 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.
- Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister);
- _as->leaveStandardStackFrame();
- _as->ret();
- _as->addPatch(continuation, _as->label());
+ Assembler::Pointer s = _as->loadStringAddress(Assembler::ScratchRegister, exceptionName);
+ generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_push_catch_scope, s, Assembler::ContextRegister);
}
void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
@@ -2052,6 +1998,8 @@ void InstructionSelection::visitRet(V4IR::Ret *s)
Q_UNUSED(s);
}
+ _as->exceptionReturnLabel = _as->label();
+
const int locals = _as->stackLayout().calculateJSStackFrameSize();
_as->subPtr(Assembler::TrustedImm32(sizeof(QV4::SafeValue)*locals), Assembler::LocalsRegister);
_as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister);