text: // 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/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-segment-iterator-prototype-breakType
  BUILTIN(SegmentIteratorPrototypeBreakType) {
    const char* const method = "get %SegmentIteratorPrototype%.breakType";
    HandleScope scope(isolate);
  
    CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method);
    return *segment_iterator->BreakType();
  }
  
  // ecma402 #sec-segment-iterator-prototype-following
  BUILTIN(SegmentIteratorPrototypeFollowing) {
    const char* const method = "%SegmentIteratorPrototype%.following";
    HandleScope scope(isolate);
    CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method);
  
    Handle<Object> from = args.atOrUndefined(isolate, 1);
  
    Maybe<bool> success =
        JSSegmentIterator::Following(isolate, segment_iterator, from);
    MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
    return *isolate->factory()->ToBoolean(success.FromJust());
  }
  
  // ecma402 #sec-segment-iterator-prototype-next
  BUILTIN(SegmentIteratorPrototypeNext) {
    const char* const method = "%SegmentIteratorPrototype%.next";
    HandleScope scope(isolate);
    CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method);
  
    RETURN_RESULT_OR_FAILURE(isolate,
                             JSSegmentIterator::Next(isolate, segment_iterator));
  }
  
  // ecma402 #sec-segment-iterator-prototype-preceding
  BUILTIN(SegmentIteratorPrototypePreceding) {
    const char* const method = "%SegmentIteratorPrototype%.preceding";
    HandleScope scope(isolate);
    CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method);
  
    Handle<Object> from = args.atOrUndefined(isolate, 1);
  
    Maybe<bool> success =
        JSSegmentIterator::Preceding(isolate, segment_iterator, from);
    MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
    return *isolate->factory()->ToBoolean(success.FromJust());
  }
  
  // ecma402 #sec-segment-iterator-prototype-index
  BUILTIN(SegmentIteratorPrototypeIndex) {
    const char* const method = "get %SegmentIteratorPrototype%.index";
    HandleScope scope(isolate);
  
    CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method);
    return *JSSegmentIterator::Index(isolate, segment_iterator);
  }
  
  BUILTIN(SegmenterConstructor) {
    HandleScope scope(isolate);
  
    return DisallowCallConstructor<JSSegmenter>(
        args, isolate, v8::Isolate::UseCounterFeature::kSegmenter,
        "Intl.Segmenter");
  }
  
  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));
  }
  
  BUILTIN(SegmenterPrototypeResolvedOptions) {
    HandleScope scope(isolate);
    CHECK_RECEIVER(JSSegmenter, segmenter_holder,
                   "Intl.Segmenter.prototype.resolvedOptions");
    return *JSSegmenter::ResolvedOptions(isolate, segmenter_holder);
  }
  
  // ecma402 #sec-Intl.Segmenter.prototype.segment
  BUILTIN(SegmenterPrototypeSegment) {
    HandleScope scope(isolate);
    CHECK_RECEIVER(JSSegmenter, segmenter_holder,
                   "Intl.Segmenter.prototype.segment");
    Handle<Object> input_text = args.atOrUndefined(isolate, 1);
    // 3. Let string be ? ToString(string).
    Handle<String> text;
    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, text,
                                       Object::ToString(isolate, input_text));
  
    // 4. Return ? CreateSegmentIterator(segment, string).
    RETURN_RESULT_OR_FAILURE(
        isolate,
        JSSegmentIterator::Create(
            isolate, segmenter_holder->icu_break_iterator().raw()->clone(),
            segmenter_holder->granularity(), text));
  }
  
  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
  