Move common code from various ISel backends into a common base-class.
authorErik Verbruggen <erik.verbruggen@me.com>
Sun, 13 Jan 2013 21:17:26 +0000 (22:17 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Tue, 15 Jan 2013 15:26:54 +0000 (16:26 +0100)
Note: all warnings are due to backends that do not fully implement the
required virtual methods. Or, rephrasing: these backends need work to
get them up-to-speed/quality for all methods that do have warnings.

Change-Id: Ib713f3d76832af42ebe893ad2896eec4bdd4bccb
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
moth/qv4isel_moth.cpp
moth/qv4isel_moth_p.h
qv4isel_llvm.cpp
qv4isel_llvm_p.h
qv4isel_masm.cpp
qv4isel_masm_p.h
qv4isel_p.cpp
qv4isel_p.h

index 6f06fe9..bfc04a3 100644 (file)
@@ -191,6 +191,74 @@ private:
     int _pinnedCount;
 };
 
+typedef VM::Value (*ALUFunction)(const VM::Value, const VM::Value, VM::ExecutionContext*);
+inline ALUFunction aluOpFunction(IR::AluOp op)
+{
+    switch (op) {
+    case IR::OpInvalid:
+        return 0;
+    case IR::OpIfTrue:
+        return 0;
+    case IR::OpNot:
+        return 0;
+    case IR::OpUMinus:
+        return 0;
+    case IR::OpUPlus:
+        return 0;
+    case IR::OpCompl:
+        return 0;
+    case IR::OpBitAnd:
+        return VM::__qmljs_bit_and;
+    case IR::OpBitOr:
+        return VM::__qmljs_bit_or;
+    case IR::OpBitXor:
+        return VM::__qmljs_bit_xor;
+    case IR::OpAdd:
+        return VM::__qmljs_add;
+    case IR::OpSub:
+        return VM::__qmljs_sub;
+    case IR::OpMul:
+        return VM::__qmljs_mul;
+    case IR::OpDiv:
+        return VM::__qmljs_div;
+    case IR::OpMod:
+        return VM::__qmljs_mod;
+    case IR::OpLShift:
+        return VM::__qmljs_shl;
+    case IR::OpRShift:
+        return VM::__qmljs_shr;
+    case IR::OpURShift:
+        return VM::__qmljs_ushr;
+    case IR::OpGt:
+        return VM::__qmljs_gt;
+    case IR::OpLt:
+        return VM::__qmljs_lt;
+    case IR::OpGe:
+        return VM::__qmljs_ge;
+    case IR::OpLe:
+        return VM::__qmljs_le;
+    case IR::OpEqual:
+        return VM::__qmljs_eq;
+    case IR::OpNotEqual:
+        return VM::__qmljs_ne;
+    case IR::OpStrictEqual:
+        return VM::__qmljs_se;
+    case IR::OpStrictNotEqual:
+        return VM::__qmljs_sne;
+    case IR::OpInstanceof:
+        return VM::__qmljs_instanceof;
+    case IR::OpIn:
+        return VM::__qmljs_in;
+    case IR::OpAnd:
+        return 0;
+    case IR::OpOr:
+        return 0;
+    default:
+        assert(!"Unknown AluOp");
+        return 0;
+    }
+};
+
 } // anonymous namespace
 
 InstructionSelection::InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module)
@@ -269,8 +337,10 @@ void InstructionSelection::run(VM::Function *vmFunction, IR::Function *function)
     qSwap(ccode, _ccode);
 }
 
-void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempIndex)
+void InstructionSelection::callActivationProperty(IR::Call *c, IR::Temp *temp)
 {
+    const int targetTempIndex = temp ? temp->index : scratchTempIndex();
+;
     IR::Name *baseName = c->base->asName();
     Q_ASSERT(baseName);
 
@@ -465,8 +535,9 @@ void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempInd
     }
 }
 
-void InstructionSelection::callValue(IR::Call *c, int targetTempIndex)
+void InstructionSelection::callValue(IR::Call *c, IR::Temp *temp)
 {
+    const int targetTempIndex = temp ? temp->index : scratchTempIndex();
     IR::Temp *t = c->base->asTemp();
     Q_ASSERT(t);
 
@@ -477,8 +548,9 @@ void InstructionSelection::callValue(IR::Call *c, int targetTempIndex)
     addInstruction(call);
 }
 
-void InstructionSelection::callProperty(IR::Call *c, int targetTempIndex)
+void InstructionSelection::callProperty(IR::Call *c, IR::Temp *temp)
 {
+    const int targetTempIndex = temp ? temp->index : scratchTempIndex();
     IR::Member *m = c->base->asMember();
     Q_ASSERT(m);
 
@@ -491,35 +563,257 @@ void InstructionSelection::callProperty(IR::Call *c, int targetTempIndex)
     addInstruction(call);
 }
 
-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();
-        assert(base != 0);
-
-        Instruction::CreateProperty create;
-        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);
+void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result)
+{
+    Instruction::CreateActivationProperty create;
+    create.name = engine()->newString(*call->base->asName()->id);
+    prepareCallArgs(call->args, create.argc, create.args);
+    create.targetTempIndex = result->index;
+    addInstruction(create);
+}
+
+void InstructionSelection::constructProperty(IR::New *call, IR::Temp *result)
+{
+    IR::Member *member = call->base->asMember();
+    assert(member != 0);
+    assert(member->base->asTemp() != 0);
+
+    Instruction::CreateProperty create;
+    create.base = member->base->asTemp()->index;
+    create.name = engine()->newString(*member->name);
+    prepareCallArgs(call->args, create.argc, create.args);
+    create.targetTempIndex = result->index;
+    addInstruction(create);
+}
+
+void InstructionSelection::constructValue(IR::New *call, IR::Temp *result)
+{
+    Instruction::CreateValue create;
+    create.func = call->base->asTemp()->index;
+    prepareCallArgs(call->args, create.argc, create.args);
+    create.targetTempIndex = result->index;
+    addInstruction(create);
+}
+
+void InstructionSelection::loadThisObject(IR::Temp *temp)
+{
+    Instruction::LoadThis load;
+    load.targetTempIndex = temp->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp)
+{
+    assert(sourceConst);
+
+    Instruction::LoadValue load;
+    load.targetTempIndex = targetTemp->index;
+    load.value = convertToValue(sourceConst);
+    addInstruction(load);
+}
+
+void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp)
+{
+    Instruction::LoadValue load;
+    load.value = VM::Value::fromString(engine()->newString(str));
+    load.targetTempIndex = targetTemp->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp)
+{
+    Instruction::LoadValue load;
+    load.value = VM::Value::fromObject(engine()->newRegExpObject(
+                                           *sourceRegexp->value,
+                                           sourceRegexp->flags));
+    load.targetTempIndex = targetTemp->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::getActivationProperty(const QString &name, IR::Temp *temp)
+{
+    Instruction::LoadName load;
+    load.name = engine()->newString(name);
+    load.targetTempIndex = temp->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
+{
+    Instruction::StoreName store;
+    store.sourceIsTemp = toValueOrTemp(source, store.source);
+    store.name = engine()->newString(targetName);
+    addInstruction(store);
+}
+
+void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target)
+{
+    VM::Function *vmFunc = vmFunction(closure->value);
+    assert(vmFunc);
+    Instruction::LoadClosure load;
+    load.value = vmFunc;
+    load.targetTempIndex = target->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::getProperty(IR::Temp *base, const QString &name, IR::Temp *target)
+{
+    Instruction::LoadProperty load;
+    load.baseTemp = base->index;
+    load.name = engine()->newString(name);
+    load.targetTempIndex = target->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName)
+{
+    Instruction::StoreProperty store;
+    store.baseTemp = targetBase->index;
+    store.name = engine()->newString(targetName);
+    store.sourceIsTemp = toValueOrTemp(source, store.source);
+    addInstruction(store);
+}
+
+void InstructionSelection::getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target)
+{
+    Instruction::LoadElement load;
+    load.base = base->index;
+    load.index = index->index;
+    load.targetTempIndex = target->index;
+    addInstruction(load);
+}
+
+void InstructionSelection::setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex)
+{
+    Instruction::StoreElement store;
+    store.base = targetBase->index;
+    store.index = targetIndex->index;
+    store.sourceIsTemp = toValueOrTemp(source, store.source);
+    addInstruction(store);
+}
+
+void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+{
+    Instruction::MoveTemp move;
+    move.fromTempIndex = sourceTemp->index;
+    move.toTempIndex = targetTemp->index;
+    addInstruction(move);
+}
+
+void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp)
+{
+    VM::Value (*op)(const VM::Value value, VM::ExecutionContext *ctx) = 0;
+    switch (oper) {
+    case IR::OpIfTrue: assert(!"unreachable"); break;
+    case IR::OpNot: op = VM::__qmljs_not; break;
+    case IR::OpUMinus: op = VM::__qmljs_uminus; break;
+    case IR::OpUPlus: op = VM::__qmljs_uplus; break;
+    case IR::OpCompl: op = VM::__qmljs_compl; break;
+    case IR::OpIncrement: op = VM::__qmljs_increment; break;
+    case IR::OpDecrement: op = VM::__qmljs_decrement; break;
+    default: assert(!"unreachable"); break;
+    } // switch
+
+    if (op) {
+        Instruction::Unop unop;
+        unop.alu = op;
+        unop.e = sourceTemp->index;
+        unop.targetTempIndex = targetTemp->index;
+        addInstruction(unop);
     } else {
-        qWarning("  NEW");
+        qWarning("  UNOP1");
     }
 }
 
