Propagate exceptions
authorRoberto Raggi <roberto.raggi@nokia.com>
Fri, 25 May 2012 09:55:50 +0000 (11:55 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Fri, 25 May 2012 09:55:50 +0000 (11:55 +0200)
12 files changed:
main.cpp
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qmljs_runtime.h
qv4codegen.cpp
qv4codegen_p.h
qv4ir_p.h
qv4isel.cpp
qv4isel_p.h
tests/exceptions.1.js
tests/exceptions.2.js [new file with mode: 0644]

index de7cb877a25b418f529bac4d348bdc8e1c0f3d9f..a7bfd0466db0025bf4121df48075c93ab9e247e2 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -104,8 +104,9 @@ void evaluate(QQmlJS::VM::ExecutionEngine *vm, const QString &fileName, const QS
 
     globalCode->code(ctx);
 
-    if (ctx->hasUncaughtException)
-        qWarning() << "Uncaught exception"; // << qPrintable(ctx->result.toString(ctx)->toQString());
+    if (ctx->hasUncaughtException) {
+        std::cerr << "Uncaught exception: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl;
+    }
 
     delete[] ctx->locals;
     delete[] ctx->vars;
index b4625aac2a770564094d5d1845319583f0c8e394..f38187cf5597ccb878ca4fe7524a01917d38a252 100644 (file)
@@ -398,6 +398,7 @@ FunctionObject *ExecutionEngine::newArrayCtor(Context *ctx)
 Object *ExecutionEngine::newArrayPrototype(Context *ctx, FunctionObject *proto)
 {
     Object *arrayProto = new ArrayPrototype(ctx, proto);
+    assert(objectPrototype.isObject());
     arrayProto->prototype = objectPrototype.objectValue;
     return arrayProto;
 }
@@ -418,18 +419,25 @@ FunctionObject *ExecutionEngine::newDateCtor(Context *ctx)
 Object *ExecutionEngine::newDatePrototype(Context *ctx, FunctionObject *proto)
 {
     Object *dateProto = new DatePrototype(ctx, proto);
+    assert(objectPrototype.isObject());
     dateProto->prototype = objectPrototype.objectValue;
     return dateProto;
 }
 
 Object *ExecutionEngine::newErrorObject(const Value &value)
 {
-    return new ErrorObject(value);
+    ErrorObject *object = new ErrorObject(value);
+    assert(objectPrototype.isObject());
+    object->prototype = objectPrototype.objectValue;
+    return object;
 }
 
 Object *ExecutionEngine::newMathObject(Context *ctx)
 {
-    return new MathObject(ctx);
+    MathObject *object = new MathObject(ctx);
+    assert(objectPrototype.isObject());
+    object->prototype = objectPrototype.objectValue;
+    return object;
 }
 
 Object *ExecutionEngine::newArgumentsObject(Context *ctx)
@@ -461,6 +469,13 @@ void Context::throwUnimplemented(const QString &message)
     throwError(Value::fromObject(engine->newErrorObject(v)));
 }
 
+void Context::throwReferenceError(const Value &value)
+{
+    String *s = value.toString(this);
+    QString msg = s->toQString() + QStringLiteral(" is not defined");
+    throwError(Value::fromObject(engine->newErrorObject(Value::fromString(this, msg))));
+}
+
 void Context::initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, int argc)
 {
     engine = e;
index 7c463f2695beaa4655e04b0aa4976b7ded80fd7e..c88bda690ce49a5e14d107bf942d57ed9b4b6063 100644 (file)
@@ -374,6 +374,7 @@ struct Context {
     void throwError(const QString &message);
     void throwTypeError();
     void throwUnimplemented(const QString &message);
+    void throwReferenceError(const Value &value);
 
     void initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, int argc);
     void leaveCallContext(FunctionObject *f, Value *r);
index 4e68359404df5c3353c8f57c78699b026e10a657..28d0bd3a87dd47820350940309c9a16b8e8b66f5 100644 (file)
@@ -490,7 +490,7 @@ void __qmljs_set_activation_element(Context *ctx, String *name, Value *index, Va
     if (Value *base = ctx->lookup(name)) {
         __qmljs_set_element(ctx, base, index, value);
     } else {
-        assert(!"reference error");
+        ctx->throwReferenceError(Value::fromString(name));
     }
 }
 
@@ -514,7 +514,7 @@ void __qmljs_copy_activation_property(Context *ctx, String *name, String *other)
     if (Value *source = ctx->lookup(other))
         __qmljs_set_activation_property(ctx, name, source);
     else
-        assert(!"reference error");
+        ctx->throwReferenceError(Value::fromString(name));
 }
 
 void __qmljs_set_activation_property_boolean(Context *ctx, String *name, bool b)
