[intl] Part 3 of NumberFormat v3

Add NumberFormat.prototype.formatRange(ToParts)?

https://github.com/tc39/proposal-intl-numberformat-v3

https://chromestatus.com/guide/edit/5707621009981440

Design Doc: https://docs.google.com/document/d/19jAogPBb6W4Samt8NWGZKu47iv0_KoQhBvLgQH3xvr8/edit


Bug: v8:10776
Change-Id: I9bb163c0c15ccac9d3a2d5e55ad38aa5c06bbaa6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3429464
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79373}
This commit is contained in:
Frank Tang 2022-03-03 18:53:18 -08:00 committed by V8 LUCI CQ
parent 82c4c977b3
commit a4bdc77fe8
14 changed files with 663 additions and 166 deletions

View File

@ -1771,6 +1771,10 @@ namespace internal {
CPP(NumberFormatInternalFormatNumber) \
/* ecma402 #sec-intl.numberformat.prototype.format */ \
CPP(NumberFormatPrototypeFormatNumber) \
/* ecma402 #sec-intl.numberformat.prototype.formatrange */ \
CPP(NumberFormatPrototypeFormatRange) \
/* ecma402 #sec-intl.numberformat.prototype.formatrangetoparts */ \
CPP(NumberFormatPrototypeFormatRangeToParts) \
/* ecma402 #sec-intl.numberformat.prototype.formattoparts */ \
CPP(NumberFormatPrototypeFormatToParts) \
/* ecma402 #sec-intl.numberformat.prototype.resolvedoptions */ \

View File

@ -163,11 +163,10 @@ BUILTIN(DateTimeFormatPrototypeFormatToParts) {
}
// Common code for DateTimeFormatPrototypeFormtRange(|ToParts)
template <class T>
template <class T, MaybeHandle<T> (*F)(Isolate*, Handle<JSDateTimeFormat>,
double, double)>
V8_WARN_UNUSED_RESULT Object DateTimeFormatRange(
BuiltinArguments args, Isolate* isolate, const char* const method_name,
MaybeHandle<T> (*format)(Isolate*, Handle<JSDateTimeFormat>, double,
double)) {
BuiltinArguments args, Isolate* isolate, const char* const method_name) {
// 1. Let dtf be this value.
// 2. If Type(dtf) is not Object, throw a TypeError exception.
CHECK_RECEIVER(JSObject, date_format_holder, method_name);
@ -211,22 +210,22 @@ V8_WARN_UNUSED_RESULT Object DateTimeFormatRange(
// 8. Return ? FormatDateTimeRange(dtf, x, y)
// OR
// 8. Return ? FormatDateTimeRangeToParts(dtf, x, y).
RETURN_RESULT_OR_FAILURE(isolate, format(isolate, dtf, x, y));
RETURN_RESULT_OR_FAILURE(isolate, F(isolate, dtf, x, y));
}
BUILTIN(DateTimeFormatPrototypeFormatRange) {
const char* const method_name = "Intl.DateTimeFormat.prototype.formatRange";
HandleScope handle_scope(isolate);
return DateTimeFormatRange<String>(args, isolate, method_name,
JSDateTimeFormat::FormatRange);
return DateTimeFormatRange<String, JSDateTimeFormat::FormatRange>(
args, isolate, method_name);
}
BUILTIN(DateTimeFormatPrototypeFormatRangeToParts) {
const char* const method_name =
"Intl.DateTimeFormat.prototype.formatRangeToParts";
HandleScope handle_scope(isolate);
return DateTimeFormatRange<JSArray>(args, isolate, method_name,
JSDateTimeFormat::FormatRangeToParts);
return DateTimeFormatRange<JSArray, JSDateTimeFormat::FormatRangeToParts>(
args, isolate, method_name);
}
namespace {
@ -527,6 +526,63 @@ BUILTIN(NumberFormatInternalFormatNumber) {
isolate, *icu_localized_number_formatter, numeric_obj));
}
// Common code for NumberFormatPrototypeFormtRange(|ToParts)
template <class T, MaybeHandle<T> (*F)(Isolate*, Handle<JSNumberFormat>,
Handle<Object>, Handle<Object>)>
V8_WARN_UNUSED_RESULT Object NumberFormatRange(BuiltinArguments args,
Isolate* isolate,
const char* const method_name) {
// 1. Let nf be this value.
// 2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
CHECK_RECEIVER(JSNumberFormat, nf, method_name);
Handle<Object> start = args.atOrUndefined(isolate, 1);
Handle<Object> end = args.atOrUndefined(isolate, 2);
Factory* factory = isolate->factory();
// 3. If start is undefined or end is undefined, throw a TypeError exception.
if (start->IsUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kInvalid,
factory->NewStringFromStaticChars("start"), start));
}
if (end->IsUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kInvalid,
factory->NewStringFromStaticChars("end"), end));
}
// 4. Let x be ? ToIntlMathematicalValue(start).
Handle<Object> x;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, x,
Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, start));
// 5. Let y be ? ToIntlMathematicalValue(end).
Handle<Object> y;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, y,
Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, end));
RETURN_RESULT_OR_FAILURE(isolate, F(isolate, nf, x, y));
}
BUILTIN(NumberFormatPrototypeFormatRange) {
const char* const method_name = "Intl.NumberFormat.prototype.formatRange";
HandleScope handle_scope(isolate);
return NumberFormatRange<String, JSNumberFormat::FormatNumericRange>(
args, isolate, method_name);
}
BUILTIN(NumberFormatPrototypeFormatRangeToParts) {
const char* const method_name =
"Intl.NumberFormat.prototype.formatRangeToParts";
HandleScope handle_scope(isolate);
return NumberFormatRange<JSArray, JSNumberFormat::FormatNumericRangeToParts>(
args, isolate, method_name);
}
BUILTIN(DateTimeFormatConstructor) {
HandleScope scope(isolate);

View File

@ -4427,7 +4427,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_error_cause)
#ifdef V8_INTL_SUPPORT
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_best_fit_matcher)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_number_format_v3)
#endif // V8_INTL_SUPPORT
#undef EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE
@ -5335,6 +5334,32 @@ void Genesis::InitializeGlobal_harmony_intl_locale_info() {
Builtin::kLocalePrototypeWeekInfo, true);
}
void Genesis::InitializeGlobal_harmony_intl_number_format_v3() {
if (!FLAG_harmony_intl_number_format_v3) return;
Handle<JSObject> intl = Handle<JSObject>::cast(
JSReceiver::GetProperty(
isolate(),
Handle<JSReceiver>(native_context()->global_object(), isolate()),
factory()->InternalizeUtf8String("Intl"))
.ToHandleChecked());
Handle<JSFunction> number_format_constructor = Handle<JSFunction>::cast(
JSReceiver::GetProperty(
isolate(), Handle<JSReceiver>(JSReceiver::cast(*intl), isolate()),
factory()->InternalizeUtf8String("NumberFormat"))
.ToHandleChecked());
Handle<JSObject> prototype(
JSObject::cast(number_format_constructor->prototype()), isolate());
SimpleInstallFunction(isolate(), prototype, "formatRange",
Builtin::kNumberFormatPrototypeFormatRange, 2, false);
SimpleInstallFunction(isolate(), prototype, "formatRangeToParts",
Builtin::kNumberFormatPrototypeFormatRangeToParts, 2,
false);
}
void Genesis::InitializeGlobal_harmony_intl_enumeration() {
if (!FLAG_harmony_intl_enumeration) return;

View File

@ -85,6 +85,7 @@
V(_, minimumFractionDigits_string, "minimumFractionDigits") \
V(_, minimumIntegerDigits_string, "minimumIntegerDigits") \
V(_, minimumSignificantDigits_string, "minimumSignificantDigits") \
V(_, minus_0, "-0") \
V(_, minusSign_string, "minusSign") \
V(_, morePrecision_string, "morePrecision") \
V(_, nan_string, "nan") \

View File

@ -2916,5 +2916,45 @@ MaybeHandle<Object> Intl::ToIntlMathematicalValueAsNumberBigIntOrString(
return input;
}
Intl::FormatRangeSourceTracker::FormatRangeSourceTracker() {
start_[0] = start_[1] = limit_[0] = limit_[1] = 0;
}
void Intl::FormatRangeSourceTracker::Add(int32_t field, int32_t start,
int32_t limit) {
DCHECK_LT(field, 2);
start_[field] = start;
limit_[field] = limit;
}
Intl::FormatRangeSource Intl::FormatRangeSourceTracker::GetSource(
int32_t start, int32_t limit) const {
FormatRangeSource source = FormatRangeSource::kShared;
if (FieldContains(0, start, limit)) {
source = FormatRangeSource::kStartRange;
} else if (FieldContains(1, start, limit)) {
source = FormatRangeSource::kEndRange;
}
return source;
}
bool Intl::FormatRangeSourceTracker::FieldContains(int32_t field, int32_t start,
int32_t limit) const {
DCHECK_LT(field, 2);
return (start_[field] <= start) && (start <= limit_[field]) &&
(start_[field] <= limit) && (limit <= limit_[field]);
}
Handle<String> Intl::SourceString(Isolate* isolate, FormatRangeSource source) {
switch (source) {
case FormatRangeSource::kShared:
return ReadOnlyRoots(isolate).shared_string_handle();
case FormatRangeSource::kStartRange:
return ReadOnlyRoots(isolate).startRange_string_handle();
case FormatRangeSource::kEndRange:
return ReadOnlyRoots(isolate).endRange_string_handle();
}
}
} // namespace internal
} // namespace v8

