Update to ES2015 == semantics for Symbol/SIMD wrappers

When == is invoked on a Symbol or SIMD vector and an object, the object should
be converted to a primitive with ToPrimitive and then compared again. This means,
for example, that for a Symbol or SIMD vector s, s == Object(s). This patch makes
that change in the implementation of ==. Only the runtime function needed to be
changed, as the code stubs and compiler specializations don't operate on Symbols
or SIMD vectors, and on these types, a fallback to the runtime function is always
used.

BUG=v8:3593
LOG=Y
R=adamk

Review URL: https://codereview.chromium.org/1421413002

Cr-Commit-Position: refs/heads/master@{#31614}
This commit is contained in:
littledan 2015-10-27 13:20:08 -07:00 committed by Commit bot
parent f8465b45f7
commit b436635ac4
7 changed files with 58 additions and 22 deletions

View File

@ -291,8 +291,9 @@ Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
} else if (y->IsString()) { } else if (y->IsString()) {
return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y)))); return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y))));
} else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) if (JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)).ToHandle(&y)) {
.ToHandle(&y)) { continue;
} else {
return Nothing<bool>(); return Nothing<bool>();
} }
} else { } else {
@ -309,8 +310,9 @@ Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
x = String::ToNumber(Handle<String>::cast(x)); x = String::ToNumber(Handle<String>::cast(x));
return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number()));
} else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) if (JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)).ToHandle(&y)) {
.ToHandle(&y)) { continue;
} else {
return Nothing<bool>(); return Nothing<bool>();
} }
} else { } else {
@ -330,25 +332,47 @@ Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
return Nothing<bool>(); return Nothing<bool>();
} }
x = Oddball::ToNumber(Handle<Oddball>::cast(x)); x = Oddball::ToNumber(Handle<Oddball>::cast(x));
continue;
} else { } else {
return Just(false); return Just(false);
} }
} else if (x->IsSymbol()) { } else if (x->IsSymbol()) {
if (y->IsSymbol()) {
return Just(x.is_identical_to(y)); return Just(x.is_identical_to(y));
} else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
if (JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)).ToHandle(&y)) {
continue;
} else {
return Nothing<bool>();
}
} else {
return Just(false);
}
} else if (x->IsSimd128Value()) { } else if (x->IsSimd128Value()) {
if (!y->IsSimd128Value()) return Just(false); if (y->IsSimd128Value()) {
return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x), return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
Handle<Simd128Value>::cast(y))); Handle<Simd128Value>::cast(y)));
} else if (y->IsJSReceiver() && !y->IsUndetectableObject()) {
if (JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)).ToHandle(&y)) {
continue;
} else {
return Nothing<bool>();
}
} else {
return Just(false);
}
} else if (x->IsJSReceiver() && !x->IsUndetectableObject()) { } else if (x->IsJSReceiver() && !x->IsUndetectableObject()) {
if (y->IsJSReceiver()) { if (y->IsJSReceiver()) {
return Just(x.is_identical_to(y)); return Just(x.is_identical_to(y));
} else if (y->IsNull() || y->IsSimd128Value() || y->IsSymbol() || } else if (y->IsNull() || y->IsUndefined()) {
y->IsUndefined()) {
return Just(false); return Just(false);
} else if (y->IsBoolean()) { } else if (y->IsBoolean()) {
y = Oddball::ToNumber(Handle<Oddball>::cast(y)); y = Oddball::ToNumber(Handle<Oddball>::cast(y));
} continue;
if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)).ToHandle(&x)) { } else if (JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x))
.ToHandle(&x)) {
continue;
} else {
return Nothing<bool>(); return Nothing<bool>();
} }
} else { } else {
@ -356,6 +380,7 @@ Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
(x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) && (x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) &&
(y->IsNull() || y->IsUndefined() || y->IsUndetectableObject())); (y->IsNull() || y->IsUndefined() || y->IsUndetectableObject()));
} }
UNREACHABLE();
} }
} }

View File

@ -2366,7 +2366,7 @@ THREADED_TEST(SymbolProperties) {
CHECK(sym_obj->IsSymbolObject()); CHECK(sym_obj->IsSymbolObject());
CHECK(!sym2->IsSymbolObject()); CHECK(!sym2->IsSymbolObject());
CHECK(!obj->IsSymbolObject()); CHECK(!obj->IsSymbolObject());
CHECK(!sym_obj->Equals(sym2)); CHECK(sym_obj->Equals(sym2));
CHECK(!sym_obj->StrictEquals(sym2)); CHECK(!sym_obj->StrictEquals(sym2));
CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj)); CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2)); CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));

