Inline floating point compare

Inline floating point compare instead of calling the stub when the following conditions are met:
  * Code is in a loop
  * Compare is not a for loop condition
  * Compare is not an equal comparison

This inlined code handles heap number to heap number and heap number to smi compare. It can also handle smi to smi compare, but whenever there is a chance of comparing two smis the smi compare is inlined before the inlined floating point compare. Support for non SSE2 hardware is included.

A new set of variants of the compare stub without the floating point comparison code is called if the inline comapre fails due to the operands not beeing heap numbers or smis.

The virtual frame has been extended with a branch taking two live results to be carried through to the destination. This makes this change much simpler as the inlined code have two live results in registers and a number of bailouts.

CompareStub::GetName needs to be updated as well. I will do that as a separate change.

Also inlined equality check if both operands can't be NaN. This can only provide positive equals if it is the same object.
Review URL: http://codereview.chromium.org/1117011

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4220 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
sgjesse@chromium.org 2010-03-23 12:36:31 +00:00
parent c7d9885ba1
commit 9240342ad6
7 changed files with 336 additions and 74 deletions

View File

@ -7159,10 +7159,11 @@ int CompareStub::MinorKey() {
// Encode the three parameters in a unique 16 bit value. To avoid duplicate // 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 // stubs the never NaN NaN condition is only taken into account if the
// condition is equals. // condition is equals.
ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 14)); ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 13));
return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) return ConditionField::encode(static_cast<unsigned>(cc_) >> 28)
| StrictField::encode(strict_) | StrictField::encode(strict_)
| NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false); | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false)
| IncludeNumberCompareField::encode(include_number_compare_);
} }

View File