@@ -552,8 +552,10 @@ void __qmljs_get_property(Context *ctx, Value *result, Value *object, String *na
     } else {
         Value o;
         __qmljs_to_object(ctx, &o, object);
-        assert(o.type == OBJECT_TYPE);
-        __qmljs_get_property(ctx, result, &o, name);
+        if (o.isObject())
+            __qmljs_get_property(ctx, result, &o, name);
+        else
+            ctx->throwTypeError();
     }
 }
 
@@ -562,7 +564,7 @@ void __qmljs_get_activation_property(Context *ctx, Value *result, String *name)
     if (Value *prop = ctx->lookup(name))
         *result = *prop;
     else
-        assert(!"reference error");
+        ctx->throwReferenceError(Value::fromString(name));
 }
 
 void __qmljs_get_activation(Context *ctx, Value *result)
@@ -667,9 +669,9 @@ void __qmljs_call_activation_property(Context *context, Value *result, String *n
 {
     Value *func = context->lookup(name);
     if (! func)
-        assert(!"reference error");
-
-    __qmljs_call_value(context, result, /*thisObject=*/ 0, func, args, argc);
+        context->throwReferenceError(Value::fromString(name));
+    else
+        __qmljs_call_value(context, result, /*thisObject=*/ 0, func, args, argc);
 }
 
 void __qmljs_call_property(Context *context, Value *result, const Value *base, String *name, Value *args, int argc)
@@ -700,10 +702,10 @@ void __qmljs_call_property(Context *context, Value *result, const Value *base, S
             }
             ctx->leaveCallContext(f, result);
         } else {
-            assert(!"not a function");
+            context->throwTypeError();
         }
     } else {
-        assert(!"not a callable object");
+        context->throwTypeError();
     }
 }
 
@@ -721,10 +723,10 @@ void __qmljs_call_value(Context *context, Value *result, const Value *thisObject
             }
             ctx->leaveCallContext(f, result);
         } else {
-            assert(!"not a function");
+            context->throwTypeError();
         }
     } else {
-        assert(!"not a callable object");
+        context->throwTypeError();
     }
 }
 
@@ -732,9 +734,9 @@ void __qmljs_construct_activation_property(Context *context, Value *result, Stri
 {
     Value *func = context->lookup(name);
     if (! func)
-        assert(!"reference error");
-
-    __qmljs_construct_value(context, result, func, args, argc);
+        context->throwReferenceError(Value::fromString(name));
+    else
+        __qmljs_construct_value(context, result, func, args, argc);
 }
 
 void __qmljs_construct_value(Context *context, Value *result, const Value *func, Value *args, int argc)
@@ -752,10 +754,10 @@ void __qmljs_construct_value(Context *context, Value *result, const Value *func,
             }
             ctx->leaveConstructorContext(f, result);
         } else {
-            assert(!"not a function");
+            context->throwTypeError();
         }
     } else {
-        assert(!"not a callable object");
+        context->throwTypeError();
     }
 }
 
@@ -781,10 +783,10 @@ void __qmljs_construct_property(Context *context, Value *result, const Value *ba
             }
             ctx->leaveConstructorContext(f, result);
         } else {
-            assert(!"not a function");
+            context->throwTypeError();
         }
     } else {
-        assert(!"not a callable object");
+        context->throwTypeError();
     }
 }
 
