frame_->EmitPush(r0); // r0 has result
} else {
- bool overwrite =
+ bool can_overwrite =
(node->expression()->AsBinaryOperation() != NULL &&
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+
+ bool no_negative_zero = node->expression()->no_negative_zero();
Load(node->expression());
switch (op) {
case Token::NOT:
case Token::SUB: {
frame_->PopToR0();
- GenericUnaryOpStub stub(Token::SUB, overwrite);
+ GenericUnaryOpStub stub(
+ Token::SUB,
+ overwrite,
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
frame_->CallStub(&stub, 0);
frame_->EmitPush(r0); // r0 has result
break;
// Go slow case if the value of the expression is zero
// to make sure that we switch between 0 and -0.
- __ cmp(r0, Operand(0));
- __ b(eq, &slow);
-
- // The value of the expression is a smi that is not zero. Try
- // optimistic subtraction '0 - value'.
- __ rsb(r1, r0, Operand(0), SetCC);
- __ b(vs, &slow);
-
- __ mov(r0, Operand(r1)); // Set r0 to result.
- __ b(&done);
+ if (negative_zero_ == kStrictNegativeZero) {
+ // If we have to check for zero, then we can check for the max negative
+ // smi while we are at it.
+ __ bic(ip, r0, Operand(0x80000000), SetCC);
+ __ b(eq, &slow);
+ __ rsb(r0, r0, Operand(0));
+ __ StubReturn(1);
+ } else {
+ // The value of the expression is a smi and 0 is OK for -0. Try
+ // optimistic subtraction '0 - value'.
+ __ rsb(r0, r0, Operand(0), SetCC);
+ __ StubReturn(1, vc);
+ // We don't have to reverse the optimistic neg since the only case
+ // where we fall through is the minimum negative Smi, which is the case
+ // where the neg leaves the register unchanged.
+ __ jmp(&slow); // Go slow on max negative Smi.
+ }
__ bind(&try_float);
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ cmp(r1, heap_number_map);
__ b(ne, &slow);
// r0 is a heap number. Get a new heap number in r1.
- if (overwrite_) {
+ if (overwrite_ == UNARY_OVERWRITE) {
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
__ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
__ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
__ b(&done);
__ bind(&try_float);
- if (!overwrite_) {
+ if (!overwrite_ == UNARY_OVERWRITE) {
// Allocate a fresh heap number, but don't overwrite r0 until
// we're sure we can do it without going through the slow case
// that needs the value in r0.
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register r0.
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register r0.
}
-void MacroAssembler::StubReturn(int argc) {
+void MacroAssembler::StubReturn(int argc, Condition cond) {
ASSERT(argc >= 1 && generating_stub());
if (argc > 1) {
- add(sp, sp, Operand((argc - 1) * kPointerSize));
+ add(sp, sp, Operand((argc - 1) * kPointerSize), LeaveCC, cond);
}
- Ret();
+ Ret(cond);
}
void TailCallStub(CodeStub* stub, Condition cond = al);
// Return from a code stub after popping its arguments.
- void StubReturn(int argc);
+ void StubReturn(int argc, Condition cond = al);
// Call a runtime routine.
void CallRuntime(Runtime::Function* f, int num_arguments);
const char* GenericUnaryOpStub::GetName() {
switch (op_) {
case Token::SUB:
- return overwrite_
- ? "GenericUnaryOpStub_SUB_Overwrite"
- : "GenericUnaryOpStub_SUB_Alloc";
+ if (negative_zero_ == kStrictNegativeZero) {
+ return overwrite_ == UNARY_OVERWRITE
+ ? "GenericUnaryOpStub_SUB_Overwrite_Strict0"
+ : "GenericUnaryOpStub_SUB_Alloc_Strict0";
+ } else {
+ return overwrite_ == UNARY_OVERWRITE
+ ? "GenericUnaryOpStub_SUB_Overwrite_Ignore0"
+ : "GenericUnaryOpStub_SUB_Alloc_Ignore0";
+ }
case Token::BIT_NOT:
- return overwrite_
+ return overwrite_ == UNARY_OVERWRITE
? "GenericUnaryOpStub_BIT_NOT_Overwrite"
: "GenericUnaryOpStub_BIT_NOT_Alloc";
default:
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
// Types of uncatchable exceptions.
enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
};
+enum NegativeZeroHandling {
+ kStrictNegativeZero,
+ kIgnoreNegativeZero
+};
+
+
class GenericUnaryOpStub : public CodeStub {
public:
- GenericUnaryOpStub(Token::Value op, bool overwrite)
- : op_(op), overwrite_(overwrite) { }
+ GenericUnaryOpStub(Token::Value op,
+ UnaryOverwriteMode overwrite,
+ NegativeZeroHandling negative_zero = kStrictNegativeZero)
+ : op_(op), overwrite_(overwrite), negative_zero_(negative_zero) { }
private:
Token::Value op_;
- bool overwrite_;
+ UnaryOverwriteMode overwrite_;
+ NegativeZeroHandling negative_zero_;
- class OverwriteField: public BitField<int, 0, 1> {};
- class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
+ class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {};
+ class NegativeZeroField: public BitField<NegativeZeroHandling, 1, 1> {};
+ class OpField: public BitField<Token::Value, 2, kMinorBits - 2> {};
Major MajorKey() { return GenericUnaryOp; }
int MinorKey() {
- return OpField::encode(op_) | OverwriteField::encode(overwrite_);
+ return OpField::encode(op_) |
+ OverwriteField::encode(overwrite_) |
+ NegativeZeroField::encode(negative_zero_);
}
void Generate(MacroAssembler* masm);
frame_->Push(&value);
} else {
Load(node->expression());
- bool overwrite =
+ bool can_overwrite =
(node->expression()->AsBinaryOperation() != NULL &&
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+ bool no_negative_zero = node->expression()->no_negative_zero();
switch (op) {
case Token::NOT:
case Token::DELETE:
break;
case Token::SUB: {
- GenericUnaryOpStub stub(Token::SUB, overwrite);
+ GenericUnaryOpStub stub(
+ Token::SUB,
+ overwrite,
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
Result operand = frame_->Pop();
Result answer = frame_->CallStub(&stub, &operand);
answer.set_type_info(TypeInfo::Number());
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &try_float, not_taken);
- // Go slow case if the value of the expression is zero
- // to make sure that we switch between 0 and -0.
- __ test(eax, Operand(eax));
- __ j(zero, &slow, not_taken);
+ if (negative_zero_ == kStrictNegativeZero) {
+ // Go slow case if the value of the expression is zero
+ // to make sure that we switch between 0 and -0.
+ __ test(eax, Operand(eax));
+ __ j(zero, &slow, not_taken);
+ }
// The value of the expression is a smi that is not zero. Try
// optimistic subtraction '0 - value'.
__ mov(edx, Operand(eax));
__ Set(eax, Immediate(0));
__ sub(eax, Operand(edx));
- __ j(overflow, &undo, not_taken);
-
- // If result is a smi we are done.
- __ test(eax, Immediate(kSmiTagMask));
- __ j(zero, &done, taken);
+ __ j(no_overflow, &done, taken);
// Restore eax and go slow case.
__ bind(&undo);
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ cmp(edx, Factory::heap_number_map());
__ j(not_equal, &slow);
- if (overwrite_) {
+ if (overwrite_ == UNARY_OVERWRITE) {
__ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
__ xor_(edx, HeapNumber::kSignMask); // Flip sign.
__ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx);
// Try to store the result in a heap number.
__ bind(&try_float);
- if (!overwrite_) {
+ if (overwrite_ == UNARY_NO_OVERWRITE) {
// Allocate a fresh heap number, but don't overwrite eax until
// we're sure we can do it without going through the slow case
// that needs the value in eax.
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register eax.
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register eax.
}
} else {
- bool overwrite =
+ bool can_overwrite =
(node->expression()->AsBinaryOperation() != NULL &&
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+ bool no_negative_zero = node->expression()->no_negative_zero();
Load(node->expression());
switch (op) {
case Token::NOT:
break;
case Token::SUB: {
- GenericUnaryOpStub stub(Token::SUB, overwrite);
+ GenericUnaryOpStub stub(
+ Token::SUB,
+ overwrite,
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
Result operand = frame_->Pop();
Result answer = frame_->CallStub(&stub, &operand);
answer.set_type_info(TypeInfo::Number());
Label try_float;
__ JumpIfNotSmi(rax, &try_float);
+ if (negative_zero_ == kIgnoreNegativeZero) {
+ __ SmiCompare(rax, Smi::FromInt(0));
+ __ j(equal, &done);
+ }
+
// Enter runtime system if the value of the smi is zero
// to make sure that we switch between 0 and -0.
// Also enter it if the value of the smi is Smi::kMinValue.
// Either zero or Smi::kMinValue, neither of which become a smi when
// negated.
- __ SmiCompare(rax, Smi::FromInt(0));
- __ j(not_equal, &slow);
- __ Move(rax, Factory::minus_zero_value());
- __ jmp(&done);
+ if (negative_zero_ == kStrictNegativeZero) {
+ __ SmiCompare(rax, Smi::FromInt(0));
+ __ j(not_equal, &slow);
+ __ Move(rax, Factory::minus_zero_value());
+ __ jmp(&done);
+ } else {
+ __ jmp(&slow);
+ }
// Try floating point case.
__ bind(&try_float);
__ shl(kScratchRegister, Immediate(63));
__ xor_(rdx, kScratchRegister); // Flip sign.
// rdx is value to store.
- if (overwrite_) {
+ if (overwrite_ == UNARY_OVERWRITE) {
__ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
} else {
__ AllocateHeapNumber(rcx, rbx, &slow);
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register rax.
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register rax.