[Intl] Implement Intl.DateTimeFormat.prototype.formatRangeToParts

Design Doc: https://goo.gl/PGUQ1d

Use template to share code between formatRange and formatRangeToParts
Lazy crate DateIntervalFormat inside formatRange/formatRangeToParts to
reduce performance impact.

Bug: v8:7729
Change-Id: I130748a5ff7ca11235e6608195d365e58d440580
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1556573
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60930}
This commit is contained in:
Frank Tang 2019-04-18 12:50:18 -07:00 committed by Commit Bot
parent a8c73a4865
commit 8034b0568b
8 changed files with 363 additions and 140 deletions

View File

@ -19,6 +19,7 @@
V(_, day_string, "day") \
V(_, dayPeriod_string, "dayPeriod") \
V(_, decimal_string, "decimal") \
V(_, endRange_string, "endRange") \
V(_, era_string, "era") \
V(_, first_string, "first") \
V(_, format_string, "format") \
@ -72,6 +73,8 @@
V(_, SegmentIterator_string, "Segment Iterator") \
V(_, sensitivity_string, "sensitivity") \
V(_, sep_string, "sep") \
V(_, shared_string, "shared") \
V(_, startRange_string, "startRange") \
V(_, strict_string, "strict") \
V(_, style_string, "style") \
V(_, term_string, "term") \

View File

@ -31,6 +31,7 @@
#include "unicode/coll.h"
#include "unicode/datefmt.h"
#include "unicode/decimfmt.h"
#include "unicode/formattedvalue.h"
#include "unicode/locid.h"
#include "unicode/normalizer2.h"
#include "unicode/numfmt.h"
@ -1934,5 +1935,16 @@ Handle<String> Intl::NumberFieldToType(Isolate* isolate,
}
}
// A helper function to convert the FormattedValue for several Intl objects.
MaybeHandle<String> Intl::FormattedToString(
Isolate* isolate, const icu::FormattedValue& formatted) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString result = formatted.toString(status);
if (U_FAILURE(status)) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), String);
}
return Intl::ToString(isolate, result);
}
} // namespace internal
} // namespace v8

View File

