|  | // Copyright 2017 the V8 project authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef V8_INTL_SUPPORT | 
|  | #error Internationalization is expected to be enabled. | 
|  | #endif  // V8_INTL_SUPPORT | 
|  |  | 
|  | #include <cmath> | 
|  | #include <list> | 
|  | #include <memory> | 
|  |  | 
|  | #include "src/builtins/builtins-utils-inl.h" | 
|  | #include "src/builtins/builtins.h" | 
|  | #include "src/date/date.h" | 
|  | #include "src/logging/counters.h" | 
|  | #include "src/objects/elements.h" | 
|  | #include "src/objects/intl-objects.h" | 
|  | #include "src/objects/js-array-inl.h" | 
|  | #include "src/objects/js-break-iterator-inl.h" | 
|  | #include "src/objects/js-collator-inl.h" | 
|  | #include "src/objects/js-date-time-format-inl.h" | 
|  | #include "src/objects/js-display-names-inl.h" | 
|  | #include "src/objects/js-list-format-inl.h" | 
|  | #include "src/objects/js-locale-inl.h" | 
|  | #include "src/objects/js-number-format-inl.h" | 
|  | #include "src/objects/js-plural-rules-inl.h" | 
|  | #include "src/objects/js-relative-time-format-inl.h" | 
|  | #include "src/objects/js-segment-iterator-inl.h" | 
|  | #include "src/objects/js-segmenter-inl.h" | 
|  | #include "src/objects/js-segments-inl.h" | 
|  | #include "src/objects/objects-inl.h" | 
|  | #include "src/objects/property-descriptor.h" | 
|  | #include "src/objects/smi.h" | 
|  | #include "unicode/brkiter.h" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  |  | 
|  | BUILTIN(StringPrototypeToUpperCaseIntl) { | 
|  | HandleScope scope(isolate); | 
|  | TO_THIS_STRING(string, "String.prototype.toUpperCase"); | 
|  | string = String::Flatten(isolate, string); | 
|  | RETURN_RESULT_OR_FAILURE(isolate, Intl::ConvertToUpper(isolate, string)); | 
|  | } | 
|  |  | 
|  | BUILTIN(StringPrototypeNormalizeIntl) { | 
|  | HandleScope handle_scope(isolate); | 
|  | isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringNormalize); | 
|  | TO_THIS_STRING(string, "String.prototype.normalize"); | 
|  |  | 
|  | Handle<Object> form_input = args.atOrUndefined(isolate, 1); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | Intl::Normalize(isolate, string, form_input)); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.v8BreakIterator.supportedLocalesOf", | 
|  | JSV8BreakIterator::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | BUILTIN(NumberFormatSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.NumberFormat.supportedLocalesOf", | 
|  | JSNumberFormat::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | BUILTIN(NumberFormatPrototypeFormatToParts) { | 
|  | const char* const method = "Intl.NumberFormat.prototype.formatToParts"; | 
|  | HandleScope handle_scope(isolate); | 
|  | CHECK_RECEIVER(JSNumberFormat, number_format, method); | 
|  |  | 
|  | Handle<Object> x; | 
|  | if (args.length() >= 2) { | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, | 
|  | Object::ToNumeric(isolate, args.at(1))); | 
|  | } else { | 
|  | x = isolate->factory()->nan_value(); | 
|  | } | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSNumberFormat::FormatToParts(isolate, number_format, x)); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatPrototypeResolvedOptions) { | 
|  | const char* const method = "Intl.DateTimeFormat.prototype.resolvedOptions"; | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSReceiver, format_holder, method); | 
|  |  | 
|  | // 3. Let dtf be ? UnwrapDateTimeFormat(dtf). | 
|  | Handle<JSDateTimeFormat> date_time_format; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, date_time_format, | 
|  | JSDateTimeFormat::UnwrapDateTimeFormat(isolate, format_holder)); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSDateTimeFormat::ResolvedOptions(isolate, date_time_format)); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.DateTimeFormat.supportedLocalesOf", | 
|  | JSDateTimeFormat::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatPrototypeFormatToParts) { | 
|  | const char* const method = "Intl.DateTimeFormat.prototype.formatToParts"; | 
|  | HandleScope handle_scope(isolate); | 
|  | CHECK_RECEIVER(JSObject, date_format_holder, method); | 
|  | Factory* factory = isolate->factory(); | 
|  |  | 
|  | if (!date_format_holder->IsJSDateTimeFormat()) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | 
|  | factory->NewStringFromAsciiChecked(method), | 
|  | date_format_holder)); | 
|  | } | 
|  | Handle<JSDateTimeFormat> dtf = | 
|  | Handle<JSDateTimeFormat>::cast(date_format_holder); | 
|  |  | 
|  | Handle<Object> x = args.atOrUndefined(isolate, 1); | 
|  | if (x->IsUndefined(isolate)) { | 
|  | x = factory->NewNumber(JSDate::CurrentTimeValue(isolate)); | 
|  | } else { | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, | 
|  | Object::ToNumber(isolate, args.at(1))); | 
|  | } | 
|  |  | 
|  | double date_value = DateCache::TimeClip(x->Number()); | 
|  | if (std::isnan(date_value)) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewRangeError(MessageTemplate::kInvalidTimeValue)); | 
|  | } | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSDateTimeFormat::FormatToParts(isolate, dtf, date_value)); | 
|  | } | 
|  |  | 
|  | // Common code for DateTimeFormatPrototypeFormtRange(|ToParts) | 
|  | template <class T> | 
|  | V8_WARN_UNUSED_RESULT Object DateTimeFormatRange( | 
|  | BuiltinArguments args, Isolate* isolate, const char* const method, | 
|  | MaybeHandle<T> (*format)(Isolate*, Handle<JSDateTimeFormat>, double, | 
|  | double)) { | 
|  | // 1. Let dtf be this value. | 
|  | // 2. If Type(dtf) is not Object, throw a TypeError exception. | 
|  | CHECK_RECEIVER(JSObject, date_format_holder, method); | 
|  |  | 
|  | Factory* factory = isolate->factory(); | 
|  |  | 
|  | // 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, | 
|  | //    throw a TypeError exception. | 
|  | if (!date_format_holder->IsJSDateTimeFormat()) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | 
|  | factory->NewStringFromAsciiChecked(method), | 
|  | date_format_holder)); | 
|  | } | 
|  | Handle<JSDateTimeFormat> dtf = | 
|  | Handle<JSDateTimeFormat>::cast(date_format_holder); | 
|  |  | 
|  | // 4. If startDate is undefined or endDate is undefined, throw a TypeError | 
|  | // exception. | 
|  | Handle<Object> start_date = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> end_date = args.atOrUndefined(isolate, 2); | 
|  | if (start_date->IsUndefined(isolate) || end_date->IsUndefined(isolate)) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewTypeError(MessageTemplate::kInvalidTimeValue)); | 
|  | } | 
|  | // 5. Let x be ? ToNumber(startDate). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, start_date, | 
|  | Object::ToNumber(isolate, start_date)); | 
|  | double x = start_date->Number(); | 
|  |  | 
|  | // 6. Let y be ? ToNumber(endDate). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, end_date, | 
|  | Object::ToNumber(isolate, end_date)); | 
|  | double y = end_date->Number(); | 
|  | // 7. If x is greater than y, throw a RangeError exception. | 
|  | if (x > y) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewRangeError(MessageTemplate::kInvalidTimeValue)); | 
|  | } | 
|  |  | 
|  | // 8. Return ? FormatDateTimeRange(dtf, x, y) | 
|  | // OR | 
|  | // 8. Return ? FormatDateTimeRangeToParts(dtf, x, y). | 
|  | RETURN_RESULT_OR_FAILURE(isolate, format(isolate, dtf, x, y)); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatPrototypeFormatRange) { | 
|  | const char* const method = "Intl.DateTimeFormat.prototype.formatRange"; | 
|  | HandleScope handle_scope(isolate); | 
|  | return DateTimeFormatRange<String>(args, isolate, method, | 
|  | JSDateTimeFormat::FormatRange); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatPrototypeFormatRangeToParts) { | 
|  | const char* const method = "Intl.DateTimeFormat.prototype.formatRangeToParts"; | 
|  | HandleScope handle_scope(isolate); | 
|  | return DateTimeFormatRange<JSArray>(args, isolate, method, | 
|  | JSDateTimeFormat::FormatRangeToParts); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | Handle<JSFunction> CreateBoundFunction(Isolate* isolate, | 
|  | Handle<JSObject> object, | 
|  | Builtins::Name builtin_id, int len) { | 
|  | Handle<NativeContext> native_context(isolate->context().native_context(), | 
|  | isolate); | 
|  | Handle<Context> context = isolate->factory()->NewBuiltinContext( | 
|  | native_context, | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kLength)); | 
|  |  | 
|  | context->set(static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction), | 
|  | *object); | 
|  |  | 
|  | Handle<SharedFunctionInfo> info = | 
|  | isolate->factory()->NewSharedFunctionInfoForBuiltin( | 
|  | isolate->factory()->empty_string(), builtin_id, kNormalFunction); | 
|  | info->set_internal_formal_parameter_count(len); | 
|  | info->set_length(len); | 
|  |  | 
|  | Handle<Map> map = isolate->strict_function_without_prototype_map(); | 
|  |  | 
|  | Handle<JSFunction> new_bound_function = | 
|  | isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context); | 
|  | return new_bound_function; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Common code shared between DateTimeFormatConstructor and | 
|  | * NumberFormatConstrutor | 
|  | */ | 
|  | template <class T> | 
|  | Object LegacyFormatConstructor(BuiltinArguments args, Isolate* isolate, | 
|  | v8::Isolate::UseCounterFeature feature, | 
|  | Handle<Object> constructor, const char* method) { | 
|  | isolate->CountUsage(feature); | 
|  | Handle<JSReceiver> new_target; | 
|  | // 1. If NewTarget is undefined, let newTarget be the active | 
|  | // function object, else let newTarget be NewTarget. | 
|  | if (args.new_target()->IsUndefined(isolate)) { | 
|  | new_target = args.target(); | 
|  | } else { | 
|  | new_target = Handle<JSReceiver>::cast(args.new_target()); | 
|  | } | 
|  |  | 
|  | // [[Construct]] | 
|  | Handle<JSFunction> target = args.target(); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | // 2. Let format be ? OrdinaryCreateFromConstructor(newTarget, | 
|  | // "%<T>Prototype%", ...). | 
|  | Handle<Map> map; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target)); | 
|  |  | 
|  | // 3. Perform ? Initialize<T>(Format, locales, options). | 
|  | Handle<T> format; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, format, T::New(isolate, map, locales, options, method)); | 
|  | // 4. Let this be the this value. | 
|  | if (args.new_target()->IsUndefined(isolate)) { | 
|  | Handle<Object> receiver = args.receiver(); | 
|  |  | 
|  | // 5. If NewTarget is undefined and ? InstanceofOperator(this, %<T>%) | 
|  | // is true, then Look up the intrinsic value that has been stored on | 
|  | // the context. | 
|  | Handle<Object> is_instance_of_obj; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, is_instance_of_obj, | 
|  | Object::InstanceOf(isolate, receiver, constructor)); | 
|  |  | 
|  | if (is_instance_of_obj->BooleanValue(isolate)) { | 
|  | if (!receiver->IsJSReceiver()) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, | 
|  | NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | 
|  | isolate->factory()->NewStringFromAsciiChecked(method), | 
|  | receiver)); | 
|  | } | 
|  | Handle<JSReceiver> rec = Handle<JSReceiver>::cast(receiver); | 
|  | // a. Perform ? DefinePropertyOrThrow(this, | 
|  | // %Intl%.[[FallbackSymbol]], PropertyDescriptor{ [[Value]]: format, | 
|  | // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }). | 
|  | PropertyDescriptor desc; | 
|  | desc.set_value(format); | 
|  | desc.set_writable(false); | 
|  | desc.set_enumerable(false); | 
|  | desc.set_configurable(false); | 
|  | Maybe<bool> success = JSReceiver::DefineOwnProperty( | 
|  | isolate, rec, isolate->factory()->intl_fallback_symbol(), &desc, | 
|  | Just(kThrowOnError)); | 
|  | MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception()); | 
|  | CHECK(success.FromJust()); | 
|  | // b. b. Return this. | 
|  | return *receiver; | 
|  | } | 
|  | } | 
|  | // 6. Return format. | 
|  | return *format; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Common code shared by ListFormat, RelativeTimeFormat, PluralRules, and | 
|  | * Segmenter | 
|  | */ | 
|  | template <class T> | 
|  | Object DisallowCallConstructor(BuiltinArguments args, Isolate* isolate, | 
|  | v8::Isolate::UseCounterFeature feature, | 
|  | const char* method) { | 
|  | isolate->CountUsage(feature); | 
|  |  | 
|  | // 1. If NewTarget is undefined, throw a TypeError exception. | 
|  | if (args.new_target()->IsUndefined(isolate)) {  // [[Call]] | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, | 
|  | NewTypeError(MessageTemplate::kConstructorNotFunction, | 
|  | isolate->factory()->NewStringFromAsciiChecked(method))); | 
|  | } | 
|  | // [[Construct]] | 
|  | Handle<JSFunction> target = args.target(); | 
|  | Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); | 
|  |  | 
|  | Handle<Map> map; | 
|  | // 2. Let result be OrdinaryCreateFromConstructor(NewTarget, | 
|  | //    "%<T>Prototype%"). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target)); | 
|  |  | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | // 3. Return New<T>(t, locales, options). | 
|  | RETURN_RESULT_OR_FAILURE(isolate, T::New(isolate, map, locales, options)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Common code shared by Collator and V8BreakIterator | 
|  | */ | 
|  | template <class T> | 
|  | Object CallOrConstructConstructor(BuiltinArguments args, Isolate* isolate, | 
|  | const char* method) { | 
|  | Handle<JSReceiver> new_target; | 
|  |  | 
|  | if (args.new_target()->IsUndefined(isolate)) { | 
|  | new_target = args.target(); | 
|  | } else { | 
|  | new_target = Handle<JSReceiver>::cast(args.new_target()); | 
|  | } | 
|  |  | 
|  | // [[Construct]] | 
|  | Handle<JSFunction> target = args.target(); | 
|  |  | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | Handle<Map> map; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target)); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | T::New(isolate, map, locales, options, method)); | 
|  | } | 
|  | }  // namespace | 
|  |  | 
|  | // Intl.DisplayNames | 
|  |  | 
|  | BUILTIN(DisplayNamesConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return DisallowCallConstructor<JSDisplayNames>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kDisplayNames, | 
|  | "Intl.DisplayNames"); | 
|  | } | 
|  |  | 
|  | BUILTIN(DisplayNamesPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSDisplayNames, holder, | 
|  | "Intl.DisplayNames.prototype.resolvedOptions"); | 
|  | return *JSDisplayNames::ResolvedOptions(isolate, holder); | 
|  | } | 
|  |  | 
|  | BUILTIN(DisplayNamesSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.DisplayNames.supportedLocalesOf", | 
|  | JSDisplayNames::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | BUILTIN(DisplayNamesPrototypeOf) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSDisplayNames, holder, "Intl.DisplayNames.prototype.of"); | 
|  | Handle<Object> code_obj = args.atOrUndefined(isolate, 1); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | JSDisplayNames::Of(isolate, holder, code_obj)); | 
|  | } | 
|  |  | 
|  | // Intl.NumberFormat | 
|  |  | 
|  | BUILTIN(NumberFormatConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return LegacyFormatConstructor<JSNumberFormat>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kNumberFormat, | 
|  | isolate->intl_number_format_function(), "Intl.NumberFormat"); | 
|  | } | 
|  |  | 
|  | BUILTIN(NumberFormatPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | const char* const method = "Intl.NumberFormat.prototype.resolvedOptions"; | 
|  |  | 
|  | // 1. Let nf be the this value. | 
|  | // 2. If Type(nf) is not Object, throw a TypeError exception. | 
|  | CHECK_RECEIVER(JSReceiver, number_format_holder, method); | 
|  |  | 
|  | // 3. Let nf be ? UnwrapNumberFormat(nf) | 
|  | Handle<JSNumberFormat> number_format; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, number_format, | 
|  | JSNumberFormat::UnwrapNumberFormat(isolate, number_format_holder)); | 
|  |  | 
|  | return *JSNumberFormat::ResolvedOptions(isolate, number_format); | 
|  | } | 
|  |  | 
|  | BUILTIN(NumberFormatPrototypeFormatNumber) { | 
|  | const char* const method = "get Intl.NumberFormat.prototype.format"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | // 1. Let nf be the this value. | 
|  | // 2. If Type(nf) is not Object, throw a TypeError exception. | 
|  | CHECK_RECEIVER(JSReceiver, receiver, method); | 
|  |  | 
|  | // 3. Let nf be ? UnwrapNumberFormat(nf). | 
|  | Handle<JSNumberFormat> number_format; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, number_format, | 
|  | JSNumberFormat::UnwrapNumberFormat(isolate, receiver)); | 
|  |  | 
|  | Handle<Object> bound_format(number_format->bound_format(), isolate); | 
|  |  | 
|  | // 4. If nf.[[BoundFormat]] is undefined, then | 
|  | if (!bound_format->IsUndefined(isolate)) { | 
|  | DCHECK(bound_format->IsJSFunction()); | 
|  | // 5. Return nf.[[BoundFormat]]. | 
|  | return *bound_format; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_format_function = CreateBoundFunction( | 
|  | isolate, number_format, Builtins::kNumberFormatInternalFormatNumber, 1); | 
|  |  | 
|  | // 4. c. Set nf.[[BoundFormat]] to F. | 
|  | number_format->set_bound_format(*new_bound_format_function); | 
|  |  | 
|  | // 5. Return nf.[[BoundFormat]]. | 
|  | return *new_bound_format_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(NumberFormatInternalFormatNumber) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | // 1. Let nf be F.[[NumberFormat]]. | 
|  | // 2. Assert: Type(nf) is Object and nf has an | 
|  | //    [[InitializedNumberFormat]] internal slot. | 
|  | Handle<JSNumberFormat> number_format = Handle<JSNumberFormat>( | 
|  | JSNumberFormat::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  |  | 
|  | // 3. If value is not provided, let value be undefined. | 
|  | Handle<Object> value = args.atOrUndefined(isolate, 1); | 
|  |  | 
|  | // 4. Let x be ? ToNumeric(value). | 
|  | Handle<Object> numeric_obj; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, numeric_obj, | 
|  | Object::ToNumeric(isolate, value)); | 
|  |  | 
|  | icu::number::LocalizedNumberFormatter* icu_localized_number_formatter = | 
|  | number_format->icu_number_formatter().raw(); | 
|  | CHECK_NOT_NULL(icu_localized_number_formatter); | 
|  |  | 
|  | // Return FormatNumber(nf, x). | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSNumberFormat::FormatNumeric( | 
|  | isolate, *icu_localized_number_formatter, numeric_obj)); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return LegacyFormatConstructor<JSDateTimeFormat>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kDateTimeFormat, | 
|  | isolate->intl_date_time_format_function(), "Intl.DateTimeFormat"); | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatPrototypeFormat) { | 
|  | const char* const method = "get Intl.DateTimeFormat.prototype.format"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | // 1. Let dtf be this value. | 
|  | // 2. If Type(dtf) is not Object, throw a TypeError exception. | 
|  | CHECK_RECEIVER(JSReceiver, receiver, method); | 
|  |  | 
|  | // 3. Let dtf be ? UnwrapDateTimeFormat(dtf). | 
|  | Handle<JSDateTimeFormat> format; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, format, | 
|  | JSDateTimeFormat::UnwrapDateTimeFormat(isolate, receiver)); | 
|  |  | 
|  | Handle<Object> bound_format = Handle<Object>(format->bound_format(), isolate); | 
|  |  | 
|  | // 4. If dtf.[[BoundFormat]] is undefined, then | 
|  | if (!bound_format->IsUndefined(isolate)) { | 
|  | DCHECK(bound_format->IsJSFunction()); | 
|  | // 5. Return dtf.[[BoundFormat]]. | 
|  | return *bound_format; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_format_function = CreateBoundFunction( | 
|  | isolate, format, Builtins::kDateTimeFormatInternalFormat, 1); | 
|  |  | 
|  | // 4.c. Set dtf.[[BoundFormat]] to F. | 
|  | format->set_bound_format(*new_bound_format_function); | 
|  |  | 
|  | // 5. Return dtf.[[BoundFormat]]. | 
|  | return *new_bound_format_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(DateTimeFormatInternalFormat) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | // 1. Let dtf be F.[[DateTimeFormat]]. | 
|  | // 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]] | 
|  | // internal slot. | 
|  | Handle<JSDateTimeFormat> date_format_holder = Handle<JSDateTimeFormat>( | 
|  | JSDateTimeFormat::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  |  | 
|  | Handle<Object> date = args.atOrUndefined(isolate, 1); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::DateTimeFormat( | 
|  | isolate, date_format_holder, date)); | 
|  | } | 
|  |  | 
|  | BUILTIN(IntlGetCanonicalLocales) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | Intl::GetCanonicalLocales(isolate, locales)); | 
|  | } | 
|  |  | 
|  | BUILTIN(ListFormatConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return DisallowCallConstructor<JSListFormat>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kListFormat, | 
|  | "Intl.ListFormat"); | 
|  | } | 
|  |  | 
|  | BUILTIN(ListFormatPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSListFormat, format_holder, | 
|  | "Intl.ListFormat.prototype.resolvedOptions"); | 
|  | return *JSListFormat::ResolvedOptions(isolate, format_holder); | 
|  | } | 
|  |  | 
|  | BUILTIN(ListFormatSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.ListFormat.supportedLocalesOf", | 
|  | JSListFormat::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | // Intl.Locale implementation | 
|  | BUILTIN(LocaleConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocale); | 
|  |  | 
|  | if (args.new_target()->IsUndefined(isolate)) {  // [[Call]] | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, | 
|  | isolate->factory()->NewStringFromAsciiChecked( | 
|  | "Intl.Locale"))); | 
|  | } | 
|  | // [[Construct]] | 
|  | Handle<JSFunction> target = args.target(); | 
|  | Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); | 
|  |  | 
|  | Handle<Object> tag = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | Handle<Map> map; | 
|  | // 6. Let locale be ? OrdinaryCreateFromConstructor(NewTarget, | 
|  | // %LocalePrototype%, internalSlotsList). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target)); | 
|  |  | 
|  | // 7. If Type(tag) is not String or Object, throw a TypeError exception. | 
|  | if (!tag->IsString() && !tag->IsJSReceiver()) { | 
|  | THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty)); | 
|  | } | 
|  |  | 
|  | Handle<String> locale_string; | 
|  | // 8. If Type(tag) is Object and tag has an [[InitializedLocale]] internal | 
|  | // slot, then | 
|  | if (tag->IsJSLocale()) { | 
|  | // a. Let tag be tag.[[Locale]]. | 
|  | locale_string = JSLocale::ToString(isolate, Handle<JSLocale>::cast(tag)); | 
|  | } else {  // 9. Else, | 
|  | // a. Let tag be ? ToString(tag). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_string, | 
|  | Object::ToString(isolate, tag)); | 
|  | } | 
|  |  | 
|  | Handle<JSReceiver> options_object; | 
|  | // 10. If options is undefined, then | 
|  | if (options->IsUndefined(isolate)) { | 
|  | // a. Let options be ! ObjectCreate(null). | 
|  | options_object = isolate->factory()->NewJSObjectWithNullProto(); | 
|  | } else {  // 11. Else | 
|  | // a. Let options be ? ToObject(options). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, options_object, | 
|  | Object::ToObject(isolate, options)); | 
|  | } | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSLocale::New(isolate, map, locale_string, options_object)); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeMaximize) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.maximize"); | 
|  | RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Maximize(isolate, locale)); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeMinimize) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.minimize"); | 
|  | RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Minimize(isolate, locale)); | 
|  | } | 
|  |  | 
|  | BUILTIN(RelativeTimeFormatSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, | 
|  | Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.RelativeTimeFormat.supportedLocalesOf", | 
|  | JSRelativeTimeFormat::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | BUILTIN(RelativeTimeFormatPrototypeFormat) { | 
|  | HandleScope scope(isolate); | 
|  | // 1. Let relativeTimeFormat be the this value. | 
|  | // 2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not | 
|  | //    have an [[InitializedRelativeTimeFormat]] internal slot whose value is | 
|  | //    true, throw a TypeError exception. | 
|  | CHECK_RECEIVER(JSRelativeTimeFormat, format_holder, | 
|  | "Intl.RelativeTimeFormat.prototype.format"); | 
|  | Handle<Object> value_obj = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> unit_obj = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSRelativeTimeFormat::Format(isolate, value_obj, unit_obj, | 
|  | format_holder)); | 
|  | } | 
|  |  | 
|  | BUILTIN(RelativeTimeFormatPrototypeFormatToParts) { | 
|  | HandleScope scope(isolate); | 
|  | // 1. Let relativeTimeFormat be the this value. | 
|  | // 2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not | 
|  | //    have an [[InitializedRelativeTimeFormat]] internal slot whose value is | 
|  | //    true, throw a TypeError exception. | 
|  | CHECK_RECEIVER(JSRelativeTimeFormat, format_holder, | 
|  | "Intl.RelativeTimeFormat.prototype.formatToParts"); | 
|  | Handle<Object> value_obj = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> unit_obj = args.atOrUndefined(isolate, 2); | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, JSRelativeTimeFormat::FormatToParts(isolate, value_obj, unit_obj, | 
|  | format_holder)); | 
|  | } | 
|  |  | 
|  | // Locale getters. | 
|  | BUILTIN(LocalePrototypeLanguage) { | 
|  | HandleScope scope(isolate); | 
|  | // CHECK_RECEIVER will case locale_holder to JSLocale. | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.language"); | 
|  |  | 
|  | return *JSLocale::Language(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeScript) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.script"); | 
|  |  | 
|  | return *JSLocale::Script(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeRegion) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.region"); | 
|  |  | 
|  | return *JSLocale::Region(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeBaseName) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.baseName"); | 
|  |  | 
|  | return *JSLocale::BaseName(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeCalendar) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.calendar"); | 
|  |  | 
|  | return *JSLocale::Calendar(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeCaseFirst) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.caseFirst"); | 
|  |  | 
|  | return *JSLocale::CaseFirst(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeCollation) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.collation"); | 
|  |  | 
|  | return *JSLocale::Collation(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeHourCycle) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.hourCycle"); | 
|  |  | 
|  | return *JSLocale::HourCycle(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeNumeric) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numeric"); | 
|  |  | 
|  | return *JSLocale::Numeric(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeNumberingSystem) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numberingSystem"); | 
|  |  | 
|  | return *JSLocale::NumberingSystem(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(LocalePrototypeToString) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.toString"); | 
|  |  | 
|  | return *JSLocale::ToString(isolate, locale); | 
|  | } | 
|  |  | 
|  | BUILTIN(RelativeTimeFormatConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return DisallowCallConstructor<JSRelativeTimeFormat>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kRelativeTimeFormat, | 
|  | "Intl.RelativeTimeFormat"); | 
|  | } | 
|  |  | 
|  | BUILTIN(RelativeTimeFormatPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSRelativeTimeFormat, format_holder, | 
|  | "Intl.RelativeTimeFormat.prototype.resolvedOptions"); | 
|  | return *JSRelativeTimeFormat::ResolvedOptions(isolate, format_holder); | 
|  | } | 
|  |  | 
|  | BUILTIN(StringPrototypeToLocaleLowerCase) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringToLocaleLowerCase); | 
|  |  | 
|  | TO_THIS_STRING(string, "String.prototype.toLocaleLowerCase"); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::StringLocaleConvertCase(isolate, string, false, | 
|  | args.atOrUndefined(isolate, 1))); | 
|  | } | 
|  |  | 
|  | BUILTIN(StringPrototypeToLocaleUpperCase) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringToLocaleUpperCase); | 
|  |  | 
|  | TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase"); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::StringLocaleConvertCase(isolate, string, true, | 
|  | args.atOrUndefined(isolate, 1))); | 
|  | } | 
|  |  | 
|  | BUILTIN(PluralRulesConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return DisallowCallConstructor<JSPluralRules>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kPluralRules, | 
|  | "Intl.PluralRules"); | 
|  | } | 
|  |  | 
|  | BUILTIN(PluralRulesPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSPluralRules, plural_rules_holder, | 
|  | "Intl.PluralRules.prototype.resolvedOptions"); | 
|  | return *JSPluralRules::ResolvedOptions(isolate, plural_rules_holder); | 
|  | } | 
|  |  | 
|  | BUILTIN(PluralRulesPrototypeSelect) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | // 1. Let pr be the this value. | 
|  | // 2. If Type(pr) is not Object, throw a TypeError exception. | 
|  | // 3. If pr does not have an [[InitializedPluralRules]] internal slot, throw a | 
|  | // TypeError exception. | 
|  | CHECK_RECEIVER(JSPluralRules, plural_rules, | 
|  | "Intl.PluralRules.prototype.select"); | 
|  |  | 
|  | // 4. Let n be ? ToNumber(value). | 
|  | Handle<Object> number = args.atOrUndefined(isolate, 1); | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number, | 
|  | Object::ToNumber(isolate, number)); | 
|  | double number_double = number->Number(); | 
|  |  | 
|  | // 5. Return ? ResolvePlural(pr, n). | 
|  | RETURN_RESULT_OR_FAILURE(isolate, JSPluralRules::ResolvePlural( | 
|  | isolate, plural_rules, number_double)); | 
|  | } | 
|  |  | 
|  | BUILTIN(PluralRulesSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.PluralRules.supportedLocalesOf", | 
|  | JSPluralRules::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | BUILTIN(CollatorConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | isolate->CountUsage(v8::Isolate::UseCounterFeature::kCollator); | 
|  |  | 
|  | return CallOrConstructConstructor<JSCollator>(args, isolate, "Intl.Collator"); | 
|  | } | 
|  |  | 
|  | BUILTIN(CollatorPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSCollator, collator_holder, | 
|  | "Intl.Collator.prototype.resolvedOptions"); | 
|  | return *JSCollator::ResolvedOptions(isolate, collator_holder); | 
|  | } | 
|  |  | 
|  | BUILTIN(CollatorSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.Collator.supportedLocalesOf", | 
|  | JSCollator::GetAvailableLocales(), 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<JSFunction> new_bound_compare_function = CreateBoundFunction( | 
|  | isolate, collator, Builtins::kCollatorInternalCompare, 2); | 
|  |  | 
|  | // 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 = Handle<JSCollator>( | 
|  | JSCollator::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | 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). | 
|  | icu::Collator* icu_collator = collator->icu_collator().raw(); | 
|  | CHECK_NOT_NULL(icu_collator); | 
|  | return *Intl::CompareStrings(isolate, *icu_collator, string_x, string_y); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-%segmentiteratorprototype%.next | 
|  | BUILTIN(SegmentIteratorPrototypeNext) { | 
|  | const char* const method = "%SegmentIterator.prototype%.next"; | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | JSSegmentIterator::Next(isolate, segment_iterator)); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-intl.segmenter | 
|  | BUILTIN(SegmenterConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return DisallowCallConstructor<JSSegmenter>( | 
|  | args, isolate, v8::Isolate::UseCounterFeature::kSegmenter, | 
|  | "Intl.Segmenter"); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-intl.segmenter.supportedlocalesof | 
|  | BUILTIN(SegmenterSupportedLocalesOf) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Object> locales = args.atOrUndefined(isolate, 1); | 
|  | Handle<Object> options = args.atOrUndefined(isolate, 2); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, Intl::SupportedLocalesOf( | 
|  | isolate, "Intl.Segmenter.supportedLocalesOf", | 
|  | JSSegmenter::GetAvailableLocales(), locales, options)); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-intl.segmenter.prototype.resolvedoptions | 
|  | BUILTIN(SegmenterPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSSegmenter, segmenter, | 
|  | "Intl.Segmenter.prototype.resolvedOptions"); | 
|  | return *JSSegmenter::ResolvedOptions(isolate, segmenter); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-intl.segmenter.prototype.segment | 
|  | BUILTIN(SegmenterPrototypeSegment) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSSegmenter, segmenter, "Intl.Segmenter.prototype.segment"); | 
|  | Handle<Object> input_text = args.atOrUndefined(isolate, 1); | 
|  | // 3. Let string be ? ToString(string). | 
|  | Handle<String> string; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | 
|  | Object::ToString(isolate, input_text)); | 
|  |  | 
|  | // 4. Return ? CreateSegmentsObject(segmenter, string). | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | JSSegments::Create(isolate, segmenter, string)); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-%segmentsprototype%.containing | 
|  | BUILTIN(SegmentsPrototypeContaining) { | 
|  | const char* const method = "%Segments.prototype%.containing"; | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSSegments, segments, method); | 
|  | Handle<Object> index = args.atOrUndefined(isolate, 1); | 
|  |  | 
|  | // 6. Let n be ? ToInteger(index). | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, index, | 
|  | Object::ToInteger(isolate, index)); | 
|  | double const n = index->Number(); | 
|  |  | 
|  | RETURN_RESULT_OR_FAILURE(isolate, | 
|  | JSSegments::Containing(isolate, segments, n)); | 
|  | } | 
|  |  | 
|  | // ecma402 #sec-%segmentsprototype%-@@iterator | 
|  | BUILTIN(SegmentsPrototypeIterator) { | 
|  | const char* const method = "%SegmentIsPrototype%[@@iterator]"; | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSSegments, segments, method); | 
|  | RETURN_RESULT_OR_FAILURE( | 
|  | isolate, | 
|  | JSSegmentIterator::Create(isolate, segments->icu_break_iterator().raw(), | 
|  | segments->granularity())); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorConstructor) { | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | return CallOrConstructConstructor<JSV8BreakIterator>(args, isolate, | 
|  | "Intl.v8BreakIterator"); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorPrototypeResolvedOptions) { | 
|  | HandleScope scope(isolate); | 
|  | CHECK_RECEIVER(JSV8BreakIterator, break_iterator, | 
|  | "Intl.v8BreakIterator.prototype.resolvedOptions"); | 
|  | return *JSV8BreakIterator::ResolvedOptions(isolate, break_iterator); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorPrototypeAdoptText) { | 
|  | const char* const method = "get Intl.v8BreakIterator.prototype.adoptText"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method); | 
|  |  | 
|  | Handle<Object> bound_adopt_text(break_iterator->bound_adopt_text(), isolate); | 
|  | if (!bound_adopt_text->IsUndefined(isolate)) { | 
|  | DCHECK(bound_adopt_text->IsJSFunction()); | 
|  | return *bound_adopt_text; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_adopt_text_function = CreateBoundFunction( | 
|  | isolate, break_iterator, Builtins::kV8BreakIteratorInternalAdoptText, 1); | 
|  | break_iterator->set_bound_adopt_text(*new_bound_adopt_text_function); | 
|  | return *new_bound_adopt_text_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorInternalAdoptText) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>( | 
|  | JSV8BreakIterator::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  |  | 
|  | Handle<Object> input_text = args.atOrUndefined(isolate, 1); | 
|  | Handle<String> text; | 
|  | ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, text, | 
|  | Object::ToString(isolate, input_text)); | 
|  |  | 
|  | JSV8BreakIterator::AdoptText(isolate, break_iterator, text); | 
|  | return ReadOnlyRoots(isolate).undefined_value(); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorPrototypeFirst) { | 
|  | const char* const method = "get Intl.v8BreakIterator.prototype.first"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method); | 
|  |  | 
|  | Handle<Object> bound_first(break_iterator->bound_first(), isolate); | 
|  | if (!bound_first->IsUndefined(isolate)) { | 
|  | DCHECK(bound_first->IsJSFunction()); | 
|  | return *bound_first; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_first_function = CreateBoundFunction( | 
|  | isolate, break_iterator, Builtins::kV8BreakIteratorInternalFirst, 0); | 
|  | break_iterator->set_bound_first(*new_bound_first_function); | 
|  | return *new_bound_first_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorInternalFirst) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>( | 
|  | JSV8BreakIterator::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  |  | 
|  | return *JSV8BreakIterator::First(isolate, break_iterator); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorPrototypeNext) { | 
|  | const char* const method = "get Intl.v8BreakIterator.prototype.next"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method); | 
|  |  | 
|  | Handle<Object> bound_next(break_iterator->bound_next(), isolate); | 
|  | if (!bound_next->IsUndefined(isolate)) { | 
|  | DCHECK(bound_next->IsJSFunction()); | 
|  | return *bound_next; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_next_function = CreateBoundFunction( | 
|  | isolate, break_iterator, Builtins::kV8BreakIteratorInternalNext, 0); | 
|  | break_iterator->set_bound_next(*new_bound_next_function); | 
|  | return *new_bound_next_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorInternalNext) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>( | 
|  | JSV8BreakIterator::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  | return *JSV8BreakIterator::Next(isolate, break_iterator); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorPrototypeCurrent) { | 
|  | const char* const method = "get Intl.v8BreakIterator.prototype.current"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method); | 
|  |  | 
|  | Handle<Object> bound_current(break_iterator->bound_current(), isolate); | 
|  | if (!bound_current->IsUndefined(isolate)) { | 
|  | DCHECK(bound_current->IsJSFunction()); | 
|  | return *bound_current; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_current_function = CreateBoundFunction( | 
|  | isolate, break_iterator, Builtins::kV8BreakIteratorInternalCurrent, 0); | 
|  | break_iterator->set_bound_current(*new_bound_current_function); | 
|  | return *new_bound_current_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorInternalCurrent) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>( | 
|  | JSV8BreakIterator::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  | return *JSV8BreakIterator::Current(isolate, break_iterator); | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorPrototypeBreakType) { | 
|  | const char* const method = "get Intl.v8BreakIterator.prototype.breakType"; | 
|  | HandleScope scope(isolate); | 
|  |  | 
|  | CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method); | 
|  |  | 
|  | Handle<Object> bound_break_type(break_iterator->bound_break_type(), isolate); | 
|  | if (!bound_break_type->IsUndefined(isolate)) { | 
|  | DCHECK(bound_break_type->IsJSFunction()); | 
|  | return *bound_break_type; | 
|  | } | 
|  |  | 
|  | Handle<JSFunction> new_bound_break_type_function = CreateBoundFunction( | 
|  | isolate, break_iterator, Builtins::kV8BreakIteratorInternalBreakType, 0); | 
|  | break_iterator->set_bound_break_type(*new_bound_break_type_function); | 
|  | return *new_bound_break_type_function; | 
|  | } | 
|  |  | 
|  | BUILTIN(V8BreakIteratorInternalBreakType) { | 
|  | HandleScope scope(isolate); | 
|  | Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
|  |  | 
|  | Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>( | 
|  | JSV8BreakIterator::cast(context->get( | 
|  | static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), | 
|  | isolate); | 
|  | return JSV8BreakIterator::BreakType(isolate, break_iterator); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace v8 |