View File

@ -59,6 +59,24 @@ class Intl {
kLength
};
enum class FormatRangeSource { kShared, kStartRange, kEndRange };
class FormatRangeSourceTracker {
public:
FormatRangeSourceTracker();
void Add(int32_t field, int32_t start, int32_t limit);
FormatRangeSource GetSource(int32_t start, int32_t limit) const;
private:
int32_t start_[2];
int32_t limit_[2];
bool FieldContains(int32_t field, int32_t start, int32_t limit) const;
};
static Handle<String> SourceString(Isolate* isolate,
FormatRangeSource source);
// Build a set of ICU locales from a list of Locales. If there is a locale
// with a script tag then the locales also include a locale without the
// script; eg, pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India)

View File

@ -2101,56 +2101,12 @@ Handle<String> JSDateTimeFormat::HourCycleAsString() const {
}
}
enum Source { kShared, kStartRange, kEndRange };
namespace {
class SourceTracker {
public:
SourceTracker() { start_[0] = start_[1] = limit_[0] = limit_[1] = 0; }
void Add(int32_t field, int32_t start, int32_t limit) {
DCHECK_LT(field, 2);
start_[field] = start;
limit_[field] = limit;
}
Source GetSource(int32_t start, int32_t limit) const {
Source source = Source::kShared;
if (FieldContains(0, start, limit)) {
source = Source::kStartRange;
} else if (FieldContains(1, start, limit)) {
source = Source::kEndRange;
}
return source;
}
private:
int32_t start_[2];
int32_t limit_[2];
bool FieldContains(int32_t field, int32_t start, int32_t limit) const {
DCHECK_LT(field, 2);
return (start_[field] <= start) && (start <= limit_[field]) &&
(start_[field] <= limit) && (limit <= limit_[field]);
}
};
Handle<String> SourceString(Isolate* isolate, Source source) {
switch (source) {
case Source::kShared:
return ReadOnlyRoots(isolate).shared_string_handle();
case Source::kStartRange:
return ReadOnlyRoots(isolate).startRange_string_handle();
case Source::kEndRange:
return ReadOnlyRoots(isolate).endRange_string_handle();
UNREACHABLE();
}
}
Maybe<bool> AddPartForFormatRange(Isolate* isolate, Handle<JSArray> array,
const icu::UnicodeString& string,
int32_t index, int32_t field, int32_t start,
int32_t end, const SourceTracker& tracker) {
Maybe<bool> AddPartForFormatRange(
Isolate* isolate, Handle<JSArray> array, const icu::UnicodeString& string,
int32_t index, int32_t field, int32_t start, int32_t end,
const Intl::FormatRangeSourceTracker& tracker) {
Handle<String> substring;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, substring,
Intl::ToString(isolate, string, start, end),
@ -2158,7 +2114,7 @@ Maybe<bool> AddPartForFormatRange(Isolate* isolate, Handle<JSArray> array,
Intl::AddElement(isolate, array, index,
IcuDateFieldIdToDateType(field, isolate), substring,
isolate->factory()->source_string(),
SourceString(isolate, tracker.GetSource(start, end)));
Intl::SourceString(isolate, tracker.GetSource(start, end)));
return Just(true);
}
@ -2193,7 +2149,7 @@ MaybeHandle<JSArray> FormattedDateIntervalToJSArray(
icu::ConstrainedFieldPosition cfpos;
int index = 0;
int32_t previous_end_pos = 0;
SourceTracker tracker;
Intl::FormatRangeSourceTracker tracker;
*outputRange = false;
while (formatted.nextPosition(cfpos, status)) {
int32_t category = cfpos.getCategory();
@ -2241,13 +2197,11 @@ MaybeHandle<JSArray> FormattedDateIntervalToJSArray(
}
// The shared code between formatRange and formatRangeToParts
template <typename T>
MaybeHandle<T> FormatRangeCommon(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, double x,
double y,
const std::function<MaybeHandle<T>(Isolate*, const icu::FormattedValue&,
bool*)>& formatToResult,
bool* outputRange) {
template <typename T,
MaybeHandle<T> (*F)(Isolate*, const icu::FormattedValue&, bool*)>
MaybeHandle<T> FormatRangeCommon(Isolate* isolate,
Handle<JSDateTimeFormat> date_time_format,
double x, double y, bool* outputRange) {
// Track newer feature formateRange and formatRangeToParts
isolate->CountUsage(v8::Isolate::UseCounterFeature::kDateTimeFormatRange);
@ -2290,7 +2244,7 @@ MaybeHandle<T> FormatRangeCommon(
if (U_FAILURE(status)) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), T);
}
return formatToResult(isolate, formatted, outputRange);
return F(isolate, formatted, outputRange);
}
} // namespace
@ -2299,8 +2253,8 @@ MaybeHandle<String> JSDateTimeFormat::FormatRange(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, double x,
double y) {
bool outputRange = true;
MaybeHandle<String> ret = FormatRangeCommon<String>(
isolate, date_time_format, x, y, FormattedToString, &outputRange);
MaybeHandle<String> ret = FormatRangeCommon<String, FormattedToString>(
isolate, date_time_format, x, y, &outputRange);
if (outputRange) {
return ret;
}
@ -2313,8 +2267,8 @@ MaybeHandle<JSArray> JSDateTimeFormat::FormatRangeToParts(
double y) {
bool outputRange = true;
MaybeHandle<JSArray> ret =
FormatRangeCommon<JSArray>(isolate, date_time_format, x, y,
FormattedDateIntervalToJSArray, &outputRange);
FormatRangeCommon<JSArray, FormattedDateIntervalToJSArray>(
isolate, date_time_format, x, y, &outputRange);
if (outputRange) {
return ret;
}

View File

@ -25,6 +25,9 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(JSNumberFormat)
ACCESSORS(JSNumberFormat, icu_number_formatter,
Managed<icu::number::LocalizedNumberFormatter>,
kIcuNumberFormatterOffset)
ACCESSORS(JSNumberFormat, icu_number_range_formatter,
Managed<icu::number::LocalizedNumberRangeFormatter>,
kIcuNumberRangeFormatterOffset)
} // namespace internal
} // namespace v8

View File

@ -20,6 +20,7 @@
#include "unicode/currunit.h"
#include "unicode/locid.h"
#include "unicode/numberformatter.h"
#include "unicode/numberrangeformatter.h"
#include "unicode/numsys.h"
#include "unicode/ucurr.h"
#include "unicode/uloc.h"
@ -1610,12 +1611,24 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
icu::number::LocalizedNumberFormatter icu_number_formatter =
settings.locale(icu_locale);
icu::number::LocalizedNumberRangeFormatter icu_number_range_formatter =
icu::number::UnlocalizedNumberRangeFormatter()
.numberFormatterBoth(settings)
.locale(icu_locale);
Handle<Managed<icu::number::LocalizedNumberFormatter>>
managed_number_formatter =
Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr(
isolate, 0,
new icu::number::LocalizedNumberFormatter(icu_number_formatter));
Handle<Managed<icu::number::LocalizedNumberRangeFormatter>>
managed_number_range_formatter =
Managed<icu::number::LocalizedNumberRangeFormatter>::FromRawPtr(
isolate, 0,
new icu::number::LocalizedNumberRangeFormatter(
icu_number_range_formatter));
// Now all properties are ready, so we can allocate the result object.
Handle<JSNumberFormat> number_format = Handle<JSNumberFormat>::cast(
isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
@ -1623,6 +1636,8 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
number_format->set_locale(*locale_str);
number_format->set_icu_number_formatter(*managed_number_formatter);
number_format->set_icu_number_range_formatter(
*managed_number_range_formatter);
number_format->set_bound_format(*factory->undefined_value());
// 31. Return numberFormat.
@ -1653,6 +1668,8 @@ Maybe<bool> IcuFormatNumber(
*formatted = number_format.formatDecimal({char_buffer, length}, status);
} else {
if (FLAG_harmony_intl_number_format_v3 && numeric_obj->IsString()) {
// TODO(ftang) Correct the handling of string after the resolution of
// https://github.com/tc39/proposal-intl-numberformat-v3/pull/82
Handle<String> string =
String::Flatten(isolate, Handle<String>::cast(numeric_obj));
DisallowGarbageCollection no_gc;
@ -1687,6 +1704,38 @@ Maybe<bool> IcuFormatNumber(
return Just(true);
}
Maybe<icu::Formattable> ToFormattable(Isolate* isolate, Handle<Object> obj,
const char* field) {
if (obj->IsBigInt()) {
Handle<BigInt> big_int = Handle<BigInt>::cast(obj);
Handle<String> big_int_string;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, big_int_string,
BigInt::ToString(isolate, big_int),
Nothing<icu::Formattable>());
big_int_string = String::Flatten(isolate, big_int_string);
{
DisallowGarbageCollection no_gc;
const String::FlatContent& flat = big_int_string->GetFlatContent(no_gc);
int32_t length = big_int_string->length();
DCHECK(flat.IsOneByte());
const char* char_buffer =
reinterpret_cast<const char*>(flat.ToOneByteVector().begin());
UErrorCode status = U_ZERO_ERROR;
icu::Formattable result({char_buffer, length}, status);
if (U_SUCCESS(status)) return Just(result);
}
THROW_NEW_ERROR_RETURN_VALUE(isolate,
NewTypeError(MessageTemplate::kIcuError),
Nothing<icu::Formattable>());
}
// TODO(ftang) Handle the case of IsString after the resolution of
// https://github.com/tc39/proposal-intl-numberformat-v3/pull/82
// FormatRange(|ToParts) does not allow NaN
DCHECK(!obj->IsNaN());
return Just(icu::Formattable(obj->Number()));
}
bool cmp_NumberFormatSpan(const NumberFormatSpan& a,
const NumberFormatSpan& b) {
// Regions that start earlier should be encountered earlier.
@ -1797,7 +1846,7 @@ std::vector<NumberFormatSpan> FlattenRegionsToParts(
namespace {
Maybe<int> ConstructParts(Isolate* isolate, icu::FormattedValue* formatted,
Handle<JSArray> result, int start_index,
bool style_is_unit, bool is_nan) {
bool style_is_unit, bool is_nan, bool output_source) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString formatted_text = formatted->toString(status);
if (U_FAILURE(status)) {
@ -1814,12 +1863,21 @@ Maybe<int> ConstructParts(Isolate* isolate, icu::FormattedValue* formatted,
// 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_text.length()));
Intl::FormatRangeSourceTracker tracker;
{
icu::ConstrainedFieldPosition cfp;
cfp.constrainCategory(UFIELD_CATEGORY_NUMBER);
while (formatted->nextPosition(cfp, status)) {
regions.push_back(
NumberFormatSpan(cfp.getField(), cfp.getStart(), cfp.getLimit()));
icu::ConstrainedFieldPosition cfpos;
while (formatted->nextPosition(cfpos, status)) {
int32_t category = cfpos.getCategory();
int32_t field = cfpos.getField();
int32_t start = cfpos.getStart();
int32_t limit = cfpos.getLimit();
if (category == UFIELD_CATEGORY_NUMBER_RANGE_SPAN) {
DCHECK_LE(field, 2);
DCHECK(FLAG_harmony_intl_number_format_v3);
tracker.Add(field, start, limit);
} else {
regions.push_back(NumberFormatSpan(field, start, limit));
}
}
}
@ -1844,13 +1902,168 @@ Maybe<int> ConstructParts(Isolate* isolate, icu::FormattedValue* formatted,
Intl::ToString(isolate, formatted_text, part.begin_pos, part.end_pos),
Nothing<int>());
Intl::AddElement(isolate, result, index, field_type_string, substring);
if (output_source) {
Intl::AddElement(
isolate, result, index, field_type_string, substring,
isolate->factory()->source_string(),
Intl::SourceString(isolate,
tracker.GetSource(part.begin_pos, part.end_pos)));
} else {
Intl::AddElement(isolate, result, index, field_type_string, substring);
}
++index;
}
JSObject::ValidateElements(*result);
return Just(index);
}
bool IsPositiveInfinity(Isolate* isolate, Handle<Object> v) {
if (v->IsBigInt()) return false;
if (v->IsString()) {
return isolate->factory()->Infinity_string()->Equals(String::cast(*v));
}
CHECK(v->IsNumber());
double const value_number = v->Number();
return std::isinf(value_number) && (value_number > 0.0);
}
bool IsNegativeInfinity(Isolate* isolate, Handle<Object> v) {
if (v->IsBigInt()) return false;
if (v->IsString()) {
return isolate->factory()->minus_Infinity_string()->Equals(
String::cast(*v));
}
CHECK(v->IsNumber());
double const value_number = v->Number();
return std::isinf(value_number) && (value_number < 0.0);
}
bool IsNegativeZero(Isolate* isolate, Handle<Object> v) {
if (v->IsBigInt()) return false;
if (v->IsString()) {
return isolate->factory()->minus_0()->Equals(String::cast(*v));
}
CHECK(v->IsNumber());
return IsMinusZero(v->Number());
}
bool LessThan(Isolate* isolate, Handle<Object> a, Handle<Object> b) {
Maybe<ComparisonResult> comparison = Object::Compare(isolate, a, b);
return comparison.IsJust() &&
comparison.FromJust() == ComparisonResult::kLessThan;
}
bool IsFiniteNonMinusZeroNumberOrBigInt(Isolate* isolate, Handle<Object> v) {
return !(IsPositiveInfinity(isolate, v) || IsNegativeInfinity(isolate, v) ||
v->IsMinusZero());
}
// #sec-partitionnumberrangepattern
template <typename T, MaybeHandle<T> (*F)(
Isolate*, icu::FormattedValue*,
const icu::number::LocalizedNumberFormatter*, bool)>
MaybeHandle<T> PartitionNumberRangePattern(Isolate* isolate,
Handle<JSNumberFormat> number_format,
Handle<Object> x, Handle<Object> y,
const char* func_name) {
Factory* factory = isolate->factory();
// 1. If x is NaN or y is NaN, throw a RangeError exception.
if (x->IsNaN()) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kInvalid,
factory->NewStringFromStaticChars("start"), x),
MaybeHandle<T>());
}
if (y->IsNaN()) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kInvalid,
factory->NewStringFromStaticChars("end"), y),
MaybeHandle<T>());
}
// 2. If x is a mathematical value, then
if (IsFiniteNonMinusZeroNumberOrBigInt(isolate, x)) {
// a. If y is a mathematical value and y < x, throw a RangeError exception.
if (IsFiniteNonMinusZeroNumberOrBigInt(isolate, y) &&
LessThan(isolate, y, x)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// b. Else if y is -∞, throw a RangeError exception.
if (IsNegativeInfinity(isolate, y)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// c. Else if y is -0 and x ≥ 0, throw a RangeError exception.
if (y->IsMinusZero() &&
!LessThan(isolate, x, Handle<Object>(Smi::zero(), isolate))) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// 3. Else if x is +∞, then
} else if (IsPositiveInfinity(isolate, x)) {
// a. If y is a mathematical value, throw a RangeError exception.
if (IsFiniteNonMinusZeroNumberOrBigInt(isolate, y)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// b. Else if y is -∞, throw a RangeError exception.
if (IsNegativeInfinity(isolate, y)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// c. Else if y is -0, throw a RangeError exception.
if (IsNegativeZero(isolate, y)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// 4. Else if x is -0, then
} else if (IsNegativeZero(isolate, x)) {
// a. If y is a mathematical value and y < 0, throw a RangeError exception.
if (IsFiniteNonMinusZeroNumberOrBigInt(isolate, y) &&
LessThan(isolate, y, Handle<Object>(Smi::zero(), isolate))) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
// b. Else if y is -∞, throw a RangeError exception.
if (IsNegativeZero(isolate, y)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalid, x, y),
MaybeHandle<T>());
}
}
Maybe<icu::Formattable> maybe_x = ToFormattable(isolate, x, "start");
MAYBE_RETURN(maybe_x, MaybeHandle<T>());
Maybe<icu::Formattable> maybe_y = ToFormattable(isolate, y, "end");
MAYBE_RETURN(maybe_y, MaybeHandle<T>());
icu::number::LocalizedNumberRangeFormatter* nrfmt =
number_format->icu_number_range_formatter().raw();
CHECK_NOT_NULL(nrfmt);
UErrorCode status = U_ZERO_ERROR;
icu::number::FormattedNumberRange formatted = nrfmt->formatFormattableRange(
maybe_x.FromJust(), maybe_y.FromJust(), status);
if (U_FAILURE(status)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewTypeError(MessageTemplate::kIcuError), MaybeHandle<T>());
}
return F(isolate, &formatted, number_format->icu_number_formatter().raw(),
false /* is_nan */);
}
MaybeHandle<String> FormatToString(Isolate* isolate,
icu::FormattedValue* formatted,
const icu::number::LocalizedNumberFormatter*,
@ -1865,19 +2078,26 @@ MaybeHandle<String> FormatToString(Isolate* isolate,
MaybeHandle<JSArray> FormatToJSArray(
Isolate* isolate, icu::FormattedValue* formatted,
const icu::number::LocalizedNumberFormatter* nfmt, bool is_nan) {
const icu::number::LocalizedNumberFormatter* nfmt, bool is_nan,
bool output_source) {
UErrorCode status = U_ZERO_ERROR;
bool is_unit = Style::UNIT == StyleFromSkeleton(nfmt->toSkeleton(status));
CHECK(U_SUCCESS(status));
Factory* factory = isolate->factory();
Handle<JSArray> result = factory->NewJSArray(0);
Maybe<int> maybe_format_to_parts =
ConstructParts(isolate, formatted, result, 0, is_unit, is_nan);
Maybe<int> maybe_format_to_parts = ConstructParts(
isolate, formatted, result, 0, is_unit, is_nan, output_source);
MAYBE_RETURN(maybe_format_to_parts, Handle<JSArray>());
return result;
}
MaybeHandle<JSArray> FormatRangeToJSArray(
Isolate* isolate, icu::FormattedValue* formatted,
const icu::number::LocalizedNumberFormatter* nfmt, bool is_nan) {
return FormatToJSArray(isolate, formatted, nfmt, is_nan, true);
}
} // namespace
MaybeHandle<String> JSNumberFormat::FormatNumeric(
@ -1908,7 +2128,23 @@ MaybeHandle<JSArray> JSNumberFormat::FormatToParts(
IcuFormatNumber(isolate, *fmt, numeric_obj, &formatted);
MAYBE_RETURN(maybe_format, Handle<JSArray>());
return FormatToJSArray(isolate, &formatted, fmt, numeric_obj->IsNaN());
return FormatToJSArray(isolate, &formatted, fmt, numeric_obj->IsNaN(), false);
}
MaybeHandle<String> JSNumberFormat::FormatNumericRange(
Isolate* isolate, Handle<JSNumberFormat> number_format,
Handle<Object> x_obj, Handle<Object> y_obj) {
return PartitionNumberRangePattern<String, FormatToString>(
isolate, number_format, x_obj, y_obj,
"Intl.NumberFormat.prototype.formatRange");
}
MaybeHandle<JSArray> JSNumberFormat::FormatNumericRangeToParts(
Isolate* isolate, Handle<JSNumberFormat> number_format,
Handle<Object> x_obj, Handle<Object> y_obj) {
return PartitionNumberRangePattern<JSArray, FormatRangeToJSArray>(
isolate, number_format, x_obj, y_obj,
"Intl.NumberFormat.prototype.formatRangeToParts");
}
namespace {

View File

@ -27,6 +27,7 @@ class UnicodeString;
namespace number {
class LocalizedNumberFormatter;
class UnlocalizedNumberFormatter;
class LocalizedNumberRangeFormatter;
} // namespace number
} // namespace U_ICU_NAMESPACE
@ -55,6 +56,16 @@ class JSNumberFormat
Isolate* isolate, Handle<JSNumberFormat> number_format,
Handle<Object> numeric_obj);
// ecma402/#sec-formatnumericrange
V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatNumericRange(
Isolate* isolate, Handle<JSNumberFormat> number_format, Handle<Object> x,
Handle<Object> y);
// ecma402/#sec-formatnumericrangetoparts
V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> FormatNumericRangeToParts(
Isolate* isolate, Handle<JSNumberFormat> number_format, Handle<Object> x,
Handle<Object> y);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatNumeric(
Isolate* isolate,
const icu::number::LocalizedNumberFormatter& number_format,
@ -81,6 +92,8 @@ class JSNumberFormat
DECL_ACCESSORS(icu_number_formatter,
Managed<icu::number::LocalizedNumberFormatter>)
DECL_ACCESSORS(icu_number_range_formatter,
Managed<icu::number::LocalizedNumberRangeFormatter>)
TQ_OBJECT_CONSTRUCTORS(JSNumberFormat)
};

View File

@ -8,5 +8,7 @@ extern class JSNumberFormat extends JSObject {
locale: String;
icu_number_formatter:
Foreign; // Managed<icu::number::LocalizedNumberFormatter>
icu_number_range_formatter:
Foreign; // Managed<icu::number::LocalizedNumberRangeFormatter>
bound_format: JSFunction|Undefined;
}

View File

@ -0,0 +1,158 @@
// 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.
// Flags: --harmony-intl-number-format-v3
const validRanges = [[-12345, -5678], [-12345, 56789], [12345, 56789]];
const nf = new Intl.NumberFormat("en", {signDisplay: "exceptZero"});
['formatRange', 'formatRangeToParts'].forEach(function(method) {
assertEquals("function", typeof nf[method]);
// 2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
// Assert if called without nf
let f = nf[method];
assertThrows(() => { f(1, 23) }, TypeError);
// Assert normal call success
assertDoesNotThrow(() => nf[method](1, 23));
// 3. If start is undefined ..., throw a TypeError exception.
assertThrows(() => { nf[method](undefined, 23) }, TypeError);
// 3. If ... end is undefined, throw a TypeError exception.
assertThrows(() => { nf[method](1, undefined) }, TypeError);
// 4. Let x be ? ToNumeric(start).
// Verify it won't throw error
assertDoesNotThrow(() => nf[method](null, 23));
assertDoesNotThrow(() => nf[method](false, 23));
assertDoesNotThrow(() => nf[method](true, 23));
assertDoesNotThrow(() => nf[method](12, 23));
assertDoesNotThrow(() => nf[method](12n, 23));
// Verify it will throw error
assertThrows(() => { nf[method](Symbol(12), 23) }, TypeError);
// 5. Let y be ? ToNumeric(end).
// Verify it won't throw error
assertDoesNotThrow(() => nf[method](-12, null));
assertDoesNotThrow(() => nf[method](-12, false));
assertDoesNotThrow(() => nf[method](-12, true));
assertDoesNotThrow(() => nf[method](12, 23));
assertDoesNotThrow(() => nf[method](12, 23n));
// Verify it will throw error
assertThrows(() => { nf[method](12, Symbol(23)) }, TypeError);
// 6. If x is NaN ..., throw a RangeError exception.
assertThrows(() => { nf[method](NaN, 23) }, RangeError);
// 6. If ... y is NaN, throw a RangeError exception.
assertThrows(() => { nf[method](12, NaN) }, RangeError);
// 8. If x is greater than y, throw a RangeError exception.
// neither x nor y are bigint.
assertThrows(() => { nf[method](23, 12) }, RangeError);
assertDoesNotThrow(() => nf[method](12, 23));
// x is not bigint but y is.
assertThrows(() => { nf[method](23, 12n) }, RangeError);
assertDoesNotThrow(() => nf[method](12, 23n));
// x is bigint but y is not.
assertThrows(() => { nf[method](23n, 12) }, RangeError);
assertDoesNotThrow(() => nf[method](12n, 23));
// both x and y are bigint.
assertThrows(() => { nf[method](23n, 12n) }, RangeError);
assertDoesNotThrow(() => nf[method](12n, 23n));
validRanges.forEach(
function([x, y]) {
const X = BigInt(x);
const Y = BigInt(y);
const formatted_x_y = nf[method](x, y);
const formatted_X_y = nf[method](X, y);
const formatted_x_Y = nf[method](x, Y);
const formatted_X_Y = nf[method](X, Y);
assertEquals(formatted_x_y, formatted_X_y);
assertEquals(formatted_x_y, formatted_x_Y);
assertEquals(formatted_x_y, formatted_X_Y);
});
});
// Check the number of part with type: "plusSign" and "minusSign" are corre
validRanges.forEach(
function([x, y]) {
const expectedPlus = (x > 0) ? ((y > 0) ? 2 : 1) : ((y > 0) ? 1 : 0);
const expectedMinus = (x < 0) ? ((y < 0) ? 2 : 1) : ((y < 0) ? 1 : 0);
let actualPlus = 0;
let actualMinus = 0;
const parts = nf.formatRangeToParts(x, y);
parts.forEach(function(part) {
if (part.type == "plusSign") actualPlus++;
if (part.type == "minusSign") actualMinus++;
});
const method = "formatRangeToParts(" + x + ", " + y + "): ";
assertEquals(expectedPlus, actualPlus,
method + "Number of type: 'plusSign' in parts is incorrect");
assertEquals(expectedMinus, actualMinus,
method + "Number of type: 'minusSign' in parts is incorrect");
});
// From https://github.com/tc39/proposal-intl-numberformat-v3#formatrange-ecma-402-393
const nf2 = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
maximumFractionDigits: 0,
});
// README.md said it expect "€35"
assertEquals("€3 €5", nf2.formatRange(3, 5));
const nf3 = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
maximumFractionDigits: 0,
});
const actual3 = nf3.formatRangeToParts(3, 5);
/*
[
{type: "currency", value: "€", source: "startRange"}
{type: "integer", value: "3", source: "startRange"}
{type: "literal", value: "", source: "shared"}
{type: "integer", value: "5", source: "endRange"}
]
*/
assertEquals(5, actual3.length);
assertEquals("currency", actual3[0].type);
assertEquals("€", actual3[0].value);
assertEquals("startRange", actual3[0].source);
assertEquals("integer", actual3[1].type);
assertEquals("3", actual3[1].value);
assertEquals("startRange", actual3[1].source);
assertEquals("literal", actual3[2].type);
assertEquals(" ", actual3[2].value);
assertEquals("shared", actual3[2].source);
assertEquals("currency", actual3[3].type);
assertEquals("€", actual3[3].value);
assertEquals("endRange", actual3[3].source);
assertEquals("integer", actual3[4].type);
assertEquals("5", actual3[4].value);
assertEquals("endRange", actual3[4].source);
const nf4 = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
maximumFractionDigits: 0,
});
assertEquals("~€3", nf4.formatRange(2.9, 3.1));
const nf5 = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
signDisplay: "always",
});
assertEquals("~+€3.00", nf5.formatRange(2.999, 3.001));
const nf6 = new Intl.NumberFormat("en");
assertEquals("3∞", nf6.formatRange(3, 1/0));
assertThrows(() => { nf6.formatRange(3, 0/0); }, RangeError);