@@ -796,12 +798,17 @@ void __qmljs_builtin_typeof(Context *context, Value *result, Value *args, int ar
 
 void __qmljs_builtin_throw(Context *context, Value *result, Value *args, int argc)
 {
-    Q_UNUSED(result);
     Q_UNUSED(argc);
-    context->result = args[0];
+    Q_UNUSED(result);
     context->hasUncaughtException = true;
+    context->result = args[0];
 }
 
+void __qmljs_builtin_rethrow(Context *context, Value *result, Value *, int)
+{
+    assert(result);
+    *result = context->result;
+}
 
 } // extern "C"
 
index afe3f075ca01185e194eeb601c8ecf2f8c02d92c..36f3b4cd9cfaa290bfe111ed3b99b0694fcc84cf 100644 (file)
@@ -63,6 +63,7 @@ void __qmljs_construct_value(Context *context, Value *result, const Value *func,
 
 void __qmljs_builtin_typeof(Context *context, Value *result, Value *args, int argc);
 void __qmljs_builtin_throw(Context *context, Value *result, Value *args, int argc);
+void __qmljs_builtin_rethrow(Context *context, Value *result, Value *args, int argc);
 
 // constructors
 void __qmljs_init_undefined(Value *result);
@@ -437,7 +438,7 @@ inline void __qmljs_to_string(Context *ctx, Value *result, const Value *value)
         if (prim.isPrimitive())
             __qmljs_to_string(ctx, result, &prim);
         else
-            assert(!"type error");
+            __qmljs_throw_type_error(ctx, result);
         break;
     }
 
index 6d475b39892097d8ec535ed8e0820dd7c158d81f..c9d14f778f8e3c255d9a2c0431923484d68b117f 100644 (file)
@@ -273,6 +273,7 @@ Codegen::Codegen()
     , _block(0)
     , _exitBlock(0)
     , _throwBlock(0)