View File

@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --harmony-simd
/** /**
* This test uses assert{True,False}(... == ...) instead of * This test uses assert{True,False}(... == ...) instead of
* assertEquals(..., ...) to not rely on the details of the * assertEquals(..., ...) to not rely on the details of the
@ -234,3 +236,15 @@ function testBadConversion(value) {
testBadConversion(0); testBadConversion(0);
testBadConversion("string"); testBadConversion("string");
testBadConversion(true); testBadConversion(true);
var s = Symbol();
testEqual(s, s);
testEqual(Object(s), s);
testEqual(new Wrapper(s), s);
testNotEqual(Object(s), Object(s));
var simd = SIMD.Float32x4(1, 2, 3, 4);
testEqual(simd, simd);
testEqual(Object(simd), simd);
testEqual(new Wrapper(simd), simd);
testNotEqual(Object(simd), Object(simd));

View File

@ -167,8 +167,8 @@ function TestEquality() {
assertTrue(symbols[i] == symbols[i]) assertTrue(symbols[i] == symbols[i])
assertFalse(symbols[i] === Object(symbols[i])) assertFalse(symbols[i] === Object(symbols[i]))
assertFalse(Object(symbols[i]) === symbols[i]) assertFalse(Object(symbols[i]) === symbols[i])
assertFalse(symbols[i] == Object(symbols[i])) assertTrue(symbols[i] == Object(symbols[i]))
assertFalse(Object(symbols[i]) == symbols[i]) assertTrue(Object(symbols[i]) == symbols[i])
assertTrue(symbols[i] === symbols[i].valueOf()) assertTrue(symbols[i] === symbols[i].valueOf())
assertTrue(symbols[i].valueOf() === symbols[i]) assertTrue(symbols[i].valueOf() === symbols[i])
assertTrue(symbols[i] == symbols[i].valueOf()) assertTrue(symbols[i] == symbols[i].valueOf())

View File

@ -132,8 +132,8 @@ function TestEquality() {
assertTrue(symbols[i] == symbols[i]) assertTrue(symbols[i] == symbols[i])
assertFalse(symbols[i] === Object(symbols[i])) assertFalse(symbols[i] === Object(symbols[i]))
assertFalse(Object(symbols[i]) === symbols[i]) assertFalse(Object(symbols[i]) === symbols[i])
assertFalse(symbols[i] == Object(symbols[i])) assertTrue(symbols[i] == Object(symbols[i]))
assertFalse(Object(symbols[i]) == symbols[i]) assertTrue(Object(symbols[i]) == symbols[i])
assertTrue(symbols[i] === symbols[i].valueOf()) assertTrue(symbols[i] === symbols[i].valueOf())
assertTrue(symbols[i].valueOf() === symbols[i]) assertTrue(symbols[i].valueOf() === symbols[i])
assertTrue(symbols[i] == symbols[i].valueOf()) assertTrue(symbols[i] == symbols[i].valueOf())

View File

@ -337,8 +337,8 @@ function TestEquality(type, lanes) {
assertTrue(instance == instance) assertTrue(instance == instance)
assertFalse(instance === Object(instance)) assertFalse(instance === Object(instance))
assertFalse(Object(instance) === instance) assertFalse(Object(instance) === instance)
assertFalse(instance == Object(instance)) assertTrue(instance == Object(instance))
assertFalse(Object(instance) == instance) assertTrue(Object(instance) == instance)
assertTrue(instance === instance.valueOf()) assertTrue(instance === instance.valueOf())
assertTrue(instance.valueOf() === instance) assertTrue(instance.valueOf() === instance)
assertTrue(instance == instance.valueOf()) assertTrue(instance == instance.valueOf())

View File

@ -620,9 +620,6 @@
'intl402/String/prototype/toLocaleUpperCase/special_casing_Lithuanian': [FAIL], 'intl402/String/prototype/toLocaleUpperCase/special_casing_Lithuanian': [FAIL],
'intl402/String/prototype/toLocaleUpperCase/special_casing_Turkish': [FAIL], 'intl402/String/prototype/toLocaleUpperCase/special_casing_Turkish': [FAIL],
# https://code.google.com/p/v8/issues/detail?id=3788
'language/expressions/equals/coerce-symbol-to-prim-return-prim': [FAIL],
######################## NEEDS INVESTIGATION ########################### ######################## NEEDS INVESTIGATION ###########################
# These test failures are specific to the intl402 suite and need investigation # These test failures are specific to the intl402 suite and need investigation