View File

@ -2451,23 +2451,10 @@
'intl402/NumberFormat/constructor-roundingIncrement': [FAIL],
'intl402/NumberFormat/test-option-roundingPriority': [FAIL],
# NumberFormat.prototype.formatRange
'intl402/NumberFormat/prototype/formatRange/builtin': [FAIL],
'intl402/NumberFormat/prototype/formatRange/en-US': [FAIL],
'intl402/NumberFormat/prototype/formatRange/invoked-as-func': [FAIL],
'intl402/NumberFormat/prototype/formatRange/length': [FAIL],
'intl402/NumberFormat/prototype/formatRange/name': [FAIL],
'intl402/NumberFormat/prototype/formatRange/nan-arguments-throws': [FAIL],
'intl402/NumberFormat/prototype/formatRange/prop-desc': [FAIL],
'intl402/NumberFormat/prototype/formatRange/pt-PT': [FAIL],
'intl402/NumberFormat/prototype/formatRange/x-greater-than-y-throws': [FAIL],
# NumberFormat.prototype.formatRangeToParts
'intl402/NumberFormat/prototype/formatRangeToParts/builtin': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/en-US': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/invoked-as-func': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/length': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/name': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/nan-arguments-throws': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/prop-desc': [FAIL],
'intl402/NumberFormat/prototype/formatRangeToParts/x-greater-than-y-throws': [FAIL],
# PluralRules.prototype.selectRange

