diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2017-06-20 11:28:27 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-06-21 09:19:59 +0000 |
commit | 48d77ce4c83c2c1d2f3ee3d01c69550e115c3226 (patch) | |
tree | b62edfd573502ded0ff436c250992684d3770567 | |
parent | 5c86161fa28e951435a735a299b886fbfbe3bb16 (diff) |
Add support for post increment/decrement
Change-Id: Ie3f03a548105fe49d29e3d60bf823435f21b0340
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 77 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 16 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 26 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 12 | ||||
-rw-r--r-- | src/qml/jit/qv4unop.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 44 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 24 |
12 files changed, 147 insertions, 88 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 6567b9a1ce..56d28d2147 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -924,10 +924,8 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) return expr; case Compl: return Reference::fromConst(this, Runtime::method_complement(v)); - case Increment: - return Reference::fromConst(this, Runtime::method_increment(v)); - case Decrement: - return Reference::fromConst(this, Runtime::method_decrement(v)); + default: + break; } } } @@ -960,17 +958,35 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) ucompl.result = dest.asLValue(); bytecodeGenerator->addInstruction(ucompl); } break; - case Increment: { - Instruction::Increment inc; + case PreIncrement: { + Instruction::PreIncrement inc; inc.source = expr.asRValue(); inc.result = dest.asLValue(); bytecodeGenerator->addInstruction(inc); + expr.store(dest); } break; - case Decrement: { - Instruction::Decrement dec; + case PreDecrement: { + Instruction::PreDecrement dec; dec.source = expr.asRValue(); dec.result = dest.asLValue(); bytecodeGenerator->addInstruction(dec); + expr.store(dest); + } break; + case PostIncrement: { + Instruction::PostIncrement inc; + inc.source = expr.asRValue(); + inc.result = dest.asLValue(); + bytecodeGenerator->addInstruction(inc); + expr.asLValue(); // mark expr as needsWriteBack + expr.writeBack(); + } break; + case PostDecrement: { + Instruction::PostDecrement dec; + dec.source = expr.asRValue(); + dec.result = dest.asLValue(); + bytecodeGenerator->addInstruction(dec); + expr.asLValue(); // mark expr as needsWriteBack + expr.writeBack(); } break; } @@ -2175,13 +2191,7 @@ bool Codegen::visit(PostDecrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken)) return false; - Reference oldValue = unop(UPlus, expr); - - TempScope scope(this); - Reference newValue = unop(Decrement, oldValue); - expr.store(newValue); - - _expr.result = oldValue; + _expr.result = unop(PostDecrement, expr); return false; } @@ -2201,14 +2211,7 @@ bool Codegen::visit(PostIncrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken)) return false; - Reference oldValue = unop(UPlus, expr); - - TempScope scope(this); - Reference newValue = unop(Increment, oldValue); - expr.store(newValue); - - _expr.result = oldValue; - + _expr.result = unop(PostIncrement, expr); return false; } @@ -2226,19 +2229,7 @@ bool Codegen::visit(PreDecrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken)) return false; - auto tmp = unop(Decrement, expr); - if (_expr.accept(nx)) { - bytecodeGenerator->setLocation(ast->decrementToken); - expr.store(tmp); - } else { - if (!tmp.isTempLocalArg()) { - auto tmp2 = Reference::fromTemp(this); - tmp2.store(tmp); - tmp = tmp2; - } - expr.store(tmp); - _expr.result = tmp; - } + _expr.result = unop(PreDecrement, expr); return false; } @@ -2257,19 +2248,7 @@ bool Codegen::visit(PreIncrementExpression *ast) if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken)) return false; - auto tmp = unop(Increment, expr); - if (_expr.accept(nx)) { - bytecodeGenerator->setLocation(ast->incrementToken); - expr.store(tmp); - } else { - if (!tmp.isTempLocalArg()) { - auto tmp2 = Reference::fromTemp(this); - tmp2.store(tmp); - tmp = tmp2; - } - expr.store(tmp); - _expr.result = tmp; - } + _expr.result = unop(PreIncrement, expr); return false; } diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 193681096e..db806f3f5e 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -463,8 +463,10 @@ protected: enum UnaryOperation { UPlus, UMinus, - Increment, - Decrement, + PreIncrement, + PreDecrement, + PostIncrement, + PostDecrement, Not, Compl }; diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 3f234f1394..07ffdfae03 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -412,13 +412,21 @@ void dumpBytecode(const char *code, int len) d << instr.result << ", " << instr.source; MOTH_END_INSTR(UComplInt) - MOTH_BEGIN_INSTR(Increment) + MOTH_BEGIN_INSTR(PreIncrement) d << instr.result << ", " << instr.source; - MOTH_END_INSTR(Increment) + MOTH_END_INSTR(PreIncrement) - MOTH_BEGIN_INSTR(Decrement) + MOTH_BEGIN_INSTR(PreDecrement) d << instr.result << ", " << instr.source; - MOTH_END_INSTR(Decrement) + MOTH_END_INSTR(PreDecrement) + + MOTH_BEGIN_INSTR(PostIncrement) + d << instr.result << ", " << instr.source; + MOTH_END_INSTR(PostIncrement) + + MOTH_BEGIN_INSTR(PostDecrement) + d << instr.result << ", " << instr.source; + MOTH_END_INSTR(PostDecrement) MOTH_BEGIN_INSTR(Binop) d << instr.alu << ", " << instr.result << ", " << instr.lhs << ", " << instr.rhs; diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 6625018443..ab22053e29 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -146,8 +146,10 @@ QT_BEGIN_NAMESPACE F(UMinus, uminus) \ F(UCompl, ucompl) \ F(UComplInt, ucomplInt) \ - F(Increment, increment) \ - F(Decrement, decrement) \ + F(PreIncrement, preIncrement) \ + F(PreDecrement, preDecrement) \ + F(PostIncrement, postIncrement) \ + F(PostDecrement, postDecrement) \ F(Binop, binop) \ F(Add, add) \ F(BitAnd, bitAnd) \ @@ -703,12 +705,22 @@ union Instr Param source; Param result; }; - struct instr_increment { + struct instr_preIncrement { MOTH_INSTR_HEADER Param source; Param result; }; - struct instr_decrement { + struct instr_preDecrement { + MOTH_INSTR_HEADER + Param source; + Param result; + }; + struct instr_postIncrement { + MOTH_INSTR_HEADER + Param source; + Param result; + }; + struct instr_postDecrement { MOTH_INSTR_HEADER Param source; Param result; @@ -901,8 +913,10 @@ union Instr instr_uminus uminus; instr_ucompl ucompl; instr_ucomplInt ucomplInt; - instr_increment increment; - instr_decrement decrement; + instr_preIncrement preIncrement; + instr_preDecrement preDecrement; + instr_postIncrement postIncrement; + instr_postDecrement postDecrement; instr_binop binop; instr_add add; instr_bitAnd bitAnd; diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 24fbe3c680..986529f600 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -754,15 +754,15 @@ void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *targ addInstruction(ucompl); return; } - case IR::OpIncrement: { - Instruction::Increment inc; + case IR::OpPreIncrement: { + Instruction::PreIncrement inc; inc.source = getParam(source); inc.result = getResultParam(target); addInstruction(inc); return; } - case IR::OpDecrement: { - Instruction::Decrement dec; + case IR::OpPreDecrement: { + Instruction::PreDecrement dec; dec.source = getParam(source); dec.result = getResultParam(target); addInstruction(dec); diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 5a58380005..464eb008e7 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -90,8 +90,10 @@ const char *opname(AluOp op) case OpUMinus: return "neg"; case OpUPlus: return "plus"; case OpCompl: return "invert"; - case OpIncrement: return "incr"; - case OpDecrement: return "decr"; + case OpPreIncrement: return "pre-incr"; + case OpPreDecrement: return "pre-decr"; + case OpPostIncrement: return "post-incr"; + case OpPostDecrement: return "post-decr"; case OpBitAnd: return "bitand"; case OpBitOr: return "bitor"; diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 1b77dbf096..82632c391e 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -156,8 +156,10 @@ enum AluOp { OpUMinus, OpUPlus, OpCompl, - OpIncrement, - OpDecrement, + OpPreIncrement, + OpPreDecrement, + OpPostIncrement, + OpPostDecrement, OpBitAnd, OpBitOr, diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 8cf5fac760..72a4a9e751 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -1993,8 +1993,8 @@ private: case OpUPlus: case OpUMinus: case OpNot: - case OpIncrement: - case OpDecrement: + case OpPreIncrement: + case OpPreDecrement: if (e->expr->type == VarType || e->expr->type == StringType || e->expr->type == QObjectType) markAsSideEffect(); break; @@ -2342,8 +2342,8 @@ private: case OpCompl: _ty.type = SInt32Type; return; case OpNot: _ty.type = BoolType; return; - case OpIncrement: - case OpDecrement: + case OpPreIncrement: + case OpPreDecrement: Q_ASSERT(!"Inplace operators should have been removed!"); Q_UNREACHABLE(); default: @@ -4178,11 +4178,11 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) constOperand->type = SInt32Type; doneSomething = true; break; - case OpIncrement: + case OpPreIncrement: constOperand->value = constOperand->value + 1; doneSomething = true; break; - case OpDecrement: + case OpPreDecrement: constOperand->value = constOperand->value - 1; doneSomething = true; break; diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp index 78546e1509..829f46ed96 100644 --- a/src/qml/jit/qv4unop.cpp +++ b/src/qml/jit/qv4unop.cpp @@ -69,8 +69,8 @@ void Unop<JITAssembler>::generate(IR::Expr *source, IR::Expr *target) case IR::OpCompl: generateCompl(source, target); return; - case IR::OpIncrement: setOp(increment); break; - case IR::OpDecrement: setOp(decrement); break; + case IR::OpIncrement: setOp(preIncrement); break; + case IR::OpDecrement: setOp(preDecrement); break; default: Q_UNREACHABLE(); } // switch diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 9737a18812..3342075f7f 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1414,7 +1414,7 @@ QV4::ReturnedValue Runtime::method_setupArgumentsObject(ExecutionEngine *engine) #endif // V4_BOOTSTRAP -QV4::ReturnedValue Runtime::method_increment(const Value &value) +QV4::ReturnedValue Runtime::method_preIncrement(const Value &value) { TRACE1(value); @@ -1426,7 +1426,7 @@ QV4::ReturnedValue Runtime::method_increment(const Value &value) } } -QV4::ReturnedValue Runtime::method_decrement(const Value &value) +QV4::ReturnedValue Runtime::method_preDecrement(const Value &value) { TRACE1(value); @@ -1438,6 +1438,46 @@ QV4::ReturnedValue Runtime::method_decrement(const Value &value) } } +QV4::ReturnedValue Runtime::method_postIncrement(Value *value) +{ + TRACE1(value); + + if (value->isNumber()) { + Value old = *value; + if (value->isInteger() && value->integerValue() < INT_MAX) { + *value = Primitive::fromInt32(value->integerValue() + 1); + } else { + *value = Primitive::fromDouble(value->doubleValue() + 1.0); + } + return old.asReturnedValue(); + } + + // ToNumber conversion needed: + double d = value->toNumberImpl(); + *value = Primitive::fromDouble(d + 1.); + return Encode(d); +} + +QV4::ReturnedValue Runtime::method_postDecrement(Value *value) +{ + TRACE1(value); + + if (value->isNumber()) { + Value old = *value; + if (value->isInteger() && value->integerValue() > INT_MIN) { + *value = Primitive::fromInt32(value->integerValue() - 1); + } else { + *value = Primitive::fromDouble(value->doubleValue() - 1.0); + } + return old.asReturnedValue(); + } + + // ToNumber conversion needed: + double d = value->toNumber(); + *value = Primitive::fromDouble(d - 1.); + return Encode(d); +} + ReturnedValue Runtime::method_toDouble(const Value &value) { TRACE1(value); diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 302facba06..fdb24d5ca2 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -160,8 +160,10 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(ReturnedValue, uMinus, (const Value &value)) \ F(ReturnedValue, uNot, (const Value &value)) \ F(ReturnedValue, complement, (const Value &value)) \ - F(ReturnedValue, increment, (const Value &value)) \ - F(ReturnedValue, decrement, (const Value &value)) \ + F(ReturnedValue, preIncrement, (const Value &value)) \ + F(ReturnedValue, preDecrement, (const Value &value)) \ + F(ReturnedValue, postIncrement, (Value *value)) \ + F(ReturnedValue, postDecrement, (Value *value)) \ \ /* binary operators */ \ F(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 1f1e202a2d..5b026b2f0d 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -857,13 +857,23 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) VALUE(instr.result) = QV4::Encode((int)~VALUE(instr.source).integerValue()); MOTH_END_INSTR(UComplInt) - MOTH_BEGIN_INSTR(Increment) - STOREVALUE(instr.result, Runtime::method_increment(VALUE(instr.source))); - MOTH_END_INSTR(Increment) - - MOTH_BEGIN_INSTR(Decrement) - STOREVALUE(instr.result, Runtime::method_decrement(VALUE(instr.source))); - MOTH_END_INSTR(Decrement) + MOTH_BEGIN_INSTR(PreIncrement) + STOREVALUE(instr.result, Runtime::method_preIncrement(VALUE(instr.source))); + MOTH_END_INSTR(PreIncrement) + + MOTH_BEGIN_INSTR(PreDecrement) + STOREVALUE(instr.result, Runtime::method_preDecrement(VALUE(instr.source))); + MOTH_END_INSTR(PreDecrement) + + MOTH_BEGIN_INSTR(PostIncrement) + //### we probably need a write-barrier for instr.source, because it will be written to + STOREVALUE(instr.result, Runtime::method_postIncrement(VALUEPTR(instr.source))); + MOTH_END_INSTR(PreIncrement) + + MOTH_BEGIN_INSTR(PostDecrement) + //### we probably need a write-barrier for instr.source, because it will be written to + STOREVALUE(instr.result, Runtime::method_postDecrement(VALUEPTR(instr.source))); + MOTH_END_INSTR(PreDecrement) MOTH_BEGIN_INSTR(Binop) QV4::Runtime::BinaryOperation op = *reinterpret_cast<QV4::Runtime::BinaryOperation *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu])); |