@ -26,6 +26,7 @@ namespace U_ICU_NAMESPACE {
class BreakIterator;
class Collator;
class DecimalFormat;
class FormattedValue;
class SimpleDateFormat;
class UnicodeString;
}
@ -186,6 +187,10 @@ class Intl {
Isolate* isolate, const icu::UnicodeString& string, int32_t begin,
int32_t end);
// Helper function to convert a FormattedValue to String
V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormattedToString(
Isolate* isolate, const icu::FormattedValue& formatted);
// Helper function to convert number field id to type string.
static Handle<String> NumberFieldToType(Isolate* isolate,
Handle<Object> numeric_obj,

View File

@ -959,14 +959,41 @@ std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormatFromCache(
cache.Pointer()->Create(icu_locale, skeleton, generator));
}
std::unique_ptr<icu::DateIntervalFormat> CreateICUDateIntervalFormat(
const icu::Locale& icu_locale, const icu::UnicodeString& skeleton) {
icu::UnicodeString SkeletonFromDateFormat(
const icu::SimpleDateFormat& icu_date_format) {
icu::UnicodeString pattern;
pattern = icu_date_format.toPattern(pattern);
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString skeleton =
icu::DateTimePatternGenerator::staticGetSkeleton(pattern, status);
CHECK(U_SUCCESS(status));
return skeleton;
}
icu::DateIntervalFormat* LazyCreateDateIntervalFormat(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format) {
Managed<icu::DateIntervalFormat> managed_format =
date_time_format->icu_date_interval_format();
if (managed_format->get()) {
return managed_format->raw();
}
icu::SimpleDateFormat* icu_simple_date_format =
date_time_format->icu_simple_date_format()->raw();
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<icu::DateIntervalFormat> date_interval_format(
icu::DateIntervalFormat::createInstance(skeleton, icu_locale, status));
if (U_FAILURE(status)) return std::unique_ptr<icu::DateIntervalFormat>();
CHECK_NOT_NULL(date_interval_format.get());
return date_interval_format;
icu::DateIntervalFormat::createInstance(
SkeletonFromDateFormat(*icu_simple_date_format),
*(date_time_format->icu_locale()->raw()), status));
if (U_FAILURE(status)) {
return nullptr;
}
date_interval_format->setTimeZone(icu_simple_date_format->getTimeZone());
Handle<Managed<icu::DateIntervalFormat>> managed_interval_format =
Managed<icu::DateIntervalFormat>::FromUniquePtr(
isolate, 0, std::move(date_interval_format));
date_time_format->set_icu_date_interval_format(*managed_interval_format);
return (*managed_interval_format)->raw();
}
Intl::HourCycle HourCycleFromPattern(const icu::UnicodeString pattern) {
@ -1103,18 +1130,6 @@ std::unique_ptr<icu::SimpleDateFormat> DateTimeStylePattern(
generator);
}
icu::UnicodeString SkeletonFromDateFormat(
const icu::SimpleDateFormat& icu_date_format) {
icu::UnicodeString pattern;
pattern = icu_date_format.toPattern(pattern);
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString skeleton =
icu::DateTimePatternGenerator::staticGetSkeleton(pattern, status);
CHECK(U_SUCCESS(status));
return skeleton;
}
class DateTimePatternGeneratorCache {
public:
// Return a clone copy that the caller have to free.
@ -1297,7 +1312,6 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
DateTimeStyle date_style = DateTimeStyle::kUndefined;
DateTimeStyle time_style = DateTimeStyle::kUndefined;
std::unique_ptr<icu::SimpleDateFormat> icu_date_format;
std::unique_ptr<icu::DateIntervalFormat> icu_date_interval_format;
if (FLAG_harmony_intl_datetime_style) {
// 28. Let dateStyle be ? GetOption(options, "dateStyle", "string", «
@ -1340,10 +1354,6 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
time_style != DateTimeStyle::kUndefined) {
icu_date_format = DateTimeStylePattern(date_style, time_style, icu_locale,
hc, *generator);
if (FLAG_harmony_intl_date_format_range) {
icu_date_interval_format = CreateICUDateIntervalFormat(
icu_locale, SkeletonFromDateFormat(*icu_date_format));
}
}
}
// 33. Else,
@ -1397,10 +1407,6 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
FATAL("Failed to create ICU date format, are ICU data files missing?");
}
}
if (FLAG_harmony_intl_date_format_range) {
icu_date_interval_format =
CreateICUDateIntervalFormat(icu_locale, skeleton_ustr);
}
// g. If dateTimeFormat.[[Hour]] is not undefined, then
if (!has_hour_option) {
@ -1449,12 +1455,10 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
Managed<icu::SimpleDateFormat>::FromUniquePtr(isolate, 0,
std::move(icu_date_format));
date_time_format->set_icu_simple_date_format(*managed_format);
if (FLAG_harmony_intl_date_format_range) {
Handle<Managed<icu::DateIntervalFormat>> managed_interval_format =
Managed<icu::DateIntervalFormat>::FromUniquePtr(
isolate, 0, std::move(icu_date_interval_format));
date_time_format->set_icu_date_interval_format(*managed_interval_format);
}
Handle<Managed<icu::DateIntervalFormat>> managed_interval_format =
Managed<icu::DateIntervalFormat>::FromRawPtr(isolate, 0, nullptr);
date_time_format->set_icu_date_interval_format(*managed_interval_format);
return date_time_format;
}
@ -1591,75 +1595,176 @@ Handle<String> JSDateTimeFormat::HourCycleAsString() const {
}
}
MaybeHandle<String> JSDateTimeFormat::FormatRange(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, double x,
double y) {
// TODO(ftang): Merge the following with FormatRangeToParts after
// the landing of ICU64 to make it cleaner.
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) {
CHECK_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 {
CHECK_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) {
Handle<String> substring;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, substring,
Intl::ToString(isolate, string, start, end),
Nothing<bool>());
Intl::AddElement(isolate, array, index,
IcuDateFieldIdToDateType(field, isolate), substring,
isolate->factory()->source_string(),
SourceString(isolate, tracker.GetSource(start, end)));
return Just(true);
}
// A helper function to convert the FormattedDateInterval to a
// MaybeHandle<JSArray> for the implementation of formatRangeToParts.
MaybeHandle<JSArray> FormattedDateIntervalToJSArray(
Isolate* isolate, const icu::FormattedValue& formatted) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString result = formatted.toString(status);
Factory* factory = isolate->factory();
Handle<JSArray> array = factory->NewJSArray(0);
icu::ConstrainedFieldPosition cfpos;
int index = 0;
int32_t previous_end_pos = 0;
SourceTracker tracker;
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_DATE_INTERVAL_SPAN) {
CHECK_LE(field, 2);
tracker.Add(field, start, limit);
} else {
CHECK(category == UFIELD_CATEGORY_DATE);
if (start > previous_end_pos) {
// Add "literal" from the previous end position to the start if
// necessary.
Maybe<bool> maybe_added =
AddPartForFormatRange(isolate, array, result, index, -1,
previous_end_pos, start, tracker);
MAYBE_RETURN(maybe_added, Handle<JSArray>());
previous_end_pos = start;
index++;
}
Maybe<bool> maybe_added = AddPartForFormatRange(
isolate, array, result, index, field, start, limit, tracker);
MAYBE_RETURN(maybe_added, Handle<JSArray>());
previous_end_pos = limit;
++index;
}
}
int32_t end = result.length();
// Add "literal" in the end if necessary.
if (end > previous_end_pos) {
Maybe<bool> maybe_added = AddPartForFormatRange(
isolate, array, result, index, -1, previous_end_pos, end, tracker);
MAYBE_RETURN(maybe_added, Handle<JSArray>());
}
if (U_FAILURE(status)) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), JSArray);
}
JSObject::ValidateElements(*array);
return array;
}
// The shared code between formatRange and formatRangeToParts
template <typename T>
MaybeHandle<T> FormatRangeCommon(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, double x,
double y,
MaybeHandle<T> (*formatToResult)(Isolate*, const icu::FormattedValue&)) {
// #sec-partitiondatetimerangepattern
// 1. Let x be TimeClip(x).
x = DateCache::TimeClip(x);
// 2. If x is NaN, throw a RangeError exception.
if (std::isnan(x)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
String);
T);
}
// 3. Let y be TimeClip(y).
y = DateCache::TimeClip(y);
// 4. If y is NaN, throw a RangeError exception.
if (std::isnan(y)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
String);
T);
}
icu::DateIntervalFormat* date_interval_format =
date_time_format->icu_date_interval_format()->raw();
CHECK_NOT_NULL(date_interval_format);
icu::DateInterval interval(x, y);
icu::UnicodeString result;
icu::FieldPosition fpos;
UErrorCode status = U_ZERO_ERROR;
date_interval_format->format(&interval, result, fpos, status);
CHECK(U_SUCCESS(status));
icu::DateIntervalFormat* format =
LazyCreateDateIntervalFormat(isolate, date_time_format);
if (format == nullptr) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), T);
}
return Intl::ToString(isolate, result);
UErrorCode status = U_ZERO_ERROR;
icu::FormattedDateInterval formatted =
format->formatToValue(interval, status);
if (U_FAILURE(status)) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), T);
}
return formatToResult(isolate, formatted);
}
} // namespace
MaybeHandle<String> JSDateTimeFormat::FormatRange(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, double x,
double y) {
return FormatRangeCommon<String>(isolate, date_time_format, x, y,
Intl::FormattedToString);
}
MaybeHandle<JSArray> JSDateTimeFormat::FormatRangeToParts(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, double x,
double y) {
// TODO(ftang): Merge the following with FormatRangeToParts after
// the landing of ICU64 to make it cleaner.
// #sec-partitiondatetimerangepattern
// 1. Let x be TimeClip(x).
x = DateCache::TimeClip(x);
// 2. If x is NaN, throw a RangeError exception.
if (std::isnan(x)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
JSArray);
}
// 3. Let y be TimeClip(y).
y = DateCache::TimeClip(y);
// 4. If y is NaN, throw a RangeError exception.
if (std::isnan(y)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
JSArray);
}
icu::DateIntervalFormat* date_interval_format =
date_time_format->icu_date_interval_format()->raw();
CHECK_NOT_NULL(date_interval_format);
Factory* factory = isolate->factory();
Handle<JSArray> result = factory->NewJSArray(0);
// TODO(ftang) To be implemented after ICU64 landed that support
// DateIntervalFormat::formatToValue() and FormattedDateInterval.
JSObject::ValidateElements(*result);
return result;
return FormatRangeCommon<JSArray>(isolate, date_time_format, x, y,
FormattedDateIntervalToJSArray);
}
} // namespace internal