View File

@ -377,76 +377,76 @@ KNOWN_MAPS = {
("read_only_space", 0x03401): (131, "BasicBlockCountersMarkerMap"),
("read_only_space", 0x03445): (147, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x03545): (161, "InterceptorInfoMap"),
("read_only_space", 0x06005): (132, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x0602d): (133, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x06055): (134, "CallableTaskMap"),
("read_only_space", 0x0607d): (135, "CallbackTaskMap"),
("read_only_space", 0x060a5): (136, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x060cd): (139, "FunctionTemplateInfoMap"),
("read_only_space", 0x060f5): (140, "ObjectTemplateInfoMap"),
("read_only_space", 0x0611d): (141, "AccessCheckInfoMap"),
("read_only_space", 0x06145): (142, "AccessorInfoMap"),
("read_only_space", 0x0616d): (143, "AccessorPairMap"),
("read_only_space", 0x06195): (144, "AliasedArgumentsEntryMap"),
("read_only_space", 0x061bd): (145, "AllocationMementoMap"),
("read_only_space", 0x061e5): (148, "AsmWasmDataMap"),
("read_only_space", 0x0620d): (149, "AsyncGeneratorRequestMap"),
("read_only_space", 0x06235): (150, "BreakPointMap"),
("read_only_space", 0x0625d): (151, "BreakPointInfoMap"),
("read_only_space", 0x06285): (152, "CachedTemplateObjectMap"),
("read_only_space", 0x062ad): (154, "CallSiteInfoMap"),
("read_only_space", 0x062d5): (155, "ClassPositionsMap"),
("read_only_space", 0x062fd): (156, "DebugInfoMap"),
("read_only_space", 0x06325): (158, "ErrorStackDataMap"),
("read_only_space", 0x0634d): (160, "FunctionTemplateRareDataMap"),
("read_only_space", 0x06375): (162, "InterpreterDataMap"),
("read_only_space", 0x0639d): (163, "ModuleRequestMap"),
("read_only_space", 0x063c5): (164, "PromiseCapabilityMap"),
("read_only_space", 0x063ed): (165, "PromiseReactionMap"),
("read_only_space", 0x06415): (166, "PropertyDescriptorObjectMap"),
("read_only_space", 0x0643d): (167, "PrototypeInfoMap"),
("read_only_space", 0x06465): (168, "RegExpBoilerplateDescriptionMap"),
("read_only_space", 0x0648d): (169, "ScriptMap"),
("read_only_space", 0x064b5): (170, "ScriptOrModuleMap"),
("read_only_space", 0x064dd): (171, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x06505): (172, "StackFrameInfoMap"),
("read_only_space", 0x0652d): (173, "TemplateObjectDescriptionMap"),
("read_only_space", 0x06555): (174, "Tuple2Map"),
("read_only_space", 0x0657d): (175, "WasmContinuationObjectMap"),
("read_only_space", 0x065a5): (176, "WasmExceptionTagMap"),
("read_only_space", 0x065cd): (177, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x065f5): (197, "SloppyArgumentsElementsMap"),
("read_only_space", 0x0661d): (233, "DescriptorArrayMap"),
("read_only_space", 0x06645): (219, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x0666d): (217, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x06695): (220, "UncompiledDataWithoutPreparseDataWithJobMap"),
("read_only_space", 0x066bd): (218, "UncompiledDataWithPreparseDataAndJobMap"),
("read_only_space", 0x066e5): (251, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x0670d): (198, "TurbofanBitsetTypeMap"),
("read_only_space", 0x06735): (202, "TurbofanUnionTypeMap"),
("read_only_space", 0x0675d): (201, "TurbofanRangeTypeMap"),
("read_only_space", 0x06785): (199, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x067ad): (200, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x067d5): (247, "InternalClassMap"),
("read_only_space", 0x067fd): (258, "SmiPairMap"),
("read_only_space", 0x06825): (257, "SmiBoxMap"),
("read_only_space", 0x0684d): (225, "ExportedSubClassBaseMap"),
("read_only_space", 0x06875): (226, "ExportedSubClassMap"),
("read_only_space", 0x0689d): (231, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x068c5): (232, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x068ed): (196, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x06915): (248, "InternalClassWithStructElementsMap"),
("read_only_space", 0x0693d): (227, "ExportedSubClass2Map"),
("read_only_space", 0x06965): (259, "SortStateMap"),
("read_only_space", 0x0698d): (146, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x069b5): (146, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x069dd): (137, "LoadHandler1Map"),
("read_only_space", 0x06a05): (137, "LoadHandler2Map"),
("read_only_space", 0x06a2d): (137, "LoadHandler3Map"),
("read_only_space", 0x06a55): (138, "StoreHandler0Map"),
("read_only_space", 0x06a7d): (138, "StoreHandler1Map"),
("read_only_space", 0x06aa5): (138, "StoreHandler2Map"),
("read_only_space", 0x06acd): (138, "StoreHandler3Map"),
("read_only_space", 0x06015): (132, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x0603d): (133, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x06065): (134, "CallableTaskMap"),
("read_only_space", 0x0608d): (135, "CallbackTaskMap"),
("read_only_space", 0x060b5): (136, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x060dd): (139, "FunctionTemplateInfoMap"),
("read_only_space", 0x06105): (140, "ObjectTemplateInfoMap"),
("read_only_space", 0x0612d): (141, "AccessCheckInfoMap"),
("read_only_space", 0x06155): (142, "AccessorInfoMap"),
("read_only_space", 0x0617d): (143, "AccessorPairMap"),
("read_only_space", 0x061a5): (144, "AliasedArgumentsEntryMap"),
("read_only_space", 0x061cd): (145, "AllocationMementoMap"),
("read_only_space", 0x061f5): (148, "AsmWasmDataMap"),
("read_only_space", 0x0621d): (149, "AsyncGeneratorRequestMap"),
("read_only_space", 0x06245): (150, "BreakPointMap"),
("read_only_space", 0x0626d): (151, "BreakPointInfoMap"),
("read_only_space", 0x06295): (152, "CachedTemplateObjectMap"),
("read_only_space", 0x062bd): (154, "CallSiteInfoMap"),
("read_only_space", 0x062e5): (155, "ClassPositionsMap"),
("read_only_space", 0x0630d): (156, "DebugInfoMap"),
("read_only_space", 0x06335): (158, "ErrorStackDataMap"),
("read_only_space", 0x0635d): (160, "FunctionTemplateRareDataMap"),
("read_only_space", 0x06385): (162, "InterpreterDataMap"),
("read_only_space", 0x063ad): (163, "ModuleRequestMap"),
("read_only_space", 0x063d5): (164, "PromiseCapabilityMap"),
("read_only_space", 0x063fd): (165, "PromiseReactionMap"),
("read_only_space", 0x06425): (166, "PropertyDescriptorObjectMap"),
("read_only_space", 0x0644d): (167, "PrototypeInfoMap"),
("read_only_space", 0x06475): (168, "RegExpBoilerplateDescriptionMap"),
("read_only_space", 0x0649d): (169, "ScriptMap"),
("read_only_space", 0x064c5): (170, "ScriptOrModuleMap"),
("read_only_space", 0x064ed): (171, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x06515): (172, "StackFrameInfoMap"),
("read_only_space", 0x0653d): (173, "TemplateObjectDescriptionMap"),
("read_only_space", 0x06565): (174, "Tuple2Map"),
("read_only_space", 0x0658d): (175, "WasmContinuationObjectMap"),
("read_only_space", 0x065b5): (176, "WasmExceptionTagMap"),
("read_only_space", 0x065dd): (177, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x06605): (197, "SloppyArgumentsElementsMap"),
("read_only_space", 0x0662d): (233, "DescriptorArrayMap"),
("read_only_space", 0x06655): (219, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x0667d): (217, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x066a5): (220, "UncompiledDataWithoutPreparseDataWithJobMap"),
("read_only_space", 0x066cd): (218, "UncompiledDataWithPreparseDataAndJobMap"),
("read_only_space", 0x066f5): (251, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x0671d): (198, "TurbofanBitsetTypeMap"),
("read_only_space", 0x06745): (202, "TurbofanUnionTypeMap"),
("read_only_space", 0x0676d): (201, "TurbofanRangeTypeMap"),
("read_only_space", 0x06795): (199, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x067bd): (200, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x067e5): (247, "InternalClassMap"),
("read_only_space", 0x0680d): (258, "SmiPairMap"),
("read_only_space", 0x06835): (257, "SmiBoxMap"),
("read_only_space", 0x0685d): (225, "ExportedSubClassBaseMap"),
("read_only_space", 0x06885): (226, "ExportedSubClassMap"),
("read_only_space", 0x068ad): (231, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x068d5): (232, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x068fd): (196, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x06925): (248, "InternalClassWithStructElementsMap"),
("read_only_space", 0x0694d): (227, "ExportedSubClass2Map"),
("read_only_space", 0x06975): (259, "SortStateMap"),
("read_only_space", 0x0699d): (146, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x069c5): (146, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x069ed): (137, "LoadHandler1Map"),
("read_only_space", 0x06a15): (137, "LoadHandler2Map"),
("read_only_space", 0x06a3d): (137, "LoadHandler3Map"),
("read_only_space", 0x06a65): (138, "StoreHandler0Map"),
("read_only_space", 0x06a8d): (138, "StoreHandler1Map"),
("read_only_space", 0x06ab5): (138, "StoreHandler2Map"),
("read_only_space", 0x06add): (138, "StoreHandler3Map"),
("map_space", 0x02149): (1057, "ExternalMap"),
("map_space", 0x02171): (2115, "JSMessageObjectMap"),
}