Remove the tempRegister from moth by loading/storing values directly.
authorErik Verbruggen <erik.verbruggen@digia.com>
Tue, 13 Nov 2012 11:25:23 +0000 (12:25 +0100)
committerErik Verbruggen <erik.verbruggen@digia.com>
Wed, 14 Nov 2012 10:44:32 +0000 (11:44 +0100)
Change-Id: I51982d5852db2e10234620d63c235484c5b8a573
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
moth/qv4instr_moth_p.h
moth/qv4isel_moth.cpp
moth/qv4isel_moth_p.h
moth/qv4vme_moth.cpp

index 6fad95e..e37f302 100644 (file)
@@ -6,15 +6,13 @@
 
 #define FOR_EACH_MOTH_INSTR(F) \
     F(Ret, ret) \
-    F(LoadUndefined, common) \
-    F(LoadNull, common) \
-    F(LoadFalse, common) \
-    F(LoadTrue, common) \
+    F(LoadUndefined, loadUndefined) \
+    F(LoadNull, loadNull) \
+    F(LoadFalse, loadFalse) \
+    F(LoadTrue, loadTrue) \
     F(LoadNumber, loadNumber) \
     F(LoadString, loadString) \
     F(LoadClosure, loadClosure) \
-    F(StoreTemp, storeTemp) \
-    F(LoadTemp, loadTemp) \
     F(MoveTemp, moveTemp) \
     F(LoadName, loadName) \
     F(StoreName, storeName) \
@@ -74,18 +72,27 @@ union Instr
 
     struct instr_common {
         MOTH_INSTR_HEADER
+        int tempIndex;
     };
     struct instr_ret {
         MOTH_INSTR_HEADER
         int tempIndex;
     }; 
-    struct instr_storeTemp {
+    struct instr_loadUndefined {
         MOTH_INSTR_HEADER
-        int tempIndex;
+        int targetTempIndex;
     };
-    struct instr_loadTemp {
+    struct instr_loadNull {
         MOTH_INSTR_HEADER
-        int tempIndex;
+        int targetTempIndex;
+    };
+    struct instr_loadFalse {
+        MOTH_INSTR_HEADER
+        int targetTempIndex;
+    };
+    struct instr_loadTrue {
+        MOTH_INSTR_HEADER
+        int targetTempIndex;
     };
     struct instr_moveTemp {
         MOTH_INSTR_HEADER
@@ -95,30 +102,37 @@ union Instr
     struct instr_loadNumber {
         MOTH_INSTR_HEADER
         double value;
+        int targetTempIndex;
     };
     struct instr_loadString {
         MOTH_INSTR_HEADER
         VM::String *value;
-    }; 
+        int targetTempIndex;
+    };
     struct instr_loadClosure {
         MOTH_INSTR_HEADER
         IR::Function *value;
+        int targetTempIndex;
     };
     struct instr_loadName {
         MOTH_INSTR_HEADER
         VM::String *name;
+        int targetTempIndex;
     };
     struct instr_storeName {
         MOTH_INSTR_HEADER
         VM::String *name;
+        int sourceTemp;
     };
     struct instr_loadProperty {
         MOTH_INSTR_HEADER
         int baseTemp;
+        int targetTempIndex;
         VM::String *name;
     };
     struct instr_storeProperty {
         MOTH_INSTR_HEADER
+        int sourceTemp;
         int baseTemp;
         VM::String *name;
     };
@@ -126,9 +140,11 @@ union Instr
         MOTH_INSTR_HEADER
         int base;
         int index;
+        int targetTempIndex;
     };
     struct instr_storeElement {
         MOTH_INSTR_HEADER
+        int sourceTemp;
         int base;
         int index;
     };
@@ -140,12 +156,16 @@ union Instr
         MOTH_INSTR_HEADER
         quint32 argc;
         quint32 args;
+        int destIndex;
+        int targetTempIndex;
     };
     struct instr_callProperty {
         MOTH_INSTR_HEADER
         VM::String *name;
+        int baseTemp;
         quint32 argc;
         quint32 args;
+        int targetTempIndex;
     };
     struct instr_callBuiltin {
         MOTH_INSTR_HEADER
@@ -160,30 +180,36 @@ union Instr
         } builtin;
         quint32 argc;
         quint32 args;
+        int targetTempIndex;
     };
     struct instr_callBuiltinDeleteMember {
         MOTH_INSTR_HEADER
         int base;
         VM::String *member;
+        int targetTempIndex;
     };
     struct instr_callBuiltinDeleteSubscript {
         MOTH_INSTR_HEADER
         int base;
         int index;
+        int targetTempIndex;
     };
     struct instr_callBuiltinDeleteName {
         MOTH_INSTR_HEADER
         VM::String *name;
+        int targetTempIndex;
     };
     struct instr_callBuiltinDeleteValue {
         MOTH_INSTR_HEADER
         int tempIndex;
+        int targetTempIndex;
     };
     struct instr_createValue {
         MOTH_INSTR_HEADER
         int func;
         quint32 argc;
         quint32 args;
+        int targetTempIndex;
     };
     struct instr_createProperty {
         MOTH_INSTR_HEADER
@@ -191,32 +217,38 @@ union Instr
         VM::String *name;
         quint32 argc;
         quint32 args;
+        int targetTempIndex;
     };
     struct instr_createActivationProperty {
         MOTH_INSTR_HEADER
         VM::String *name;
         quint32 argc;
         quint32 args;
+        int targetTempIndex;
     };
     struct instr_jump {
         MOTH_INSTR_HEADER
         ptrdiff_t offset; 
+        int tempIndex;
     };
     struct instr_unop {
         MOTH_INSTR_HEADER
-        int e;
         VM::Value (*alu)(const VM::Value value, VM::Context *ctx);
+        int e;
+        int targetTempIndex;
     };
     struct instr_binop {
         MOTH_INSTR_HEADER
+        VM::Value (*alu)(const VM::Value , const VM::Value, VM::Context *);
+        int targetTempIndex;
         ValueOrTemp lhs;
         ValueOrTemp rhs;
         unsigned lhsIsTemp:1;
         unsigned rhsIsTemp:1;
-        VM::Value (*alu)(const VM::Value , const VM::Value, VM::Context *);
     };
     struct instr_loadThis {
         MOTH_INSTR_HEADER
+        int targetTempIndex;
     };
     struct instr_inplaceElementOp {
         MOTH_INSTR_HEADER
@@ -241,8 +273,10 @@ union Instr
 
     instr_common common;
     instr_ret ret;
-    instr_storeTemp storeTemp;
-    instr_loadTemp loadTemp;
+    instr_loadUndefined loadUndefined;
+    instr_loadNull loadNull;
+    instr_loadFalse loadFalse;
+    instr_loadTrue loadTrue;
     instr_moveTemp moveTemp;
     instr_loadNumber loadNumber;
     instr_loadString loadString;
index 9411658..9550bb6 100644 (file)
@@ -41,7 +41,7 @@ void InstructionSelection::operator()(IR::Function *function)
     _function->code = VME::exec;
     _function->codeData = _ccode;
 
-    int locals = _function->tempCount - _function->locals.size() + _function->maxNumberOfArguments;
+    int locals = _function->tempCount - _function->locals.size() + _function->maxNumberOfArguments + 1;
     assert(locals >= 0);
 
     Instruction::Push push;
@@ -72,19 +72,24 @@ void InstructionSelection::operator()(IR::Function *function)
     qSwap(_function, function);
 }
 
-void InstructionSelection::callActivationProperty(IR::Call *c)
+void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempIndex)
 {
     IR::Name *baseName = c->base->asName();
     Q_ASSERT(baseName);
 
     switch (baseName->builtin) {
     case IR::Name::builtin_invalid: {
+        const int scratchIndex = scratchTempIndex();
+
         Instruction::LoadName load;
         load.name = _engine->newString(*baseName->id);
+        load.targetTempIndex = scratchIndex;
         addInstruction(load);
 
         Instruction::CallValue call;
         prepareCallArgs(c->args, call.argc, call.args);
+        call.destIndex = scratchIndex;
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
@@ -95,6 +100,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c)
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_typeof;
         prepareCallArgs(c->args, call.argc, call.args);
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
@@ -105,24 +111,28 @@ void InstructionSelection::callActivationProperty(IR::Call *c)
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_throw;
         prepareCallArgs(c->args, call.argc, call.args);
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
     case IR::Name::builtin_create_exception_handler: {
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_create_exception_handler;
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
     case IR::Name::builtin_delete_exception_handler: {
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_delete_exception_handler;
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
     case IR::Name::builtin_get_exception: {
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_get_exception;
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
@@ -130,6 +140,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c)
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_foreach_iterator_object;
         prepareCallArgs(c->args, call.argc, call.args);
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
@@ -137,6 +148,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c)
         Instruction::CallBuiltin call;
         call.builtin = Instruction::CallBuiltin::builtin_foreach_next_property_name;
         prepareCallArgs(c->args, call.argc, call.args);
+        call.targetTempIndex = targetTempIndex;
         addInstruction(call);
     } break;
 
@@ -145,19 +157,23 @@ void InstructionSelection::callActivationProperty(IR::Call *c)
             Instruction::CallBuiltinDeleteMember call;
             call.base = m->base->asTemp()->index;
             call.member = _engine->newString(*m->name);
+            call.targetTempIndex = targetTempIndex;
             addInstruction(call);
         } else if (IR::Subscript *ss = c->args->expr->asSubscript()) {
             Instruction::CallBuiltinDeleteSubscript call;
             call.base = m->base->asTemp()->index;
             call.index = ss->index->asTemp()->index;
+            call.targetTempIndex = targetTempIndex;
             addInstruction(call);
         } else if (IR::Name *n = c->args->expr->asName()) {
             Instruction::CallBuiltinDeleteName call;
             call.name = _engine->newString(*n->id);
+            call.targetTempIndex = targetTempIndex;
             addInstruction(call);
         } else {
             Instruction::CallBuiltinDeleteValue call;
             call.tempIndex = c->args->expr->asTemp()->index;
+            call.targetTempIndex = targetTempIndex;
             addInstruction(call);
         }
     } break;