+void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+{
+    Instruction::Binop binop;
+    binop.alu = aluOpFunction(oper);
+    binop.lhsIsTemp = toValueOrTemp(leftSource, binop.lhs);
+    binop.rhsIsTemp = toValueOrTemp(rightSource, binop.rhs);
+    binop.targetTempIndex = target->index;
+    addInstruction(binop);
+}
+
+void InstructionSelection::inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName)
+{
+    void (*op)(VM::Value value, VM::String *name, VM::ExecutionContext *ctx) = 0;
+    switch (oper) {
+    case IR::OpBitAnd: op = VM::__qmljs_inplace_bit_and_name; break;
+    case IR::OpBitOr: op = VM::__qmljs_inplace_bit_or_name; break;
+    case IR::OpBitXor: op = VM::__qmljs_inplace_bit_xor_name; break;
+    case IR::OpAdd: op = VM::__qmljs_inplace_add_name; break;
+    case IR::OpSub: op = VM::__qmljs_inplace_sub_name; break;
+    case IR::OpMul: op = VM::__qmljs_inplace_mul_name; break;
+    case IR::OpDiv: op = VM::__qmljs_inplace_div_name; break;
+    case IR::OpMod: op = VM::__qmljs_inplace_mod_name; break;
+    case IR::OpLShift: op = VM::__qmljs_inplace_shl_name; break;
+    case IR::OpRShift: op = VM::__qmljs_inplace_shr_name; break;
+    case IR::OpURShift: op = VM::__qmljs_inplace_ushr_name; break;
+    default: break;
+    }
+
+    if (op) {
+        Instruction::InplaceNameOp ieo;
+        ieo.alu = op;
+        ieo.targetName = engine()->newString(targetName);
+        ieo.sourceIsTemp = toValueOrTemp(sourceExpr, ieo.source);
+        addInstruction(ieo);
+    }
+}
+
+void InstructionSelection::inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp)
+{
+    void (*op)(VM::Value base, VM::Value index, VM::Value value, VM::ExecutionContext *ctx) = 0;
+    switch (oper) {
+    case IR::OpBitAnd: op = VM::__qmljs_inplace_bit_and_element; break;
+    case IR::OpBitOr: op = VM::__qmljs_inplace_bit_or_element; break;
+    case IR::OpBitXor: op = VM::__qmljs_inplace_bit_xor_element; break;
+    case IR::OpAdd: op = VM::__qmljs_inplace_add_element; break;
+    case IR::OpSub: op = VM::__qmljs_inplace_sub_element; break;
+    case IR::OpMul: op = VM::__qmljs_inplace_mul_element; break;
+    case IR::OpDiv: op = VM::__qmljs_inplace_div_element; break;
+    case IR::OpMod: op = VM::__qmljs_inplace_mod_element; break;
+    case IR::OpLShift: op = VM::__qmljs_inplace_shl_element; break;
+    case IR::OpRShift: op = VM::__qmljs_inplace_shr_element; break;
+    case IR::OpURShift: op = VM::__qmljs_inplace_ushr_element; break;
+    default: break;
+    }
+
+    Instruction::InplaceElementOp ieo;
+    ieo.alu = op;
+    ieo.targetBase = targetBaseTemp->index;
+    ieo.targetIndex = targetIndexTemp->index;
+    ieo.sourceIsTemp = toValueOrTemp(sourceExpr, ieo.source);
+    addInstruction(ieo);
+}
+
+void InstructionSelection::inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName)
+{
+    void (*op)(VM::Value value, VM::Value base, VM::String *name, VM::ExecutionContext *ctx) = 0;
+    switch (oper) {
+    case IR::OpBitAnd: op = VM::__qmljs_inplace_bit_and_member; break;
+    case IR::OpBitOr: op = VM::__qmljs_inplace_bit_or_member; break;
+    case IR::OpBitXor: op = VM::__qmljs_inplace_bit_xor_member; break;
+    case IR::OpAdd: op = VM::__qmljs_inplace_add_member; break;
+    case IR::OpSub: op = VM::__qmljs_inplace_sub_member; break;
+    case IR::OpMul: op = VM::__qmljs_inplace_mul_member; break;
+    case IR::OpDiv: op = VM::__qmljs_inplace_div_member; break;
+    case IR::OpMod: op = VM::__qmljs_inplace_mod_member; break;
+    case IR::OpLShift: op = VM::__qmljs_inplace_shl_member; break;
+    case IR::OpRShift: op = VM::__qmljs_inplace_shr_member; break;
+    case IR::OpURShift: op = VM::__qmljs_inplace_ushr_member; break;
+    default: break;
+    }
+
+    Instruction::InplaceMemberOp imo;
+    imo.alu = op;
+    imo.targetBase = targetBase->index;
+    imo.targetMember = engine()->newString(targetName);
+    imo.sourceIsTemp = toValueOrTemp(source, imo.source);
+    addInstruction(imo);
+}
+
 void InstructionSelection::prepareCallArgs(IR::ExprList *e, quint32 &argc, quint32 &args)
 {
     argc = 0;
@@ -557,337 +851,6 @@ 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, targetTempIndex);
-        } else if (c->base->asTemp()) {
-            callValue(c, targetTempIndex);
-        } else if (c->base->asMember()) {
-            callProperty(c, targetTempIndex);
-        } else {
-            Q_UNREACHABLE();
-        }
-    } else {
-        Q_UNREACHABLE();
-    }
-}
-
-void InstructionSelection::visitEnter(IR::Enter *)
-{
-    qWarning("%s", __PRETTY_FUNCTION__);
-    Q_UNREACHABLE();
-}
-
-void InstructionSelection::visitLeave(IR::Leave *)
-{
-    qWarning("%s", __PRETTY_FUNCTION__);
-    Q_UNREACHABLE();
-}
-
-typedef VM::Value (*ALUFunction)(const VM::Value, const VM::Value, VM::ExecutionContext*);
-static inline ALUFunction aluOpFunction(IR::AluOp op)
-{
-    switch (op) {
-    case IR::OpInvalid:
-        return 0;
-    case IR::OpIfTrue:
-        return 0;
-    case IR::OpNot:
-        return 0;
-    case IR::OpUMinus:
-        return 0;
-    case IR::OpUPlus:
-        return 0;
-    case IR::OpCompl:
-        return 0;
-    case IR::OpBitAnd:
-        return VM::__qmljs_bit_and;
-    case IR::OpBitOr:
-        return VM::__qmljs_bit_or;
-    case IR::OpBitXor:
-        return VM::__qmljs_bit_xor;
-    case IR::OpAdd:
-        return VM::__qmljs_add;
-    case IR::OpSub:
-        return VM::__qmljs_sub;
-    case IR::OpMul:
-        return VM::__qmljs_mul;
-    case IR::OpDiv:
-        return VM::__qmljs_div;
-    case IR::OpMod:
-        return VM::__qmljs_mod;
-    case IR::OpLShift:
-        return VM::__qmljs_shl;
-    case IR::OpRShift:
-        return VM::__qmljs_shr;
-    case IR::OpURShift:
-        return VM::__qmljs_ushr;
-    case IR::OpGt:
-        return VM::__qmljs_gt;
-    case IR::OpLt:
-        return VM::__qmljs_lt;
-    case IR::OpGe:
-        return VM::__qmljs_ge;
-    case IR::OpLe:
-        return VM::__qmljs_le;
-    case IR::OpEqual:
-        return VM::__qmljs_eq;
-    case IR::OpNotEqual:
-        return VM::__qmljs_ne;
-    case IR::OpStrictEqual:
-        return VM::__qmljs_se;
-    case IR::OpStrictNotEqual:
-        return VM::__qmljs_sne;
-    case IR::OpInstanceof:
-        return VM::__qmljs_instanceof;
-    case IR::OpIn:
-        return VM::__qmljs_in;
-    case IR::OpAnd:
-        return 0;
-    case IR::OpOr:
-        return 0;
-    default:
-        assert(!"Unknown AluOp");
-        return 0;
-    }
-};
-
-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.
-                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 (s->source->asTemp() || s->source->asConst()) {
-            if (s->op == IR::OpInvalid) {
-                if (IR::Temp *t2 = s->source->asTemp()) {
-                    Instruction::MoveTemp move;
-                    move.fromTempIndex = t2->index;
-                    move.toTempIndex = targetTempIndex;
-                    addInstruction(move);
-                } else {
-                    IR::Const *c = s->source->asConst();
-                    assert(c);
-                    Instruction::LoadValue load;
-                    load.targetTempIndex = targetTempIndex;
-                    load.value = convertToValue(c);
-                    addInstruction(load);
-                }
-            } else {
-                Instruction::Binop binop;
-                binop.alu = aluOpFunction(s->op);
-                binop.lhsIsTemp = toValueOrTemp(t, binop.lhs);
-                binop.rhsIsTemp = toValueOrTemp(s->source, binop.rhs);
-                binop.targetTempIndex = targetTempIndex;
-                addInstruction(binop);
-            }
-        } else if (IR::String *str = s->source->asString()) {
-            Instruction::LoadValue load;
-            load.value = VM::Value::fromString(engine()->newString(*str->value));
-            load.targetTempIndex = targetTempIndex;
-            addInstruction(load);
-        } else if (IR::Closure *clos = s->source->asClosure()) {
-            VM::Function *vmFunc = vmFunction(clos->value);
-            assert(vmFunc);
-            Instruction::LoadClosure load;
-            load.value = vmFunc;
-            load.targetTempIndex = targetTempIndex;
-            addInstruction(load);
-        } else if (IR::New *ctor = s->source->asNew()) {
-            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");
-            }
-        } else if (IR::Subscript *ss = s->source->asSubscript()) {
-            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()) {
-                VM::Value (*op)(const VM::Value value, VM::ExecutionContext *ctx) = 0;
-                switch (u->op) {
-                case IR::OpIfTrue: assert(!"unreachable"); break;
-                case IR::OpNot: op = VM::__qmljs_not; break;
-                case IR::OpUMinus: op = VM::__qmljs_uminus; break;
-                case IR::OpUPlus: op = VM::__qmljs_uplus; break;
-                case IR::OpCompl: op = VM::__qmljs_compl; break;
-                case IR::OpIncrement: op = VM::__qmljs_increment; break;
-                case IR::OpDecrement: op = VM::__qmljs_decrement; break;
-                default: assert(!"unreachable"); break;
-                } // switch
-
-                if (op) {
-                    Instruction::Unop unop;
-                    unop.alu = op;
-                    unop.e = e->index;
-                    unop.targetTempIndex = targetTempIndex;
-                    addInstruction(unop);
-                } else {
-                    qWarning("  UNOP1");
-                }
-            } else {
-                qWarning("  UNOP2");
-                s->dump(qout, IR::Stmt::MIR);
-                qout << endl;
-            }
-        } else if (IR::Binop *b = s->source->asBinop()) {
-            Instruction::Binop binop;
-            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, targetTempIndex);
-            } else if (c->base->asMember()) {
-                callProperty(c, targetTempIndex);
-            } else if (c->base->asTemp()) {
-                callValue(c, targetTempIndex);
-            } else {
-                Q_UNREACHABLE();
-            }
-        }
-        return;
-    } else if (IR::Name *n = s->target->asName()) {
-        if (s->source->asTemp() || s->source->asConst()) {
-            void (*op)(VM::Value value, VM::String *name, VM::ExecutionContext *ctx) = 0;
-            switch (s->op) {
-            case IR::OpBitAnd: op = VM::__qmljs_inplace_bit_and_name; break;
-            case IR::OpBitOr: op = VM::__qmljs_inplace_bit_or_name; break;
-            case IR::OpBitXor: op = VM::__qmljs_inplace_bit_xor_name; break;
-            case IR::OpAdd: op = VM::__qmljs_inplace_add_name; break;
-            case IR::OpSub: op = VM::__qmljs_inplace_sub_name; break;
-            case IR::OpMul: op = VM::__qmljs_inplace_mul_name; break;
-            case IR::OpDiv: op = VM::__qmljs_inplace_div_name; break;
-            case IR::OpMod: op = VM::__qmljs_inplace_mod_name; break;
-            case IR::OpLShift: op = VM::__qmljs_inplace_shl_name; break;
-            case IR::OpRShift: op = VM::__qmljs_inplace_shr_name; break;
-            case IR::OpURShift: op = VM::__qmljs_inplace_ushr_name; break;
-            default: break;
-            }
-
-            if (op) {
-                Instruction::InplaceNameOp ieo;
-                ieo.alu = op;
-                ieo.targetName = engine()->newString(*n->id);
-                ieo.sourceIsTemp = toValueOrTemp(s->source, ieo.source);
-                addInstruction(ieo);
-                return;
-            } else if (s->op == IR::OpInvalid) {
-                Instruction::StoreName store;
-                store.sourceIsTemp = toValueOrTemp(s->source, store.source);
-                store.name = engine()->newString(*n->id);
-                addInstruction(store);
-                return;
-            }
-        }
-        qWarning("NAME");
-    } else if (IR::Subscript *ss = s->target->asSubscript()) {
-        if (s->source->asTemp() || s->source->asConst()) {
-            void (*op)(VM::Value base, VM::Value index, VM::Value value, VM::ExecutionContext *ctx) = 0;
-            switch (s->op) {
-            case IR::OpBitAnd: op = VM::__qmljs_inplace_bit_and_element; break;
-            case IR::OpBitOr: op = VM::__qmljs_inplace_bit_or_element; break;
-            case IR::OpBitXor: op = VM::__qmljs_inplace_bit_xor_element; break;
-            case IR::OpAdd: op = VM::__qmljs_inplace_add_element; break;
-            case IR::OpSub: op = VM::__qmljs_inplace_sub_element; break;
-            case IR::OpMul: op = VM::__qmljs_inplace_mul_element; break;
-            case IR::OpDiv: op = VM::__qmljs_inplace_div_element; break;
-            case IR::OpMod: op = VM::__qmljs_inplace_mod_element; break;
-            case IR::OpLShift: op = VM::__qmljs_inplace_shl_element; break;
-            case IR::OpRShift: op = VM::__qmljs_inplace_shr_element; break;
-            case IR::OpURShift: op = VM::__qmljs_inplace_ushr_element; break;
-            default: break;
-            }
-
-            if (op) {
-                Instruction::InplaceElementOp ieo;
-                ieo.alu = op;
-                ieo.targetBase = ss->base->asTemp()->index;
-                ieo.targetIndex = ss->index->asTemp()->index;
-                ieo.sourceIsTemp = toValueOrTemp(s->source, ieo.source);
-                addInstruction(ieo);
-                return;
-            } else if (s->op == IR::OpInvalid) {
-                Instruction::StoreElement store;
-                store.base = ss->base->asTemp()->index;
-                store.index = ss->index->asTemp()->index;
-                store.sourceIsTemp = toValueOrTemp(s->source, store.source);
-                addInstruction(store);
-                return;
-            }
-        }
-        qWarning("SUBSCRIPT");
-    } else if (IR::Member *m = s->target->asMember()) {
-        if (s->source->asTemp() || s->source->asConst()) {
-            void (*op)(VM::Value value, VM::Value base, VM::String *name, VM::ExecutionContext *ctx) = 0;
-            switch (s->op) {
-            case IR::OpBitAnd: op = VM::__qmljs_inplace_bit_and_member; break;
-            case IR::OpBitOr: op = VM::__qmljs_inplace_bit_or_member; break;
-            case IR::OpBitXor: op = VM::__qmljs_inplace_bit_xor_member; break;
-            case IR::OpAdd: op = VM::__qmljs_inplace_add_member; break;
-            case IR::OpSub: op = VM::__qmljs_inplace_sub_member; break;
-            case IR::OpMul: op = VM::__qmljs_inplace_mul_member; break;
-            case IR::OpDiv: op = VM::__qmljs_inplace_div_member; break;
-            case IR::OpMod: op = VM::__qmljs_inplace_mod_member; break;
-            case IR::OpLShift: op = VM::__qmljs_inplace_shl_member; break;
-            case IR::OpRShift: op = VM::__qmljs_inplace_shr_member; break;
-            case IR::OpURShift: op = VM::__qmljs_inplace_ushr_member; break;
-            default: break;
-            }
-
-            if (op) {
-                Instruction::InplaceMemberOp imo;
-                imo.alu = op;
-                imo.targetBase = m->base->asTemp()->index;
-                imo.targetMember = engine()->newString(*m->name);
-                imo.sourceIsTemp = toValueOrTemp(s->source, imo.source);
-                addInstruction(imo);
-                return;
-            } else if (s->op == IR::OpInvalid) {
-                Instruction::StoreProperty store;
-                store.baseTemp = m->base->asTemp()->index;
-                store.name = engine()->newString(*m->name);
-                store.sourceIsTemp = toValueOrTemp(s->source, store.source);
-                addInstruction(store);
-                return;
-            }
-        }
-        qWarning("MEMBER");
-    }
-
-    Q_UNIMPLEMENTED();
-    s->dump(qout, IR::Stmt::MIR);
-    qout << endl;
-    Q_UNREACHABLE();
-}
-
 void InstructionSelection::visitJump(IR::Jump *s)
 {
     Instruction::Jump jump;
index dece413..0456394 100644 (file)
@@ -9,7 +9,9 @@
 namespace QQmlJS {
 namespace Moth {
 
-class InstructionSelection : public IR::StmtVisitor, public EvalInstructionSelection
+class InstructionSelection:
+        public IR::InstructionSelection,
+        public EvalInstructionSelection
 {
 public:
     InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
@@ -18,14 +20,34 @@ public:
     virtual void run(VM::Function *vmFunction, IR::Function *function);
 
 protected:
-    virtual void visitExp(IR::Exp *);
-    virtual void visitEnter(IR::Enter *);
-    virtual void visitLeave(IR::Leave *);
-    virtual void visitMove(IR::Move *);
     virtual void visitJump(IR::Jump *);
     virtual void visitCJump(IR::CJump *);
     virtual void visitRet(IR::Ret *);
 
+    virtual void callActivationProperty(IR::Call *c, IR::Temp *temp);
+    virtual void callValue(IR::Call *c, IR::Temp *temp);
+    virtual void callProperty(IR::Call *c, IR::Temp *temp);
+    virtual void constructActivationProperty(IR::New *call, IR::Temp *result);
+    virtual void constructProperty(IR::New *call, IR::Temp *result);
+    virtual void constructValue(IR::New *call, IR::Temp *result);
+    virtual void loadThisObject(IR::Temp *temp);
+    virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp);
+    virtual void loadString(const QString &str, IR::Temp *targetTemp);
+    virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp);
+    virtual void getActivationProperty(const QString &name, IR::Temp *temp);
+    virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
+    virtual void initClosure(IR::Closure *closure, IR::Temp *target);
+    virtual void getProperty(IR::Temp *base, const QString &name, IR::Temp *target);
+    virtual void setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+    virtual void getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target);
+    virtual void setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex);
+    virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp);
+    virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp);
+    virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+    virtual void inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName);
+    virtual void inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp);
+    virtual void inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+
 private:
     struct Instruction {
 #define MOTH_INSTR_DATA_TYPEDEF(I, FMT) typedef InstrData<Instr::I> I;
@@ -36,10 +58,6 @@ private:
     };
 
     void simpleMove(IR::Move *);