+    , _handlersBlock(0)
     , _returnAddress(0)
     , _env(0)
 {
@@ -1441,9 +1442,11 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
     IR::BasicBlock *entryBlock = function->newBasicBlock();
     IR::BasicBlock *exitBlock = function->newBasicBlock();
     IR::BasicBlock *throwBlock = function->newBasicBlock();
+    IR::BasicBlock *handlersBlock = function->newBasicBlock();
     function->hasDirectEval = _env->hasDirectEval;
     function->hasNestedFunctions = _env->hasNestedFunctions;
     function->maxNumberOfArguments = _env->maxNumberOfArguments;
+    function->handlersBlock = handlersBlock;
 
     for (int i = 0; i < _env->vars.size(); ++i) {
         unsigned t = entryBlock->newTemp();
@@ -1462,6 +1465,7 @@ 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) {
@@ -1478,12 +1482,17 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
         _block->JUMP(_exitBlock);
 
     if (! _throwBlock->isTerminated())
-        _throwBlock->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);
 
     qSwap(_function, function);
     qSwap(_block, entryBlock);
     qSwap(_exitBlock, exitBlock);
     qSwap(_throwBlock, throwBlock);
+    qSwap(_handlersBlock, handlersBlock);
     qSwap(_returnAddress, returnAddress);
 
     leaveEnvironment();
index 9deec764bd39aa9f67f0be7aa9557708a128698d..87e967da8066f652401f26a757711ac3b32d896c 100644 (file)
@@ -284,6 +284,7 @@ private:
     IR::BasicBlock *_block;
     IR::BasicBlock *_exitBlock;
     IR::BasicBlock *_throwBlock;
+    IR::BasicBlock *_handlersBlock;
     unsigned _returnAddress;
     Environment *_env;
     QHash<AST::Node *, Environment *> _envMap;
index d35f7e4be88f41418c787fd2a19b0501de8a1f47..7bac2faf58d0d73f7d290bce1ab838e1aa5ee34b 100644 (file)
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -258,7 +258,8 @@ struct Name: Expr {
     enum Builtin {
         builtin_invalid,
         builtin_typeof,
-        builtin_throw
+        builtin_throw,
+        builtin_rethrow
     };
 
     const QString *id;
@@ -599,6 +600,7 @@ struct Function {
     QSet<QString> strings;
     QList<const QString *> formals;
     QList<const QString *> locals;
+    IR::BasicBlock *handlersBlock;
     void (*code)(VM::Context *);
     bool hasDirectEval: 1;
     bool hasNestedFunctions: 1;
@@ -609,6 +611,7 @@ struct Function {
         : module(module)
         , pool(&module->pool)
         , tempCount(0)
+        , handlersBlock(0)
         , maxNumberOfArguments(0)
         , code(0)
         , hasDirectEval(false)
index 0ef8268a2456e1cc5465fc150cf648443fa390df..061250239fd29464687ae973b5307a76af687981 100644 (file)
@@ -223,13 +223,15 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu
             amd64_mov_reg_imm(_codePtr, AMD64_RCX, argc);
             amd64_call_code(_codePtr, __qmljs_builtin_throw);
             break;
+        case IR::Name::builtin_rethrow:
+            amd64_lea_membase(_codePtr, AMD64_RDX, AMD64_RSP, 0);
+            amd64_mov_reg_imm(_codePtr, AMD64_RCX, argc);
+            amd64_call_code(_codePtr, __qmljs_builtin_rethrow);
+            return; // we need to return to avoid checking the exceptions
         }
     }
 
-    amd64_mov_reg_membase(_codePtr, AMD64_RAX, AMD64_R14, offsetof(Context, hasUncaughtException), 4);
-    amd64_alu_reg_imm_size(_codePtr, X86_CMP, AMD64_RAX, 1, 1);
-    _patches[_function->basicBlocks.last()].append(_codePtr); // ### TODO: jump to the exception handler
-    amd64_branch32(_codePtr, X86_CC_E, /* exception handler */ 0, 1);
+    checkExceptions();
 }
 
 
@@ -265,10 +267,7 @@ void InstructionSelection::callValue(IR::Call *call, IR::Temp *result)
     amd64_mov_reg_imm(_codePtr, AMD64_R9, argc);
     amd64_call_code(_codePtr, __qmljs_call_value);
 
-    amd64_mov_reg_membase(_codePtr, AMD64_RAX, AMD64_R14, offsetof(Context, hasUncaughtException), 4);
-    amd64_alu_reg_imm_size(_codePtr, X86_CMP, AMD64_RAX, 1, 1);
-    _patches[_function->basicBlocks.last()].append(_codePtr); // ### TODO: jump to the exception handler
-    amd64_branch32(_codePtr, X86_CC_E, /* exception handler */ 0, 1);
+    checkExceptions();
 }
 
 void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result)
@@ -304,6 +303,8 @@ void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result)
     amd64_lea_membase(_codePtr, AMD64_R8, AMD64_RSP, 0);
     amd64_mov_reg_imm(_codePtr, AMD64_R9, argc);
     amd64_call_code(_codePtr, __qmljs_call_property);
+
+    checkExceptions();
 }
 
 void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result)
@@ -336,6 +337,8 @@ void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *
     amd64_lea_membase(_codePtr, AMD64_RCX, AMD64_RSP, 0);
     amd64_mov_reg_imm(_codePtr, AMD64_R8, argc);
     amd64_call_code(_codePtr, __qmljs_construct_activation_property);
+
+    checkExceptions();
 }
 
 void InstructionSelection::constructProperty(IR::New *call, IR::Temp *result)
@@ -371,6 +374,8 @@ void InstructionSelection::constructProperty(IR::New *call, IR::Temp *result)
     amd64_lea_membase(_codePtr, AMD64_R8, AMD64_RSP, 0);
     amd64_mov_reg_imm(_codePtr, AMD64_R9, argc);
     amd64_call_code(_codePtr, __qmljs_construct_property);
+
+    checkExceptions();
 }
 
 void InstructionSelection::constructValue(IR::New *call, IR::Temp *result)
