Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 4fa1b68496fd7e1ab6563064d218edb45ec12c60..7db54aa811e7ce2ed260f4ec729675231fd830bd 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -4,6 +4,7 @@ |
| #include "src/objects.h" |
| +#include <cmath> |
| #include <iomanip> |
| #include <sstream> |
| @@ -163,6 +164,19 @@ namespace { |
| // TODO(bmeurer): Maybe we should introduce a marker interface Number, |
| // where we put all these methods at some point? |
| +ComparisonResult NumberCompare(double x, double y) { |
| + if (std::isnan(x) || std::isnan(y)) { |
| + return ComparisonResult::kUndefined; |
| + } else if (x < y) { |
| + return ComparisonResult::kLessThan; |
| + } else if (x > y) { |
| + return ComparisonResult::kGreaterThan; |
| + } else { |
| + return ComparisonResult::kEqual; |
| + } |
| +} |
| + |
| + |
| bool NumberEquals(double x, double y) { |
| // Must check explicitly for NaN's on Windows, but -0 works fine. |
| if (std::isnan(x)) return false; |
| @@ -184,6 +198,44 @@ bool NumberEquals(Handle<Object> x, Handle<Object> y) { |
| // static |
| +Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y, |
| + Strength strength) { |
|
conradw
2015/09/18 08:59:22
We've been trying to use the Strength enum only fo
Benedikt Meurer
2015/09/18 09:52:03
Hm, that was totally non obvious from the comment
|
| + if (!is_strong(strength)) { |
| + // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. |
| + if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) || |
| + !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) { |
| + return Nothing<ComparisonResult>(); |
| + } |
| + } |
| + if (x->IsString() && y->IsString()) { |
| + // ES6 section 7.2.11 Abstract Relational Comparison step 5. |
| + return Just( |
| + String::Compare(Handle<String>::cast(x), Handle<String>::cast(y))); |
| + } |
| + // ES6 section 7.2.11 Abstract Relational Comparison step 6. |
| + if (!is_strong(strength)) { |
| + if (!Object::ToNumber(x).ToHandle(&x) || |
| + !Object::ToNumber(y).ToHandle(&y)) { |
| + return Nothing<ComparisonResult>(); |
| + } |
| + } else { |
| + if (!x->IsNumber()) { |
| + Isolate* const isolate = Handle<HeapObject>::cast(x)->GetIsolate(); |
|
conradw
2015/09/18 08:59:22
Can the isolates ever be different here?
Benedikt Meurer
2015/09/18 09:52:03
No, but either x or y can be a Smi and therefore t
|
| + isolate->Throw(*isolate->factory()->NewTypeError( |
| + MessageTemplate::kStrongImplicitConversion)); |
| + return Nothing<ComparisonResult>(); |
| + } else if (!y->IsNumber()) { |
| + Isolate* const isolate = Handle<HeapObject>::cast(y)->GetIsolate(); |
| + isolate->Throw(*isolate->factory()->NewTypeError( |
| + MessageTemplate::kStrongImplicitConversion)); |
| + return Nothing<ComparisonResult>(); |
| + } |
| + } |
| + return Just(NumberCompare(x->Number(), y->Number())); |
| +} |
| + |
| + |
| +// static |
| Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) { |
| while (true) { |
| if (x->IsNumber()) { |
| @@ -9603,6 +9655,69 @@ bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
| } |
| +// static |
| +ComparisonResult String::Compare(Handle<String> x, Handle<String> y) { |
| + // A few fast case tests before we flatten. |
| + if (x.is_identical_to(y)) { |
| + return ComparisonResult::kEqual; |
| + } else if (y->length() == 0) { |
| + return x->length() == 0 ? ComparisonResult::kEqual |
| + : ComparisonResult::kGreaterThan; |
| + } else if (x->length() == 0) { |
| + return ComparisonResult::kLessThan; |
| + } |
| + |
| + int const d = x->Get(0) - y->Get(0); |
| + if (d < 0) { |
| + return ComparisonResult::kLessThan; |
| + } else if (d > 0) { |
| + return ComparisonResult::kGreaterThan; |
| + } |
| + |
| + // Slow case. |
| + x = String::Flatten(x); |
| + y = String::Flatten(y); |
| + |
| + DisallowHeapAllocation no_gc; |
| + ComparisonResult result = ComparisonResult::kEqual; |
| + int prefix_length = x->length(); |
| + if (y->length() < prefix_length) { |
| + prefix_length = y->length(); |
| + result = ComparisonResult::kGreaterThan; |
| + } else if (y->length() > prefix_length) { |
| + result = ComparisonResult::kLessThan; |
| + } |
| + int r; |
| + String::FlatContent x_content = x->GetFlatContent(); |
| + String::FlatContent y_content = y->GetFlatContent(); |
| + if (x_content.IsOneByte()) { |
| + Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); |
| + if (y_content.IsOneByte()) { |
| + Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); |
| + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| + } else { |
| + Vector<const uc16> y_chars = y_content.ToUC16Vector(); |
| + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| + } |
| + } else { |
| + Vector<const uc16> x_chars = x_content.ToUC16Vector(); |
| + if (y_content.IsOneByte()) { |
| + Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); |
| + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| + } else { |
| + Vector<const uc16> y_chars = y_content.ToUC16Vector(); |
| + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| + } |
| + } |
| + if (r < 0) { |
| + result = ComparisonResult::kLessThan; |
| + } else if (r > 0) { |
| + result = ComparisonResult::kGreaterThan; |
| + } |
| + return result; |
| +} |
| + |
| + |
| bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) { |
| int slen = length(); |
| // Can't check exact length equality, but we can check bounds. |