@@ -168,43 +184,39 @@ void InstructionSelection::callActivationProperty(IR::Call *c)
     }
 }
 
-void InstructionSelection::callValue(IR::Call *c)
+void InstructionSelection::callValue(IR::Call *c, int targetTempIndex)
 {
     IR::Temp *t = c->base->asTemp();
     Q_ASSERT(t);
 
-    Instruction::LoadTemp load;
-    load.tempIndex = t->index;
-    addInstruction(load);
-
     Instruction::CallValue call;
     prepareCallArgs(c->args, call.argc, call.args);
+    call.destIndex = t->index;
+    call.targetTempIndex = targetTempIndex;
     addInstruction(call);
 }
 
-void InstructionSelection::callProperty(IR::Call *c)
+void InstructionSelection::callProperty(IR::Call *c, int targetTempIndex)
 {
     IR::Member *m = c->base->asMember();
     Q_ASSERT(m);
 
-    // load the base
-    Instruction::LoadTemp load;
-    load.tempIndex = m->base->asTemp()->index;
-    addInstruction(load);
-
     // call the property on the loaded base
     Instruction::CallProperty call;
+    call.baseTemp = m->base->asTemp()->index;
     call.name = _engine->newString(*m->name);
     prepareCallArgs(c->args, call.argc, call.args);
+    call.targetTempIndex = targetTempIndex;
     addInstruction(call);
 }
 