@@ -405,6 +410,14 @@ void InstructionSelection::constructValue(IR::New *call, IR::Temp *result)
     amd64_call_code(_codePtr, __qmljs_construct_value);
 }
 
+void InstructionSelection::checkExceptions()
+{
+    amd64_mov_reg_membase(_codePtr, AMD64_RAX, AMD64_R14, offsetof(Context, hasUncaughtException), 4);
+    amd64_alu_reg_imm_size(_codePtr, X86_CMP, AMD64_RAX, 1, 1);
+    _patches[_function->handlersBlock].append(_codePtr);
+    amd64_branch32(_codePtr, X86_CC_E, 0, 1);
+}
+
 void InstructionSelection::visitExp(IR::Exp *s)
 {
     if (IR::Call *c = s->expr->asCall()) {
@@ -462,32 +475,33 @@ void InstructionSelection::visitMove(IR::Move *s)
                     Q_UNIMPLEMENTED();
                     assert(!"TODO");
                 }
-                return;
             } else if (IR::String *str = s->source->asString()) {
                 amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                 amd64_mov_reg_imm(_codePtr, AMD64_RSI, propertyName);
                 amd64_mov_reg_imm(_codePtr, AMD64_RDX, _engine->newString(*str->value));
                 amd64_call_code(_codePtr, __qmljs_set_activation_property_string);
-                return;
             } else if (IR::Temp *t = s->source->asTemp()) {
                 amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                 amd64_mov_reg_imm(_codePtr, AMD64_RSI, propertyName);
                 loadTempAddress(AMD64_RDX, t);
                 amd64_call_code(_codePtr, __qmljs_set_activation_property);
-                return;
             } else if (IR::Name *other = s->source->asName()) {
                 amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                 amd64_mov_reg_imm(_codePtr, AMD64_RSI, propertyName);
                 amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*other->id));
                 amd64_call_code(_codePtr, __qmljs_copy_activation_property);
-                return;
             } else if (IR::Closure *clos = s->source->asClosure()) {
                 amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                 amd64_mov_reg_imm(_codePtr, AMD64_RSI, propertyName);
                 amd64_mov_reg_imm(_codePtr, AMD64_RDX, clos->value);
                 amd64_call_code(_codePtr, __qmljs_set_activation_property_closure);
-                return;
+            } else {
+                Q_UNIMPLEMENTED();
+                assert(!"TODO");
             }
+
+            checkExceptions();
+            return;
         } else if (IR::Temp *t = s->target->asTemp()) {
             if (IR::Name *n = s->source->asName()) {
                 amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
@@ -498,6 +512,7 @@ void InstructionSelection::visitMove(IR::Move *s)
                     String *propertyName = identifier(*n->id);
                     amd64_mov_reg_imm(_codePtr, AMD64_RDX, propertyName);
                     amd64_call_code(_codePtr, __qmljs_get_activation_property);
+                    checkExceptions();
                 }
                 return;
             } else if (IR::Const *c = s->source->asConst()) {
@@ -567,6 +582,7 @@ void InstructionSelection::visitMove(IR::Move *s)
                     loadTempAddress(AMD64_RDX, base);
                     amd64_mov_reg_imm(_codePtr, AMD64_RCX, identifier(*m->name));
                     amd64_call_code(_codePtr, __qmljs_get_property);
+                    checkExceptions();
                     return;
                 }
                 assert(!"wip");
@@ -577,6 +593,7 @@ void InstructionSelection::visitMove(IR::Move *s)
                 loadTempAddress(AMD64_RDX, ss->base->asTemp());
                 loadTempAddress(AMD64_RCX, ss->index->asTemp());
                 amd64_call_code(_codePtr, __qmljs_get_element);
