Reland "[intl] Implement DurationFormat"

This is a reland of commit 39f0b4ad8a

Fix pdf_unittests linking problem by include "src/objects/managed-inl.h"
and "src/objects/objects-inl.h" in src/objects/js-duration-format.cc

Original change's description:
> [intl] Implement DurationFormat
>
> Spec Text: https://tc39.es/proposal-intl-duration-format
> Spec Repo: https://github.com/tc39/proposal-intl-duration-format
> Design Doc:
> https://docs.google.com/document/d/1UMwkeeiqVyVNhNW8CS1vwN9g2cIH0AryaU16DT-vGg0/edit#
>
>
> Bug: v8:11660
> Change-Id: Icd14e0ee4d386a5d84ccd624fc2a8bb707cc7870
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3833436
> Reviewed-by: Adam Klein <adamk@chromium.org>
> Reviewed-by: Shu-yu Guo <syg@chromium.org>
> Commit-Queue: Frank Tang <ftang@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#83503}

Bug: v8:11660
Change-Id: I851650b2d630badbd0bff6b17b3e41b877a2eb8f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3929754
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83525}
This commit is contained in:
Frank Tang 2022-10-04 11:41:01 -07:00 committed by V8 LUCI CQ
parent d7b4cf552c
commit cc40beb19a
32 changed files with 1419 additions and 205 deletions

View File

