diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-10-21 17:07:45 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-29 10:38:48 +0100 |
commit | 34bf0139c75de861c948391737af3c8c2a42703c (patch) | |
tree | 3eeeb615078c27b30e15a77adcda7d6537baef17 /src/qml/compiler/qv4codegen.cpp | |
parent | 5229a8b259286c9ea61036fd6b4bd0039104a206 (diff) |
Rework IR code generation for try/catch/finally
Simplify the generated code. Add a special block to catch
exceptions thrown inside a catch() statement.
store the exception on the stack when entering finally and
rethrow it at the end. This ensure correct behavior for
break/continue/return statements inside finally.
Don't check for exceptions after calling push_catch_scope
and pop_scope in the JIT'ed code. This can lead to infinite
loops when throwing inside an exception handler.
Change-Id: I67e9325794e2fd25b0773b21e02fbaadb43faab0
Change-Id: Ic1ea9c0c43eec1d49177dc1ab4552a1da04e96fe
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 97 |
1 files changed, 48 insertions, 49 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index b7ea7491d6..b366582ade 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2328,57 +2328,47 @@ 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 *surroundingExceptionHandler = exceptionHandler(); + // We always need a finally body to clean up the exception handler // exceptions thrown in finally get catched by the surrounding catch block - V4IR::BasicBlock *finallyBody = _function->newBasicBlock(groupStartBlock(), exceptionHandler(), V4IR::Function::DontInsertBlock); + V4IR::BasicBlock *finallyBody = 0; + V4IR::BasicBlock *catchBody = 0; + V4IR::BasicBlock *catchExceptionHandler = 0; + V4IR::BasicBlock *end = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, V4IR::Function::DontInsertBlock); - // 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); + if (ast->finallyExpression) + finallyBody = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, V4IR::Function::DontInsertBlock); - int hasException = _block->newTemp(); - move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false)); + if (ast->catchExpression) { + // exception handler for the catch body + catchExceptionHandler = _function->newBasicBlock(groupStartBlock(), 0, V4IR::Function::DontInsertBlock); + pushExceptionHandler(catchExceptionHandler); + catchBody = _function->newBasicBlock(groupStartBlock(), catchExceptionHandler, V4IR::Function::DontInsertBlock); + popExceptionHandler(); + pushExceptionHandler(catchBody); + } else { + Q_ASSERT(finallyBody); + pushExceptionHandler(finallyBody); + } 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. - V4IR::ExprList *finishTryArgs = _function->New<V4IR::ExprList>(); - finishTryArgs->init(_block->TEMP(hasException)); - - ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression, finishTryArgs); + ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression); _scopeAndFinally = &tcf; _block = tryBody; statement(ast->statement); - _block->JUMP(finallyBody); + _block->JUMP(finallyBody ? finallyBody : end); - _function->insertBasicBlock(catchBody); - _block = catchBody; + popExceptionHandler(); if (ast->catchExpression) { - // check if an exception got thrown within catch. Go to finally - // and then rethrow - 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); + pushExceptionHandler(catchExceptionHandler); + _function->insertBasicBlock(catchBody); + _block = catchBody; - _block = b; - } - - move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, true)); - - if (ast->catchExpression) { ++_function->insideWithOrCatch; V4IR::ExprList *catchArgs = _function->New<V4IR::ExprList>(); catchArgs->init(_block->STRING(_function->newString(ast->catchExpression->name.toString()))); @@ -2391,28 +2381,37 @@ bool Codegen::visit(TryStatement *ast) } _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)); + _block->JUMP(finallyBody ? finallyBody : end); + popExceptionHandler(); + + _function->insertBasicBlock(catchExceptionHandler); + catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0)); + if (finallyBody || surroundingExceptionHandler) + catchExceptionHandler->JUMP(finallyBody ? finallyBody : surroundingExceptionHandler); + else + catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(V4IR::Name::builtin_rethrow, 0, 0), 0)); } - _block->JUMP(finallyBody); _scopeAndFinally = tcf.parent; - // exceptions thrown in finally get catched by the surrounding catch statement - popExceptionHandler(); + if (finallyBody) { + _function->insertBasicBlock(finallyBody); + _block = finallyBody; - _function->insertBasicBlock(finallyBody); + int hasException = _block->newTemp(); + move(_block->TEMP(hasException), _block->CALL(_block->NAME(V4IR::Name::builtin_unwind_exception, /*line*/0, /*column*/0), 0)); - _block = finallyBody; - if (ast->finallyExpression && ast->finallyExpression->statement) - statement(ast->finallyExpression->statement); + if (ast->finallyExpression && ast->finallyExpression->statement) + statement(ast->finallyExpression->statement); - V4IR::BasicBlock *rethrowBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - V4IR::BasicBlock *after = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - _block->CJUMP(_block->TEMP(hasException), rethrowBlock, after); - _block = rethrowBlock; - _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_rethrow, /*line*/0, /*column*/0), 0)); + V4IR::ExprList *arg = _function->New<V4IR::ExprList>(); + arg->expr = _block->TEMP(hasException); + _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), arg)); + _block->JUMP(end); + } - _block = after; + _function->insertBasicBlock(end); + _block = end; return false; } |