+                checkExceptions();
                 return;
             } else if (IR::Unop *u = s->source->asUnop()) {
                 if (IR::Temp *e = u->expr->asTemp()) {
@@ -709,14 +726,12 @@ void InstructionSelection::visitMove(IR::Move *s)
                     amd64_mov_reg_imm(_codePtr, AMD64_RAX, &c->value);
                     amd64_movsd_reg_regp(_codePtr, X86_XMM0, AMD64_RAX);
                     amd64_call_code(_codePtr, __qmljs_set_property_number);
-                    return;
                 } else if (IR::String *str = s->source->asString()) {
                     amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                     loadTempAddress(AMD64_RSI, base);
                     amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*m->name));
                     amd64_mov_reg_imm(_codePtr, AMD64_RCX, _engine->newString(*str->value));
                     amd64_call_code(_codePtr, __qmljs_set_property_string);
-                    return;
                 } else if (IR::Temp *t = s->source->asTemp()) {
                     // __qmljs_set_property(ctx, object, name, value);
                     amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
@@ -724,15 +739,18 @@ void InstructionSelection::visitMove(IR::Move *s)
                     amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*m->name));
                     loadTempAddress(AMD64_RCX, t);
                     amd64_call_code(_codePtr, __qmljs_set_property);
-                    return;
                 } else if (IR::Closure *clos = s->source->asClosure()) {
                     amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                     loadTempAddress(AMD64_RSI, base);
                     amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*m->name));
                     amd64_mov_reg_imm(_codePtr, AMD64_RCX, clos->value);
                     amd64_call_code(_codePtr, __qmljs_set_property_closure);
-                    return;
+                } else {
+                    Q_UNIMPLEMENTED();
+                    assert(!"TODO");
                 }
+                checkExceptions();
+                return;
             }
         } else if (IR::Subscript *ss = s->target->asSubscript()) {
             if (IR::Temp *t2 = s->source->asTemp()) {
@@ -740,16 +758,24 @@ void InstructionSelection::visitMove(IR::Move *s)
                 loadTempAddress(AMD64_RDX, ss->index->asTemp());
                 loadTempAddress(AMD64_RCX, t2);
                 amd64_call_code(_codePtr, __qmljs_set_element);
-                return;
             } else if (IR::Const *c = s->source->asConst()) {
-                amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
-                loadTempAddress(AMD64_RSI, ss->base->asTemp());
-                loadTempAddress(AMD64_RDX, ss->index->asTemp());
-                amd64_mov_reg_imm(_codePtr, AMD64_RAX, &c->value);
-                amd64_movsd_reg_regp(_codePtr, X86_XMM0, AMD64_RAX);
-                amd64_call_code(_codePtr, __qmljs_set_element_number);
-                return;
+                if (c->type == IR::NumberType) {
+                    amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
+                    loadTempAddress(AMD64_RSI, ss->base->asTemp());
+                    loadTempAddress(AMD64_RDX, ss->index->asTemp());
+                    amd64_mov_reg_imm(_codePtr, AMD64_RAX, &c->value);
+                    amd64_movsd_reg_regp(_codePtr, X86_XMM0, AMD64_RAX);
+                    amd64_call_code(_codePtr, __qmljs_set_element_number);
+                } else {
+                    Q_UNIMPLEMENTED();
+                    assert(!"TODO");
+                }
+            } else {
+                Q_UNIMPLEMENTED();
+                assert(!"TODO");
             }
+            checkExceptions();
+            return;
         }
     } else {
         // inplace assignment, e.g. x += 1, ++x, ...
index c6da581683e4b2f643536a1176c769f016b17994..d53d028c50dff3220ce8810f04459f906e80a69e 100644 (file)
@@ -26,6 +26,7 @@ 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 *);
index 1f10d986765fbc6af5fdc8d79316747922166605..5e4e152c196d299c258d998a492d55e01e4007c0 100644 (file)
@@ -2,7 +2,7 @@
 function foo(a) {
     x = 1
     if (a)
-        throw 0;
+        throw 100;
     print("unreachable.1")
 }
 
diff --git a/tests/exceptions.2.js b/tests/exceptions.2.js
new file mode 100644 (file)
index 0000000..16b93b8
--- /dev/null
@@ -0,0 +1,2 @@
+
+print(foo)