Get rid of redundant type member from V4 instructions
authorKent Hansen <kent.hansen@nokia.com>
Thu, 22 Sep 2011 11:40:48 +0000 (13:40 +0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 23 Sep 2011 09:27:31 +0000 (11:27 +0200)
When interpretation is threaded, the type member is
redundant, since we can obtain the type from the
instruction address.

Getting rid of the type member can save at least one
byte per instruction (possibly more because of
alignment). On ia32, the Noop and Block instructions
become 4 bytes smaller.

The compiler has been refactored to leave it up to
the Bytecode class to decide whether the instruction
address or type (enum) should be stored.

To achieve this, the "low-level" Instr union was
renamed to V4Instr, and the new Instr struct
used by the compiler provides typedefs for
instantiating the data used by each particular
instruction. Lastly, the gen() function (instruction
emitter) was made template-based to provide the
instruction type.

The instructions Bool, Int, Real, String were
renamed to Load{Bool,Int,Real,String} to make the
new code more readable.

This approach follows a similar refactoring in the
QML-VME interpreter.

Change-Id: I9bf16b099a85afdfb719a25fb18047408882d61e
Reviewed-on: http://codereview.qt-project.org/5393
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
src/declarative/qml/v4/qdeclarativev4bindings.cpp
src/declarative/qml/v4/qdeclarativev4compiler.cpp
src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
src/declarative/qml/v4/qdeclarativev4instruction.cpp
src/declarative/qml/v4/qdeclarativev4instruction_p.h

index 20d79dc..1a1f5cc 100644 (file)
@@ -789,7 +789,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
     QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
     const char *code = program->instructions();
     code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
-    const Instr *instr = (const Instr *) code;
+    const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
 
     const char *data = program->data();
 
@@ -1110,26 +1110,26 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
     }
     QML_V4_END_INSTR(MathPIReal, unaryop)
 
-    QML_V4_BEGIN_INSTR(Real, real_value)
+    QML_V4_BEGIN_INSTR(LoadReal, real_value)
         registers[instr->real_value.reg].setqreal(instr->real_value.value);
-    QML_V4_END_INSTR(Real, real_value)
+    QML_V4_END_INSTR(LoadReal, real_value)
 
-    QML_V4_BEGIN_INSTR(Int, int_value)
+    QML_V4_BEGIN_INSTR(LoadInt, int_value)
         registers[instr->int_value.reg].setint(instr->int_value.value);
-    QML_V4_END_INSTR(Int, int_value)
+    QML_V4_END_INSTR(LoadInt, int_value)
 
-    QML_V4_BEGIN_INSTR(Bool, bool_value)
+    QML_V4_BEGIN_INSTR(LoadBool, bool_value)
         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
-    QML_V4_END_INSTR(Bool, bool_value)
+    QML_V4_END_INSTR(LoadBool, bool_value)
 
-    QML_V4_BEGIN_INSTR(String, string_value)
+    QML_V4_BEGIN_INSTR(LoadString, string_value)
     {
         Register &output = registers[instr->string_value.reg];
         QChar *string = (QChar *)(data + instr->string_value.offset);
         new (output.getstringptr()) QString(string, instr->string_value.length);
         STRING_REGISTER(instr->string_value.reg);
     }
-    QML_V4_END_INSTR(String, string_value)
+    QML_V4_END_INSTR(LoadString, string_value)
 
     QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
     {
index fa4cd25..35ec924 100644 (file)
@@ -106,10 +106,9 @@ void QDeclarativeV4CompilerPrivate::trace(int line, int column)
 
         if (bytecode.isEmpty()) {
             if (qmlBindingsTest || bindingsDump()) {
-                Instr id;
-                id.common.type = Instr::BindingId;
-                id.id.column = column;
-                id.id.line = line;
+                Instr::BindingId id;
+                id.column = column;
+                id.line = line;
                 gen(id);
             }
 
@@ -119,11 +118,10 @@ void QDeclarativeV4CompilerPrivate::trace(int line, int column)
                 int offset = data.count();
                 data += strdata;
 
-                Instr test;
-                test.common.type = Instr::EnableV4Test;
-                test.string_value.reg = 0;
-                test.string_value.offset = offset;
-                test.string_value.length = str.length();
+                Instr::EnableV4Test test;
+                test.reg = 0;
+                test.offset = offset;
+                test.length = str.length();
                 gen(test);
             }
         }
@@ -133,8 +131,8 @@ void QDeclarativeV4CompilerPrivate::trace(int line, int column)
         qSwap(usedSubscriptionIdsChanged, usic);
 
         int blockopIndex = bytecode.size();