-void InstructionSelection::construct(IR::New *ctor)
+void InstructionSelection::construct(IR::New *ctor, int targetTempIndex)
 {
     if (IR::Name *baseName = ctor->base->asName()) {
         Instruction::CreateActivationProperty create;
         create.name = _engine->newString(*baseName->id);
         prepareCallArgs(ctor->args, create.argc, create.args);
+        create.targetTempIndex = targetTempIndex;
         addInstruction(create);
     } else if (IR::Member *member = ctor->base->asMember()) {
         IR::Temp *base = member->base->asTemp();
@@ -214,11 +226,13 @@ void InstructionSelection::construct(IR::New *ctor)
         create.base = base->index;
         create.name = _engine->newString(*member->name);
         prepareCallArgs(ctor->args, create.argc, create.args);
+        create.targetTempIndex = targetTempIndex;
         addInstruction(create);
     } else if (IR::Temp *baseTemp = ctor->base->asTemp()) {
         Instruction::CreateValue create;
         create.func = baseTemp->index;
         prepareCallArgs(ctor->args, create.argc, create.args);
+        create.targetTempIndex = targetTempIndex;
         addInstruction(create);
     } else {
         qWarning("  NEW");
@@ -230,13 +244,15 @@ void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint
     argc = 0;
     args = 0;
 
+    /*
     int locals = _function->tempCount - _function->locals.size() + _function->maxNumberOfArguments;
 
+    The condition for this case is wrong: the locals check is incorrect:
     if (e && e->next == 0 && e->expr->asTemp()->index >= 0 && e->expr->asTemp()->index < locals) {
         // We pass single arguments as references to the stack
         argc = 1;
         args = e->expr->asTemp()->index;
-    } else if (e) {
+    } else */if (e) {
         // We need to move all the temps into the function arg array
         int argLocation = _function->tempCount - _function->locals.size();
         assert(argLocation >= 0);
@@ -256,17 +272,17 @@ void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint
 void InstructionSelection::visitExp(IR::Exp *s)
 {
     if (IR::Call *c = s->expr->asCall()) {
+        // These are calls where the result is ignored.
+        const int targetTempIndex = scratchTempIndex();
         if (c->base->asName()) {
-            callActivationProperty(c);
+            callActivationProperty(c, targetTempIndex);
         } else if (c->base->asTemp()) {
-            callValue(c);
+            callValue(c, targetTempIndex);
         } else if (c->base->asMember()) {
-            callProperty(c);
+            callProperty(c, targetTempIndex);
         } else {
             Q_UNREACHABLE();
         }
-
-        // TODO: check if we should store the return value ?
     } else {
         Q_UNREACHABLE();
     }
@@ -355,57 +371,77 @@ static inline ALUFunction aluOpFunction(IR::AluOp op)
 void InstructionSelection::visitMove(IR::Move *s)
 {
     if (IR::Temp *t = s->target->asTemp()) {
+        const int targetTempIndex = t->index;
         // Check what kind of load it is, and generate the instruction for that.
         // The store to the temp (the target) is done afterwards.
         if (IR::Name *n = s->source->asName()) {
             Q_UNUSED(n);
             if (*n->id == QStringLiteral("this")) { // ### `this' should be a builtin.
-                addInstruction(Instruction::LoadThis());
+                Instruction::LoadThis load;
+                load.targetTempIndex = targetTempIndex;
+                addInstruction(load);
             } else {
                 Instruction::LoadName load;
                 load.name = _engine->newString(*n->id);
+                load.targetTempIndex = targetTempIndex;
                 addInstruction(load);
             }
         } else if (IR::Const *c = s->source->asConst()) {
             switch (c->type) {
-            case IR::UndefinedType:
-                addInstruction(Instruction::LoadUndefined());
-                break;
-            case IR::NullType:
-                addInstruction(Instruction::LoadNull());
-                break;
+            case IR::UndefinedType: {
+                Instruction::LoadUndefined load;
+                load.targetTempIndex = targetTempIndex;
+                addInstruction(load);
+            } break;
+            case IR::NullType: {
+                Instruction::LoadNull load;
+                load.targetTempIndex = targetTempIndex;
+                addInstruction(load);
+            } break;
             case IR::BoolType:
-                if (c->value) addInstruction(Instruction::LoadTrue());
-                else addInstruction(Instruction::LoadFalse());
+                if (c->value) {
+                    Instruction::LoadTrue load;
+                    load.targetTempIndex = targetTempIndex;
+                    addInstruction(load);
+                } else {
+                    Instruction::LoadFalse load;
+                    load.targetTempIndex = targetTempIndex;
+                    addInstruction(load);
+                }
                 break;
             case IR::NumberType: {
                 Instruction::LoadNumber load;
                 load.value = c->value;
+                load.targetTempIndex = targetTempIndex;
                 addInstruction(load);
-                } break;
+            } break;
             default:
                 Q_UNREACHABLE();
                 break;
             }
         } else if (IR::Temp *t2 = s->source->asTemp()) {
-            Instruction::LoadTemp load;
-            load.tempIndex = t2->index;
-            addInstruction(load);
+            Instruction::MoveTemp move;
+            move.fromTempIndex = t2->index;
+            move.toTempIndex = targetTempIndex;
+            addInstruction(move);
         } else if (IR::String *str = s->source->asString()) {
             Instruction::LoadString load;
             load.value = _engine->newString(*str->value);
+            load.targetTempIndex = targetTempIndex;
             addInstruction(load);
         } else if (IR::Closure *clos = s->source->asClosure()) {
             Instruction::LoadClosure load;
             load.value = clos->value;
+            load.targetTempIndex = targetTempIndex;
             addInstruction(load);
         } else if (IR::New *ctor = s->source->asNew()) {
-            construct(ctor);
+            construct(ctor, targetTempIndex);
         } else if (IR::Member *m = s->source->asMember()) {
             if (IR::Temp *base = m->base->asTemp()) {
                 Instruction::LoadProperty load;
                 load.baseTemp = base->index;
                 load.name = _engine->newString(*m->name);
+                load.targetTempIndex = targetTempIndex;
                 addInstruction(load);
             } else {
                 qWarning("  MEMBER");
@@ -414,6 +450,7 @@ void InstructionSelection::visitMove(IR::Move *s)
             Instruction::LoadElement load;
             load.base = ss->base->asTemp()->index;
             load.index = ss->index->asTemp()->index;
+            load.targetTempIndex = targetTempIndex;
             addInstruction(load);
         } else if (IR::Unop *u = s->source->asUnop()) {
             if (IR::Temp *e = u->expr->asTemp()) {
@@ -431,6 +468,7 @@ void InstructionSelection::visitMove(IR::Move *s)
                     Instruction::Unop unop;
                     unop.alu = op;
                     unop.e = e->index;
+                    unop.targetTempIndex = targetTempIndex;
                     addInstruction(unop);
                 } else {
                     qWarning("  UNOP1");
@@ -445,22 +483,19 @@ void InstructionSelection::visitMove(IR::Move *s)
             binop.alu = aluOpFunction(b->op);
             binop.lhsIsTemp = toValueOrTemp(b->left, binop.lhs);
             binop.rhsIsTemp = toValueOrTemp(b->right, binop.rhs);
+            binop.targetTempIndex = targetTempIndex;
             addInstruction(binop);
         } else if (IR::Call *c = s->source->asCall()) {
             if (c->base->asName()) {
-                callActivationProperty(c);
+                callActivationProperty(c, targetTempIndex);
             } else if (c->base->asMember()) {
-                callProperty(c);
+                callProperty(c, targetTempIndex);
             } else if (c->base->asTemp()) {
-                callValue(c);
+                callValue(c, targetTempIndex);
             } else {
                 Q_UNREACHABLE();
             }
         }
-
-        Instruction::StoreTemp st;
-        st.tempIndex = t->index;
-        addInstruction(st);
         return;
     } else if (IR::Name *n = s->target->asName()) {
         if (IR::Temp *t = s->source->asTemp()) {
@@ -488,11 +523,8 @@ void InstructionSelection::visitMove(IR::Move *s)
                 addInstruction(ieo);
                 return;
             } else if (s->op == IR::OpInvalid) {
-                Instruction::LoadTemp load;
-                load.tempIndex = t->index;
-                addInstruction(load);
-
                 Instruction::StoreName store;
+                store.sourceTemp = t->index;
                 store.name = _engine->newString(*n->id);
                 addInstruction(store);
                 return;
@@ -526,11 +558,8 @@ void InstructionSelection::visitMove(IR::Move *s)
                 addInstruction(ieo);
                 return;
             } else if (s->op == IR::OpInvalid) {
-                Instruction::LoadTemp load;
-                load.tempIndex = t->index;
-                addInstruction(load);
-
                 Instruction::StoreElement store;
+                store.sourceTemp = t->index;
                 store.base = ss->base->asTemp()->index;
                 store.index = ss->index->asTemp()->index;
                 addInstruction(store);
@@ -565,11 +594,8 @@ void InstructionSelection::visitMove(IR::Move *s)
                 addInstruction(imo);
                 return;
             } else if (s->op == IR::OpInvalid) {
-                Instruction::LoadTemp load;
-                load.tempIndex = t->index;
-                addInstruction(load);
-
                 Instruction::StoreProperty store;
+                store.sourceTemp = t->index;
                 store.baseTemp = m->base->asTemp()->index;
                 store.name = _engine->newString(*m->name);
                 addInstruction(store);
@@ -596,15 +622,16 @@ void InstructionSelection::visitJump(IR::Jump *s)
 
 void InstructionSelection::visitCJump(IR::CJump *s)
 {
+    int tempIndex;
     if (IR::Temp *t = s->cond->asTemp()) {
-        Instruction::LoadTemp load;
-        load.tempIndex = t->index;
-        addInstruction(load);
+        tempIndex = t->index;
     } else if (IR::Binop *b = s->cond->asBinop()) {
+        tempIndex = scratchTempIndex();
         Instruction::Binop binop;
         binop.alu = aluOpFunction(b->op);
         binop.lhsIsTemp = toValueOrTemp(b->left, binop.lhs);
         binop.rhsIsTemp = toValueOrTemp(b->right, binop.rhs);
+        binop.targetTempIndex = tempIndex;
         addInstruction(binop);
     } else {
         Q_UNREACHABLE();
@@ -612,6 +639,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
 
     Instruction::CJump jump;
     jump.offset = 0;
+    jump.tempIndex = tempIndex;
     ptrdiff_t tl = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
     _patches[s->iftrue].append(tl);
 
index 6c92564..bb024c5 100644 (file)
@@ -35,11 +35,12 @@ private:
     };
 
     void simpleMove(IR::Move *);
-    void callActivationProperty(IR::Call *c);
-    void callValue(IR::Call *c);
-    void callProperty(IR::Call *c);
-    void construct(IR::New *ctor);
+    void callActivationProperty(IR::Call *c, int targetTempIndex);
+    void callValue(IR::Call *c, int targetTempIndex);
+    void callProperty(IR::Call *c, int targetTempIndex);
+    void construct(IR::New *ctor, int targetTempIndex);
     void prepareCallArgs(IR::ExprList *, quint32 &, quint32 &);
+    int scratchTempIndex() { return _function->tempCount - _function->locals.size() + _function->maxNumberOfArguments; }
 
     template <int Instr>
     inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
index 9bd3bf8..66df75f 100644 (file)
@@ -49,7 +49,22 @@ using namespace QQmlJS::Moth;
 
 static inline VM::Value *tempValue(QQmlJS::VM::Context *context, QVector<VM::Value> &stack, int index)
 {
-    TRACE(tempValue, "index = %d / arg = %d / local = %d, stack size = %d", index, (-index-1), index - stack.count(), stack.size());
+#ifdef DO_TRACE_INSTR
+    const char *kind;
+    int pos;
+    if (index < 0) {
+        kind = "arg";
+        pos = -index - 1;
+    } else if (index < (int) context->varCount) {
+        kind = "local";
+        pos = index;
+    } else {
+        kind = "temp";
+        pos = index - context->varCount;
+    }
+    fprintf(stderr, "    tempValue: index = %d : %s = %d, stack size = %d\n",
+          index, kind, pos, stack.size());
+#endif // DO_TRACE_INSTR
 
     if (index < 0) {
         const int arg = -index - 1;
@@ -84,7 +99,6 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code
 #endif
 
     QVector<VM::Value> stack;
-    VM::Value tempRegister;
 
 #ifdef MOTH_THREADED_INTERPRETER
     const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
@@ -95,75 +109,68 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code
         switch (genericInstr->common.instructionType) {
 #endif
 
-    MOTH_BEGIN_INSTR(StoreTemp)
-        TEMP(instr.tempIndex) = tempRegister;
-    MOTH_END_INSTR(StoreTemp)
-
-    MOTH_BEGIN_INSTR(LoadTemp)
-        tempRegister = TEMP(instr.tempIndex);
-    MOTH_END_INSTR(LoadTemp)
-
     MOTH_BEGIN_INSTR(MoveTemp)
-        TEMP(instr.toTempIndex) = TEMP(instr.fromTempIndex);
+        VM::Value tmp = TEMP(instr.fromTempIndex);
+        TEMP(instr.toTempIndex) = tmp;
     MOTH_END_INSTR(MoveTemp)
 
     MOTH_BEGIN_INSTR(LoadUndefined)
-        tempRegister = VM::Value::undefinedValue();
+        TEMP(instr.targetTempIndex) = VM::Value::undefinedValue();
     MOTH_END_INSTR(LoadUndefined)
 
     MOTH_BEGIN_INSTR(LoadNull)
-        tempRegister = VM::Value::nullValue();
+        TEMP(instr.targetTempIndex) = VM::Value::nullValue();
     MOTH_END_INSTR(LoadNull)
 
     MOTH_BEGIN_INSTR(LoadTrue)
-        tempRegister = VM::Value::fromBoolean(true);
+        TEMP(instr.targetTempIndex) = VM::Value::fromBoolean(true);
     MOTH_END_INSTR(LoadTrue)
 
     MOTH_BEGIN_INSTR(LoadFalse)
-        tempRegister = VM::Value::fromBoolean(false);
+        TEMP(instr.targetTempIndex) = VM::Value::fromBoolean(false);
     MOTH_END_INSTR(LoadFalse)
 
     MOTH_BEGIN_INSTR(LoadNumber)
         TRACE(inline, "number = %f", instr.value);
-        tempRegister = VM::Value::fromDouble(instr.value);
+        TEMP(instr.targetTempIndex) = VM::Value::fromDouble(instr.value);
     MOTH_END_INSTR(LoadNumber)
 
     MOTH_BEGIN_INSTR(LoadString)
-        tempRegister = VM::Value::fromString(instr.value);
+        TEMP(instr.targetTempIndex) = VM::Value::fromString(instr.value);
     MOTH_END_INSTR(LoadString)
 
     MOTH_BEGIN_INSTR(LoadClosure)
-        tempRegister = __qmljs_init_closure(instr.value, context);
+        TEMP(instr.targetTempIndex) = __qmljs_init_closure(instr.value, context);
     MOTH_END_INSTR(LoadClosure)
 
     MOTH_BEGIN_INSTR(LoadName)
         TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData());
-        tempRegister = __qmljs_get_activation_property(context, instr.name);
+        TEMP(instr.targetTempIndex) = __qmljs_get_activation_property(context, instr.name);
     MOTH_END_INSTR(LoadName)
 
     MOTH_BEGIN_INSTR(StoreName)
         TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData());
-        __qmljs_set_activation_property(context, instr.name, tempRegister);
+        __qmljs_set_activation_property(context, instr.name, TEMP(instr.sourceTemp));
     MOTH_END_INSTR(StoreName)
 
     MOTH_BEGIN_INSTR(LoadElement)
-        tempRegister = __qmljs_get_element(context, TEMP(instr.base), TEMP(instr.index));
+        TEMP(instr.targetTempIndex) = __qmljs_get_element(context, TEMP(instr.base), TEMP(instr.index));
     MOTH_END_INSTR(LoadElement)
 
     MOTH_BEGIN_INSTR(StoreElement)
-        __qmljs_set_element(context, TEMP(instr.base), TEMP(instr.index), tempRegister);
+        __qmljs_set_element(context, TEMP(instr.base), TEMP(instr.index), TEMP(instr.sourceTemp));
     MOTH_END_INSTR(StoreElement)
 
     MOTH_BEGIN_INSTR(LoadProperty)
         TRACE(inline, "base temp = %d, property name = %s", instr.baseTemp, instr.name->toQString().toUtf8().constData());
         VM::Value base = TEMP(instr.baseTemp);
-        tempRegister = __qmljs_get_property(context, base, instr.name);
+        TEMP(instr.targetTempIndex) = __qmljs_get_property(context, base, instr.name);
     MOTH_END_INSTR(LoadProperty)
 
     MOTH_BEGIN_INSTR(StoreProperty)
         TRACE(inline, "base temp = %d, property name = %s", instr.baseTemp, instr.name->toQString().toUtf8().constData());
         VM::Value base = TEMP(instr.baseTemp);
-        __qmljs_set_property(context, base, instr.name, tempRegister);
+        __qmljs_set_property(context, base, instr.name, TEMP(instr.sourceTemp));
     MOTH_END_INSTR(StoreProperty)
 
     MOTH_BEGIN_INSTR(Push)
@@ -172,13 +179,14 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code
     MOTH_END_INSTR(Push)
 
     MOTH_BEGIN_INSTR(CallValue)
+        TRACE(Call, "argStart = %d, argc = %d, result temp index = %d", instr.args, instr.argc, instr.targetTempIndex);
         VM::Value *args = stack.data() + instr.args;
-        tempRegister = __qmljs_call_value(context, VM::Value::undefinedValue(), tempRegister, args, instr.argc);
+        TEMP(instr.targetTempIndex) = __qmljs_call_value(context, VM::Value::undefinedValue(), TEMP(instr.destIndex), args, instr.argc);
     MOTH_END_INSTR(CallValue)
 
     MOTH_BEGIN_INSTR(CallProperty)
         VM::Value *args = stack.data() + instr.args;
-        tempRegister = __qmljs_call_property(context, tempRegister, instr.name, args, instr.argc);
+        TEMP(instr.targetTempIndex) = __qmljs_call_property(context, TEMP(instr.baseTemp), instr.name, args, instr.argc);
     MOTH_END_INSTR(CallProperty)
 
     MOTH_BEGIN_INSTR(CallBuiltin)
@@ -186,60 +194,60 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code
         void *buf;
         switch (instr.builtin) {
         case Instr::instr_callBuiltin::builtin_typeof:
-            tempRegister = __qmljs_builtin_typeof(args[0], context);
+            TEMP(instr.targetTempIndex) = __qmljs_builtin_typeof(args[0], context);
             break;
         case Instr::instr_callBuiltin::builtin_throw:
-            __qmljs_builtin_typeof(args[0], context);
+            TEMP(instr.targetTempIndex) = __qmljs_builtin_typeof(args[0], context);
             break;
         case Instr::instr_callBuiltin::builtin_create_exception_handler:
             buf = __qmljs_create_exception_handler(context);
-            tempRegister = VM::Value::fromInt32(setjmp(* static_cast<jmp_buf *>(buf)));
+            TEMP(instr.targetTempIndex) = VM::Value::fromInt32(setjmp(* static_cast<jmp_buf *>(buf)));
             break;
         case Instr::instr_callBuiltin::builtin_delete_exception_handler:
             __qmljs_delete_exception_handler(context);
             break;
         case Instr::instr_callBuiltin::builtin_get_exception:
-            tempRegister = __qmljs_get_exception(context);
+            TEMP(instr.targetTempIndex) = __qmljs_get_exception(context);
             break;
         case Instr::instr_callBuiltin::builtin_foreach_iterator_object:
-            tempRegister = __qmljs_foreach_iterator_object(args[0], context);
+            TEMP(instr.targetTempIndex) = __qmljs_foreach_iterator_object(args[0], context);
             break;
         case Instr::instr_callBuiltin::builtin_foreach_next_property_name:
-            tempRegister = __qmljs_foreach_next_property_name(args[0]);
+            TEMP(instr.targetTempIndex) = __qmljs_foreach_next_property_name(args[0]);
             break;
         }
     MOTH_END_INSTR(CallBuiltin)
 
     MOTH_BEGIN_INSTR(CallBuiltinDeleteMember)
-        tempRegister = __qmljs_delete_member(context, TEMP(instr.base), instr.member);
+        TEMP(instr.targetTempIndex) = __qmljs_delete_member(context, TEMP(instr.base), instr.member);
     MOTH_END_INSTR(CallBuiltinDeleteMember)
 
     MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript)
-        tempRegister = __qmljs_delete_subscript(context, TEMP(instr.base), TEMP(instr.index));
+        TEMP(instr.targetTempIndex) = __qmljs_delete_subscript(context, TEMP(instr.base), TEMP(instr.index));
     MOTH_END_INSTR(CallBuiltinDeleteSubscript)
 
     MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
-        tempRegister = __qmljs_delete_property(context, instr.name);
+        TEMP(instr.targetTempIndex) = __qmljs_delete_property(context, instr.name);
     MOTH_END_INSTR(CallBuiltinDeleteName)
 
     MOTH_BEGIN_INSTR(CallBuiltinDeleteValue)
-        tempRegister = __qmljs_delete_value(context, TEMP(instr.tempIndex));
+        TEMP(instr.targetTempIndex) = __qmljs_delete_value(context, TEMP(instr.tempIndex));
     MOTH_END_INSTR(CallBuiltinDeleteValue)
 
     MOTH_BEGIN_INSTR(CreateValue)
         VM::Value *args = stack.data() + instr.args;
-        tempRegister = __qmljs_construct_value(context, TEMP(instr.func), args, instr.argc);
+        TEMP(instr.targetTempIndex) = __qmljs_construct_value(context, TEMP(instr.func), args, instr.argc);
     MOTH_END_INSTR(CreateValue)
 
     MOTH_BEGIN_INSTR(CreateProperty)
         VM::Value *args = stack.data() + instr.args;
-        tempRegister = __qmljs_construct_property(context, TEMP(instr.base), instr.name, args, instr.argc);
+        TEMP(instr.targetTempIndex) = __qmljs_construct_property(context, TEMP(instr.base), instr.name, args, instr.argc);
     MOTH_END_INSTR(CreateProperty)
 
     MOTH_BEGIN_INSTR(CreateActivationProperty)
         TRACE(inline, "property name = %s, argc = %d", instr.name->toQString().toUtf8().constData(), instr.argc);
         VM::Value *args = stack.data() + instr.args;
-        tempRegister = __qmljs_construct_activation_property(context, instr.name, args, instr.argc);
+        TEMP(instr.targetTempIndex) = __qmljs_construct_activation_property(context, instr.name, args, instr.argc);
     MOTH_END_INSTR(CreateActivationProperty)
 
     MOTH_BEGIN_INSTR(Jump)
@@ -247,18 +255,18 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code
     MOTH_END_INSTR(Jump)
 
     MOTH_BEGIN_INSTR(CJump)
-        if (__qmljs_to_boolean(tempRegister, context))
+        if (__qmljs_to_boolean(TEMP(instr.tempIndex), context))
             code = ((uchar *)&instr.offset) + instr.offset;
     MOTH_END_INSTR(CJump)
 
     MOTH_BEGIN_INSTR(Unop)
-        tempRegister = instr.alu(TEMP(instr.e), context);
+        TEMP(instr.targetTempIndex) = instr.alu(TEMP(instr.e), context);
     MOTH_END_INSTR(Unop)
 
     MOTH_BEGIN_INSTR(Binop)
         VM::Value lhs = instr.lhsIsTemp ? TEMP(instr.lhs.tempIndex) : instr.lhs.value;
         VM::Value rhs = instr.rhsIsTemp ? TEMP(instr.rhs.tempIndex) : instr.rhs.value;
-        tempRegister = instr.alu(lhs, rhs, context);
+        TEMP(instr.targetTempIndex) = instr.alu(lhs, rhs, context);
     MOTH_END_INSTR(Binop)
 
     MOTH_BEGIN_INSTR(Ret)
@@ -267,7 +275,7 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code
     MOTH_END_INSTR(Ret)
 
     MOTH_BEGIN_INSTR(LoadThis)
-        tempRegister = __qmljs_get_thisObject(context);
+        TEMP(instr.targetTempIndex) = __qmljs_get_thisObject(context);
     MOTH_END_INSTR(LoadThis)
 
     MOTH_BEGIN_INSTR(InplaceElementOp)