[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:
bmeurer 2015-09-17 23:35:36 -07:00 committed by Commit bot
parent dc39f3089e
commit 593c655a3c
19 changed files with 310 additions and 188 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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, \

View File

@ -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);

View File

@ -522,7 +522,6 @@ class FullCodeGenerator: public AstVisitor {
F(StringCharCodeAt) \
F(StringAdd) \
F(SubString) \
F(StringCompare) \
F(RegExpExec) \
F(RegExpConstructResult) \
F(NumberToString) \

View File

@ -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)));

View File

@ -2235,7 +2235,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
F(StringCharCodeAt) \
F(StringAdd) \
F(SubString) \
F(StringCompare) \
F(RegExpExec) \
F(RegExpConstructResult) \
F(NumberToString) \

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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,

View File

@ -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) {

View File

@ -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);

View File

@ -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);
}

View File

@ -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) \

View File

@ -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);