@ -346,8 +346,12 @@ class CompareStub: public CodeStub {
public: public:
CompareStub(Condition cc, CompareStub(Condition cc,
bool strict, bool strict,
NaNInformation nan_info = kBothCouldBeNaN) : NaNInformation nan_info = kBothCouldBeNaN,
cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { } bool include_number_compare = true) :
cc_(cc),
strict_(strict),
never_nan_nan_(nan_info == kCantBothBeNaN),
include_number_compare_(include_number_compare) { }
void Generate(MacroAssembler* masm); void Generate(MacroAssembler* masm);
@ -360,11 +364,16 @@ class CompareStub: public CodeStub {
// generating the minor key for other comparisons to avoid creating more // generating the minor key for other comparisons to avoid creating more
// stubs. // stubs.
bool never_nan_nan_; bool never_nan_nan_;
// Do generate the number comparison code in the stub. Stubs without number
// 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_;
// Encoding of the minor key CCCCCCCCCCCCCCNS. // Encoding of the minor key CCCCCCCCCCCCCCNS.
class StrictField: public BitField<bool, 0, 1> {}; class StrictField: public BitField<bool, 0, 1> {};
class NeverNanNanField: public BitField<bool, 1, 1> {}; class NeverNanNanField: public BitField<bool, 1, 1> {};
class ConditionField: public BitField<int, 2, 14> {}; class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
class ConditionField: public BitField<int, 3, 13> {};
Major MajorKey() { return Compare; } Major MajorKey() { return Compare; }

View File

@ -911,6 +911,7 @@ class FloatingPointHelper : public AllStatic {
// operand in register number. Returns operand as floating point number // operand in register number. Returns operand as floating point number
// on FPU stack. // on FPU stack.
static void LoadFloatOperand(MacroAssembler* masm, Register number); static void LoadFloatOperand(MacroAssembler* masm, Register number);
// Code pattern for loading floating point values. Input values must // Code pattern for loading floating point values. Input values must
// be either smi or heap number objects (fp values). Requirements: // 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. // 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, static void CheckFloatOperands(MacroAssembler* masm,
Label* non_float, Label* non_float,
Register scratch); Register scratch);
// Takes the operands in edx and eax and loads them as integers in eax // Takes the operands in edx and eax and loads them as integers in eax
// and ecx. // and ecx.
static void LoadAsIntegers(MacroAssembler* masm, 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. // into xmm0 and xmm1 if they are. Operands are in edx and eax.
// Leaves operands unchanged. // Leaves operands unchanged.
static void LoadSSE2Operands(MacroAssembler* masm); static void LoadSSE2Operands(MacroAssembler* masm);
// Test if operands are numbers (smi or HeapNumber objects), and load // 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 // 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. // 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, void CodeGenerator::Comparison(AstNode* node,
Condition cc, Condition cc,
bool strict, bool strict,
@ -2431,7 +2450,7 @@ void CodeGenerator::Comparison(AstNode* node,
left_side = right_side; left_side = right_side;
right_side = temp; right_side = temp;
cc = ReverseCondition(cc); 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. // CompareStub and the inline code both support all values of cc.
} }
// Implement comparison against a constant Smi, inlining the case // Implement comparison against a constant Smi, inlining the case
@ -2480,16 +2499,7 @@ void CodeGenerator::Comparison(AstNode* node,
// Jump to builtin for NaN. // Jump to builtin for NaN.
not_number.Branch(parity_even, &left_side); not_number.Branch(parity_even, &left_side);
left_side.Unuse(); left_side.Unuse();
Condition double_cc = cc; dest->true_target()->Branch(DoubleCondition(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->false_target()->Jump(); dest->false_target()->Jump();
not_number.Bind(&left_side); not_number.Bind(&left_side);
} }
@ -2688,21 +2698,54 @@ void CodeGenerator::Comparison(AstNode* node,
dest->Split(cc); dest->Split(cc);
} }
} else { } else {
// Neither side is a constant Smi or null. // Neither side is a constant Smi, constant 1-char string or constant null.
// If either side is a non-smi constant, skip the smi check. // If either side is a non-smi constant, or known to be a heap number skip
// the smi check.
bool known_non_smi = bool known_non_smi =
(left_side.is_constant() && !left_side.handle()->IsSmi()) || (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 = NaNInformation nan_info =
(CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ?
kBothCouldBeNaN : kBothCouldBeNaN :
kCantBothBeNaN; 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(); left_side.ToRegister();
right_side.ToRegister(); right_side.ToRegister();
if (known_non_smi) { if (known_non_smi) {
// When non-smi, call out to the compare stub. // Inline the equality check if both operands can't be a NaN. If both
CompareStub stub(cc, strict, nan_info); // 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); Result answer = frame_->CallStub(&stub, &left_side, &right_side);
if (cc == equal) { if (cc == equal) {
__ test(answer.reg(), Operand(answer.reg())); __ test(answer.reg(), Operand(answer.reg()));
@ -2721,6 +2764,7 @@ void CodeGenerator::Comparison(AstNode* node,
Register left_reg = left_side.reg(); Register left_reg = left_side.reg();
Register right_reg = right_side.reg(); Register right_reg = right_side.reg();
// In-line check for comparing two smis.
Result temp = allocator_->Allocate(); Result temp = allocator_->Allocate();
ASSERT(temp.is_valid()); ASSERT(temp.is_valid());
__ mov(temp.reg(), left_side.reg()); __ mov(temp.reg(), left_side.reg());
@ -2728,8 +2772,22 @@ void CodeGenerator::Comparison(AstNode* node,
__ test(temp.reg(), Immediate(kSmiTagMask)); __ test(temp.reg(), Immediate(kSmiTagMask));
temp.Unuse(); temp.Unuse();
is_smi.Branch(zero, taken); 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); Result answer = frame_->CallStub(&stub, &left_side, &right_side);
if (cc == equal) { if (cc == equal) {
__ test(answer.reg(), Operand(answer.reg())); __ 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,
&not_numbers);
LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side,
&not_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,
&not_numbers);
CheckComparisonOperand(masm_, right_side, left_side, right_side,
&not_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 // Call the function just below TOS on the stack with the given
// arguments. The receiver is the TOS. // arguments. The receiver is the TOS.
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
@ -10821,63 +11023,70 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ push(edx); __ push(edx);
__ push(ecx); __ push(ecx);
// Inlined floating point compare. // Generate the number comparison code.
// Call builtin if operands are not floating point or smi. if (include_number_compare_) {
Label check_for_symbols; Label non_number_comparison;
Label unordered; Label unordered;
if (CpuFeatures::IsSupported(SSE2)) { if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2); CpuFeatures::Scope use_sse2(SSE2);
CpuFeatures::Scope use_cmov(CMOV); CpuFeatures::Scope use_cmov(CMOV);
FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols); FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
__ comisd(xmm0, xmm1); __ comisd(xmm0, xmm1);
// Jump to builtin for NaN. // Don't base result on EFLAGS when a NaN is involved.
__ j(parity_even, &unordered, not_taken); __ j(parity_even, &unordered, not_taken);
__ mov(eax, 0); // equal // Return a result of -1, 0, or 1, based on EFLAGS.
__ mov(ecx, Immediate(Smi::FromInt(1))); __ mov(eax, 0); // equal
__ cmov(above, eax, Operand(ecx)); __ mov(ecx, Immediate(Smi::FromInt(1)));
__ mov(ecx, Immediate(Smi::FromInt(-1))); __ cmov(above, eax, Operand(ecx));
__ cmov(below, eax, Operand(ecx)); __ mov(ecx, Immediate(Smi::FromInt(-1)));
__ ret(2 * kPointerSize); __ cmov(below, eax, Operand(ecx));
} else { __ ret(2 * kPointerSize);
FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); } else {
FloatingPointHelper::LoadFloatOperands(masm, ecx); FloatingPointHelper::CheckFloatOperands(
__ FCmp(); masm, &non_number_comparison, ebx);
FloatingPointHelper::LoadFloatOperands(masm, ecx);
__ FCmp();
// Jump to builtin for NaN. // Don't base result on EFLAGS when a NaN is involved.
__ j(parity_even, &unordered, not_taken); __ j(parity_even, &unordered, not_taken);
Label below_lbl, above_lbl; Label below_label, above_label;
// Return a result of -1, 0, or 1, to indicate result of comparison. // Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove
__ j(below, &below_lbl, not_taken); // two arguments from the stack as they have been pushed in preparation
__ j(above, &above_lbl, not_taken); // of a possible runtime call.
__ j(below, &below_label, not_taken);
__ j(above, &above_label, not_taken);
__ xor_(eax, Operand(eax)); // equal __ xor_(eax, Operand(eax));
// Both arguments were pushed in case a runtime call was needed. __ ret(2 * kPointerSize);
__ ret(2 * kPointerSize);
__ bind(&below_lbl); __ bind(&below_label);
__ mov(eax, Immediate(Smi::FromInt(-1))); __ mov(eax, Immediate(Smi::FromInt(-1)));
__ ret(2 * kPointerSize); __ ret(2 * kPointerSize);
__ bind(&above_lbl); __ bind(&above_label);
__ mov(eax, Immediate(Smi::FromInt(1))); __ 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 __ 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. // Fast negative check for symbol-to-symbol equality.
__ bind(&check_for_symbols);
Label check_for_strings; Label check_for_strings;
if (cc_ == equal) { if (cc_ == equal) {
BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); 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 // 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 // stubs the never NaN NaN condition is only taken into account if the
// condition is equals. // condition is equals.
ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); ASSERT(static_cast<unsigned>(cc_) < (1 << 13));
return ConditionField::encode(static_cast<unsigned>(cc_)) return ConditionField::encode(static_cast<unsigned>(cc_))
| StrictField::encode(strict_) | 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_not_equal;
Label result_greater; Label result_greater;
Label compare_lengths; Label compare_lengths;
__ IncrementCounter(&Counters::string_compare_native, 1);
// Find minimum length. // Find minimum length.
Label left_shorter; Label left_shorter;
__ mov(scratch1, FieldOperand(left, String::kLengthOffset)); __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
@ -12268,7 +12481,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
__ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
// Compare flat ascii strings. // Compare flat ascii strings.
__ IncrementCounter(&Counters::string_compare_native, 1);
GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
// Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)

View File

@ -528,6 +528,10 @@ class CodeGenerator: public AstVisitor {
Condition cc, Condition cc,
bool strict, bool strict,
ControlDestination* destination); ControlDestination* destination);
void GenerateInlineNumberComparison(Result* left_side,
Result* right_side,
Condition cc,
ControlDestination* dest);
// To prevent long attacker-controlled byte sequences, integer constants // To prevent long attacker-controlled byte sequences, integer constants
// from the JavaScript source are loaded in two parts if they are larger // from the JavaScript source are loaded in two parts if they are larger

View File

@ -290,6 +290,25 @@ void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
} }
void JumpTarget::Branch(Condition cc, Result* arg0, Result* arg1, Hint hint) {
ASSERT(cgen()->has_valid_frame());
// We want to check that non-frame registers at the call site stay in
// the same registers on the fall-through branch.
DECLARE_ARGCHECK_VARS(arg0);
DECLARE_ARGCHECK_VARS(arg1);
cgen()->frame()->Push(arg0);
cgen()->frame()->Push(arg1);
DoBranch(cc, hint);
*arg1 = cgen()->frame()->Pop();
*arg0 = cgen()->frame()->Pop();
ASSERT_ARGCHECK(arg0);
ASSERT_ARGCHECK(arg1);
}
void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) { void BreakTarget::Branch(Condition cc, Result* arg, Hint hint) {
ASSERT(cgen()->has_valid_frame()); ASSERT(cgen()->has_valid_frame());
@ -331,6 +350,17 @@ void JumpTarget::Bind(Result* arg) {
} }
void JumpTarget::Bind(Result* arg0, Result* arg1) {
if (cgen()->has_valid_frame()) {
cgen()->frame()->Push(arg0);
cgen()->frame()->Push(arg1);
}
DoBind();
*arg1 = cgen()->frame()->Pop();
*arg0 = cgen()->frame()->Pop();
}
void JumpTarget::AddReachingFrame(VirtualFrame* frame) { void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
ASSERT(reaching_frames_.length() == merge_labels_.length()); ASSERT(reaching_frames_.length() == merge_labels_.length());
ASSERT(entry_frame_ == NULL); ASSERT(entry_frame_ == NULL);

View File

@ -117,12 +117,17 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// the target and the fall-through. // the target and the fall-through.
virtual void Branch(Condition cc, Hint hint = no_hint); virtual void Branch(Condition cc, Hint hint = no_hint);
virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint); virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
virtual void Branch(Condition cc,
Result* arg0,
Result* arg1,
Hint hint = no_hint);
// Bind a jump target. If there is no current frame at the binding // Bind a jump target. If there is no current frame at the binding
// site, there must be at least one frame reaching via a forward // site, there must be at least one frame reaching via a forward
// jump. // jump.
virtual void Bind(); virtual void Bind();
virtual void Bind(Result* arg); virtual void Bind(Result* arg);
virtual void Bind(Result* arg0, Result* arg1);
// Emit a call to a jump target. There must be a current frame at // Emit a call to a jump target. There must be a current frame at
// the call. The frame at the target is the same as the current // the call. The frame at the target is the same as the current

View File

@ -9105,10 +9105,11 @@ int CompareStub::MinorKey() {
// Encode the three parameters in a unique 16 bit value. To avoid duplicate // 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 // stubs the never NaN NaN condition is only taken into account if the
// condition is equals. // condition is equals.
ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); ASSERT(static_cast<unsigned>(cc_) < (1 << 13));
return ConditionField::encode(static_cast<unsigned>(cc_)) return ConditionField::encode(static_cast<unsigned>(cc_))
| StrictField::encode(strict_) | StrictField::encode(strict_)
| NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false); | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
| IncludeNumberCompareField::encode(include_number_compare_);
} }