Commit 521e8464 authored by Ujjwal Sharma's avatar Ujjwal Sharma Committed by Commit Bot

[intl] Port Collator.prototype.compare and bound compare function to C++

This increases the size of a Collator instance by a word to store
the bound compare function.

The instance to be bound is stored on the context of this builtin function.

Bug: v8:7800
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: Ie7581ab59fdfe4efff6d960e07ed2164fa6d9959
Reviewed-on: https://chromium-review.googlesource.com/1171967Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55130}
parent 7eded300
......@@ -2952,6 +2952,17 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
isolate_, prototype, factory->to_string_tag_symbol(),
factory->Object_string(),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
SimpleInstallGetter(isolate_, prototype,
factory->InternalizeUtf8String("compare"),
Builtins::kCollatorPrototypeCompare, false);
{
Handle<SharedFunctionInfo> info = SimpleCreateBuiltinSharedFunctionInfo(
isolate_, Builtins::kCollatorInternalCompare,
factory->empty_string(), 2);
native_context()->set_collator_internal_compare_shared_fun(*info);
}
}
{
......
......@@ -1381,7 +1381,11 @@ namespace internal {
/* ecma402 #sup-string.prototype.tolocalelowercase */ \
CPP(StringPrototypeToLocaleLowerCase) \
/* ecma402 #sup-string.prototype.tolocaleuppercase */ \
CPP(StringPrototypeToLocaleUpperCase)
CPP(StringPrototypeToLocaleUpperCase) \
/* ecma402 #sec-intl.collator.prototype.compare */ \
CPP(CollatorPrototypeCompare) \
/* ecma 402 #sec-collator-compare-functions*/ \
CPP(CollatorInternalCompare)
#else
#define BUILTIN_LIST(CPP, API, TFJ, TFC, TFS, TFH, ASM) \
BUILTIN_LIST_BASE(CPP, API, TFJ, TFC, TFS, TFH, ASM) \
......
......@@ -1121,5 +1121,75 @@ BUILTIN(CollatorConstructor) {
isolate, collator, locales, options));
}
BUILTIN(CollatorPrototypeCompare) {
const char* const method = "get Intl.Collator.prototype.compare";
HandleScope scope(isolate);
// 1. Let collator be this value.
// 2. If Type(collator) is not Object, throw a TypeError exception.
// 3. If collator does not have an [[InitializedCollator]] internal slot,
// throw a TypeError exception.
CHECK_RECEIVER(JSCollator, collator, method);
// 4. If collator.[[BoundCompare]] is undefined, then
Handle<Object> bound_compare(collator->bound_compare(), isolate);
if (!bound_compare->IsUndefined(isolate)) {
DCHECK(bound_compare->IsJSFunction());
// 5. Return collator.[[BoundCompare]].
return *bound_compare;
}
Handle<Context> native_context =
Handle<Context>(isolate->context()->native_context(), isolate);
Handle<Context> context = isolate->factory()->NewBuiltinContext(
native_context, JSCollator::ContextSlot::kLength);
// 4.b. Set F.[[Collator]] to collator.
context->set(JSCollator::ContextSlot::kCollator, *collator);
Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo>(
native_context->collator_internal_compare_shared_fun(), isolate);
Handle<Map> map = isolate->strict_function_without_prototype_map();
// 4.a. Let F be a new built-in function object as defined in 10.3.3.1.
Handle<JSFunction> new_bound_compare_function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
// 4.c. Set collator.[[BoundCompare]] to F.
collator->set_bound_compare(*new_bound_compare_function);
// 5. Return collator.[[BoundCompare]].
return *new_bound_compare_function;
}
BUILTIN(CollatorInternalCompare) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let collator be F.[[Collator]].
// 2. Assert: Type(collator) is Object and collator has an
// [[InitializedCollator]] internal slot.
Handle<JSCollator> collator_holder = Handle<JSCollator>(
JSCollator::cast(context->get(JSCollator::ContextSlot::kCollator)),
isolate);
// 3. If x is not provided, let x be undefined.
Handle<Object> x = args.atOrUndefined(isolate, 1);
// 4. If y is not provided, let y be undefined.
Handle<Object> y = args.atOrUndefined(isolate, 2);
// 5. Let X be ? ToString(x).
Handle<String> string_x;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string_x,
Object::ToString(isolate, x));
// 6. Let Y be ? ToString(y).
Handle<String> string_y;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string_y,
Object::ToString(isolate, y));
// 7. Return CompareStrings(collator, X, Y).
return *Intl::CompareStrings(isolate, collator_holder, string_x, string_y);
}
} // namespace internal
} // namespace v8
......@@ -209,6 +209,8 @@ enum ContextLookupFlags {
number_format_internal_format_number_shared_fun) \
V(INTL_LOCALE_FUNCTION_INDEX, JSFunction, intl_locale_function) \
V(INTL_COLLATOR_FUNCTION_INDEX, JSFunction, intl_collator_function) \
V(INTL_COLLATOR_INTERNAL_COMPARE_SHARED_FUN, SharedFunctionInfo, \
collator_internal_compare_shared_fun) \
V(INTL_PLURAL_RULES_FUNCTION_INDEX, JSFunction, intl_plural_rules_function) \
V(INTL_V8_BREAK_ITERATOR_FUNCTION_INDEX, JSFunction, \
intl_v8_break_iterator_function) \
......
......@@ -756,23 +756,6 @@ DEFINE_METHOD(
);
/**
* When the compare method is called with two arguments x and y, it returns a
* Number other than NaN that represents the result of a locale-sensitive
* String comparison of x with y.
* The result is intended to order String values in the sort order specified
* by the effective locale and collation options computed during construction
* of this Collator object, and will be negative, zero, or positive, depending
* on whether x comes before y in the sort order, the Strings are equal under
* the sort order, or x comes after y in the sort order, respectively.
*/
function compare(collator, x, y) {
return %InternalCompare(collator, TO_STRING(x), TO_STRING(y));
};
AddBoundMethod(GlobalIntlCollator, 'compare', compare, 2, COLLATOR_TYPE, false);
DEFINE_METHOD(
GlobalIntlPluralRules.prototype,
resolvedOptions() {
......
......@@ -1876,6 +1876,7 @@ void JSCollator::JSCollatorVerify(Isolate* isolate) {
JSObjectVerify(isolate);
VerifyObjectField(isolate, kICUCollatorOffset);
VerifyObjectField(isolate, kFlagsOffset);
VerifyObjectField(isolate, kBoundCompareOffset);
}
void JSListFormat::JSListFormatVerify(Isolate* isolate) {
......
......@@ -1950,6 +1950,7 @@ void JSCollator::JSCollatorPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSCollator");
os << "\n - usage: " << JSCollator::UsageToString(usage());
os << "\n - icu collator: " << Brief(icu_collator());
os << "\n - bound compare: " << Brief(bound_compare());
os << "\n";
}
......
......@@ -1789,14 +1789,15 @@ MaybeHandle<Object> Intl::StringLocaleCompare(Isolate* isolate,
locales, options),
Object);
CHECK(collator->IsJSCollator());
return Intl::InternalCompare(isolate, Handle<JSCollator>::cast(collator),
string1, string2);
return Intl::CompareStrings(isolate, Handle<JSCollator>::cast(collator),
string1, string2);
}
Handle<Object> Intl::InternalCompare(Isolate* isolate,
Handle<JSCollator> collator,
Handle<String> string1,
Handle<String> string2) {
// ecma402/#sec-collator-comparestrings
Handle<Object> Intl::CompareStrings(Isolate* isolate,
Handle<JSCollator> collator,
Handle<String> string1,
Handle<String> string2) {
Factory* factory = isolate->factory();
icu::Collator* icu_collator = collator->icu_collator()->raw();
CHECK_NOT_NULL(icu_collator);
......
......@@ -298,7 +298,7 @@ class Intl {
Isolate* isolate, Handle<String> s1, Handle<String> s2,
Handle<Object> locales, Handle<Object> options);
V8_WARN_UNUSED_RESULT static Handle<Object> InternalCompare(
V8_WARN_UNUSED_RESULT static Handle<Object> CompareStrings(
Isolate* isolate, Handle<JSCollator> collator, Handle<String> s1,
Handle<String> s2);
......
......@@ -19,6 +19,7 @@ namespace v8 {
namespace internal {
ACCESSORS(JSCollator, icu_collator, Managed<icu::Collator>, kICUCollatorOffset)
ACCESSORS(JSCollator, bound_compare, Object, kBoundCompareOffset);
SMI_ACCESSORS(JSCollator, flags, kFlagsOffset)
inline void JSCollator::set_usage(Usage usage) {
......
......@@ -49,15 +49,24 @@ class JSCollator : public JSObject {
static const char* UsageToString(Usage usage);
// Layout description.
#define JS_COLLATOR_FIELDS(V) \
V(kICUCollatorOffset, kPointerSize) \
V(kFlagsOffset, kPointerSize) \
/* Total size. */ \
#define JS_COLLATOR_FIELDS(V) \
V(kICUCollatorOffset, kPointerSize) \
V(kFlagsOffset, kPointerSize) \
V(kBoundCompareOffset, kPointerSize) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_COLLATOR_FIELDS)
#undef JS_COLLATOR_FIELDS
// ContextSlot defines the context structure for the bound
// Collator.prototype.compare function.
enum ContextSlot {
// The collator instance that the function holding this context is bound to.
kCollator = Context::MIN_CONTEXT_SLOTS,
kLength
};
// Bit positions in |flags|.
#define FLAGS_BIT_FIELDS(V, _) V(UsageBits, Usage, 1, _)
......@@ -68,6 +77,7 @@ class JSCollator : public JSObject {
STATIC_ASSERT(Usage::SEARCH <= UsageBits::kMax);
DECL_ACCESSORS(icu_collator, Managed<icu::Collator>)
DECL_ACCESSORS(bound_compare, Object);
DECL_INT_ACCESSORS(flags)
private:
......
......@@ -274,18 +274,6 @@ RUNTIME_FUNCTION(Runtime_CurrencyDigits) {
return *Intl::CurrencyDigits(isolate, currency);
}
RUNTIME_FUNCTION(Runtime_InternalCompare) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSCollator, collator, 0);
CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
return *Intl::InternalCompare(isolate, collator, string1, string2);
}
RUNTIME_FUNCTION(Runtime_CollatorResolvedOptions) {
HandleScope scope(isolate);
......
......@@ -221,7 +221,6 @@ namespace internal {
F(FormatListToParts, 2, 1) \
F(GetDefaultICULocale, 0, 1) \
F(GetNumberOption, 5, 1) \
F(InternalCompare, 3, 1) \
F(InternalDateFormat, 2, 1) \
F(IntlUnwrapReceiver, 5, 1) \
F(IsInitializedIntlObjectOfType, 2, 1) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment