Instead the JS exception value is now part of the C++ Exception object.
This also allows getting rid of some run-time functions.
Change-Id: I43ff773cacd5e925ba96601f3633ccf3b62273be
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
__qmljs_throw(context, *value);
}
-void __qmljs_llvm_create_exception_handler(ExecutionContext *context, Value *result)
-{
- // ### FIXME.
- __qmljs_create_exception_handler(context);
- *result = Value::undefinedValue();
-}
-
void __qmljs_llvm_delete_exception_handler(ExecutionContext *context)
{
// ### FIXME.
}
-void __qmljs_llvm_get_exception(ExecutionContext *context, Value *result)
-{
- __qmljs_get_exception(context, result);
-}
-
void __qmljs_llvm_foreach_iterator_object(ExecutionContext *context, Value *result, Value *in)
{
__qmljs_foreach_iterator_object(context, result, *in);
MOTH_END_INSTR(CallBuiltinThrow)
MOTH_BEGIN_INSTR(EnterTry)
- __qmljs_create_exception_handler(context);
+ VALUE(instr.exceptionVar) = VM::Value::undefinedValue();
try {
const uchar *tryCode = ((uchar *)&instr.tryOffset) + instr.tryOffset;
run(context, tryCode, stack, stackSize);
code = tryCode;
} catch (VM::Exception &ex) {
ex.accept(context);
- __qmljs_get_exception(context, VALUEPTR(instr.exceptionVar));
+ VALUE(instr.exceptionVar) = ex.value();
try {
- VM::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(instr.exceptionVarName, context);
+ VM::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(instr.exceptionVarName, ex.value(), context);
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
run(catchContext, catchCode, stack, stackSize);
code = catchCode;
context = __qmljs_builtin_pop_scope(catchContext);
} catch (VM::Exception &ex) {
ex.accept(context);
- __qmljs_get_exception(context, VALUEPTR(instr.exceptionVar));
+ VALUE(instr.exceptionVar) = ex.value();
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
run(context, catchCode, stack, stackSize);
code = catchCode;
, debugger(0)
, globalObject(Value::nullValue())
, globalCode(0)
- , exception(Value::nullValue())
, externalResourceComparison(0)
{
MemoryManager::GCBlocker gcBlocker(memoryManager);
if (globalCode)
globalCode->mark();
- exception.mark();
-
for (int i = 0; i < argumentsAccessors.size(); ++i) {
const PropertyDescriptor &pd = argumentsAccessors.at(i);
pd.get->mark();
String *id_set;
String *id_eval;
- Value exception;
-
QVector<Function *> functions;
ExternalResourceComparison externalResourceComparison;
return withCtx;
}
-ExecutionContext *ExecutionContext::createCatchScope(String *exceptionVarName)
+ExecutionContext *ExecutionContext::createCatchScope(String *exceptionVarName, const Value &exceptionValue)
{
ExecutionContext *catchCtx = engine->newContext();
- catchCtx->initForCatch(this, exceptionVarName);
+ catchCtx->initForCatch(this, exceptionVarName, exceptionValue);
engine->current = catchCtx;
return catchCtx;
}
strictMode = false;
activation = 0;
withObject = 0;
-
- eng->exception = Value::undefinedValue();
}
void ExecutionContext::init(ExecutionContext *p, Object *with)
withObject = with;
}
-void ExecutionContext::initForCatch(ExecutionContext *p, String *exceptionVarName)
+void ExecutionContext::initForCatch(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue)
{
engine = p->engine;
parent = p;
argumentCount = 0;
locals = 0;
this->exceptionVarName = exceptionVarName;
- exceptionValue = engine->exception;
+ this->exceptionValue = exceptionValue;
strictMode = p->strictMode;
activation = 0;
withObject = 0;
void init(ExecutionEngine *e);
void init(ExecutionContext *p, Object *with);
- void initForCatch(ExecutionContext *p, String *exceptionVarName);
+ void initForCatch(ExecutionContext *p, String *exceptionVarName, const QQmlJS::VM::Value &exceptionValue);
void destroy();
bool hasBinding(String *name) const;
bool deleteBinding(ExecutionContext *ctx, String *name);
ExecutionContext *createWithScope(Object *with);
- ExecutionContext *createCatchScope(String* exceptionVarName);
+ ExecutionContext *createCatchScope(String* exceptionVarName, const QQmlJS::VM::Value &exceptionValue);
ExecutionContext *popScope();
void initCallContext(ExecutionContext *parent);
return str;
}
-Exception::Exception(ExecutionContext *throwingContext)
+Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue)
{
this->throwingContext = throwingContext;
+ this->exception = exceptionValue;
accepted = false;
}
if (context->engine->debugger)
context->engine->debugger->aboutToThrow(value);
- context->engine->exception = value;
-
- throw Exception(context);
-}
-
-Q_V4_EXPORT void __qmljs_create_exception_handler(ExecutionContext *context)
-{
- context->engine->exception = Value::undefinedValue();
-}
-
-void __qmljs_get_exception(ExecutionContext *context, Value *result)
-{
- *result = context->engine->exception;
+ throw Exception(context, value);
}
void __qmljs_builtin_typeof(ExecutionContext *ctx, Value *result, const Value &value)
return ctx->createWithScope(obj);
}
-ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, ExecutionContext *ctx)
+ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, const Value &exceptionValue, ExecutionContext *ctx)
{
- return ctx->createCatchScope(exceptionVarName);
+ return ctx->createCatchScope(exceptionVarName, exceptionValue);
}
ExecutionContext *__qmljs_builtin_pop_scope(ExecutionContext *ctx)
struct ExecutionEngine;
struct Q_V4_EXPORT Exception {
- explicit Exception(ExecutionContext *throwingContext);
+ explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue);
~Exception();
void accept(ExecutionContext *catchingContext);
void partiallyUnwindContext(ExecutionContext *catchingContext);
+
+ Value value() const { return exception; }
+
private:
ExecutionContext *throwingContext;
bool accepted;
+ Value exception;
};
extern "C" {
void Q_NORETURN __qmljs_builtin_throw(ExecutionContext *context, const Value &val);
void Q_NORETURN __qmljs_builtin_rethrow(ExecutionContext *context);
ExecutionContext *__qmljs_builtin_push_with_scope(const Value &o, ExecutionContext *ctx);
-ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, ExecutionContext *ctx);
+ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, const QQmlJS::VM::Value &exceptionValue, ExecutionContext *ctx);
ExecutionContext *__qmljs_builtin_pop_scope(ExecutionContext *ctx);
void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String *name);
void __qmljs_builtin_define_property(ExecutionContext *ctx, const Value &object, String *name, Value *val);
void __qmljs_delete_name(ExecutionContext *ctx, Value *result, String *name);
void Q_NORETURN __qmljs_throw(ExecutionContext*, const Value &value);
-// actually returns a jmp_buf *
-Q_V4_EXPORT void __qmljs_create_exception_handler(ExecutionContext *context);
-void __qmljs_get_exception(ExecutionContext *context, Value *result);
// binary operators
typedef void (*BinOp)(ExecutionContext *ctx, Value *result, const Value &left, const Value &right);
static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunctionEntryPoint tryBody, MiddleOfFunctionEntryPoint catchBody,
VM::String *exceptionVarName, Value *exceptionVar)
{
+ *exceptionVar = Value::undefinedValue();
void *addressToContinueAt = 0;
try {
addressToContinueAt = tryBody(context, localsPtr);
} catch (Exception& ex) {
ex.accept(context);
- __qmljs_get_exception(context, exceptionVar);
+ *exceptionVar = ex.value();
try {
- ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, context);
+ ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, ex.value(), context);
addressToContinueAt = catchBody(catchContext, localsPtr);
context = __qmljs_builtin_pop_scope(catchContext);
} catch (Exception& ex) {
- __qmljs_get_exception(context, exceptionVar);
+ *exceptionVar = ex.value();
ex.accept(context);
addressToContinueAt = catchBody(context, localsPtr);
}
void InstructionSelection::visitTry(IR::Try *t)
{
- generateFunctionCall(Assembler::Void, __qmljs_create_exception_handler, Assembler::ContextRegister);
-
// 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.
} // builtins
-static void showException(QQmlJS::VM::ExecutionContext *ctx)
+static void showException(QQmlJS::VM::ExecutionContext *ctx, const QQmlJS::VM::Value &exception)
{
- QQmlJS::VM::ErrorObject *e = ctx->engine->exception.asErrorObject();
+ QQmlJS::VM::ErrorObject *e = exception.asErrorObject();
if (!e) {
- std::cerr << "Uncaught exception: " << qPrintable(ctx->engine->exception.toString(ctx)->toQString()) << std::endl;
+ std::cerr << "Uncaught exception: " << qPrintable(exception.toString(ctx)->toQString()) << std::endl;
return;
}
const QString code = QString::fromUtf8(file.readAll());
file.close();
- __qmljs_create_exception_handler(ctx);
try {
QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode,
/*strictMode =*/ false, /*inheritContext =*/ false);
}
} catch (QQmlJS::VM::Exception& ex) {
ex.accept(ctx);
- showException(ctx);
+ showException(ctx, ex.value());
return EXIT_FAILURE;
}