-    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 outgoingArgumentTempStart() const { return _function->tempCount; }
index eea515c..3d95491 100644 (file)
@@ -98,7 +98,7 @@ int compileWithLLVM(IR::Module *module, const QString &fileName, LLVMOutputType
     //----
 
     llvm::InitializeNativeTarget();
-    LLVMInstructionSelection llvmIsel(llvm::getGlobalContext());
+    LLVM::InstructionSelection llvmIsel(llvm::getGlobalContext());
 
     const QString moduleName = QFileInfo(fileName).fileName();
     llvm::StringRef moduleId(moduleName.toUtf8().constData());
@@ -230,12 +230,13 @@ int compileWithLLVM(IR::Module *module, const QString &fileName, LLVMOutputType
 } // QQmlJS
 
 using namespace QQmlJS;
+using namespace QQmlJS::LLVM;
 
 namespace {
 QTextStream qerr(stderr, QIODevice::WriteOnly);
 }
 
-LLVMInstructionSelection::LLVMInstructionSelection(llvm::LLVMContext &context)
+InstructionSelection::InstructionSelection(llvm::LLVMContext &context)
     : llvm::IRBuilder<>(context)
     , _llvmModule(0)
     , _llvmFunction(0)
@@ -252,7 +253,7 @@ LLVMInstructionSelection::LLVMInstructionSelection(llvm::LLVMContext &context)
 {
 }
 
-void LLVMInstructionSelection::buildLLVMModule(IR::Module *module, llvm::Module *llvmModule, llvm::FunctionPassManager *fpm)
+void InstructionSelection::buildLLVMModule(IR::Module *module, llvm::Module *llvmModule, llvm::FunctionPassManager *fpm)
 {
     qSwap(_llvmModule, llvmModule);
     qSwap(_fpm, fpm);
@@ -297,7 +298,145 @@ void LLVMInstructionSelection::buildLLVMModule(IR::Module *module, llvm::Module
     qSwap(_llvmModule, llvmModule);
 }
 
-llvm::Function *LLVMInstructionSelection::getLLVMFunction(IR::Function *function)
+void InstructionSelection::callActivationProperty(IR::Call *c, IR::Temp *temp)
+{
+    // TODO: implement instead of visitExp
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::callValue(IR::Call *c, IR::Temp *temp)
+{
+    // TODO: implement instead of visitExp
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::callProperty(IR::Call *c, IR::Temp *temp)
+{
+    // TODO: implement instead of visitExp
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::constructProperty(IR::New *call, IR::Temp *result)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::constructValue(IR::New *call, IR::Temp *result)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadThisObject(IR::Temp *temp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadConst(IR::Const *con, IR::Temp *temp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::getActivationProperty(const QString &name, IR::Temp *temp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::getProperty(IR::Temp *base, const QString &name, IR::Temp *target)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName)
+{
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+}
+
+llvm::Function *InstructionSelection::getLLVMFunction(IR::Function *function)
 {
     llvm::Function *&f = _functionMap[function];
     if (! f) {
@@ -314,7 +453,7 @@ llvm::Function *LLVMInstructionSelection::getLLVMFunction(IR::Function *function
     return f;
 }
 
-llvm::Function *LLVMInstructionSelection::compileLLVMFunction(IR::Function *function)
+llvm::Function *InstructionSelection::compileLLVMFunction(IR::Function *function)
 {
     llvm::Function *llvmFunction = getLLVMFunction(function);
 
@@ -375,7 +514,7 @@ llvm::Function *LLVMInstructionSelection::compileLLVMFunction(IR::Function *func
     return llvmFunction;
 }
 
-llvm::BasicBlock *LLVMInstructionSelection::getLLVMBasicBlock(IR::BasicBlock *block)
+llvm::BasicBlock *InstructionSelection::getLLVMBasicBlock(IR::BasicBlock *block)
 {
     llvm::BasicBlock *&llvmBlock = _blockMap[block];
     if (! llvmBlock)
@@ -384,7 +523,7 @@ llvm::BasicBlock *LLVMInstructionSelection::getLLVMBasicBlock(IR::BasicBlock *bl
     return llvmBlock;
 }
 
-llvm::Value *LLVMInstructionSelection::getLLVMValue(IR::Expr *expr)
+llvm::Value *InstructionSelection::getLLVMValue(IR::Expr *expr)
 {
     llvm::Value *llvmValue = 0;
     if (expr) {
@@ -400,7 +539,7 @@ llvm::Value *LLVMInstructionSelection::getLLVMValue(IR::Expr *expr)
     return llvmValue;
 }
 
-llvm::Value *LLVMInstructionSelection::getLLVMTempReference(IR::Expr *expr)
+llvm::Value *InstructionSelection::getLLVMTempReference(IR::Expr *expr)
 {
     if (IR::Temp *t = expr->asTemp())
         return getLLVMTemp(t);
@@ -410,7 +549,7 @@ llvm::Value *LLVMInstructionSelection::getLLVMTempReference(IR::Expr *expr)
     return addr;
 }
 
-llvm::Value *LLVMInstructionSelection::getLLVMCondition(IR::Expr *expr)
+llvm::Value *InstructionSelection::getLLVMCondition(IR::Expr *expr)
 {
     llvm::Value *value = 0;
     if (IR::Temp *t = expr->asTemp()) {
@@ -432,7 +571,7 @@ llvm::Value *LLVMInstructionSelection::getLLVMCondition(IR::Expr *expr)
                        value);
 }
 
-llvm::Value *LLVMInstructionSelection::getLLVMTemp(IR::Temp *temp)
+llvm::Value *InstructionSelection::getLLVMTemp(IR::Temp *temp)
 {
     if (temp->index < 0) {
         const int index = -temp->index -1;
@@ -443,7 +582,7 @@ llvm::Value *LLVMInstructionSelection::getLLVMTemp(IR::Temp *temp)
     return _tempMap[temp->index];
 }
 
-llvm::Value *LLVMInstructionSelection::getStringPtr(const QString &s)
+llvm::Value *InstructionSelection::getStringPtr(const QString &s)
 {
     llvm::Value *&value = _stringMap[s];
     if (! value) {
@@ -454,7 +593,7 @@ llvm::Value *LLVMInstructionSelection::getStringPtr(const QString &s)
     return value;
 }
 
-llvm::Value *LLVMInstructionSelection::getIdentifier(const QString &s)
+llvm::Value *InstructionSelection::getIdentifier(const QString &s)
 {
     llvm::Value *str = getStringPtr(s);
     llvm::Value *id = CreateCall2(_llvmModule->getFunction("__qmljs_identifier_from_utf8"),
@@ -462,22 +601,12 @@ llvm::Value *LLVMInstructionSelection::getIdentifier(const QString &s)
     return id;
 }
 
-void LLVMInstructionSelection::visitExp(IR::Exp *s)
+void InstructionSelection::visitExp(IR::Exp *s)
 {
     getLLVMValue(s->expr);
 }
 
-void LLVMInstructionSelection::visitEnter(IR::Enter *)
-{
-    Q_UNREACHABLE();
-}
-
-void LLVMInstructionSelection::visitLeave(IR::Leave *)
-{
-    Q_UNREACHABLE();
-}
-
-void LLVMInstructionSelection::genMoveSubscript(IR::Move *s)
+void InstructionSelection::genMoveSubscript(IR::Move *s)
 {
     IR::Subscript *subscript = s->target->asSubscript();
     llvm::Value *base = getLLVMTempReference(subscript->base);
@@ -487,7 +616,7 @@ void LLVMInstructionSelection::genMoveSubscript(IR::Move *s)
                 _llvmFunction->arg_begin(), base, index, source);
 }
 
-void LLVMInstructionSelection::genMoveMember(IR::Move *s)
+void InstructionSelection::genMoveMember(IR::Move *s)
 {
     IR::Member *m = s->target->asMember();
     llvm::Value *base = getLLVMTempReference(m->base);
@@ -497,7 +626,7 @@ void LLVMInstructionSelection::genMoveMember(IR::Move *s)
                 _llvmFunction->arg_begin(), base, name, source);
 }
 
-void LLVMInstructionSelection::visitMove(IR::Move *s)
+void InstructionSelection::visitMove(IR::Move *s)
 {
     if (s->op == IR::OpInvalid) {
         if (s->target->asSubscript()) {
@@ -647,19 +776,19 @@ void LLVMInstructionSelection::visitMove(IR::Move *s)
     return;
 }
 
-void LLVMInstructionSelection::visitJump(IR::Jump *s)
+void InstructionSelection::visitJump(IR::Jump *s)
 {
     CreateBr(getLLVMBasicBlock(s->target));
 }
 
-void LLVMInstructionSelection::visitCJump(IR::CJump *s)
+void InstructionSelection::visitCJump(IR::CJump *s)
 {
     CreateCondBr(getLLVMCondition(s->cond),
                  getLLVMBasicBlock(s->iftrue),
                  getLLVMBasicBlock(s->iffalse));
 }
 
-void LLVMInstructionSelection::visitRet(IR::Ret *s)
+void InstructionSelection::visitRet(IR::Ret *s)
 {
     IR::Temp *t = s->expr->asTemp();
     assert(t != 0);
@@ -669,14 +798,14 @@ void LLVMInstructionSelection::visitRet(IR::Ret *s)
     CreateRetVoid();
 }
 
-void LLVMInstructionSelection::visitConst(IR::Const *e)
+void InstructionSelection::visitConst(IR::Const *e)
 {
     llvm::Value *tmp = createValue(e);
 
     _llvmValue = CreateLoad(tmp);
 }
 
-void LLVMInstructionSelection::visitString(IR::String *e)
+void InstructionSelection::visitString(IR::String *e)
 {
     llvm::Value *tmp = newLLVMTemp(_valueTy);
     CreateCall3(_llvmModule->getFunction("__qmljs_llvm_init_string"),
@@ -685,7 +814,7 @@ void LLVMInstructionSelection::visitString(IR::String *e)
     _llvmValue = CreateLoad(tmp);
 }
 
-void LLVMInstructionSelection::visitRegExp(IR::RegExp *e)
+void InstructionSelection::visitRegExp(IR::RegExp *e)
 {
     e->dump(qerr);
     qerr << endl;
@@ -693,7 +822,7 @@ void LLVMInstructionSelection::visitRegExp(IR::RegExp *e)
     _llvmValue = llvm::Constant::getNullValue(_valueTy);
 }
 
-void LLVMInstructionSelection::visitName(IR::Name *e)
+void InstructionSelection::visitName(IR::Name *e)
 {
     llvm::Value *result = newLLVMTemp(_valueTy);
 
@@ -709,14 +838,14 @@ void LLVMInstructionSelection::visitName(IR::Name *e)
 
 }
 
-void LLVMInstructionSelection::visitTemp(IR::Temp *e)
+void InstructionSelection::visitTemp(IR::Temp *e)
 {
     if (llvm::Value *t = getLLVMTemp(e)) {
         _llvmValue = CreateLoad(t);
     }
 }
 
-void LLVMInstructionSelection::visitClosure(IR::Closure *e)
+void InstructionSelection::visitClosure(IR::Closure *e)
 {
     llvm::Value *tmp = newLLVMTemp(_valueTy);
     llvm::Value *clos = getLLVMFunction(e->value);
@@ -726,21 +855,21 @@ void LLVMInstructionSelection::visitClosure(IR::Closure *e)
     _llvmValue = CreateLoad(tmp);
 }
 
-void LLVMInstructionSelection::visitUnop(IR::Unop *e)
+void InstructionSelection::visitUnop(IR::Unop *e)
 {
     llvm::Value *result = newLLVMTemp(_valueTy);
     genUnop(result, e);
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::visitBinop(IR::Binop *e)
+void InstructionSelection::visitBinop(IR::Binop *e)
 {
     llvm::Value *result = newLLVMTemp(_valueTy);
     genBinop(result, e);
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::genUnop(llvm::Value *result, IR::Unop *e)
+void InstructionSelection::genUnop(llvm::Value *result, IR::Unop *e)
 {
     IR::Temp *t = e->expr->asTemp();
     assert(t != 0);
@@ -762,7 +891,7 @@ void LLVMInstructionSelection::genUnop(llvm::Value *result, IR::Unop *e)
     CreateCall3(op, _llvmFunction->arg_begin(), result, expr);
 }
 
-void LLVMInstructionSelection::genBinop(llvm::Value *result, IR::Binop *e)
+void InstructionSelection::genBinop(llvm::Value *result, IR::Binop *e)
 {
     assert(e->left->asTemp() || e->left->asConst());
     assert(e->right->asTemp() || e->right->asConst());
@@ -816,13 +945,13 @@ void LLVMInstructionSelection::genBinop(llvm::Value *result, IR::Binop *e)
     CreateCall4(op, _llvmFunction->arg_begin(), result, left, right);
 }
 
-llvm::AllocaInst *LLVMInstructionSelection::newLLVMTemp(llvm::Type *type, llvm::Value *size)
+llvm::AllocaInst *InstructionSelection::newLLVMTemp(llvm::Type *type, llvm::Value *size)
 {
     llvm::AllocaInst *addr = new llvm::AllocaInst(type, size, llvm::Twine(), _allocaInsertPoint);
     return addr;
 }
 
-llvm::Value * LLVMInstructionSelection::genArguments(IR::ExprList *exprs, int &argc)
+llvm::Value * InstructionSelection::genArguments(IR::ExprList *exprs, int &argc)
 {
     llvm::Value *args = 0;
 
@@ -844,7 +973,7 @@ llvm::Value * LLVMInstructionSelection::genArguments(IR::ExprList *exprs, int &a
     return args;
 }
 
-void LLVMInstructionSelection::genCallMember(IR::Call *e, llvm::Value *result)
+void InstructionSelection::genCallMember(IR::Call *e, llvm::Value *result)
 {
     if (! result)
         result = newLLVMTemp(_valueTy);
@@ -869,7 +998,7 @@ void LLVMInstructionSelection::genCallMember(IR::Call *e, llvm::Value *result)
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::genConstructMember(IR::New *e, llvm::Value *result)
+void InstructionSelection::genConstructMember(IR::New *e, llvm::Value *result)
 {
     if (! result)
         result = newLLVMTemp(_valueTy);
@@ -894,7 +1023,7 @@ void LLVMInstructionSelection::genConstructMember(IR::New *e, llvm::Value *resul
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::genCallTemp(IR::Call *e, llvm::Value *result)
+void InstructionSelection::genCallTemp(IR::Call *e, llvm::Value *result)
 {
     if (! result)
         result = newLLVMTemp(_valueTy);
@@ -920,7 +1049,7 @@ void LLVMInstructionSelection::genCallTemp(IR::Call *e, llvm::Value *result)
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::genConstructTemp(IR::New *e, llvm::Value *result)
+void InstructionSelection::genConstructTemp(IR::New *e, llvm::Value *result)
 {
     if (! result)
         result = newLLVMTemp(_valueTy);
@@ -943,7 +1072,7 @@ void LLVMInstructionSelection::genConstructTemp(IR::New *e, llvm::Value *result)
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::genCallName(IR::Call *e, llvm::Value *result)
+void InstructionSelection::genCallName(IR::Call *e, llvm::Value *result)
 {
     IR::Name *base = e->base->asName();
 
@@ -1046,7 +1175,7 @@ void LLVMInstructionSelection::genCallName(IR::Call *e, llvm::Value *result)
     }
 }
 
-void LLVMInstructionSelection::genConstructName(IR::New *e, llvm::Value *result)
+void InstructionSelection::genConstructName(IR::New *e, llvm::Value *result)
 {
     IR::Name *base = e->base->asName();
 
@@ -1068,7 +1197,7 @@ void LLVMInstructionSelection::genConstructName(IR::New *e, llvm::Value *result)
     }
 }
 
-void LLVMInstructionSelection::visitCall(IR::Call *e)
+void InstructionSelection::visitCall(IR::Call *e)
 {
     if (e->base->asMember()) {
         genCallMember(e);
@@ -1092,7 +1221,7 @@ void LLVMInstructionSelection::visitCall(IR::Call *e)
     }
 }
 
-void LLVMInstructionSelection::visitNew(IR::New *e)
+void InstructionSelection::visitNew(IR::New *e)
 {
     if (e->base->asMember()) {
         genConstructMember(e);
@@ -1116,7 +1245,7 @@ void LLVMInstructionSelection::visitNew(IR::New *e)
     }
 }
 
-void LLVMInstructionSelection::visitSubscript(IR::Subscript *e)
+void InstructionSelection::visitSubscript(IR::Subscript *e)
 {
     llvm::Value *result = newLLVMTemp(_valueTy);
     llvm::Value *base = getLLVMTempReference(e->base);
@@ -1126,7 +1255,7 @@ void LLVMInstructionSelection::visitSubscript(IR::Subscript *e)
     _llvmValue = CreateLoad(result);
 }
 
-void LLVMInstructionSelection::visitMember(IR::Member *e)
+void InstructionSelection::visitMember(IR::Member *e)
 {
     llvm::Value *result = newLLVMTemp(_valueTy);
     llvm::Value *base = getLLVMTempReference(e->base);
@@ -1137,7 +1266,7 @@ void LLVMInstructionSelection::visitMember(IR::Member *e)
     _llvmValue = CreateLoad(result);
 }
 
-llvm::Value *LLVMInstructionSelection::createValue(IR::Const *e)
+llvm::Value *InstructionSelection::createValue(IR::Const *e)
 {
     llvm::Value *tmp = newLLVMTemp(_valueTy);
 
@@ -1167,7 +1296,7 @@ llvm::Value *LLVMInstructionSelection::createValue(IR::Const *e)
     return tmp;
 }
 
-llvm::Value *LLVMInstructionSelection::toValuePtr(IR::Expr *e)
+llvm::Value *InstructionSelection::toValuePtr(IR::Expr *e)
 {
     if (IR::Temp *t = e->asTemp()) {
         return getLLVMTemp(t);
index 3f51a21..cb5775a 100644 (file)
 #include "qv4ir_p.h"
 
 namespace QQmlJS {
+namespace LLVM {
 
-class LLVMInstructionSelection:
+class InstructionSelection:
         public llvm::IRBuilder<>,
-        protected IR::StmtVisitor,
+        public IR::InstructionSelection,
         protected IR::ExprVisitor
 {
 public:
-    LLVMInstructionSelection(llvm::LLVMContext &context);
+    InstructionSelection(llvm::LLVMContext &context);
 
     void buildLLVMModule(IR::Module *module, llvm::Module *llvmModule, llvm::FunctionPassManager *fpm);
+
+public: // methods from InstructionSelection:
+    virtual void callActivationProperty(IR::Call *c, IR::Temp *temp);
+    virtual void callValue(IR::Call *c, IR::Temp *temp);
+    virtual void callProperty(IR::Call *c, IR::Temp *temp);
+    virtual void constructActivationProperty(IR::New *call, IR::Temp *result);
+    virtual void constructProperty(IR::New *call, IR::Temp *result);
+    virtual void constructValue(IR::New *call, IR::Temp *result);
+    virtual void loadThisObject(IR::Temp *temp);
+    virtual void loadConst(IR::Const *con, IR::Temp *temp);
+    virtual void loadString(const QString &str, IR::Temp *targetTemp);
+    virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp);
+    virtual void getActivationProperty(const QString &name, IR::Temp *temp);
+    virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
+    virtual void initClosure(IR::Closure *closure, IR::Temp *target);
+    virtual void getProperty(IR::Temp *base, const QString &name, IR::Temp *target);
+    virtual void setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+    virtual void getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target);
+    virtual void setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex);
+    virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp);
+    virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp);
+    virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+    virtual void inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName);
+    virtual void inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp);
+    virtual void inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+
+public: // visitor methods for StmtVisitor:
+    virtual void visitExp(IR::Exp *); // TODO: remove
+    virtual void visitMove(IR::Move *);
+    virtual void visitJump(IR::Jump *);
+    virtual void visitCJump(IR::CJump *);
+    virtual void visitRet(IR::Ret *);
+
+public: // visitor methods for ExprVisitor:
+    virtual void visitConst(IR::Const *);
+    virtual void visitString(IR::String *);
+    virtual void visitRegExp(IR::RegExp *);
+    virtual void visitName(IR::Name *);
+    virtual void visitTemp(IR::Temp *);
+    virtual void visitClosure(IR::Closure *);
+    virtual void visitUnop(IR::Unop *);
+    virtual void visitBinop(IR::Binop *);
+    virtual void visitCall(IR::Call *);
+    virtual void visitNew(IR::New *);
+    virtual void visitSubscript(IR::Subscript *);
+    virtual void visitMember(IR::Member *);
+
+private:
     llvm::Function *getLLVMFunction(IR::Function *function);
     llvm::Function *compileLLVMFunction(IR::Function *function);
     llvm::BasicBlock *getLLVMBasicBlock(IR::BasicBlock *block);
@@ -89,29 +138,6 @@ public:
     void genConstructMember(IR::New *e, llvm::Value *result = 0);
     void genMoveSubscript(IR::Move *s);
     void genMoveMember(IR::Move *s);
-
-    virtual void visitExp(IR::Exp *);
-    virtual void visitEnter(IR::Enter *);
-    virtual void visitLeave(IR::Leave *);
-    virtual void visitMove(IR::Move *);
-    virtual void visitJump(IR::Jump *);
-    virtual void visitCJump(IR::CJump *);
-    virtual void visitRet(IR::Ret *);
-
-    virtual void visitConst(IR::Const *);
-    virtual void visitString(IR::String *);
-    virtual void visitRegExp(IR::RegExp *);
-    virtual void visitName(IR::Name *);
-    virtual void visitTemp(IR::Temp *);
-    virtual void visitClosure(IR::Closure *);
-    virtual void visitUnop(IR::Unop *);
-    virtual void visitBinop(IR::Binop *);
-    virtual void visitCall(IR::Call *);
-    virtual void visitNew(IR::New *);
-    virtual void visitSubscript(IR::Subscript *);
-    virtual void visitMember(IR::Member *);
-
-private:
     llvm::Value *createValue(IR::Const *e);
     llvm::Value *toValuePtr(IR::Expr *e);
 
@@ -134,6 +160,7 @@ private:
     llvm::FunctionPassManager *_fpm;
 };
 
-} // end of namespace QQmlJS
+} // LLVM namespace
+} // QQmlJS namespace
 
 #endif // QV4ISEL_LLVM_P_H
index 3f44f26..b73bddc 100644 (file)
@@ -58,10 +58,6 @@ using namespace QQmlJS;
 using namespace QQmlJS::MASM;
 using namespace QQmlJS::VM;
 
-namespace {
-QTextStream qout(stderr, QIODevice::WriteOnly);
-}
-
 Assembler::Assembler(IR::Function* function)
     : _function(function)
 {
@@ -585,6 +581,179 @@ void InstructionSelection::callValue(IR::Call *call, IR::Temp *result)
     generateFunctionCall(result, __qmljs_call_value, Assembler::ContextRegister, thisObject, baseTemp, baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
 }
 
+void InstructionSelection::loadThisObject(IR::Temp *temp)
+{
+    generateFunctionCall(temp, __qmljs_get_thisObject, Assembler::ContextRegister);
+}
+
+void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp)
+{
+    _asm->storeValue(convertToValue(sourceConst), targetTemp);
+}
+
+void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp)
+{
+    Value v = Value::fromString(engine()->newString(str));
+    _asm->storeValue(v, targetTemp);
+}
+
+void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp)
+{
+    Value v = Value::fromObject(engine()->newRegExpObject(*sourceRegexp->value,
+                                                          sourceRegexp->flags));
+    _asm->storeValue(v, targetTemp);
+}
+
+void InstructionSelection::getActivationProperty(const QString &name, IR::Temp *temp)
+{
+    String *propertyName = identifier(name);
+    generateFunctionCall(temp, __qmljs_get_activation_property, Assembler::ContextRegister, propertyName);
+}
+
+void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
+{
+    String *propertyName = identifier(targetName);
+    generateFunctionCall(Assembler::Void, __qmljs_set_activation_property, Assembler::ContextRegister, propertyName, source);
+}
+
+void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target)
+{
+    VM::Function *vmFunc = vmFunction(closure->value);
+    assert(vmFunc);
+    generateFunctionCall(target, __qmljs_init_closure, Assembler::TrustedImmPtr(vmFunc), Assembler::ContextRegister);
+}
+
+void InstructionSelection::getProperty(IR::Temp *base, const QString &name, IR::Temp *target)
+{
+    generateFunctionCall(target, __qmljs_get_property, Assembler::ContextRegister, base, identifier(name));
+}
+
+void InstructionSelection::setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName)
+{
+    generateFunctionCall(Assembler::Void, __qmljs_set_property, Assembler::ContextRegister, targetBase, identifier(targetName), source);
+}
+
+void InstructionSelection::getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target)
+{
+    generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister, base, index);
+}
+
+void InstructionSelection::setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex)
+{
+    generateFunctionCall(Assembler::Void, __qmljs_set_element, Assembler::ContextRegister, targetBase, targetIndex, source);
+}
+
+void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+{
+    _asm->copyValue(targetTemp, sourceTemp);
+}
+
+#define setOp(op, opName, operation) \
+    do { op = operation; opName = isel_stringIfy(operation); } while (0)
+
+void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp)
+{
+    Value (*op)(const Value value, ExecutionContext *ctx) = 0;
+    const char *opName = 0;
+    switch (oper) {
+    case IR::OpIfTrue: assert(!"unreachable"); break;
+    case IR::OpNot: setOp(op, opName, __qmljs_not); break;
+    case IR::OpUMinus: setOp(op, opName, __qmljs_uminus); break;
+    case IR::OpUPlus: setOp(op, opName, __qmljs_uplus); break;
+    case IR::OpCompl: setOp(op, opName, __qmljs_compl); break;
+    case IR::OpIncrement: setOp(op, opName, __qmljs_increment); break;
+    case IR::OpDecrement: setOp(op, opName, __qmljs_decrement); break;
+    default: assert(!"unreachable"); break;
+    } // switch
+
+    if (op)
+        _asm->generateFunctionCallImp(targetTemp, opName, op, sourceTemp,
+                                      Assembler::ContextRegister);
+}
+
+void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+{
+    _asm->generateBinOp(oper, target, leftSource, rightSource);
+}
+
+void InstructionSelection::inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName)
+{
+    void (*op)(const Value value, String *name, ExecutionContext *ctx) = 0;
+    const char *opName = 0;
+    switch (oper) {
+    case IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_name); break;
+    case IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_name); break;
+    case IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_name); break;
+    case IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_name); break;
+    case IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_name); break;
+    case IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_name); break;
+    case IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_name); break;
+    case IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_name); break;
+    case IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_name); break;
+    case IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_name); break;
+    case IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_name); break;
+    default:
+        Q_UNREACHABLE();
+        break;
+    }
+    if (op) {
+        _asm->generateFunctionCallImp(Assembler::Void, opName, op, sourceExpr, identifier(targetName), Assembler::ContextRegister);
+    }
+}
+
+void InstructionSelection::inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp)
+{
+    void (*op)(Value base, Value index, Value value, ExecutionContext *ctx) = 0;
+    const char *opName = 0;
+    switch (oper) {
+    case IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_element); break;
+    case IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_element); break;
+    case IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_element); break;
+    case IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_element); break;
+    case IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_element); break;
+    case IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_element); break;
+    case IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_element); break;
+    case IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_element); break;
+    case IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_element); break;
+    case IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_element); break;
+    case IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_element); break;
+    default:
+        Q_UNREACHABLE();
+        break;
+    }
+
+    if (op) {
+        _asm->generateFunctionCallImp(Assembler::Void, opName, op, targetBaseTemp, targetIndexTemp, sourceExpr, Assembler::ContextRegister);
+    }
+}
+
+void InstructionSelection::inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName)
+{
+    void (*op)(Value value, Value base, String *name, ExecutionContext *ctx) = 0;
+    const char *opName = 0;
+    switch (oper) {
+    case IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_member); break;
+    case IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_member); break;
+    case IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_member); break;
+    case IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_member); break;
+    case IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_member); break;
+    case IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_member); break;
+    case IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_member); break;
+    case IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_member); break;
+    case IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_member); break;
+    case IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_member); break;
+    case IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_member); break;
+    default:
+        Q_UNREACHABLE();
+        break;
+    }
+
+    if (op) {
+        String* member = identifier(targetName);
+        _asm->generateFunctionCallImp(Assembler::Void, opName, op, source, targetBase, member, Assembler::ContextRegister);
+    }
+}
+
 void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result)
 {
     IR::Member *member = call->base->asMember();
@@ -622,253 +791,6 @@ void InstructionSelection::constructValue(IR::New *call, IR::Temp *result)
     generateFunctionCall(result, __qmljs_construct_value, Assembler::ContextRegister, baseTemp, baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
 }
 
-void InstructionSelection::visitExp(IR::Exp *s)
-{
-    if (IR::Call *c = s->expr->asCall()) {
-        if (c->base->asName()) {
-            callActivationProperty(c, 0);
-            return;
-        } else if (c->base->asTemp()) {
-            callValue(c, 0);
-            return;
-        } else if (c->base->asMember()) {
-            callProperty(c, 0);
-            return;
-        }
-    }
-    assert(!"TODO");
-}
-
-void InstructionSelection::visitEnter(IR::Enter *)
-{
-    Q_UNIMPLEMENTED();
-    assert(!"TODO");
-}
-
-void InstructionSelection::visitLeave(IR::Leave *)
-{
-    Q_UNIMPLEMENTED();
-    assert(!"TODO");
-}
-
-#define setOp(op, opName, operation) \
-    do { op = operation; opName = isel_stringIfy(operation); } while (0)
-
-void InstructionSelection::visitMove(IR::Move *s)
-{
-
-    if (s->op == IR::OpInvalid) {
-        if (IR::Name *n = s->target->asName()) {
-            String *propertyName = identifier(*n->id);
-
-            if (s->source->asTemp() || s->source->asConst()) {
-                generateFunctionCall(Assembler::Void, __qmljs_set_activation_property, Assembler::ContextRegister, propertyName, s->source);
-                return;
-            } else {
-                Q_UNREACHABLE();
-            }
-        } else if (IR::Temp *t = s->target->asTemp()) {
-            if (IR::Name *n = s->source->asName()) {
-                if (*n->id == QStringLiteral("this")) { // ### `this' should be a builtin.
-                    generateFunctionCall(t, __qmljs_get_thisObject, Assembler::ContextRegister);
-                } else {
-                    String *propertyName = identifier(*n->id);
-                    generateFunctionCall(t, __qmljs_get_activation_property, Assembler::ContextRegister, propertyName);
-                }
-                return;
-            } else if (IR::Const *c = s->source->asConst()) {
-                Value v = convertToValue(c);
-                _asm->storeValue(v, t);
-                return;
-            } else if (IR::Temp *t2 = s->source->asTemp()) {
-                _asm->copyValue(t, t2);
-                return;
-            } else if (IR::String *str = s->source->asString()) {
-                Value v = Value::fromString(engine()->newString(*str->value));
-                _asm->storeValue(v, t);
-                return;
-            } else if (IR::RegExp *re = s->source->asRegExp()) {
-                Value v = Value::fromObject(engine()->newRegExpObject(*re->value, re->flags));
-                _asm->storeValue(v, t);
-                return;
-            } else if (IR::Closure *clos = s->source->asClosure()) {
-                VM::Function *vmFunc = vmFunction(clos->value);
-                assert(vmFunc);
-                generateFunctionCall(t, __qmljs_init_closure, Assembler::TrustedImmPtr(vmFunc), Assembler::ContextRegister);
-                return;
-            } else if (IR::New *ctor = s->source->asNew()) {
-                if (ctor->base->asName()) {
-                    constructActivationProperty(ctor, t);
-                    return;
-                } else if (ctor->base->asMember()) {
-                    constructProperty(ctor, t);
-                    return;
-                } else if (ctor->base->asTemp()) {
-                    constructValue(ctor, t);
-                    return;
-                }
-            } else if (IR::Member *m = s->source->asMember()) {
-                //__qmljs_get_property(ctx, result, object, name);
-                if (IR::Temp *base = m->base->asTemp()) {
-                    generateFunctionCall(t, __qmljs_get_property, Assembler::ContextRegister, base, identifier(*m->name));
-                    return;
-                }
-                assert(!"wip");
-                return;
-            } else if (IR::Subscript *ss = s->source->asSubscript()) {
-                generateFunctionCall(t, __qmljs_get_element, Assembler::ContextRegister, ss->base->asTemp(), ss->index->asTemp());
-                return;
-            } else if (IR::Unop *u = s->source->asUnop()) {
-                if (IR::Temp *e = u->expr->asTemp()) {
-                    Value (*op)(const Value value, ExecutionContext *ctx) = 0;
-                    const char *opName = 0;
-                    switch (u->op) {
-                    case IR::OpIfTrue: assert(!"unreachable"); break;
-                    case IR::OpNot: setOp(op, opName, __qmljs_not); break;
-                    case IR::OpUMinus: setOp(op, opName, __qmljs_uminus); break;
-                    case IR::OpUPlus: setOp(op, opName, __qmljs_uplus); break;
-                    case IR::OpCompl: setOp(op, opName, __qmljs_compl); break;
-                    case IR::OpIncrement: setOp(op, opName, __qmljs_increment); break;
-                    case IR::OpDecrement: setOp(op, opName, __qmljs_decrement); break;
-                    default: assert(!"unreachable"); break;
-                    } // switch
-
-                    if (op)
-                        _asm->generateFunctionCallImp(t, opName, op, e, Assembler::ContextRegister);
-                    return;
-                }
-            } else if (IR::Binop *b = s->source->asBinop()) {
-                if ((b->left->asTemp() || b->left->asConst()) &&
-                    (b->right->asTemp() || b->right->asConst())) {
-                    _asm->generateBinOp((IR::AluOp)b->op, t, b->left, b->right);
-                    return;
-                }
-            } else if (IR::Call *c = s->source->asCall()) {
-                if (c->base->asName()) {
-                    callActivationProperty(c, t);
-                    return;
-                } else if (c->base->asMember()) {
-                    callProperty(c, t);
-                    return;
-                } else if (c->base->asTemp()) {
-                    callValue(c, t);
-                    return;
-                }
-            }
-        } else if (IR::Member *m = s->target->asMember()) {
-            if (IR::Temp *base = m->base->asTemp()) {
-                if (s->source->asTemp() || s->source->asConst()) {
-                    generateFunctionCall(Assembler::Void, __qmljs_set_property, Assembler::ContextRegister, base, identifier(*m->name), s->source);
-                    return;
-                } else {
-                    Q_UNREACHABLE();
-                }
-            }
-        } else if (IR::Subscript *ss = s->target->asSubscript()) {
-            if (s->source->asTemp() || s->source->asConst()) {
-                generateFunctionCall(Assembler::Void, __qmljs_set_element, Assembler::ContextRegister, ss->base->asTemp(), ss->index->asTemp(), s->source);
-                return;
-            } else {
-                Q_UNIMPLEMENTED();
-            }
-        }
-    } else {
-        // inplace assignment, e.g. x += 1, ++x, ...
-        if (IR::Temp *t = s->target->asTemp()) {
-            if (s->source->asTemp() || s->source->asConst()) {
-                _asm->generateBinOp((IR::AluOp)s->op, t, t, s->source);
-                return;
-            }
-        } else if (IR::Name *n = s->target->asName()) {
-            if (s->source->asTemp() || s->source->asConst()) {
-                void (*op)(const Value value, String *name, ExecutionContext *ctx) = 0;
-                const char *opName = 0;
-                switch (s->op) {
-                case IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_name); break;
-                case IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_name); break;
-                case IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_name); break;
-                case IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_name); break;
-                case IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_name); break;
-                case IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_name); break;
-                case IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_name); break;
-                case IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_name); break;
-                case IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_name); break;
-                case IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_name); break;
-                case IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_name); break;
-                default:
-                    Q_UNREACHABLE();
-                    break;
-                }
-                if (op) {
-                    _asm->generateFunctionCallImp(Assembler::Void, opName, op, s->source, identifier(*n->id), Assembler::ContextRegister);
-                }
-                return;
-            }
-        } else if (IR::Subscript *ss = s->target->asSubscript()) {
-            if (s->source->asTemp() || s->source->asConst()) {
-                void (*op)(Value base, Value index, Value value, ExecutionContext *ctx) = 0;
-                const char *opName = 0;
-                switch (s->op) {
-                case IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_element); break;
-                case IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_element); break;
-                case IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_element); break;
-                case IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_element); break;
-                case IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_element); break;
-                case IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_element); break;
-                case IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_element); break;
-                case IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_element); break;
-                case IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_element); break;
-                case IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_element); break;
-                case IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_element); break;
-                default:
-                    Q_UNREACHABLE();
-                    break;
-                }
-
-                if (op) {
-                    IR::Temp* base = ss->base->asTemp();
-                    IR::Temp* index = ss->index->asTemp();
-                    _asm->generateFunctionCallImp(Assembler::Void, opName, op, base, index, s->source, Assembler::ContextRegister);
-                }
-                return;
-            }
-        } else if (IR::Member *m = s->target->asMember()) {
-            if (s->source->asTemp() || s->source->asConst()) {
-                void (*op)(Value value, Value base, String *name, ExecutionContext *ctx) = 0;
-                const char *opName = 0;
-                switch (s->op) {
-                case IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_member); break;
-                case IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_member); break;
-                case IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_member); break;
-                case IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_member); break;
-                case IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_member); break;
-                case IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_member); break;
-                case IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_member); break;
-                case IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_member); break;
-                case IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_member); break;
-                case IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_member); break;
-                case IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_member); break;
-                default:
-                    Q_UNREACHABLE();
-                    break;
-                }
-
-                if (op) {
-                    IR::Temp* base = m->base->asTemp();
-                    String* member = identifier(*m->name);
-                    _asm->generateFunctionCallImp(Assembler::Void, opName, op, s->source, base, member, Assembler::ContextRegister);
-                }
-                return;
-            }
-        }
-    }
-    Q_UNIMPLEMENTED();
-    s->dump(qout, IR::Stmt::MIR);
-    qout << endl;
-    assert(!"TODO");
-
-}
-
 void InstructionSelection::visitJump(IR::Jump *s)
 {
     _asm->jumpToBlock(_block, s->target);
index 481392c..c042bd6 100644 (file)
@@ -641,7 +641,9 @@ private:
     QList<CallToLink> _callsToLink;
 };
 
