aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--moth/qv4isel_moth.cpp2
-rw-r--r--qmljs_runtime.cpp22
-rw-r--r--qmljs_runtime.h2
-rw-r--r--qv4codegen.cpp48
-rw-r--r--qv4ir.cpp2
-rw-r--r--qv4ir_p.h2
-rw-r--r--qv4isel_masm.cpp4
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 {
diff --git a/qv4ir.cpp b/qv4ir.cpp
index 3cceeb8680..33b8b7721d 100644
--- a/qv4ir.cpp
+++ b/qv4ir.cpp
@@ -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 "|";
diff --git a/qv4ir_p.h b/qv4ir_p.h
index c6d05d21c4..b605e60b26 100644
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -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