Make the CompareStub and the UnaryOpStub accept smi inputs.

The stubs get an additional flag for including the smi code
inside the stub. This allows us to generate more compact code
if we don't want to inline the smi case outside the stub.

Review URL: http://codereview.chromium.org/3388005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5456 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2010-09-15 10:14:25 +00:00
parent dae5fc6f81
commit bd6a8c1e4e
14 changed files with 393 additions and 152 deletions

View File

@ -930,6 +930,24 @@ void CompareStub::Generate(MacroAssembler* masm) {
Label slow; // Call builtin.
Label not_smis, both_loaded_as_doubles, lhs_not_nan;
if (include_smi_compare_) {
Label not_two_smis, smi_done;
__ orr(r2, r1, r0);
__ tst(r2, Operand(kSmiTagMask));
__ b(ne, &not_two_smis);
__ sub(r0, r1, r0);
__ b(vc, &smi_done);
// Correct the sign in case of overflow.
__ rsb(r0, r0, Operand(0, RelocInfo::NONE));
__ bind(&smi_done);
__ Ret();
__ bind(&not_two_smis);
} else if (FLAG_debug_code) {
__ orr(r2, r1, r0);
__ tst(r2, Operand(kSmiTagMask));
__ Assert(nz, "CompareStub: unexpected smi operands.");
}
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
@ -2288,7 +2306,7 @@ void StackCheckStub::Generate(MacroAssembler* masm) {
__ push(r0);
__ TailCallRuntime(Runtime::kStackGuard, 1, 1);
__ StubReturn(1);
__ Ret();
}
@ -2299,32 +2317,37 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
if (op_ == Token::SUB) {
// Check whether the value is a smi.
Label try_float;
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, &try_float);
if (include_smi_code_) {
// Check whether the value is a smi.
Label try_float;
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, &try_float);
// Go slow case if the value of the expression is zero
// to make sure that we switch between 0 and -0.
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, RelocInfo::NONE));
__ 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, RelocInfo::NONE), 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.
// Go slow case if the value of the expression is zero
// to make sure that we switch between 0 and -0.
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, RelocInfo::NONE));
__ Ret();
} 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, RelocInfo::NONE), SetCC);
__ Ret(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);
} else if (FLAG_debug_code) {
__ tst(r0, Operand(kSmiTagMask));
__ Assert(ne, "Unexpected smi operand.");
}
__ bind(&try_float);
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
__ cmp(r1, heap_number_map);
@ -2344,6 +2367,19 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ mov(r0, Operand(r1));
}
} else if (op_ == Token::BIT_NOT) {
if (include_smi_code_) {
Label non_smi;
__ BranchOnNotSmi(r0, &non_smi);
__ mvn(r0, Operand(r0));
// Bit-clear inverted smi-tag.
__ bic(r0, r0, Operand(kSmiTagMask));
__ Ret();
__ bind(&non_smi);
} else if (FLAG_debug_code) {
__ tst(r0, Operand(kSmiTagMask));
__ Assert(ne, "Unexpected smi operand.");
}
// Check if the operand is a heap number.
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
@ -2391,7 +2427,7 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
}
__ bind(&done);
__ StubReturn(1);
__ Ret();
// Handle the slow case by jumping to the JavaScript builtin.
__ bind(&slow);
@ -3499,6 +3535,11 @@ const char* CompareStub::GetName() {
include_number_compare_name = "_NO_NUMBER";
}
const char* include_smi_compare_name = "";
if (!include_smi_compare_) {
include_smi_compare_name = "_NO_SMI";
}
OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
"CompareStub_%s%s%s%s%s%s",
cc_name,
@ -3506,7 +3547,8 @@ const char* CompareStub::GetName() {
rhs_name,
strict_name,
never_nan_nan_name,
include_number_compare_name);
include_number_compare_name,
include_smi_compare_name);
return name_;
}
@ -3522,7 +3564,8 @@ int CompareStub::MinorKey() {
| RegisterField::encode(lhs_.is(r0))
| StrictField::encode(strict_)
| NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false)
| IncludeNumberCompareField::encode(include_number_compare_);
| IncludeNumberCompareField::encode(include_number_compare_)
| IncludeSmiCompareField::encode(include_smi_compare_);
}

View File