-class InstructionSelection: protected IR::StmtVisitor, public EvalInstructionSelection
+class InstructionSelection:
+        protected IR::InstructionSelection,
+        public EvalInstructionSelection
 {
 public:
     InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
@@ -650,6 +652,27 @@ public:
     virtual void run(VM::Function *vmFunction, IR::Function *function);
 
 protected:
+    virtual void callActivationProperty(IR::Call *call, IR::Temp *result);
+    virtual void callProperty(IR::Call *call, IR::Temp *result);
+    virtual void callValue(IR::Call *call, IR::Temp *result);
+    virtual void loadThisObject(IR::Temp *temp);
+    virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp);
+    virtual void loadString(const QString &str, IR::Temp *targetTemp);
+    virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp);
+    virtual void getActivationProperty(const QString &name, IR::Temp *temp);
+    virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
+    virtual void initClosure(IR::Closure *closure, IR::Temp *target);
+    virtual void getProperty(IR::Temp *base, const QString &name, IR::Temp *target);
+    virtual void setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+    virtual void getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target);
+    virtual void setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex);
+    virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp);
+    virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp);
+    virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+    virtual void inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName);
+    virtual void inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp);
+    virtual void inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+
     typedef Assembler::Address Address;
     typedef Assembler::Pointer Pointer;
 
