Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index a7c3d7610c42ad192c2396cba4dedea79370ec67..91aa2ae250360535fb89e37dcd6f79f394cc4f3f 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -98,13 +98,13 @@ MaybeHandle<Object> Object::ToNumber(Handle<Object> input) { |
if (input->IsNumber()) { |
return input; |
} |
- Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate(); |
- if (input->IsOddball()) { |
- return handle(Handle<Oddball>::cast(input)->to_number(), isolate); |
- } |
if (input->IsString()) { |
return String::ToNumber(Handle<String>::cast(input)); |
} |
+ if (input->IsOddball()) { |
+ return Oddball::ToNumber(Handle<Oddball>::cast(input)); |
+ } |
+ Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate(); |
if (input->IsSymbol()) { |
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), |
Object); |
@@ -159,13 +159,114 @@ bool Object::BooleanValue() { |
} |
+namespace { |
+ |
+// TODO(bmeurer): Maybe we should introduce a marker interface Number, |
+// where we put all these methods at some point? |
+bool NumberEquals(double x, double y) { |
+ // Must check explicitly for NaN's on Windows, but -0 works fine. |
+ if (std::isnan(x)) return false; |
+ if (std::isnan(y)) return false; |
+ return x == y; |
+} |
+ |
+ |
+bool NumberEquals(const Object* x, const Object* y) { |
+ return NumberEquals(x->Number(), y->Number()); |
+} |
+ |
+ |
+bool NumberEquals(Handle<Object> x, Handle<Object> y) { |
+ return NumberEquals(*x, *y); |
+} |
+ |
+} // namespace |
+ |
+ |
+// static |
+Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) { |
+ while (true) { |
+ if (x->IsNumber()) { |
+ if (y->IsNumber()) { |
+ return Just(NumberEquals(x, y)); |
+ } else if (y->IsBoolean()) { |
+ return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); |
+ } else if (y->IsString()) { |
+ return Just(NumberEquals(x, String::ToNumber(Handle<String>::cast(y)))); |
+ } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { |
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) |
+ .ToHandle(&y)) { |
+ return Nothing<bool>(); |
+ } |
+ } else { |
+ return Just(false); |
+ } |
+ } else if (x->IsString()) { |
+ if (y->IsString()) { |
+ return Just( |
+ String::Equals(Handle<String>::cast(x), Handle<String>::cast(y))); |
+ } else if (y->IsNumber()) { |
+ x = String::ToNumber(Handle<String>::cast(x)); |
+ return Just(NumberEquals(x, y)); |
+ } else if (y->IsBoolean()) { |
+ x = String::ToNumber(Handle<String>::cast(x)); |
+ return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); |
+ } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { |
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) |
+ .ToHandle(&y)) { |
+ return Nothing<bool>(); |
+ } |
+ } else { |
+ return Just(false); |
+ } |
+ } else if (x->IsBoolean()) { |
+ if (y->IsOddball()) { |
+ return Just(x.is_identical_to(y)); |
+ } else if (y->IsNumber()) { |
+ return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); |
+ } else if (y->IsString()) { |
+ y = String::ToNumber(Handle<String>::cast(y)); |
+ return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); |
+ } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { |
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) |
+ .ToHandle(&y)) { |
+ return Nothing<bool>(); |
+ } |
+ x = Oddball::ToNumber(Handle<Oddball>::cast(x)); |
+ } else { |
+ return Just(false); |
+ } |
+ } else if (x->IsSymbol()) { |
+ return Just(x.is_identical_to(y)); |
+ } else if (x->IsSimd128Value()) { |
+ if (!y->IsSimd128Value()) return Just(false); |
+ return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x), |
+ Handle<Simd128Value>::cast(y))); |
+ } else if (x->IsJSReceiver() && !x->IsUndetectableObject()) { |
+ if (y->IsJSReceiver()) { |
+ return Just(x.is_identical_to(y)); |
+ } else if (y->IsNull() || y->IsSimd128Value() || y->IsSymbol() || |
+ y->IsUndefined()) { |
+ return Just(false); |
+ } else if (y->IsBoolean()) { |
+ y = Oddball::ToNumber(Handle<Oddball>::cast(y)); |
+ } |
+ if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)).ToHandle(&x)) { |
+ return Nothing<bool>(); |
+ } |
+ } else { |
+ return Just( |
+ (x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) && |
+ (y->IsNull() || y->IsUndefined() || y->IsUndetectableObject())); |
+ } |
+ } |
+} |
+ |
+ |
bool Object::StrictEquals(Object* that) { |
if (this->IsNumber()) { |
if (!that->IsNumber()) return false; |
- double const x = this->Number(); |
- double const y = that->Number(); |
- // Must check explicitly for NaN:s on Windows, but -0 works fine. |
- return x == y && !std::isnan(x) && !std::isnan(y); |
+ return NumberEquals(this, that); |
} else if (this->IsString()) { |
if (!that->IsString()) return false; |
return String::cast(this)->Equals(String::cast(that)); |