|
|
|
@ -911,6 +911,7 @@ class FloatingPointHelper : public AllStatic {
|
|
|
|
|
// operand in register number. Returns operand as floating point number
|
|
|
|
|
// on FPU stack.
|
|
|
|
|
static void LoadFloatOperand(MacroAssembler* masm, Register number);
|
|
|
|
|
|
|
|
|
|
// Code pattern for loading floating point values. Input values must
|
|
|
|
|
// be either smi or heap number objects (fp values). Requirements:
|
|
|
|
|
// operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax.
|
|
|
|
@ -929,6 +930,7 @@ class FloatingPointHelper : public AllStatic {
|
|
|
|
|
static void CheckFloatOperands(MacroAssembler* masm,
|
|
|
|
|
Label* non_float,
|
|
|
|
|
Register scratch);
|
|
|
|
|
|
|
|
|
|
// Takes the operands in edx and eax and loads them as integers in eax
|
|
|
|
|
// and ecx.
|
|
|
|
|
static void LoadAsIntegers(MacroAssembler* masm,
|
|
|
|
@ -947,6 +949,7 @@ class FloatingPointHelper : public AllStatic {
|
|
|
|
|
// into xmm0 and xmm1 if they are. Operands are in edx and eax.
|
|
|
|
|
// Leaves operands unchanged.
|
|
|
|
|
static void LoadSSE2Operands(MacroAssembler* masm);
|
|
|
|
|
|
|
|
|
|
// Test if operands are numbers (smi or HeapNumber objects), and load
|
|
|
|
|
// them into xmm0 and xmm1 if they are. Jump to label not_numbers if
|
|
|
|
|
// either operand is not a number. Operands are in edx and eax.
|
|
|
|
@ -2361,6 +2364,22 @@ static bool CouldBeNaN(const Result& result) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Convert from signed to unsigned comparison to match the way EFLAGS are set
|
|
|
|
|
// by FPU and XMM compare instructions.
|
|
|
|
|
static Condition DoubleCondition(Condition cc) {
|
|
|
|
|
switch (cc) {
|
|
|
|
|
case less: return below;
|
|
|
|
|
case equal: return equal;
|
|
|
|
|
case less_equal: return below_equal;
|
|
|
|
|
case greater: return above;
|
|
|
|
|
case greater_equal: return above_equal;
|
|
|
|
|
default: UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
return equal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
Condition cc,
|
|
|
|
|
bool strict,
|
|
|
|
@ -2431,7 +2450,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
left_side = right_side;
|
|
|
|
|
right_side = temp;
|
|
|
|
|
cc = ReverseCondition(cc);
|
|
|
|
|
// This may reintroduce greater or less_equal as the value of cc.
|
|
|
|
|
// This may re-introduce greater or less_equal as the value of cc.
|
|
|
|
|
// CompareStub and the inline code both support all values of cc.
|
|
|
|
|
}
|
|
|
|
|
// Implement comparison against a constant Smi, inlining the case
|
|
|
|
@ -2480,16 +2499,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
// Jump to builtin for NaN.
|
|
|
|
|
not_number.Branch(parity_even, &left_side);
|
|
|
|
|
left_side.Unuse();
|
|
|
|
|
Condition double_cc = cc;
|
|
|
|
|
switch (cc) {
|
|
|
|
|
case less: double_cc = below; break;
|
|
|
|
|
case equal: double_cc = equal; break;
|
|
|
|
|
case less_equal: double_cc = below_equal; break;
|
|
|
|
|
case greater: double_cc = above; break;
|
|
|
|
|
case greater_equal: double_cc = above_equal; break;
|
|
|
|
|
default: UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
dest->true_target()->Branch(double_cc);
|
|
|
|
|
dest->true_target()->Branch(DoubleCondition(cc));
|
|
|
|
|
dest->false_target()->Jump();
|
|
|
|
|
not_number.Bind(&left_side);
|
|
|
|
|
}
|
|
|
|
@ -2688,21 +2698,54 @@ void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
dest->Split(cc);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Neither side is a constant Smi or null.
|
|
|
|
|
// If either side is a non-smi constant, skip the smi check.
|
|
|
|
|
// Neither side is a constant Smi, constant 1-char string or constant null.
|
|
|
|
|
// If either side is a non-smi constant, or known to be a heap number skip
|
|
|
|
|
// the smi check.
|
|
|
|
|
bool known_non_smi =
|
|
|
|
|
(left_side.is_constant() && !left_side.handle()->IsSmi()) ||
|
|
|
|
|
(right_side.is_constant() && !right_side.handle()->IsSmi());
|
|
|
|
|
(right_side.is_constant() && !right_side.handle()->IsSmi()) ||
|
|
|
|
|
left_side.number_info().IsHeapNumber() ||
|
|
|
|
|
right_side.number_info().IsHeapNumber();
|
|
|
|
|
NaNInformation nan_info =
|
|
|
|
|
(CouldBeNaN(left_side) && CouldBeNaN(right_side)) ?
|
|
|
|
|
kBothCouldBeNaN :
|
|
|
|
|
kCantBothBeNaN;
|
|
|
|
|
|
|
|
|
|
// Inline number comparison handling any combination of smi's and heap
|
|
|
|
|
// numbers if:
|
|
|
|
|
// code is in a loop
|
|
|
|
|
// the compare operation is different from equal
|
|
|
|
|
// compare is not a for-loop comparison
|
|
|
|
|
// The reason for excluding equal is that it will most likely be done
|
|
|
|
|
// with smi's (not heap numbers) and the code to comparing smi's is inlined
|
|
|
|
|
// separately. The same reason applies for for-loop comparison which will
|
|
|
|
|
// also most likely be smi comparisons.
|
|
|
|
|
bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
|
|
|
|
|
&& node->AsCompareOperation()->is_for_loop_condition();
|
|
|
|
|
bool inline_number_compare = loop_nesting() > 0
|
|
|
|
|
&& cc != equal
|
|
|
|
|
&& !is_for_loop_compare;
|
|
|
|
|
|
|
|
|
|
// Left and right needed in registers for the following code.
|
|
|
|
|
left_side.ToRegister();
|
|
|
|
|
right_side.ToRegister();
|
|
|
|
|
|
|
|
|
|
if (known_non_smi) {
|
|
|
|
|
// When non-smi, call out to the compare stub.
|
|
|
|
|
CompareStub stub(cc, strict, nan_info);
|
|
|
|
|
// Inline the equality check if both operands can't be a NaN. If both
|
|
|
|
|
// objects are the same they are equal.
|
|
|
|
|
if (nan_info == kCantBothBeNaN && cc == equal) {
|
|
|
|
|
__ cmp(left_side.reg(), Operand(right_side.reg()));
|
|
|
|
|
dest->true_target()->Branch(equal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inline number comparison.
|
|
|
|
|
if (inline_number_compare) {
|
|
|
|
|
GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
|
|
|
|
|
if (cc == equal) {
|
|
|
|
|
__ test(answer.reg(), Operand(answer.reg()));
|
|
|
|
@ -2721,6 +2764,7 @@ void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
Register left_reg = left_side.reg();
|
|
|
|
|
Register right_reg = right_side.reg();
|
|
|
|
|
|
|
|
|
|
// In-line check for comparing two smis.
|
|
|
|
|
Result temp = allocator_->Allocate();
|
|
|
|
|
ASSERT(temp.is_valid());
|
|
|
|
|
__ mov(temp.reg(), left_side.reg());
|
|
|
|
@ -2728,8 +2772,22 @@ void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
__ test(temp.reg(), Immediate(kSmiTagMask));
|
|
|
|
|
temp.Unuse();
|
|
|
|
|
is_smi.Branch(zero, taken);
|
|
|
|
|
// When non-smi, call out to the compare stub.
|
|
|
|
|
CompareStub stub(cc, strict, nan_info);
|
|
|
|
|
|
|
|
|
|
// Inline the equality check if both operands can't be a NaN. If both
|
|
|
|
|
// objects are the same they are equal.
|
|
|
|
|
if (nan_info == kCantBothBeNaN && cc == equal) {
|
|
|
|
|
__ cmp(left_side.reg(), Operand(right_side.reg()));
|
|
|
|
|
dest->true_target()->Branch(equal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inline number comparison.
|
|
|
|
|
if (inline_number_compare) {
|
|
|
|
|
GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
|
|
|
|
|
if (cc == equal) {
|
|
|
|
|
__ test(answer.reg(), Operand(answer.reg()));
|
|
|
|
@ -2752,6 +2810,150 @@ void CodeGenerator::Comparison(AstNode* node,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check that the comparison operand is a number. Jump to not_numbers jump
|
|
|
|
|
// target passing the left and right result if the operand is not a number.
|
|
|
|
|
static void CheckComparisonOperand(MacroAssembler* masm_,
|
|
|
|
|
Result* operand,
|
|
|
|
|
Result* left_side,
|
|
|
|
|
Result* right_side,
|
|
|
|
|
JumpTarget* not_numbers) {
|
|
|
|
|
// Perform check if operand is not known to be a number.
|
|
|
|
|
if (!operand->number_info().IsNumber()) {
|
|
|
|
|
Label done;
|
|
|
|
|
__ test(operand->reg(), Immediate(kSmiTagMask));
|
|
|
|
|
__ j(zero, &done);
|
|
|
|
|
__ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
|
|
|
|
|
Immediate(Factory::heap_number_map()));
|
|
|
|
|
not_numbers->Branch(not_equal, left_side, right_side, not_taken);
|
|
|
|
|
__ bind(&done);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load a comparison operand to the FPU stack. This assumes that the operand has
|
|
|
|
|
// already been checked and is a number.
|
|
|
|
|
static void LoadComparisonOperand(MacroAssembler* masm_,
|
|
|
|
|
Result* operand,
|
|
|
|
|
Result* left_side,
|
|
|
|
|
Result* right_side) {
|
|
|
|
|
Label done;
|
|
|
|
|
if (operand->number_info().IsHeapNumber()) {
|
|
|
|
|
// Operand is known to be a heap number, just load it.
|
|
|
|
|
__ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset));
|
|
|
|
|
} else if (operand->number_info().IsSmi()) {
|
|
|
|
|
// Operand is known to be a smi. Convert it to double and keep the original
|
|
|
|
|
// smi.
|
|
|
|
|
__ SmiUntag(operand->reg());
|
|
|
|
|
__ push(operand->reg());
|
|
|
|
|
__ fild_s(Operand(esp, 0));
|
|
|
|
|
__ pop(operand->reg());
|
|
|
|
|
__ SmiTag(operand->reg());
|
|
|
|
|
} else {
|
|
|
|
|
// Operand type not known, check for smi otherwise assume heap number.
|
|
|
|
|
Label smi;
|
|
|
|
|
__ test(operand->reg(), Immediate(kSmiTagMask));
|
|
|
|
|
__ j(zero, &smi);
|
|
|
|
|
__ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset));
|
|
|
|
|
__ jmp(&done);
|
|
|
|
|
__ bind(&smi);
|
|
|
|
|
__ SmiUntag(operand->reg());
|
|
|
|
|
__ push(operand->reg());
|
|
|
|
|
__ fild_s(Operand(esp, 0));
|
|
|
|
|
__ pop(operand->reg());
|
|
|
|
|
__ SmiTag(operand->reg());
|
|
|
|
|
__ jmp(&done);
|
|
|
|
|
}
|
|
|
|
|
__ bind(&done);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load a comparison operand into into a XMM register. Jump to not_numbers jump
|
|
|
|
|
// target passing the left and right result if the operand is not a number.
|
|
|
|
|
static void LoadComparisonOperandSSE2(MacroAssembler* masm_,
|
|
|
|
|
Result* operand,
|
|
|
|
|
XMMRegister reg,
|
|
|
|
|
Result* left_side,
|
|
|
|
|
Result* right_side,
|
|
|
|
|
JumpTarget* not_numbers) {
|
|
|
|
|
Label done;
|
|
|
|
|
if (operand->number_info().IsHeapNumber()) {
|
|
|
|
|
// Operand is known to be a heap number, just load it.
|
|
|
|
|
__ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
|
|
|
|
|
} else if (operand->number_info().IsSmi()) {
|
|
|
|
|
// Operand is known to be a smi. Convert it to double and keep the original
|
|
|
|
|
// smi.
|
|
|
|
|
__ SmiUntag(operand->reg());
|
|
|
|
|
__ cvtsi2sd(reg, Operand(operand->reg()));
|
|
|
|
|
__ SmiTag(left_side->reg());
|
|
|
|
|
} else {
|
|
|
|
|
// Operand type not known, check for smi or heap number.
|
|
|
|
|
Label smi;
|
|
|
|
|
__ test(operand->reg(), Immediate(kSmiTagMask));
|
|
|
|
|
__ j(zero, &smi);
|
|
|
|
|
if (!operand->number_info().IsNumber()) {
|
|
|
|
|
__ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
|
|
|
|
|
Immediate(Factory::heap_number_map()));
|
|
|
|
|
not_numbers->Branch(not_equal, left_side, right_side, taken);
|
|
|
|
|
}
|
|
|
|
|
__ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
|
|
|
|
|
__ jmp(&done);
|
|
|
|
|
|
|
|
|
|
__ bind(&smi);
|
|
|
|
|
// Comvert smi to float and keep the original smi.
|
|
|
|
|
__ SmiUntag(operand->reg());
|
|
|
|
|
__ cvtsi2sd(reg, Operand(operand->reg()));
|
|
|
|
|
__ SmiTag(operand->reg());
|
|
|
|
|
__ jmp(&done);
|
|
|
|
|
}
|
|
|
|
|
__ bind(&done);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::GenerateInlineNumberComparison(Result* left_side,
|
|
|
|
|
Result* right_side,
|
|
|
|
|
Condition cc,
|
|
|
|
|
ControlDestination* dest) {
|
|
|
|
|
ASSERT(left_side->is_register());
|
|
|
|
|
ASSERT(right_side->is_register());
|
|
|
|
|
|
|
|
|
|
JumpTarget not_numbers;
|
|
|
|
|
if (CpuFeatures::IsSupported(SSE2)) {
|
|
|
|
|
CpuFeatures::Scope use_sse2(SSE2);
|
|
|
|
|
|
|
|
|
|
// Load left and right operand into registers xmm0 and xmm1 and compare.
|
|
|
|
|
LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side,
|
|
|
|
|
¬_numbers);
|
|
|
|
|
LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side,
|
|
|
|
|
¬_numbers);
|
|
|
|
|
__ comisd(xmm0, xmm1);
|
|
|
|
|
} else {
|
|
|
|
|
Label check_right, compare;
|
|
|
|
|
|
|
|
|
|
// Make sure that both comparison operands are numbers.
|
|
|
|
|
CheckComparisonOperand(masm_, left_side, left_side, right_side,
|
|
|
|
|
¬_numbers);
|
|
|
|
|
CheckComparisonOperand(masm_, right_side, left_side, right_side,
|
|
|
|
|
¬_numbers);
|
|
|
|
|
|
|
|
|
|
// Load right and left operand to FPU stack and compare.
|
|
|
|
|
LoadComparisonOperand(masm_, right_side, left_side, right_side);
|
|
|
|
|
LoadComparisonOperand(masm_, left_side, left_side, right_side);
|
|
|
|
|
__ FCmp();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bail out if a NaN is involved.
|
|
|
|
|
not_numbers.Branch(parity_even, left_side, right_side, not_taken);
|
|
|
|
|
|
|
|
|
|
// Split to destination targets based on comparison.
|
|
|
|
|
left_side->Unuse();
|
|
|
|
|
right_side->Unuse();
|
|
|
|
|
dest->true_target()->Branch(DoubleCondition(cc));
|
|
|
|
|
dest->false_target()->Jump();
|
|
|
|
|
|
|
|
|
|
not_numbers.Bind(left_side, right_side);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Call the function just below TOS on the stack with the given
|
|
|
|
|
// arguments. The receiver is the TOS.
|
|
|
|
|
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
|
|
|
|
@ -10821,63 +11023,70 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
|
|
|
|
__ push(edx);
|
|
|
|
|
__ push(ecx);
|
|
|
|
|
|
|
|
|
|
// Inlined floating point compare.
|
|
|
|
|
// Call builtin if operands are not floating point or smi.
|
|
|
|
|
Label check_for_symbols;
|
|
|
|
|
Label unordered;
|
|
|
|
|
if (CpuFeatures::IsSupported(SSE2)) {
|
|
|
|
|
CpuFeatures::Scope use_sse2(SSE2);
|
|
|
|
|
CpuFeatures::Scope use_cmov(CMOV);
|
|
|
|
|
// Generate the number comparison code.
|
|
|
|
|
if (include_number_compare_) {
|
|
|
|
|
Label non_number_comparison;
|
|
|
|
|
Label unordered;
|
|
|
|
|
if (CpuFeatures::IsSupported(SSE2)) {
|
|
|
|
|
CpuFeatures::Scope use_sse2(SSE2);
|
|
|
|
|
CpuFeatures::Scope use_cmov(CMOV);
|
|
|
|
|
|
|
|
|
|
FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols);
|
|
|
|
|
__ comisd(xmm0, xmm1);
|
|
|
|
|
FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
|
|
|
|
|
__ comisd(xmm0, xmm1);
|
|
|
|
|
|
|
|
|
|
// Jump to builtin for NaN.
|
|
|
|
|
__ j(parity_even, &unordered, not_taken);
|
|
|
|
|
__ mov(eax, 0); // equal
|
|
|
|
|
__ mov(ecx, Immediate(Smi::FromInt(1)));
|
|
|
|
|
__ cmov(above, eax, Operand(ecx));
|
|
|
|
|
__ mov(ecx, Immediate(Smi::FromInt(-1)));
|
|
|
|
|
__ cmov(below, eax, Operand(ecx));
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
} else {
|
|
|
|
|
FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx);
|
|
|
|
|
FloatingPointHelper::LoadFloatOperands(masm, ecx);
|
|
|
|
|
__ FCmp();
|
|
|
|
|
// Don't base result on EFLAGS when a NaN is involved.
|
|
|
|
|
__ j(parity_even, &unordered, not_taken);
|
|
|
|
|
// Return a result of -1, 0, or 1, based on EFLAGS.
|
|
|
|
|
__ mov(eax, 0); // equal
|
|
|
|
|
__ mov(ecx, Immediate(Smi::FromInt(1)));
|
|
|
|
|
__ cmov(above, eax, Operand(ecx));
|
|
|
|
|
__ mov(ecx, Immediate(Smi::FromInt(-1)));
|
|
|
|
|
__ cmov(below, eax, Operand(ecx));
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
} else {
|
|
|
|
|
FloatingPointHelper::CheckFloatOperands(
|
|
|
|
|
masm, &non_number_comparison, ebx);
|
|
|
|
|
FloatingPointHelper::LoadFloatOperands(masm, ecx);
|
|
|
|
|
__ FCmp();
|
|
|
|
|
|
|
|
|
|
// Jump to builtin for NaN.
|
|
|
|
|
__ j(parity_even, &unordered, not_taken);
|
|
|
|
|
// Don't base result on EFLAGS when a NaN is involved.
|
|
|
|
|
__ j(parity_even, &unordered, not_taken);
|
|
|
|
|
|
|
|
|
|
Label below_lbl, above_lbl;
|
|
|
|
|
// Return a result of -1, 0, or 1, to indicate result of comparison.
|
|
|
|
|
__ j(below, &below_lbl, not_taken);
|
|
|
|
|
__ j(above, &above_lbl, not_taken);
|
|
|
|
|
Label below_label, above_label;
|
|
|
|
|
// Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove
|
|
|
|
|
// two arguments from the stack as they have been pushed in preparation
|
|
|
|
|
// of a possible runtime call.
|
|
|
|
|
__ j(below, &below_label, not_taken);
|
|
|
|
|
__ j(above, &above_label, not_taken);
|
|
|
|
|
|
|
|
|
|
__ xor_(eax, Operand(eax)); // equal
|
|
|
|
|
// Both arguments were pushed in case a runtime call was needed.
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
__ xor_(eax, Operand(eax));
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
|
|
|
|
|
__ bind(&below_lbl);
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(-1)));
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
__ bind(&below_label);
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(-1)));
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
|
|
|
|
|
__ bind(&above_lbl);
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(1)));
|
|
|
|
|
__ bind(&above_label);
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(1)));
|
|
|
|
|
__ ret(2 * kPointerSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If one of the numbers was NaN, then the result is always false.
|
|
|
|
|
// The cc is never not-equal.
|
|
|
|
|
__ bind(&unordered);
|
|
|
|
|
ASSERT(cc_ != not_equal);
|
|
|
|
|
if (cc_ == less || cc_ == less_equal) {
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(1)));
|
|
|
|
|
} else {
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(-1)));
|
|
|
|
|
}
|
|
|
|
|
__ ret(2 * kPointerSize); // eax, edx were pushed
|
|
|
|
|
|
|
|
|
|
// The number comparison code did not provide a valid result.
|
|
|
|
|
__ bind(&non_number_comparison);
|
|
|
|
|
}
|
|
|
|
|
// If one of the numbers was NaN, then the result is always false.
|
|
|
|
|
// The cc is never not-equal.
|
|
|
|
|
__ bind(&unordered);
|
|
|
|
|
ASSERT(cc_ != not_equal);
|
|
|
|
|
if (cc_ == less || cc_ == less_equal) {
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(1)));
|
|
|
|
|
} else {
|
|
|
|
|
__ mov(eax, Immediate(Smi::FromInt(-1)));
|
|
|
|
|
}
|
|
|
|
|
__ ret(2 * kPointerSize); // eax, edx were pushed
|
|
|
|
|
|
|
|
|
|
// Fast negative check for symbol-to-symbol equality.
|
|
|
|
|
__ bind(&check_for_symbols);
|
|
|
|
|
Label check_for_strings;
|
|
|
|
|
if (cc_ == equal) {
|
|
|
|
|
BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
|
|
|
|
@ -11534,10 +11743,11 @@ int CompareStub::MinorKey() {
|
|
|
|
|
// Encode the three parameters in a unique 16 bit value. To avoid duplicate
|
|
|
|
|
// stubs the never NaN NaN condition is only taken into account if the
|
|
|
|
|
// condition is equals.
|
|
|
|
|
ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
|
|
|
|
|
ASSERT(static_cast<unsigned>(cc_) < (1 << 13));
|
|
|
|
|
return ConditionField::encode(static_cast<unsigned>(cc_))
|
|
|
|
|
| StrictField::encode(strict_)
|
|
|
|
|
| NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false);
|
|
|
|
|
| NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
|
|
|
|
|
| IncludeNumberCompareField::encode(include_number_compare_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -12171,6 +12381,9 @@ void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
|
|
|
|
|
Label result_not_equal;
|
|
|
|
|
Label result_greater;
|
|
|
|
|
Label compare_lengths;
|
|
|
|
|
|
|
|
|
|
__ IncrementCounter(&Counters::string_compare_native, 1);
|
|
|
|
|
|
|
|
|
|
// Find minimum length.
|
|
|
|
|
Label left_shorter;
|
|
|
|
|
__ mov(scratch1, FieldOperand(left, String::kLengthOffset));
|
|
|
|
@ -12268,7 +12481,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
|
|
|
|
|
__ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
|
|
|
|
|
|
|
|
|
|
// Compare flat ascii strings.
|
|
|
|
|
__ IncrementCounter(&Counters::string_compare_native, 1);
|
|
|
|
|
GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
|
|
|
|
|
|
|
|
|
|
// Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
|
|
|
|
|