diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 6e8537af6c..967d53e9aa 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -380,7 +380,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } // If result_saved == true: the result is saved on top of the stack. - // If result_saved == false: the result is in eax. + // If result_saved == false: the result is in r0. bool result_saved = false; for (int i = 0; i < expr->properties()->length(); i++) { @@ -972,6 +972,81 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { } +void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { + VariableProxy* v = expr->expression()->AsVariableProxy(); + ASSERT(v->AsVariable() != NULL); + ASSERT(v->AsVariable()->is_global()); + + Visit(v); + + __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); + + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kValue: // Fall through + case Expression::kTest: // Fall through + case Expression::kTestValue: // Fall through + case Expression::kValueTest: + // Duplicate the result on the stack. + __ push(r0); + break; + case Expression::kEffect: + // Do not save result. + break; + } + // Call runtime for +1/-1. + __ push(r0); + __ mov(ip, Operand(Smi::FromInt(1))); + __ push(ip); + if (expr->op() == Token::INC) { + __ CallRuntime(Runtime::kNumberAdd, 2); + } else { + __ CallRuntime(Runtime::kNumberSub, 2); + } + // Call Store IC. + __ mov(r2, Operand(v->AsVariable()->name())); + __ ldr(ip, CodeGenerator::GlobalObject()); + __ push(ip); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + // Restore up stack after store IC. + __ add(sp, sp, Operand(kPointerSize)); + + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: // Fall through + case Expression::kValue: + // Do nothing. Result in either on the stack for value context + // or discarded for effect context. + break; + case Expression::kTest: + __ pop(r0); + TestAndBranch(r0, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + __ ldr(r0, MemOperand(sp)); + TestAndBranch(r0, true_label_, &discard); + __ bind(&discard); + __ add(sp, sp, Operand(kPointerSize)); + __ b(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + __ ldr(r0, MemOperand(sp)); + TestAndBranch(r0, &discard, false_label_); + __ bind(&discard); + __ add(sp, sp, Operand(kPointerSize)); + __ b(true_label_); + break; + } + } +} + + void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { switch (expr->op()) { case Token::COMMA: diff --git a/src/compiler.cc b/src/compiler.cc index e70b64a24b..e9db632db7 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -847,7 +847,11 @@ void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) { void CodeGenSelector::VisitCountOperation(CountOperation* expr) { - BAILOUT("CountOperation"); + // We support postfix count operations on global variables. + if (expr->is_prefix()) BAILOUT("Prefix CountOperation"); + Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); + if (var == NULL || !var->is_global()) BAILOUT("non-global postincrement"); + ProcessExpression(expr->expression(), Expression::kValue); } diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index 7d7b21fdc5..615821fc27 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -434,11 +434,6 @@ void FastCodeGenerator::VisitThrow(Throw* expr) { } -void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { - UNREACHABLE(); -} - - void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { UNREACHABLE(); } diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index a2114e5cdf..9225934aee 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -993,6 +993,79 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { } +void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { + VariableProxy* v = expr->expression()->AsVariableProxy(); + ASSERT(v->AsVariable() != NULL); + ASSERT(v->AsVariable()->is_global()); + + Visit(v); + + __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); + + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kValue: // Fall through + case Expression::kTest: // Fall through + case Expression::kTestValue: // Fall through + case Expression::kValueTest: + // Duplicate the result on the stack. + __ push(eax); + break; + case Expression::kEffect: + // Do not save result. + break; + } + // Call runtime for +1/-1. + __ push(eax); + __ push(Immediate(Smi::FromInt(1))); + if (expr->op() == Token::INC) { + __ CallRuntime(Runtime::kNumberAdd, 2); + } else { + __ CallRuntime(Runtime::kNumberSub, 2); + } + // Call Store IC. + __ mov(ecx, v->AsVariable()->name()); + __ push(CodeGenerator::GlobalObject()); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + // Restore up stack after store IC. + __ add(Operand(esp), Immediate(kPointerSize)); + + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: // Fall through + case Expression::kValue: + // Do nothing. Result in either on the stack for value context + // or discarded for effect context. + break; + case Expression::kTest: + __ pop(eax); + TestAndBranch(eax, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + __ mov(eax, Operand(esp, 0)); + TestAndBranch(eax, true_label_, &discard); + __ bind(&discard); + __ add(Operand(esp), Immediate(kPointerSize)); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + __ mov(eax, Operand(esp, 0)); + TestAndBranch(eax, &discard, false_label_); + __ bind(&discard); + __ add(Operand(esp), Immediate(kPointerSize)); + __ jmp(true_label_); + break; + } + } +} + + void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { switch (expr->op()) { case Token::COMMA: diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index 70ce36a1e3..d9cfa299cd 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -914,6 +914,78 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { Move(expr->context(), rax); } +void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { + VariableProxy* v = expr->expression()->AsVariableProxy(); + ASSERT(v->AsVariable() != NULL); + ASSERT(v->AsVariable()->is_global()); + + Visit(v); + + __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); + + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kValue: // Fall through + case Expression::kTest: // Fall through + case Expression::kTestValue: // Fall through + case Expression::kValueTest: + // Duplicate the result on the stack. + __ push(rax); + break; + case Expression::kEffect: + // Do not save result. + break; + } + // Call runtime for +1/-1. + __ push(rax); + __ Push(Smi::FromInt(1)); + if (expr->op() == Token::INC) { + __ CallRuntime(Runtime::kNumberAdd, 2); + } else { + __ CallRuntime(Runtime::kNumberSub, 2); + } + // Call Store IC. + __ Move(rcx, v->AsVariable()->name()); + __ push(CodeGenerator::GlobalObject()); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + // Restore up stack after store IC + __ addq(rsp, Immediate(kPointerSize)); + + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: // Fall through + case Expression::kValue: + // Do nothing. Result in either on the stack for value context + // or discarded for effect context. + break; + case Expression::kTest: + __ pop(rax); + TestAndBranch(rax, true_label_, false_label_); + break; + case Expression::kValueTest: { + Label discard; + __ movq(rax, Operand(rsp, 0)); + TestAndBranch(rax, true_label_, &discard); + __ bind(&discard); + __ addq(rsp, Immediate(kPointerSize)); + __ jmp(false_label_); + break; + } + case Expression::kTestValue: { + Label discard; + __ movq(rax, Operand(rsp, 0)); + TestAndBranch(rax, &discard, false_label_); + __ bind(&discard); + __ addq(rsp, Immediate(kPointerSize)); + __ jmp(true_label_); + break; + } + } +} + void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { Comment cmnt(masm_, "[ UnaryOperation"); diff --git a/test/mjsunit/compiler/globals.js b/test/mjsunit/compiler/globals.js index 066f9277b3..0abd5dd33c 100644 --- a/test/mjsunit/compiler/globals.js +++ b/test/mjsunit/compiler/globals.js @@ -53,3 +53,13 @@ assertEquals("2", eval('g')); // Test a second load. g = 3; assertEquals(3, eval('g')); + +// Test postfix count operation +var t; +t = g++; +assertEquals(3, t); +assertEquals(4, g); + +code = "g--; 1"; +assertEquals(1, eval(code)); +assertEquals(3, g);