-        Instr blockop;
-        blockop.block(currentBlockMask);
+        Instr::Block blockop;
+        blockop.block = currentBlockMask;
         gen(blockop);
 
         foreach (IR::Stmt *s, block->statements) {
@@ -169,8 +167,9 @@ void QDeclarativeV4CompilerPrivate::trace(int line, int column)
     if (! _discarded) {
         // back patching
         foreach (const Patch &patch, patches) {
-            Instr &instr = bytecode[patch.offset];
-            instr.branchop.offset = patch.block->offset - patch.offset - instr.size();
+            V4Instr &instr = bytecode[patch.offset];
+            int size = V4Instr::size(instructionType(&instr));
+            instr.branchop.offset = patch.block->offset - patch.offset - size;
         }
 
         patches.clear();
@@ -211,22 +210,27 @@ void QDeclarativeV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
 //
 void QDeclarativeV4CompilerPrivate::visitConst(IR::Const *e)
 {
-    Instr i;
     switch (e->type) {
-    case IR::BoolType:
-        i.move_reg_bool(currentReg, e->value);
+    case IR::BoolType: {
+        Instr::LoadBool i;
+        i.reg = currentReg;
+        i.value = e->value;
         gen(i);
-        break;
+        break;
 
-    case IR::IntType:
-        i.move_reg_int(currentReg, e->value);
+    case IR::IntType: {
+        Instr::LoadInt i;
+        i.reg = currentReg;
+        i.value = e->value;
         gen(i);
-        break;
+        break;
 
-    case IR::RealType:
-        i.move_reg_qreal(currentReg, e->value);
+    case IR::RealType: {
+        Instr::LoadReal i;
+        i.reg = currentReg;
+        i.value = e->value;
         gen(i);
-        break;
+        break;
 
     default:
         if (qmlVerboseCompiler())
@@ -251,8 +255,8 @@ void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
 
     if (e->storage == IR::Name::RootStorage) {
 
-        Instr instr;
-        instr.load_root(currentReg);
+        Instr::LoadRoot instr;
+        instr.reg = currentReg;
         gen(instr);
 
         if (e->symbol == IR::Name::IdObject) {
@@ -262,23 +266,26 @@ void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
 
     } else if (e->storage == IR::Name::ScopeStorage) {
 
-        Instr instr;
-        instr.load_scope(currentReg);
+        Instr::LoadScope instr;
+        instr.reg = currentReg;
         gen(instr);
 
         _subscribeName << contextName();
 
     } else if (e->storage == IR::Name::IdStorage) {
 
-        Instr instr;
-        instr.load_id(currentReg, e->index);
+        Instr::LoadId instr;
+        instr.reg = currentReg;
+        instr.index = e->index;
         gen(instr);
 
         _subscribeName << QLatin1String("$$$ID_") + *e->id;
 
         if (blockNeedsSubscription(_subscribeName)) {
-            Instr sub;
-            sub.subscribeId(currentReg, subscriptionIndex(_subscribeName), instr.load.index);
+            Instr::SubscribeId sub;
+            sub.reg = currentReg;
+            sub.offset = subscriptionIndex(_subscribeName);
+            sub.index = instr.index;
             gen(sub);
         }
 
@@ -299,13 +306,12 @@ void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
     case IR::Name::AttachType: {
         _subscribeName << *e->id;
 
-        Instr attached;
-        attached.common.type = Instr::LoadAttached;
-        attached.attached.output = currentReg;
-        attached.attached.reg = currentReg;
-        attached.attached.exceptionId = exceptionId(e->line, e->column);
+        Instr::LoadAttached attached;
+        attached.output = currentReg;
+        attached.reg = currentReg;
+        attached.exceptionId = exceptionId(e->line, e->column);
         Q_ASSERT(e->declarativeType->attachedPropertiesId() != -1);
-        attached.attached.id = e->declarativeType->attachedPropertiesId();
+        attached.id = e->declarativeType->attachedPropertiesId();
         gen(attached);
     } break;
 
@@ -349,31 +355,31 @@ void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
             break;
         } // switch
 
-        Instr fetch;
-
         if (fastFetchIndex != -1) {
-            fetch.common.type = Instr::FetchAndSubscribe;
-            fetch.fetchAndSubscribe.reg = currentReg;
-            fetch.fetchAndSubscribe.function = fastFetchIndex;
-            fetch.fetchAndSubscribe.subscription = subscriptionIndex(_subscribeName);
-            fetch.fetchAndSubscribe.exceptionId = exceptionId(e->line, e->column);
-            fetch.fetchAndSubscribe.valueType = regType;
+            Instr::FetchAndSubscribe fetch;
+            fetch.reg = currentReg;
+            fetch.function = fastFetchIndex;
+            fetch.subscription = subscriptionIndex(_subscribeName);
+            fetch.exceptionId = exceptionId(e->line, e->column);
+            fetch.valueType = regType;
+            gen(fetch);
         } else {
             if (blockNeedsSubscription(_subscribeName) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
-                Instr sub;
-                sub.subscribe(currentReg, subscriptionIndex(_subscribeName), prop.notifySignalIndex());
+                Instr::Subscribe sub;
+                sub.reg = currentReg;
+                sub.offset = subscriptionIndex(_subscribeName);
+                sub.index = prop.notifySignalIndex();
                 gen(sub);
             }
 
-            fetch.common.type = Instr::Fetch;
-            fetch.fetch.reg = currentReg;
-            fetch.fetch.index = e->index;
-            fetch.fetch.exceptionId = exceptionId(e->line, e->column);
-            fetch.fetch.valueType = regType;
+            Instr::Fetch fetch;
+            fetch.reg = currentReg;
+            fetch.index = e->index;
+            fetch.exceptionId = exceptionId(e->line, e->column);
+            fetch.valueType = regType;
+            gen(fetch);
         }
 
-        gen(fetch);
-
     } break;
     } // switch
 }
@@ -381,16 +387,15 @@ void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
 void QDeclarativeV4CompilerPrivate::visitTemp(IR::Temp *e)
 {
     if (currentReg != e->index) {
-        Instr i;
-        i.move_reg_reg(currentReg, e->index);
+        Instr::Copy i;
+        i.reg = currentReg;
+        i.src = e->index;
         gen(i);
     }
 }
 
 void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
 {
-    Instr i;
-
     quint8 src = currentReg;
     
     if (IR::Temp *temp = e->expr->asTemp()) {
@@ -407,24 +412,32 @@ void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
     case IR::OpIfTrue:
         convertToBool(e->expr, src);
         if (src != currentReg) {
-            i.move_reg_reg(currentReg, src);
+            Instr::Copy i;
+            i.reg = currentReg;
+            i.src = src;
             gen(i);
         }
         break;
 
-    case IR::OpNot:
+    case IR::OpNot: {
+        Instr::UnaryNot i;
         convertToBool(e->expr, src);
-        i.unary_not(currentReg, src);
+        i.output = currentReg;
+        i.src = src;
         gen(i);
-        break;
+        break;
 
     case IR::OpUMinus:
         if (e->expr->type == IR::RealType) {
-            i.uminus_real(currentReg, src);
+            Instr::UnaryMinusReal i;
+            i.output = currentReg;
+            i.src = src;
             gen(i);
         } else if (e->expr->type == IR::IntType) {
             convertToReal(e->expr, currentReg);
-            i.uminus_real(currentReg, src);
+            Instr::UnaryMinusReal i;
+            i.output = currentReg;
+            i.src = src;
             gen(i);
         } else {
             discard();
@@ -433,11 +446,15 @@ void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
 
     case IR::OpUPlus:
         if (e->expr->type == IR::RealType) {
-            i.uplus_real(currentReg, src);
+            Instr::UnaryPlusReal i;
+            i.output = currentReg;
+            i.src = src;
             gen(i);
         } else if (e->expr->type == IR::IntType) {
             convertToReal(e->expr, currentReg);
-            i.uplus_real(currentReg, src);
+            Instr::UnaryPlusReal i;
+            i.output = currentReg;
+            i.src = src;
             gen(i);
         } else {
             discard();
@@ -445,9 +462,8 @@ void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
         break;
 
     case IR::OpCompl:
-        i.ucompl_real(currentReg, src);
-        gen(i);
-        discard(); // ???
+        // TODO
+        discard();
         break;
 
     case IR::OpBitAnd:
@@ -481,20 +497,18 @@ void QDeclarativeV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
     if (expr->type == IR::RealType)
         return;
 
-    Instr conv;
-    conv.unaryop.output = reg;
-    conv.unaryop.src = reg;
-
     switch (expr->type) {
-    case IR::BoolType:
-        conv.common.type = Instr::ConvertBoolToReal;
-        gen(conv);
-        break;
+    case IR::BoolType: {
+        Instr::ConvertBoolToReal i;
+        i.output = i.src = reg;
+        gen(i);
+        } break;
 
-    case IR::IntType:
-        conv.common.type = Instr::ConvertIntToReal;
-        gen(conv);
-        break;
+    case IR::IntType: {
+        Instr::ConvertIntToReal i;
+        i.output = i.src = reg;
+        gen(i);
+        } break;
 
     case IR::RealType:
         // nothing to do
@@ -511,24 +525,22 @@ void QDeclarativeV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
     if (expr->type == IR::IntType)
         return;
 
-    Instr conv;
-    conv.unaryop.output = reg;
-    conv.unaryop.src = reg;
-
     switch (expr->type) {
-    case IR::BoolType:
-        conv.common.type = Instr::ConvertBoolToInt;
-        gen(conv);
-        break;
+    case IR::BoolType: {
+        Instr::ConvertBoolToInt i;
+        i.output = i.src = reg;
+        gen(i);
+        } break;
 
     case IR::IntType:
         // nothing to do
         return;
 
-    case IR::RealType:
-        conv.common.type = Instr::ConvertRealToInt;
-        gen(conv);
-        break;
+    case IR::RealType: {
+        Instr::ConvertRealToInt i;
+        i.output = i.src = reg;
+        gen(i);
+        } break;
 
     default:
         discard();
@@ -541,29 +553,28 @@ void QDeclarativeV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
     if (expr->type == IR::BoolType)
         return;
 
-    Instr conv;
-    conv.unaryop.output = reg;
-    conv.unaryop.src = reg;
-
     switch (expr->type) {
     case IR::BoolType:
         // nothing to do
         break;
 
-    case IR::IntType:
-        conv.common.type = Instr::ConvertIntToBool;
-        gen(conv);
-        break;
+    case IR::IntType: {
+        Instr::ConvertIntToBool i;
+        i.output = i.src = reg;
+        gen(i);
+        } break;
 
-    case IR::RealType:
-        conv.common.type = Instr::ConvertRealToBool;
-        gen(conv);
-        return;
+    case IR::RealType: {
+        Instr::ConvertRealToBool i;
+        i.output = i.src = reg;
+        gen(i);
+        } return;
 
-    case IR::StringType:
-        conv.common.type = Instr::ConvertStringToBool;
-        gen(conv);
-        return;
+    case IR::StringType: {
+        Instr::ConvertStringToBool i;
+        i.output = i.src = reg;
+        gen(i);
+        } return;
 
     default:
         discard();
@@ -575,97 +586,97 @@ quint8 QDeclarativeV4CompilerPrivate::instructionOpcode(IR::Binop *e)
 {
     switch (e->op) {
     case IR::OpInvalid:
-        return Instr::Noop;
+        return V4Instr::Noop;
 
     case IR::OpIfTrue:
     case IR::OpNot:
     case IR::OpUMinus:
     case IR::OpUPlus:
     case IR::OpCompl:
-        return Instr::Noop;
+        return V4Instr::Noop;
 
     case IR::OpBitAnd:
-        return Instr::BitAndInt;
+        return V4Instr::BitAndInt;
 
     case IR::OpBitOr:
-        return Instr::BitOrInt;
+        return V4Instr::BitOrInt;
 
     case IR::OpBitXor:
-        return Instr::BitXorInt;
+        return V4Instr::BitXorInt;
 
     case IR::OpAdd:
         if (e->type == IR::StringType)
-            return Instr::AddString;
-        return Instr::AddReal;
+            return V4Instr::AddString;
+        return V4Instr::AddReal;
 
     case IR::OpSub:
-        return Instr::SubReal;
+        return V4Instr::SubReal;
 
     case IR::OpMul:
-        return Instr::MulReal;
+        return V4Instr::MulReal;
 
     case IR::OpDiv:
-        return Instr::DivReal;
+        return V4Instr::DivReal;
 
     case IR::OpMod:
-        return Instr::ModReal;
+        return V4Instr::ModReal;
 
     case IR::OpLShift:
-        return Instr::LShiftInt;
+        return V4Instr::LShiftInt;
 
     case IR::OpRShift:
-        return Instr::RShiftInt;
+        return V4Instr::RShiftInt;
 
     case IR::OpURShift:
-        return Instr::URShiftInt;
+        return V4Instr::URShiftInt;
 
     case IR::OpGt:
         if (e->left->type == IR::StringType)
-            return Instr::GtString;
-        return Instr::GtReal;
+            return V4Instr::GtString;
+        return V4Instr::GtReal;
 
     case IR::OpLt:
         if (e->left->type == IR::StringType)
-            return Instr::LtString;
-        return Instr::LtReal;
+            return V4Instr::LtString;
+        return V4Instr::LtReal;
 
     case IR::OpGe:
         if (e->left->type == IR::StringType)
-            return Instr::GeString;
-        return Instr::GeReal;
+            return V4Instr::GeString;
+        return V4Instr::GeReal;
 
     case IR::OpLe:
         if (e->left->type == IR::StringType)
-            return Instr::LeString;
-        return Instr::LeReal;
+            return V4Instr::LeString;
+        return V4Instr::LeReal;
 
     case IR::OpEqual:
         if (e->left->type == IR::StringType)
-            return Instr::EqualString;
-        return Instr::EqualReal;
+            return V4Instr::EqualString;
+        return V4Instr::EqualReal;
 
     case IR::OpNotEqual:
         if (e->left->type == IR::StringType)
-            return Instr::NotEqualString;
-        return Instr::NotEqualReal;
+            return V4Instr::NotEqualString;
+        return V4Instr::NotEqualReal;
 
     case IR::OpStrictEqual:
         if (e->left->type == IR::StringType)
-            return Instr::StrictEqualString;
-        return Instr::StrictEqualReal;
+            return V4Instr::StrictEqualString;
+        return V4Instr::StrictEqualReal;
 
     case IR::OpStrictNotEqual:
         if (e->left->type == IR::StringType)
-            return Instr::StrictNotEqualString;
-        return Instr::StrictNotEqualReal;
+            return V4Instr::StrictNotEqualString;
+        return V4Instr::StrictNotEqualReal;
 
     case IR::OpAnd:
     case IR::OpOr:
-        return Instr::Noop;
+        return V4Instr::Noop;
 
     } // switch
 
-    return Instr::Noop;
+    return V4Instr::Noop;
 }
 
 void QDeclarativeV4CompilerPrivate::visitBinop(IR::Binop *e)
@@ -754,13 +765,12 @@ void QDeclarativeV4CompilerPrivate::visitBinop(IR::Binop *e)
     } // switch
 
     const quint8 opcode = instructionOpcode(e);
-    if (opcode != Instr::Noop) {
-        Instr instr;
-        instr.common.type = opcode;
+    if (opcode != V4Instr::Noop) {
+        V4Instr instr;
         instr.binaryop.output = currentReg;
         instr.binaryop.left = left;
         instr.binaryop.right = right;
-        gen(instr);
+        gen(static_cast<V4Instr::Type>(opcode), instr);
     }
 }
 
@@ -771,37 +781,37 @@ void QDeclarativeV4CompilerPrivate::visitCall(IR::Call *call)
         if (arg != 0 && arg->type == IR::RealType) {
             traceExpression(arg, currentReg);
 
-            Instr instr;
-            instr.common.type = Instr::Noop;
-
             switch (name->builtin) {
             case IR::NoBuiltinSymbol:
                 break;
 
-            case IR::MathSinBultinFunction:
-                instr.math_sin_real(currentReg);
-                break;
-
-            case IR::MathCosBultinFunction:
-                instr.math_cos_real(currentReg);
-                break;
-
-            case IR::MathRoundBultinFunction:
-                instr.math_round_real(currentReg);
-                break;
-
-            case IR::MathFloorBultinFunction:
-                instr.math_floor_real(currentReg);
-                break;
+            case IR::MathSinBultinFunction: {
+                Instr::MathSinReal i;
+                i.output = i.src = currentReg;
+                gen(i);
+                } return;
+
+            case IR::MathCosBultinFunction: {
+                Instr::MathCosReal i;
+                i.output = i.src = currentReg;
+                gen(i);
+                } return;
+
+            case IR::MathRoundBultinFunction: {
+                Instr::MathRoundReal i;
+                i.output = i.src = currentReg;
+                gen(i);
+                } return;
+
+            case IR::MathFloorBultinFunction: {
+                Instr::MathFloorReal i;
+                i.output = i.src = currentReg;
+                gen(i);
+                } return;
 
             case IR::MathPIBuiltinConstant:
                 break;
             } // switch
-
-            if (instr.common.type != Instr::Noop) {
-                gen(instr);
-                return;
-            }
         }
     }
 
@@ -834,47 +844,47 @@ void QDeclarativeV4CompilerPrivate::visitMove(IR::Move *s)
         else
             traceExpression(s->source, dest);
 
-        Instr conv;
-        conv.common.type = Instr::Noop;
+        V4Instr::Type opcode = V4Instr::Noop;
         if (target->type == IR::BoolType) {
             switch (s->source->type) {
-            case IR::IntType: conv.common.type = Instr::ConvertIntToBool; break;
-            case IR::RealType: conv.common.type = Instr::ConvertRealToBool; break;
-            case IR::StringType: conv.common.type = Instr::ConvertStringToBool; break;
+            case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
+            case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
+            case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
             default: break;
             } // switch
         } else if (target->type == IR::IntType) {
             switch (s->source->type) {
-            case IR::BoolType: conv.common.type = Instr::ConvertBoolToInt; break;
+            case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
             case IR::RealType: {
                 if (s->isMoveForReturn)
-                    conv.common.type = Instr::MathRoundReal;
+                    opcode = V4Instr::MathRoundReal;
                 else
-                    conv.common.type = Instr::ConvertRealToInt; 
+                    opcode = V4Instr::ConvertRealToInt;
                 break;
             }
-            case IR::StringType: conv.common.type = Instr::ConvertStringToInt; break;
+            case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
             default: break;
             } // switch
         } else if (target->type == IR::RealType) {
             switch (s->source->type) {
-            case IR::BoolType: conv.common.type = Instr::ConvertBoolToReal; break;
-            case IR::IntType: conv.common.type = Instr::ConvertIntToReal; break;
-            case IR::StringType: conv.common.type = Instr::ConvertStringToReal; break;
+            case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
+            case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
+            case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
             default: break;
             } // switch
         } else if (target->type == IR::StringType) {
             switch (s->source->type) {
-            case IR::BoolType: conv.common.type = Instr::ConvertBoolToString; break;
-            case IR::IntType: conv.common.type = Instr::ConvertIntToString; break;
-            case IR::RealType: conv.common.type = Instr::ConvertRealToString; break;
+            case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
+            case IR::IntType:  opcode = V4Instr::ConvertIntToString; break;
+            case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
             default: break;
             } // switch
         }
-        if (conv.common.type != Instr::Noop) {
+        if (opcode != V4Instr::Noop) {
+            V4Instr conv;
             conv.unaryop.output = dest;
             conv.unaryop.src = src;
-            gen(conv);
+            gen(opcode, conv);
         } else {
             discard();
         }
@@ -887,8 +897,8 @@ void QDeclarativeV4CompilerPrivate::visitJump(IR::Jump *s)
 {
     patches.append(Patch(s->target, bytecode.size()));
 
-    Instr i;
-    i.branch(0); // ### backpatch
+    Instr::Branch i;
+    i.offset = 0; // ### backpatch
     gen(i);
 }
 
@@ -898,8 +908,9 @@ void QDeclarativeV4CompilerPrivate::visitCJump(IR::CJump *s)
 
     patches.append(Patch(s->iftrue, bytecode.size()));
 
-    Instr i;
-    i.branch_true(currentReg, 0); // ### backpatch
+    Instr::BranchTrue i;
+    i.reg = currentReg;
+    i.offset = 0; // ### backpatch
     gen(i);
 }
 
@@ -916,33 +927,32 @@ void QDeclarativeV4CompilerPrivate::visitRet(IR::Ret *s)
     }
 
     if (qmlBindingsTest) {
-        Instr test;
-        test.common.type = Instr::TestV4Store;
-        test.storetest.reg = storeReg;
+        Instr::TestV4Store test;
+        test.reg = storeReg;
         switch (s->type) {
         case IR::StringType:
-            test.storetest.regType = QMetaType::QString;
+            test.regType = QMetaType::QString;
             break;
         case IR::UrlType:
-            test.storetest.regType = QMetaType::QUrl;
+            test.regType = QMetaType::QUrl;
             break;
         case IR::AnchorLineType:
-            test.storetest.regType = qMetaTypeId<QDeclarative1AnchorLine>();
+            test.regType = qMetaTypeId<QDeclarative1AnchorLine>();
             break;
         case IR::SGAnchorLineType:
-            test.storetest.regType = qMetaTypeId<QSGAnchorLine>();
+            test.regType = qMetaTypeId<QSGAnchorLine>();
             break;
         case IR::ObjectType:
-            test.storetest.regType = QMetaType::QObjectStar;
+            test.regType = QMetaType::QObjectStar;
             break;
         case IR::BoolType:
-            test.storetest.regType = QMetaType::Bool;
+            test.regType = QMetaType::Bool;
             break;
         case IR::IntType:
-            test.storetest.regType = QMetaType::Int;
+            test.regType = QMetaType::Int;
             break;
         case IR::RealType:
-            test.storetest.regType = QMetaType::QReal;
+            test.regType = QMetaType::QReal;
             break;
         default:
             discard();
@@ -951,12 +961,11 @@ void QDeclarativeV4CompilerPrivate::visitRet(IR::Ret *s)
         gen(test);
     }
 
-    Instr store;
-    store.common.type = Instr::Store;
-    store.store.output = 0;
-    store.store.index = expression->property->index;
-    store.store.reg = storeReg;
-    store.store.exceptionId = exceptionId(s->line, s->column);
+    Instr::Store store;
+    store.output = 0;
+    store.index = expression->property->index;
+    store.reg = storeReg;
+    store.exceptionId = exceptionId(s->line, s->column);
     gen(store);
 }
 
@@ -971,13 +980,9 @@ void QDeclarativeV4Compiler::dump(const QByteArray &programData)
 
     const int programSize = program->instructionCount;
     const char *start = program->instructions();
-    const char *code = start;
-    const char *end = code + programSize;
-    while (code < end) {
-        Instr *instr = (Instr *) code;
-        instr->dump(code - start);
-        code += instr->size();
-    }
+    const char *end = start + programSize;
+    Bytecode bc;
+    bc.dump(start, end);
 }
 
 /*!
@@ -1079,11 +1084,10 @@ int QDeclarativeV4CompilerPrivate::registerLiteralString(quint8 reg, const QStri
     int offset = data.count();
     data += strdata;
 
-    Instr string;
-    string.common.type = Instr::String;
-    string.string_value.reg = reg;
-    string.string_value.offset = offset;
-    string.string_value.length = str.length();
+    Instr::LoadString string;
+    string.reg = reg;
+    string.offset = offset;
+    string.length = str.length();
     gen(string);
 
     return reg;
@@ -1108,12 +1112,11 @@ int QDeclarativeV4CompilerPrivate::registerString(const QString &string)
         *iter = qMakePair(registeredStrings.count(), rv);
     } 
 
-    Instr reg;
-    reg.common.type = Instr::InitString;
-    reg.initstring.offset = iter->first;
-    reg.initstring.dataIdx = iter->second;
+    Instr::InitString reg;
+    reg.offset = iter->first;
+    reg.dataIdx = iter->second;
     gen(reg);
-    return reg.initstring.offset;
+    return reg.offset;
 }
 
 /*!
@@ -1275,14 +1278,13 @@ QByteArray QDeclarativeV4Compiler::program() const
         prog.bindings = d->committed.count();
 
         Bytecode bc;
-        Instr jump;
-        jump.common.type = Instr::Jump;
-        jump.jump.reg = -1;
+        QDeclarativeV4CompilerPrivate::Instr::Jump jump;
+        jump.reg = -1;
 
         for (int ii = 0; ii < d->committed.count(); ++ii) {
-            jump.jump.count = d->committed.count() - ii - 1;
-            jump.jump.count*= jump.size();
-            jump.jump.count+= d->committed.offsets.at(ii);
+            jump.count = d->committed.count() - ii - 1;
+            jump.count*= V4InstrMeta<V4Instr::Jump>::Size;
+            jump.count+= d->committed.offsets.at(ii);
             bc.append(jump);
         }
 
index eab609a..aba713b 100644 (file)
@@ -209,8 +209,15 @@ public:
     void convertToBool(QDeclarativeJS::IR::Expr *expr, int reg);
     quint8 instructionOpcode(QDeclarativeJS::IR::Binop *e);
 
-protected:
+    struct Instr {
+#define QML_V4_INSTR_DATA_TYPEDEF(I, FMT) typedef QDeclarativeJS::V4InstrData<QDeclarativeJS::V4Instr::I> I;
+    FOR_EACH_V4_INSTR(QML_V4_INSTR_DATA_TYPEDEF)
+#undef QML_v4_INSTR_DATA_TYPEDEF
+    private:
+        Instr();
+    };
 
+protected:
     //
     // tracing
     //
@@ -218,7 +225,14 @@ protected:
     void trace(QVector<QDeclarativeJS::IR::BasicBlock *> *blocks);
     void traceExpression(QDeclarativeJS::IR::Expr *e, quint8 r);
 
-    inline void gen(const QDeclarativeJS::Instr &i) { bytecode.append(i); }
+    template <int Instr>
+    inline void gen(const QDeclarativeJS::V4InstrData<Instr> &i)
+    { bytecode.append(i); }
+    inline void gen(QDeclarativeJS::V4Instr::Type type, QDeclarativeJS::V4Instr &instr)
+    { bytecode.append(type, instr); }
+
+    inline QDeclarativeJS::V4Instr::Type instructionType(const QDeclarativeJS::V4Instr *i) const
+    { return bytecode.instructionType(i); }
 
     //
     // expressions
index dd68923..6ae28f9 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
-
 namespace QDeclarativeJS {
 
 #ifdef DEBUG_INSTR_DUMP
 static struct DumpInstrAtStartup {
     DumpInstrAtStartup() {
-#define DUMP_INSTR_AT_STARTUP(Type, FMT) { Instr i; i.common.type = Instr::Type; i.dump(0); }
+        Bytecode bc;
+#define DUMP_INSTR_AT_STARTUP(I, FMT) { V4InstrData<V4Instr::I> i; bc.append(i); }
         FOR_EACH_V4_INSTR(DUMP_INSTR_AT_STARTUP);
+#undef DUMP_INSTR_AT_STARTUP
+        const char *start = bc.constData();
+        const char *end = start + bc.size();
+        bc.dump(start, end);
     }
 } dump_instr_at_startup;
 #endif
 
-int Instr::size() const
+int V4Instr::size(Type type)
 {
 #define V4_RETURN_INSTR_SIZE(I, FMT) case I: return QML_V4_INSTR_SIZE(I, FMT);
-    switch (common.type) {
+    switch (type) {
     FOR_EACH_V4_INSTR(V4_RETURN_INSTR_SIZE)
     }
 #undef V4_RETURN_INSTR_SIZE
     return 0;
 }
 
-void Instr::dump(int address) const
+void Bytecode::dump(const V4Instr *i, int address) const
 {
     QByteArray leading;
     if (address != -1) {
@@ -86,241 +89,241 @@ void Instr::dump(int address) const
 
 #define INSTR_DUMP qWarning().nospace() << leading.constData() 
 
-    switch (common.type) {
-    case Instr::Noop:
+    switch (instructionType(i)) {
+    case V4Instr::Noop:
         INSTR_DUMP << "\t" << "Noop";
         break;
-    case Instr::BindingId:
-        INSTR_DUMP << id.line << ":" << id.column << ":";
+    case V4Instr::BindingId:
+        INSTR_DUMP << i->id.line << ":" << i->id.column << ":";
         break;
-    case Instr::Subscribe:
-        INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << subscribeop.reg << ") Notify_Signal(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+    case V4Instr::Subscribe:
+        INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << i->subscribeop.reg << ") Notify_Signal(" << i->subscribeop.index << ") -> Subscribe_Slot(" << i->subscribeop.offset << ")";
         break;
-    case Instr::SubscribeId:
-        INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+    case V4Instr::SubscribeId:
+        INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << i->subscribeop.index << ") -> Subscribe_Slot(" << i->subscribeop.offset << ")";
         break;
-    case Instr::FetchAndSubscribe:
-        INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << fetchAndSubscribe.reg << ") Fast_Accessor(" << fetchAndSubscribe.function << ") -> Output_Reg(" << fetchAndSubscribe.reg << ") Subscription_Slot(" <<  fetchAndSubscribe.subscription << ")";
+    case V4Instr::FetchAndSubscribe:
+        INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << i->fetchAndSubscribe.reg << ") Fast_Accessor(" << i->fetchAndSubscribe.function << ") -> Output_Reg(" << i->fetchAndSubscribe.reg << ") Subscription_Slot(" <<  i->fetchAndSubscribe.subscription << ")";
         break;
-    case Instr::LoadId:
-        INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << load.index << ") -> Output_Reg(" << load.reg << ")";
+    case V4Instr::LoadId:
+        INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << i->load.index << ") -> Output_Reg(" << i->load.reg << ")";
         break;
-    case Instr::LoadScope:
-        INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+    case V4Instr::LoadScope:
+        INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << i->load.reg << ")";
         break;
-    case Instr::LoadRoot:
-        INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+    case V4Instr::LoadRoot:
+        INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << i->load.reg << ")";
         break;
-    case Instr::LoadAttached:
-        INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << attached.reg << ") Attached_Index(" << attached.id << ") -> Output_Reg(" << attached.output << ")";
+    case V4Instr::LoadAttached:
+        INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << i->attached.reg << ") Attached_Index(" << i->attached.id << ") -> Output_Reg(" << i->attached.output << ")";
         break;
-    case Instr::UnaryNot:
-        INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::UnaryNot:
+        INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::UnaryMinusReal:
-        INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::UnaryMinusReal:
+        INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::UnaryMinusInt:
-        INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::UnaryMinusInt:
+        INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::UnaryPlusReal:
-        INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::UnaryPlusReal:
+        INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::UnaryPlusInt:
-        INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::UnaryPlusInt:
+        INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertBoolToInt:
-        INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertBoolToInt:
+        INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertBoolToReal:
-        INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertBoolToReal:
+        INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertBoolToString:
-        INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertBoolToString:
+        INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertIntToBool:
-        INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertIntToBool:
+        INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertIntToReal:
-        INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertIntToReal:
+        INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertIntToString:
-        INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertIntToString:
+        INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertRealToBool:
-        INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertRealToBool:
+        INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertRealToInt:
-        INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertRealToInt:
+        INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertRealToString:
-        INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertRealToString:
+        INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertStringToBool:
-        INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertStringToBool:
+        INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertStringToInt:
-        INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertStringToInt:
+        INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::ConvertStringToReal:
-        INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::ConvertStringToReal:
+        INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::MathSinReal:
-        INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::MathSinReal:
+        INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::MathCosReal:
-        INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::MathCosReal:
+        INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::MathRoundReal:
-        INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::MathRoundReal:
+        INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::MathFloorReal:
-        INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::MathFloorReal:
+        INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::MathPIReal:
-        INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+    case V4Instr::MathPIReal:
+        INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
         break;
-    case Instr::Real:
-        INSTR_DUMP << "\t" << "Real" << "\t\t\t" << "Constant(" << real_value.value << ") -> Output_Reg(" << real_value.reg << ")";
+    case V4Instr::LoadReal:
+        INSTR_DUMP << "\t" << "LoadReal" << "\t\t" << "Constant(" << i->real_value.value << ") -> Output_Reg(" << i->real_value.reg << ")";
         break;
-    case Instr::Int:
-        INSTR_DUMP << "\t" << "Int" << "\t\t\t" << "Constant(" << int_value.value << ") -> Output_Reg(" << int_value.reg << ")";
+    case V4Instr::LoadInt:
+        INSTR_DUMP << "\t" << "LoadInt" << "\t\t\t" << "Constant(" << i->int_value.value << ") -> Output_Reg(" << i->int_value.reg << ")";
         break;
-    case Instr::Bool:
-        INSTR_DUMP << "\t" << "Bool" << "\t\t\t" << "Constant(" << bool_value.value << ") -> Output_Reg(" << bool_value.reg << ")";
+    case V4Instr::LoadBool:
+        INSTR_DUMP << "\t" << "LoadBool" << "\t\t" << "Constant(" << i->bool_value.value << ") -> Output_Reg(" << i->bool_value.reg << ")";
         break;
-    case Instr::String:
-        INSTR_DUMP << "\t" << "String" << "\t\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ") -> Output_Register(" << string_value.reg << ")";
+    case V4Instr::LoadString:
+        INSTR_DUMP << "\t" << "LoadString" << "\t\t" << "String_DataIndex(" << i->string_value.offset << ") String_Length(" << i->string_value.length << ") -> Output_Register(" << i->string_value.reg << ")";
         break;
-    case Instr::EnableV4Test:
-        INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ")";
+    case V4Instr::EnableV4Test:
+        INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << i->string_value.offset << ") String_Length(" << i->string_value.length << ")";
         break;
-    case Instr::TestV4Store:
-        INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << storetest.reg << ") Reg_Type(" << storetest.regType << ")";
+    case V4Instr::TestV4Store:
+        INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << i->storetest.reg << ") Reg_Type(" << i->storetest.regType << ")";
         break;
-    case Instr::BitAndInt:
-        INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::BitAndInt:
+        INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::BitOrInt:
-        INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::BitOrInt:
+        INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::BitXorInt:
-        INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::BitXorInt:
+        INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::AddReal:
-        INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::AddReal:
+        INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::AddString:
-        INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::AddString:
+        INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::SubReal:
-        INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::SubReal:
+        INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::MulReal:
-        INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::MulReal:
+        INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::DivReal:
-        INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::DivReal:
+        INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::ModReal:
-        INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::ModReal:
+        INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::LShiftInt:
-        INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::LShiftInt:
+        INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::RShiftInt:
-        INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::RShiftInt:
+        INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::URShiftInt:
-        INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::URShiftInt:
+        INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::GtReal:
-        INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::GtReal:
+        INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::LtReal:
-        INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::LtReal:
+        INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::GeReal:
-        INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::GeReal:
+        INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::LeReal:
-        INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::LeReal:
+        INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::EqualReal:
-        INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::EqualReal:
+        INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::NotEqualReal:
-        INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::NotEqualReal:
+        INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::StrictEqualReal:
-        INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::StrictEqualReal:
+        INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::StrictNotEqualReal:
-        INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::StrictNotEqualReal:
+        INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::GtString:
-        INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::GtString:
+        INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::LtString:
-        INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::LtString:
+        INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::GeString:
-        INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::GeString:
+        INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::LeString:
-        INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::LeString:
+        INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::EqualString:
-        INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::EqualString:
+        INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::NotEqualString:
-        INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::NotEqualString:
+        INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::StrictEqualString:
-        INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::StrictEqualString:
+        INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::StrictNotEqualString:
-        INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+    case V4Instr::StrictNotEqualString:
+        INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
         break;
-    case Instr::NewString:
-        INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << construct.reg << ")";
+    case V4Instr::NewString:
+        INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << i->construct.reg << ")";
         break;
-    case Instr::NewUrl:
-        INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << construct.reg << ")";
+    case V4Instr::NewUrl:
+        INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << i->construct.reg << ")";
         break;
-    case Instr::CleanupRegister:
-        INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << cleanup.reg << ")";
+    case V4Instr::CleanupRegister:
+        INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << i->cleanup.reg << ")";
         break;
-    case Instr::Fetch:
-        INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << fetch.reg << ") Property_Index(" << fetch.index << ") -> Output_Reg(" << fetch.reg << ")";
+    case V4Instr::Fetch:
+        INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << i->fetch.reg << ") Property_Index(" << i->fetch.index << ") -> Output_Reg(" << i->fetch.reg << ")";
         break;
-    case Instr::Store:
-        INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << store.reg << ") -> Object_Reg(" << store.output << ") Property_Index(" << store.index << ")";
+    case V4Instr::Store:
+        INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << i->store.reg << ") -> Object_Reg(" << i->store.output << ") Property_Index(" << i->store.index << ")";
         break;
-    case Instr::Copy:
-        INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << copy.src << ") -> Output_Reg(" << copy.reg << ")";
+    case V4Instr::Copy:
+        INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << i->copy.src << ") -> Output_Reg(" << i->copy.reg << ")";
         break;
-    case Instr::Jump:
-        if (jump.reg != -1) {
-            INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ") [if false == Input_Reg(" << jump.reg << ")]";
+    case V4Instr::Jump:
+        if (i->jump.reg != -1) {
+            INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + i->jump.count) << ") [if false == Input_Reg(" << i->jump.reg << ")]";
         } else {
-            INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ")";
+            INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + i->jump.count) << ")";
         }
         break;
-    case Instr::BranchFalse:
-        INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if false == Input_Reg(" << branchop.reg << ")]";
+    case V4Instr::BranchFalse:
+        INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + i->branchop.offset) << ") [if false == Input_Reg(" << i->branchop.reg << ")]";
         break;
-    case Instr::BranchTrue:
-        INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if true == Input_Reg(" << branchop.reg << ")]";
+    case V4Instr::BranchTrue:
+        INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + i->branchop.offset) << ") [if true == Input_Reg(" << i->branchop.reg << ")]";
         break;
-    case Instr::Branch:
-        INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + branchop.offset) << ")";
+    case V4Instr::Branch:
+        INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + i->branchop.offset) << ")";
         break;
-    case Instr::InitString:
-        INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << initstring.dataIdx << ") -> String_Slot(" << initstring.offset << ")";
+    case V4Instr::InitString:
+        INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << i->initstring.dataIdx << ") -> String_Slot(" << i->initstring.offset << ")";
         break;
-    case Instr::Block:
-        INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(blockop.block, 16).constData()  << ")";
+    case V4Instr::Block:
+        INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(i->blockop.block, 16).constData()  << ")";
         break;
     default:
         INSTR_DUMP << "\t" << "Unknown";
@@ -328,224 +331,68 @@ void Instr::dump(int address) const
     }
 }
 
-void Instr::noop()
-{
-    common.type = Noop;
-}
-
-void Instr::load_root(quint8 reg)
-{
-    common.type = LoadRoot;
-    load.reg = reg;
-    load.index = 0;
-}
-
-void Instr::load_scope(quint8 reg)
-{
-    common.type = LoadScope;
-    load.reg = reg;
-    load.index = 0;
-}
-
-void Instr::load_id(quint8 reg, quint32 idIndex)
-{
-    common.type = LoadId;
-    load.reg = reg;
-    load.index = idIndex;
-}
-
-void Instr::subscribe(qint8 reg, quint16 subscribeSlot, quint32 notifyIndex)
-{
-    common.type = Instr::Subscribe;
-    subscribeop.reg = reg;
-    subscribeop.offset = subscribeSlot;
-    subscribeop.index = notifyIndex; 
-}
-
-void Instr::subscribeId(qint8 reg, quint16 subscribeSlot, quint32 idIndex)
-{
-    common.type = Instr::SubscribeId;
-    subscribeop.reg = reg;
-    subscribeop.offset = subscribeSlot;
-    subscribeop.index = idIndex;
-}
-
-void Instr::move_reg_bool(quint8 reg, bool value)
-{
-    common.type = Bool;
-    bool_value.reg = reg;
-    bool_value.value = value;
-}
-
-void Instr::move_reg_int(quint8 reg, int value)
-{
-    common.type = Int;
-    int_value.reg = reg;
-    int_value.value = value;
-}
-
-void Instr::move_reg_qreal(quint8 reg, qreal value)
-{
-    common.type = Real;
-    real_value.reg = reg;
-    real_value.value = value;
-}
-
-void Instr::move_reg_reg(quint8 reg, quint8 src)
-{
-    common.type = Copy;
-    copy.reg = reg;
-    copy.src = src;
-}
-
-void Instr::unary_not(quint8 dest, quint8 src)
-{
-    common.type = UnaryNot;
-    unaryop.src = src;
-    unaryop.output = dest;
-}
-
-void Instr::uminus_real(quint8 dest, quint8 src)
-{
-    common.type = UnaryMinusReal;
-    unaryop.src = src;
-    unaryop.output = dest;
-}
-
-void Instr::uminus_int(quint8 dest, quint8 src)
-{
-    common.type = UnaryMinusInt;
-    unaryop.src = src;
-    unaryop.output = dest;
-}
-
-void Instr::uplus_real(quint8 dest, quint8 src)
-{
-    common.type = UnaryPlusReal;
-    unaryop.src = src;
-    unaryop.output = dest;
-}
-
-void Instr::uplus_int(quint8 dest, quint8 src)
-{
-    common.type = UnaryPlusInt;
-    unaryop.src = src;
-    unaryop.output = dest;
-}
-
-void Instr::ucompl_real(quint8 dest, quint8 src)
-{
-    Q_UNUSED(dest);
-    Q_UNUSED(src);
-    if (qmlVerboseCompiler())
-        qWarning() << "TODO" << Q_FUNC_INFO;
-}
-
-void Instr::ucompl_int(quint8 dest, quint8 src)
-{
-    Q_UNUSED(dest);
-    Q_UNUSED(src);
-    if (qmlVerboseCompiler())
-        qWarning() << "TODO" << Q_FUNC_INFO;
-}
-
-void Instr::math_sin_real(quint8 reg)
+void Bytecode::dump(const char *start, const char *end) const
 {
-    common.type = MathSinReal;
-    unaryop.src = reg;
-    unaryop.output = reg;
-}
-
-void Instr::math_cos_real(quint8 reg)
-{
-    common.type = MathCosReal;
-    unaryop.src = reg;
-    unaryop.output = reg;
-}
-
-void Instr::math_round_real(quint8 reg)
-{
-    common.type = MathRoundReal;
-    unaryop.src = reg;
-    unaryop.output = reg;
-}
-
-void Instr::math_floor_real(quint8 reg)
-{
-    common.type = MathFloorReal;
-    unaryop.src = reg;
-    unaryop.output = reg;
-}
-
-void Instr::math_pi_real(quint8 reg)
-{
-    common.type = MathPIReal;
-    unaryop.src = reg;
-    unaryop.output = reg;
-}
-
-void Instr::branch_true(quint8 reg, qint16 offset)
-{
-    common.type = BranchTrue;
-    branchop.reg = reg;
-    branchop.offset = offset;
+    const char *code = start;
+    while (code < end) {
+        const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
+        dump(instr, code - start);
+        code += V4Instr::size(instructionType(instr));
+    }
 }
 
-void Instr::branch_false(quint8 reg, qint16 offset)
+Bytecode::Bytecode()
 {
-    common.type = BranchFalse;
-    branchop.reg = reg;
-    branchop.offset = offset;
+#ifdef QML_THREADED_INTERPRETER
+    decodeInstr = QDeclarativeV4Bindings::getDecodeInstrTable();
+#endif
 }
 
-void Instr::branch(qint16 offset)
+V4Instr::Type Bytecode::instructionType(const V4Instr *instr) const
 {
-    common.type = Branch;
-    branchop.offset = offset;
-}
+#ifdef QML_THREADED_INTERPRETER
+    void *code = instr->common.code;
 
-void Instr::block(quint32 mask)
-{
-    common.type = Block;
-    blockop.block = mask;
-}
+#  define CHECK_V4_INSTR_CODE(I, FMT) \
+    if (decodeInstr[static_cast<int>(V4Instr::I)] == code) \
+        return V4Instr::I;
 
-Bytecode::Bytecode()
-{
-#ifdef QML_THREADED_INTERPRETER
-    decodeInstr = QDeclarativeV4Bindings::getDecodeInstrTable();
+    FOR_EACH_V4_INSTR(CHECK_V4_INSTR_CODE)
+    Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid instruction address");
+    return static_cast<V4Instr::Type>(0);
+#  undef CHECK_V4_INSTR_CODE
+#else
+    return static_cast<V4Instr::Type>(instr.common.type);
 #endif
+
 }
 
-void Bytecode::append(const Instr &instr)
+void Bytecode::append(V4Instr::Type type, V4Instr &instr)
 {
-    const char *it;
 #ifdef QML_THREADED_INTERPRETER
-    Instr i = instr;
-    i.common.code = decodeInstr[i.common.type];
-    it = (const char *) &i;
+    instr.common.code = decodeInstr[static_cast<int>(type)];
 #else
-    it = (const char *) &instr;
+    instr.common.type = type;
 #endif
-    d.append(it, instr.size());
+    d.append(reinterpret_cast<const char *>(&instr), V4Instr::size(type));
 }
 
 int Bytecode::remove(int offset)
 {
-    const Instr *instr = (const Instr *) (d.begin() + offset);
-    const int instrSize = instr->size();
+    const V4Instr *instr = reinterpret_cast<const V4Instr *>(d.begin() + offset);
+    const int instrSize = V4Instr::size(instructionType(instr));
     d.remove(offset, instrSize);
     return instrSize;
 }
 
-const Instr &Bytecode::operator[](int offset) const
+const V4Instr &Bytecode::operator[](int offset) const
 {
-    return *((const Instr *) (d.begin() + offset));
+    return *(reinterpret_cast<const V4Instr *>(d.begin() + offset));
 }
 
-Instr &Bytecode::operator[](int offset)
+V4Instr &Bytecode::operator[](int offset)
 {
-    return *((Instr *) (d.begin() + offset));
+    return *(reinterpret_cast<V4Instr *>(d.begin() + offset));
 }
 
 }
index 6efe933..46336b4 100644 (file)
@@ -94,10 +94,10 @@ QT_BEGIN_NAMESPACE
     F(MathRoundReal, unaryop) \
     F(MathFloorReal, unaryop) \
     F(MathPIReal, unaryop) \
-    F(Real, real_value) \
-    F(Int, int_value) \
-    F(Bool, bool_value) \
-    F(String, string_value) \
+    F(LoadReal, real_value) \
+    F(LoadInt, int_value) \
+    F(LoadBool, bool_value) \
+    F(LoadString, string_value) \
     F(EnableV4Test, string_value) \
     F(TestV4Store, storetest) \
     F(BitAndInt, binaryop) \
@@ -147,85 +147,52 @@ QT_BEGIN_NAMESPACE
 #endif
 
 #ifdef Q_ALIGNOF
-#  define QML_V4_INSTR_ALIGN_MASK (Q_ALIGNOF(Instr) - 1)
+#  define QML_V4_INSTR_ALIGN_MASK (Q_ALIGNOF(V4Instr) - 1)
 #else
 #  define QML_V4_INSTR_ALIGN_MASK (sizeof(void *) - 1)
 #endif
 
 #define QML_V4_INSTR_ENUM(I, FMT) I,
 #define QML_V4_INSTR_ADDR(I, FMT) &&op_##I,
-#define QML_V4_INSTR_SIZE(I, FMT) ((sizeof(Instr::instr_##FMT) + QML_V4_INSTR_ALIGN_MASK) & ~QML_V4_INSTR_ALIGN_MASK)
+#define QML_V4_INSTR_SIZE(I, FMT) ((sizeof(V4Instr::instr_##FMT) + QML_V4_INSTR_ALIGN_MASK) & ~QML_V4_INSTR_ALIGN_MASK)
 
 #ifdef QML_THREADED_INTERPRETER
 #  define QML_V4_BEGIN_INSTR(I,FMT) op_##I:
-#  define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const Instr *) code; goto *instr->common.code;
+#  define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const V4Instr *) code; goto *instr->common.code;
 #  define QML_V4_INSTR_HEADER void *code;
 #else
 #  define QML_V4_BEGIN_INSTR(I,FMT) case Instr::I:
-#  define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const Instr *) code; break;
-#  define QML_V4_INSTR_HEADER
+#  define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const V4Instr *) code; break;
+#  define QML_V4_INSTR_HEADER quint8 type;
 #endif
 
 namespace QDeclarativeJS {
 
-union Instr {
-    int size() const;
-    void dump(int = -1) const;
-    void noop();
-    void load_root(quint8 reg);
-    void load_scope(quint8 reg);
-    void load_id(quint8 reg, quint32 idIndex);
-    void subscribe(qint8 reg, quint16 offset, quint32 index);
-    void subscribeId(qint8 reg, quint16 offset, quint32 index);
-    void move_reg_bool(quint8 reg, bool value);
-    void move_reg_int(quint8 reg, int value);
-    void move_reg_qreal(quint8 reg, qreal value);
-    void move_reg_reg(quint8 reg, quint8 src);
-
-    void unary_not(quint8 dest, quint8 src);
-    void uminus_real(quint8 dest, quint8 src);
-    void uminus_int(quint8 dest, quint8 src);
-    void uplus_real(quint8 dest, quint8 src);
-    void uplus_int(quint8 dest, quint8 src);
-    void ucompl_real(quint8 dest, quint8 src);
-    void ucompl_int(quint8 dest, quint8 src);
-
-    void math_sin_real(quint8 reg);
-    void math_cos_real(quint8 reg);
-    void math_round_real(quint8 reg);
-    void math_floor_real(quint8 reg);
-    void math_pi_real(quint8 reg);
-    void branch_true(quint8 reg, qint16 offset);
-    void branch_false(quint8 reg, qint16 offset);
-    void branch(qint16 offset);
-    void block(quint32 mask);
-
-    enum {
+union V4Instr {
+    enum Type {
         FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM)
     };
 
+    static int size(Type type);
+
     struct instr_common {
         QML_V4_INSTR_HEADER
-        quint8 type;
     };
 
     struct instr_id {
         QML_V4_INSTR_HEADER
-        quint8 type;
         quint16 column;
         quint32 line;
     };
 
     struct instr_init {
         QML_V4_INSTR_HEADER
-        quint8 type;
         quint16 subscriptions;
         quint16 identifiers;
     };
 
     struct instr_subscribeop {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         quint16 offset;
         quint32 index;
@@ -233,14 +200,12 @@ union Instr {
 
     struct instr_load {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         quint32 index;
     };
 
     struct instr_attached {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 output;
         qint8 reg;
         quint8 exceptionId;
@@ -249,7 +214,6 @@ union Instr {
 
     struct instr_store {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 output;
         qint8 reg;
         quint8 exceptionId;
@@ -258,14 +222,12 @@ union Instr {
 
     struct instr_storetest {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         qint32 regType;
     };
 
     struct instr_fetchAndSubscribe {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         quint8 exceptionId;
         quint8 valueType;
@@ -275,7 +237,6 @@ union Instr {
 
     struct instr_fetch{
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         quint8 exceptionId;
         quint8 valueType;
@@ -284,41 +245,35 @@ union Instr {
 
     struct instr_copy {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         qint8 src;
     };
 
     struct instr_construct {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
     };
 
     struct instr_real_value {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         qreal value; // XXX Makes the instruction 12 bytes
     };
 
     struct instr_int_value {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         int value;
     };
 
     struct instr_bool_value {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         bool value;
     };
 
     struct instr_string_value {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         quint16 length;
         quint32 offset;
@@ -326,7 +281,6 @@ union Instr {
 
     struct instr_binaryop {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 output;
         qint8 left;
         qint8 right;
@@ -334,21 +288,18 @@ union Instr {
 
     struct instr_unaryop {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 output;
         qint8 src;
     };
 
     struct instr_jump {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         quint32 count;
     };
 
     struct instr_find {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
         qint8 src;
         quint8 exceptionId;
@@ -358,27 +309,23 @@ union Instr {
 
     struct instr_cleanup {
         QML_V4_INSTR_HEADER
-        quint8 type;
         qint8 reg;
     };
 
     struct instr_initstring {
         QML_V4_INSTR_HEADER
-        quint8 type;
         quint16 offset;
         quint32 dataIdx;
     };
 
     struct instr_branchop {
         QML_V4_INSTR_HEADER
-        quint8 type;
         quint8 reg;
         qint16 offset;
     };
 
     struct instr_blockop {
         QML_V4_INSTR_HEADER
-        quint8 type;
         quint32 block;
     };
 
@@ -408,6 +355,25 @@ union Instr {
     instr_blockop blockop;
 };
 
+template<int N>
+struct V4InstrMeta {
+};
+
+#define QML_V4_INSTR_META_TEMPLATE(I, FMT) \
+    template<> struct V4InstrMeta<(int)V4Instr::I> { \
+        enum { Size = QML_V4_INSTR_SIZE(I, FMT) }; \
+        typedef V4Instr::instr_##FMT DataType; \
+        static const DataType &data(const V4Instr &instr) { return instr.FMT; } \
+        static void setData(V4Instr &instr, const DataType &v) { instr.FMT = v; } \
+    };
+FOR_EACH_V4_INSTR(QML_V4_INSTR_META_TEMPLATE);
+#undef QML_V4_INSTR_META_TEMPLATE
+
+template<int Instr>
+class V4InstrData : public V4InstrMeta<Instr>::DataType
+{
+};
+
 class Bytecode
 {
     Q_DISABLE_COPY(Bytecode)
@@ -420,21 +386,27 @@ public:
     int count() const { return d.count(); }
     void clear() { d.clear(); }
     bool isEmpty() const { return d.isEmpty(); }
-    void append(const Instr &instr);
+    V4Instr::Type instructionType(const V4Instr *instr) const;
 
-    template <typename _It>
-    void append(_It it, _It last)
+    template <int Instr>
+    void append(const V4InstrData<Instr> &data)
     {
-        for (; it != last; ++it)
-            append(*it);
+        V4Instr genericInstr;
+        V4InstrMeta<Instr>::setData(genericInstr, data);
+        return append(static_cast<V4Instr::Type>(Instr), genericInstr);
     }
+    void append(V4Instr::Type type, V4Instr &instr);
 
     int remove(int index);
 
-    const Instr &operator[](int offset) const;
-    Instr &operator[](int offset);
+    const V4Instr &operator[](int offset) const;
+    V4Instr &operator[](int offset);
+
+    void dump(const char *start, const char *end) const;
 
 private:
+    void dump(const V4Instr *instr, int = -1) const;
+
     QVarLengthArray<char, 4 * 1024> d;
 #ifdef QML_THREADED_INTERPRETER
     void **decodeInstr;