@@ -679,17 +702,10 @@ protected:
     }
 
     VM::String *identifier(const QString &s);
-    void callActivationProperty(IR::Call *call, IR::Temp *result);
-    void callProperty(IR::Call *call, IR::Temp *result);
-    void constructActivationProperty(IR::New *call, IR::Temp *result);
-    void constructProperty(IR::New *ctor, IR::Temp *result);
-    void callValue(IR::Call *call, IR::Temp *result);
-    void constructValue(IR::New *call, IR::Temp *result);
-
-    virtual void visitExp(IR::Exp *);
-    virtual void visitEnter(IR::Enter *);
-    virtual void visitLeave(IR::Leave *);
-    virtual void visitMove(IR::Move *s);
+    virtual void constructActivationProperty(IR::New *call, IR::Temp *result);
+    virtual void constructProperty(IR::New *ctor, IR::Temp *result);
+    virtual void constructValue(IR::New *call, IR::Temp *result);
+
     virtual void visitJump(IR::Jump *);
     virtual void visitCJump(IR::CJump *);
     virtual void visitRet(IR::Ret *);
index 6d5d229..bff9f4a 100644 (file)
@@ -8,9 +8,14 @@
 
 #include <cassert>
 
+namespace {
+QTextStream qout(stderr, QIODevice::WriteOnly);
+} // anonymous namespace
+
 using namespace QQmlJS;
