From 5f06c71bc1bf146977b6a189491f73ddf8792777 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 22 Oct 2012 00:18:31 +0200 Subject: [PATCH] Proper exception handling Implement exceptions using setjmp/longjmp. The advantage is that this removes all exception handling overhead from regular code, the only code that still has a (very small) overhead is the try{} catch() {} statement. Change-Id: I43d6a60dfc9dfd4b7a20d2e99ab0a9315b4d8a2f Reviewed-by: Simon Hausmann --- llvm_runtime.cpp | 5 ---- main.cpp | 18 +++++++----- qmljs_objects.h | 8 +++++ qmljs_runtime.cpp | 86 +++++++++++++++++++++++++++-------------------------- qmljs_runtime.h | 14 +++++---- qv4codegen.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++------- qv4codegen_p.h | 1 - qv4ir.cpp | 24 ++++++++++++++- qv4ir_p.h | 4 ++- qv4isel_llvm.cpp | 7 ----- qv4isel_masm.cpp | 43 ++++++++++----------------- qv4isel_masm_p.h | 6 +++- 12 files changed, 195 insertions(+), 109 deletions(-) diff --git a/llvm_runtime.cpp b/llvm_runtime.cpp index fbc534f..158cb66 100644 --- a/llvm_runtime.cpp +++ b/llvm_runtime.cpp @@ -457,11 +457,6 @@ void __qmljs_llvm_throw(Context *context, Value *value) __qmljs_throw(*value, context); } -void __qmljs_llvm_rethrow(Context *context, Value *result) -{ - *result = __qmljs_rethrow(context); -} - void __qmljs_llvm_get_this_object(Context *ctx, Value *result) { *result = __qmljs_get_thisObject(ctx); diff --git a/main.cpp b/main.cpp index d20b350..f5f51c3 100644 --- a/main.cpp +++ b/main.cpp @@ -44,6 +44,7 @@ #endif #include "qmljs_objects.h" +#include "qmljs_runtime.h" #include "qv4codegen_p.h" #include "qv4isel_masm_p.h" #include "qv4isel_moth_p.h" @@ -239,7 +240,6 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS return; } - ctx->hasUncaughtException = false; if (! ctx->activation.isObject()) ctx->activation = VM::Value::fromObject(new QQmlJS::VM::Object()); @@ -247,6 +247,15 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS ctx->activation.objectValue()->setProperty(ctx, *local, QQmlJS::VM::Value::undefinedValue()); } + void * buf = __qmljs_create_exception_handler(ctx); + if (setjmp(*(jmp_buf *)buf)) { + if (VM::ErrorObject *e = ctx->result.asErrorObject()) + std::cerr << "Uncaught exception: " << qPrintable(e->value.toString(ctx)->toQString()) << std::endl; + else + std::cerr << "Uncaught exception: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; + return; + } + if (useMoth) { Moth::VME vme; vme(ctx, code); @@ -254,12 +263,7 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS globalCode->code(ctx, globalCode->codeData); } - if (ctx->hasUncaughtException) { - if (VM::ErrorObject *e = ctx->result.asErrorObject()) - std::cerr << "Uncaught exception: " << qPrintable(e->value.toString(ctx)->toQString()) << std::endl; - else - std::cerr << "Uncaught exception: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; - } else if (! ctx->result.isUndefined()) { + if (! ctx->result.isUndefined()) { if (! qgetenv("SHOW_EXIT_VALUE").isNull()) std::cout << "exit value: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; } diff --git a/qmljs_objects.h b/qmljs_objects.h index a4c9082..a98b640 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -49,6 +49,7 @@ #include #include #include +#include namespace QQmlJS { @@ -459,6 +460,13 @@ struct ExecutionEngine String *id_arguments; String *id___proto__; + struct ExceptionHandler { + Context *context; + jmp_buf stackFrame; + }; + + QVector unwindStack; + ExecutionEngine(); Context *newContext(); diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index 8a1ffc2..f0c7326 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -284,7 +284,6 @@ void Context::init(ExecutionEngine *eng) vars = 0; varCount = 0; calledAsConstructor = false; - hasUncaughtException = false; } Value *Context::lookupPropertyDescriptor(String *name) @@ -302,7 +301,7 @@ Value *Context::lookupPropertyDescriptor(String *name) void Context::throwError(Value value) { result = value; - hasUncaughtException = true; + __qmljs_builtin_throw(value, this); } void Context::throwError(const QString &message) @@ -330,10 +329,11 @@ void Context::throwReferenceError(Value value) throwError(Value::fromObject(engine->newErrorObject(Value::fromString(this, msg)))); } -void Context::initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, unsigned argc) +void Context::initCallContext(Context *parent, const Value *object, FunctionObject *f, Value *args, unsigned argc) { - engine = e; - parent = f->scope; + engine = parent->engine; + this->parent = f->scope; + assert(this->parent == f->scope); result = Value::undefinedValue(); if (f->needsActivation) @@ -360,23 +360,22 @@ void Context::initCallContext(ExecutionEngine *e, const Value *object, FunctionO vars = f->varList; varCount = f->varCount; locals = varCount ? new Value[varCount] : 0; - hasUncaughtException = false; calledAsConstructor = false; if (varCount) std::fill(locals, locals + varCount, Value::undefinedValue()); } -void Context::leaveCallContext(FunctionObject *f) +void Context::leaveCallContext() { - if (! f->needsActivation) { + if (!activation.isNull()) { delete[] locals; locals = 0; } } -void Context::initConstructorContext(ExecutionEngine *e, Value *object, FunctionObject *f, Value *args, unsigned argc) +void Context::initConstructorContext(Context *parent, Value *object, FunctionObject *f, Value *args, unsigned argc) { - initCallContext(e, object, f, args, argc); + initCallContext(parent, object, f, args, argc); calledAsConstructor = true; } @@ -390,7 +389,7 @@ void Context::leaveConstructorContext(FunctionObject *f) if (! thisObject.isObject()) thisObject.objectValue()->prototype = engine->objectPrototype; - leaveCallContext(f); + leaveCallContext(); } extern "C" { @@ -1205,13 +1204,9 @@ Value __qmljs_call_property(Context *context, Value base, String *name, Value *a if (FunctionObject *f = func.asFunctionObject()) { Context k; Context *ctx = f->needsActivation ? context->engine->newContext() : &k; - ctx->initCallContext(context->engine, &thisObject, f, args, argc); + ctx->initCallContext(context, &thisObject, f, args, argc); f->call(ctx); - if (ctx->hasUncaughtException) { - context->hasUncaughtException = ctx->hasUncaughtException; // propagate the exception - context->result = ctx->result; - } - ctx->leaveCallContext(f); + ctx->leaveCallContext(); result = ctx->result; } else { context->throwTypeError(); @@ -1224,13 +1219,9 @@ Value __qmljs_call_function(Context *context, Value thisObject, FunctionObject * Context k; Context *ctx = f->needsActivation ? context->engine->newContext() : &k; const Value *that = thisObject.isUndefined() ? 0 : &thisObject; - ctx->initCallContext(context->engine, that, f, args, argc); + ctx->initCallContext(context, that, f, args, argc); f->call(ctx); - if (ctx->hasUncaughtException) { - context->hasUncaughtException = ctx->hasUncaughtException; // propagate the exception - context->result = ctx->result; - } - ctx->leaveCallContext(f); + ctx->leaveCallContext(); return ctx->result; } @@ -1259,12 +1250,8 @@ Value __qmljs_construct_value(Context *context, Value func, Value *args, int arg if (FunctionObject *f = func.asFunctionObject()) { Context k; Context *ctx = f->needsActivation ? context->engine->newContext() : &k; - ctx->initConstructorContext(context->engine, 0, f, args, argc); + ctx->initConstructorContext(context, 0, f, args, argc); f->construct(ctx); - if (ctx->hasUncaughtException) { - context->hasUncaughtException = ctx->hasUncaughtException; // propagate the exception - context->result = ctx->result; - } ctx->leaveConstructorContext(f); return ctx->result; } @@ -1282,13 +1269,9 @@ Value __qmljs_construct_property(Context *context, Value base, String *name, Val if (FunctionObject *f = func.asFunctionObject()) { Context k; Context *ctx = f->needsActivation ? context->engine->newContext() : &k; - ctx->initConstructorContext(context->engine, 0, f, args, argc); + ctx->initConstructorContext(context, 0, f, args, argc); ctx->calledAsConstructor = true; f->construct(ctx); - if (ctx->hasUncaughtException) { - context->hasUncaughtException = ctx->hasUncaughtException; // propagate the exception - context->result = ctx->result; - } ctx->leaveConstructorContext(f); return ctx->result; } @@ -1298,11 +1281,37 @@ Value __qmljs_construct_property(Context *context, Value base, String *name, Val void __qmljs_throw(Value value, Context *context) { - context->hasUncaughtException = true; - context->result = value; + assert(!context->engine->unwindStack.isEmpty()); + + ExecutionEngine::ExceptionHandler handler = context->engine->unwindStack.last(); + + // clean up call contexts + while (context != handler.context) { + context->leaveCallContext(); + context = context->parent; + } + + handler.context->result = value; + + longjmp(handler.stackFrame, 1); +} + +void *__qmljs_create_exception_handler(Context *context) +{ + context->engine->unwindStack.append(ExecutionEngine::ExceptionHandler()); + ExecutionEngine::ExceptionHandler *handler = &context->engine->unwindStack.last(); + handler->context = context; + return handler->stackFrame; +} + +void __qmljs_delete_exception_handler(Context *context) +{ + assert(!context->engine->unwindStack.isEmpty()); + + context->engine->unwindStack.pop_back(); } -Value __qmljs_rethrow(Context *context) +Value __qmljs_get_exception(Context *context) { return context->result; } @@ -1317,11 +1326,6 @@ void __qmljs_builtin_throw(Value val, Context *context) __qmljs_throw(val, context); } -Value __qmljs_builtin_rethrow(Context *context) -{ - return context->result; -} - } // extern "C" diff --git a/qmljs_runtime.h b/qmljs_runtime.h index 012c556..e424b08 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -105,7 +105,7 @@ Value __qmljs_construct_value(Context *context, Value func, Value *args, int arg Value __qmljs_builtin_typeof(Value val, Context *context); void __qmljs_builtin_throw(Value val, Context *context); -Value __qmljs_builtin_rethrow(Context *context); + // constructors Value __qmljs_init_closure(IR::Function *clos, Context *ctx); @@ -182,7 +182,10 @@ Value __qmljs_delete_value(Context *ctx, Value value); Value __qmljs_typeof(Value value, Context *ctx); void __qmljs_throw(Value value, Context *context); -Value __qmljs_rethrow(Context *context); +// actually returns a jmp_buf * +void *__qmljs_create_exception_handler(Context *context); +void __qmljs_delete_exception_handler(Context *context); +Value __qmljs_get_exception(Context *context); // binary operators Value __qmljs_instanceof(Value left, Value right, Context *ctx); @@ -570,7 +573,6 @@ struct Context { String **vars; unsigned int varCount; int calledAsConstructor; - int hasUncaughtException; Value *lookupPropertyDescriptor(String *name); @@ -600,10 +602,10 @@ struct Context { void throwUnimplemented(const QString &message); #endif - void initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, unsigned argc); - void leaveCallContext(FunctionObject *f); + void initCallContext(Context *parent, const Value *object, FunctionObject *f, Value *args, unsigned argc); + void leaveCallContext(); - void initConstructorContext(ExecutionEngine *e, Value *object, FunctionObject *f, Value *args, unsigned argc); + void initConstructorContext(Context *parent, Value *object, FunctionObject *f, Value *args, unsigned argc); void leaveConstructorContext(FunctionObject *f); }; diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 5dd0041..a037739 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -294,7 +294,6 @@ Codegen::Codegen() , _block(0) , _exitBlock(0) , _throwBlock(0) - , _handlersBlock(0) , _returnAddress(0) , _mode(GlobalCode) , _env(0) @@ -1069,8 +1068,9 @@ bool Codegen::visit(FunctionExpression *ast) bool Codegen::visit(IdentifierExpression *ast) { + int index = _env->findMember(ast->name.toString()); + if (! _function->hasDirectEval && _env->parent) { - int index = _env->findMember(ast->name.toString()); if (index != -1) { _expr.code = _block->TEMP(index); return false; @@ -1082,6 +1082,12 @@ bool Codegen::visit(IdentifierExpression *ast) } } + if (index >= _env->vars.size()) { + // named local variable, e.g. in a catch statement + _expr.code = _block->TEMP(index); + return false; + } + _expr.code = _block->NAME(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn); @@ -1484,7 +1490,6 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, qSwap(_block, entryBlock); qSwap(_exitBlock, exitBlock); qSwap(_throwBlock, throwBlock); - qSwap(_handlersBlock, handlersBlock); qSwap(_returnAddress, returnAddress); for (FormalParameterList *it = formals; it; it = it->next) { @@ -1512,17 +1517,13 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, _block->JUMP(_exitBlock); - _throwBlock->JUMP(_function->handlersBlock); - - _handlersBlock->MOVE(_handlersBlock->TEMP(_returnAddress), - _handlersBlock->CALL(_handlersBlock->NAME(IR::Name::builtin_rethrow, 0, 0), 0)); - _handlersBlock->JUMP(_exitBlock); + // ### should not be required + _throwBlock->JUMP(_exitBlock); qSwap(_function, function); qSwap(_block, entryBlock); qSwap(_exitBlock, exitBlock); qSwap(_throwBlock, throwBlock); - qSwap(_handlersBlock, handlersBlock); qSwap(_returnAddress, returnAddress); leaveEnvironment(); @@ -1858,9 +1859,74 @@ bool Codegen::visit(ThrowStatement *ast) return false; } -bool Codegen::visit(TryStatement *) +bool Codegen::visit(TryStatement *ast) { - assert(!"not implemented"); + IR::BasicBlock *tryBody = _function->newBasicBlock(); + IR::BasicBlock *catchBody = ast->catchExpression ? _function->newBasicBlock() : 0; + IR::BasicBlock *finallyBody = ast->finallyExpression ? _function->newBasicBlock() : 0; + IR::BasicBlock *after = _function->newBasicBlock(); + assert(catchBody || finallyBody); + + int inCatch = 0; + if (catchBody && finallyBody) { + inCatch = _block->newTemp(); + move(_block->TEMP(inCatch), _block->CONST(IR::BoolType, false)); + } + + int hasException = _block->newTemp(); + move(_block->TEMP(hasException), _block->CALL(_block->NAME(IR::Name::builtin_create_exception_handler, 0, 0), 0)); + + _block->CJUMP(_block->TEMP(hasException), catchBody ? catchBody : finallyBody, tryBody); + + _block = tryBody; + statement(ast->statement); + _block->JUMP(finallyBody ? finallyBody : after); + + // regular flow does not go into the catch statement + if (catchBody) { + _block = catchBody; + + if (finallyBody) { + if (inCatch != 0) { + // an exception got thrown within catch. Go to finally + // and then rethrow + IR::BasicBlock *b = _function->newBasicBlock(); + _block->CJUMP(_block->TEMP(inCatch), finallyBody, b); + _block = b; + } + // if we have finally we need to clear the exception here, so we don't rethrow + move(_block->TEMP(inCatch), _block->CONST(IR::BoolType, true)); + move(_block->TEMP(hasException), _block->CONST(IR::BoolType, false)); + } else { + // otherwise remove the exception handler, so that throw inside catch will + // give the correct result + _block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_delete_exception_handler, 0, 0), 0)); + } + + const int exception = _block->newTemp(); + move(_block->TEMP(exception), _block->CALL(_block->NAME(IR::Name::builtin_get_exception, 0, 0), 0)); + + // the variable ued in the catch statement is local and hides any global + // variable with the same name. + int hiddenIndex = _env->findMember(ast->catchExpression->name.toString()); + _env->members.insert(ast->catchExpression->name.toString(), exception); + + statement(ast->catchExpression->statement); + + // reset the variable name to the one from the outer scope + _env->members.insert(ast->catchExpression->name.toString(), hiddenIndex); + _block->JUMP(finallyBody ? finallyBody : after); + } + + if (finallyBody) { + _block = finallyBody; + _block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_delete_exception_handler, 0, 0), 0)); + statement(ast->finallyExpression->statement); + _block->CJUMP(_block->TEMP(hasException), _throwBlock, after); + } + + _block = after; + return false; } diff --git a/qv4codegen_p.h b/qv4codegen_p.h index 8e9f505..95fedb5 100644 --- a/qv4codegen_p.h +++ b/qv4codegen_p.h @@ -312,7 +312,6 @@ private: IR::BasicBlock *_block; IR::BasicBlock *_exitBlock; IR::BasicBlock *_throwBlock; - IR::BasicBlock *_handlersBlock; unsigned _returnAddress; Mode _mode; Environment *_env; diff --git a/qv4ir.cpp b/qv4ir.cpp index f3db7e9..40c85c8 100644 --- a/qv4ir.cpp +++ b/qv4ir.cpp @@ -213,12 +213,34 @@ void Name::init(Builtin builtin, quint32 line, quint32 column) this->column = column; } +static const char *builtin_to_string(Name::Builtin b) +{ + switch (b) { + case Name::builtin_invalid: + return "builtin_invalid"; + case Name::builtin_typeof: + return "builtin_typeof"; + case Name::builtin_delete: + return "builtin_delete"; + case Name::builtin_throw: + return "builtin_throw"; + case Name::builtin_create_exception_handler: + return "builtin_create_exception_handler"; + case Name::builtin_delete_exception_handler: + return "builtin_delete_exception_handler"; + case Name::builtin_get_exception: + return "builtin_get_exception"; + } + return "builtin_(###FIXME)"; +}; + + void Name::dump(QTextStream &out) { if (id) out << *id; else - out << "__qmljs_builtin_%" << (int) builtin; + out << builtin_to_string(builtin); } void Temp::dump(QTextStream &out) diff --git a/qv4ir_p.h b/qv4ir_p.h index efae2e4..7853cc2 100644 --- a/qv4ir_p.h +++ b/qv4ir_p.h @@ -272,7 +272,9 @@ struct Name: Expr { builtin_typeof, builtin_delete, builtin_throw, - builtin_rethrow + builtin_create_exception_handler, + builtin_delete_exception_handler, + builtin_get_exception }; const QString *id; diff --git a/qv4isel_llvm.cpp b/qv4isel_llvm.cpp index eae3bc4..040111f 100644 --- a/qv4isel_llvm.cpp +++ b/qv4isel_llvm.cpp @@ -935,13 +935,6 @@ void LLVMInstructionSelection::genCallName(IR::Call *e, llvm::Value *result) _llvmValue = llvm::UndefValue::get(_valueTy); return; - case IR::Name::builtin_rethrow: - CreateCall2(_llvmModule->getFunction("__qmljs_llvm_rethrow"), - _llvmFunction->arg_begin(), result); - _llvmValue = CreateLoad(result); - return; - } - Q_UNREACHABLE(); } else { llvm::Value *name = getIdentifier(*base->id); diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp index e5c78ab..5254b6d 100644 --- a/qv4isel_masm.cpp +++ b/qv4isel_masm.cpp @@ -139,6 +139,11 @@ void InstructionSelection::operator()(IR::Function *function) functions[ctl.externalFunction.value()] = ctl.functionName; } + foreach (CatchBlockToLink cbl, _catchHandlers) { + Label target = _addrs.value(cbl.catchBlock); + linkBuffer.patch(cbl.ptr, linkBuffer.locationOf(target)); + } + #if OS(LINUX) char* disasmOutput = 0; size_t disasmLength = 0; @@ -204,7 +209,6 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu IR::Temp *arg = call->args->expr->asTemp(); assert(arg != 0); generateFunctionCall(result, __qmljs_builtin_typeof, arg, ContextRegister); - checkExceptions(); } break; case IR::Name::builtin_delete: @@ -214,13 +218,18 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu IR::Temp *arg = call->args->expr->asTemp(); assert(arg != 0); generateFunctionCall(Void, __qmljs_builtin_throw, arg, ContextRegister); - checkExceptions(); } break; - case IR::Name::builtin_rethrow: - // don't use callRuntimeMethod, as we need to return to avoid checking the exceptions - generateFunctionCall(result, __qmljs_builtin_rethrow, ContextRegister); - return; + case IR::Name::builtin_create_exception_handler: + generateFunctionCall(ReturnValueRegister, __qmljs_create_exception_handler, ContextRegister); + generateFunctionCall(result, setjmp, ReturnValueRegister); + break; + case IR::Name::builtin_delete_exception_handler: + generateFunctionCall(Void, __qmljs_delete_exception_handler, ContextRegister); + break; + case IR::Name::builtin_get_exception: + generateFunctionCall(result, __qmljs_get_exception, ContextRegister); + break; } } } @@ -234,7 +243,6 @@ void InstructionSelection::callValue(IR::Call *call, IR::Temp *result) int argc = prepareVariableArguments(call->args); IR::Temp* thisObject = 0; generateFunctionCall(result, __qmljs_call_value, ContextRegister, thisObject, baseTemp, baseAddressForCallArguments(), TrustedImm32(argc)); - checkExceptions(); } void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result) @@ -245,7 +253,6 @@ void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result) int argc = prepareVariableArguments(call->args); generateFunctionCall(result, __qmljs_call_property, ContextRegister, member->base->asTemp(), identifier(*member->name), baseAddressForCallArguments(), TrustedImm32(argc)); - checkExceptions(); } void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result) @@ -264,7 +271,6 @@ void InstructionSelection::constructProperty(IR::New *call, IR::Temp *result) int argc = prepareVariableArguments(call->args); generateFunctionCall(result, __qmljs_construct_property, ContextRegister, member->base->asTemp(), identifier(*member->name), baseAddressForCallArguments(), TrustedImm32(argc)); - checkExceptions(); } void InstructionSelection::constructValue(IR::New *call, IR::Temp *result) @@ -274,14 +280,6 @@ void InstructionSelection::constructValue(IR::New *call, IR::Temp *result) int argc = prepareVariableArguments(call->args); generateFunctionCall(result, __qmljs_construct_value, ContextRegister, baseTemp, baseAddressForCallArguments(), TrustedImm32(argc)); - checkExceptions(); -} - -void InstructionSelection::checkExceptions() -{ - Address addr(ContextRegister, offsetof(Context, hasUncaughtException)); - Jump jmp = branch8(NotEqual, addr, TrustedImm32(0)); - _patches[_function->handlersBlock].append(jmp); } void InstructionSelection::visitExp(IR::Exp *s) @@ -325,7 +323,6 @@ void InstructionSelection::visitMove(IR::Move *s) if (IR::Temp *t = s->source->asTemp()) { generateFunctionCall(Void, __qmljs_set_activation_property, ContextRegister, propertyName, t); - checkExceptions(); return; } else { Q_UNREACHABLE(); @@ -337,7 +334,6 @@ void InstructionSelection::visitMove(IR::Move *s) } else { String *propertyName = identifier(*n->id); generateFunctionCall(t, __qmljs_get_activation_property, ContextRegister, propertyName); - checkExceptions(); } return; } else if (IR::Const *c = s->source->asConst()) { @@ -399,14 +395,12 @@ void InstructionSelection::visitMove(IR::Move *s) //__qmljs_get_property(ctx, result, object, name); if (IR::Temp *base = m->base->asTemp()) { generateFunctionCall(t, __qmljs_get_property, ContextRegister, base, identifier(*m->name)); - checkExceptions(); return; } assert(!"wip"); return; } else if (IR::Subscript *ss = s->source->asSubscript()) { generateFunctionCall(t, __qmljs_get_element, ContextRegister, ss->base->asTemp(), ss->index->asTemp()); - checkExceptions(); return; } else if (IR::Unop *u = s->source->asUnop()) { if (IR::Temp *e = u->expr->asTemp()) { @@ -491,7 +485,6 @@ void InstructionSelection::visitMove(IR::Move *s) if (IR::Temp *base = m->base->asTemp()) { if (IR::Temp *t = s->source->asTemp()) { generateFunctionCall(Void, __qmljs_set_property, ContextRegister, base, identifier(*m->name), t); - checkExceptions(); return; } else { Q_UNREACHABLE(); @@ -500,7 +493,6 @@ void InstructionSelection::visitMove(IR::Move *s) } else if (IR::Subscript *ss = s->target->asSubscript()) { if (IR::Temp *t2 = s->source->asTemp()) { generateFunctionCall(Void, __qmljs_set_element, ContextRegister, ss->base->asTemp(), ss->index->asTemp(), t2); - checkExceptions(); return; } else { Q_UNIMPLEMENTED(); @@ -554,7 +546,6 @@ void InstructionSelection::visitMove(IR::Move *s) } if (op) { generateFunctionCallImp(Void, opName, op, t, identifier(*n->id), ContextRegister); - checkExceptions(); } return; } @@ -583,7 +574,6 @@ void InstructionSelection::visitMove(IR::Move *s) IR::Temp* base = ss->base->asTemp(); IR::Temp* index = ss->index->asTemp(); generateFunctionCallImp(Void, opName, op, base, index, t, ContextRegister); - checkExceptions(); } return; } @@ -612,7 +602,6 @@ void InstructionSelection::visitMove(IR::Move *s) IR::Temp* base = m->base->asTemp(); String* member = identifier(*m->name); generateFunctionCallImp(Void, opName, op, t, base, member, ContextRegister); - checkExceptions(); } return; } @@ -730,14 +719,12 @@ void InstructionSelection::callRuntimeMethodImp(IR::Temp *result, const char* na int argc = prepareVariableArguments(args); generateFunctionCallImp(result, name, method, ContextRegister, identifier(*baseName->id), baseAddressForCallArguments(), TrustedImm32(argc)); - checkExceptions(); } void InstructionSelection::callRuntimeMethodImp(IR::Temp *result, const char* name, BuiltinMethod method, IR::ExprList *args) { int argc = prepareVariableArguments(args); generateFunctionCallImp(result, name, method, ContextRegister, baseAddressForCallArguments(), TrustedImm32(argc)); - checkExceptions(); } template diff --git a/qv4isel_masm_p.h b/qv4isel_masm_p.h index 8565ad2..49f712f 100644 --- a/qv4isel_masm_p.h +++ b/qv4isel_masm_p.h @@ -216,7 +216,6 @@ protected: void constructProperty(IR::New *ctor, IR::Temp *result); void callValue(IR::Call *call, IR::Temp *result); void constructValue(IR::New *call, IR::Temp *result); - void checkExceptions(); virtual void visitExp(IR::Exp *); virtual void visitEnter(IR::Enter *); @@ -523,6 +522,10 @@ private: FunctionPtr externalFunction; const char* functionName; }; + struct CatchBlockToLink { + DataLabelPtr ptr; + IR::BasicBlock *catchBlock; + }; void storeValue(VM::Value value, Address destination) { @@ -544,6 +547,7 @@ private: uchar *_codePtr; QHash > _patches; QHash _addrs; + QList _catchHandlers; QList _callsToLink; }; -- 2.7.4