[runtime] Replace COMPARE/COMPARE_STRONG with proper Object::Compare.
This removes the weird COMPARE and COMPARE_STRONG JavaScript builtins and replaces them with a proper C++ implementation in Object::Compare and appropriate wrappers Object::LessThan, Object::GreaterThan, and friends that are intended to be used by a true/false returning CompareIC in the future, as well as the interpreter. As a short-term solution we provide %Compare and %Compare_Strong entry points for the current CompareIC that return the appropriate integer values expected by fullcodegen currently. Now the Abstract Relational Comparison is also using the correct ToPrimitive implementation, which properly supports @@toPrimitive. BUG=v8:4307 LOG=n Review URL: https://codereview.chromium.org/1350113002 Cr-Commit-Position: refs/heads/master@{#30816}
This commit is contained in:
parent
dc39f3089e
commit
593c655a3c
@ -685,9 +685,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals, 2,
|
||||
1);
|
||||
} else {
|
||||
int context_index = is_strong(strength())
|
||||
? Context::COMPARE_STRONG_BUILTIN_INDEX
|
||||
: Context::COMPARE_BUILTIN_INDEX;
|
||||
int ncr; // NaN compare result
|
||||
if (cc == lt || cc == le) {
|
||||
ncr = GREATER;
|
||||
@ -700,7 +697,9 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
|
||||
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
|
||||
// tagged as a small integer.
|
||||
__ InvokeBuiltin(context_index, JUMP_FUNCTION);
|
||||
__ TailCallRuntime(
|
||||
is_strong(strength()) ? Runtime::kCompare_Strong : Runtime::kCompare, 3,
|
||||
1);
|
||||
}
|
||||
|
||||
__ bind(&miss);
|
||||
|
@ -656,9 +656,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals, 2,
|
||||
1);
|
||||
} else {
|
||||
int context_index = is_strong(strength())
|
||||
? Context::COMPARE_STRONG_BUILTIN_INDEX
|
||||
: Context::COMPARE_BUILTIN_INDEX;
|
||||
int ncr; // NaN compare result
|
||||
if ((cond == lt) || (cond == le)) {
|
||||
ncr = GREATER;
|
||||
@ -671,7 +668,9 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
|
||||
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
|
||||
// tagged as a small integer.
|
||||
__ InvokeBuiltin(context_index, JUMP_FUNCTION);
|
||||
__ TailCallRuntime(
|
||||
is_strong(strength()) ? Runtime::kCompare_Strong : Runtime::kCompare, 3,
|
||||
1);
|
||||
}
|
||||
|
||||
__ Bind(&miss);
|
||||
|
@ -92,8 +92,6 @@ enum BindingFlags {
|
||||
|
||||
#define NATIVE_CONTEXT_JS_BUILTINS(V) \
|
||||
V(APPLY_PREPARE_BUILTIN_INDEX, JSFunction, apply_prepare_builtin) \
|
||||
V(COMPARE_BUILTIN_INDEX, JSFunction, compare_builtin) \
|
||||
V(COMPARE_STRONG_BUILTIN_INDEX, JSFunction, compare_strong_builtin) \
|
||||
V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction, \
|
||||
concat_iterable_to_array_builtin) \
|
||||
V(REFLECT_APPLY_PREPARE_BUILTIN_INDEX, JSFunction, \
|
||||
|
@ -498,19 +498,6 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
StringCompareStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(result_register());
|
||||
}
|
||||
|
||||
|
||||
bool RecordStatementPosition(MacroAssembler* masm, int pos) {
|
||||
if (pos == RelocInfo::kNoPosition) return false;
|
||||
masm->positions_recorder()->RecordStatementPosition(pos);
|
||||
|
@ -522,7 +522,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(StringCharCodeAt) \
|
||||
F(StringAdd) \
|
||||
F(SubString) \
|
||||
F(StringCompare) \
|
||||
F(RegExpExec) \
|
||||
F(RegExpConstructResult) \
|
||||
F(NumberToString) \
|
||||
|
@ -12478,16 +12478,6 @@ void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
|
||||
}
|
||||
|
||||
|
||||
// Fast support for StringCompare.
|
||||
void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
|
||||
DCHECK_EQ(2, call->arguments()->length());
|
||||
CHECK_ALIVE(VisitExpressions(call->arguments()));
|
||||
PushArgumentsFromEnvironment(call->arguments()->length());
|
||||
HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2);
|
||||
return ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateStringGetLength(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
|
@ -2235,7 +2235,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
F(StringCharCodeAt) \
|
||||
F(StringAdd) \
|
||||
F(SubString) \
|
||||
F(StringCompare) \
|
||||
F(RegExpExec) \
|
||||
F(RegExpConstructResult) \
|
||||
F(NumberToString) \
|
||||
|
@ -1872,9 +1872,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals, 2,
|
||||
1);
|
||||
} else {
|
||||
int native_context_index = is_strong(strength())
|
||||
? Context::COMPARE_STRONG_BUILTIN_INDEX
|
||||
: Context::COMPARE_BUILTIN_INDEX;
|
||||
__ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
||||
|
||||
// Restore return address on the stack.
|
||||
@ -1882,7 +1879,9 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
|
||||
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
|
||||
// tagged as a small integer.
|
||||
__ InvokeBuiltin(native_context_index, JUMP_FUNCTION);
|
||||
__ TailCallRuntime(
|
||||
is_strong(strength()) ? Runtime::kCompare_Strong : Runtime::kCompare, 3,
|
||||
1);
|
||||
}
|
||||
|
||||
__ bind(&miss);
|
||||
|
@ -731,9 +731,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals, 2,
|
||||
1);
|
||||
} else {
|
||||
int context_index = is_strong(strength())
|
||||
? Context::COMPARE_STRONG_BUILTIN_INDEX
|
||||
: Context::COMPARE_BUILTIN_INDEX;
|
||||
int ncr; // NaN compare result.
|
||||
if (cc == lt || cc == le) {
|
||||
ncr = GREATER;
|
||||
@ -746,7 +743,9 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
|
||||
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
|
||||
// tagged as a small integer.
|
||||
__ InvokeBuiltin(context_index, JUMP_FUNCTION);
|
||||
__ TailCallRuntime(
|
||||
is_strong(strength()) ? Runtime::kCompare_Strong : Runtime::kCompare, 3,
|
||||
1);
|
||||
}
|
||||
|
||||
__ bind(&miss);
|
||||
|
@ -726,9 +726,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals, 2,
|
||||
1);
|
||||
} else {
|
||||
int context_index = is_strong(strength())
|
||||
? Context::COMPARE_STRONG_BUILTIN_INDEX
|
||||
: Context::COMPARE_BUILTIN_INDEX;
|
||||
int ncr; // NaN compare result.
|
||||
if (cc == lt || cc == le) {
|
||||
ncr = GREATER;
|
||||
@ -741,7 +738,9 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
|
||||
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
|
||||
// tagged as a small integer.
|
||||
__ InvokeBuiltin(context_index, JUMP_FUNCTION);
|
||||
__ TailCallRuntime(
|
||||
is_strong(strength()) ? Runtime::kCompare_Strong : Runtime::kCompare, 3,
|
||||
1);
|
||||
}
|
||||
|
||||
__ bind(&miss);
|
||||
|
@ -7076,6 +7076,78 @@ String* String::GetForwardedInternalizedString() {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Maybe<bool> Object::GreaterThan(Handle<Object> x, Handle<Object> y,
|
||||
Strength strength) {
|
||||
Maybe<ComparisonResult> result = Compare(x, y, strength);
|
||||
if (result.IsJust()) {
|
||||
switch (result.FromJust()) {
|
||||
case ComparisonResult::kGreaterThan:
|
||||
return Just(true);
|
||||
case ComparisonResult::kLessThan:
|
||||
case ComparisonResult::kEqual:
|
||||
case ComparisonResult::kUndefined:
|
||||
return Just(false);
|
||||
}
|
||||
}
|
||||
return Nothing<bool>();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Maybe<bool> Object::GreaterThanOrEqual(Handle<Object> x, Handle<Object> y,
|
||||
Strength strength) {
|
||||
Maybe<ComparisonResult> result = Compare(x, y, strength);
|
||||
if (result.IsJust()) {
|
||||
switch (result.FromJust()) {
|
||||
case ComparisonResult::kEqual:
|
||||
case ComparisonResult::kGreaterThan:
|
||||
return Just(true);
|
||||
case ComparisonResult::kLessThan:
|
||||
case ComparisonResult::kUndefined:
|
||||
return Just(false);
|
||||
}
|
||||
}
|
||||
return Nothing<bool>();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Maybe<bool> Object::LessThan(Handle<Object> x, Handle<Object> y,
|
||||
Strength strength) {
|
||||
Maybe<ComparisonResult> result = Compare(x, y, strength);
|
||||
if (result.IsJust()) {
|
||||
switch (result.FromJust()) {
|
||||
case ComparisonResult::kLessThan:
|
||||
return Just(true);
|
||||
case ComparisonResult::kEqual:
|
||||
case ComparisonResult::kGreaterThan:
|
||||
case ComparisonResult::kUndefined:
|
||||
return Just(false);
|
||||
}
|
||||
}
|
||||
return Nothing<bool>();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Maybe<bool> Object::LessThanOrEqual(Handle<Object> x, Handle<Object> y,
|
||||
Strength strength) {
|
||||
Maybe<ComparisonResult> result = Compare(x, y, strength);
|
||||
if (result.IsJust()) {
|
||||
switch (result.FromJust()) {
|
||||
case ComparisonResult::kEqual:
|
||||
case ComparisonResult::kLessThan:
|
||||
return Just(true);
|
||||
case ComparisonResult::kGreaterThan:
|
||||
case ComparisonResult::kUndefined:
|
||||
return Just(false);
|
||||
}
|
||||
}
|
||||
return Nothing<bool>();
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> Object::GetPropertyOrElement(Handle<Object> object,
|
||||
Handle<Name> name,
|
||||
LanguageMode language_mode) {
|
||||
|
115
src/objects.cc
115
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;
|
||||
@ -183,6 +197,44 @@ bool NumberEquals(Handle<Object> x, Handle<Object> y) {
|
||||
} // namespace
|
||||
|
||||
|
||||
// static
|
||||
Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y,
|
||||
Strength strength) {
|
||||
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();
|
||||
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) {
|
||||
@ -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.
|
||||
|
@ -800,6 +800,7 @@ enum FixedArraySubInstanceType {
|
||||
};
|
||||
|
||||
|
||||
// TODO(bmeurer): Remove this in favor of the ComparisonResult below.
|
||||
enum CompareResult {
|
||||
LESS = -1,
|
||||
EQUAL = 0,
|
||||
@ -809,6 +810,16 @@ enum CompareResult {
|
||||
};
|
||||
|
||||
|
||||
// Result of an abstract relational comparison of x and y, implemented according
|
||||
// to ES6 section 7.2.11 Abstract Relational Comparison.
|
||||
enum class ComparisonResult {
|
||||
kLessThan, // x < y
|
||||
kEqual, // x = y
|
||||
kGreaterThan, // x > x
|
||||
kUndefined // at least one of x or y was undefined or NaN
|
||||
};
|
||||
|
||||
|
||||
#define DECL_BOOLEAN_ACCESSORS(name) \
|
||||
inline bool name() const; \
|
||||
inline void set_##name(bool value); \
|
||||
@ -1083,6 +1094,10 @@ class Object {
|
||||
|
||||
bool BooleanValue(); // ECMA-262 9.2.
|
||||
|
||||
// ES6 section 7.2.11 Abstract Relational Comparison
|
||||
MUST_USE_RESULT static Maybe<ComparisonResult> Compare(
|
||||
Handle<Object> x, Handle<Object> y, Strength strength = Strength::WEAK);
|
||||
|
||||
// ES6 section 7.2.12 Abstract Equality Comparison
|
||||
MUST_USE_RESULT static Maybe<bool> Equals(Handle<Object> x, Handle<Object> y);
|
||||
|
||||
@ -1148,6 +1163,16 @@ class Object {
|
||||
Isolate* isolate, Handle<Object> lhs, Handle<Object> rhs,
|
||||
Strength strength = Strength::WEAK);
|
||||
|
||||
// ES6 section 12.9 Relational Operators
|
||||
MUST_USE_RESULT static inline Maybe<bool> GreaterThan(
|
||||
Handle<Object> x, Handle<Object> y, Strength strength = Strength::WEAK);
|
||||
MUST_USE_RESULT static inline Maybe<bool> GreaterThanOrEqual(
|
||||
Handle<Object> x, Handle<Object> y, Strength strength = Strength::WEAK);
|
||||
MUST_USE_RESULT static inline Maybe<bool> LessThan(
|
||||
Handle<Object> x, Handle<Object> y, Strength strength = Strength::WEAK);
|
||||
MUST_USE_RESULT static inline Maybe<bool> LessThanOrEqual(
|
||||
Handle<Object> x, Handle<Object> y, Strength strength = Strength::WEAK);
|
||||
|
||||
// ES6 section 12.11 Binary Bitwise Operators
|
||||
MUST_USE_RESULT static MaybeHandle<Object> BitwiseAnd(
|
||||
Isolate* isolate, Handle<Object> lhs, Handle<Object> rhs,
|
||||
@ -8489,6 +8514,20 @@ class String: public Name {
|
||||
// Requires: StringShape(this).IsIndirect() && this->IsFlat()
|
||||
inline String* GetUnderlying();
|
||||
|
||||
// String relational comparison, implemented according to ES6 section 7.2.11
|
||||
// Abstract Relational Comparison (step 5): The comparison of Strings uses a
|
||||
// simple lexicographic ordering on sequences of code unit values. There is no
|
||||
// attempt to use the more complex, semantically oriented definitions of
|
||||
// character or string equality and collating order defined in the Unicode
|
||||
// specification. Therefore String values that are canonically equal according
|
||||
// to the Unicode standard could test as unequal. In effect this algorithm
|
||||
// assumes that both Strings are already in normalized form. Also, note that
|
||||
// for strings containing supplementary characters, lexicographic ordering on
|
||||
// sequences of UTF-16 code unit values differs from that on sequences of code
|
||||
// point values.
|
||||
MUST_USE_RESULT static ComparisonResult Compare(Handle<String> x,
|
||||
Handle<String> y);
|
||||
|
||||
// String equality operations.
|
||||
inline bool Equals(String* other);
|
||||
inline static bool Equals(Handle<String> one, Handle<String> two);
|
||||
|
@ -38,57 +38,6 @@ var isConcatSpreadableSymbol =
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* -----------------------------------
|
||||
- - - C o m p a r i s o n - - -
|
||||
-----------------------------------
|
||||
*/
|
||||
|
||||
// ECMA-262, section 11.8.5, page 53. The 'ncr' parameter is used as
|
||||
// the result when either (or both) the operands are NaN.
|
||||
function COMPARE(x, ncr) {
|
||||
var left;
|
||||
var right;
|
||||
// Fast cases for string, numbers and undefined compares.
|
||||
if (IS_STRING(this)) {
|
||||
if (IS_STRING(x)) return %_StringCompare(this, x);
|
||||
if (IS_UNDEFINED(x)) return ncr;
|
||||
left = this;
|
||||
} else if (IS_NUMBER(this)) {
|
||||
if (IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
|
||||
if (IS_UNDEFINED(x)) return ncr;
|
||||
left = this;
|
||||
} else if (IS_UNDEFINED(this)) {
|
||||
if (!IS_UNDEFINED(x)) {
|
||||
%to_primitive(x, NUMBER_HINT);
|
||||
}
|
||||
return ncr;
|
||||
} else if (IS_UNDEFINED(x)) {
|
||||
%to_primitive(this, NUMBER_HINT);
|
||||
return ncr;
|
||||
} else {
|
||||
left = %to_primitive(this, NUMBER_HINT);
|
||||
}
|
||||
|
||||
right = %to_primitive(x, NUMBER_HINT);
|
||||
if (IS_STRING(left) && IS_STRING(right)) {
|
||||
return %_StringCompare(left, right);
|
||||
} else {
|
||||
var left_number = %to_number_fun(left);
|
||||
var right_number = %to_number_fun(right);
|
||||
if (NUMBER_IS_NAN(left_number) || NUMBER_IS_NAN(right_number)) return ncr;
|
||||
return %NumberCompare(left_number, right_number, ncr);
|
||||
}
|
||||
}
|
||||
|
||||
// Strong mode COMPARE throws if an implicit conversion would be performed
|
||||
function COMPARE_STRONG(x, ncr) {
|
||||
if (IS_STRING(this) && IS_STRING(x)) return %_StringCompare(this, x);
|
||||
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
|
||||
|
||||
throw %make_type_error(kStrongImplicitConversion);
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------
|
||||
- - - H e l p e r s - - -
|
||||
-----------------------------
|
||||
@ -433,8 +382,6 @@ $toString = ToString;
|
||||
|
||||
%InstallToContext([
|
||||
"apply_prepare_builtin", APPLY_PREPARE,
|
||||
"compare_builtin", COMPARE,
|
||||
"compare_strong_builtin", COMPARE_STRONG,
|
||||
"concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
|
||||
"reflect_apply_prepare_builtin", REFLECT_APPLY_PREPARE,
|
||||
"reflect_construct_prepare_builtin", REFLECT_CONSTRUCT_PREPARE,
|
||||
|
@ -9,12 +9,6 @@
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
|
||||
|
||||
#ifndef _STLP_VENDOR_CSTD
|
||||
// STLPort doesn't import isless into the std namespace.
|
||||
using std::isless;
|
||||
#endif
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
@ -232,20 +226,6 @@ RUNTIME_FUNCTION(Runtime_NumberImul) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_NumberCompare) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
|
||||
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
|
||||
CONVERT_DOUBLE_ARG_CHECKED(y, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
|
||||
if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
|
||||
if (x == y) return Smi::FromInt(EQUAL);
|
||||
if (isless(x, y)) return Smi::FromInt(LESS);
|
||||
return Smi::FromInt(GREATER);
|
||||
}
|
||||
|
||||
|
||||
// Compare two Smis as if they were converted to strings and then
|
||||
// compared lexicographically.
|
||||
RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
|
||||
|
@ -1491,6 +1491,58 @@ RUNTIME_FUNCTION(Runtime_StrictEquals) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan,
|
||||
// GreaterThan, etc. which return true or false.
|
||||
RUNTIME_FUNCTION(Runtime_Compare) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, ncr, 2);
|
||||
Maybe<ComparisonResult> result = Object::Compare(x, y);
|
||||
if (result.IsJust()) {
|
||||
switch (result.FromJust()) {
|
||||
case ComparisonResult::kLessThan:
|
||||
return Smi::FromInt(LESS);
|
||||
case ComparisonResult::kEqual:
|
||||
return Smi::FromInt(EQUAL);
|
||||
case ComparisonResult::kGreaterThan:
|
||||
return Smi::FromInt(GREATER);
|
||||
case ComparisonResult::kUndefined:
|
||||
return *ncr;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
return isolate->heap()->exception();
|
||||
}
|
||||
|
||||
|
||||
// TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan,
|
||||
// GreaterThan, etc. which return true or false.
|
||||
RUNTIME_FUNCTION(Runtime_Compare_Strong) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, ncr, 2);
|
||||
Maybe<ComparisonResult> result = Object::Compare(x, y, Strength::STRONG);
|
||||
if (result.IsJust()) {
|
||||
switch (result.FromJust()) {
|
||||
case ComparisonResult::kLessThan:
|
||||
return Smi::FromInt(LESS);
|
||||
case ComparisonResult::kEqual:
|
||||
return Smi::FromInt(EQUAL);
|
||||
case ComparisonResult::kGreaterThan:
|
||||
return Smi::FromInt(GREATER);
|
||||
case ComparisonResult::kUndefined:
|
||||
return *ncr;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
return isolate->heap()->exception();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_InstanceOf) {
|
||||
// ECMA-262, section 11.8.6, page 54.
|
||||
HandleScope shs(isolate);
|
||||
|
@ -419,70 +419,22 @@ RUNTIME_FUNCTION(Runtime_CharFromCode) {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_StringCompare) {
|
||||
HandleScope handle_scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
|
||||
DCHECK_EQ(2, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
|
||||
|
||||
isolate->counters()->string_compare_runtime()->Increment();
|
||||
|
||||
// A few fast case tests before we flatten.
|
||||
if (x.is_identical_to(y)) return Smi::FromInt(EQUAL);
|
||||
if (y->length() == 0) {
|
||||
if (x->length() == 0) return Smi::FromInt(EQUAL);
|
||||
return Smi::FromInt(GREATER);
|
||||
} else if (x->length() == 0) {
|
||||
return Smi::FromInt(LESS);
|
||||
switch (String::Compare(x, y)) {
|
||||
case ComparisonResult::kLessThan:
|
||||
return Smi::FromInt(LESS);
|
||||
case ComparisonResult::kEqual:
|
||||
return Smi::FromInt(EQUAL);
|
||||
case ComparisonResult::kGreaterThan:
|
||||
return Smi::FromInt(GREATER);
|
||||
case ComparisonResult::kUndefined:
|
||||
break;
|
||||
}
|
||||
|
||||
int d = x->Get(0) - y->Get(0);
|
||||
if (d < 0)
|
||||
return Smi::FromInt(LESS);
|
||||
else if (d > 0)
|
||||
return Smi::FromInt(GREATER);
|
||||
|
||||
// Slow case.
|
||||
x = String::Flatten(x);
|
||||
y = String::Flatten(y);
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
Object* equal_prefix_result = Smi::FromInt(EQUAL);
|
||||
int prefix_length = x->length();
|
||||
if (y->length() < prefix_length) {
|
||||
prefix_length = y->length();
|
||||
equal_prefix_result = Smi::FromInt(GREATER);
|
||||
} else if (y->length() > prefix_length) {
|
||||
equal_prefix_result = Smi::FromInt(LESS);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
Object* result;
|
||||
if (r == 0) {
|
||||
result = equal_prefix_result;
|
||||
} else {
|
||||
result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
|
||||
}
|
||||
return result;
|
||||
UNREACHABLE();
|
||||
return Smi::FromInt(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,7 +407,6 @@ namespace internal {
|
||||
F(NumberToIntegerMapMinusZero, 1, 1) \
|
||||
F(NumberToSmi, 1, 1) \
|
||||
F(NumberImul, 2, 1) \
|
||||
F(NumberCompare, 3, 1) \
|
||||
F(SmiLexicographicCompare, 2, 1) \
|
||||
F(MaxSmi, 0, 1) \
|
||||
F(IsSmi, 1, 1) \
|
||||
@ -480,6 +479,8 @@ namespace internal {
|
||||
F(ToName, 1, 1) \
|
||||
F(Equals, 2, 1) \
|
||||
F(StrictEquals, 2, 1) \
|
||||
F(Compare, 3, 1) \
|
||||
F(Compare_Strong, 3, 1) \
|
||||
F(InstanceOf, 2, 1) \
|
||||
F(HasInPrototypeChain, 2, 1) \
|
||||
F(CreateIterResultObject, 2, 1) \
|
||||
|
@ -1739,15 +1739,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals, 2,
|
||||
1);
|
||||
} else {
|
||||
int context_index = is_strong(strength())
|
||||
? Context::COMPARE_STRONG_BUILTIN_INDEX
|
||||
: Context::COMPARE_BUILTIN_INDEX;
|
||||
__ Push(Smi::FromInt(NegativeComparisonResult(cc)));
|
||||
__ PushReturnAddressFrom(rcx);
|
||||
|
||||
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
|
||||
// tagged as a small integer.
|
||||
__ InvokeBuiltin(context_index, JUMP_FUNCTION);
|
||||
__ TailCallRuntime(
|
||||
is_strong(strength()) ? Runtime::kCompare_Strong : Runtime::kCompare, 3,
|
||||
1);
|
||||
}
|
||||
|
||||
__ bind(&miss);
|
||||
|
Loading…
Reference in New Issue
Block a user