+using namespace QQmlJS::IR;
 
-EvalInstructionSelection::EvalInstructionSelection(VM::ExecutionEngine *engine, IR::Module *module)
+EvalInstructionSelection::EvalInstructionSelection(VM::ExecutionEngine *engine, Module *module)
     : _engine(engine)
 {
     assert(engine);
@@ -28,7 +33,7 @@ EvalInstructionSelection::~EvalInstructionSelection()
 EvalISelFactory::~EvalISelFactory()
 {}
 
-VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngine *engine, IR::Function *irFunction)
+VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngine *engine, Function *irFunction)
 {
     VM::Function *vmFunction = engine->newFunction(irFunction->name ? *irFunction->name : QString());
     _irToVM.insert(irFunction, vmFunction);
@@ -53,9 +58,159 @@ VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngin
     return vmFunction;
 }
 
-VM::Function *EvalInstructionSelection::vmFunction(IR::Function *f) {
+VM::Function *EvalInstructionSelection::vmFunction(Function *f) {
     VM::Function *function = _irToVM[f];
     if (!function->code)
         run(function, f);
     return function;
 }
+
+void InstructionSelection::visitMove(IR::Move *s)
+{
+    if (s->op == IR::OpInvalid) {
+        if (IR::Name *n = s->target->asName()) {
+            if (s->source->asTemp() || s->source->asConst()) {
+                setActivationProperty(s->source, *n->id);
+                return;
+            }
+        } else if (IR::Temp *t = s->target->asTemp()) {
+            if (IR::Name *n = s->source->asName()) {
+                if (*n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
+                    loadThisObject(t);
+                else
+                    getActivationProperty(*n->id, t);
+                return;
+            } else if (IR::Const *c = s->source->asConst()) {
+                loadConst(c, t);
+                return;
+            } else if (IR::Temp *t2 = s->source->asTemp()) {
+                copyValue(t2, t);
+                return;
+            } else if (IR::String *str = s->source->asString()) {
+                loadString(*str->value, t);
+                return;
+            } else if (IR::RegExp *re = s->source->asRegExp()) {
+                loadRegexp(re, t);
+                return;
+            } else if (IR::Closure *clos = s->source->asClosure()) {
+                initClosure(clos, t);
+                return;
+            } else if (IR::New *ctor = s->source->asNew()) {
+                if (ctor->base->asName()) {
+                    constructActivationProperty(ctor, t);
+                    return;
+                } else if (ctor->base->asMember()) {
+                    constructProperty(ctor, t);
+                    return;
+                } else if (ctor->base->asTemp()) {
+                    constructValue(ctor, t);
+                    return;
+                }
+            } else if (IR::Member *m = s->source->asMember()) {
+                if (IR::Temp *base = m->base->asTemp()) {
+                    getProperty(base, *m->name, t);
+                    return;
+                }
+            } else if (IR::Subscript *ss = s->source->asSubscript()) {
+                getElement(ss->base->asTemp(), ss->index->asTemp(), t);
+                return;
+            } else if (IR::Unop *u = s->source->asUnop()) {
+                if (IR::Temp *e = u->expr->asTemp()) {
+                    unop(u->op, e, t);
+                    return;
+                }
+            } else if (IR::Binop *b = s->source->asBinop()) {
+                if ((b->left->asTemp() || b->left->asConst())
+                        && (b->right->asTemp() || b->right->asConst())) {
+                    binop(b->op, b->left, b->right, t);
+                    return;
+                }
+            } else if (IR::Call *c = s->source->asCall()) {
+                if (c->base->asName()) {
+                    callActivationProperty(c, t);
+                    return;
+                } else if (c->base->asMember()) {
+                    callProperty(c, t);
+                    return;
+                } else if (c->base->asTemp()) {
+                    callValue(c, t);
+                    return;
+                }
+            }
+        } else if (IR::Member *m = s->target->asMember()) {
+            if (IR::Temp *base = m->base->asTemp()) {
+                if (s->source->asTemp() || s->source->asConst()) {
+                    setProperty(s->source, base, *m->name);
+                    return;
+                }
+            }
+        } else if (IR::Subscript *ss = s->target->asSubscript()) {
+            if (s->source->asTemp() || s->source->asConst()) {
+                setElement(s->source, ss->base->asTemp(), ss->index->asTemp());
+                return;
+            }
+        }
+    } else {
+        // inplace assignment, e.g. x += 1, ++x, ...
+        if (IR::Temp *t = s->target->asTemp()) {
+            if (s->source->asTemp() || s->source->asConst()) {
+                binop(s->op, t, s->source, t);
+                return;
+            }
+        } else if (IR::Name *n = s->target->asName()) {
+            if (s->source->asTemp() || s->source->asConst()) {
+                inplaceNameOp(s->op, s->source, *n->id);
+                return;
+            }
+        } else if (IR::Subscript *ss = s->target->asSubscript()) {
+            if (s->source->asTemp() || s->source->asConst()) {
+                inplaceElementOp(s->op, s->source, ss->base->asTemp(),
+                                 ss->index->asTemp());
+                return;
+            }
+        } else if (IR::Member *m = s->target->asMember()) {
+            if (s->source->asTemp() || s->source->asConst()) {
+                inplaceMemberOp(s->op, s->source, m->base->asTemp(), *m->name);
+                return;
+            }
+        }
+    }
+
+    // For anything else...:
+    Q_UNIMPLEMENTED();
+    s->dump(qout, IR::Stmt::MIR);
+    qout << endl;
+    assert(!"TODO");
+}
+
+InstructionSelection::~InstructionSelection()
+{
+}
+
+void InstructionSelection::visitEnter(Enter *)
+{
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::visitLeave(Leave *)
+{
+    Q_UNREACHABLE();
+}
+
+void InstructionSelection::visitExp(IR::Exp *s)
+{
+    if (IR::Call *c = s->expr->asCall()) {
+        // These are calls where the result is ignored.
+        if (c->base->asName()) {
+            callActivationProperty(c, 0);
+        } else if (c->base->asTemp()) {
+            callValue(c, 0);
+        } else if (c->base->asMember()) {
+            callProperty(c, 0);
+        } else {
+            Q_UNREACHABLE();
+        }
+    } else {
+        Q_UNREACHABLE();
+    }
+}
index 221a564..59464c6 100644 (file)
 #ifndef QV4ISEL_P_H
 #define QV4ISEL_P_H
 
+#include "qv4ir_p.h"
+
 #include <qglobal.h>
 #include <QHash>
 
 namespace QQmlJS {
 
-namespace IR {
-struct Function;
-struct Module;
-} // namespace IR;
-
 namespace VM {
 struct ExecutionEngine;
 struct Function;
@@ -70,6 +67,45 @@ public:
     virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine, IR::Module *module) = 0;
 };
 
+namespace IR {
+class InstructionSelection: protected IR::StmtVisitor
+{
+public:
+    virtual ~InstructionSelection() = 0;
+
+public: // visitor methods for StmtVisitor:
+    virtual void visitMove(IR::Move *s);
+    virtual void visitEnter(IR::Enter *);
+    virtual void visitLeave(IR::Leave *);
+    virtual void visitExp(IR::Exp *s);
+
+public: // to implement by subclasses:
+    virtual void callActivationProperty(IR::Call *c, IR::Temp *temp) = 0;
+    virtual void callValue(IR::Call *c, IR::Temp *temp) = 0;
+    virtual void callProperty(IR::Call *c, IR::Temp *temp) = 0;
+    virtual void constructActivationProperty(IR::New *call, IR::Temp *result) = 0;
+    virtual void constructProperty(IR::New *ctor, IR::Temp *result) = 0;
+    virtual void constructValue(IR::New *call, IR::Temp *result) = 0;
+    virtual void loadThisObject(IR::Temp *temp) = 0;
+    virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp) = 0;
+    virtual void loadString(const QString &str, IR::Temp *targetTemp) = 0;
+    virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp) = 0;
+    virtual void getActivationProperty(const QString &name, IR::Temp *temp) = 0;
+    virtual void setActivationProperty(IR::Expr *source, const QString &targetName) = 0;
+    virtual void initClosure(IR::Closure *closure, IR::Temp *target) = 0;
+    virtual void getProperty(IR::Temp *base, const QString &name, IR::Temp *target) = 0;
+    virtual void setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName) = 0;
+    virtual void getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target) = 0;
+    virtual void setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex) = 0;
+    virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0;
+    virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0;
+    virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) = 0;
+    virtual void inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName) = 0;
+    virtual void inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp) = 0;
+    virtual void inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName) = 0;
+};
+} // namespace IR
+
 } // namespace QQmlJS
 
 #endif // QV4ISEL_P_H