@ -1651,7 +1651,7 @@ void CodeGenerator::Comparison(Condition cc,
// Perform non-smi comparison by stub.
// CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0.
// We call with 0 args because there are 0 on the stack.
CompareStub stub(cc, strict, kBothCouldBeNaN, true, lhs, rhs);
CompareStub stub(cc, strict, NO_SMI_COMPARE_IN_STUB, lhs, rhs);
frame_->CallStub(&stub, 0);
__ cmp(r0, Operand(0, RelocInfo::NONE));
exit.Jump();
@ -5985,6 +5985,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
GenericUnaryOpStub stub(
Token::SUB,
overwrite,
NO_UNARY_FLAGS,
no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
frame_->CallStub(&stub, 0);
frame_->EmitPush(r0); // r0 has result
@ -6009,7 +6010,9 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
not_smi_label.Bind();
frame_->SpillAll();
__ Move(r0, tos);
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
GenericUnaryOpStub stub(Token::BIT_NOT,
overwrite,
NO_UNARY_SMI_CODE_IN_STUB);
frame_->CallStub(&stub, 0);
frame_->EmitPush(r0);

View File

@ -672,7 +672,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Perform the comparison as if via '==='.
__ ldr(r1, MemOperand(sp, 0)); // Switch value.
if (ShouldInlineSmiCase(Token::EQ_STRICT)) {
bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
if (inline_smi_code) {
Label slow_case;
__ orr(r2, r1, r0);
__ tst(r2, Operand(kSmiTagMask));
@ -684,7 +685,10 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&slow_case);
}
CompareStub stub(eq, true, kBothCouldBeNaN, true, r1, r0);
CompareFlags flags = inline_smi_code
? NO_SMI_COMPARE_IN_STUB
: NO_COMPARE_FLAGS;
CompareStub stub(eq, true, flags, r1, r0);
__ CallStub(&stub);
__ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(ne, &next_test);
@ -2888,7 +2892,9 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode overwrite =
can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
GenericUnaryOpStub stub(Token::SUB,
overwrite,
NO_UNARY_FLAGS);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register r0.
VisitForValue(expr->expression(), kAccumulator);
@ -2903,7 +2909,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// in the accumulator register r0.
VisitForValue(expr->expression(), kAccumulator);
Label done;
if (ShouldInlineSmiCase(expr->op())) {
bool inline_smi_code = ShouldInlineSmiCase(expr->op());
if (inline_smi_code) {
Label call_stub;
__ BranchOnNotSmi(r0, &call_stub);
__ mvn(r0, Operand(r0));
@ -2913,9 +2920,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
__ bind(&call_stub);
}
bool overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOpFlags flags = inline_smi_code
? NO_UNARY_SMI_CODE_IN_STUB
: NO_UNARY_FLAGS;
UnaryOverwriteMode mode =
overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, mode);
GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
__ CallStub(&stub);
__ bind(&done);
Apply(context_, r0);
@ -3292,7 +3302,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}
if (ShouldInlineSmiCase(op)) {
bool inline_smi_code = ShouldInlineSmiCase(op);
if (inline_smi_code) {
Label slow_case;
__ orr(r2, r0, Operand(r1));
__ BranchOnNotSmi(r2, &slow_case);
@ -3300,8 +3311,10 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Split(cc, if_true, if_false, NULL);
__ bind(&slow_case);
}
CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0);
CompareFlags flags = inline_smi_code
? NO_SMI_COMPARE_IN_STUB
: NO_COMPARE_FLAGS;
CompareStub stub(cc, strict, flags, r1, r0);
__ CallStub(&stub);
__ cmp(r0, Operand(0, RelocInfo::NONE));
Split(cc, if_true, if_false, fall_through);

View File

@ -1242,15 +1242,6 @@ void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
}
void MacroAssembler::StubReturn(int argc, Condition cond) {
ASSERT(argc >= 1 && generating_stub());
if (argc > 1) {
add(sp, sp, Operand((argc - 1) * kPointerSize), LeaveCC, cond);
}
Ret(cond);
}
void MacroAssembler::IllegalOperation(int num_arguments) {
if (num_arguments > 0) {
add(sp, sp, Operand(num_arguments * kPointerSize));

View File

@ -531,9 +531,6 @@ class MacroAssembler: public Assembler {
// Call a code stub.
void TailCallStub(CodeStub* stub, Condition cond = al);
// Return from a code stub after popping its arguments.
void StubReturn(int argc, Condition cond = al);
// Call a runtime routine.
void CallRuntime(Runtime::Function* f, int num_arguments);

View File

@ -340,27 +340,40 @@ enum NegativeZeroHandling {
};
enum UnaryOpFlags {
NO_UNARY_FLAGS = 0,
NO_UNARY_SMI_CODE_IN_STUB = 1 << 0
};
class GenericUnaryOpStub : public CodeStub {
public:
GenericUnaryOpStub(Token::Value op,
UnaryOverwriteMode overwrite,
UnaryOpFlags flags,
NegativeZeroHandling negative_zero = kStrictNegativeZero)
: op_(op), overwrite_(overwrite), negative_zero_(negative_zero) { }
: op_(op),
overwrite_(overwrite),
include_smi_code_((flags & NO_UNARY_SMI_CODE_IN_STUB) == 0),
negative_zero_(negative_zero) { }
private:
Token::Value op_;
UnaryOverwriteMode overwrite_;
bool include_smi_code_;
NegativeZeroHandling negative_zero_;
class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {};
class NegativeZeroField: public BitField<NegativeZeroHandling, 1, 1> {};
class OpField: public BitField<Token::Value, 2, kMinorBits - 2> {};
class IncludeSmiCodeField: public BitField<bool, 1, 1> {};
class NegativeZeroField: public BitField<NegativeZeroHandling, 2, 1> {};
class OpField: public BitField<Token::Value, 3, kMinorBits - 3> {};
Major MajorKey() { return GenericUnaryOp; }
int MinorKey() {
return OpField::encode(op_) |
OverwriteField::encode(overwrite_) |
NegativeZeroField::encode(negative_zero_);
OverwriteField::encode(overwrite_) |
IncludeSmiCodeField::encode(include_smi_code_) |
NegativeZeroField::encode(negative_zero_);
}
void Generate(MacroAssembler* masm);
@ -375,22 +388,43 @@ enum NaNInformation {
};
// Flags that control the compare stub code generation.
enum CompareFlags {
NO_COMPARE_FLAGS = 0,
NO_SMI_COMPARE_IN_STUB = 1 << 0,
NO_NUMBER_COMPARE_IN_STUB = 1 << 1,
CANT_BOTH_BE_NAN = 1 << 2
};
class CompareStub: public CodeStub {
public:
CompareStub(Condition cc,
bool strict,
NaNInformation nan_info = kBothCouldBeNaN,
bool include_number_compare = true,
Register lhs = no_reg,
Register rhs = no_reg) :
CompareFlags flags,
Register lhs,
Register rhs) :
cc_(cc),
strict_(strict),
never_nan_nan_(nan_info == kCantBothBeNaN),
include_number_compare_(include_number_compare),
never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
lhs_(lhs),
rhs_(rhs),
name_(NULL) { }
CompareStub(Condition cc,
bool strict,
CompareFlags flags) :
cc_(cc),
strict_(strict),
never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
lhs_(no_reg),
rhs_(no_reg),
name_(NULL) { }
void Generate(MacroAssembler* masm);
private:
@ -406,6 +440,10 @@ class CompareStub: public CodeStub {
// comparison code is used when the number comparison has been inlined, and
// the stub will be called if one of the operands is not a number.
bool include_number_compare_;
// Generate the comparison code for two smi operands in the stub.
bool include_smi_compare_;
// Register holding the left hand side of the comparison if the stub gives
// a choice, no_reg otherwise.
Register lhs_;
@ -413,12 +451,13 @@ class CompareStub: public CodeStub {
// a choice, no_reg otherwise.
Register rhs_;
// Encoding of the minor key CCCCCCCCCCCCRCNS.
// Encoding of the minor key in 16 bits.
class StrictField: public BitField<bool, 0, 1> {};
class NeverNanNanField: public BitField<bool, 1, 1> {};
class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
class RegisterField: public BitField<bool, 3, 1> {};
class ConditionField: public BitField<int, 4, 12> {};
class IncludeSmiCompareField: public BitField<bool, 3, 1> {};
class RegisterField: public BitField<bool, 4, 1> {};
class ConditionField: public BitField<int, 5, 11> {};
Major MajorKey() { return Compare; }
@ -436,11 +475,13 @@ class CompareStub: public CodeStub {
const char* GetName();
#ifdef DEBUG
void Print() {
PrintF("CompareStub (cc %d), (strict %s), "
"(never_nan_nan %s), (number_compare %s) ",
PrintF("CompareStub (minor %d) (cc %d), (strict %s), "
"(never_nan_nan %s), (smi_compare %s) (number_compare %s) ",
MinorKey(),
static_cast<int>(cc_),
strict_ ? "true" : "false",
never_nan_nan_ ? "true" : "false",
include_smi_compare_ ? "inluded" : "not included",
include_number_compare_ ? "included" : "not included");
if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) {

View File

@ -174,6 +174,10 @@ DEFINE_bool(enable_liveedit, true, "enable liveedit experimental feature")
DEFINE_int(max_stack_trace_source_length, 300,
"maximum length of function source code printed in a stack trace.")
// full-codegen.cc
DEFINE_bool(always_inline_smi_code, false,
"always inline smi code in non-opt code")
// heap.cc
DEFINE_int(max_new_space_size, 0, "max size of the new generation")
DEFINE_int(max_old_space_size, 0, "max size of the old generation")

View File

@ -324,15 +324,11 @@ int FullCodeGenerator::SlotOffset(Slot* slot) {
bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
// TODO(kasperl): Once the compare stub allows leaving out the
// inlined smi case, we should get rid of this check.
if (Token::IsCompareOp(op)) return true;
// TODO(kasperl): Once the unary bit not stub allows leaving out
// the inlined smi case, we should get rid of this check.
if (op == Token::BIT_NOT) return true;
// Inline smi case inside loops, but not division and modulo which
// are too complicated and take up too much space.
return (op != Token::DIV) && (op != Token::MOD) && (loop_depth_ > 0);
if (op == Token::DIV ||op == Token::MOD) return false;
if (FLAG_always_inline_smi_code) return true;
return loop_depth_ > 0;
}

View File

@ -1879,36 +1879,36 @@ void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
Label slow, done;
Label slow, done, undo;
if (op_ == Token::SUB) {
// Check whether the value is a smi.
Label try_float;
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &try_float, not_taken);
if (include_smi_code_) {
// Check whether the value is a smi.
Label try_float;
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &try_float, 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);
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);
__ StubReturn(1);
// Try floating point case.
__ bind(&try_float);
} else if (FLAG_debug_code) {
__ AbortIfSmi(eax);
}
// The value of the expression is a smi that is not zero. Try
// optimistic subtraction '0 - value'.
Label undo;
__ mov(edx, Operand(eax));
__ Set(eax, Immediate(0));
__ sub(eax, Operand(edx));
__ j(no_overflow, &done, taken);
// Restore eax and go slow case.
__ bind(&undo);
__ mov(eax, Operand(edx));
__ jmp(&slow);
// Try floating point case.
__ bind(&try_float);
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ cmp(edx, Factory::heap_number_map());
__ j(not_equal, &slow);
@ -1928,6 +1928,18 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
}
} else if (op_ == Token::BIT_NOT) {
if (include_smi_code_) {
Label non_smi;
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &non_smi);
__ not_(eax);
__ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag.
__ ret(0);
__ bind(&non_smi);
} else if (FLAG_debug_code) {
__ AbortIfSmi(eax);
}
// Check if the operand is a heap number.
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ cmp(edx, Factory::heap_number_map());
@ -1978,6 +1990,10 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ bind(&done);
__ StubReturn(1);
// Restore eax and go slow case.
__ bind(&undo);
__ mov(eax, Operand(edx));
// Handle the slow case by jumping to the JavaScript builtin.
__ bind(&slow);
__ pop(ecx); // pop return address.
@ -2613,6 +2629,27 @@ void CompareStub::Generate(MacroAssembler* masm) {
Label check_unequal_objects, done;
// Compare two smis if required.
if (include_smi_compare_) {
Label non_smi, smi_done;
__ mov(ecx, Operand(edx));
__ or_(ecx, Operand(eax));
__ test(ecx, Immediate(kSmiTagMask));
__ j(not_zero, &non_smi, not_taken);
__ sub(edx, Operand(eax)); // Return on the result of the subtraction.
__ j(no_overflow, &smi_done);
__ neg(edx); // Correct sign in case of overflow.
__ bind(&smi_done);
__ mov(eax, edx);
__ ret(0);
__ bind(&non_smi);
} else if (FLAG_debug_code) {
__ mov(ecx, Operand(edx));
__ or_(ecx, Operand(eax));
__ test(ecx, Immediate(kSmiTagMask));
__ Assert(not_zero, "Unexpected smi operands.");
}
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
@ -3501,7 +3538,8 @@ int CompareStub::MinorKey() {
| RegisterField::encode(false) // lhs_ and rhs_ are not used
| StrictField::encode(strict_)
| NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
| IncludeNumberCompareField::encode(include_number_compare_);
| IncludeNumberCompareField::encode(include_number_compare_)
| IncludeSmiCompareField::encode(include_smi_compare_);
}
@ -3541,12 +3579,18 @@ const char* CompareStub::GetName() {
include_number_compare_name = "_NO_NUMBER";
}
const char* include_smi_compare_name = "";
if (!include_smi_compare_) {
include_smi_compare_name = "_NO_SMI";
}
OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
"CompareStub_%s%s%s%s",
"CompareStub_%s%s%s%s%s",
cc_name,
strict_name,
never_nan_nan_name,
include_number_compare_name);
include_number_compare_name,
include_smi_compare_name);
return name_;
}

View File

@ -2646,6 +2646,19 @@ static Condition DoubleCondition(Condition cc) {
}
static CompareFlags ComputeCompareFlags(NaNInformation nan_info,
bool inline_number_compare) {
CompareFlags flags = NO_SMI_COMPARE_IN_STUB;
if (nan_info == kCantBothBeNaN) {
flags = static_cast<CompareFlags>(flags | CANT_BOTH_BE_NAN);
}
if (inline_number_compare) {
flags = static_cast<CompareFlags>(flags | NO_NUMBER_COMPARE_IN_STUB);
}
return flags;
}
void CodeGenerator::Comparison(AstNode* node,
Condition cc,
bool strict,
@ -2773,7 +2786,9 @@ void CodeGenerator::Comparison(AstNode* node,
// Setup and call the compare stub.
is_not_string.Bind(&left_side);
CompareStub stub(cc, strict, kCantBothBeNaN);
CompareFlags flags =
static_cast<CompareFlags>(CANT_BOTH_BE_NAN | NO_SMI_COMPARE_IN_STUB);
CompareStub stub(cc, strict, flags);
Result result = frame_->CallStub(&stub, &left_side, &right_side);
result.ToRegister();
__ cmp(result.reg(), 0);
@ -2867,7 +2882,8 @@ void CodeGenerator::Comparison(AstNode* node,
// End of in-line compare, call out to the compare stub. Don't include
// number comparison in the stub if it was inlined.
CompareStub stub(cc, strict, nan_info, !inline_number_compare);
CompareFlags flags = ComputeCompareFlags(nan_info, inline_number_compare);
CompareStub stub(cc, strict, flags);
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
__ test(answer.reg(), Operand(answer.reg()));
answer.Unuse();
@ -2900,7 +2916,9 @@ void CodeGenerator::Comparison(AstNode* node,
// End of in-line compare, call out to the compare stub. Don't include
// number comparison in the stub if it was inlined.
CompareStub stub(cc, strict, nan_info, !inline_number_compare);
CompareFlags flags =
ComputeCompareFlags(nan_info, inline_number_compare);
CompareStub stub(cc, strict, flags);
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
__ test(answer.reg(), Operand(answer.reg()));
answer.Unuse();
@ -2994,7 +3012,6 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
dest->false_target()->Branch(zero);
} else {
// Do the smi check, then the comparison.
JumpTarget is_not_smi;
__ test(left_reg, Immediate(kSmiTagMask));
is_smi.Branch(zero, left_side, right_side);
}
@ -3031,7 +3048,9 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
}
// Setup and call the compare stub.
CompareStub stub(cc, strict, kCantBothBeNaN);
CompareFlags flags =
static_cast<CompareFlags>(CANT_BOTH_BE_NAN | NO_SMI_CODE_IN_STUB);
CompareStub stub(cc, strict, flags);
Result result = frame_->CallStub(&stub, left_side, right_side);
result.ToRegister();
__ test(result.reg(), Operand(result.reg()));
@ -8146,6 +8165,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
GenericUnaryOpStub stub(
Token::SUB,
overwrite,
NO_UNARY_FLAGS,
no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
Result operand = frame_->Pop();
Result answer = frame_->CallStub(&stub, &operand);
@ -8173,7 +8193,9 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
__ test(operand.reg(), Immediate(kSmiTagMask));
smi_label.Branch(zero, &operand, taken);
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
GenericUnaryOpStub stub(Token::BIT_NOT,
overwrite,
NO_UNARY_SMI_CODE_IN_STUB);
Result answer = frame_->CallStub(&stub, &operand);
continue_label.Jump(&answer);

View File

@ -684,7 +684,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Perform the comparison as if via '==='.
__ mov(edx, Operand(esp, 0)); // Switch value.
if (ShouldInlineSmiCase(Token::EQ_STRICT)) {
bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
if (inline_smi_code) {
Label slow_case;
__ mov(ecx, edx);
__ or_(ecx, Operand(eax));
@ -697,7 +698,10 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&slow_case);
}
CompareStub stub(equal, true);
CompareFlags flags = inline_smi_code
? NO_SMI_COMPARE_IN_STUB
: NO_COMPARE_FLAGS;
CompareStub stub(equal, true, flags);
__ CallStub(&stub);
__ test(eax, Operand(eax));
__ j(not_equal, &next_test);
@ -3258,7 +3262,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode overwrite =
can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register eax.
VisitForValue(expr->expression(), kAccumulator);
@ -3273,7 +3277,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// in the accumulator register eax.
VisitForValue(expr->expression(), kAccumulator);
Label done;
if (ShouldInlineSmiCase(expr->op())) {
bool inline_smi_case = ShouldInlineSmiCase(expr->op());
if (inline_smi_case) {
Label call_stub;
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &call_stub);
@ -3285,7 +3290,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
bool overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode mode =
overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, mode);
UnaryOpFlags flags = inline_smi_case
? NO_UNARY_SMI_CODE_IN_STUB
: NO_UNARY_FLAGS;
GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
__ CallStub(&stub);
__ bind(&done);
Apply(context_, eax);
@ -3674,7 +3682,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}
if (ShouldInlineSmiCase(op)) {
bool inline_smi_code = ShouldInlineSmiCase(op);
if (inline_smi_code) {
Label slow_case;
__ mov(ecx, Operand(edx));
__ or_(ecx, Operand(eax));
@ -3685,7 +3694,10 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ bind(&slow_case);
}
CompareStub stub(cc, strict);
CompareFlags flags = inline_smi_code
? NO_SMI_COMPARE_IN_STUB
: NO_COMPARE_FLAGS;
CompareStub stub(cc, strict, flags);
__ CallStub(&stub);
__ test(eax, Operand(eax));
Split(cc, if_true, if_false, fall_through);

View File

@ -1404,33 +1404,35 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
Label slow, done;
if (op_ == Token::SUB) {
// Check whether the value is a smi.
Label try_float;
__ JumpIfNotSmi(rax, &try_float);
if (include_smi_code_) {
// Check whether the value is a smi.
Label try_float;
__ JumpIfNotSmi(rax, &try_float);
if (negative_zero_ == kIgnoreNegativeZero) {
__ SmiCompare(rax, Smi::FromInt(0));
__ j(equal, &done);
}
__ SmiNeg(rax, rax, &done);
if (negative_zero_ == kIgnoreNegativeZero) {
__ SmiCompare(rax, Smi::FromInt(0));
__ j(equal, &done);
// Either zero or Smi::kMinValue, neither of which become a smi when
// negated. We handle negative zero here if required. We always enter
// the runtime system if we have Smi::kMinValue.
if (negative_zero_ == kStrictNegativeZero) {
__ SmiCompare(rax, Smi::FromInt(0));
__ j(not_equal, &slow);
__ Move(rax, Factory::minus_zero_value());
__ jmp(&done);
} else {
__ SmiCompare(rax, Smi::FromInt(Smi::kMinValue));
__ j(equal, &slow);
__ jmp(&done);
}
// Try floating point case.
__ bind(&try_float);
} else if (FLAG_debug_code) {
__ AbortIfSmi(rax);
}
// 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.
__ SmiNeg(rax, rax, &done);
// Either zero or Smi::kMinValue, neither of which become a smi when
// negated.
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);
__ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
__ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &slow);
@ -1449,6 +1451,17 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ movq(rax, rcx);
}
} else if (op_ == Token::BIT_NOT) {
if (include_smi_code_) {
Label try_float;
__ JumpIfNotSmi(rax, &try_float);
__ SmiNot(rax, rax);
__ jmp(&done);
// Try floating point case.
__ bind(&try_float);
} else if (FLAG_debug_code) {
__ AbortIfSmi(rax);
}
// Check if the operand is a heap number.
__ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
__ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
@ -2115,6 +2128,26 @@ void CompareStub::Generate(MacroAssembler* masm) {
ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
Label check_unequal_objects, done;
// Compare two smis if required.
if (include_smi_compare_) {
Label non_smi, smi_done;
__ JumpIfNotBothSmi(rax, rdx, &non_smi);
__ subq(rdx, rax);
__ j(no_overflow, &smi_done);
__ neg(rdx); // Correct sign in case of overflow.
__ bind(&smi_done);
__ movq(rax, rdx);
__ ret(0);
__ bind(&non_smi);
} else if (FLAG_debug_code) {
Label ok;
__ JumpIfNotSmi(rdx, &ok);
__ JumpIfNotSmi(rax, &ok);
__ Abort("CompareStub: smi operands");
__ bind(&ok);
}
// The compare stub returns a positive, negative, or zero 64-bit integer
// value in rax, corresponding to result of comparing the two inputs.
// NOTICE! This code is only reached after a smi-fast-case check, so
@ -3001,7 +3034,8 @@ int CompareStub::MinorKey() {
| RegisterField::encode(false) // lhs_ and rhs_ are not used
| StrictField::encode(strict_)
| NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
| IncludeNumberCompareField::encode(include_number_compare_);
| IncludeNumberCompareField::encode(include_number_compare_)
| IncludeSmiCompareField::encode(include_smi_compare_);
}
@ -3041,12 +3075,18 @@ const char* CompareStub::GetName() {
include_number_compare_name = "_NO_NUMBER";
}
const char* include_smi_compare_name = "";
if (!include_smi_compare_) {
include_smi_compare_name = "_NO_SMI";
}
OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
"CompareStub_%s%s%s%s",
cc_name,
strict_name,
never_nan_nan_name,
include_number_compare_name);
include_number_compare_name,
include_smi_compare_name);
return name_;
}

View File

@ -1940,6 +1940,19 @@ static Condition DoubleCondition(Condition cc) {
}
static CompareFlags ComputeCompareFlags(NaNInformation nan_info,
bool inline_number_compare) {
CompareFlags flags = NO_SMI_COMPARE_IN_STUB;
if (nan_info == kCantBothBeNaN) {
flags = static_cast<CompareFlags>(flags | CANT_BOTH_BE_NAN);
}
if (inline_number_compare) {
flags = static_cast<CompareFlags>(flags | NO_NUMBER_COMPARE_IN_STUB);
}
return flags;
}
void CodeGenerator::Comparison(AstNode* node,
Condition cc,
bool strict,
@ -2070,7 +2083,9 @@ void CodeGenerator::Comparison(AstNode* node,
// Setup and call the compare stub.
is_not_string.Bind(&left_side);
CompareStub stub(cc, strict, kCantBothBeNaN);
CompareFlags flags =
static_cast<CompareFlags>(CANT_BOTH_BE_NAN | NO_SMI_CODE_IN_STUB);
CompareStub stub(cc, strict, flags);
Result result = frame_->CallStub(&stub, &left_side, &right_side);
result.ToRegister();
__ testq(result.reg(), result.reg());
@ -2174,7 +2189,8 @@ void CodeGenerator::Comparison(AstNode* node,
// End of in-line compare, call out to the compare stub. Don't include
// number comparison in the stub if it was inlined.
CompareStub stub(cc, strict, nan_info, !inline_number_compare);
CompareFlags flags = ComputeCompareFlags(nan_info, inline_number_compare);
CompareStub stub(cc, strict, flags);
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
__ testq(answer.reg(), answer.reg()); // Sets both zero and sign flag.
answer.Unuse();
@ -2207,7 +2223,9 @@ void CodeGenerator::Comparison(AstNode* node,
// End of in-line compare, call out to the compare stub. Don't include
// number comparison in the stub if it was inlined.
CompareStub stub(cc, strict, nan_info, !inline_number_compare);
CompareFlags flags =
ComputeCompareFlags(nan_info, inline_number_compare);
CompareStub stub(cc, strict, flags);
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
__ testq(answer.reg(), answer.reg()); // Sets both zero and sign flags.
answer.Unuse();
@ -2332,7 +2350,9 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
}
// Setup and call the compare stub.
CompareStub stub(cc, strict, kCantBothBeNaN);
CompareFlags flags =
static_cast<CompareFlags>(CANT_BOTH_BE_NAN | NO_SMI_CODE_IN_STUB);
CompareStub stub(cc, strict, flags);
Result result = frame_->CallStub(&stub, left_side, right_side);
result.ToRegister();
__ testq(result.reg(), result.reg());
@ -7395,6 +7415,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
GenericUnaryOpStub stub(
Token::SUB,
overwrite,
NO_UNARY_FLAGS,
no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
Result operand = frame_->Pop();
Result answer = frame_->CallStub(&stub, &operand);
@ -7413,7 +7434,9 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
Condition is_smi = masm_->CheckSmi(operand.reg());
smi_label.Branch(is_smi, &operand);
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
GenericUnaryOpStub stub(Token::BIT_NOT,
overwrite,
NO_UNARY_SMI_CODE_IN_STUB);
Result answer = frame_->CallStub(&stub, &operand);
continue_label.Jump(&answer);

View File

@ -677,9 +677,10 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
VisitForValue(clause->label(), kAccumulator);
// Perform the comparison as if via '==='.
if (ShouldInlineSmiCase(Token::EQ_STRICT)) {
__ movq(rdx, Operand(rsp, 0)); // Switch value.
bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
if (inline_smi_code) {
Label slow_case;
__ movq(rdx, Operand(rsp, 0)); // Switch value.
__ JumpIfNotBothSmi(rdx, rax, &slow_case);
__ SmiCompare(rdx, rax);
__ j(not_equal, &next_test);
@ -688,7 +689,10 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&slow_case);
}
CompareStub stub(equal, true);
CompareFlags flags = inline_smi_code
? NO_SMI_COMPARE_IN_STUB
: NO_COMPARE_FLAGS;
CompareStub stub(equal, true, flags);
__ CallStub(&stub);
__ testq(rax, rax);
__ j(not_equal, &next_test);
@ -2955,7 +2959,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode overwrite =
can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register rax.
VisitForValue(expr->expression(), kAccumulator);
@ -2970,7 +2974,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// in the accumulator register rax.
VisitForValue(expr->expression(), kAccumulator);
Label done;
if (ShouldInlineSmiCase(expr->op())) {
bool inline_smi_case = ShouldInlineSmiCase(expr->op());
if (inline_smi_case) {
Label call_stub;
__ JumpIfNotSmi(rax, &call_stub);
__ SmiNot(rax, rax);
@ -2980,7 +2985,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
bool overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode mode =
overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, mode);
UnaryOpFlags flags = inline_smi_case
? NO_UNARY_SMI_CODE_IN_STUB
: NO_UNARY_FLAGS;
GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
__ CallStub(&stub);
__ bind(&done);
Apply(context_, rax);
@ -3363,7 +3371,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}
if (ShouldInlineSmiCase(op)) {
bool inline_smi_code = ShouldInlineSmiCase(op);
if (inline_smi_code) {
Label slow_case;
__ JumpIfNotBothSmi(rax, rdx, &slow_case);
__ SmiCompare(rdx, rax);
@ -3371,7 +3380,10 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ bind(&slow_case);
}
CompareStub stub(cc, strict);
CompareFlags flags = inline_smi_code
? NO_SMI_COMPARE_IN_STUB
: NO_COMPARE_FLAGS;
CompareStub stub(cc, strict, flags);
__ CallStub(&stub);
__ testq(rax, rax);
Split(cc, if_true, if_false, fall_through);