diff options
author | Simon Hausmann <[email protected]> | 2013-10-16 14:03:48 +0200 |
---|---|---|
committer | The Qt Project <[email protected]> | 2013-10-16 16:03:57 +0200 |
commit | 12c3579136b6925e75cca4f3a9b8bae2e4665db7 (patch) | |
tree | 17f82a28141856af0954ffe4eff20ebc679a3265 /src | |
parent | c1c526aafb2fc70ac6155eb775b3784f1e2e6504 (diff) |
Speed up exception propagation
Avoid catch (...) with re-throw as it turns that this is very slow because it
throws a new exception and the unwinder starts from scratch. Instead use stack
allocated objects and cleaning destructors to restore state before continuing
with the propagation of exceptions.
Change-Id: I6d95026bcd60b58cb6258a9dae28623a46739532
Reviewed-by: Lars Knoll <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/localstorage/plugin.cpp | 55 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 17 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_cxxabi.cpp | 16 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 19 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 25 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 72 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4globalobject.cpp | 46 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 43 |
10 files changed, 136 insertions, 163 deletions
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 84bcb756e8..9a0528a28f 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -322,6 +322,35 @@ static ReturnedValue qmlsqldatabase_executeSql(SimpleCallContext *ctx) return result.asReturnedValue(); } +struct TransactionRollback { + QSqlDatabase *db; + bool *inTransactionFlag; + + TransactionRollback(QSqlDatabase *database, bool *transactionFlag) + : db(database) + , inTransactionFlag(transactionFlag) + { + if (inTransactionFlag) + *inTransactionFlag = true; + } + + ~TransactionRollback() + { + if (inTransactionFlag) + *inTransactionFlag = false; + if (db) + db->rollback(); + } + + void clear() { + db = 0; + if (inTransactionFlag) + *inTransactionFlag = false; + inTransactionFlag = 0; + } +}; + + static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx) { if (ctx->callData->argc < 2) @@ -349,7 +378,6 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx) w->type = QQmlSqlDatabaseWrapper::Query; w->database = db; w->version = r->version; - w->inTransaction = true; bool ok = true; if (!!callback) { @@ -359,12 +387,10 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx) ScopedCallData callData(scope, 1); callData->thisObject = engine->global(); callData->args[0] = w; - try { - callback->call(callData); - } catch (...) { - db.rollback(); - ctx->rethrowException(); - } + + TransactionRollback rollbackOnException(&db, &w->inTransaction); + callback->call(callData); + rollbackOnException.clear(); if (!db.commit()) { db.rollback(); V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed")); @@ -373,8 +399,6 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx) } } - w->inTransaction = false; - if (ok) { w->version = to_version; #ifndef QT_NO_SETTINGS @@ -408,22 +432,15 @@ static ReturnedValue qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, b w->database = db; w->version = r->version; w->readonly = readOnly; - w->inTransaction = true; db.transaction(); if (callback) { ScopedCallData callData(scope, 1); callData->thisObject = engine->global(); callData->args[0] = w; - try { - callback->call(callData); - } catch (...) { - w->inTransaction = false; - db.rollback(); - ctx->rethrowException(); - } - - w->inTransaction = false; + TransactionRollback rollbackOnException(&db, &w->inTransaction); + callback->call(callData); + rollbackOnException.clear(); if (!db.commit()) db.rollback(); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index be6e1649cf..f3d2ab66ed 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -649,11 +649,6 @@ ReturnedValue ExecutionContext::catchException(StackTrace *trace) return engine->catchException(this, trace); } -void ExecutionContext::rethrowException() -{ - engine->rethrowException(this); -} - void ExecutionContext::throwReferenceError(const ValueRef value) { Scope scope(this); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index d44c7d25f9..e5b0c431ca 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -147,7 +147,6 @@ struct Q_QML_EXPORT ExecutionContext // Can only be called from within catch(...), rethrows if no JS exception. ReturnedValue catchException(StackTrace *trace = 0); - void Q_NORETURN rethrowException(); void mark(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 23faa43ac7..d312db272c 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -826,19 +826,9 @@ void ExecutionEngine::throwException(const ValueRef value) throwInternal(); } -void ExecutionEngine::rethrowException(ExecutionContext *intermediateCatchingContext) -{ - if (hasException) { - while (current != intermediateCatchingContext) - popContext(); - } - rethrowInternal(); -} - ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace) { - if (!hasException) - rethrowInternal(); + Q_ASSERT(hasException); while (current != catchingContext) popContext(); if (trace) @@ -858,11 +848,6 @@ void ExecutionEngine::throwInternal() { throw DummyException(); } - -void ExecutionEngine::rethrowInternal() -{ - throw; -} #endif QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_cxxabi.cpp b/src/qml/jsruntime/qv4engine_cxxabi.cpp index dfe1db8fe3..f29af5a284 100644 --- a/src/qml/jsruntime/qv4engine_cxxabi.cpp +++ b/src/qml/jsruntime/qv4engine_cxxabi.cpp @@ -118,22 +118,6 @@ void ExecutionEngine::throwInternal() std::terminate(); } -void ExecutionEngine::rethrowInternal() -{ - cxa_eh_globals *globals = __cxa_get_globals(); - cxa_exception *exception = globals->caughtExceptions; - - // Make sure we only re-throw our foreign exceptions. For general re-throw - // we'd need different code. -#ifndef __ARM_EABI_UNWINDER__ - Q_ASSERT(exception->unwindHeader.exception_class == 0x514d4c4a53563400); // QMLJSV40 -#endif - - globals->caughtExceptions = 0; - _Unwind_RaiseException(&exception->unwindHeader); - std::terminate(); -} - QT_END_NAMESPACE /* diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 5da556452e..e49b6a4ebf 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -326,11 +326,9 @@ struct Q_QML_EXPORT ExecutionEngine StackTrace exceptionStackTrace; void Q_NORETURN throwException(const ValueRef value); - void Q_NORETURN rethrowException(ExecutionContext *intermediateCatchingContext); ReturnedValue catchException(ExecutionContext *catchingContext, StackTrace *trace); void Q_NORETURN throwInternal(); - void Q_NORETURN rethrowInternal(); // ---- @@ -351,6 +349,23 @@ inline ExecutionContext *ExecutionEngine::popContext() return current; } +struct ExecutionContextSaver +{ + ExecutionEngine *engine; + ExecutionContext *savedContext; + + ExecutionContextSaver(ExecutionContext *context) + : engine(context->engine) + , savedContext(context) + { + } + ~ExecutionContextSaver() + { + while (engine->current != savedContext) + engine->popContext(); + } +}; + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 34ab5df73a..35c98897a0 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -86,13 +86,24 @@ struct Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; inline ReturnedValue code(ExecutionContext *ctx, const uchar *data) { - SafeValue *stack = ctx->engine->jsStackTop; - try { - return codePtr(ctx, data); - } catch (...) { - ctx->engine->jsStackTop = stack; - ctx->rethrowException(); - } + + struct StackSaver { + ExecutionEngine *engine; + SafeValue *stack; + + StackSaver(ExecutionEngine *engine) + : engine(engine) + , stack(engine->jsStackTop) + {} + + ~StackSaver() + { + engine->jsStackTop = stack; + } + }; + + StackSaver(ctx->engine); + return codePtr(ctx, data); } ReturnedValue (*codePtr)(ExecutionContext *, const uchar *); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 8faf2a74b6..55baef06db 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -443,16 +443,8 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) callData->thisObject = obj.asReturnedValue(); ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData); - ScopedValue result(scope); - SAVE_JS_STACK(f->scope); - try { - result = f->function->code(ctx, f->function->codeData); - } catch (...) { - context->rethrowException(); - } - CHECK_JS_STACK(f->scope); - ctx->engine->popContext(); - + ExecutionContextSaver ctxSaver(context); + ScopedValue result(scope, f->function->code(ctx, f->function->codeData)); if (result->isObject()) return result.asReturnedValue(); return obj.asReturnedValue(); @@ -474,16 +466,8 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) } } - ScopedValue result(scope); - SAVE_JS_STACK(f->scope); - try { - result = f->function->code(ctx, f->function->codeData); - } catch (...) { - context->rethrowException(); - } - CHECK_JS_STACK(f->scope); - ctx->engine->popContext(); - return result.asReturnedValue(); + ExecutionContextSaver ctxSaver(context); + return f->function->code(ctx, f->function->codeData); } DEFINE_MANAGED_VTABLE(SimpleScriptFunction); @@ -540,16 +524,12 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) callData->thisObject = obj; ExecutionContext *ctx = context->newCallContext(stackSpace, scope.alloc(f->varCount), f.getPointer(), callData); - try { - Scoped<Object> result(scope, f->function->code(ctx, f->function->codeData)); - ctx->engine->popContext(); + ExecutionContextSaver ctxSaver(context); + Scoped<Object> result(scope, f->function->code(ctx, f->function->codeData)); - if (!result) - return obj.asReturnedValue(); - return result.asReturnedValue(); - } catch (...) { - context->rethrowException(); - } + if (!result) + return obj.asReturnedValue(); + return result.asReturnedValue(); } ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) @@ -570,16 +550,8 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) } } - ScopedValue result(scope); - SAVE_JS_STACK(f->scope); - try { - result = f->function->code(ctx, f->function->codeData); - } catch (...) { - context->rethrowException(); - } - CHECK_JS_STACK(f->scope); - ctx->engine->popContext(); - return result.asReturnedValue(); + ExecutionContextSaver ctxSaver(context); + return f->function->code(ctx, f->function->codeData); } @@ -613,15 +585,8 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) ctx.callData = callData; v4->pushContext(&ctx); - ScopedValue result(scope); - try { - result = f->code(&ctx); - } catch (...) { - context->rethrowException(); - } - - context->engine->popContext(); - return result.asReturnedValue(); + ExecutionContextSaver ctxSaver(context); + return f->code(&ctx); } ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) @@ -637,15 +602,8 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) ctx.callData = callData; v4->pushContext(&ctx); - ScopedValue result(scope); - try { - result = f->code(&ctx, f->index); - } catch (...) { - context->rethrowException(); - } - - context->engine->popContext(); - return result.asReturnedValue(); + ExecutionContextSaver ctxSaver(context); + return f->code(&ctx, f->index); } DEFINE_MANAGED_VTABLE(IndexedBuiltinFunction); diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 3b1e0b1bae..4dcdb08415 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -355,6 +355,27 @@ EvalFunction::EvalFunction(ExecutionContext *scope) ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) { + struct ContextStateSaver { + ExecutionContext *savedContext; + bool strictMode; + ExecutionContext::EvalCode *evalCode; + CompiledData::CompilationUnit *compilationUnit; + + ContextStateSaver(ExecutionContext *context) + : savedContext(context) + , strictMode(context->strictMode) + , evalCode(context->currentEvalCode) + , compilationUnit(context->compilationUnit) + {} + + ~ContextStateSaver() + { + savedContext->strictMode = strictMode; + savedContext->currentEvalCode = evalCode; + savedContext->compilationUnit = compilationUnit; + } + }; + if (callData->argc < 1) return Encode::undefined(); @@ -395,36 +416,19 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) return e->call(callData); } + ExecutionContextSaver ctxSaver(parentContext); + ContextStateSaver stateSaver(ctx); + ExecutionContext::EvalCode evalCode; evalCode.function = function; evalCode.next = ctx->currentEvalCode; ctx->currentEvalCode = &evalCode; // set the correct strict mode flag on the context - bool cstrict = ctx->strictMode; ctx->strictMode = strictMode; - - CompiledData::CompilationUnit * const oldCompilationUnit = ctx->compilationUnit; ctx->compilationUnit = function->compilationUnit; - ScopedValue result(scope); - try { - result = function->code(ctx, function->codeData); - } catch (...) { - ctx->strictMode = cstrict; - ctx->currentEvalCode = evalCode.next; - ctx->compilationUnit = oldCompilationUnit; - ctx->rethrowException(); - } - - ctx->strictMode = cstrict; - ctx->currentEvalCode = evalCode.next; - ctx->compilationUnit = oldCompilationUnit; - - while (engine->current != parentContext) - engine->popContext(); - - return result.asReturnedValue(); + return function->code(ctx, function->codeData); } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 885ea8ea76..d30132140b 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -227,6 +227,27 @@ void Script::parse() ReturnedValue Script::run() { + struct ContextStateSaver { + ExecutionContext *savedContext; + bool strictMode; + Lookup *lookups; + CompiledData::CompilationUnit *compilationUnit; + + ContextStateSaver(ExecutionContext *context) + : savedContext(context) + , strictMode(context->strictMode) + , lookups(context->lookups) + , compilationUnit(context->compilationUnit) + {} + + ~ContextStateSaver() + { + savedContext->strictMode = strictMode; + savedContext->lookups = lookups; + savedContext->compilationUnit = compilationUnit; + } + }; + if (!parsed) parse(); if (!vmFunction) @@ -238,29 +259,13 @@ ReturnedValue Script::run() if (qml.isUndefined()) { TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction); - bool strict = scope->strictMode; - Lookup *oldLookups = scope->lookups; - CompiledData::CompilationUnit * const oldCompilationUnit = scope->compilationUnit; - + ExecutionContextSaver ctxSaver(scope); + ContextStateSaver stateSaver(scope); scope->strictMode = vmFunction->isStrict(); scope->lookups = vmFunction->compilationUnit->runtimeLookups; scope->compilationUnit = vmFunction->compilationUnit; - QV4::ScopedValue result(valueScope); - try { - result = vmFunction->code(scope, vmFunction->codeData); - } catch (...) { - scope->strictMode = strict; - scope->lookups = oldLookups; - scope->compilationUnit = oldCompilationUnit; - scope->rethrowException(); - } - - scope->lookups = oldLookups; - scope->compilationUnit = oldCompilationUnit; - - return result.asReturnedValue(); - + return vmFunction->code(scope, vmFunction->codeData); } else { ScopedObject qmlObj(valueScope, qml.value()); FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj); |