diff options
-rw-r--r-- | moth/qv4isel_moth.cpp | 2 | ||||
-rw-r--r-- | qmljs_runtime.cpp | 22 | ||||
-rw-r--r-- | qmljs_runtime.h | 2 | ||||
-rw-r--r-- | qv4codegen.cpp | 48 | ||||
-rw-r--r-- | qv4ir.cpp | 2 | ||||
-rw-r--r-- | qv4ir_p.h | 2 | ||||
-rw-r--r-- | qv4isel_masm.cpp | 4 |
7 files changed, 75 insertions, 7 deletions
diff --git a/moth/qv4isel_moth.cpp b/moth/qv4isel_moth.cpp index 328fdce38c..5b00ccf552 100644 --- a/moth/qv4isel_moth.cpp +++ b/moth/qv4isel_moth.cpp @@ -653,6 +653,8 @@ void InstructionSelection::visitMove(IR::Move *s) 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 diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index 25a3c11ec0..5ef2c6c9f0 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -873,6 +873,28 @@ void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String * ctx->createMutableBinding(name, deletable); } +Value __qmljs_increment(Value value, ExecutionContext *ctx) +{ + TRACE1(value); + + if (value.isInteger()) + return Value::fromInt32(value.integerValue() + 1); + + double d = __qmljs_to_number(value, ctx); + return Value::fromDouble(d + 1); +} + +Value __qmljs_decrement(Value value, ExecutionContext *ctx) +{ + TRACE1(value); + + if (value.isInteger()) + return Value::fromInt32(value.integerValue() - 1); + + double d = __qmljs_to_number(value, ctx); + return Value::fromDouble(d - 1); +} + } // extern "C" diff --git a/qmljs_runtime.h b/qmljs_runtime.h index 2de6f19f55..263c151145 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -174,6 +174,8 @@ Value __qmljs_uplus(Value value, ExecutionContext *ctx); Value __qmljs_uminus(Value value, ExecutionContext *ctx); Value __qmljs_compl(Value value, ExecutionContext *ctx); Value __qmljs_not(Value value, ExecutionContext *ctx); +Value __qmljs_increment(Value value, ExecutionContext *ctx); +Value __qmljs_decrement(Value value, ExecutionContext *ctx); Value __qmljs_delete_subscript(ExecutionContext *ctx, Value base, Value index); Value __qmljs_delete_member(ExecutionContext *ctx, Value base, String *name); diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 48027863f3..fef6b4e733 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -515,6 +515,10 @@ IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr) return expr; case IR::OpCompl: return _block->CONST(IR::NumberType, ~VM::Value::toInt32(c->value)); + case IR::OpIncrement: + return _block->CONST(IR::NumberType, c->value + 1); + case IR::OpDecrement: + return _block->CONST(IR::NumberType, c->value - 1); default: break; } @@ -567,6 +571,8 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right) case IR::OpUMinus: case IR::OpUPlus: case IR::OpCompl: + case IR::OpIncrement: + case IR::OpDecrement: case IR::OpInvalid: break; } @@ -1310,13 +1316,21 @@ bool Codegen::visit(ObjectLiteral *ast) bool Codegen::visit(PostDecrementExpression *ast) { + // ### + // Throw a SyntaxError exception if the following conditions are all true: + // Type(lhs) is Reference is true + // IsStrictReference(lhs) is true + // Type(GetBase(lhs)) is Environment Record + // GetReferencedName(lhs) is either "eval" or "arguments" + + Result expr = expression(ast->base); if (_expr.accept(nx)) { - move(*expr, _block->CONST(IR::NumberType, 1), IR::OpSub); + move(*expr, unop(IR::OpDecrement, *expr)); } else { const unsigned t = _block->newTemp(); move(_block->TEMP(t), *expr); - move(*expr, _block->CONST(IR::NumberType, 1), IR::OpSub); + move(*expr, unop(IR::OpDecrement, _block->TEMP(t))); _expr.code = _block->TEMP(t); } return false; @@ -1324,13 +1338,20 @@ bool Codegen::visit(PostDecrementExpression *ast) bool Codegen::visit(PostIncrementExpression *ast) { + // ### + // Throw a SyntaxError exception if the following conditions are all true: + // Type(lhs) is Reference is true + // IsStrictReference(lhs) is true + // Type(GetBase(lhs)) is Environment Record + // GetReferencedName(lhs) is either "eval" or "arguments" + Result expr = expression(ast->base); if (_expr.accept(nx)) { - move(*expr, _block->CONST(IR::NumberType, 1), IR::OpAdd); + move(*expr, unop(IR::OpIncrement, *expr)); } else { const unsigned t = _block->newTemp(); move(_block->TEMP(t), *expr); - move(*expr, _block->CONST(IR::NumberType, 1), IR::OpAdd); + move(*expr, unop(IR::OpIncrement, _block->TEMP(t))); _expr.code = _block->TEMP(t); } return false; @@ -1338,8 +1359,15 @@ bool Codegen::visit(PostIncrementExpression *ast) bool Codegen::visit(PreDecrementExpression *ast) { + // ### + // Throw a SyntaxError exception if the following conditions are all true: + // Type(lhs) is Reference is true + // IsStrictReference(lhs) is true + // Type(GetBase(lhs)) is Environment Record + // GetReferencedName(lhs) is either "eval" or "arguments" + Result expr = expression(ast->expression); - move(*expr, _block->CONST(IR::NumberType, 1), IR::OpSub); + move(*expr, unop(IR::OpDecrement, *expr)); if (_expr.accept(nx)) { // nothing to do } else { @@ -1350,9 +1378,15 @@ bool Codegen::visit(PreDecrementExpression *ast) bool Codegen::visit(PreIncrementExpression *ast) { - Result expr = expression(ast->expression); - move(*expr, _block->CONST(IR::NumberType, 1), IR::OpAdd); + // ### + // Throw a SyntaxError exception if the following conditions are all true: + // Type(lhs) is Reference is true + // IsStrictReference(lhs) is true + // Type(GetBase(lhs)) is Environment Record + // GetReferencedName(lhs) is either "eval" or "arguments" + Result expr = expression(ast->expression); + move(*expr, unop(IR::OpIncrement, *expr)); if (_expr.accept(nx)) { // nothing to do } else { @@ -73,6 +73,8 @@ const char *opname(AluOp op) case OpUMinus: return "-"; case OpUPlus: return "+"; case OpCompl: return "~"; + case OpIncrement: return "++"; + case OpDecrement: return "--"; case OpBitAnd: return "&"; case OpBitOr: return "|"; @@ -115,6 +115,8 @@ enum AluOp { OpUMinus, OpUPlus, OpCompl, + OpIncrement, + OpDecrement, OpBitAnd, OpBitOr, diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp index d667fa5cb3..cabd1f7c5c 100644 --- a/qv4isel_masm.cpp +++ b/qv4isel_masm.cpp @@ -187,6 +187,8 @@ const Assembler::BinaryOperationInfo Assembler::binaryOperations[QQmlJS::IR::Las NULL_OP, // OpUMinus NULL_OP, // OpUPlus NULL_OP, // OpCompl + NULL_OP, // OpIncrement + NULL_OP, // OpDecrement INLINE_OP(__qmljs_bit_and, &Assembler::inline_and32, &Assembler::inline_and32), // OpBitAnd INLINE_OP(__qmljs_bit_or, &Assembler::inline_or32, &Assembler::inline_or32), // OpBitOr @@ -688,6 +690,8 @@ void InstructionSelection::visitMove(IR::Move *s) 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 |