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)
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);
}
}
-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);
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);
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;
}
}
-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;
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);
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;
};
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; }
//----
llvm::InitializeNativeTarget();
- LLVMInstructionSelection llvmIsel(llvm::getGlobalContext());
+ LLVM::InstructionSelection llvmIsel(llvm::getGlobalContext());
const QString moduleName = QFileInfo(fileName).fileName();
llvm::StringRef moduleId(moduleName.toUtf8().constData());
} // 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)
{
}
-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);
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) {
return f;
}
-llvm::Function *LLVMInstructionSelection::compileLLVMFunction(IR::Function *function)
+llvm::Function *InstructionSelection::compileLLVMFunction(IR::Function *function)
{
llvm::Function *llvmFunction = getLLVMFunction(function);
return llvmFunction;
}
-llvm::BasicBlock *LLVMInstructionSelection::getLLVMBasicBlock(IR::BasicBlock *block)
+llvm::BasicBlock *InstructionSelection::getLLVMBasicBlock(IR::BasicBlock *block)
{
llvm::BasicBlock *&llvmBlock = _blockMap[block];
if (! llvmBlock)
return llvmBlock;
}
-llvm::Value *LLVMInstructionSelection::getLLVMValue(IR::Expr *expr)
+llvm::Value *InstructionSelection::getLLVMValue(IR::Expr *expr)
{
llvm::Value *llvmValue = 0;
if (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);
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()) {
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;
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) {
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"),
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);
_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);
_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()) {
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);
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"),
_llvmValue = CreateLoad(tmp);
}
-void LLVMInstructionSelection::visitRegExp(IR::RegExp *e)
+void InstructionSelection::visitRegExp(IR::RegExp *e)
{
e->dump(qerr);
qerr << endl;
_llvmValue = llvm::Constant::getNullValue(_valueTy);
}
-void LLVMInstructionSelection::visitName(IR::Name *e)
+void InstructionSelection::visitName(IR::Name *e)
{
llvm::Value *result = newLLVMTemp(_valueTy);
}
-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);
_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);
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());
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;
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);
_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);
_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);
_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);
_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();
}
}
-void LLVMInstructionSelection::genConstructName(IR::New *e, llvm::Value *result)
+void InstructionSelection::genConstructName(IR::New *e, llvm::Value *result)
{
IR::Name *base = e->base->asName();
}
}
-void LLVMInstructionSelection::visitCall(IR::Call *e)
+void InstructionSelection::visitCall(IR::Call *e)
{
if (e->base->asMember()) {
genCallMember(e);
}
}
-void LLVMInstructionSelection::visitNew(IR::New *e)
+void InstructionSelection::visitNew(IR::New *e)
{
if (e->base->asMember()) {
genConstructMember(e);
}
}
-void LLVMInstructionSelection::visitSubscript(IR::Subscript *e)
+void InstructionSelection::visitSubscript(IR::Subscript *e)
{
llvm::Value *result = newLLVMTemp(_valueTy);
llvm::Value *base = getLLVMTempReference(e->base);
_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);
_llvmValue = CreateLoad(result);
}
-llvm::Value *LLVMInstructionSelection::createValue(IR::Const *e)
+llvm::Value *InstructionSelection::createValue(IR::Const *e)
{
llvm::Value *tmp = newLLVMTemp(_valueTy);
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);
#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);
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);
llvm::FunctionPassManager *_fpm;
};
-} // end of namespace QQmlJS
+} // LLVM namespace
+} // QQmlJS namespace
#endif // QV4ISEL_LLVM_P_H
using namespace QQmlJS::MASM;
using namespace QQmlJS::VM;
-namespace {
-QTextStream qout(stderr, QIODevice::WriteOnly);
-}
-
Assembler::Assembler(IR::Function* function)
: _function(function)
{
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();
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);
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);
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;
}
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 *);
#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);
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);
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();
+ }
+}
#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;
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