View File

@ -296,7 +296,7 @@ Maybe<std::vector<icu::UnicodeString>> ToUnicodeStringArray(
template <typename T>
MaybeHandle<T> FormatListCommon(
Isolate* isolate, Handle<JSListFormat> format, Handle<JSArray> list,
MaybeHandle<T> (*formatToResult)(Isolate*, const icu::FormattedList&)) {
MaybeHandle<T> (*formatToResult)(Isolate*, const icu::FormattedValue&)) {
DCHECK(!list->IsUndefined());
// ecma402 #sec-createpartsfromlist
// 2. If list contains any element value such that Type(value) is not String,
@ -318,18 +318,6 @@ MaybeHandle<T> FormatListCommon(
return formatToResult(isolate, formatted);
}
// A helper function to convert the FormattedList to a
// MaybeHandle<String> for the implementation of format.
MaybeHandle<String> FormattedToString(Isolate* isolate,
const icu::FormattedList& formatted) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString result = formatted.toString(status);
if (U_FAILURE(status)) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), String);
}
return Intl::ToString(isolate, result);
}
Handle<String> IcuFieldIdToType(Isolate* isolate, int32_t field_id) {
switch (field_id) {
case ULISTFMT_LITERAL_FIELD:
@ -345,8 +333,8 @@ Handle<String> IcuFieldIdToType(Isolate* isolate, int32_t field_id) {
// A helper function to convert the FormattedList to a
// MaybeHandle<JSArray> for the implementation of formatToParts.
MaybeHandle<JSArray> FormattedToJSArray(Isolate* isolate,
const icu::FormattedList& formatted) {
MaybeHandle<JSArray> FormattedListToJSArray(
Isolate* isolate, const icu::FormattedValue& formatted) {
Handle<JSArray> array = isolate->factory()->NewJSArray(0);
icu::ConstrainedFieldPosition cfpos;
cfpos.constrainCategory(UFIELD_CATEGORY_LIST);
@ -375,13 +363,15 @@ MaybeHandle<JSArray> FormattedToJSArray(Isolate* isolate,
MaybeHandle<String> JSListFormat::FormatList(Isolate* isolate,
Handle<JSListFormat> format,
Handle<JSArray> list) {
return FormatListCommon<String>(isolate, format, list, FormattedToString);
return FormatListCommon<String>(isolate, format, list,
Intl::FormattedToString);
}
// ecma42 #sec-formatlisttoparts
MaybeHandle<JSArray> JSListFormat::FormatListToParts(
Isolate* isolate, Handle<JSListFormat> format, Handle<JSArray> list) {
return FormatListCommon<JSArray>(isolate, format, list, FormattedToJSArray);
return FormatListCommon<JSArray>(isolate, format, list,
FormattedListToJSArray);
}
const std::set<std::string>& JSListFormat::GetAvailableLocales() {

View File

@ -0,0 +1,49 @@
// Copyright 2019 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-date-format-range
const date1 = new Date("2019-01-03T03:20");
const date2 = new Date("2019-01-05T19:33");
const date3 = new Date("2019-01-05T22:57");
// value: "Jan 3 5, 2019"
// source: hhhhShhhEhhhhhh
// type: mmmldllldllyyyy
// h: Shared, S: startRange, E: endRange
// m: month, l: literal, d: day, y: year
const expected1 = [
{type: "month", value: "Jan", source: "shared"},
{type: "literal", value: " ", source: "shared"},
{type: "day", value: "3", source: "startRange"},
{type: "literal", value: " ", source: "shared"},
{type: "day", value: "5", source: "endRange"},
{type: "literal", value: ", ", source: "shared"},
{type: "year", value: "2019", source: "shared"}
];
var dtf = new Intl.DateTimeFormat(["en"], {year: "numeric", month: "short", day: "numeric"});
const ret1 = dtf.formatRangeToParts(date1, date2);
assertEquals(expected1, ret1);
// value: "Jan 5, 7 10 PM"
// source: hhhhhhhShhhEEhhh
// type: mmmldlldlllhhlpp
// h: Shared, S: startRange, E: endRange
// m: month, l: literal, d: day, h: hour, p: dayPeriod
const expected2 = [
{type: "month", value: "Jan", source: "shared"},
{type: "literal", value: " ", source: "shared"},
{type: "day", value: "5", source: "shared"},
{type: "literal", value: ", ", source: "shared"},
{type: "hour", value: "7", source: "startRange"},
{type: "literal", value: " ", source: "shared"},
{type: "hour", value: "10", source: "endRange"},
{type: "literal", value: " ", source: "shared"},
{type: "dayPeriod", value: "PM", source: "shared"}
];
dtf = new Intl.DateTimeFormat(["en"], {month: "short", day: "numeric", hour: "numeric"});
const ret2 = dtf.formatRangeToParts(date2, date3);
assertEquals(expected2, ret2);

View File

@ -11,8 +11,10 @@ assertFalse(descriptor.enumerable);
assertTrue(descriptor.configurable);
const date1 = new Date("2019-1-3");
const date2 = new Date("2019-3-4");
const dtf = new Intl.DateTimeFormat();
const date2 = new Date("2019-1-5");
const date3 = new Date("2019-3-4");
const date4 = new Date("2020-3-4");
let dtf = new Intl.DateTimeFormat();
assertThrows(() => dtf.formatRangeToParts(), RangeError);
assertThrows(() => dtf.formatRangeToParts(date1), RangeError);
assertThrows(() => dtf.formatRangeToParts(undefined, date2), RangeError);
@ -22,3 +24,60 @@ assertThrows(() => dtf.formatRangeToParts(date1, "2019-5-4"), RangeError);
assertThrows(() => dtf.formatRangeToParts(date2, date1), RangeError);
assertDoesNotThrow(() =>dtf.formatRangeToParts(date1, date2));
function partsToString(parts) {
return parts.map(x => x.value).join("");
}
const validSources = ["startRange", "endRange", "shared"];
const validTypes = ["literal", "year", "month", "day", "hour", "minute", "second",
"weekday", "dayPeriod", "timeZoneName", "era"];
function assertParts(parts) {
const str = partsToString(parts);
parts.forEach(function(part) {
// Check the range of part.source
assertTrue(validSources.includes(part.source),
"Invalid source '" + part.source + "' in '" + str + "' for '" + part.value + "'");
// Check the range of part.type
assertTrue(validTypes.includes(part.type),
"Invalid type '" + part.type + "' in '" + str + "' for '" + part.value + "'");
// Check the part.value is a string
assertEquals("string", typeof part.value, "Invalid value for '" + str + "'");
});
}
function verifyFormatRangeToParts(a, b, dtf) {
var parts = dtf.formatRangeToParts(a, b);
// Check each parts fulfill basic property of the parts.
assertParts(parts);
// ensure the 'value' in the parts is the same as the output of
// the formatRange.
assertEquals(dtf.formatRange(a, b), partsToString(parts));
}
verifyFormatRangeToParts(date1, date2, dtf);
verifyFormatRangeToParts(date1, date3, dtf);
verifyFormatRangeToParts(date1, date4, dtf);
verifyFormatRangeToParts(date2, date3, dtf);
verifyFormatRangeToParts(date2, date4, dtf);
verifyFormatRangeToParts(date3, date4, dtf);
dtf = new Intl.DateTimeFormat(["en"], {year: "numeric", month: "short", day: "numeric"});
verifyFormatRangeToParts(date1, date2, dtf);
verifyFormatRangeToParts(date1, date3, dtf);
verifyFormatRangeToParts(date1, date4, dtf);
verifyFormatRangeToParts(date2, date3, dtf);
verifyFormatRangeToParts(date2, date4, dtf);
verifyFormatRangeToParts(date3, date4, dtf);
// Test the sequence of ToNumber and TimeClip
var secondDateAccessed = false;
assertThrows(
() =>
dtf.formatRangeToParts(
new Date(864000000*10000000 + 1), // a date will cause TimeClip return NaN
{ get [Symbol.toPrimitive]() { secondDateAccessed = true; return {}} }),
TypeError);
assertTrue(secondDateAccessed);

View File

@ -304,47 +304,47 @@ KNOWN_MAPS = {
("read_only_space", 0x026e1): (98, "EnumCacheMap"),
("read_only_space", 0x02781): (114, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x02ad1): (101, "InterceptorInfoMap"),
("read_only_space", 0x050b9): (89, "AccessCheckInfoMap"),
("read_only_space", 0x05109): (90, "AccessorInfoMap"),
("read_only_space", 0x05159): (91, "AccessorPairMap"),
("read_only_space", 0x051a9): (92, "AliasedArgumentsEntryMap"),
("read_only_space", 0x051f9): (93, "AllocationMementoMap"),
("read_only_space", 0x05249): (94, "AsmWasmDataMap"),
("read_only_space", 0x05299): (95, "AsyncGeneratorRequestMap"),
("read_only_space", 0x052e9): (96, "ClassPositionsMap"),
("read_only_space", 0x05339): (97, "DebugInfoMap"),
("read_only_space", 0x05389): (99, "FunctionTemplateInfoMap"),
("read_only_space", 0x053d9): (100, "FunctionTemplateRareDataMap"),
("read_only_space", 0x05429): (102, "InterpreterDataMap"),
("read_only_space", 0x05479): (103, "ModuleInfoEntryMap"),
("read_only_space", 0x054c9): (104, "ModuleMap"),
("read_only_space", 0x05519): (105, "ObjectTemplateInfoMap"),
("read_only_space", 0x05569): (106, "PromiseCapabilityMap"),
("read_only_space", 0x055b9): (107, "PromiseReactionMap"),
("read_only_space", 0x05609): (108, "PrototypeInfoMap"),
("read_only_space", 0x05659): (109, "ScriptMap"),
("read_only_space", 0x056a9): (110, "StackFrameInfoMap"),
("read_only_space", 0x056f9): (111, "StackTraceFrameMap"),
("read_only_space", 0x05749): (112, "Tuple2Map"),
("read_only_space", 0x05799): (113, "Tuple3Map"),
("read_only_space", 0x057e9): (115, "WasmDebugInfoMap"),
("read_only_space", 0x05839): (116, "WasmExceptionTagMap"),
("read_only_space", 0x05889): (117, "WasmExportedFunctionDataMap"),
("read_only_space", 0x058d9): (118, "CallableTaskMap"),
("read_only_space", 0x05929): (119, "CallbackTaskMap"),
("read_only_space", 0x05979): (120, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x059c9): (121, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05a19): (122, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x05a69): (123, "FinalizationGroupCleanupJobTaskMap"),
("read_only_space", 0x05ab9): (124, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x05b09): (124, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05b59): (159, "LoadHandler1Map"),
("read_only_space", 0x05ba9): (159, "LoadHandler2Map"),
("read_only_space", 0x05bf9): (159, "LoadHandler3Map"),
("read_only_space", 0x05c49): (167, "StoreHandler0Map"),
("read_only_space", 0x05c99): (167, "StoreHandler1Map"),
("read_only_space", 0x05ce9): (167, "StoreHandler2Map"),
("read_only_space", 0x05d39): (167, "StoreHandler3Map"),
("read_only_space", 0x05109): (89, "AccessCheckInfoMap"),
("read_only_space", 0x05159): (90, "AccessorInfoMap"),
("read_only_space", 0x051a9): (91, "AccessorPairMap"),
("read_only_space", 0x051f9): (92, "AliasedArgumentsEntryMap"),
("read_only_space", 0x05249): (93, "AllocationMementoMap"),
("read_only_space", 0x05299): (94, "AsmWasmDataMap"),
("read_only_space", 0x052e9): (95, "AsyncGeneratorRequestMap"),
("read_only_space", 0x05339): (96, "ClassPositionsMap"),
("read_only_space", 0x05389): (97, "DebugInfoMap"),
("read_only_space", 0x053d9): (99, "FunctionTemplateInfoMap"),
("read_only_space", 0x05429): (100, "FunctionTemplateRareDataMap"),
("read_only_space", 0x05479): (102, "InterpreterDataMap"),
("read_only_space", 0x054c9): (103, "ModuleInfoEntryMap"),
("read_only_space", 0x05519): (104, "ModuleMap"),
("read_only_space", 0x05569): (105, "ObjectTemplateInfoMap"),
("read_only_space", 0x055b9): (106, "PromiseCapabilityMap"),
("read_only_space", 0x05609): (107, "PromiseReactionMap"),
("read_only_space", 0x05659): (108, "PrototypeInfoMap"),
("read_only_space", 0x056a9): (109, "ScriptMap"),
("read_only_space", 0x056f9): (110, "StackFrameInfoMap"),
("read_only_space", 0x05749): (111, "StackTraceFrameMap"),
("read_only_space", 0x05799): (112, "Tuple2Map"),
("read_only_space", 0x057e9): (113, "Tuple3Map"),
("read_only_space", 0x05839): (115, "WasmDebugInfoMap"),
("read_only_space", 0x05889): (116, "WasmExceptionTagMap"),
("read_only_space", 0x058d9): (117, "WasmExportedFunctionDataMap"),
("read_only_space", 0x05929): (118, "CallableTaskMap"),
("read_only_space", 0x05979): (119, "CallbackTaskMap"),
("read_only_space", 0x059c9): (120, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x05a19): (121, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05a69): (122, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x05ab9): (123, "FinalizationGroupCleanupJobTaskMap"),
("read_only_space", 0x05b09): (124, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x05b59): (124, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05ba9): (159, "LoadHandler1Map"),
("read_only_space", 0x05bf9): (159, "LoadHandler2Map"),
("read_only_space", 0x05c49): (159, "LoadHandler3Map"),
("read_only_space", 0x05c99): (167, "StoreHandler0Map"),
("read_only_space", 0x05ce9): (167, "StoreHandler1Map"),
("read_only_space", 0x05d39): (167, "StoreHandler2Map"),
("read_only_space", 0x05d89): (167, "StoreHandler3Map"),
("map_space", 0x00139): (1057, "ExternalMap"),
("map_space", 0x00189): (1073, "JSMessageObjectMap"),
}