aboutsummaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/qml/compiler/qv4codegen.cpp175
-rw-r--r--src/qml/compiler/qv4codegen_p.h18
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h14
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp78
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h44
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp27
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h4
-rw-r--r--src/qml/compiler/qv4isel_p.cpp12
-rw-r--r--src/qml/compiler/qv4isel_p.h3
-rw-r--r--src/qml/compiler/qv4jsir.cpp51
-rw-r--r--src/qml/compiler/qv4jsir_p.h37
-rw-r--r--src/qml/compiler/qv4regalloc.cpp7
-rw-r--r--src/qml/compiler/qv4ssa.cpp23
-rw-r--r--src/qml/jsruntime/qv4context.cpp63
-rw-r--r--src/qml/jsruntime/qv4context_p.h23
-rw-r--r--src/qml/jsruntime/qv4engine.cpp4
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp16
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h6
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp34
20 files changed, 246 insertions, 397 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index a68920235e..b7ea7491d6 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -403,7 +403,6 @@ Codegen::Codegen(bool strict)
, _function(0)
, _block(0)
, _exitBlock(0)
- , _throwBlock(0)
, _returnAddress(0)
, _env(0)
, _loop(0)
@@ -1074,13 +1073,13 @@ bool Codegen::visit(BinaryExpression *ast)
{
if (ast->op == QSOperator::And) {
if (_expr.accept(cx)) {
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
condition(ast->left, iftrue, _expr.iffalse);
_block = iftrue;
condition(ast->right, _expr.iftrue, _expr.iffalse);
} else {
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
const unsigned r = _block->newTemp();
@@ -1096,13 +1095,13 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
} else if (ast->op == QSOperator::Or) {
if (_expr.accept(cx)) {
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
condition(ast->left, _expr.iftrue, iffalse);
_block = iffalse;
condition(ast->right, _expr.iftrue, _expr.iffalse);
} else {
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
const unsigned r = _block->newTemp();
move(_block->TEMP(r), *expression(ast->left));
@@ -1253,9 +1252,9 @@ bool Codegen::visit(CallExpression *ast)
bool Codegen::visit(ConditionalExpression *ast)
{
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
const unsigned t = _block->newTemp();
@@ -1761,6 +1760,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
{
Loop *loop = 0;
qSwap(_loop, loop);
+ QStack<V4IR::BasicBlock *> exceptionHandlers;
+ qSwap(_exceptionHandlers, exceptionHandlers);
ScopeAndFinally *scopeAndFinally = 0;
@@ -1768,9 +1769,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
V4IR::Function *function = _module->newFunction(name, _function);
int functionIndex = _module->functions.count() - 1;
- V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
- V4IR::BasicBlock *throwBlock = function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock(), 0);
+ V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), 0, V4IR::Function::DontInsertBlock);
function->hasDirectEval = _env->hasDirectEval;
function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
@@ -1827,15 +1827,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
entryBlock->MOVE(entryBlock->TEMP(returnAddress), entryBlock->CONST(V4IR::UndefinedType, 0));
exitBlock->RET(exitBlock->TEMP(returnAddress));
- V4IR::ExprList *throwArgs = function->New<V4IR::ExprList>();
- throwArgs->expr = throwBlock->TEMP(returnAddress);
- throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
- throwBlock->JUMP(exitBlock);
qSwap(_function, function);
qSwap(_block, entryBlock);
qSwap(_exitBlock, exitBlock);
- qSwap(_throwBlock, throwBlock);
qSwap(_returnAddress, returnAddress);
qSwap(_scopeAndFinally, scopeAndFinally);
@@ -1871,9 +1866,9 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
qSwap(_function, function);
qSwap(_block, entryBlock);
qSwap(_exitBlock, exitBlock);
- qSwap(_throwBlock, throwBlock);
qSwap(_returnAddress, returnAddress);
qSwap(_scopeAndFinally, scopeAndFinally);
+ qSwap(_exceptionHandlers, exceptionHandlers);
qSwap(_loop, loop);
leaveEnvironment();
@@ -1973,9 +1968,9 @@ bool Codegen::visit(DebuggerStatement *)
bool Codegen::visit(DoWhileStatement *ast)
{
- V4IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody);
- V4IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody, exceptionHandler());
+ V4IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, loopbody, loopend, loopcond);
@@ -2014,9 +2009,9 @@ bool Codegen::visit(ExpressionStatement *ast)
bool Codegen::visit(ForEachStatement *ast)
{
- V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin);
- V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
+ V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, foreachin, foreachend, foreachin);
@@ -2052,10 +2047,10 @@ bool Codegen::visit(ForEachStatement *ast)
bool Codegen::visit(ForStatement *ast)
{
- V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, forcond, forend, forstep);
@@ -2085,9 +2080,10 @@ bool Codegen::visit(ForStatement *ast)
bool Codegen::visit(IfStatement *ast)
{
- V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock()) : 0;
- V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock(), exceptionHandler()) : 0;
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+
condition(ast->expression, iftrue, ast->ko ? iffalse : endif);
_block = iftrue;
@@ -2127,7 +2123,7 @@ bool Codegen::visit(LabelledStatement *ast)
AST::cast<AST::LocalForEachStatement *>(ast->statement)) {
statement(ast->statement); // labelledStatement will be associated with the ast->statement's loop.
} else {
- V4IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast->statement, 0, breakBlock, /*continueBlock*/ 0);
statement(ast->statement);
_block->JUMP(breakBlock);
@@ -2140,9 +2136,9 @@ bool Codegen::visit(LabelledStatement *ast)
bool Codegen::visit(LocalForEachStatement *ast)
{
- V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin);
- V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
+ V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, foreachin, foreachend, foreachin);
@@ -2178,10 +2174,10 @@ bool Codegen::visit(LocalForEachStatement *ast)
bool Codegen::visit(LocalForStatement *ast)
{
- V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond);
- V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler());
+ V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, forcond, forend, forstep);
@@ -2225,11 +2221,11 @@ bool Codegen::visit(ReturnStatement *ast)
bool Codegen::visit(SwitchStatement *ast)
{
- V4IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
if (ast->block) {
Result lhs = expression(ast->expression);
- V4IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->JUMP(switchcond);
V4IR::BasicBlock *previousBlock = 0;
@@ -2240,7 +2236,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
- _block = _function->newBasicBlock(groupStartBlock());
+ _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
blockMap[clause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2253,7 +2249,7 @@ bool Codegen::visit(SwitchStatement *ast)
}
if (ast->block->defaultClause) {
- _block = _function->newBasicBlock(groupStartBlock());
+ _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
blockMap[ast->block->defaultClause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2268,7 +2264,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
- _block = _function->newBasicBlock(groupStartBlock());
+ _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
blockMap[clause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2289,7 +2285,7 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
Result rhs = expression(clause->expression);
V4IR::BasicBlock *iftrue = blockMap[clause];
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
cjump(binop(V4IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
_block = iffalse;
}
@@ -2298,7 +2294,7 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
Result rhs = expression(clause->expression);
V4IR::BasicBlock *iftrue = blockMap[clause];
- V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
cjump(binop(V4IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
_block = iffalse;
}
@@ -2318,7 +2314,9 @@ bool Codegen::visit(ThrowStatement *ast)
{
Result expr = expression(ast->expression);
move(_block->TEMP(_returnAddress), *expr);
- _block->JUMP(_throwBlock);
+ V4IR::ExprList *throwArgs = _function->New<V4IR::ExprList>();
+ throwArgs->expr = _block->TEMP(_returnAddress);
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
return false;
}
@@ -2330,21 +2328,24 @@ bool Codegen::visit(TryStatement *ast)
(ast->catchExpression->name == QLatin1String("eval") || ast->catchExpression->name == QLatin1String("arguments")))
throwSyntaxError(ast->catchExpression->identifierToken, QCoreApplication::translate("qv4codegen", "Catch variable name may not be eval or arguments in strict mode"));
- V4IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *catchBody = _function->newBasicBlock(groupStartBlock());
// We always need a finally body to clean up the exception handler
- V4IR::BasicBlock *finallyBody = _function->newBasicBlock(groupStartBlock());
+ // exceptions thrown in finally get catched by the surrounding catch block
+ V4IR::BasicBlock *finallyBody = _function->newBasicBlock(groupStartBlock(), exceptionHandler(), V4IR::Function::DontInsertBlock);
- V4IR::BasicBlock *throwBlock = _function->newBasicBlock(groupStartBlock());
- V4IR::ExprList *throwArgs = _function->New<V4IR::ExprList>();
- throwArgs->expr = throwBlock->TEMP(_returnAddress);
- throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
- throwBlock->JUMP(catchBody);
- qSwap(_throwBlock, throwBlock);
+ // the Catch block for catch is the block itself. We protect against recursion by checking the
+ // hasException boolean
+ // all basic blocks within try and catch get catched by catchBody
+ V4IR::BasicBlock *catchBody = _function->newBasicBlock(groupStartBlock(), 0, V4IR::Function::DontInsertBlock);
+ catchBody->catchBlock = catchBody;
+ pushExceptionHandler(catchBody);
int hasException = _block->newTemp();
move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false));
+ V4IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ _block->JUMP(tryBody);
+
+ // ### Remove
// Pass the hidden "needRethrow" TEMP to the
// builtin_delete_exception_handler, in order to have those TEMPs alive for
// the duration of the exception handling block.
@@ -2354,23 +2355,24 @@ bool Codegen::visit(TryStatement *ast)
ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression, finishTryArgs);
_scopeAndFinally = &tcf;
- int exception_to_rethrow = _block->newTemp();
-
- _block->TRY(tryBody, catchBody,
- _function->newString(ast->catchExpression ? ast->catchExpression->name.toString() : QString()),
- _block->TEMP(exception_to_rethrow));
-
_block = tryBody;
statement(ast->statement);
_block->JUMP(finallyBody);
+ _function->insertBasicBlock(catchBody);
_block = catchBody;
if (ast->catchExpression) {
// check if an exception got thrown within catch. Go to finally
// and then rethrow
- V4IR::BasicBlock *b = _function->newBasicBlock(groupStartBlock());
- _block->CJUMP(_block->TEMP(hasException), finallyBody, b);
+ V4IR::BasicBlock *cleanupCatchScope = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *b = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ _block->CJUMP(_block->TEMP(hasException), cleanupCatchScope, b);
+
+ _block = cleanupCatchScope;
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+ _block->JUMP(finallyBody);
+
_block = b;
}
@@ -2378,12 +2380,16 @@ bool Codegen::visit(TryStatement *ast)
if (ast->catchExpression) {
++_function->insideWithOrCatch;
+ V4IR::ExprList *catchArgs = _function->New<V4IR::ExprList>();
+ catchArgs->init(_block->STRING(_function->newString(ast->catchExpression->name.toString())));
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_push_catch_scope, 0, 0), catchArgs));
{
ScopeAndFinally scope(_scopeAndFinally, ScopeAndFinally::CatchScope);
_scopeAndFinally = &scope;
statement(ast->catchExpression->statement);
_scopeAndFinally = scope.parent;
}
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
--_function->insideWithOrCatch;
move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false));
}
@@ -2391,21 +2397,20 @@ bool Codegen::visit(TryStatement *ast)
_scopeAndFinally = tcf.parent;
- qSwap(_throwBlock, throwBlock);
+ // exceptions thrown in finally get catched by the surrounding catch statement
+ popExceptionHandler();
- V4IR::BasicBlock *after = _function->newBasicBlock(groupStartBlock());
- _block = finallyBody;
-
- _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_finish_try, 0, 0), finishTryArgs));
+ _function->insertBasicBlock(finallyBody);
+ _block = finallyBody;
if (ast->finallyExpression && ast->finallyExpression->statement)
statement(ast->finallyExpression->statement);
- V4IR::BasicBlock *rethrowBlock = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *rethrowBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *after = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->CJUMP(_block->TEMP(hasException), rethrowBlock, after);
_block = rethrowBlock;
- move(_block->TEMP(_returnAddress), _block->TEMP(exception_to_rethrow));
- _block->JUMP(_throwBlock);
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_rethrow, /*line*/0, /*column*/0), 0));
_block = after;
@@ -2420,14 +2425,13 @@ void Codegen::unwindException(Codegen::ScopeAndFinally *outest)
while (_scopeAndFinally != outest) {
switch (_scopeAndFinally->type) {
case ScopeAndFinally::WithScope:
- _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0)));
// fall through
case ScopeAndFinally::CatchScope:
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0)));
_scopeAndFinally = _scopeAndFinally->parent;
--_function->insideWithOrCatch;
break;
case ScopeAndFinally::TryScope: {
- _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_finish_try, 0, 0), _scopeAndFinally->finishTryArgs));
ScopeAndFinally *tc = _scopeAndFinally;
_scopeAndFinally = tc->parent;
if (tc->finally && tc->finally->statement)
@@ -2448,9 +2452,9 @@ bool Codegen::visit(VariableStatement *ast)
bool Codegen::visit(WhileStatement *ast)
{
- V4IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock());
- V4IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond);
- V4IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ V4IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond, exceptionHandler());
+ V4IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
enterLoop(ast, whilecond, whileend, whilecond);
@@ -2472,7 +2476,17 @@ bool Codegen::visit(WithStatement *ast)
{
_function->hasWith = true;
- V4IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock());
+ // need an exception handler for with to cleanup the with scope
+ V4IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+ if (!exceptionHandler())
+ withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(V4IR::Name::builtin_rethrow, 0, 0), 0));
+ else
+ withExceptionHandler->JUMP(exceptionHandler());
+
+ pushExceptionHandler(withExceptionHandler);
+
+ V4IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->JUMP(withBlock);
_block = withBlock;
@@ -2491,8 +2505,9 @@ bool Codegen::visit(WithStatement *ast)
}
--_function->insideWithOrCatch;
_block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+ popExceptionHandler();
- V4IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
_block->JUMP(next);
_block = next;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 66b80c377b..652f395a88 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -272,6 +272,22 @@ protected:
return it->groupStartBlock;
return 0;
}
+ V4IR::BasicBlock *exceptionHandler() const
+ {
+ if (_exceptionHandlers.isEmpty())
+ return 0;
+ return _exceptionHandlers.top();
+ }
+ void pushExceptionHandler(V4IR::BasicBlock *handler)
+ {
+ handler->isExceptionHandler = true;
+ _exceptionHandlers.push(handler);
+ }
+ void popExceptionHandler()
+ {
+ Q_ASSERT(!_exceptionHandlers.isEmpty());
+ _exceptionHandlers.pop();
+ }
V4IR::Expr *member(V4IR::Expr *base, const QString *name);
V4IR::Expr *subscript(V4IR::Expr *base, V4IR::Expr *index);
@@ -428,7 +444,6 @@ protected:
V4IR::Function *_function;
V4IR::BasicBlock *_block;
V4IR::BasicBlock *_exitBlock;
- V4IR::BasicBlock *_throwBlock;
unsigned _returnAddress;
Environment *_env;
Loop *_loop;
@@ -436,6 +451,7 @@ protected:
ScopeAndFinally *_scopeAndFinally;
QHash<AST::Node *, Environment *> _envMap;
QHash<AST::FunctionExpression *, int> _functionMap;
+ QStack<V4IR::BasicBlock *> _exceptionHandlers;
bool _strictMode;
QList<QQmlError> _errors;
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 3c28633491..b9163b38d3 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -64,13 +64,11 @@ QT_BEGIN_NAMESPACE
F(LoadProperty, loadProperty) \
F(StoreProperty, storeProperty) \
F(Push, push) \
- F(EnterTry, enterTry) \
F(CallValue, callValue) \
F(CallProperty, callProperty) \
F(CallElement, callElement) \
F(CallActivationProperty, callActivationProperty) \
F(CallBuiltinThrow, callBuiltinThrow) \
- F(CallBuiltinFinishTry, callBuiltinFinishTry) \
F(CallBuiltinPushScope, callBuiltinPushScope) \
F(CallBuiltinPopScope, callBuiltinPopScope) \
F(CallBuiltinForeachIteratorObject, callBuiltinForeachIteratorObject) \
@@ -274,13 +272,6 @@ union Instr
MOTH_INSTR_HEADER
quint32 value;
};
- struct instr_enterTry {
- MOTH_INSTR_HEADER
- ptrdiff_t tryOffset;
- ptrdiff_t catchOffset;
- int exceptionVarName;
- Param exceptionVar;
- };
struct instr_callValue {
MOTH_INSTR_HEADER
quint32 argc;
@@ -315,9 +306,6 @@ union Instr
MOTH_INSTR_HEADER
Param arg;
};
- struct instr_callBuiltinFinishTry {
- MOTH_INSTR_HEADER
- };
struct instr_callBuiltinPushScope {
MOTH_INSTR_HEADER
Param arg;
@@ -498,13 +486,11 @@ union Instr
instr_loadProperty loadProperty;
instr_storeProperty storeProperty;
instr_push push;
- instr_enterTry enterTry;
instr_callValue callValue;
instr_callProperty callProperty;
instr_callElement callElement;
instr_callActivationProperty callActivationProperty;
instr_callBuiltinThrow callBuiltinThrow;
- instr_callBuiltinFinishTry callBuiltinFinishTry;
instr_callBuiltinPushScope callBuiltinPushScope;
instr_callBuiltinPopScope callBuiltinPopScope;
instr_callBuiltinForeachIteratorObject callBuiltinForeachIteratorObject;
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);
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index bd4c564ab9..3d1b271cdc 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -49,6 +49,7 @@
#include "private/qv4lookup_p.h"
#include <QtCore/QHash>
+#include <QtCore/QStack>
#include <config.h>
#include <wtf/Vector.h>
@@ -62,6 +63,7 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace MASM {
+
class InstructionSelection;
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
@@ -88,6 +90,13 @@ struct RelativeCall {
{}
};
+
+template <typename T>
+struct ExceptionCheck {
+ enum { NeedsCheck = 1 };
+};
+
+
class Assembler : public JSC::MacroAssembler
{
public:
@@ -874,6 +883,23 @@ public:
void enterStandardStackFrame();
void leaveStandardStackFrame();
+ void checkException() {
+ loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext, engine)), ScratchRegister);
+ load32(Address(ScratchRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
+ Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ if (catchBlock)
+ addPatch(catchBlock, exceptionThrown);
+ else
+ exceptionPropagationJumps.append(exceptionThrown);
+ }
+ void jumpToExceptionHandler() {
+ Jump exceptionThrown = jump();
+ if (catchBlock)
+ addPatch(catchBlock, exceptionThrown);
+ else
+ exceptionPropagationJumps.append(exceptionThrown);
+ }
+
template <int argumentNumber, typename T>
void loadArgumentOnStackOrRegister(const T &value)
{
@@ -917,7 +943,6 @@ public:
enum { Size = 0 };
};
-
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
@@ -954,10 +979,15 @@ public:
callAbsolute(functionName, function);
- storeReturnValue(r);
-
if (stackSpaceNeeded)
add32(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
+
+ if (ExceptionCheck<Callable>::NeedsCheck) {
+ checkException();
+ }
+
+ storeReturnValue(r);
+
}
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
@@ -1351,6 +1381,9 @@ public:
const StackLayout stackLayout() const { return _stackLayout; }
ConstantTable &constantTable() { return _constTable; }
+ Label exceptionReturnLabel;
+ V4IR::BasicBlock * catchBlock;
+ QVector<Jump> exceptionPropagationJumps;
private:
const StackLayout _stackLayout;
ConstantTable _constTable;
@@ -1410,7 +1443,8 @@ protected:
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinDeleteValue(V4IR::Temp *result);
virtual void callBuiltinThrow(V4IR::Expr *arg);
- virtual void callBuiltinFinishTry();
+ virtual void callBuiltinReThrow();
+ virtual void callBuiltinPushCatchScope(const QString &exceptionName);
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
@@ -1469,7 +1503,6 @@ protected:
virtual void visitJump(V4IR::Jump *);
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
- virtual void visitTry(V4IR::Try *);
Assembler::Jump genTryDoubleConversion(V4IR::Expr *src, Assembler::FPRegisterID dest);
Assembler::Jump genInlineBinop(V4IR::AluOp oper, V4IR::Expr *leftSource,
@@ -1589,7 +1622,6 @@ private:
V4IR::Function* _function;
QSet<V4IR::Jump *> _removableJumps;
Assembler* _as;
- QSet<V4IR::BasicBlock*> _reentryBlocks;
CompilationUnit *compilationUnit;
};
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index d354bf66a5..2e31aa10a0 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -684,22 +684,6 @@ void InstructionSelection::visitRet(V4IR::Ret *s)
addInstruction(ret);
}
-void InstructionSelection::visitTry(V4IR::Try *t)
-{
- Instruction::EnterTry enterTry;
- enterTry.tryOffset = 0;
- enterTry.catchOffset = 0;
- enterTry.exceptionVarName = registerString(*t->exceptionVarName);
- enterTry.exceptionVar = getParam(t->exceptionVar);
- ptrdiff_t enterTryLoc = addInstruction(enterTry);
-
- ptrdiff_t tryLoc = enterTryLoc + (((const char *)&enterTry.tryOffset) - ((const char *)&enterTry));
- _patches[t->tryBlock].append(tryLoc);
-
- ptrdiff_t catchLoc = enterTryLoc + (((const char *)&enterTry.catchOffset) - ((const char *)&enterTry));
- _patches[t->catchBlock].append(catchLoc);
-}
-
void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
Instruction::CallActivationProperty call;
@@ -788,10 +772,15 @@ void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg)
addInstruction(call);
}
-void InstructionSelection::callBuiltinFinishTry()
+void InstructionSelection::callBuiltinReThrow()
{
- Instruction::CallBuiltinFinishTry call;
- addInstruction(call);
+ // ###
+}
+
+
+void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
+{
+ // ####
}
void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 725dd264aa..8be28b5605 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -82,7 +82,6 @@ protected:
virtual void visitJump(V4IR::Jump *);
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
- virtual void visitTry(V4IR::Try *);
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callBuiltinTypeofMember(V4IR::Expr *base, const QString &name, V4IR::Temp *result);
@@ -94,7 +93,8 @@ protected:
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinDeleteValue(V4IR::Temp *result);
virtual void callBuiltinThrow(V4IR::Expr *arg);
- virtual void callBuiltinFinishTry();
+ virtual void callBuiltinReThrow();
+ virtual void callBuiltinPushCatchScope(const QString &exceptionName);
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 483cb8e6f9..7d10230f43 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -266,9 +266,15 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
callBuiltinThrow(arg);
} return;
- case V4IR::Name::builtin_finish_try:
- callBuiltinFinishTry();
- return;
+ case V4IR::Name::builtin_rethrow: {
+ callBuiltinReThrow();
+ } return;
+
+ case V4IR::Name::builtin_push_catch_scope: {
+ V4IR::String *s = call->args->expr->asString();
+ Q_ASSERT(s);
+ callBuiltinPushCatchScope(*s->value);
+ } return;
case V4IR::Name::builtin_foreach_iterator_object: {
V4IR::Temp *arg = call->args->expr->asTemp();
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 8fd59b609c..9895e2fd04 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -119,7 +119,8 @@ public: // to implement by subclasses:
virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result) = 0;
virtual void callBuiltinDeleteValue(V4IR::Temp *result) = 0;
virtual void callBuiltinThrow(V4IR::Expr *arg) = 0;
- virtual void callBuiltinFinishTry() = 0;
+ virtual void callBuiltinReThrow() = 0;
+ virtual void callBuiltinPushCatchScope(const QString &exceptionName) = 0;
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result) = 0;
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result) = 0;
virtual void callBuiltinPushWithScope(V4IR::Temp *arg) = 0;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 50afcf29c2..f0a37895b5 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -217,11 +217,6 @@ struct RemoveSharedExpressions: V4IR::StmtVisitor, V4IR::ExprVisitor
s->expr = cleanup(s->expr);
}
- virtual void visitTry(Try *)
- {
- // nothing to do for Try statements
- }
-
virtual void visitPhi(V4IR::Phi *) { Q_UNIMPLEMENTED(); }
// expressions
@@ -400,8 +395,10 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_delete";
case Name::builtin_throw:
return "builtin_throw";
- case Name::builtin_finish_try:
- return "builtin_finish_try";
+ case Name::builtin_rethrow:
+ return "builtin_rethrow";
+ case Name::builtin_push_catch_scope:
+ return "builtin_push_catch_scope";
case V4IR::Name::builtin_foreach_iterator_object:
return "builtin_foreach_iterator_object";
case V4IR::Name::builtin_foreach_next_property_name:
@@ -585,13 +582,6 @@ void Ret::dump(QTextStream &out, Mode)
out << ';';
}
-void Try::dump(QTextStream &out, Stmt::Mode mode)
-{
- out << "try L" << tryBlock->index << "; catch exception in ";
- exceptionVar->dump(out);
- out << " with the name " << exceptionVarName << " and go to L" << catchBlock->index << ';';
-}
-
void Phi::dump(QTextStream &out, Stmt::Mode mode)
{
targetTemp->dump(out);
@@ -653,9 +643,9 @@ const QString *Function::newString(const QString &text)
return &*strings.insert(text);
}
-BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlockInsertMode mode)
+BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode)
{
- BasicBlock *block = new BasicBlock(this, containingLoop);
+ BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock);
return mode == InsertBlock ? insertBasicBlock(block) : block;
}
@@ -905,33 +895,12 @@ Stmt *BasicBlock::RET(Temp *expr)
return s;
}
-Stmt *BasicBlock::TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString *exceptionVarName, Temp *exceptionVar)
-{
- if (isTerminated())
- return 0;
-
- Try *t = function->New<Try>();
- t->init(tryBlock, catchBlock, exceptionVarName, exceptionVar);
- appendStatement(t);
-
- assert(! out.contains(tryBlock));
- out.append(tryBlock);
-
- assert(! out.contains(catchBlock));
- out.append(catchBlock);
-
- assert(! tryBlock->in.contains(this));
- tryBlock->in.append(this);
-
- assert(! catchBlock->in.contains(this));
- catchBlock->in.append(this);
-
- return t;
-}
-
void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
{
- out << 'L' << index << ':' << endl;
+ out << 'L' << index << ':';
+ if (catchBlock)
+ out << " (catchBlock L" << catchBlock->index << ")";
+ out << endl;
foreach (Stmt *s, statements) {
out << '\t';
s->dump(out, mode);
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 8d090cab1e..ee8e0c0636 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -119,7 +119,6 @@ struct Move;
struct Jump;
struct CJump;
struct Ret;
-struct Try;
struct Phi;
enum AluOp {
@@ -215,7 +214,6 @@ struct StmtVisitor {
virtual void visitJump(Jump *) = 0;
virtual void visitCJump(CJump *) = 0;
virtual void visitRet(Ret *) = 0;
- virtual void visitTry(Try *) = 0;
virtual void visitPhi(Phi *) = 0;
};
@@ -312,7 +310,8 @@ struct Name: Expr {
builtin_typeof,
builtin_delete,
builtin_throw,
- builtin_finish_try,
+ builtin_rethrow,
+ builtin_push_catch_scope,
builtin_foreach_iterator_object,
builtin_foreach_next_property_name,
builtin_push_with_scope,
@@ -552,7 +551,6 @@ struct Stmt {
virtual Jump *asJump() { return 0; }
virtual CJump *asCJump() { return 0; }
virtual Ret *asRet() { return 0; }
- virtual Try *asTry() { return 0; }
virtual Phi *asPhi() { return 0; }
virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
@@ -646,28 +644,6 @@ struct Ret: Stmt {
virtual void dump(QTextStream &out, Mode);
};
-struct Try: Stmt {
- BasicBlock *tryBlock;
- BasicBlock *catchBlock;
- const QString *exceptionVarName;
- Temp *exceptionVar; // place to store the caught exception, for use when re-throwing
-
- void init(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString *exceptionVarName, Temp *exceptionVar)
- {
- this->tryBlock = tryBlock;
- this->catchBlock = catchBlock;
- this->exceptionVarName = exceptionVarName;
- this->exceptionVar = exceptionVar;
- }
-
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitTry(this); }
- virtual Try *asTry() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
-};
-
struct Phi: Stmt {
Temp *targetTemp;
@@ -751,7 +727,7 @@ struct Function {
DontInsertBlock
};
- BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlockInsertMode mode = InsertBlock);
+ BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
const QString *newString(const QString &text);
void RECEIVE(const QString &name) { formals.append(newString(name)); }
@@ -771,17 +747,21 @@ struct Function {
struct BasicBlock {
Function *function;
+ BasicBlock *catchBlock;
QVector<Stmt *> statements;
QVector<BasicBlock *> in;
QVector<BasicBlock *> out;
QBitArray liveIn;
QBitArray liveOut;
int index;
+ bool isExceptionHandler;
AST::SourceLocation nextLocation;
- BasicBlock(Function *function, BasicBlock *containingLoop)
+ BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher)
: function(function)
+ , catchBlock(catcher)
, index(-1)
+ , isExceptionHandler(false)
, _containingGroup(containingLoop)
, _groupStart(false)
{}
@@ -837,7 +817,6 @@ struct BasicBlock {
Stmt *JUMP(BasicBlock *target);
Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
Stmt *RET(Temp *expr);
- Stmt *TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString *exceptionVarName, Temp *exceptionVar);
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index c35ee860f7..5d1265b4b6 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -193,7 +193,8 @@ protected: // IRDecoder
virtual void callBuiltinDeleteName(const QString &, V4IR::Temp *) {}
virtual void callBuiltinDeleteValue(V4IR::Temp *) {}
virtual void callBuiltinThrow(V4IR::Expr *) {}
- virtual void callBuiltinFinishTry() {}
+ virtual void callBuiltinReThrow() {}
+ virtual void callBuiltinPushCatchScope(const QString &) {};
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *, V4IR::Temp *) {}
virtual void callBuiltinForeachNextProperty(V4IR::Temp *, V4IR::Temp *) {}
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *, V4IR::Temp *) {}
@@ -506,9 +507,6 @@ protected: // IRDecoder
virtual void visitRet(V4IR::Ret *s)
{ addUses(s->expr->asTemp(), Use::CouldHaveRegister); }
- virtual void visitTry(V4IR::Try *)
- { Q_UNREACHABLE(); } // this should never happen, we do not optimize when there is a try in the function
-
virtual void visitPhi(V4IR::Phi *s)
{
addDef(s->targetTemp, true);
@@ -954,7 +952,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) { Q_UNREACHABLE(); }
virtual void visitPhi(Phi *) {}
};
} // anonymous namespace
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index d1ebbcc26b..77ee957538 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -118,6 +118,11 @@ void showMeTheCode(Function *function)
str.append('L');
str.append(QByteArray::number(bb->index));
str.append(':');
+ if (bb->catchBlock) {
+ str.append(" (exception handler L");
+ str.append(QByteArray::number(bb->catchBlock->index));
+ str.append(')');
+ }
for (int i = 66 - str.length(); i; --i)
str.append(' ');
qout << str;
@@ -481,8 +486,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) { // ### TODO
- }
virtual void visitCall(Call *e) {
e->base->accept(this);
@@ -725,7 +728,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *s) { /* this should never happen */ }
virtual void visitConst(Const *) {}
virtual void visitString(String *) {}
@@ -959,7 +961,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) {}
virtual void visitPhi(Phi *s) {
addDef(s->targetTemp);
@@ -1310,7 +1311,6 @@ private:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *s) { s->exceptionVar->accept(this); }
virtual void visitPhi(Phi *s) {
s->targetTemp->accept(this);
foreach (Expr *e, s->d->incoming)
@@ -1520,7 +1520,6 @@ protected:
virtual void visitJump(Jump *) { _ty = TypingResult(MissingType); }
virtual void visitCJump(CJump *s) { _ty = run(s->cond); }
virtual void visitRet(Ret *s) { _ty = run(s->expr); }
- virtual void visitTry(Try *s) { setType(s->exceptionVar, VarType); _ty = TypingResult(MissingType); }
virtual void visitPhi(Phi *s) {
_ty = run(s->d->incoming[0]);
for (int i = 1, ei = s->d->incoming.size(); i != ei; ++i) {
@@ -1796,7 +1795,6 @@ protected:
run(s->cond, BoolType);
}
virtual void visitRet(Ret *s) { run(s->expr); }
- virtual void visitTry(Try *) {}
virtual void visitPhi(Phi *s) {
Type ty = s->targetTemp->type;
for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i)
@@ -1818,7 +1816,7 @@ void splitCriticalEdges(Function *f)
#endif
// create the basic block:
- BasicBlock *newBB = new BasicBlock(f, bb->containingGroup());
+ BasicBlock *newBB = new BasicBlock(f, bb->containingGroup(), bb->catchBlock);
newBB->index = f->basicBlocks.last()->index + 1;
f->basicBlocks.append(newBB);
Jump *s = f->New<Jump>();
@@ -1962,7 +1960,7 @@ void cleanupBasicBlocks(Function *function)
W.removeFirst();
if (toRemove.contains(bb))
continue;
- if (bb->in.isEmpty()) {
+ if (bb->in.isEmpty() && !bb->isExceptionHandler) {
foreach (BasicBlock *outBB, bb->out) {
int idx = outBB->in.indexOf(bb);
if (idx != -1) {
@@ -2103,7 +2101,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { check(s->cond); }
virtual void visitRet(Ret *s) { check(s->expr); }
- virtual void visitTry(Try *) { Q_UNREACHABLE(); }
virtual void visitPhi(Phi *s) {
for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i)
check(s->d->incoming[i]);
@@ -2166,6 +2163,11 @@ namespace {
/// Important: this assumes that there are no critical edges in the control-flow graph!
void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector<Stmt *> &W)
{
+ // don't purge blocks that are entry points for catch statements. They might not be directly
+ // connected, but are required anyway
+ if (bb->isExceptionHandler)
+ return;
+
QVector<BasicBlock *> toPurge;
toPurge.append(bb);
@@ -2603,7 +2605,6 @@ protected:
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitTry(Try *) {}
virtual void visitPhi(Phi *s) {
// Handled separately
}
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index f3d2ab66ed..c14d987171 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -461,69 +461,6 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name)
return 0;
}
-ReturnedValue ExecutionContext::getPropertyNoThrow(const StringRef name)
-{
- Scope scope(this);
- ScopedValue v(scope);
- name->makeIdentifier();
-
- if (name->equals(engine->id_this))
- return callData->thisObject.asReturnedValue();
-
- bool hasWith = false;
- bool hasCatchScope = false;
- for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
- if (ctx->type == Type_WithContext) {
- ScopedObject w(scope, static_cast<WithContext *>(ctx)->withObject);
- hasWith = true;
- bool hasProperty = false;
- v = w->get(name, &hasProperty);
- if (hasProperty) {
- return v.asReturnedValue();
- }
- continue;
- }
-
- else if (ctx->type == Type_CatchContext) {
- hasCatchScope = true;
- CatchContext *c = static_cast<CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name))
- return c->exceptionValue.asReturnedValue();
- }
-
- else if (ctx->type >= Type_CallContext) {
- QV4::CallContext *c = static_cast<CallContext *>(ctx);
- ScopedFunctionObject f(scope, c->function);
- if (f->needsActivation || hasWith || hasCatchScope) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return c->locals[i].asReturnedValue();
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return c->callData->args[i].asReturnedValue();
- }
- if (c->activation) {
- bool hasProperty = false;
- v = c->activation->get(name, &hasProperty);
- if (hasProperty)
- return v.asReturnedValue();
- }
- if (f->function && f->function->isNamedExpression()
- && name->equals(f->function->name))
- return f.asReturnedValue();
- }
-
- else if (ctx->type == Type_GlobalContext) {
- GlobalContext *g = static_cast<GlobalContext *>(ctx);
- bool hasProperty = false;
- v = g->global->get(name, &hasProperty);
- if (hasProperty)
- return v.asReturnedValue();
- }
- }
- return Encode::undefined();
-}
-
ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectRef base)
{
Scope scope(this);
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index e5b0c431ca..e85350451b 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -127,21 +127,20 @@ struct Q_QML_EXPORT ExecutionContext
void createMutableBinding(const StringRef name, bool deletable);
- void Q_NORETURN throwError(const QV4::ValueRef value);
- void Q_NORETURN throwError(const QString &message);
- void Q_NORETURN throwSyntaxError(const QString &message);
- void Q_NORETURN throwSyntaxError(const QString &message, const QString &fileName, int line, int column);
- void Q_NORETURN throwTypeError();
- void Q_NORETURN throwTypeError(const QString &message);
- void Q_NORETURN throwReferenceError(const ValueRef value);
- void Q_NORETURN throwReferenceError(const QString &value, const QString &fileName, int line, int column);
- void Q_NORETURN throwRangeError(const ValueRef value);
- void Q_NORETURN throwURIError(const ValueRef msg);
- void Q_NORETURN throwUnimplemented(const QString &message);
+ void throwError(const QV4::ValueRef value);
+ void throwError(const QString &message);
+ void throwSyntaxError(const QString &message);
+ void throwSyntaxError(const QString &message, const QString &fileName, int line, int column);
+ void throwTypeError();
+ void throwTypeError(const QString &message);
+ void throwReferenceError(const ValueRef value);
+ void throwReferenceError(const QString &value, const QString &fileName, int line, int column);
+ void throwRangeError(const ValueRef value);
+ void throwURIError(const ValueRef msg);
+ void throwUnimplemented(const QString &message);
void setProperty(const StringRef name, const ValueRef value);
ReturnedValue getProperty(const StringRef name);
- ReturnedValue getPropertyNoThrow(const StringRef name);
ReturnedValue getPropertyAndBase(const StringRef name, ObjectRef base);
bool deleteProperty(const StringRef name);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 2c68c4f400..3449c1aa3c 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -809,7 +809,7 @@ QmlExtensions *ExecutionEngine::qmlExtensions()
void ExecutionEngine::throwException(const ValueRef value)
{
- Q_ASSERT(!hasException);
+// Q_ASSERT(!hasException);
hasException = true;
exceptionValue = value;
QV4::Scope scope(this);
@@ -822,8 +822,6 @@ void ExecutionEngine::throwException(const ValueRef value)
if (debugger)
debugger->aboutToThrow(value);
- UnwindHelper::prepareForUnwind(current);
- throwInternal();
}
ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace)
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 24fb4ad923..3eaf08dd2a 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -323,10 +323,10 @@ struct Q_QML_EXPORT ExecutionEngine
// Exception handling
SafeValue exceptionValue;
- bool hasException;
+ quint32 hasException;
StackTrace exceptionStackTrace;
- void Q_NORETURN throwException(const ValueRef value);
+ void throwException(const ValueRef value);
ReturnedValue catchException(ExecutionContext *catchingContext, StackTrace *trace);
// Use only inside catch(...) -- will re-throw if no JS exception
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6f914fa3c2..9b16f4e45a 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -769,6 +769,9 @@ ReturnedValue __qmljs_call_activation_property(ExecutionContext *context, const
ScopedObject base(scope);
ScopedValue func(scope, context->getPropertyAndBase(name, base));
+ if (context->engine->hasException)
+ return Encode::undefined();
+
if (base)
callData->thisObject = base;
@@ -866,6 +869,9 @@ ReturnedValue __qmljs_construct_activation_property(ExecutionContext *context, c
{
Scope scope(context);
ScopedValue func(scope, context->getProperty(name));
+ if (context->engine->hasException)
+ return Encode::undefined();
+
Object *f = func->asObject();
if (!f)
context->throwTypeError();
@@ -931,7 +937,9 @@ ReturnedValue __qmljs_builtin_typeof(ExecutionContext *ctx, const ValueRef value
QV4::ReturnedValue __qmljs_builtin_typeof_name(ExecutionContext *context, const StringRef name)
{
Scope scope(context);
- ScopedValue prop(scope, context->getPropertyNoThrow(name));
+ ScopedValue prop(scope, context->getProperty(name));
+ // typeof doesn't throw. clear any possible exception
+ context->engine->hasException = false;
return __qmljs_builtin_typeof(context, prop);
}
@@ -959,9 +967,11 @@ ExecutionContext *__qmljs_builtin_push_with_scope(const ValueRef o, ExecutionCon
return ctx->newWithContext(obj);
}
-ExecutionContext *__qmljs_builtin_push_catch_scope(const StringRef exceptionVarName, const ValueRef exceptionValue, ExecutionContext *ctx)
+ExecutionContext *__qmljs_builtin_push_catch_scope(const StringRef exceptionVarName, ExecutionContext *ctx)
{
- return ctx->newCatchContext(exceptionVarName, exceptionValue);
+ Scope scope(ctx);
+ ScopedValue v(scope, ctx->engine->catchException(ctx, 0));
+ return ctx->newCatchContext(exceptionVarName, v);
}
ExecutionContext *__qmljs_builtin_pop_scope(ExecutionContext *ctx)
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 4ede7ae991..50a1ce17d1 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -127,9 +127,9 @@ QV4::ReturnedValue __qmljs_builtin_typeof_name(QV4::ExecutionContext *context, c
QV4::ReturnedValue __qmljs_builtin_typeof_member(QV4::ExecutionContext* context, const QV4::ValueRef base, const QV4::StringRef name);
QV4::ReturnedValue __qmljs_builtin_typeof_element(QV4::ExecutionContext* context, const QV4::ValueRef base, const QV4::ValueRef index);
-void Q_NORETURN __qmljs_builtin_rethrow(QV4::ExecutionContext *context);
+void __qmljs_builtin_rethrow(QV4::ExecutionContext *context);
QV4::ExecutionContext *__qmljs_builtin_push_with_scope(const QV4::ValueRef o, QV4::ExecutionContext *ctx);
-QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(const QV4::StringRef exceptionVarName, const QV4::ValueRef exceptionValue, QV4::ExecutionContext *ctx);
+QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(const QV4::StringRef exceptionVarName, QV4::ExecutionContext *ctx);
QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx);
void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, const QV4::StringRef name);
void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, QV4::ValueRef val);
@@ -199,7 +199,7 @@ QV4::ReturnedValue __qmljs_delete_subscript(QV4::ExecutionContext *ctx, const QV
ReturnedValue __qmljs_delete_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::StringRef name);
ReturnedValue __qmljs_delete_name(QV4::ExecutionContext *ctx, const QV4::StringRef name);
-void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::ValueRef value);
+void __qmljs_throw(QV4::ExecutionContext*, const QV4::ValueRef value);
// binary operators
typedef QV4::ReturnedValue (*BinOp)(const QV4::ValueRef left, const QV4::ValueRef right);
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 64b49f9a05..04a07093c1 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -365,40 +365,6 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
__qmljs_throw(context, VALUEPTR(instr.arg));
MOTH_END_INSTR(CallBuiltinThrow)
- MOTH_BEGIN_INSTR(EnterTry)
- VALUE(instr.exceptionVar) = QV4::Primitive::undefinedValue();
- bool caughtException = false;
- try {
- const uchar *tryCode = ((uchar *)&instr.tryOffset) + instr.tryOffset;
- run(context, tryCode, stack, stackSize);
- code = tryCode;
- context->interpreterInstructionPointer = &code;
- } catch (...) {
- STOREVALUE(instr.exceptionVar, context->catchException());
- caughtException = true;
- }
- if (caughtException) {
- try {
- QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(runtimeStrings[instr.exceptionVarName], VALUEPTR(instr.exceptionVar), context);
- const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
- run(catchContext, catchCode, stack, stackSize);
- code = catchCode;
- context->interpreterInstructionPointer = &code;
- context = __qmljs_builtin_pop_scope(catchContext);
- } catch (...) {
- STOREVALUE(instr.exceptionVar, context->catchException());
- const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
- run(context, catchCode, stack, stackSize);
- code = catchCode;
- context->interpreterInstructionPointer = &code;
- }
- }
- MOTH_END_INSTR(EnterTry)
-
- MOTH_BEGIN_INSTR(CallBuiltinFinishTry)
- return QV4::ReturnedValue(0);
- MOTH_END_INSTR(CallBuiltinFinishTry)
-
MOTH_BEGIN_INSTR(CallBuiltinPushScope)
context = __qmljs_builtin_push_with_scope(VALUEPTR(instr.arg), context);
MOTH_END_INSTR(CallBuiltinPushScope)