@ -981,6 +981,7 @@ filegroup(
"src/objects/js-collator.tq",
"src/objects/js-date-time-format.tq",
"src/objects/js-display-names.tq",
"src/objects/js-duration-format.tq",
"src/objects/js-list-format.tq",
"src/objects/js-locale.tq",
"src/objects/js-number-format.tq",
@ -2605,6 +2606,9 @@ filegroup(
"src/objects/js-display-names.cc",
"src/objects/js-display-names.h",
"src/objects/js-display-names-inl.h",
"src/objects/js-duration-format.cc",
"src/objects/js-duration-format.h",
"src/objects/js-duration-format-inl.h",
"src/objects/js-list-format.cc",
"src/objects/js-list-format.h",
"src/objects/js-list-format-inl.h",

View File

@ -1856,6 +1856,7 @@ if (v8_enable_i18n_support) {
"src/objects/js-collator.tq",
"src/objects/js-date-time-format.tq",
"src/objects/js-display-names.tq",
"src/objects/js-duration-format.tq",
"src/objects/js-list-format.tq",
"src/objects/js-locale.tq",
"src/objects/js-number-format.tq",
@ -3669,6 +3670,8 @@ v8_header_set("v8_internal_headers") {
"src/objects/js-date-time-format.h",
"src/objects/js-display-names-inl.h",
"src/objects/js-display-names.h",
"src/objects/js-duration-format-inl.h",
"src/objects/js-duration-format.h",
"src/objects/js-list-format-inl.h",
"src/objects/js-list-format.h",
"src/objects/js-locale-inl.h",
@ -4530,6 +4533,7 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/js-collator.cc",
"src/objects/js-date-time-format.cc",
"src/objects/js-display-names.cc",
"src/objects/js-duration-format.cc",
"src/objects/js-function.cc",
"src/objects/js-list-format.cc",
"src/objects/js-locale.cc",
@ -5118,6 +5122,7 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/js-collator.cc",
"src/objects/js-date-time-format.cc",
"src/objects/js-display-names.cc",
"src/objects/js-duration-format.cc",
"src/objects/js-list-format.cc",
"src/objects/js-locale.cc",
"src/objects/js-number-format.cc",

View File

@ -536,6 +536,7 @@ class V8_EXPORT Isolate {
kFunctionPrototypeCaller = 114,
kTurboFanOsrCompileStarted = 115,
kAsyncStackTaggingCreateTaskCall = 116,
kDurationFormat = 117,
// If you add new values here, you'll also need to update Chromium's:
// web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to

View File

@ -1750,6 +1750,16 @@ namespace internal {
CPP(DisplayNamesPrototypeResolvedOptions) \
/* ecma402 #sec-Intl.DisplayNames.supportedLocalesOf */ \
CPP(DisplayNamesSupportedLocalesOf) \
/* ecma402 #sec-intl-durationformat-constructor */ \
CPP(DurationFormatConstructor) \
/* ecma402 #sec-Intl.DurationFormat.prototype.format */ \
CPP(DurationFormatPrototypeFormat) \
/* ecma402 #sec-Intl.DurationFormat.prototype.formatToParts */ \
CPP(DurationFormatPrototypeFormatToParts) \
/* ecma402 #sec-Intl.DurationFormat.prototype.resolvedOptions */ \
CPP(DurationFormatPrototypeResolvedOptions) \
/* ecma402 #sec-Intl.DurationFormat.supportedLocalesOf */ \
CPP(DurationFormatSupportedLocalesOf) \
/* ecma402 #sec-intl.getcanonicallocales */ \
CPP(IntlGetCanonicalLocales) \
/* ecma402 #sec-intl.supportedvaluesof */ \

View File

@ -21,6 +21,7 @@
#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-duration-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"
@ -383,6 +384,51 @@ BUILTIN(DisplayNamesPrototypeOf) {
JSDisplayNames::Of(isolate, holder, code_obj));
}
// Intl.DurationFormat
BUILTIN(DurationFormatConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSDurationFormat>(
args, isolate, v8::Isolate::UseCounterFeature::kDurationFormat,
"Intl.DurationFormat");
}
BUILTIN(DurationFormatPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDurationFormat, holder,
"Intl.DurationFormat.prototype.resolvedOptions");
return *JSDurationFormat::ResolvedOptions(isolate, holder);
}
BUILTIN(DurationFormatSupportedLocalesOf) {
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.DurationFormat.supportedLocalesOf",
JSDurationFormat::GetAvailableLocales(), locales, options));
}
BUILTIN(DurationFormatPrototypeFormat) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDurationFormat, holder,
"Intl.DurationFormat.prototype.format");
Handle<Object> value = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate,
JSDurationFormat::Format(isolate, holder, value));
}
BUILTIN(DurationFormatPrototypeFormatToParts) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDurationFormat, holder,
"Intl.DurationFormat.prototype.formatToParts");
Handle<Object> value = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(
isolate, JSDurationFormat::FormatToParts(isolate, holder, value));
}
// Intl.NumberFormat
BUILTIN(NumberFormatConstructor) {

View File

@ -47,6 +47,7 @@ class JSCollator;
class JSCollection;
class JSDateTimeFormat;
class JSDisplayNames;
class JSDurationFormat;
class JSListFormat;
class JSLocale;
class JSNumberFormat;

View File

@ -227,6 +227,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_DURATION_FORMAT_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:

View File

@ -46,6 +46,7 @@
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-date-time-format-inl.h"
#include "src/objects/js-display-names-inl.h"
#include "src/objects/js-duration-format-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-generator-inl.h"
#ifdef V8_INTL_SUPPORT

View File

@ -2452,6 +2452,15 @@ void JSDisplayNames::JSDisplayNamesPrint(std::ostream& os) {
JSObjectPrintBody(os, *this);
}
void JSDurationFormat::JSDurationFormatPrint(std::ostream& os) {
JSObjectPrintHeader(os, *this, "JSDurationFormat");
os << "\n - style_flags: " << style_flags();
os << "\n - display_flags: " << display_flags();
os << "\n - icu locale: " << Brief(icu_locale());
os << "\n - icu number formatter: " << Brief(icu_number_formatter());
JSObjectPrintBody(os, *this);
}
void JSListFormat::JSListFormatPrint(std::ostream& os) {
JSObjectPrintHeader(os, *this, "JSListFormat");
os << "\n - locale: " << Brief(locale());

View File

@ -231,9 +231,10 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
V(harmony_regexp_unicode_sets, "harmony RegExp Unicode Sets")
#ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) \
HARMONY_INPROGRESS_BASE(V) \
V(harmony_intl_best_fit_matcher, "Intl BestFitMatcher")
#define HARMONY_INPROGRESS(V) \
HARMONY_INPROGRESS_BASE(V) \
V(harmony_intl_best_fit_matcher, "Intl BestFitMatcher") \
V(harmony_intl_duration_format, "Intl DurationFormat API")
#else
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
#endif

View File

@ -47,6 +47,7 @@
#include "src/objects/js-collator.h"
#include "src/objects/js-date-time-format.h"
#include "src/objects/js-display-names.h"
#include "src/objects/js-duration-format.h"
#include "src/objects/js-list-format.h"
#include "src/objects/js-locale.h"
#include "src/objects/js-number-format.h"
@ -5554,6 +5555,46 @@ void Genesis::InitializeGlobal_experimental_web_snapshots() {
Builtin::kWebSnapshotDeserialize, 2, false);
}
#ifdef V8_INTL_SUPPORT
void Genesis::InitializeGlobal_harmony_intl_duration_format() {
if (!FLAG_harmony_intl_duration_format) return;
Handle<JSObject> intl = Handle<JSObject>::cast(
JSReceiver::GetProperty(
isolate(),
Handle<JSReceiver>(native_context()->global_object(), isolate()),
factory()->InternalizeUtf8String("Intl"))
.ToHandleChecked());
Handle<JSFunction> duration_format_fun = InstallFunction(
isolate(), intl, "DurationFormat", JS_DURATION_FORMAT_TYPE,
JSDurationFormat::kHeaderSize, 0, factory()->the_hole_value(),
Builtin::kDurationFormatConstructor);
duration_format_fun->shared().set_length(0);
duration_format_fun->shared().DontAdaptArguments();
InstallWithIntrinsicDefaultProto(
isolate(), duration_format_fun,
Context::INTL_DURATION_FORMAT_FUNCTION_INDEX);
SimpleInstallFunction(isolate(), duration_format_fun, "supportedLocalesOf",
Builtin::kDurationFormatSupportedLocalesOf, 1, false);
Handle<JSObject> prototype(
JSObject::cast(duration_format_fun->instance_prototype()), isolate());
InstallToStringTag(isolate(), prototype, "Intl.DurationFormat");
SimpleInstallFunction(isolate(), prototype, "resolvedOptions",
Builtin::kDurationFormatPrototypeResolvedOptions, 0,
false);
SimpleInstallFunction(isolate(), prototype, "format",
Builtin::kDurationFormatPrototypeFormat, 1, false);
SimpleInstallFunction(isolate(), prototype, "formatToParts",
Builtin::kDurationFormatPrototypeFormatToParts, 1,
false);
}
#endif // V8_INTL_SUPPORT
Handle<JSFunction> Genesis::CreateArrayBuffer(
Handle<String> name, ArrayBufferKind array_buffer_kind) {
// Create the %ArrayBufferPrototype%

View File

@ -27,8 +27,10 @@
V(_, dateStyle_string, "dateStyle") \
V(_, dateTimeField_string, "dateTimeField") \
V(_, dayPeriod_string, "dayPeriod") \
V(_, daysDisplay_string, "daysDisplay") \
V(_, decimal_string, "decimal") \
V(_, dialect_string, "dialect") \
V(_, digital_string, "digital") \
V(_, direction_string, "direction") \
V(_, endRange_string, "endRange") \
V(_, engineering_string, "engineering") \
@ -43,6 +45,7 @@
V(_, floor_string, "floor") \
V(_, format_string, "format") \
V(_, fraction_string, "fraction") \
V(_, fractionalDigits_string, "fractionalDigits") \
V(_, fractionalSecond_string, "fractionalSecond") \
V(_, full_string, "full") \
V(_, granularity_string, "granularity") \
@ -60,6 +63,7 @@
V(_, hour12_string, "hour12") \
V(_, hourCycle_string, "hourCycle") \
V(_, hourCycles_string, "hourCycles") \
V(_, hoursDisplay_string, "hoursDisplay") \
V(_, ideo_string, "ideo") \
V(_, ignorePunctuation_string, "ignorePunctuation") \
V(_, Invalid_Date_string, "Invalid Date") \
@ -78,6 +82,8 @@
V(_, ltr_string, "ltr") \
V(_, maximumFractionDigits_string, "maximumFractionDigits") \
V(_, maximumSignificantDigits_string, "maximumSignificantDigits") \
V(_, microsecondsDisplay_string, "microsecondsDisplay") \
V(_, millisecondsDisplay_string, "millisecondsDisplay") \
V(_, min2_string, "min2") \
V(_, minimalDays_string, "minimalDays") \
V(_, minimumFractionDigits_string, "minimumFractionDigits") \
@ -85,8 +91,11 @@
V(_, minimumSignificantDigits_string, "minimumSignificantDigits") \
V(_, minus_0, "-0") \
V(_, minusSign_string, "minusSign") \
V(_, minutesDisplay_string, "minutesDisplay") \
V(_, monthsDisplay_string, "monthsDisplay") \
V(_, morePrecision_string, "morePrecision") \
V(_, nan_string, "nan") \
V(_, nanosecondsDisplay_string, "nanosecondsDisplay") \
V(_, narrowSymbol_string, "narrowSymbol") \
V(_, negative_string, "negative") \
V(_, never_string, "never") \
@ -106,6 +115,7 @@
V(_, roundingPriority_string, "roundingPriority") \
V(_, rtl_string, "rtl") \
V(_, scientific_string, "scientific") \
V(_, secondsDisplay_string, "secondsDisplay") \
V(_, segment_string, "segment") \
V(_, SegmentIterator_string, "Segment Iterator") \
V(_, Segments_string, "Segments") \
@ -125,6 +135,7 @@
V(_, timeZoneName_string, "timeZoneName") \
V(_, trailingZeroDisplay_string, "trailingZeroDisplay") \
V(_, trunc_string, "trunc") \
V(_, two_digit_string, "2-digit") \
V(_, type_string, "type") \
V(_, unknown_string, "unknown") \
V(_, upper_string, "upper") \
@ -133,8 +144,10 @@
V(_, unitDisplay_string, "unitDisplay") \
V(_, weekday_string, "weekday") \
V(_, weekend_string, "weekend") \
V(_, weeksDisplay_string, "weeksDisplay") \
V(_, weekInfo_string, "weekInfo") \
V(_, yearName_string, "yearName")
V(_, yearName_string, "yearName") \
V(_, yearsDisplay_string, "yearsDisplay")
#else // V8_INTL_SUPPORT
#define INTERNALIZED_STRING_LIST_GENERATOR_INTL(V, _)
#endif // V8_INTL_SUPPORT

View File

@ -97,6 +97,7 @@
#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-duration-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"

View File

@ -157,6 +157,8 @@ enum ContextLookupFlags {
intl_date_time_format_function) \
V(INTL_DISPLAY_NAMES_FUNCTION_INDEX, JSFunction, \
intl_display_names_function) \
V(INTL_DURATION_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_duration_format_function) \
V(INTL_NUMBER_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_number_format_function) \
V(INTL_LOCALE_FUNCTION_INDEX, JSFunction, intl_locale_function) \

View File

@ -0,0 +1,104 @@
// Copyright 2022 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
#ifndef V8_OBJECTS_JS_DURATION_FORMAT_INL_H_
#define V8_OBJECTS_JS_DURATION_FORMAT_INL_H_
#include "src/objects/js-duration-format.h"
#include "src/objects/objects-inl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
#include "torque-generated/src/objects/js-duration-format-tq-inl.inc"
TQ_OBJECT_CONSTRUCTORS_IMPL(JSDurationFormat)
ACCESSORS(JSDurationFormat, icu_locale, Managed<icu::Locale>, kIcuLocaleOffset)
#define IMPL_INLINE_SETTER_GETTER(T, n, B, f, M) \
inline void JSDurationFormat::set_##n(T value) { \
DCHECK_GE(B::kMax, value); \
DCHECK_GE(T::M, value); \
set_##f(B::update(f(), value)); \
} \
inline JSDurationFormat::T JSDurationFormat::n() const { \
return B::decode(f()); \
}
#define IMPL_INLINE_DISPLAY_SETTER_GETTER(f, R) \
IMPL_INLINE_SETTER_GETTER(Display, f##_display, R##DisplayBit, \
display_flags, kAlways)
#define IMPL_INLINE_FIELD_STYLE3_SETTER_GETTER(f, R) \
IMPL_INLINE_SETTER_GETTER(FieldStyle, f##_style, R##StyleBits, style_flags, \
kNarrow)
#define IMPL_INLINE_FIELD_STYLE4_SETTER_GETTER(f, R) \
IMPL_INLINE_SETTER_GETTER(FieldStyle, f##_style, R##StyleBits, style_flags, \
kNumeric)
#define IMPL_INLINE_FIELD_STYLE5_SETTER_GETTER(f, R) \
IMPL_INLINE_SETTER_GETTER(FieldStyle, f##_style, R##StyleBits, style_flags, \
k2Digit)
IMPL_INLINE_DISPLAY_SETTER_GETTER(years, Years)
IMPL_INLINE_DISPLAY_SETTER_GETTER(months, Months)
IMPL_INLINE_DISPLAY_SETTER_GETTER(weeks, Weeks)
IMPL_INLINE_DISPLAY_SETTER_GETTER(days, Days)
IMPL_INLINE_DISPLAY_SETTER_GETTER(hours, Hours)
IMPL_INLINE_DISPLAY_SETTER_GETTER(minutes, Minutes)
IMPL_INLINE_DISPLAY_SETTER_GETTER(seconds, Seconds)
IMPL_INLINE_DISPLAY_SETTER_GETTER(milliseconds, Milliseconds)
IMPL_INLINE_DISPLAY_SETTER_GETTER(microseconds, Microseconds)
IMPL_INLINE_DISPLAY_SETTER_GETTER(nanoseconds, Nanoseconds)
IMPL_INLINE_SETTER_GETTER(Style, style, StyleBits, style_flags, kDigital)
IMPL_INLINE_FIELD_STYLE3_SETTER_GETTER(years, Years)
IMPL_INLINE_FIELD_STYLE3_SETTER_GETTER(months, Months)
IMPL_INLINE_FIELD_STYLE3_SETTER_GETTER(weeks, Weeks)
IMPL_INLINE_FIELD_STYLE3_SETTER_GETTER(days, Days)
IMPL_INLINE_FIELD_STYLE5_SETTER_GETTER(hours, Hours)
IMPL_INLINE_FIELD_STYLE5_SETTER_GETTER(minutes, Minutes)
IMPL_INLINE_FIELD_STYLE5_SETTER_GETTER(seconds, Seconds)
IMPL_INLINE_FIELD_STYLE4_SETTER_GETTER(milliseconds, Milliseconds)
IMPL_INLINE_FIELD_STYLE4_SETTER_GETTER(microseconds, Microseconds)
IMPL_INLINE_FIELD_STYLE4_SETTER_GETTER(nanoseconds, Nanoseconds)
#undef IMPL_INLINE_SETTER_GETTER
#undef IMPL_INLINE_DISPLAY_SETTER_GETTER
#undef IMPL_INLINE_FIELD_STYLE3_SETTER_GETTER
#undef IMPL_INLINE_FIELD_STYLE5_SETTER_GETTER
inline void JSDurationFormat::set_fractional_digits(int32_t digits) {
DCHECK_GE(9, digits);
DCHECK_LE(0, digits);
int hints = display_flags();
hints = FractionalDigitsBits::update(hints, digits);
set_display_flags(hints);
}
inline int32_t JSDurationFormat::fractional_digits() const {
int32_t v = FractionalDigitsBits::decode(display_flags());
DCHECK_GE(9, v);
DCHECK_LE(0, v);
return v;
}
ACCESSORS(JSDurationFormat, icu_number_formatter,
Managed<icu::number::LocalizedNumberFormatter>,
kIcuNumberFormatterOffset)
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_DURATION_FORMAT_INL_H_

View File

@ -0,0 +1,774 @@
// Copyright 2022 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 "src/objects/js-duration-format.h"
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-duration-format-inl.h"
#include "src/objects/js-number-format.h"
#include "src/objects/js-temporal-objects.h"
#include "src/objects/managed-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/option-utils.h"
#include "unicode/listformatter.h"
#include "unicode/locid.h"
#include "unicode/numberformatter.h"
#include "unicode/ulistformatter.h"
#include "unicode/unumberformatter.h"
namespace v8 {
namespace internal {
using temporal::DurationRecord;
namespace {
// #sec-getdurationunitoptions
enum class StylesList { k3Styles, k4Styles, k5Styles };
enum class UnitKind { kMinutesOrSeconds, kOthers };
struct DurationUnitOptions {
JSDurationFormat::FieldStyle style;
JSDurationFormat::Display display;
};
Maybe<DurationUnitOptions> GetDurationUnitOptions(
Isolate* isolate, const char* unit, const char* display_field,
Handle<JSReceiver> options, JSDurationFormat::Style base_style,
StylesList styles_list, JSDurationFormat::FieldStyle prev_style,
UnitKind unit_kind, const char* method_name) {
JSDurationFormat::FieldStyle style;
JSDurationFormat::FieldStyle digital_base;
// 1. Let style be ? GetOption(options, unit, "string", stylesList,
// undefined).
switch (styles_list) {
case StylesList::k3Styles:
// For years, months, weeks, days
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, style,
GetStringOption<JSDurationFormat::FieldStyle>(
isolate, options, unit, method_name, {"long", "short", "narrow"},
{JSDurationFormat::FieldStyle::kLong,
JSDurationFormat::FieldStyle::kShort,
JSDurationFormat::FieldStyle::kNarrow},
JSDurationFormat::FieldStyle::kUndefined),
Nothing<DurationUnitOptions>());
digital_base = JSDurationFormat::FieldStyle::kShort;
break;
case StylesList::k4Styles:
// For milliseconds, microseconds, nanoseconds
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, style,
GetStringOption<JSDurationFormat::FieldStyle>(
isolate, options, unit, method_name,
{"long", "short", "narrow", "numeric"},
{JSDurationFormat::FieldStyle::kLong,
JSDurationFormat::FieldStyle::kShort,
JSDurationFormat::FieldStyle::kNarrow,
JSDurationFormat::FieldStyle::kNumeric},
JSDurationFormat::FieldStyle::kUndefined),
Nothing<DurationUnitOptions>());
digital_base = JSDurationFormat::FieldStyle::kNumeric;
break;
case StylesList::k5Styles:
// For hours, minutes, seconds
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, style,
GetStringOption<JSDurationFormat::FieldStyle>(
isolate, options, unit, method_name,
{"long", "short", "narrow", "numeric", "2-digit"},
{JSDurationFormat::FieldStyle::kLong,
JSDurationFormat::FieldStyle::kShort,
JSDurationFormat::FieldStyle::kNarrow,
JSDurationFormat::FieldStyle::kNumeric,
JSDurationFormat::FieldStyle::k2Digit},
JSDurationFormat::FieldStyle::kUndefined),
Nothing<DurationUnitOptions>());
digital_base = JSDurationFormat::FieldStyle::kNumeric;
break;
}
// 2. Let displayDefault be "always".
JSDurationFormat::Display display_default =
JSDurationFormat::Display::kAlways;
// 3. If style is undefined, then
if (style == JSDurationFormat::FieldStyle::kUndefined) {
// a. If baseStyle is "digital", then
if (base_style == JSDurationFormat::Style::kDigital) {
// i. If unit is not one of "hours", "minutes", or "seconds", then
if (styles_list != StylesList::k5Styles) {
DCHECK_NE(0, strcmp(unit, "hours"));
DCHECK_NE(0, strcmp(unit, "minutes"));
DCHECK_NE(0, strcmp(unit, "seconds"));
// a. Set displayDefault to "auto".
display_default = JSDurationFormat::Display::kAuto;
}
// ii. Set style to digitalBase.
style = digital_base;
// b. Else
} else {
// i. Set displayDefault to "auto".
display_default = JSDurationFormat::Display::kAuto;
// ii. if prevStyle is "numeric" or "2-digit", then
if (prev_style == JSDurationFormat::FieldStyle::kNumeric ||
prev_style == JSDurationFormat::FieldStyle::k2Digit) {
// 1. Set style to "numeric".
style = JSDurationFormat::FieldStyle::kNumeric;
// iii. Else,
} else {
// 1. Set style to baseStyle.
switch (base_style) {
case JSDurationFormat::Style::kLong:
style = JSDurationFormat::FieldStyle::kLong;
break;
case JSDurationFormat::Style::kShort:
style = JSDurationFormat::FieldStyle::kShort;
break;
case JSDurationFormat::Style::kNarrow:
style = JSDurationFormat::FieldStyle::kNarrow;
break;
default:
UNREACHABLE();
}
}
}
}
// 4. Let displayField be the string-concatenation of unit and "Display".
// 5. Let display be ? GetOption(options, displayField, "string", « "auto",
// "always" », displayDefault).
JSDurationFormat::Display display;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, display,
GetStringOption<JSDurationFormat::Display>(
isolate, options, display_field, method_name, {"auto", "always"},
{JSDurationFormat::Display::kAuto,
JSDurationFormat::Display::kAlways},
display_default),
Nothing<DurationUnitOptions>());
// 6. If prevStyle is "numeric" or "2-digit", then
if (prev_style == JSDurationFormat::FieldStyle::kNumeric ||
prev_style == JSDurationFormat::FieldStyle::k2Digit) {
// a. If style is not "numeric" or "2-digit", then
if (style != JSDurationFormat::FieldStyle::kNumeric &&
style != JSDurationFormat::FieldStyle::k2Digit) {
// i. Throw a RangeError exception.
// b. Else if unit is "minutes" or "seconds", then
} else if (unit_kind == UnitKind::kMinutesOrSeconds) {
CHECK(strcmp(unit, "minutes") == 0 || strcmp(unit, "seconds") == 0);
// i. Set style to "2-digit".
style = JSDurationFormat::FieldStyle::k2Digit;
}
}
// 7. Return the Record { [[Style]]: style, [[Display]]: display }.
return Just(DurationUnitOptions({style, display}));
}
} // namespace
MaybeHandle<JSDurationFormat> JSDurationFormat::New(
Isolate* isolate, Handle<Map> map, Handle<Object> locales,
Handle<Object> input_options) {
Factory* factory = isolate->factory();
const char* method_name = "Intl.DurationFormat";
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
std::vector<std::string> requested_locales;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, requested_locales,
Intl::CanonicalizeLocaleList(isolate, locales),
Handle<JSDurationFormat>());
// 4. Let options be ? GetOptionsObject(options).
Handle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, input_options, method_name),
JSDurationFormat);
// 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «
// "lookup", "best fit" », "best fit").
Intl::MatcherOption matcher;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, matcher, Intl::GetLocaleMatcher(isolate, options, method_name),
Handle<JSDurationFormat>());
// 6. Let numberingSystem be ? GetOption(options, "numberingSystem", "string",
// undefined, undefined).
//
// 7. If numberingSystem is not undefined, then
//
// a. If numberingSystem does not match the Unicode Locale Identifier type
// nonterminal, throw a RangeError exception.
// Note: The matching test and throw in Step 7-a is throw inside
// Intl::GetNumberingSystem.
std::unique_ptr<char[]> numbering_system_str = nullptr;
bool get;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, get,
Intl::GetNumberingSystem(isolate, options, method_name,
&numbering_system_str),
Handle<JSDurationFormat>());
// 8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]:
// numberingSystem }.
// 9. Let r be ResolveLocale(%DurationFormat%.[[AvailableLocales]],
// requestedLocales, opt, %DurationFormat%.[[RelevantExtensionKeys]],
// %DurationFormat%.[[LocaleData]]).
std::set<std::string> relevant_extension_keys{"nu"};
Intl::ResolvedLocale r;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, r,
Intl::ResolveLocale(isolate, JSDurationFormat::GetAvailableLocales(),
requested_locales, matcher, relevant_extension_keys),
Handle<JSDurationFormat>());
// 10. Let locale be r.[[locale]].
icu::Locale r_locale = r.icu_locale;
UErrorCode status = U_ZERO_ERROR;
// 11. Set durationFormat.[[Locale]] to locale.
// 12. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
if (numbering_system_str != nullptr) {
auto nu_extension_it = r.extensions.find("nu");
if (nu_extension_it != r.extensions.end() &&
nu_extension_it->second != numbering_system_str.get()) {
r_locale.setUnicodeKeywordValue("nu", nullptr, status);
DCHECK(U_SUCCESS(status));
}
}
icu::Locale icu_locale = r_locale;
if (numbering_system_str != nullptr &&
Intl::IsValidNumberingSystem(numbering_system_str.get())) {
r_locale.setUnicodeKeywordValue("nu", numbering_system_str.get(), status);
DCHECK(U_SUCCESS(status));
}
std::string numbering_system = Intl::GetNumberingSystem(r_locale);
// 13. Let style be ? GetOption(options, "style", "string", « "long", "short",
// "narrow", "digital" », "long").
Style style;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, style,
GetStringOption<Style>(
isolate, options, "style", method_name,
{"long", "short", "narrow", "digital"},
{Style::kLong, Style::kShort, Style::kNarrow, Style::kDigital},
Style::kShort),
Handle<JSDurationFormat>());
// 14. Set durationFormat.[[Style]] to style.
// 15. Set durationFormat.[[DataLocale]] to r.[[dataLocale]].
Handle<Managed<icu::Locale>> managed_locale =
Managed<icu::Locale>::FromRawPtr(isolate, 0, icu_locale.clone());
// 16. Let prevStyle be the empty String.
FieldStyle prev_style = FieldStyle::kUndefined;
// 17. For each row of Table 1, except the header row, in table order, do
// a. Let styleSlot be the Style Slot value of the current row.
// b. Let displaySlot be the Display Slot value of the current row.
// c. Let unit be the Unit value.
// d. Let valueList be the Values value.
// e. Let digitalBase be the Digital Default value.
// f. Let unitOptions be ? GetDurationUnitOptions(unit, options, style,
// valueList, digitalBase, prevStyle).
// of durationFormat to unitOptions.[[Style]].
// h. Set the value of the
// displaySlot slot of durationFormat to unitOptions.[[Display]].
// i. If unit is one of "hours", "minutes", "seconds", "milliseconds",
// or "microseconds", then
// i. Set prevStyle to unitOptions.[[Style]].
// g. Set the value of the styleSlot slot
DurationUnitOptions years_option;
DurationUnitOptions months_option;
DurationUnitOptions weeks_option;
DurationUnitOptions days_option;
DurationUnitOptions hours_option;
DurationUnitOptions minutes_option;
DurationUnitOptions seconds_option;
DurationUnitOptions milliseconds_option;
DurationUnitOptions microseconds_option;
DurationUnitOptions nanoseconds_option;
#define CALL_GET_DURATION_UNIT_OPTIONS(u, sl, uk) \
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE( \
isolate, u##_option, \
GetDurationUnitOptions(isolate, #u, #u "Display", options, style, sl, \
prev_style, uk, method_name), \
Handle<JSDurationFormat>());
CALL_GET_DURATION_UNIT_OPTIONS(years, StylesList::k3Styles, UnitKind::kOthers)
CALL_GET_DURATION_UNIT_OPTIONS(months, StylesList::k3Styles,
UnitKind::kOthers)
CALL_GET_DURATION_UNIT_OPTIONS(weeks, StylesList::k3Styles, UnitKind::kOthers)
CALL_GET_DURATION_UNIT_OPTIONS(days, StylesList::k3Styles, UnitKind::kOthers)
CALL_GET_DURATION_UNIT_OPTIONS(hours, StylesList::k5Styles, UnitKind::kOthers)
prev_style = hours_option.style;
CALL_GET_DURATION_UNIT_OPTIONS(minutes, StylesList::k5Styles,
UnitKind::kMinutesOrSeconds)
prev_style = minutes_option.style;
CALL_GET_DURATION_UNIT_OPTIONS(seconds, StylesList::k5Styles,
UnitKind::kMinutesOrSeconds)
prev_style = seconds_option.style;
CALL_GET_DURATION_UNIT_OPTIONS(milliseconds, StylesList::k4Styles,
UnitKind::kOthers)
prev_style = milliseconds_option.style;
CALL_GET_DURATION_UNIT_OPTIONS(microseconds, StylesList::k4Styles,
UnitKind::kOthers)
prev_style = microseconds_option.style;
CALL_GET_DURATION_UNIT_OPTIONS(nanoseconds, StylesList::k4Styles,
UnitKind::kOthers)
#undef CALL_GET_DURATION_UNIT_OPTIONS
// 18. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options,
// "fractionalDigits", 0, 9, undefined).
int fractional_digits;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, fractional_digits,
GetNumberOption(isolate, options, factory->fractionalDigits_string(), 0,
9, 0),
Handle<JSDurationFormat>());
icu::number::LocalizedNumberFormatter fmt =
icu::number::UnlocalizedNumberFormatter()
.roundingMode(UNUM_ROUND_HALFUP)
.locale(icu_locale);
if (!numbering_system.empty() && numbering_system != "latn") {
fmt = fmt.adoptSymbols(icu::NumberingSystem::createInstanceByName(
numbering_system.c_str(), status));
DCHECK(U_SUCCESS(status));
}
Handle<Managed<icu::number::LocalizedNumberFormatter>>
managed_number_formatter =
Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr(
isolate, 0, new icu::number::LocalizedNumberFormatter(fmt));
// 19. Return durationFormat.
Handle<JSDurationFormat> duration_format = Handle<JSDurationFormat>::cast(
factory->NewFastOrSlowJSObjectFromMap(map));
duration_format->set_style_flags(0);
duration_format->set_display_flags(0);
duration_format->set_style(style);
duration_format->set_years_style(years_option.style);
duration_format->set_months_style(months_option.style);
duration_format->set_weeks_style(weeks_option.style);
duration_format->set_days_style(days_option.style);
duration_format->set_hours_style(hours_option.style);
duration_format->set_minutes_style(minutes_option.style);
duration_format->set_seconds_style(seconds_option.style);
duration_format->set_milliseconds_style(milliseconds_option.style);
duration_format->set_microseconds_style(microseconds_option.style);
duration_format->set_nanoseconds_style(nanoseconds_option.style);
duration_format->set_years_display(years_option.display);
duration_format->set_months_display(months_option.display);
duration_format->set_weeks_display(weeks_option.display);
duration_format->set_days_display(days_option.display);
duration_format->set_hours_display(hours_option.display);
duration_format->set_minutes_display(minutes_option.display);
duration_format->set_seconds_display(seconds_option.display);
duration_format->set_milliseconds_display(milliseconds_option.display);
duration_format->set_microseconds_display(microseconds_option.display);
duration_format->set_nanoseconds_display(nanoseconds_option.display);
duration_format->set_fractional_digits(fractional_digits);
duration_format->set_icu_locale(*managed_locale);
duration_format->set_icu_number_formatter(*managed_number_formatter);
return duration_format;
}
namespace {
Handle<String> StyleToString(Isolate* isolate, JSDurationFormat::Style style) {
switch (style) {
case JSDurationFormat::Style::kLong:
return ReadOnlyRoots(isolate).long_string_handle();
case JSDurationFormat::Style::kShort:
return ReadOnlyRoots(isolate).short_string_handle();
case JSDurationFormat::Style::kNarrow:
return ReadOnlyRoots(isolate).narrow_string_handle();
case JSDurationFormat::Style::kDigital:
return ReadOnlyRoots(isolate).digital_string_handle();
}
}
Handle<String> StyleToString(Isolate* isolate,
JSDurationFormat::FieldStyle style) {
switch (style) {
case JSDurationFormat::FieldStyle::kLong:
return ReadOnlyRoots(isolate).long_string_handle();
case JSDurationFormat::FieldStyle::kShort:
return ReadOnlyRoots(isolate).short_string_handle();
case JSDurationFormat::FieldStyle::kNarrow:
return ReadOnlyRoots(isolate).narrow_string_handle();
case JSDurationFormat::FieldStyle::kNumeric:
return ReadOnlyRoots(isolate).numeric_string_handle();
case JSDurationFormat::FieldStyle::k2Digit:
return ReadOnlyRoots(isolate).two_digit_string_handle();
case JSDurationFormat::FieldStyle::kUndefined:
UNREACHABLE();
}
}
Handle<String> DisplayToString(Isolate* isolate,
JSDurationFormat::Display display) {
switch (display) {
case JSDurationFormat::Display::kAuto:
return ReadOnlyRoots(isolate).auto_string_handle();
case JSDurationFormat::Display::kAlways:
return ReadOnlyRoots(isolate).always_string_handle();
}
}
} // namespace
Handle<JSObject> JSDurationFormat::ResolvedOptions(
Isolate* isolate, Handle<JSDurationFormat> format) {
Factory* factory = isolate->factory();
Handle<JSObject> options = factory->NewJSObject(isolate->object_function());
Handle<String> locale = factory->NewStringFromAsciiChecked(
Intl::ToLanguageTag(*format->icu_locale().raw()).FromJust().c_str());
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString skeleton =
format->icu_number_formatter().raw()->toSkeleton(status);
DCHECK(U_SUCCESS(status));
Handle<String> numbering_system;
CHECK(Intl::ToString(isolate,
JSNumberFormat::NumberingSystemFromSkeleton(skeleton))
.ToHandle(&numbering_system));
Handle<Smi> fractional_digits =
handle(Smi::FromInt(format->fractional_digits()), isolate);
bool created;
#define OUTPUT_PROPERTY(s, f) \
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE( \
isolate, created, \
JSReceiver::CreateDataProperty(isolate, options, factory->s(), f, \
Just(kDontThrow)), \
Handle<JSObject>()); \
CHECK(created);
#define OUTPUT_STYLE_PROPERTY(p) \
OUTPUT_PROPERTY(p##_string, StyleToString(isolate, format->p##_style()))
#define OUTPUT_DISPLAY_PROPERTY(p) \
OUTPUT_PROPERTY(p##Display_string, \
DisplayToString(isolate, format->p##_display()))
#define OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(p) \
OUTPUT_STYLE_PROPERTY(p); \
OUTPUT_DISPLAY_PROPERTY(p);
OUTPUT_PROPERTY(locale_string, locale);
OUTPUT_PROPERTY(style_string, StyleToString(isolate, format->style()));
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(years);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(months);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(weeks);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(days);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(hours);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(minutes);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(seconds);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(milliseconds);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(microseconds);
OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(nanoseconds);
OUTPUT_PROPERTY(fractionalDigits_string, fractional_digits);
OUTPUT_PROPERTY(numberingSystem_string, numbering_system);
#undef OUTPUT_PROPERTY
#undef OUTPUT_STYLE_PROPERTY
#undef OUTPUT_DISPLAY_PROPERTY
#undef OUTPUT_STYLE_AND_DISPLAY_PROPERTIES
return options;
}
namespace {
UNumberUnitWidth ToUNumberUnitWidth(JSDurationFormat::FieldStyle style) {
switch (style) {
case JSDurationFormat::FieldStyle::kShort:
return UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT;
case JSDurationFormat::FieldStyle::kLong:
return UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME;
case JSDurationFormat::FieldStyle::kNarrow:
return UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW;
default:
UNREACHABLE();
}
}
void Output(std::vector<icu::UnicodeString>* out, double value,
const icu::number::LocalizedNumberFormatter& fmt) {
UErrorCode status = U_ZERO_ERROR;
out->push_back(fmt.formatDouble(value, status).toString(status));
CHECK(U_SUCCESS(status));
}
void Output3Styles(std::vector<icu::UnicodeString>* out,
std::vector<std::string>* types, const char* type,
double value, JSDurationFormat::Display display,
const icu::number::LocalizedNumberFormatter& fmt) {
if (value == 0 && display == JSDurationFormat::Display::kAuto) return;
types->push_back(type);
Output(out, value, fmt);
}
void Output4Styles(std::vector<icu::UnicodeString>* out,
std::vector<std::string>* types, const char* type,
double value, JSDurationFormat::Display display,
JSDurationFormat::FieldStyle style,
const icu::number::LocalizedNumberFormatter& fmt,
icu::MeasureUnit unit) {
if (value == 0 && display == JSDurationFormat::Display::kAuto) return;
if (style == JSDurationFormat::FieldStyle::kNumeric) {
types->push_back(type);
return Output(out, value, fmt);
}
Output3Styles(out, types, type, value, display,
fmt.unit(unit).unitWidth(ToUNumberUnitWidth(style)));
}
void Output5Styles(std::vector<icu::UnicodeString>* out,
std::vector<std::string>* types, const char* type,
double value, JSDurationFormat::Display display,
JSDurationFormat::FieldStyle style,
const icu::number::LocalizedNumberFormatter& fmt,
icu::MeasureUnit unit) {
if (value == 0 && display == JSDurationFormat::Display::kAuto) return;
if (style == JSDurationFormat::FieldStyle::k2Digit) {
types->push_back(type);
return Output(out, value,
fmt.integerWidth(icu::number::IntegerWidth::zeroFillTo(2)));
}
Output4Styles(out, types, type, value, display, style, fmt, unit);
}
void DurationRecordToListOfStrings(
std::vector<icu::UnicodeString>* out, std::vector<std::string>* types,
Handle<JSDurationFormat> df,
const icu::number::LocalizedNumberFormatter& fmt,
const DurationRecord& record) {
// The handling of "2-digit" or "numeric" style of
// step l.i.6.c.i-ii "Let separator be
// dataLocaleData.[[digitalFormat]].[[separator]]." and
// "Append the new Record { [[Type]]: "literal", [[Value]]: separator} to the
// end of result." are not implemented following the spec due to unresolved
// issues in
// https://github.com/tc39/proposal-intl-duration-format/issues/55
Output3Styles(out, types, "years", record.years, df->years_display(),
fmt.unit(icu::MeasureUnit::getYear())
.unitWidth(ToUNumberUnitWidth(df->years_style())));
Output3Styles(out, types, "months", record.months, df->months_display(),
fmt.unit(icu::MeasureUnit::getMonth())
.unitWidth(ToUNumberUnitWidth(df->months_style())));
Output3Styles(out, types, "weeks", record.weeks, df->weeks_display(),
fmt.unit(icu::MeasureUnit::getWeek())
.unitWidth(ToUNumberUnitWidth(df->weeks_style())));
Output3Styles(out, types, "days", record.time_duration.days,
df->days_display(),
fmt.unit(icu::MeasureUnit::getDay())
.unitWidth(ToUNumberUnitWidth(df->days_style())));
Output5Styles(out, types, "hours", record.time_duration.hours,
df->hours_display(), df->hours_style(), fmt,
icu::MeasureUnit::getHour());
Output5Styles(out, types, "minutes", record.time_duration.minutes,
df->minutes_display(), df->minutes_style(), fmt,
icu::MeasureUnit::getMinute());
int32_t fractional_digits = df->fractional_digits();
if (df->milliseconds_style() == JSDurationFormat::FieldStyle::kNumeric) {
// a. Set value to value + duration.[[Milliseconds]] / 10^3 +
// duration.[[Microseconds]] / 10^6 + duration.[[Nanoseconds]] / 10^9.
double value = record.time_duration.seconds +
record.time_duration.milliseconds / 1e3 +
record.time_duration.microseconds / 1e6 +
record.time_duration.nanoseconds / 1e9;
Output5Styles(out, types, "seconds", value, df->seconds_display(),
df->seconds_style(),
fmt.precision(icu::number::Precision::minMaxFraction(
fractional_digits, fractional_digits)),
icu::MeasureUnit::getSecond());
return;
}
Output5Styles(out, types, "seconds", record.time_duration.seconds,
df->seconds_display(), df->seconds_style(), fmt,
icu::MeasureUnit::getSecond());
if (df->microseconds_style() == JSDurationFormat::FieldStyle::kNumeric) {
// a. Set value to value + duration.[[Microseconds]] / 10^3 +
// duration.[[Nanoseconds]] / 10^6.
double value = record.time_duration.milliseconds +
record.time_duration.microseconds / 1e3 +
record.time_duration.nanoseconds / 1e6;
Output4Styles(out, types, "milliseconds", value, df->milliseconds_display(),
df->milliseconds_style(),
fmt.precision(icu::number::Precision::minMaxFraction(
fractional_digits, fractional_digits)),
icu::MeasureUnit::getMillisecond());
return;
}
Output4Styles(out, types, "milliseconds", record.time_duration.milliseconds,
df->milliseconds_display(), df->milliseconds_style(), fmt,
icu::MeasureUnit::getMillisecond());
if (df->nanoseconds_style() == JSDurationFormat::FieldStyle::kNumeric) {
// a. Set value to value + duration.[[Nanoseconds]] / 10^3.
double value = record.time_duration.microseconds +
record.time_duration.nanoseconds / 1e3;
Output4Styles(out, types, "microseconds", value, df->microseconds_display(),
df->microseconds_style(),
fmt.precision(icu::number::Precision::minMaxFraction(
fractional_digits, fractional_digits)),
icu::MeasureUnit::getMicrosecond());
return;
}
Output4Styles(out, types, "microseconds", record.time_duration.microseconds,
df->microseconds_display(), df->microseconds_style(), fmt,
icu::MeasureUnit::getMicrosecond());
Output4Styles(out, types, "nanoseconds", record.time_duration.nanoseconds,
df->nanoseconds_display(), df->nanoseconds_style(), fmt,
icu::MeasureUnit::getNanosecond());
}
UListFormatterWidth StyleToWidth(JSDurationFormat::Style style) {
switch (style) {
case JSDurationFormat::Style::kLong:
return ULISTFMT_WIDTH_WIDE;
case JSDurationFormat::Style::kShort:
return ULISTFMT_WIDTH_SHORT;
case JSDurationFormat::Style::kNarrow:
case JSDurationFormat::Style::kDigital:
return ULISTFMT_WIDTH_NARROW;
}
UNREACHABLE();
}
template <typename T,
MaybeHandle<T> (*Format)(Isolate*, const icu::FormattedValue&,
const std::vector<std::string>&)>
MaybeHandle<T> PartitionDurationFormatPattern(Isolate* isolate,
Handle<JSDurationFormat> df,
const DurationRecord& record,
const char* method_name) {
// 4. Let lfOpts be ! OrdinaryObjectCreate(null).
// 5. Perform ! CreateDataPropertyOrThrow(lfOpts, "type", "unit").
UListFormatterType type = ULISTFMT_TYPE_UNITS;
// 6. Let listStyle be durationFormat.[[Style]].
// 7. If listStyle is "digital", then
// a. Set listStyle to "narrow".
// 8. Perform ! CreateDataPropertyOrThrow(lfOpts, "style", listStyle).
UListFormatterWidth list_style = StyleToWidth(df->style());
// 9. Let lf be ! Construct(%ListFormat%, « durationFormat.[[Locale]], lfOpts
// »).
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale = *df->icu_locale().raw();
std::unique_ptr<icu::ListFormatter> formatter(
icu::ListFormatter::createInstance(icu_locale, type, list_style, status));
CHECK(U_SUCCESS(status));
std::vector<icu::UnicodeString> list;
std::vector<std::string> types;
DurationRecordToListOfStrings(&list, &types, df,
*(df->icu_number_formatter().raw()), record);
icu::FormattedList formatted = formatter->formatStringsToValue(
list.data(), static_cast<int32_t>(list.size()), status);
CHECK(U_SUCCESS(status));
return Format(isolate, formatted, types);
}
template <typename T,
MaybeHandle<T> (*Format)(Isolate*, const icu::FormattedValue&,
const std::vector<std::string>&)>
MaybeHandle<T> FormatCommon(Isolate* isolate, Handle<JSDurationFormat> df,
Handle<Object> duration, const char* method_name) {
// 1. Let df be this value.
// 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]).
// 3. Let record be ? ToDurationRecord(duration).
DurationRecord record;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, record,
temporal::ToPartialDuration(isolate, duration,
{0, 0, 0, {0, 0, 0, 0, 0, 0, 0}}),
Handle<T>());
// 4. If IsValidDurationRecord(record) is false, throw a RangeError exception.
if (!temporal::IsValidDuration(isolate, record)) {
THROW_NEW_ERROR(
isolate,
NewRangeError(MessageTemplate::kInvalid,
isolate->factory()->object_string(), duration),
T);
}
// 5. Let parts be ! PartitionDurationFormatPattern(df, record).
return PartitionDurationFormatPattern<T, Format>(isolate, df, record,
method_name);
}
} // namespace
MaybeHandle<String> FormattedToString(Isolate* isolate,
const icu::FormattedValue& formatted,
const std::vector<std::string>&) {
return Intl::FormattedToString(isolate, formatted);
}
MaybeHandle<JSArray> FormattedListToJSArray(
Isolate* isolate, const icu::FormattedValue& formatted,
const std::vector<std::string>& types) {
Factory* factory = isolate->factory();
Handle<JSArray> array = factory->NewJSArray(0);
icu::ConstrainedFieldPosition cfpos;
cfpos.constrainCategory(UFIELD_CATEGORY_LIST);
int index = 0;
int type_index = 0;
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString string = formatted.toString(status);
Handle<String> substring;
while (formatted.nextPosition(cfpos, status) && U_SUCCESS(status)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, substring,
Intl::ToString(isolate, string, cfpos.getStart(), cfpos.getLimit()),
JSArray);
Handle<String> type_string = factory->literal_string();
if (cfpos.getField() == ULISTFMT_ELEMENT_FIELD) {
type_string =
factory->NewStringFromAsciiChecked(types[type_index].c_str());
type_index++;
}
Intl::AddElement(isolate, array, index++, type_string, substring);
}
if (U_FAILURE(status)) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), JSArray);
}
JSObject::ValidateElements(*array);
return array;
}
MaybeHandle<String> JSDurationFormat::Format(Isolate* isolate,
Handle<JSDurationFormat> df,
Handle<Object> duration) {
const char* method_name = "Intl.DurationFormat.prototype.format";
return FormatCommon<String, FormattedToString>(isolate, df, duration,
method_name);
}
MaybeHandle<JSArray> JSDurationFormat::FormatToParts(
Isolate* isolate, Handle<JSDurationFormat> df, Handle<Object> duration) {
const char* method_name = "Intl.DurationFormat.prototype.formatToParts";
return FormatCommon<JSArray, FormattedListToJSArray>(isolate, df, duration,
method_name);
}
const std::set<std::string>& JSDurationFormat::GetAvailableLocales() {
return JSNumberFormat::GetAvailableLocales();
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,166 @@
// Copyright 2022 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
#ifndef V8_OBJECTS_JS_DURATION_FORMAT_H_
#define V8_OBJECTS_JS_DURATION_FORMAT_H_
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/objects/managed.h"
#include "src/objects/objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace U_ICU_NAMESPACE {
class Locale;
namespace number {
class LocalizedNumberFormatter;
} // namespace number
} // namespace U_ICU_NAMESPACE
namespace v8 {
namespace internal {
#include "torque-generated/src/objects/js-duration-format-tq.inc"
class JSDurationFormat
: public TorqueGeneratedJSDurationFormat<JSDurationFormat, JSObject> {
public:
// Creates duration format object with properties derived from input
// locales and options.
V8_WARN_UNUSED_RESULT static MaybeHandle<JSDurationFormat> New(
Isolate* isolate, Handle<Map> map, Handle<Object> locales,
Handle<Object> options);
V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSDurationFormat> format_holder);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> Format(
Isolate* isolate, Handle<JSDurationFormat> df, Handle<Object> duration);
V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> FormatToParts(
Isolate* isolate, Handle<JSDurationFormat> df, Handle<Object> duration);
V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales();
enum class Display {
kAuto,
kAlways,
kMax = kAlways
};
enum class Style {
kLong,
kShort,
kNarrow,
kDigital,
kMax = kDigital
};
// The ordering of these values is significant, because sub-ranges are
// encoded using bitfields.
enum class FieldStyle {
kLong,
kShort,
kNarrow,
kNumeric,
k2Digit,
kUndefined,
kStyle3Max = kNarrow,
kStyle4Max = kNumeric,
kStyle5Max = k2Digit,
};
#define DECLARE_INLINE_SETTER_GETTER(T, n) \
inline void set_##n(T display); \
inline T n() const;
#define DECLARE_INLINE_DISPLAY_SETTER_GETTER(f) \
DECLARE_INLINE_SETTER_GETTER(Display, f##_display)
#define DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(f) \
DECLARE_INLINE_SETTER_GETTER(FieldStyle, f##_style)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(years)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(months)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(weeks)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(days)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(hours)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(minutes)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(seconds)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(milliseconds)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(microseconds)
DECLARE_INLINE_DISPLAY_SETTER_GETTER(nanoseconds)
DECLARE_INLINE_SETTER_GETTER(Style, style)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(years)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(months)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(weeks)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(days)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(hours)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(minutes)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(seconds)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(milliseconds)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(microseconds)
DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER(nanoseconds)
#undef DECLARE_INLINE_SETTER_GETTER
#undef DECLARE_INLINE_STYLE_SETTER_GETTER
#undef DECLARE_INLINE_FIELD_STYLE_SETTER_GETTER
inline void set_fractional_digits(int32_t digits);
inline int32_t fractional_digits() const;
// Bit positions in |flags|.
DEFINE_TORQUE_GENERATED_JS_DURATION_FORMAT_DISPLAY_FLAGS()
DEFINE_TORQUE_GENERATED_JS_DURATION_FORMAT_STYLE_FLAGS()
static_assert(YearsDisplayBit::is_valid(Display::kMax));
static_assert(MonthsDisplayBit::is_valid(Display::kMax));
static_assert(WeeksDisplayBit::is_valid(Display::kMax));
static_assert(DaysDisplayBit::is_valid(Display::kMax));
static_assert(HoursDisplayBit::is_valid(Display::kMax));
static_assert(MinutesDisplayBit::is_valid(Display::kMax));
static_assert(SecondsDisplayBit::is_valid(Display::kMax));
static_assert(MillisecondsDisplayBit::is_valid(Display::kMax));
static_assert(MicrosecondsDisplayBit::is_valid(Display::kMax));
static_assert(NanosecondsDisplayBit::is_valid(Display::kMax));
static_assert(StyleBits::is_valid(Style::kMax));
static_assert(YearsStyleBits::is_valid(FieldStyle::kStyle3Max));
static_assert(MonthsStyleBits::is_valid(FieldStyle::kStyle3Max));
static_assert(WeeksStyleBits::is_valid(FieldStyle::kStyle3Max));
static_assert(DaysStyleBits::is_valid(FieldStyle::kStyle3Max));
static_assert(HoursStyleBits::is_valid(FieldStyle::kStyle5Max));
static_assert(MinutesStyleBits::is_valid(FieldStyle::kStyle5Max));
static_assert(SecondsStyleBits::is_valid(FieldStyle::kStyle5Max));
static_assert(MillisecondsStyleBits::is_valid(FieldStyle::kStyle4Max));
static_assert(MicrosecondsStyleBits::is_valid(FieldStyle::kStyle4Max));
static_assert(NanosecondsStyleBits::is_valid(FieldStyle::kStyle4Max));
DECL_ACCESSORS(icu_locale, Managed<icu::Locale>)
DECL_ACCESSORS(icu_number_formatter,
Managed<icu::number::LocalizedNumberFormatter>)
DECL_PRINTER(JSDurationFormat)
TQ_OBJECT_CONSTRUCTORS(JSDurationFormat)
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_DURATION_FORMAT_H_

View File

@ -0,0 +1,45 @@
// Copyright 2022 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.
#include 'src/objects/js-duration-format.h'
type JSDurationFormatStyle extends int32 constexpr 'JSDurationFormat::Style';
type JSDurationFormatFieldStyle extends int32
constexpr 'JSDurationFormat::FieldStyle';
type JSDurationFormatDisplay extends int32
constexpr 'JSDurationFormat::Display';
bitfield struct JSDurationFormatStyleFlags extends uint31 {
style: JSDurationFormatStyle: 2 bit;
years_style: JSDurationFormatFieldStyle: 2 bit;
months_style: JSDurationFormatFieldStyle: 2 bit;
weeks_style: JSDurationFormatFieldStyle: 2 bit;
days_style: JSDurationFormatFieldStyle: 2 bit;
hours_style: JSDurationFormatFieldStyle: 3 bit;
minutes_style: JSDurationFormatFieldStyle: 3 bit;
seconds_style: JSDurationFormatFieldStyle: 3 bit;
milliseconds_style: JSDurationFormatFieldStyle: 2 bit;
microseconds_style: JSDurationFormatFieldStyle: 2 bit;
nanoseconds_style: JSDurationFormatFieldStyle: 2 bit;
}
bitfield struct JSDurationFormatDisplayFlags extends uint31 {
years_display: JSDurationFormatDisplay: 1 bit;
months_display: JSDurationFormatDisplay: 1 bit;
weeks_display: JSDurationFormatDisplay: 1 bit;
days_display: JSDurationFormatDisplay: 1 bit;
hours_display: JSDurationFormatDisplay: 1 bit;
minutes_display: JSDurationFormatDisplay: 1 bit;
seconds_display: JSDurationFormatDisplay: 1 bit;
milliseconds_display: JSDurationFormatDisplay: 1 bit;
microseconds_display: JSDurationFormatDisplay: 1 bit;
nanoseconds_display: JSDurationFormatDisplay: 1 bit;
fractional_digits: int32: 4 bit;
}
extern class JSDurationFormat extends JSObject {
style_flags: SmiTagged<JSDurationFormatStyleFlags>;
display_flags: SmiTagged<JSDurationFormatDisplayFlags>;
icu_locale: Foreign; // Managed<icu::Locale>
icu_number_formatter:
Foreign; // Managed<icu::number::LocalizedNumberFormatter>
}

View File

@ -844,6 +844,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_DURATION_FORMAT_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:

View File

@ -458,7 +458,8 @@ const icu::UnicodeString CurrencyFromSkeleton(
return skeleton.tempSubString(index, 3);
}
const icu::UnicodeString NumberingSystemFromSkeleton(
} // namespace
const icu::UnicodeString JSNumberFormat::NumberingSystemFromSkeleton(
const icu::UnicodeString& skeleton) {
const char numbering_system[] = "numbering-system/";
int32_t index = skeleton.indexOf(numbering_system);
@ -470,6 +471,8 @@ const icu::UnicodeString NumberingSystemFromSkeleton(
return res.tempSubString(0, index);
}
namespace {
// Return CurrencySign as string based on skeleton.
Handle<String> CurrencySignString(Isolate* isolate,
const icu::UnicodeString& skeleton) {
@ -949,7 +952,7 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions(
Handle<String> locale = Handle<String>(number_format->locale(), isolate);
const icu::UnicodeString numberingSystem_ustr =
NumberingSystemFromSkeleton(skeleton);
JSNumberFormat::NumberingSystemFromSkeleton(skeleton);
// 5. For each row of Table 4, except the header row, in table order, do
// Table 4: Resolved Options of NumberFormat Instances
// Internal Slot Property

View File

@ -96,6 +96,9 @@ class JSNumberFormat
const Intl::NumberFormatDigitOptions& digit_options,
int rounding_increment, ShowTrailingZeros show);
static const icu::UnicodeString NumberingSystemFromSkeleton(
const icu::UnicodeString& skeleton);
V8_WARN_UNUSED_RESULT static Maybe<icu::number::LocalizedNumberRangeFormatter>
GetRangeFormatter(
Isolate* isolate, String locale,

View File

@ -42,6 +42,7 @@
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-date-time-format.h"
#include "src/objects/js-display-names.h"
#include "src/objects/js-duration-format.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-generator-inl.h"
#ifdef V8_INTL_SUPPORT
@ -2544,6 +2545,8 @@ int JSObject::GetHeaderSize(InstanceType type,
return JSDateTimeFormat::kHeaderSize;
case JS_DISPLAY_NAMES_TYPE:
return JSDisplayNames::kHeaderSize;
case JS_DURATION_FORMAT_TYPE:
return JSDurationFormat::kHeaderSize;
case JS_LIST_FORMAT_TYPE:
return JSListFormat::kHeaderSize;
case JS_LOCALE_TYPE:

View File

@ -103,47 +103,15 @@ struct InstantRecord {
Handle<Object> offset_string; // String or Undefined
};
// #sec-temporal-time-duration-records
struct TimeDurationRecord {
double days;
double hours;
double minutes;
double seconds;
double milliseconds;
double microseconds;
double nanoseconds;
// #sec-temporal-createtimedurationrecord
static Maybe<TimeDurationRecord> Create(Isolate* isolate, double days,
double hours, double minutes,
double seconds, double milliseconds,
double microseconds,
double nanoseconds);
};
// #sec-temporal-duration-records
// Cannot reuse DateDurationRecord here due to duplicate days.
struct DurationRecord {
double years;
double months;
double weeks;
TimeDurationRecord time_duration;
// #sec-temporal-createdurationrecord
static Maybe<DurationRecord> Create(Isolate* isolate, double years,
double months, double weeks, double days,
double hours, double minutes,
double seconds, double milliseconds,
double microseconds, double nanoseconds);
};
using temporal::DurationRecord;
using temporal::IsValidDuration;
using temporal::TimeDurationRecord;
struct DurationRecordWithRemainder {
DurationRecord record;
double remainder;
};
// #sec-temporal-isvalidduration
bool IsValidDuration(Isolate* isolate, const DurationRecord& dur);
// #sec-temporal-date-duration-records
struct DateDurationRecord {
double years;
@ -1005,6 +973,9 @@ Maybe<DateDurationRecord> DateDurationRecord::Create(
return Just(record);
}
} // namespace
namespace temporal {
// #sec-temporal-createtimedurationrecord
Maybe<TimeDurationRecord> TimeDurationRecord::Create(
Isolate* isolate, double days, double hours, double minutes, double seconds,
@ -1051,7 +1022,9 @@ Maybe<DurationRecord> DurationRecord::Create(
// (𝔽(nanoseconds)) }.
return Just(record);
}
} // namespace temporal
namespace {
// #sec-temporal-createtemporalduration
MaybeHandle<JSTemporalDuration> CreateTemporalDuration(
Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
@ -6025,6 +5998,10 @@ int32_t DurationSign(Isolate* isolaet, const DurationRecord& dur) {
return 0;
}
} // namespace
namespace temporal {
// #sec-temporal-isvalidduration
bool IsValidDuration(Isolate* isolate, const DurationRecord& dur) {
TEMPORAL_ENTER_FUNC();
@ -6055,6 +6032,10 @@ bool IsValidDuration(Isolate* isolate, const DurationRecord& dur) {
time.microseconds > 0 || time.nanoseconds > 0)));
}
} // namespace temporal
namespace {
// #sec-temporal-isisoleapyear
bool IsISOLeapYear(Isolate* isolate, int32_t year) {
TEMPORAL_ENTER_FUNC();

View File

@ -1146,6 +1146,49 @@ MaybeHandle<JSTemporalInstant> BuiltinTimeZoneGetInstantForCompatible(
Isolate* isolate, Handle<JSReceiver> time_zone,
Handle<JSTemporalPlainDateTime> date_time, const char* method_name);
// For Intl.DurationFormat
// #sec-temporal-time-duration-records
struct TimeDurationRecord {
double days;
double hours;
double minutes;
double seconds;
double milliseconds;
double microseconds;
double nanoseconds;
// #sec-temporal-createtimedurationrecord
static Maybe<TimeDurationRecord> Create(Isolate* isolate, double days,
double hours, double minutes,
double seconds, double milliseconds,
double microseconds,
double nanoseconds);
};
// #sec-temporal-duration-records
// Cannot reuse DateDurationRecord here due to duplicate days.
struct DurationRecord {
double years;
double months;
double weeks;
TimeDurationRecord time_duration;
// #sec-temporal-createdurationrecord
static Maybe<DurationRecord> Create(Isolate* isolate, double years,
double months, double weeks, double days,
double hours, double minutes,
double seconds, double milliseconds,
double microseconds, double nanoseconds);
};
// #sec-temporal-topartialduration
Maybe<DurationRecord> ToPartialDuration(
Isolate* isolate, Handle<Object> temporal_duration_like_obj,
const DurationRecord& input);
// #sec-temporal-isvalidduration
bool IsValidDuration(Isolate* isolate, const DurationRecord& dur);
} // namespace temporal
} // namespace internal
} // namespace v8

View File

@ -304,6 +304,7 @@ VisitorId Map::GetVisitorId(Map map) {
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_DURATION_FORMAT_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:

View File

@ -279,6 +279,7 @@ class ZoneForwardList;
V(JSCollator) \
V(JSDateTimeFormat) \
V(JSDisplayNames) \
V(JSDurationFormat) \
V(JSListFormat) \
V(JSLocale) \
V(JSNumberFormat) \

View File

@ -1285,6 +1285,7 @@ auto BodyDescriptorApply(InstanceType type, Args&&... args) {
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_DURATION_FORMAT_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:

View File

@ -86,6 +86,7 @@
// - JSCollator // If V8_INTL_SUPPORT enabled.
// - JSDateTimeFormat // If V8_INTL_SUPPORT enabled.
// - JSDisplayNames // If V8_INTL_SUPPORT enabled.
// - JSDurationFormat // If V8_INTL_SUPPORT enabled.
// - JSListFormat // If V8_INTL_SUPPORT enabled.
// - JSLocale // If V8_INTL_SUPPORT enabled.
// - JSNumberFormat // If V8_INTL_SUPPORT enabled.

View File

@ -653,60 +653,8 @@
'language/identifiers/start-unicode-15.0.0': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=11660
'intl402/DurationFormat/prototype/prototype_attributes': [FAIL],
'intl402/DurationFormat/prototype/constructor/prop-desc': [FAIL],
'intl402/DurationFormat/prototype/constructor/value': [FAIL],
'intl402/DurationFormat/prototype/format/length': [FAIL],
'intl402/DurationFormat/prototype/format/name': [FAIL],
'intl402/DurationFormat/prototype/format/prop-desc': [FAIL],
'intl402/DurationFormat/prototype/format/throw-invoked-as-func': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/length': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/name': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/prop-desc': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/throw-invoked-as-func': [FAIL],
'intl402/DurationFormat/prototype/resolvedOptions/length': [FAIL],
'intl402/DurationFormat/prototype/resolvedOptions/name': [FAIL],
'intl402/DurationFormat/prototype/resolvedOptions/prop-desc': [FAIL],
'intl402/DurationFormat/prototype/resolvedOptions/throw-invoked-as-func': [FAIL],
'intl402/DurationFormat/prototype/toStringTag/toString': [FAIL],
'intl402/DurationFormat/prototype/toStringTag/toStringTag': [FAIL],
'intl402/DurationFormat/constructor-locales-invalid': [FAIL],
'intl402/DurationFormat/constructor-locales-valid': [FAIL],
'intl402/DurationFormat/constructor-options-defaults': [FAIL],
'intl402/DurationFormat/constructor-options-fractionalDigits-invalid': [FAIL],
'intl402/DurationFormat/constructor-options-fractionalDigits-valid': [FAIL],
'intl402/DurationFormat/constructor-options-invalid': [FAIL],
'intl402/DurationFormat/constructor-options-localeMatcher-invalid': [FAIL],
'intl402/DurationFormat/constructor-options-localeMatcher-valid': [FAIL],
'intl402/DurationFormat/constructor-options-numberingSystem-invalid': [FAIL],
'intl402/DurationFormat/constructor-options-numberingSystem-valid': [FAIL],
'intl402/DurationFormat/constructor-options-order': [FAIL],
'intl402/DurationFormat/constructor-options-style-invalid': [FAIL],
'intl402/DurationFormat/constructor-options-style-valid': [FAIL],
'intl402/DurationFormat/extensibility': [FAIL],
'intl402/DurationFormat/length': [FAIL],
'intl402/DurationFormat/name': [FAIL],
'intl402/DurationFormat/newtarget-undefined': [FAIL],
'intl402/DurationFormat/prop-desc': [FAIL],
'intl402/DurationFormat/prototype': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/basic': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/branding': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/length': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/locales-empty': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/locales-invalid': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/locales-specific': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/name': [FAIL],
'intl402/DurationFormat/supportedLocalesOf/prop-desc': [FAIL],
'intl402/DurationFormat/prototype/format/invalid-negative-duration-throws': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/invalid-negative-duration-throws': [FAIL],
'intl402/DurationFormat/prototype/format/basic-format-en': [FAIL],
'intl402/DurationFormat/prototype/format/branding': [FAIL],
'intl402/DurationFormat/prototype/format/invalid-arguments-throws': [FAIL],
'intl402/DurationFormat/prototype/format/not-a-constructor': [FAIL],
# https://github.com/tc39/proposal-intl-duration-format/issues/114
'intl402/DurationFormat/prototype/format/style-options-en': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/branding': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/invalid-arguments-throws': [FAIL],
'intl402/DurationFormat/prototype/formatToParts/not-a-constructor': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=12763
'language/expressions/class/decorator/syntax/class-valid/decorator-member-expr-private-identifier': [FAIL],

View File

@ -42,6 +42,7 @@ from testrunner.outproc import test262
# TODO(littledan): move the flag mapping into the status file
FEATURE_FLAGS = {
'Intl.NumberFormat-v3': '--harmony-intl-number-format-v3',
'Intl.DurationFormat': '--harmony-intl-duration-format',
'Symbol.prototype.description': '--harmony-symbol-description',
'FinalizationRegistry': '--harmony-weak-refs-with-cleanup-some',
'WeakRef': '--harmony-weak-refs-with-cleanup-some',

View File

@ -53,6 +53,7 @@ export const CATEGORIES = new Map([
'JS_COLLATOR_TYPE',
'JS_DATE_TIME_FORMAT_TYPE',
'JS_DISPLAY_NAMES_TYPE',
'JS_DURATION_FORMAT_TYPE',
'JS_LIST_FORMAT_TYPE',
'JS_LOCALE_TYPE',
'JS_NUMBER_FORMAT_TYPE',

View File

@ -241,45 +241,46 @@ INSTANCE_TYPES = {
2111: "JS_DATE_TYPE",
2112: "JS_DATE_TIME_FORMAT_TYPE",
2113: "JS_DISPLAY_NAMES_TYPE",
2114: "JS_ERROR_TYPE",
2115: "JS_EXTERNAL_OBJECT_TYPE",
2116: "JS_FINALIZATION_REGISTRY_TYPE",
2117: "JS_LIST_FORMAT_TYPE",
2118: "JS_LOCALE_TYPE",
2119: "JS_MESSAGE_OBJECT_TYPE",
2120: "JS_NUMBER_FORMAT_TYPE",
2121: "JS_PLURAL_RULES_TYPE",
2122: "JS_REG_EXP_TYPE",
2123: "JS_REG_EXP_STRING_ITERATOR_TYPE",
2124: "JS_RELATIVE_TIME_FORMAT_TYPE",
2125: "JS_SEGMENT_ITERATOR_TYPE",
2126: "JS_SEGMENTER_TYPE",
2127: "JS_SEGMENTS_TYPE",
2128: "JS_SHADOW_REALM_TYPE",
2129: "JS_SHARED_ARRAY_TYPE",
2130: "JS_SHARED_STRUCT_TYPE",
2131: "JS_STRING_ITERATOR_TYPE",
2132: "JS_TEMPORAL_CALENDAR_TYPE",
2133: "JS_TEMPORAL_DURATION_TYPE",
2134: "JS_TEMPORAL_INSTANT_TYPE",
2135: "JS_TEMPORAL_PLAIN_DATE_TYPE",
2136: "JS_TEMPORAL_PLAIN_DATE_TIME_TYPE",
2137: "JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE",
2138: "JS_TEMPORAL_PLAIN_TIME_TYPE",
2139: "JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE",
2140: "JS_TEMPORAL_TIME_ZONE_TYPE",
2141: "JS_TEMPORAL_ZONED_DATE_TIME_TYPE",
2142: "JS_V8_BREAK_ITERATOR_TYPE",
2143: "JS_WEAK_REF_TYPE",
2144: "WASM_EXCEPTION_PACKAGE_TYPE",
2145: "WASM_GLOBAL_OBJECT_TYPE",
2146: "WASM_INSTANCE_OBJECT_TYPE",
2147: "WASM_MEMORY_OBJECT_TYPE",
2148: "WASM_MODULE_OBJECT_TYPE",
2149: "WASM_SUSPENDER_OBJECT_TYPE",
2150: "WASM_TABLE_OBJECT_TYPE",
2151: "WASM_TAG_OBJECT_TYPE",
2152: "WASM_VALUE_OBJECT_TYPE",
2114: "JS_DURATION_FORMAT_TYPE",
2115: "JS_ERROR_TYPE",
2116: "JS_EXTERNAL_OBJECT_TYPE",
2117: "JS_FINALIZATION_REGISTRY_TYPE",
2118: "JS_LIST_FORMAT_TYPE",
2119: "JS_LOCALE_TYPE",
2120: "JS_MESSAGE_OBJECT_TYPE",
2121: "JS_NUMBER_FORMAT_TYPE",
2122: "JS_PLURAL_RULES_TYPE",
2123: "JS_REG_EXP_TYPE",
2124: "JS_REG_EXP_STRING_ITERATOR_TYPE",
2125: "JS_RELATIVE_TIME_FORMAT_TYPE",
2126: "JS_SEGMENT_ITERATOR_TYPE",
2127: "JS_SEGMENTER_TYPE",
2128: "JS_SEGMENTS_TYPE",
2129: "JS_SHADOW_REALM_TYPE",
2130: "JS_SHARED_ARRAY_TYPE",
2131: "JS_SHARED_STRUCT_TYPE",
2132: "JS_STRING_ITERATOR_TYPE",
2133: "JS_TEMPORAL_CALENDAR_TYPE",
2134: "JS_TEMPORAL_DURATION_TYPE",
2135: "JS_TEMPORAL_INSTANT_TYPE",
2136: "JS_TEMPORAL_PLAIN_DATE_TYPE",
2137: "JS_TEMPORAL_PLAIN_DATE_TIME_TYPE",
2138: "JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE",
2139: "JS_TEMPORAL_PLAIN_TIME_TYPE",
2140: "JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE",
2141: "JS_TEMPORAL_TIME_ZONE_TYPE",
2142: "JS_TEMPORAL_ZONED_DATE_TIME_TYPE",
2143: "JS_V8_BREAK_ITERATOR_TYPE",
2144: "JS_WEAK_REF_TYPE",
2145: "WASM_EXCEPTION_PACKAGE_TYPE",
2146: "WASM_GLOBAL_OBJECT_TYPE",
2147: "WASM_INSTANCE_OBJECT_TYPE",
2148: "WASM_MEMORY_OBJECT_TYPE",
2149: "WASM_MODULE_OBJECT_TYPE",
2150: "WASM_SUSPENDER_OBJECT_TYPE",
2151: "WASM_TABLE_OBJECT_TYPE",
2152: "WASM_TAG_OBJECT_TYPE",
2153: "WASM_VALUE_OBJECT_TYPE",
}
# List of known V8 maps.
@ -393,78 +394,78 @@ KNOWN_MAPS = {
("read_only_space", 0x03491): (131, "BasicBlockCountersMarkerMap"),
("read_only_space", 0x034d5): (146, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x035d5): (159, "InterceptorInfoMap"),
("read_only_space", 0x07455): (132, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x0747d): (133, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x074a5): (134, "CallableTaskMap"),
("read_only_space", 0x074cd): (135, "CallbackTaskMap"),
("read_only_space", 0x074f5): (136, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x0751d): (139, "FunctionTemplateInfoMap"),
("read_only_space", 0x07545): (140, "ObjectTemplateInfoMap"),
("read_only_space", 0x0756d): (141, "AccessCheckInfoMap"),
("read_only_space", 0x07595): (142, "AccessorPairMap"),
("read_only_space", 0x075bd): (143, "AliasedArgumentsEntryMap"),
("read_only_space", 0x075e5): (144, "AllocationMementoMap"),
("read_only_space", 0x0760d): (147, "AsmWasmDataMap"),
("read_only_space", 0x07635): (148, "AsyncGeneratorRequestMap"),
("read_only_space", 0x0765d): (149, "BreakPointMap"),
("read_only_space", 0x07685): (150, "BreakPointInfoMap"),
("read_only_space", 0x076ad): (151, "CachedTemplateObjectMap"),
("read_only_space", 0x076d5): (152, "CallSiteInfoMap"),
("read_only_space", 0x076fd): (153, "ClassPositionsMap"),
("read_only_space", 0x07725): (154, "DebugInfoMap"),
("read_only_space", 0x0774d): (156, "ErrorStackDataMap"),
("read_only_space", 0x07775): (158, "FunctionTemplateRareDataMap"),
("read_only_space", 0x0779d): (160, "InterpreterDataMap"),
("read_only_space", 0x077c5): (161, "ModuleRequestMap"),
("read_only_space", 0x077ed): (162, "PromiseCapabilityMap"),
("read_only_space", 0x07815): (163, "PromiseOnStackMap"),
("read_only_space", 0x0783d): (164, "PromiseReactionMap"),
("read_only_space", 0x07865): (165, "PropertyDescriptorObjectMap"),
("read_only_space", 0x0788d): (166, "PrototypeInfoMap"),
("read_only_space", 0x078b5): (167, "RegExpBoilerplateDescriptionMap"),
("read_only_space", 0x078dd): (168, "ScriptMap"),
("read_only_space", 0x07905): (169, "ScriptOrModuleMap"),
("read_only_space", 0x0792d): (170, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x07955): (171, "StackFrameInfoMap"),
("read_only_space", 0x0797d): (172, "TemplateObjectDescriptionMap"),
("read_only_space", 0x079a5): (173, "Tuple2Map"),
("read_only_space", 0x079cd): (174, "WasmExceptionTagMap"),
("read_only_space", 0x079f5): (175, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x07a1d): (195, "SloppyArgumentsElementsMap"),
("read_only_space", 0x07a45): (228, "DescriptorArrayMap"),
("read_only_space", 0x07a6d): (217, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x07a95): (215, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x07abd): (218, "UncompiledDataWithoutPreparseDataWithJobMap"),
("read_only_space", 0x07ae5): (216, "UncompiledDataWithPreparseDataAndJobMap"),
("read_only_space", 0x07b0d): (249, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x07b35): (196, "TurbofanBitsetTypeMap"),
("read_only_space", 0x07b5d): (200, "TurbofanUnionTypeMap"),
("read_only_space", 0x07b85): (199, "TurbofanRangeTypeMap"),
("read_only_space", 0x07bad): (197, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x07bd5): (198, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x07bfd): (245, "InternalClassMap"),
("read_only_space", 0x07c25): (256, "SmiPairMap"),
("read_only_space", 0x07c4d): (255, "SmiBoxMap"),
("read_only_space", 0x07c75): (201, "ExportedSubClassBaseMap"),
("read_only_space", 0x07c9d): (202, "ExportedSubClassMap"),
("read_only_space", 0x07cc5): (226, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x07ced): (227, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x07d15): (194, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x07d3d): (246, "InternalClassWithStructElementsMap"),
("read_only_space", 0x07d65): (203, "ExportedSubClass2Map"),
("read_only_space", 0x07d8d): (257, "SortStateMap"),
("read_only_space", 0x07db5): (263, "WasmStringViewIterMap"),
("read_only_space", 0x07ddd): (145, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x07e05): (145, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x07ed1): (137, "LoadHandler1Map"),
("read_only_space", 0x07ef9): (137, "LoadHandler2Map"),
("read_only_space", 0x07f21): (137, "LoadHandler3Map"),
("read_only_space", 0x07f49): (138, "StoreHandler0Map"),
("read_only_space", 0x07f71): (138, "StoreHandler1Map"),
("read_only_space", 0x07f99): (138, "StoreHandler2Map"),
("read_only_space", 0x07fc1): (138, "StoreHandler3Map"),
("old_space", 0x0439d): (2115, "ExternalMap"),
("old_space", 0x043cd): (2119, "JSMessageObjectMap"),
("read_only_space", 0x075ad): (132, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x075d5): (133, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x075fd): (134, "CallableTaskMap"),
("read_only_space", 0x07625): (135, "CallbackTaskMap"),
("read_only_space", 0x0764d): (136, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x07675): (139, "FunctionTemplateInfoMap"),
("read_only_space", 0x0769d): (140, "ObjectTemplateInfoMap"),
("read_only_space", 0x076c5): (141, "AccessCheckInfoMap"),
("read_only_space", 0x076ed): (142, "AccessorPairMap"),
("read_only_space", 0x07715): (143, "AliasedArgumentsEntryMap"),
("read_only_space", 0x0773d): (144, "AllocationMementoMap"),
("read_only_space", 0x07765): (147, "AsmWasmDataMap"),
("read_only_space", 0x0778d): (148, "AsyncGeneratorRequestMap"),
("read_only_space", 0x077b5): (149, "BreakPointMap"),
("read_only_space", 0x077dd): (150, "BreakPointInfoMap"),
("read_only_space", 0x07805): (151, "CachedTemplateObjectMap"),
("read_only_space", 0x0782d): (152, "CallSiteInfoMap"),
("read_only_space", 0x07855): (153, "ClassPositionsMap"),
("read_only_space", 0x0787d): (154, "DebugInfoMap"),
("read_only_space", 0x078a5): (156, "ErrorStackDataMap"),
("read_only_space", 0x078cd): (158, "FunctionTemplateRareDataMap"),
("read_only_space", 0x078f5): (160, "InterpreterDataMap"),
("read_only_space", 0x0791d): (161, "ModuleRequestMap"),
("read_only_space", 0x07945): (162, "PromiseCapabilityMap"),
("read_only_space", 0x0796d): (163, "PromiseOnStackMap"),
("read_only_space", 0x07995): (164, "PromiseReactionMap"),
("read_only_space", 0x079bd): (165, "PropertyDescriptorObjectMap"),
("read_only_space", 0x079e5): (166, "PrototypeInfoMap"),
("read_only_space", 0x07a0d): (167, "RegExpBoilerplateDescriptionMap"),
("read_only_space", 0x07a35): (168, "ScriptMap"),
("read_only_space", 0x07a5d): (169, "ScriptOrModuleMap"),
("read_only_space", 0x07a85): (170, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x07aad): (171, "StackFrameInfoMap"),
("read_only_space", 0x07ad5): (172, "TemplateObjectDescriptionMap"),
("read_only_space", 0x07afd): (173, "Tuple2Map"),
("read_only_space", 0x07b25): (174, "WasmExceptionTagMap"),
("read_only_space", 0x07b4d): (175, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x07b75): (195, "SloppyArgumentsElementsMap"),
("read_only_space", 0x07b9d): (228, "DescriptorArrayMap"),
("read_only_space", 0x07bc5): (217, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x07bed): (215, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x07c15): (218, "UncompiledDataWithoutPreparseDataWithJobMap"),
("read_only_space", 0x07c3d): (216, "UncompiledDataWithPreparseDataAndJobMap"),
("read_only_space", 0x07c65): (249, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x07c8d): (196, "TurbofanBitsetTypeMap"),
("read_only_space", 0x07cb5): (200, "TurbofanUnionTypeMap"),
("read_only_space", 0x07cdd): (199, "TurbofanRangeTypeMap"),
("read_only_space", 0x07d05): (197, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x07d2d): (198, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x07d55): (245, "InternalClassMap"),
("read_only_space", 0x07d7d): (256, "SmiPairMap"),
("read_only_space", 0x07da5): (255, "SmiBoxMap"),
("read_only_space", 0x07dcd): (201, "ExportedSubClassBaseMap"),
("read_only_space", 0x07df5): (202, "ExportedSubClassMap"),
("read_only_space", 0x07e1d): (226, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x07e45): (227, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x07e6d): (194, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x07e95): (246, "InternalClassWithStructElementsMap"),
("read_only_space", 0x07ebd): (203, "ExportedSubClass2Map"),
("read_only_space", 0x07ee5): (257, "SortStateMap"),
("read_only_space", 0x07f0d): (263, "WasmStringViewIterMap"),
("read_only_space", 0x07f35): (145, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x07f5d): (145, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x08029): (137, "LoadHandler1Map"),
("read_only_space", 0x08051): (137, "LoadHandler2Map"),
("read_only_space", 0x08079): (137, "LoadHandler3Map"),
("read_only_space", 0x080a1): (138, "StoreHandler0Map"),
("read_only_space", 0x080c9): (138, "StoreHandler1Map"),
("read_only_space", 0x080f1): (138, "StoreHandler2Map"),
("read_only_space", 0x08119): (138, "StoreHandler3Map"),
("old_space", 0x0439d): (2116, "ExternalMap"),
("old_space", 0x043cd): (2120, "JSMessageObjectMap"),
}
# List of known V8 objects.