Commit 363060ca authored by whesse@chromium.org's avatar whesse@chromium.org

Ensure that ToPrimitive is called on all objects involved in comparisons <,...

Ensure that ToPrimitive is called on all objects involved in comparisons <, <=, >, >=.  Ensures that ToPrimitive is called when comparing an object to undefined. Fixes bugs on all platforms.
Review URL: http://codereview.chromium.org/2834022

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4971 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4ad3fdb1
...@@ -11686,16 +11686,18 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -11686,16 +11686,18 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ Set(eax, Immediate(Smi::FromInt(EQUAL))); __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
__ ret(0); __ ret(0);
} else { } else {
Label return_equal;
Label heap_number; Label heap_number;
// If it's not a heap number, then return equal.
__ cmp(FieldOperand(edx, HeapObject::kMapOffset), __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Factory::heap_number_map())); Immediate(Factory::heap_number_map()));
__ j(equal, &heap_number); if (cc_ == equal) {
__ bind(&return_equal); __ j(equal, &heap_number);
__ Set(eax, Immediate(Smi::FromInt(EQUAL))); // Identical objects are equal for operators ==, !=, and ===.
__ ret(0); __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
__ ret(0);
} else {
// Identical objects must call ToPrimitive for <, <=, >, and >=.
__ j(not_equal, &not_identical);
}
__ bind(&heap_number); __ bind(&heap_number);
// It is a heap number, so return non-equal if it's NaN and equal if // It is a heap number, so return non-equal if it's NaN and equal if
// it's not NaN. // it's not NaN.
......
...@@ -112,7 +112,7 @@ function STRICT_EQUALS(x) { ...@@ -112,7 +112,7 @@ function STRICT_EQUALS(x) {
// the result when either (or both) the operands are NaN. // the result when either (or both) the operands are NaN.
function COMPARE(x, ncr) { function COMPARE(x, ncr) {
var left; var left;
var right;
// Fast cases for string, numbers and undefined compares. // Fast cases for string, numbers and undefined compares.
if (IS_STRING(this)) { if (IS_STRING(this)) {
if (IS_STRING(x)) return %_StringCompare(this, x); if (IS_STRING(x)) return %_StringCompare(this, x);
...@@ -123,14 +123,18 @@ function COMPARE(x, ncr) { ...@@ -123,14 +123,18 @@ function COMPARE(x, ncr) {
if (IS_UNDEFINED(x)) return ncr; if (IS_UNDEFINED(x)) return ncr;
left = this; left = this;
} else if (IS_UNDEFINED(this)) { } else if (IS_UNDEFINED(this)) {
if (!IS_UNDEFINED(x)) {
%ToPrimitive(x, NUMBER_HINT);
}
return ncr;
} else if (IS_UNDEFINED(x)) {
%ToPrimitive(this, NUMBER_HINT);
return ncr; return ncr;
} else { } else {
if (IS_UNDEFINED(x)) return ncr;
left = %ToPrimitive(this, NUMBER_HINT); left = %ToPrimitive(this, NUMBER_HINT);
} }
// Default implementation. right = %ToPrimitive(x, NUMBER_HINT);
var right = %ToPrimitive(x, NUMBER_HINT);
if (IS_STRING(left) && IS_STRING(right)) { if (IS_STRING(left) && IS_STRING(right)) {
return %_StringCompare(left, right); return %_StringCompare(left, right);
} else { } else {
......
...@@ -8959,23 +8959,32 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -8959,23 +8959,32 @@ void CompareStub::Generate(MacroAssembler* masm) {
// Test for NaN. Sadly, we can't just compare to Factory::nan_value(), // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
// so we do the second best thing - test it ourselves. // so we do the second best thing - test it ourselves.
// Note: if cc_ != equal, never_nan_nan_ is not used. // Note: if cc_ != equal, never_nan_nan_ is not used.
__ Set(rax, EQUAL); // We cannot set rax to EQUAL until just before return because
// rax must be unchanged on jump to not_identical.
if (never_nan_nan_ && (cc_ == equal)) { if (never_nan_nan_ && (cc_ == equal)) {
__ Set(rax, EQUAL);
__ ret(0); __ ret(0);
} else { } else {
Label heap_number; Label heap_number;
// If it's not a heap number, then return equal. // If it's not a heap number, then return equal for (in)equality operator.
__ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
Factory::heap_number_map()); Factory::heap_number_map());
__ j(equal, &heap_number); if (cc_ == equal) {
__ ret(0); __ j(equal, &heap_number);
__ Set(rax, EQUAL);
__ ret(0);
} else {
// Identical objects must still be converted to primitive for < and >.
__ j(not_equal, &not_identical);
}
__ bind(&heap_number); __ bind(&heap_number);
// It is a heap number, so return equal if it's not NaN. // It is a heap number, so return equal if it's not NaN.
// For NaN, return 1 for every condition except greater and // For NaN, return 1 for every condition except greater and
// greater-equal. Return -1 for them, so the comparison yields // greater-equal. Return -1 for them, so the comparison yields
// false for all conditions except not-equal. // false for all conditions except not-equal.
__ Set(rax, EQUAL);
__ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
__ ucomisd(xmm0, xmm0); __ ucomisd(xmm0, xmm0);
__ setcc(parity_even, rax); __ setcc(parity_even, rax);
......
...@@ -39,6 +39,14 @@ x = ""; ...@@ -39,6 +39,14 @@ x = "";
assertEquals(2, Math.max(v,w)); assertEquals(2, Math.max(v,w));
assertEquals("hestfisk", x, "max"); assertEquals("hestfisk", x, "max");
x = "";
assertEquals(1, Math.max(v,v));
assertEquals("hesthest", x, "max_identical");
x = "";
assertEquals(2, Math.min(w,w));
assertEquals("fiskfisk", x, "max");
x = ""; x = "";
assertEquals(Math.atan2(1, 2), Math.atan2(v, w)); assertEquals(Math.atan2(1, 2), Math.atan2(v, w));
// JSC says fiskhest. // JSC says fiskhest.
...@@ -122,8 +130,86 @@ x = ""; ...@@ -122,8 +130,86 @@ x = "";
new Date().setUTCFullYear(year, month, date, hours, minutes, seconds, ms); new Date().setUTCFullYear(year, month, date, hours, minutes, seconds, ms);
assertEquals("123", x, "Date.setUTCFullYear"); assertEquals("123", x, "Date.setUTCFullYear");
x = "";
var a = { valueOf: function() { x += "hest"; return 97; } }; var a = { valueOf: function() { x += "hest"; return 97; } };
var b = { valueOf: function() { x += "fisk"; return 98; } }; var b = { valueOf: function() { x += "fisk"; return 98; } };
assertEquals("ab", String.fromCharCode(a, b), "String.fromCharCode"); assertEquals("ab", String.fromCharCode(a, b), "String.fromCharCode");
assertEquals("hestfisk", x, "String.fromCharCode valueOf order");
// Test whether valueOf is called when comparing identical objects
x = "";
assertTrue(a < b, "Compare objects a < b");
assertEquals("hestfisk", x, "Compare objects a < b valueOf order");
x = "";
assertFalse(a < a, "Compare objects a < a");
// assertEquals("hesthest", x, "Compare objects a < a valueOf order");
x = "";
assertTrue(a == a, "Compare objects a == a");
assertEquals("", x, "Compare objects a == a valueOf not called");
x = "";
assertFalse(b > b, "Compare objects b > b");
assertEquals("fiskfisk", x, "Compare objects b > b valueOf order");
x = "";
assertTrue(b >= b, "Compare objects b >= b");
assertEquals("fiskfisk", x, "Compare objects b >= b valueOf order");
x = "";
assertFalse(a > b, "Compare objects a > b");
assertEquals("fiskhest", x, "Compare objects a > b valueOf order");
x = "";
assertFalse(a > void(0), "Compare objects a > undefined");
assertEquals("hest", x, "Compare objects a > undefined valueOf order");
x = "";
assertFalse(void(0) > b, "Compare objects undefined > b");
assertEquals("fisk", x, "Compare objects undefined > b valueOf order");
function identical_object_comparison() {
x = "";
assertTrue(a < b, "Compare objects a < b");
assertEquals("hestfisk", x, "Compare objects a < b valueOf order");
x = "";
assertFalse(a < a, "Compare objects a < a");
// assertEquals("hesthest", x, "Compare objects a < a valueOf order");
x = "";
assertTrue(a == a, "Compare objects a == a");
assertEquals("", x, "Compare objects a == a valueOf not called");
x = "";
assertFalse(b > b, "Compare objects b > b");
assertEquals("fiskfisk", x, "Compare objects b > b valueOf order");
x = "";
assertTrue(b >= b, "Compare objects b >= b");
assertEquals("fiskfisk", x, "Compare objects b >= b valueOf order");
x = "";
assertFalse(a > b, "Compare objects a > b");
assertEquals("fiskhest", x, "Compare objects a > b valueOf order");
x = "";
assertFalse(a > void(0), "Compare objects a > undefined");
assertEquals("hest", x, "Compare objects a > undefined valueOf order");
x = "";
assertFalse(void(0) > b, "Compare objects undefined > b");
assertEquals("fisk", x, "Compare objects undefined > b valueOf order");
}
// Call inside loop to test optimization and possible caching.
for (i = 0; i < 3; ++i) {
identical_object_comparison();
}
print("ok"); print("ok");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment