aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/builtins-intl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/builtins-intl.cc')
-rw-r--r--deps/v8/src/builtins/builtins-intl.cc1296
1 files changed, 628 insertions, 668 deletions
diff --git a/deps/v8/src/builtins/builtins-intl.cc b/deps/v8/src/builtins/builtins-intl.cc
index 1d54d0da80..01c8a9ddcd 100644
--- a/deps/v8/src/builtins/builtins-intl.cc
+++ b/deps/v8/src/builtins/builtins-intl.cc
@@ -10,7 +10,6 @@
#include <list>
#include <memory>
-#include "src/builtins/builtins-intl.h"
#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/date.h"
@@ -19,11 +18,16 @@
#include "src/objects-inl.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-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-segmenter-inl.h"
+#include "src/property-descriptor.h"
#include "unicode/datefmt.h"
#include "unicode/decimfmt.h"
@@ -32,12 +36,10 @@
#include "unicode/listformatter.h"
#include "unicode/normalizer2.h"
#include "unicode/numfmt.h"
-#include "unicode/reldatefmt.h"
#include "unicode/smpdtfmt.h"
#include "unicode/udat.h"
#include "unicode/ufieldpositer.h"
#include "unicode/unistr.h"
-#include "unicode/ureldatefmt.h"
#include "unicode/ustring.h"
namespace v8 {
@@ -128,329 +130,30 @@ BUILTIN(StringPrototypeNormalizeIntl) {
result.length())));
}
-namespace {
-
-// The list comes from third_party/icu/source/i18n/unicode/unum.h.
-// They're mapped to NumberFormat part types mentioned throughout
-// https://tc39.github.io/ecma402/#sec-partitionnumberpattern .
-Handle<String> IcuNumberFieldIdToNumberType(int32_t field_id, double number,
- Isolate* isolate) {
- switch (static_cast<UNumberFormatFields>(field_id)) {
- case UNUM_INTEGER_FIELD:
- if (std::isfinite(number)) return isolate->factory()->integer_string();
- if (std::isnan(number)) return isolate->factory()->nan_string();
- return isolate->factory()->infinity_string();
- case UNUM_FRACTION_FIELD:
- return isolate->factory()->fraction_string();
- case UNUM_DECIMAL_SEPARATOR_FIELD:
- return isolate->factory()->decimal_string();
- case UNUM_GROUPING_SEPARATOR_FIELD:
- return isolate->factory()->group_string();
- case UNUM_CURRENCY_FIELD:
- return isolate->factory()->currency_string();
- case UNUM_PERCENT_FIELD:
- return isolate->factory()->percentSign_string();
- case UNUM_SIGN_FIELD:
- return number < 0 ? isolate->factory()->minusSign_string()
- : isolate->factory()->plusSign_string();
-
- case UNUM_EXPONENT_SYMBOL_FIELD:
- case UNUM_EXPONENT_SIGN_FIELD:
- case UNUM_EXPONENT_FIELD:
- // We should never get these because we're not using any scientific
- // formatter.
- UNREACHABLE();
- return Handle<String>();
-
- case UNUM_PERMILL_FIELD:
- // We're not creating any permill formatter, and it's not even clear how
- // that would be possible with the ICU API.
- UNREACHABLE();
- return Handle<String>();
-
- default:
- UNREACHABLE();
- return Handle<String>();
- }
-}
-
-// The list comes from third_party/icu/source/i18n/unicode/udat.h.
-// They're mapped to DateTimeFormat components listed at
-// https://tc39.github.io/ecma402/#sec-datetimeformat-abstracts .
-
-Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) {
- switch (field_id) {
- case -1:
- return isolate->factory()->literal_string();
- case UDAT_YEAR_FIELD:
- case UDAT_EXTENDED_YEAR_FIELD:
- case UDAT_YEAR_NAME_FIELD:
- return isolate->factory()->year_string();
- case UDAT_MONTH_FIELD:
- case UDAT_STANDALONE_MONTH_FIELD:
- return isolate->factory()->month_string();
- case UDAT_DATE_FIELD:
- return isolate->factory()->day_string();
- case UDAT_HOUR_OF_DAY1_FIELD:
- case UDAT_HOUR_OF_DAY0_FIELD:
- case UDAT_HOUR1_FIELD:
- case UDAT_HOUR0_FIELD:
- return isolate->factory()->hour_string();
- case UDAT_MINUTE_FIELD:
- return isolate->factory()->minute_string();
- case UDAT_SECOND_FIELD:
- return isolate->factory()->second_string();
- case UDAT_DAY_OF_WEEK_FIELD:
- case UDAT_DOW_LOCAL_FIELD:
- case UDAT_STANDALONE_DAY_FIELD:
- return isolate->factory()->weekday_string();
- case UDAT_AM_PM_FIELD:
- return isolate->factory()->dayperiod_string();
- case UDAT_TIMEZONE_FIELD:
- case UDAT_TIMEZONE_RFC_FIELD:
- case UDAT_TIMEZONE_GENERIC_FIELD:
- case UDAT_TIMEZONE_SPECIAL_FIELD:
- case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD:
- case UDAT_TIMEZONE_ISO_FIELD:
- case UDAT_TIMEZONE_ISO_LOCAL_FIELD:
- return isolate->factory()->timeZoneName_string();
- case UDAT_ERA_FIELD:
- return isolate->factory()->era_string();
- default:
- // Other UDAT_*_FIELD's cannot show up because there is no way to specify
- // them via options of Intl.DateTimeFormat.
- UNREACHABLE();
- // To prevent MSVC from issuing C4715 warning.
- return Handle<String>();
- }
-}
-
-bool cmp_NumberFormatSpan(const NumberFormatSpan& a,
- const NumberFormatSpan& b) {
- // Regions that start earlier should be encountered earlier.
- if (a.begin_pos < b.begin_pos) return true;
- if (a.begin_pos > b.begin_pos) return false;
- // For regions that start in the same place, regions that last longer should
- // be encountered earlier.
- if (a.end_pos < b.end_pos) return false;
- if (a.end_pos > b.end_pos) return true;
- // For regions that are exactly the same, one of them must be the "literal"
- // backdrop we added, which has a field_id of -1, so consider higher field_ids
- // to be later.
- return a.field_id < b.field_id;
-}
-
-MaybeHandle<Object> FormatNumberToParts(Isolate* isolate,
- icu::NumberFormat* fmt, double number) {
- Factory* factory = isolate->factory();
-
- icu::UnicodeString formatted;
- icu::FieldPositionIterator fp_iter;
- UErrorCode status = U_ZERO_ERROR;
- fmt->format(number, formatted, &fp_iter, status);
- if (U_FAILURE(status)) {
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), Object);
- }
-
- Handle<JSArray> result = factory->NewJSArray(0);
- int32_t length = formatted.length();
- if (length == 0) return result;
-
- std::vector<NumberFormatSpan> regions;
- // Add a "literal" backdrop for the entire string. This will be used if no
- // other region covers some part of the formatted string. It's possible
- // there's another field with exactly the same begin and end as this backdrop,
- // in which case the backdrop's field_id of -1 will give it lower priority.
- regions.push_back(NumberFormatSpan(-1, 0, formatted.length()));
-
- {
- icu::FieldPosition fp;
- while (fp_iter.next(fp)) {
- regions.push_back(NumberFormatSpan(fp.getField(), fp.getBeginIndex(),
- fp.getEndIndex()));
- }
- }
-
- std::vector<NumberFormatSpan> parts = FlattenRegionsToParts(&regions);
-
- int index = 0;
- for (auto it = parts.begin(); it < parts.end(); it++) {
- NumberFormatSpan part = *it;
- Handle<String> field_type_string =
- part.field_id == -1
- ? isolate->factory()->literal_string()
- : IcuNumberFieldIdToNumberType(part.field_id, number, isolate);
- Handle<String> substring;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, substring,
- Intl::ToString(isolate, formatted, part.begin_pos, part.end_pos),
- Object);
- Intl::AddElement(isolate, result, index, field_type_string, substring);
- ++index;
- }
- JSObject::ValidateElements(*result);
-
- return result;
-}
-
-MaybeHandle<Object> FormatDateToParts(Isolate* isolate, icu::DateFormat* format,
- double date_value) {
- Factory* factory = isolate->factory();
-
- icu::UnicodeString formatted;
- icu::FieldPositionIterator fp_iter;
- icu::FieldPosition fp;
- UErrorCode status = U_ZERO_ERROR;
- format->format(date_value, formatted, &fp_iter, status);
- if (U_FAILURE(status)) {
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), Object);
- }
+BUILTIN(V8BreakIteratorSupportedLocalesOf) {
+ HandleScope scope(isolate);
+ Handle<Object> locales = args.atOrUndefined(isolate, 1);
+ Handle<Object> options = args.atOrUndefined(isolate, 2);
- Handle<JSArray> result = factory->NewJSArray(0);
- int32_t length = formatted.length();
- if (length == 0) return result;
-
- int index = 0;
- int32_t previous_end_pos = 0;
- Handle<String> substring;
- while (fp_iter.next(fp)) {
- int32_t begin_pos = fp.getBeginIndex();
- int32_t end_pos = fp.getEndIndex();
-
- if (previous_end_pos < begin_pos) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, substring,
- Intl::ToString(isolate, formatted, previous_end_pos, begin_pos),
- Object);
- Intl::AddElement(isolate, result, index,
- IcuDateFieldIdToDateType(-1, isolate), substring);
- ++index;
- }
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, substring,
- Intl::ToString(isolate, formatted, begin_pos, end_pos), Object);
- Intl::AddElement(isolate, result, index,
- IcuDateFieldIdToDateType(fp.getField(), isolate),
- substring);
- previous_end_pos = end_pos;
- ++index;
- }
- if (previous_end_pos < length) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, substring,
- Intl::ToString(isolate, formatted, previous_end_pos, length), Object);
- Intl::AddElement(isolate, result, index,
- IcuDateFieldIdToDateType(-1, isolate), substring);
- }
- JSObject::ValidateElements(*result);
- return result;
+ RETURN_RESULT_OR_FAILURE(
+ isolate, Intl::SupportedLocalesOf(isolate, ICUService::kBreakIterator,
+ locales, options));
}
-} // namespace
-
-// Flattens a list of possibly-overlapping "regions" to a list of
-// non-overlapping "parts". At least one of the input regions must span the
-// entire space of possible indexes. The regions parameter will sorted in-place
-// according to some criteria; this is done for performance to avoid copying the
-// input.
-std::vector<NumberFormatSpan> FlattenRegionsToParts(
- std::vector<NumberFormatSpan>* regions) {
- // The intention of this algorithm is that it's used to translate ICU "fields"
- // to JavaScript "parts" of a formatted string. Each ICU field and JavaScript
- // part has an integer field_id, which corresponds to something like "grouping
- // separator", "fraction", or "percent sign", and has a begin and end
- // position. Here's a diagram of:
-
- // var nf = new Intl.NumberFormat(['de'], {style:'currency',currency:'EUR'});
- // nf.formatToParts(123456.78);
-
- // : 6
- // input regions: 0000000211 7
- // ('-' means -1): ------------
- // formatted string: "123.456,78 €"
- // output parts: 0006000211-7
-
- // To illustrate the requirements of this algorithm, here's a contrived and
- // convoluted example of inputs and expected outputs:
-
- // : 4
- // : 22 33 3
- // : 11111 22
- // input regions: 0000000 111
- // : ------------
- // formatted string: "abcdefghijkl"
- // output parts: 0221340--231
- // (The characters in the formatted string are irrelevant to this function.)
-
- // We arrange the overlapping input regions like a mountain range where
- // smaller regions are "on top" of larger regions, and we output a birds-eye
- // view of the mountains, so that smaller regions take priority over larger
- // regions.
- std::sort(regions->begin(), regions->end(), cmp_NumberFormatSpan);
- std::vector<size_t> overlapping_region_index_stack;
- // At least one item in regions must be a region spanning the entire string.
- // Due to the sorting above, the first item in the vector will be one of them.
- overlapping_region_index_stack.push_back(0);
- NumberFormatSpan top_region = regions->at(0);
- size_t region_iterator = 1;
- int32_t entire_size = top_region.end_pos;
-
- std::vector<NumberFormatSpan> out_parts;
-
- // The "climber" is a cursor that advances from left to right climbing "up"
- // and "down" the mountains. Whenever the climber moves to the right, that
- // represents an item of output.
- int32_t climber = 0;
- while (climber < entire_size) {
- int32_t next_region_begin_pos;
- if (region_iterator < regions->size()) {
- next_region_begin_pos = regions->at(region_iterator).begin_pos;
- } else {
- // finish off the rest of the input by proceeding to the end.
- next_region_begin_pos = entire_size;
- }
+BUILTIN(NumberFormatSupportedLocalesOf) {
+ HandleScope scope(isolate);
+ Handle<Object> locales = args.atOrUndefined(isolate, 1);
+ Handle<Object> options = args.atOrUndefined(isolate, 2);
- if (climber < next_region_begin_pos) {
- while (top_region.end_pos < next_region_begin_pos) {
- if (climber < top_region.end_pos) {
- // step down
- out_parts.push_back(NumberFormatSpan(top_region.field_id, climber,
- top_region.end_pos));
- climber = top_region.end_pos;
- } else {
- // drop down
- }
- overlapping_region_index_stack.pop_back();
- top_region = regions->at(overlapping_region_index_stack.back());
- }
- if (climber < next_region_begin_pos) {
- // cross a plateau/mesa/valley
- out_parts.push_back(NumberFormatSpan(top_region.field_id, climber,
- next_region_begin_pos));
- climber = next_region_begin_pos;
- }
- }
- if (region_iterator < regions->size()) {
- overlapping_region_index_stack.push_back(region_iterator++);
- top_region = regions->at(overlapping_region_index_stack.back());
- }
- }
- return out_parts;
+ RETURN_RESULT_OR_FAILURE(
+ isolate, Intl::SupportedLocalesOf(isolate, ICUService::kNumberFormat,
+ locales, options));
}
BUILTIN(NumberFormatPrototypeFormatToParts) {
const char* const method = "Intl.NumberFormat.prototype.formatToParts";
HandleScope handle_scope(isolate);
- CHECK_RECEIVER(JSObject, number_format_holder, method);
-
- if (!Intl::IsObjectOfType(isolate, number_format_holder,
- Intl::Type::kNumberFormat)) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate,
- NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
- isolate->factory()->NewStringFromAsciiChecked(method),
- number_format_holder));
- }
+ CHECK_RECEIVER(JSNumberFormat, number_format, method);
Handle<Object> x;
if (args.length() >= 2) {
@@ -460,12 +163,33 @@ BUILTIN(NumberFormatPrototypeFormatToParts) {
x = isolate->factory()->nan_value();
}
- icu::DecimalFormat* number_format =
- NumberFormat::UnpackNumberFormat(number_format_holder);
- CHECK_NOT_NULL(number_format);
+ RETURN_RESULT_OR_FAILURE(isolate, JSNumberFormat::FormatToParts(
+ isolate, number_format, x->Number()));
+}
+
+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, FormatNumberToParts(isolate, number_format, x->Number()));
+ isolate, Intl::SupportedLocalesOf(isolate, ICUService::kDateFormat,
+ locales, options));
}
BUILTIN(DateTimeFormatPrototypeFormatToParts) {
@@ -474,13 +198,14 @@ BUILTIN(DateTimeFormatPrototypeFormatToParts) {
CHECK_RECEIVER(JSObject, date_format_holder, method);
Factory* factory = isolate->factory();
- if (!Intl::IsObjectOfType(isolate, date_format_holder,
- Intl::Type::kDateTimeFormat)) {
+ 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)) {
@@ -496,12 +221,142 @@ BUILTIN(DateTimeFormatPrototypeFormatToParts) {
isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
}
- icu::SimpleDateFormat* date_format =
- DateFormat::UnpackDateFormat(date_format_holder);
- CHECK_NOT_NULL(date_format);
+ RETURN_RESULT_OR_FAILURE(
+ isolate, JSDateTimeFormat::FormatToParts(isolate, dtf, date_value));
+}
+
+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* FormatConstructor(BuiltinArguments args, Isolate* isolate,
+ Handle<Object> constructor, const char* method) {
+ 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<JSObject> format_obj;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, format_obj,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
+ Handle<T> format = Handle<T>::cast(format_obj);
+
+ // 3. Perform ? Initialize<T>(Format, locales, options).
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, format, T::Initialize(isolate, format, locales, options));
+ // 4. Let this be the this value.
+ 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.
+ // Call the instanceof function
+ Handle<Object> is_instance_of_obj;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, is_instance_of_obj,
+ Object::InstanceOf(isolate, receiver, constructor));
+
+ // Get the boolean value of the result
+ bool is_instance_of = is_instance_of_obj->BooleanValue(isolate);
+
+ if (args.new_target()->IsUndefined(isolate) && is_instance_of) {
+ 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,
+ kThrowOnError);
+ MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
+ CHECK(success.FromJust());
+ // b. b. Return this.
+ return *receiver;
+ }
+ // 6. Return format.
+ return *format;
+}
+
+} // namespace
+
+BUILTIN(NumberFormatConstructor) {
+ HandleScope scope(isolate);
+
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kNumberFormat);
+
+ return FormatConstructor<JSNumberFormat>(
+ args, isolate, 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_RESULT_OR_FAILURE(isolate,
- FormatDateToParts(isolate, date_format, date_value));
+ return *JSNumberFormat::ResolvedOptions(isolate, number_format);
}
BUILTIN(NumberFormatPrototypeFormatNumber) {
@@ -513,17 +368,12 @@ BUILTIN(NumberFormatPrototypeFormatNumber) {
CHECK_RECEIVER(JSReceiver, receiver, method);
// 3. Let nf be ? UnwrapNumberFormat(nf).
- Handle<JSObject> number_format_holder;
+ Handle<JSNumberFormat> number_format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, number_format_holder,
- NumberFormat::Unwrap(isolate, receiver, method));
+ isolate, number_format,
+ JSNumberFormat::UnwrapNumberFormat(isolate, receiver));
- DCHECK(Intl::IsObjectOfType(isolate, number_format_holder,
- Intl::Type::kNumberFormat));
-
- Handle<Object> bound_format = Handle<Object>(
- number_format_holder->GetEmbedderField(NumberFormat::kBoundFormatIndex),
- isolate);
+ Handle<Object> bound_format(number_format->bound_format(), isolate);
// 4. If nf.[[BoundFormat]] is undefined, then
if (!bound_format->IsUndefined(isolate)) {
@@ -532,29 +382,11 @@ BUILTIN(NumberFormatPrototypeFormatNumber) {
return *bound_format;
}
- Handle<NativeContext> native_context(isolate->context()->native_context(),
- isolate);
-
- Handle<Context> context = isolate->factory()->NewBuiltinContext(
- native_context, NumberFormat::ContextSlot::kLength);
-
- // 4. b. Set F.[[NumberFormat]] to nf.
- context->set(NumberFormat::ContextSlot::kNumberFormat, *number_format_holder);
-
- Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo>(
- native_context->number_format_internal_format_number_shared_fun(),
- isolate);
-
- Handle<Map> map = isolate->strict_function_without_prototype_map();
-
- // 4. a. Let F be a new built-in function object as defined in
- // Number Format Functions (11.1.4).
- Handle<JSFunction> new_bound_format_function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
+ Handle<JSFunction> new_bound_format_function = CreateBoundFunction(
+ isolate, number_format, Builtins::kNumberFormatInternalFormatNumber, 1);
// 4. c. Set nf.[[BoundFormat]] to F.
- number_format_holder->SetEmbedderField(NumberFormat::kBoundFormatIndex,
- *new_bound_format_function);
+ number_format->set_bound_format(*new_bound_format_function);
// 5. Return nf.[[BoundFormat]].
return *new_bound_format_function;
@@ -566,14 +398,12 @@ BUILTIN(NumberFormatInternalFormatNumber) {
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let nf be F.[[NumberFormat]].
- Handle<JSObject> number_format_holder = Handle<JSObject>(
- JSObject::cast(context->get(NumberFormat::ContextSlot::kNumberFormat)),
- isolate);
-
// 2. Assert: Type(nf) is Object and nf has an
// [[InitializedNumberFormat]] internal slot.
- DCHECK(Intl::IsObjectOfType(isolate, number_format_holder,
- Intl::Type::kNumberFormat));
+ 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);
@@ -590,8 +420,18 @@ BUILTIN(NumberFormatInternalFormatNumber) {
double number = number_obj->Number();
// Return FormatNumber(nf, x).
- RETURN_RESULT_OR_FAILURE(isolate, NumberFormat::FormatNumber(
- isolate, number_format_holder, number));
+ RETURN_RESULT_OR_FAILURE(
+ isolate, JSNumberFormat::FormatNumber(isolate, number_format, number));
+}
+
+BUILTIN(DateTimeFormatConstructor) {
+ HandleScope scope(isolate);
+
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kDateTimeFormat);
+
+ return FormatConstructor<JSDateTimeFormat>(
+ args, isolate, isolate->intl_date_time_format_function(),
+ "Intl.DateTimeFormat");
}
BUILTIN(DateTimeFormatPrototypeFormat) {
@@ -603,16 +443,12 @@ BUILTIN(DateTimeFormatPrototypeFormat) {
CHECK_RECEIVER(JSReceiver, receiver, method);
// 3. Let dtf be ? UnwrapDateTimeFormat(dtf).
- Handle<JSObject> date_format_holder;
+ Handle<JSDateTimeFormat> format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, date_format_holder,
- DateFormat::Unwrap(isolate, receiver, method));
- DCHECK(Intl::IsObjectOfType(isolate, date_format_holder,
- Intl::Type::kDateTimeFormat));
+ isolate, format,
+ JSDateTimeFormat::UnwrapDateTimeFormat(isolate, receiver));
- Handle<Object> bound_format = Handle<Object>(
- date_format_holder->GetEmbedderField(DateFormat::kBoundFormatIndex),
- isolate);
+ Handle<Object> bound_format = Handle<Object>(format->bound_format(), isolate);
// 4. If dtf.[[BoundFormat]] is undefined, then
if (!bound_format->IsUndefined(isolate)) {
@@ -621,26 +457,11 @@ BUILTIN(DateTimeFormatPrototypeFormat) {
return *bound_format;
}
- Handle<NativeContext> native_context(isolate->context()->native_context(),
- isolate);
- Handle<Context> context = isolate->factory()->NewBuiltinContext(
- native_context, DateFormat::ContextSlot::kLength);
-
- // 4.b. Set F.[[DateTimeFormat]] to dtf.
- context->set(DateFormat::ContextSlot::kDateFormat, *date_format_holder);
-
- Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo>(
- native_context->date_format_internal_format_shared_fun(), isolate);
- Handle<Map> map = isolate->strict_function_without_prototype_map();
-
- // 4.a. Let F be a new built-in function object as defined in DateTime Format
- // Functions (12.1.5).
- Handle<JSFunction> new_bound_format_function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
+ Handle<JSFunction> new_bound_format_function = CreateBoundFunction(
+ isolate, format, Builtins::kDateTimeFormatInternalFormat, 1);
// 4.c. Set dtf.[[BoundFormat]] to F.
- date_format_holder->SetEmbedderField(DateFormat::kBoundFormatIndex,
- *new_bound_format_function);
+ format->set_bound_format(*new_bound_format_function);
// 5. Return dtf.[[BoundFormat]].
return *new_bound_format_function;
@@ -651,23 +472,24 @@ BUILTIN(DateTimeFormatInternalFormat) {
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let dtf be F.[[DateTimeFormat]].
- Handle<JSObject> date_format_holder = Handle<JSObject>(
- JSObject::cast(context->get(DateFormat::ContextSlot::kDateFormat)),
- isolate);
-
// 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
// internal slot.
- DCHECK(Intl::IsObjectOfType(isolate, date_format_holder,
- Intl::Type::kDateTimeFormat));
+ 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, DateFormat::DateTimeFormat(isolate, date_format_holder, date));
+ RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::DateTimeFormat(
+ isolate, date_format_holder, date));
}
BUILTIN(ListFormatConstructor) {
HandleScope scope(isolate);
+
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kListFormat);
+
// 1. If NewTarget is undefined, throw a TypeError exception.
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
@@ -682,8 +504,9 @@ BUILTIN(ListFormatConstructor) {
Handle<JSObject> result;
// 2. Let listFormat be OrdinaryCreateFromConstructor(NewTarget,
// "%ListFormatPrototype%").
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- JSObject::New(target, new_target));
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
Handle<JSListFormat> format = Handle<JSListFormat>::cast(result);
format->set_flags(0);
@@ -691,8 +514,8 @@ BUILTIN(ListFormatConstructor) {
Handle<Object> options = args.atOrUndefined(isolate, 2);
// 3. Return InitializeListFormat(listFormat, locales, options).
- RETURN_RESULT_OR_FAILURE(isolate, JSListFormat::InitializeListFormat(
- isolate, format, locales, options));
+ RETURN_RESULT_OR_FAILURE(
+ isolate, JSListFormat::Initialize(isolate, format, locales, options));
}
BUILTIN(ListFormatPrototypeResolvedOptions) {
@@ -702,42 +525,62 @@ BUILTIN(ListFormatPrototypeResolvedOptions) {
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, ICUService::kListFormatter,
+ locales, options));
+}
+
namespace {
MaybeHandle<JSLocale> CreateLocale(Isolate* isolate,
Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
Handle<Object> tag, Handle<Object> options) {
- Handle<JSObject> result;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
- JSObject::New(constructor, new_target), JSLocale);
-
- // First parameter is a locale, as a string/object. Can't be empty.
+ Handle<JSObject> locale;
+ // 6. Let locale be ? OrdinaryCreateFromConstructor(NewTarget,
+ // %LocalePrototype%, internalSlotsList).
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, locale,
+ JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
+ JSLocale);
+
+ // 7. If Type(tag) is not String or Object, throw a TypeError exception.
if (!tag->IsString() && !tag->IsJSReceiver()) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty),
JSLocale);
}
Handle<String> locale_string;
+ // 8. If Type(tag) is Object and tag has an [[InitializedLocale]] internal
+ // slot, then
if (tag->IsJSLocale() && Handle<JSLocale>::cast(tag)->locale()->IsString()) {
+ // a. Let tag be tag.[[Locale]].
locale_string =
Handle<String>(Handle<JSLocale>::cast(tag)->locale(), isolate);
- } else {
+ } else { // 9. Else,
+ // a. Let tag be ? ToString(tag).
ASSIGN_RETURN_ON_EXCEPTION(isolate, locale_string,
Object::ToString(isolate, tag), JSLocale);
}
Handle<JSReceiver> options_object;
- if (options->IsNullOrUndefined(isolate)) {
- // Make empty options bag.
+ // 10. If options is undefined, then
+ if (options->IsUndefined(isolate)) {
+ // a. Let options be ! ObjectCreate(null).
options_object = isolate->factory()->NewJSObjectWithNullProto();
- } else {
+ } else { // 11. Else
+ // a. Let options be ? ToObject(options).
ASSIGN_RETURN_ON_EXCEPTION(isolate, options_object,
Object::ToObject(isolate, options), JSLocale);
}
- return JSLocale::InitializeLocale(isolate, Handle<JSLocale>::cast(result),
- locale_string, options_object);
+ return JSLocale::Initialize(isolate, Handle<JSLocale>::cast(locale),
+ locale_string, options_object);
}
} // namespace
@@ -745,6 +588,9 @@ MaybeHandle<JSLocale> CreateLocale(Isolate* isolate,
// 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,
@@ -786,186 +632,17 @@ BUILTIN(LocalePrototypeMinimize) {
isolate->factory()->NewJSObjectWithNullProto()));
}
-namespace {
-
-MaybeHandle<JSArray> GenerateRelativeTimeFormatParts(
- Isolate* isolate, icu::UnicodeString formatted,
- icu::UnicodeString integer_part, Handle<String> unit) {
- Factory* factory = isolate->factory();
- Handle<JSArray> array = factory->NewJSArray(0);
- int32_t found = formatted.indexOf(integer_part);
-
- Handle<String> substring;
- if (found < 0) {
- // Cannot find the integer_part in the formatted.
- // Return [{'type': 'literal', 'value': formatted}]
- ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
- Intl::ToString(isolate, formatted), JSArray);
- Intl::AddElement(isolate, array,
- 0, // index
- factory->literal_string(), // field_type_string
- substring);
- } else {
- // Found the formatted integer in the result.
- int index = 0;
-
- // array.push({
- // 'type': 'literal',
- // 'value': formatted.substring(0, found)})
- if (found > 0) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
- Intl::ToString(isolate, formatted, 0, found),
- JSArray);
- Intl::AddElement(isolate, array, index++,
- factory->literal_string(), // field_type_string
- substring);
- }
-
- // array.push({
- // 'type': 'integer',
- // 'value': formatted.substring(found, found + integer_part.length),
- // 'unit': unit})
- ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
- Intl::ToString(isolate, formatted, found,
- found + integer_part.length()),
- JSArray);
- Intl::AddElement(isolate, array, index++,
- factory->integer_string(), // field_type_string
- substring, factory->unit_string(), unit);
-
- // array.push({
- // 'type': 'literal',
- // 'value': formatted.substring(
- // found + integer_part.length, formatted.length)})
- if (found + integer_part.length() < formatted.length()) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, substring,
- Intl::ToString(isolate, formatted, found + integer_part.length(),
- formatted.length()),
- JSArray);
- Intl::AddElement(isolate, array, index,
- factory->literal_string(), // field_type_string
- substring);
- }
- }
- return array;
-}
-
-bool GetURelativeDateTimeUnit(Handle<String> unit,
- URelativeDateTimeUnit* unit_enum) {
- std::unique_ptr<char[]> unit_str = unit->ToCString();
- if ((strcmp("second", unit_str.get()) == 0) ||
- (strcmp("seconds", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_SECOND;
- } else if ((strcmp("minute", unit_str.get()) == 0) ||
- (strcmp("minutes", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_MINUTE;
- } else if ((strcmp("hour", unit_str.get()) == 0) ||
- (strcmp("hours", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_HOUR;
- } else if ((strcmp("day", unit_str.get()) == 0) ||
- (strcmp("days", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_DAY;
- } else if ((strcmp("week", unit_str.get()) == 0) ||
- (strcmp("weeks", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_WEEK;
- } else if ((strcmp("month", unit_str.get()) == 0) ||
- (strcmp("months", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_MONTH;
- } else if ((strcmp("quarter", unit_str.get()) == 0) ||
- (strcmp("quarters", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_QUARTER;
- } else if ((strcmp("year", unit_str.get()) == 0) ||
- (strcmp("years", unit_str.get()) == 0)) {
- *unit_enum = UDAT_REL_UNIT_YEAR;
- } else {
- return false;
- }
- return true;
-}
-
-MaybeHandle<Object> RelativeTimeFormatPrototypeFormatCommon(
- BuiltinArguments args, Isolate* isolate,
- Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
- bool to_parts) {
- Factory* factory = isolate->factory();
- Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
- Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
-
- // 3. Let value be ? ToNumber(value).
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::ToNumber(isolate, value_obj), Object);
- double number = value->Number();
- // 4. Let unit be ? ToString(unit).
- Handle<String> unit;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, unit, Object::ToString(isolate, unit_obj),
- Object);
-
- // 4. If isFinite(value) is false, then throw a RangeError exception.
- if (!std::isfinite(number)) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kNotFiniteNumber,
- isolate->factory()->NewStringFromAsciiChecked(func_name)),
- Object);
- }
-
- icu::RelativeDateTimeFormatter* formatter =
- JSRelativeTimeFormat::UnpackFormatter(format_holder);
- CHECK_NOT_NULL(formatter);
-
- URelativeDateTimeUnit unit_enum;
- if (!GetURelativeDateTimeUnit(unit, &unit_enum)) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kInvalidUnit,
- isolate->factory()->NewStringFromAsciiChecked(func_name),
- unit),
- Object);
- }
-
- UErrorCode status = U_ZERO_ERROR;
- icu::UnicodeString formatted;
- if (unit_enum == UDAT_REL_UNIT_QUARTER) {
- // ICU have not yet implement UDAT_REL_UNIT_QUARTER.
- } else {
- if (format_holder->numeric() == JSRelativeTimeFormat::Numeric::ALWAYS) {
- formatter->formatNumeric(number, unit_enum, formatted, status);
- } else {
- DCHECK_EQ(JSRelativeTimeFormat::Numeric::AUTO, format_holder->numeric());
- formatter->format(number, unit_enum, formatted, status);
- }
- }
-
- if (U_FAILURE(status)) {
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), Object);
- }
-
- if (to_parts) {
- icu::UnicodeString integer;
- icu::FieldPosition pos;
- formatter->getNumberFormat().format(std::abs(number), integer, pos, status);
- if (U_FAILURE(status)) {
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError),
- Object);
- }
-
- Handle<JSArray> elements;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, elements,
- GenerateRelativeTimeFormatParts(isolate, formatted, integer, unit),
- Object);
- return elements;
- }
+BUILTIN(RelativeTimeFormatSupportedLocalesOf) {
+ HandleScope scope(isolate);
+ Handle<Object> locales = args.atOrUndefined(isolate, 1);
+ Handle<Object> options = args.atOrUndefined(isolate, 2);
- return factory->NewStringFromTwoByte(Vector<const uint16_t>(
- reinterpret_cast<const uint16_t*>(formatted.getBuffer()),
- formatted.length()));
+ RETURN_RESULT_OR_FAILURE(
+ isolate,
+ Intl::SupportedLocalesOf(isolate, ICUService::kRelativeDateTimeFormatter,
+ locales, options));
}
-} // namespace
-
BUILTIN(RelativeTimeFormatPrototypeFormat) {
HandleScope scope(isolate);
// 1. Let relativeTimeFormat be the this value.
@@ -974,9 +651,12 @@ BUILTIN(RelativeTimeFormatPrototypeFormat) {
// true, throw a TypeError exception.
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.format");
- RETURN_RESULT_OR_FAILURE(isolate,
- RelativeTimeFormatPrototypeFormatCommon(
- args, isolate, format_holder, "format", false));
+ 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, "format", false));
}
BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
@@ -987,9 +667,11 @@ BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
// true, throw a TypeError exception.
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.formatToParts");
- RETURN_RESULT_OR_FAILURE(
- isolate, RelativeTimeFormatPrototypeFormatCommon(
- args, isolate, format_holder, "formatToParts", true));
+ 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, "formatToParts", true));
}
// Locale getters.
@@ -1033,7 +715,7 @@ BUILTIN(LocalePrototypeCaseFirst) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.caseFirst");
- return locale_holder->case_first();
+ return *(locale_holder->CaseFirstAsString());
}
BUILTIN(LocalePrototypeCollation) {
@@ -1047,14 +729,23 @@ BUILTIN(LocalePrototypeHourCycle) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.hourCycle");
- return locale_holder->hour_cycle();
+ return *(locale_holder->HourCycleAsString());
}
BUILTIN(LocalePrototypeNumeric) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.numeric");
- return locale_holder->numeric();
+ switch (locale_holder->numeric()) {
+ case JSLocale::Numeric::TRUE_VALUE:
+ return *(isolate->factory()->true_value());
+ case JSLocale::Numeric::FALSE_VALUE:
+ return *(isolate->factory()->false_value());
+ case JSLocale::Numeric::NOTSET:
+ return *(isolate->factory()->undefined_value());
+ case JSLocale::Numeric::COUNT:
+ UNREACHABLE();
+ }
}
BUILTIN(LocalePrototypeNumberingSystem) {
@@ -1074,6 +765,9 @@ BUILTIN(LocalePrototypeToString) {
BUILTIN(RelativeTimeFormatConstructor) {
HandleScope scope(isolate);
+
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kRelativeTimeFormat);
+
// 1. If NewTarget is undefined, throw a TypeError exception.
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
@@ -1089,8 +783,9 @@ BUILTIN(RelativeTimeFormatConstructor) {
// 2. Let relativeTimeFormat be
// ! OrdinaryCreateFromConstructor(NewTarget,
// "%RelativeTimeFormatPrototype%").
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- JSObject::New(target, new_target));
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
Handle<JSRelativeTimeFormat> format =
Handle<JSRelativeTimeFormat>::cast(result);
format->set_flags(0);
@@ -1100,9 +795,8 @@ BUILTIN(RelativeTimeFormatConstructor) {
// 3. Return ? InitializeRelativeTimeFormat(relativeTimeFormat, locales,
// options).
- RETURN_RESULT_OR_FAILURE(isolate,
- JSRelativeTimeFormat::InitializeRelativeTimeFormat(
- isolate, format, locales, options));
+ RETURN_RESULT_OR_FAILURE(isolate, JSRelativeTimeFormat::Initialize(
+ isolate, format, locales, options));
}
BUILTIN(RelativeTimeFormatPrototypeResolvedOptions) {
@@ -1114,7 +808,11 @@ BUILTIN(RelativeTimeFormatPrototypeResolvedOptions) {
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)));
@@ -1122,7 +820,11 @@ BUILTIN(StringPrototypeToLocaleLowerCase) {
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)));
@@ -1131,6 +833,8 @@ BUILTIN(StringPrototypeToLocaleUpperCase) {
BUILTIN(PluralRulesConstructor) {
HandleScope scope(isolate);
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kPluralRules);
+
// 1. If NewTarget is undefined, throw a TypeError exception.
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
@@ -1152,19 +856,61 @@ BUILTIN(PluralRulesConstructor) {
// [[MinimumFractionDigits]], [[MaximumFractionDigits]],
// [[MinimumSignificantDigits]], [[MaximumSignificantDigits]] »).
Handle<JSObject> plural_rules_obj;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, plural_rules_obj,
- JSObject::New(target, new_target));
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, plural_rules_obj,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
Handle<JSPluralRules> plural_rules =
Handle<JSPluralRules>::cast(plural_rules_obj);
// 3. Return ? InitializePluralRules(pluralRules, locales, options).
RETURN_RESULT_OR_FAILURE(
- isolate, JSPluralRules::InitializePluralRules(isolate, plural_rules,
- locales, options));
+ isolate,
+ JSPluralRules::Initialize(isolate, plural_rules, locales, options));
+}
+
+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, ICUService::kPluralRules,
+ locales, options));
}
BUILTIN(CollatorConstructor) {
HandleScope scope(isolate);
+
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kCollator);
+
Handle<JSReceiver> new_target;
// 1. If NewTarget is undefined, let newTarget be the active
// function object, else let newTarget be NewTarget.
@@ -1183,14 +929,31 @@ BUILTIN(CollatorConstructor) {
// 5. Let collator be ? OrdinaryCreateFromConstructor(newTarget,
// "%CollatorPrototype%", internalSlotsList).
Handle<JSObject> collator_obj;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, collator_obj,
- JSObject::New(target, new_target));
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, collator_obj,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
Handle<JSCollator> collator = Handle<JSCollator>::cast(collator_obj);
- collator->set_flags(0);
// 6. Return ? InitializeCollator(collator, locales, options).
- RETURN_RESULT_OR_FAILURE(isolate, JSCollator::InitializeCollator(
- isolate, collator, locales, options));
+ RETURN_RESULT_OR_FAILURE(
+ isolate, JSCollator::Initialize(isolate, collator, locales, options));
+}
+
+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, ICUService::kCollator, locales,
+ options));
}
BUILTIN(CollatorPrototypeCompare) {
@@ -1211,21 +974,8 @@ BUILTIN(CollatorPrototypeCompare) {
return *bound_compare;
}
- Handle<NativeContext> native_context(isolate->context()->native_context(),
- isolate);
- Handle<Context> context = isolate->factory()->NewBuiltinContext(
- native_context, JSCollator::ContextSlot::kLength);
-
- // 4.b. Set F.[[Collator]] to collator.
- context->set(JSCollator::ContextSlot::kCollator, *collator);
-
- Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo>(
- native_context->collator_internal_compare_shared_fun(), isolate);
- Handle<Map> map = isolate->strict_function_without_prototype_map();
-
- // 4.a. Let F be a new built-in function object as defined in 10.3.3.1.
- Handle<JSFunction> new_bound_compare_function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
+ 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);
@@ -1242,7 +992,8 @@ BUILTIN(CollatorInternalCompare) {
// 2. Assert: Type(collator) is Object and collator has an
// [[InitializedCollator]] internal slot.
Handle<JSCollator> collator_holder = Handle<JSCollator>(
- JSCollator::cast(context->get(JSCollator::ContextSlot::kCollator)),
+ JSCollator::cast(context->get(
+ static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
// 3. If x is not provided, let x be undefined.
@@ -1263,71 +1014,280 @@ BUILTIN(CollatorInternalCompare) {
return *Intl::CompareStrings(isolate, collator_holder, string_x, string_y);
}
-BUILTIN(BreakIteratorPrototypeAdoptText) {
- const char* const method = "get Intl.v8BreakIterator.prototype.adoptText";
+BUILTIN(SegmenterConstructor) {
HandleScope scope(isolate);
- CHECK_RECEIVER(JSObject, break_iterator_holder, method);
- if (!Intl::IsObjectOfType(isolate, break_iterator_holder,
- Intl::Type::kBreakIterator)) {
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kSegmenter);
+
+ // 1. If NewTarget is undefined, throw a TypeError exception.
+ if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
- isolate,
- NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
- isolate->factory()->NewStringFromAsciiChecked(method),
- break_iterator_holder));
+ isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
+ isolate->factory()->NewStringFromStaticChars(
+ "Intl.Segmenter")));
}
+ // [[Construct]]
+ Handle<JSFunction> target = args.target();
+ Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
- Handle<Object> bound_adopt_text =
- Handle<Object>(break_iterator_holder->GetEmbedderField(
- V8BreakIterator::kBoundAdoptTextIndex),
- isolate);
+ Handle<JSObject> result;
+ // 2. Let segmenter be OrdinaryCreateFromConstructor(NewTarget,
+ // "%SegmenterPrototype%").
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
+ Handle<JSSegmenter> segmenter = Handle<JSSegmenter>::cast(result);
+ segmenter->set_flags(0);
- if (!bound_adopt_text->IsUndefined(isolate)) {
- DCHECK(bound_adopt_text->IsJSFunction());
- return *bound_adopt_text;
+ Handle<Object> locales = args.atOrUndefined(isolate, 1);
+ Handle<Object> options = args.atOrUndefined(isolate, 2);
+
+ RETURN_RESULT_OR_FAILURE(
+ isolate, JSSegmenter::Initialize(isolate, segmenter, locales, options));
+}
+
+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, ICUService::kSegmenter,
+ locales, options));
+}
+
+BUILTIN(SegmenterPrototypeResolvedOptions) {
+ HandleScope scope(isolate);
+ CHECK_RECEIVER(JSSegmenter, segmenter_holder,
+ "Intl.Segmenter.prototype.resolvedOptions");
+ return *JSSegmenter::ResolvedOptions(isolate, segmenter_holder);
+}
+
+BUILTIN(V8BreakIteratorConstructor) {
+ HandleScope scope(isolate);
+ Handle<JSReceiver> new_target;
+
+ if (args.new_target()->IsUndefined(isolate)) {
+ new_target = args.target();
+ } else {
+ new_target = Handle<JSReceiver>::cast(args.new_target());
}
- Handle<NativeContext> native_context(isolate->context()->native_context(),
- isolate);
- Handle<Context> context = isolate->factory()->NewBuiltinContext(
- native_context, static_cast<int>(V8BreakIterator::ContextSlot::kLength));
+ // [[Construct]]
+ Handle<JSFunction> target = args.target();
- context->set(static_cast<int>(V8BreakIterator::ContextSlot::kV8BreakIterator),
- *break_iterator_holder);
+ Handle<Object> locales = args.atOrUndefined(isolate, 1);
+ Handle<Object> options = args.atOrUndefined(isolate, 2);
- Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo>(
- native_context->break_iterator_internal_adopt_text_shared_fun(), isolate);
- Handle<Map> map = isolate->strict_function_without_prototype_map();
+ Handle<JSObject> break_iterator_obj;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, break_iterator_obj,
+ JSObject::New(target, new_target, Handle<AllocationSite>::null()));
+ Handle<JSV8BreakIterator> break_iterator =
+ Handle<JSV8BreakIterator>::cast(break_iterator_obj);
- Handle<JSFunction> new_bound_adopt_text_function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
+ RETURN_RESULT_OR_FAILURE(
+ isolate,
+ JSV8BreakIterator::Initialize(isolate, break_iterator, locales, options));
+}
- break_iterator_holder->SetEmbedderField(V8BreakIterator::kBoundAdoptTextIndex,
- *new_bound_adopt_text_function);
+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(BreakIteratorInternalAdoptText) {
+BUILTIN(V8BreakIteratorInternalAdoptText) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
- Handle<JSObject> break_iterator_holder = Handle<JSObject>(
- JSObject::cast(context->get(
- static_cast<int>(V8BreakIterator::ContextSlot::kV8BreakIterator))),
+ Handle<JSV8BreakIterator> break_iterator_holder = Handle<JSV8BreakIterator>(
+ JSV8BreakIterator::cast(context->get(
+ static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
- DCHECK(Intl::IsObjectOfType(isolate, break_iterator_holder,
- Intl::Type::kBreakIterator));
-
Handle<Object> input_text = args.atOrUndefined(isolate, 1);
Handle<String> text;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, text,
Object::ToString(isolate, input_text));
- V8BreakIterator::AdoptText(isolate, break_iterator_holder, text);
+ JSV8BreakIterator::AdoptText(isolate, break_iterator_holder, 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_holder, method);
+
+ Handle<Object> bound_first(break_iterator_holder->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_holder,
+ Builtins::kV8BreakIteratorInternalFirst, 0);
+ break_iterator_holder->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_holder = Handle<JSV8BreakIterator>(
+ JSV8BreakIterator::cast(context->get(
+ static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
+ isolate);
+
+ icu::BreakIterator* break_iterator =
+ break_iterator_holder->break_iterator()->raw();
+ CHECK_NOT_NULL(break_iterator);
+
+ return *isolate->factory()->NewNumberFromInt(break_iterator->first());
+}
+
+BUILTIN(V8BreakIteratorPrototypeNext) {
+ const char* const method = "get Intl.v8BreakIterator.prototype.next";
+ HandleScope scope(isolate);
+
+ CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method);
+
+ Handle<Object> bound_next(break_iterator_holder->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_holder,
+ Builtins::kV8BreakIteratorInternalNext, 0);
+ break_iterator_holder->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_holder = Handle<JSV8BreakIterator>(
+ JSV8BreakIterator::cast(context->get(
+ static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
+ isolate);
+
+ icu::BreakIterator* break_iterator =
+ break_iterator_holder->break_iterator()->raw();
+ CHECK_NOT_NULL(break_iterator);
+
+ return *isolate->factory()->NewNumberFromInt(break_iterator->next());
+}
+
+BUILTIN(V8BreakIteratorPrototypeCurrent) {
+ const char* const method = "get Intl.v8BreakIterator.prototype.current";
+ HandleScope scope(isolate);
+
+ CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method);
+
+ Handle<Object> bound_current(break_iterator_holder->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_holder,
+ Builtins::kV8BreakIteratorInternalCurrent, 0);
+ break_iterator_holder->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_holder = Handle<JSV8BreakIterator>(
+ JSV8BreakIterator::cast(context->get(
+ static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
+ isolate);
+
+ icu::BreakIterator* break_iterator =
+ break_iterator_holder->break_iterator()->raw();
+ CHECK_NOT_NULL(break_iterator);
+
+ return *isolate->factory()->NewNumberFromInt(break_iterator->current());
+}
+
+BUILTIN(V8BreakIteratorPrototypeBreakType) {
+ const char* const method = "get Intl.v8BreakIterator.prototype.breakType";
+ HandleScope scope(isolate);
+
+ CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method);
+
+ Handle<Object> bound_break_type(break_iterator_holder->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_holder,
+ Builtins::kV8BreakIteratorInternalBreakType, 0);
+ break_iterator_holder->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_holder = Handle<JSV8BreakIterator>(
+ JSV8BreakIterator::cast(context->get(
+ static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
+ isolate);
+
+ icu::BreakIterator* break_iterator =
+ break_iterator_holder->break_iterator()->raw();
+ CHECK_NOT_NULL(break_iterator);
+
+ int32_t status = break_iterator->getRuleStatus();
+ // Keep return values in sync with JavaScript BreakType enum.
+ if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
+ return *isolate->factory()->NewStringFromStaticChars("none");
+ } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
+ return ReadOnlyRoots(isolate).number_string();
+ } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
+ return *isolate->factory()->NewStringFromStaticChars("letter");
+ } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
+ return *isolate->factory()->NewStringFromStaticChars("kana");
+ } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
+ return *isolate->factory()->NewStringFromStaticChars("ideo");
+ } else {
+ return *isolate->factory()->NewStringFromStaticChars("unknown");
+ }
+}
+
} // namespace internal
} // namespace v8