From 593c655a3c814277283f9fa1520d5ce59d6b019c Mon Sep 17 00:00:00 2001 From: bmeurer Date: Thu, 17 Sep 2015 23:35:36 -0700 Subject: [PATCH] [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} --- src/arm/code-stubs-arm.cc | 7 +- src/arm64/code-stubs-arm64.cc | 7 +- src/contexts.h | 2 - src/full-codegen/full-codegen.cc | 13 ---- src/full-codegen/full-codegen.h | 1 - src/hydrogen.cc | 10 --- src/hydrogen.h | 1 - src/ia32/code-stubs-ia32.cc | 7 +- src/mips/code-stubs-mips.cc | 7 +- src/mips64/code-stubs-mips64.cc | 7 +- src/objects-inl.h | 72 +++++++++++++++++++ src/objects.cc | 115 +++++++++++++++++++++++++++++++ src/objects.h | 39 +++++++++++ src/runtime.js | 53 -------------- src/runtime/runtime-numbers.cc | 20 ------ src/runtime/runtime-object.cc | 52 ++++++++++++++ src/runtime/runtime-strings.cc | 72 ++++--------------- src/runtime/runtime.h | 3 +- src/x64/code-stubs-x64.cc | 10 +-- 19 files changed, 310 insertions(+), 188 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 825594200..7996779a1 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -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); diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index 61bca1a52..7173bdbf2 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -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); diff --git a/src/contexts.h b/src/contexts.h index 69f66960f..e5407f1f0 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -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, \ diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc index e88918557..ea53844fb 100644 --- a/src/full-codegen/full-codegen.cc +++ b/src/full-codegen/full-codegen.cc @@ -498,19 +498,6 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { } -void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { - ZoneList* 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); diff --git a/src/full-codegen/full-codegen.h b/src/full-codegen/full-codegen.h index dc11d157e..3cdb6d52e 100644 --- a/src/full-codegen/full-codegen.h +++ b/src/full-codegen/full-codegen.h @@ -522,7 +522,6 @@ class FullCodeGenerator: public AstVisitor { F(StringCharCodeAt) \ F(StringAdd) \ F(SubString) \ - F(StringCompare) \ F(RegExpExec) \ F(RegExpConstructResult) \ F(NumberToString) \ diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 52184b36e..135fafbc9 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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(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))); diff --git a/src/hydrogen.h b/src/hydrogen.h index f60f2cb72..272bc5a55 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2235,7 +2235,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { F(StringCharCodeAt) \ F(StringAdd) \ F(SubString) \ - F(StringCompare) \ F(RegExpExec) \ F(RegExpConstructResult) \ F(NumberToString) \ diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index b61e1ef57..e698c658f 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -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); diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 3fd484248..ae038075b 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -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); diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc index cb7e22018..98ca8521c 100644 --- a/src/mips64/code-stubs-mips64.cc +++ b/src/mips64/code-stubs-mips64.cc @@ -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); diff --git a/src/objects-inl.h b/src/objects-inl.h index 22736dc4b..1e0b6838a 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -7076,6 +7076,78 @@ String* String::GetForwardedInternalizedString() { } +// static +Maybe Object::GreaterThan(Handle x, Handle y, + Strength strength) { + Maybe 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(); +} + + +// static +Maybe Object::GreaterThanOrEqual(Handle x, Handle y, + Strength strength) { + Maybe 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(); +} + + +// static +Maybe Object::LessThan(Handle x, Handle y, + Strength strength) { + Maybe 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(); +} + + +// static +Maybe Object::LessThanOrEqual(Handle x, Handle y, + Strength strength) { + Maybe 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(); +} + + MaybeHandle Object::GetPropertyOrElement(Handle object, Handle name, LanguageMode language_mode) { diff --git a/src/objects.cc b/src/objects.cc index 4fa1b6849..7db54aa81 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -4,6 +4,7 @@ #include "src/objects.h" +#include #include #include @@ -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 x, Handle y) { } // namespace +// static +Maybe Object::Compare(Handle x, Handle 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(); + } + } + if (x->IsString() && y->IsString()) { + // ES6 section 7.2.11 Abstract Relational Comparison step 5. + return Just( + String::Compare(Handle::cast(x), Handle::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(); + } + } else { + if (!x->IsNumber()) { + Isolate* const isolate = Handle::cast(x)->GetIsolate(); + isolate->Throw(*isolate->factory()->NewTypeError( + MessageTemplate::kStrongImplicitConversion)); + return Nothing(); + } else if (!y->IsNumber()) { + Isolate* const isolate = Handle::cast(y)->GetIsolate(); + isolate->Throw(*isolate->factory()->NewTypeError( + MessageTemplate::kStrongImplicitConversion)); + return Nothing(); + } + } + return Just(NumberCompare(x->Number(), y->Number())); +} + + // static Maybe Object::Equals(Handle x, Handle y) { while (true) { @@ -9603,6 +9655,69 @@ bool String::SlowEquals(Handle one, Handle two) { } +// static +ComparisonResult String::Compare(Handle x, Handle 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 x_chars = x_content.ToOneByteVector(); + if (y_content.IsOneByte()) { + Vector y_chars = y_content.ToOneByteVector(); + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); + } else { + Vector y_chars = y_content.ToUC16Vector(); + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); + } + } else { + Vector x_chars = x_content.ToUC16Vector(); + if (y_content.IsOneByte()) { + Vector y_chars = y_content.ToOneByteVector(); + r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); + } else { + Vector 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 str, bool allow_prefix_match) { int slen = length(); // Can't check exact length equality, but we can check bounds. diff --git a/src/objects.h b/src/objects.h index 74ed13908..e28081c33 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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 Compare( + Handle x, Handle y, Strength strength = Strength::WEAK); + // ES6 section 7.2.12 Abstract Equality Comparison MUST_USE_RESULT static Maybe Equals(Handle x, Handle y); @@ -1148,6 +1163,16 @@ class Object { Isolate* isolate, Handle lhs, Handle rhs, Strength strength = Strength::WEAK); + // ES6 section 12.9 Relational Operators + MUST_USE_RESULT static inline Maybe GreaterThan( + Handle x, Handle y, Strength strength = Strength::WEAK); + MUST_USE_RESULT static inline Maybe GreaterThanOrEqual( + Handle x, Handle y, Strength strength = Strength::WEAK); + MUST_USE_RESULT static inline Maybe LessThan( + Handle x, Handle y, Strength strength = Strength::WEAK); + MUST_USE_RESULT static inline Maybe LessThanOrEqual( + Handle x, Handle y, Strength strength = Strength::WEAK); + // ES6 section 12.11 Binary Bitwise Operators MUST_USE_RESULT static MaybeHandle BitwiseAnd( Isolate* isolate, Handle lhs, Handle 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 x, + Handle y); + // String equality operations. inline bool Equals(String* other); inline static bool Equals(Handle one, Handle two); diff --git a/src/runtime.js b/src/runtime.js index a49a3bdfa..9ace6ff82 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -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, diff --git a/src/runtime/runtime-numbers.cc b/src/runtime/runtime-numbers.cc index bcdd89f14..e4eae3a04 100644 --- a/src/runtime/runtime-numbers.cc +++ b/src/runtime/runtime-numbers.cc @@ -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) { diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index a1d9dfa94..d2f1ee88e 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -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 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 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); diff --git a/src/runtime/runtime-strings.cc b/src/runtime/runtime-strings.cc index 0e6bf8308..b8ccbc8d9 100644 --- a/src/runtime/runtime-strings.cc +++ b/src/runtime/runtime-strings.cc @@ -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); - } - - 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 x_chars = x_content.ToOneByteVector(); - if (y_content.IsOneByte()) { - Vector y_chars = y_content.ToOneByteVector(); - r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); - } else { - Vector y_chars = y_content.ToUC16Vector(); - r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); - } - } else { - Vector x_chars = x_content.ToUC16Vector(); - if (y_content.IsOneByte()) { - Vector y_chars = y_content.ToOneByteVector(); - r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); - } else { - Vector 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); + 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; } - return result; + UNREACHABLE(); + return Smi::FromInt(0); } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 546c33e04..c1f72bb2b 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -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) \ diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 11f891cfe..dde834f8e 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -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); -- 2.34.1