Title: [260349] trunk
Revision
260349
Author
[email protected]
Date
2020-04-19 22:15:35 -0700 (Sun, 19 Apr 2020)

Log Message

[ECMA-402] Intl.RelativeTimeFormat missing in WebKit
https://bugs.webkit.org/show_bug.cgi?id=209770

Reviewed by Darin Adler.

JSTests:

* stress/intl-relativetimeformat.js: Added.

* test262/config.yaml:
Enable Intl.RelativeTimeFormat feature with flag.

* test262/expectations.yaml:
Mark known failures.
Test for locale validation is not specific to RelativeTimeFormat and should be investigated separately.
Tests for Polish appear to be wrong and should be corrected in test262.

Source/_javascript_Core:

This patch implements the recent ECMA-402 feature Intl.RelativeTimeFormat.

RelativeTimeFormat has format / formatToParts functions like NumberFormat / DateTimeFormat
and is used to turn a number and unit into a formatted relative time string, e.g.:

  new Intl.RelativeTimeFormat('en').format(10, 'day')
  > 'in 10 days'

  new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'day')
  > 'today'

Implementation of RelativeTimeFormat#formatToParts makes direct use of NumberFormat#formatToParts,
as the relative time string consists of at most one formatted number with optional literal text on either side.

This feature is runtime-guarded by the `useIntlRelativeTimeFormat` option.

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* _javascript_Core.xcodeproj/project.pbxproj:
* Sources.txt:
* runtime/CommonIdentifiers.h:
* runtime/IntlRelativeTimeFormat.cpp: Added.
* runtime/IntlRelativeTimeFormat.h: Added.
* runtime/IntlRelativeTimeFormatConstructor.cpp: Added.
* runtime/IntlRelativeTimeFormatConstructor.h: Added.
* runtime/IntlRelativeTimeFormatPrototype.cpp: Added.
* runtime/IntlRelativeTimeFormatPrototype.h: Added.
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::relativeTimeFormatStructure):
* runtime/OptionsList.h:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
Add feature and runtime option.

* runtime/IntlDateTimeFormat.cpp:
(JSC::IntlDateTimeFormat::formatToParts):
* runtime/IntlPluralRules.cpp:
(JSC::IntlPluralRules::initializePluralRules):
(JSC::IntlPluralRules::resolvedOptions):
Make "type" a property name.

* runtime/IntlNumberFormat.cpp:
(JSC::IntlNumberFormat::initializeNumberFormat):
(JSC::IntlNumberFormat::resolvedOptions):
(JSC::IntlNumberFormat::formatToPartsInternal):
(JSC::IntlNumberFormat::formatToParts):
* runtime/IntlNumberFormat.h:
Factor out formatToPartsInternal so that RelativeTimeFormat can use it with its own UNumberFormat.
(This logic is too complicated to duplicate; it's because ICU won't split, e.g., "10,000" into parts for us.)

* runtime/IntlObject.cpp:
(JSC::IntlObject::IntlObject):
(JSC::IntlObject::create):
(JSC::IntlObject::finishCreation):
(JSC::intlAvailableLocales):
(JSC::intlCollatorAvailableLocales):
(JSC::isUnicodeLocaleIdentifierType):
(JSC::supportedLocales):
(JSC::intlDateTimeFormatAvailableLocales): Deleted.
(JSC::intlNumberFormatAvailableLocales): Deleted.
* runtime/IntlObject.h:
(JSC::intlDateTimeFormatAvailableLocales):
(JSC::intlNumberFormatAvailableLocales):
(JSC::intlPluralRulesAvailableLocales):
(JSC::intlRelativeTimeFormatAvailableLocales):
Perform three corrections for Intl classes:
  1. Collator should be the only class with unique "available locales".
     [unum|udat]_getAvailable exist but they've deferred to uloc_getAvailable for 20 years.
  2. isUnicodeLocaleIdentifierType isn't just `alphanum{3,8}` but rather `alphanum{3,8} (sep alphanum{3,8})*`.
     This is my own mistake from r239941.
  3. supportedLocalesOf entries should not be frozen.
     Changed in https://github.com/tc39/ecma402/pull/278.

* tools/JSDollarVM.cpp:
(JSC::functionICUVersion):
(JSC::JSDollarVM::finishCreation):
Add $vm.icuVersion so that we can add per-line skips to stress tests.

Tools:

* Scripts/run-jsc-stress-tests:
Add runIntlRelativeTimeFormatEnabled.

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (260348 => 260349)


--- trunk/JSTests/ChangeLog	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/JSTests/ChangeLog	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,3 +1,20 @@
+2020-04-19  Ross Kirsling  <[email protected]>
+
+        [ECMA-402] Intl.RelativeTimeFormat missing in WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=209770
+
+        Reviewed by Darin Adler.
+
+        * stress/intl-relativetimeformat.js: Added.
+
+        * test262/config.yaml:
+        Enable Intl.RelativeTimeFormat feature with flag.
+
+        * test262/expectations.yaml:
+        Mark known failures.
+        Test for locale validation is not specific to RelativeTimeFormat and should be investigated separately.
+        Tests for Polish appear to be wrong and should be corrected in test262.
+
 2020-04-18  Keith Miller  <[email protected]>
 
         Unreviewed, mark test passing.

Added: trunk/JSTests/stress/intl-relativetimeformat.js (0 => 260349)


--- trunk/JSTests/stress/intl-relativetimeformat.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-relativetimeformat.js	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,273 @@
+//@ runIntlRelativeTimeFormatEnabled
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+const icuVersion = $vm.icuVersion();
+function shouldBeForICUVersion(minimumVersion, actual, expected) {
+    if (icuVersion < minimumVersion)
+        return;
+
+    if (actual !== expected)
+        throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+function shouldNotThrow(func) {
+    func();
+}
+
+function shouldThrow(func, errorType) {
+    let error;
+    try {
+        func();
+    } catch (e) {
+        error = e;
+    }
+
+    if (!(error instanceof errorType))
+        throw new Error(`Expected ${errorType.name}!`);
+}
+
+shouldBe(Intl.RelativeTimeFormat instanceof Function, true);
+shouldBe(Intl.RelativeTimeFormat.length, 0);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat, 'prototype').writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat, 'prototype').enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat, 'prototype').configurable, false);
+
+shouldThrow(() => Intl.RelativeTimeFormat(), TypeError);
+shouldThrow(() => Intl.RelativeTimeFormat.call({}), TypeError);
+
+shouldThrow(() => new Intl.RelativeTimeFormat('$'), RangeError);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', null), TypeError);
+
+shouldBe(new Intl.RelativeTimeFormat() instanceof Intl.RelativeTimeFormat, true);
+
+{
+    class DerivedRelativeTimeFormat extends Intl.RelativeTimeFormat {}
+
+    const drtf = new DerivedRelativeTimeFormat();
+    shouldBe(drtf instanceof DerivedRelativeTimeFormat, true);
+    shouldBe(drtf instanceof Intl.RelativeTimeFormat, true);
+    shouldBe(drtf.format, Intl.RelativeTimeFormat.prototype.format);
+    shouldBe(drtf.formatToParts, Intl.RelativeTimeFormat.prototype.formatToParts);
+    shouldBe(Object.getPrototypeOf(drtf), DerivedRelativeTimeFormat.prototype);
+    shouldBe(Object.getPrototypeOf(DerivedRelativeTimeFormat.prototype), Intl.RelativeTimeFormat.prototype);
+}
+
+shouldBe(Intl.RelativeTimeFormat.supportedLocalesOf.length, 1);
+shouldBe(Intl.RelativeTimeFormat.supportedLocalesOf() instanceof Array, true);
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf.call(null, 'en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf.call({}, 'en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf.call(1, 'en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(9)), '[]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf({ length: 4, 1: 'en', 0: 'es', 3: 'de' })), '["es","en","de"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(['en', 'pt', 'en', 'es'])), '["en","pt","es"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('En-laTn-us-variant2-variant1-1abc-U-ko-tRue-A-aa-aaa-x-RESERVED')), '["en-Latn-US-variant2-variant1-1abc-a-aa-aaa-u-ko-x-reserved"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('no-bok')), '["nb"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('x-some-thing')), '[]');
+
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(Object.create(null, { length: { get() { throw new Error(); } } })), Error);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(Object.create(null, { length: { value: 1 }, 0: { get() { throw new Error(); } } })), Error);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf([{ toString() { throw new Error(); } }]), Error);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf([5]), TypeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(''), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('a'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('abcdefghij'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('#$'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-@-abc'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-u'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-u-kn-true-u-ko-true'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-x'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-*'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en--US'), RangeError);
+
+const validLanguageTags = [
+    'de', // ISO 639 language code
+    'de-DE', // + ISO 3166-1 country code
+    'DE-de', // tags are case-insensitive
+    'cmn', // ISO 639 language code
+    'cmn-Hans', // + script code
+    'CMN-hANS', // tags are case-insensitive
+    'cmn-hans-cn', // + ISO 3166-1 country code
+    'es-419', // + UN M.49 region code
+    'es-419-u-nu-latn-cu-bob', // + Unicode locale extension sequence
+    'i-klingon', // grandfathered tag
+    'cmn-hans-cn-t-ca-u-ca-x-t-u', // singleton subtags can also be used as private use subtags
+    'enochian-enochian', // language and variant subtags may be the same
+    'de-gregory-u-ca-gregory', // variant and extension subtags may be the same
+    'aa-a-foo-x-a-foo-bar', // variant subtags can also be used as private use subtags
+    'x-en-US-12345', // anything goes in private use tags
+    'x-12345-12345-en-US',
+    'x-en-US-12345-12345',
+    'x-en-u-foo',
+    'x-en-u-foo-u-bar'
+];
+for (let validLanguageTag of validLanguageTags)
+    shouldNotThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(validLanguageTag));
+
+shouldBe(Object.getPrototypeOf(Intl.RelativeTimeFormat.prototype), Object.prototype);
+
+shouldBe(Intl.RelativeTimeFormat.prototype.constructor, Intl.RelativeTimeFormat);
+
+shouldBe(Intl.RelativeTimeFormat.prototype[Symbol.toStringTag], 'Intl.RelativeTimeFormat');
+shouldBe(Object.prototype.toString.call(Intl.RelativeTimeFormat.prototype), '[object Intl.RelativeTimeFormat]');
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat.prototype, Symbol.toStringTag).writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat.prototype, Symbol.toStringTag).enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat.prototype, Symbol.toStringTag).configurable, true);
+
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher:'bad' }), RangeError);
+shouldNotThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher:'lookup' }));
+shouldNotThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher:'best fit' }));
+
+const defaultRTF = new Intl.RelativeTimeFormat('en');
+
+shouldBe(Intl.RelativeTimeFormat.prototype.resolvedOptions.length, 0);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.resolvedOptions.call(5), TypeError);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.resolvedOptions.call({}), TypeError);
+shouldBe(defaultRTF.resolvedOptions() instanceof Object, true);
+shouldBe(defaultRTF.resolvedOptions() !== defaultRTF.resolvedOptions(), true);
+shouldBe(defaultRTF.resolvedOptions().locale, 'en');
+shouldBe(defaultRTF.resolvedOptions().style, 'long');
+shouldBe(defaultRTF.resolvedOptions().numeric, 'always');
+shouldBe(defaultRTF.resolvedOptions().numberingSystem, 'latn');
+
+shouldBe(new Intl.RelativeTimeFormat('en-u-nu-hanidec').resolvedOptions().locale, 'en-u-nu-hanidec');
+shouldBe(new Intl.RelativeTimeFormat('en-u-nu-hanidec', { numberingSystem: 'gujr' }).resolvedOptions().locale, 'en');
+shouldBe(new Intl.RelativeTimeFormat('en', { numberingSystem: 'hanidec' }).resolvedOptions().locale, 'en');
+shouldBe(new Intl.RelativeTimeFormat('en-u-ca-chinese').resolvedOptions().locale, 'en');
+
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { style: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { style: 'bad' }), RangeError);
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'long' }).resolvedOptions().style, 'long');
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'short' }).resolvedOptions().style, 'short');
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'narrow' }).resolvedOptions().style, 'narrow');
+
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { numeric: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { numeric: 'bad' }), RangeError);
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'always' }).resolvedOptions().numeric, 'always');
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).resolvedOptions().numeric, 'auto');
+
+const numberingSystems = [
+    'arab', 'arabext', 'bali', 'beng', 'deva', 'fullwide', 'gujr', 'guru',
+    'hanidec', 'khmr', 'knda', 'laoo', 'latn', 'limb', 'mlym', 'mong', 'mymr',
+    'orya', 'tamldec', 'telu', 'thai', 'tibt'
+]
+for (let numberingSystem of numberingSystems) {
+    shouldBe(new Intl.RelativeTimeFormat('en', { numberingSystem }).resolvedOptions().numberingSystem, numberingSystem);
+    shouldBe(new Intl.RelativeTimeFormat(`en-u-nu-${numberingSystem}`).resolvedOptions().numberingSystem, numberingSystem);
+}
+
+shouldBe(Intl.RelativeTimeFormat.prototype.format.length, 2);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.format.call({}, 3, 'days'), TypeError);
+shouldThrow(() => defaultRTF.format(Symbol(), 'days'), TypeError);
+shouldThrow(() => defaultRTF.format(3, Symbol()), TypeError);
+shouldThrow(() => defaultRTF.format(Infinity, 'days'), RangeError);
+shouldThrow(() => defaultRTF.format(3, 'centuries'), RangeError);
+
+const units = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'];
+if (icuVersion >= 63)
+    units.push('quarter');
+
+for (let unit of units) {
+    shouldBe(defaultRTF.format(10, unit), defaultRTF.format(10, `${unit}s`));
+
+    shouldBe(defaultRTF.format(10000.5, unit), `in 10,000.5 ${unit}s`);
+    shouldBe(defaultRTF.format(10, unit), `in 10 ${unit}s`);
+    shouldBe(defaultRTF.format(0, unit), `in 0 ${unit}s`);
+    shouldBe(defaultRTF.format(-10, unit), `10 ${unit}s ago`);
+    shouldBe(defaultRTF.format(-10000.5, unit), `10,000.5 ${unit}s ago`);
+
+    shouldBeForICUVersion(64, defaultRTF.format(1, unit), `in 1 ${unit}`);
+    shouldBeForICUVersion(63, defaultRTF.format(-0, unit), `0 ${unit}s ago`);
+    shouldBeForICUVersion(64, defaultRTF.format(-1, unit), `1 ${unit} ago`);
+}
+
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'short' }).format(10, 'second'), 'in 10 sec.');
+shouldBe(new Intl.RelativeTimeFormat('ru', { style: 'short' }).format(10, 'second'), 'через 10 сек.');
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'narrow' }).format(10, 'second'), 'in 10 sec.');
+shouldBe(new Intl.RelativeTimeFormat('ru', { style: 'narrow' }).format(10, 'second'), '+10 с');
+
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'second'), 'now');
+shouldBe(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).format(0, 'second'), '今');
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'day'), 'today');
+shouldBe(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).format(0, 'day'), '今日');
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'year'), 'this year');
+shouldBe(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).format(0, 'year'), '今年');
+
+shouldBe(new Intl.RelativeTimeFormat('en', { numberingSystem: 'thai' }).format(-10, 'hour'), '๑๐ hours ago');
+shouldBe(new Intl.RelativeTimeFormat('en-u-nu-thai').format(-10, 'hour'), '๑๐ hours ago');
+shouldBe(new Intl.RelativeTimeFormat('ko', { numberingSystem: 'hanidec' }).format(-10, 'hour'), '一〇시간 전');
+shouldBe(new Intl.RelativeTimeFormat('ko-u-nu-hanidec').format(-10, 'hour'), '一〇시간 전');
+
+shouldBe(Intl.RelativeTimeFormat.prototype.formatToParts.length, 2);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.formatToParts.call({}, 3, 'days'), TypeError);
+shouldThrow(() => defaultRTF.formatToParts(Symbol(), 'days'), TypeError);
+shouldThrow(() => defaultRTF.formatToParts(3, Symbol()), TypeError);
+shouldThrow(() => defaultRTF.formatToParts(Infinity, 'days'), RangeError);
+shouldThrow(() => defaultRTF.formatToParts(3, 'centuries'), RangeError);
+
+for (let unit of units) {
+    shouldBe(JSON.stringify(defaultRTF.formatToParts(10, unit)), JSON.stringify(defaultRTF.formatToParts(10, `${unit}s`)));
+
+    const concatenateValues = (parts) => parts.map(part => part.value).join('');
+
+    shouldBe(concatenateValues(defaultRTF.formatToParts(10000.5, unit)), `in 10,000.5 ${unit}s`);
+    shouldBe(concatenateValues(defaultRTF.formatToParts(10, unit)), `in 10 ${unit}s`);
+    shouldBe(concatenateValues(defaultRTF.formatToParts(0, unit)), `in 0 ${unit}s`);
+    shouldBe(concatenateValues(defaultRTF.formatToParts(-10, unit)), `10 ${unit}s ago`);
+    shouldBe(concatenateValues(defaultRTF.formatToParts(-10000.5, unit)), `10,000.5 ${unit}s ago`);
+
+    shouldBeForICUVersion(64, concatenateValues(defaultRTF.formatToParts(1, unit)), `in 1 ${unit}`);
+    shouldBeForICUVersion(63, concatenateValues(defaultRTF.formatToParts(-0, unit)), `0 ${unit}s ago`);
+    shouldBeForICUVersion(64, concatenateValues(defaultRTF.formatToParts(-1, unit)), `1 ${unit} ago`);
+}
+
+shouldBe(
+    JSON.stringify(defaultRTF.formatToParts(10000.5, 'day')),
+    JSON.stringify([
+        { type: 'literal', value: 'in ' },
+        { type: 'integer', value: '10', unit: 'day' },
+        { type: 'group', value: ',', unit: 'day' },
+        { type: 'integer', value: '000', unit: 'day' },
+        { type: 'decimal', value: '.', unit: 'day' },
+        { type: 'fraction', value: '5', unit: 'day' },
+        { type: 'literal', value: ' days' }
+    ])
+);
+
+shouldBe(
+    JSON.stringify(new Intl.RelativeTimeFormat('sw').formatToParts(10, 'year')),
+    JSON.stringify([
+        { type: 'literal', value: 'baada ya miaka ' },
+        { type: 'integer', value: '10', unit: 'year' },
+    ])
+);
+
+shouldBe(
+    JSON.stringify(new Intl.RelativeTimeFormat('ru', { style: 'narrow' }).formatToParts(10, 'second')),
+    JSON.stringify([
+        { type: 'literal', value: '+' },
+        { type: 'integer', value: '10', unit: 'second' },
+        { type: 'literal', value: ' с' }
+    ])
+);
+
+shouldBe(
+    JSON.stringify(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).formatToParts(0, 'week')),
+    JSON.stringify([
+        { type: 'literal', value: '今週' }
+    ])
+);
+
+shouldBe(
+    JSON.stringify(new Intl.RelativeTimeFormat('ko', { numberingSystem: 'hanidec' }).formatToParts(-10, 'hour')),
+    JSON.stringify([
+        { type: 'integer', value: '一〇', unit: 'hour' },
+        { type: 'literal', value: '시간 전' }
+    ])
+);

Modified: trunk/JSTests/test262/config.yaml (260348 => 260349)


--- trunk/JSTests/test262/config.yaml	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/JSTests/test262/config.yaml	2020-04-20 05:15:35 UTC (rev 260349)
@@ -2,6 +2,7 @@
 ---
 flags:
   BigInt: useBigInt
+  Intl.RelativeTimeFormat: useIntlRelativeTimeFormat
   WeakRef: useWeakRefs
   class-fields-public: usePublicClassFields
   logical-assignment-operators: useLogicalAssignmentOperators
@@ -30,7 +31,6 @@
     - Intl.ListFormat
     - Intl.Locale
     - Intl.NumberFormat-unified
-    - Intl.RelativeTimeFormat
     - Intl.Segmenter
   paths:
     - test/built-ins/DataView/prototype/getBigInt64
@@ -153,3 +153,7 @@
     # https://bugs.webkit.org/show_bug.cgi?id=209783
     - test/intl402/DateTimeFormat/prototype/format/related-year-zh.js
     - test/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js
+
+    # requires ICU 65 (https://unicode-org.atlassian.net/browse/ICU-20654)
+    - test/intl402/RelativeTimeFormat/prototype/format/en-us-numeric-auto.js
+    - test/intl402/RelativeTimeFormat/prototype/formatToParts/en-us-numeric-auto.js

Modified: trunk/JSTests/test262/expectations.yaml (260348 => 260349)


--- trunk/JSTests/test262/expectations.yaml	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/JSTests/test262/expectations.yaml	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1935,12 +1935,33 @@
 test/intl402/PluralRules/proto-from-ctor-realm.js:
   default: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Object]», «[object Object]») to be true'
   strict mode: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Object]», «[object Object]») to be true'
+test/intl402/RelativeTimeFormat/constructor/constructor/locales-valid.js:
+  default: 'Test262Error: Grandfathered Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Grandfathered Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/RelativeTimeFormat/constructor/constructor/proto-from-ctor-realm.js:
+  default: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Intl.RelativeTimeFormat]», «[object Intl.RelativeTimeFormat]») to be true'
+  strict mode: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Intl.RelativeTimeFormat]», «[object Intl.RelativeTimeFormat]») to be true'
+test/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-long.js:
+  default: 'Test262Error: Expected SameValue(«za 1000 sekund», «za 1 000 sekund») to be true'
+  strict mode: 'Test262Error: Expected SameValue(«za 1000 sekund», «za 1 000 sekund») to be true'
+test/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-narrow.js:
+  default: 'Test262Error: Expected SameValue(«za 1000 s», «za 1 000 s») to be true'
+  strict mode: 'Test262Error: Expected SameValue(«za 1000 s», «za 1 000 s») to be true'
+test/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-short.js:
+  default: 'Test262Error: Expected SameValue(«za 1000 sek.», «za 1 000 sek.») to be true'
+  strict mode: 'Test262Error: Expected SameValue(«za 1000 sek.», «za 1 000 sek.») to be true'
+test/intl402/RelativeTimeFormat/prototype/formatToParts/pl-pl-style-long.js:
+  default: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+  strict mode: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+test/intl402/RelativeTimeFormat/prototype/formatToParts/pl-pl-style-narrow.js:
+  default: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+  strict mode: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+test/intl402/RelativeTimeFormat/prototype/formatToParts/pl-pl-style-short.js:
+  default: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+  strict mode: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
 test/intl402/language-tags-invalid.js:
   default: 'Test262Error: Test data "de-gregory-gregory" is a canonicalized and structurally valid language tag.'
   strict mode: 'Test262Error: Test data "de-gregory-gregory" is a canonicalized and structurally valid language tag.'
-test/intl402/supportedLocalesOf-returned-array-elements-are-not-frozen.js:
-  default: 'Test262Error: Property 0 of object returned by SupportedLocales is not writable. Expected SameValue(«false», «true») to be true (Testing with Collator.)'
-  strict mode: 'Test262Error: Property 0 of object returned by SupportedLocales is not writable. Expected SameValue(«false», «true») to be true (Testing with Collator.)'
 test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-arguments.js:
   default: 'Test262Error: Expected obj[0] to have enumerable:false.'
 test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-param.js:

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (260348 => 260349)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2020-04-20 05:15:35 UTC (rev 260349)
@@ -75,6 +75,8 @@
     runtime/IntlObject.cpp
     runtime/IntlPluralRulesConstructor.cpp
     runtime/IntlPluralRulesPrototype.cpp
+    runtime/IntlRelativeTimeFormatConstructor.cpp
+    runtime/IntlRelativeTimeFormatPrototype.cpp
     runtime/JSDataViewPrototype.cpp
     runtime/JSGlobalObject.cpp
     runtime/JSInternalPromiseConstructor.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (260348 => 260349)


--- trunk/Source/_javascript_Core/ChangeLog	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,3 +1,94 @@
+2020-04-19  Ross Kirsling  <[email protected]>
+
+        [ECMA-402] Intl.RelativeTimeFormat missing in WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=209770
+
+        Reviewed by Darin Adler.
+
+        This patch implements the recent ECMA-402 feature Intl.RelativeTimeFormat.
+
+        RelativeTimeFormat has format / formatToParts functions like NumberFormat / DateTimeFormat
+        and is used to turn a number and unit into a formatted relative time string, e.g.:
+
+          new Intl.RelativeTimeFormat('en').format(10, 'day')
+          > 'in 10 days'
+
+          new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'day')
+          > 'today'
+
+        Implementation of RelativeTimeFormat#formatToParts makes direct use of NumberFormat#formatToParts,
+        as the relative time string consists of at most one formatted number with optional literal text on either side.
+
+        This feature is runtime-guarded by the `useIntlRelativeTimeFormat` option.
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * runtime/CommonIdentifiers.h:
+        * runtime/IntlRelativeTimeFormat.cpp: Added.
+        * runtime/IntlRelativeTimeFormat.h: Added.
+        * runtime/IntlRelativeTimeFormatConstructor.cpp: Added.
+        * runtime/IntlRelativeTimeFormatConstructor.h: Added.
+        * runtime/IntlRelativeTimeFormatPrototype.cpp: Added.
+        * runtime/IntlRelativeTimeFormatPrototype.h: Added.
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::relativeTimeFormatStructure):
+        * runtime/OptionsList.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+        Add feature and runtime option.
+
+        * runtime/IntlDateTimeFormat.cpp:
+        (JSC::IntlDateTimeFormat::formatToParts):
+        * runtime/IntlPluralRules.cpp:
+        (JSC::IntlPluralRules::initializePluralRules):
+        (JSC::IntlPluralRules::resolvedOptions):
+        Make "type" a property name.
+
+        * runtime/IntlNumberFormat.cpp:
+        (JSC::IntlNumberFormat::initializeNumberFormat):
+        (JSC::IntlNumberFormat::resolvedOptions):
+        (JSC::IntlNumberFormat::formatToPartsInternal):
+        (JSC::IntlNumberFormat::formatToParts):
+        * runtime/IntlNumberFormat.h:
+        Factor out formatToPartsInternal so that RelativeTimeFormat can use it with its own UNumberFormat.
+        (This logic is too complicated to duplicate; it's because ICU won't split, e.g., "10,000" into parts for us.)
+
+        * runtime/IntlObject.cpp:
+        (JSC::IntlObject::IntlObject):
+        (JSC::IntlObject::create):
+        (JSC::IntlObject::finishCreation):
+        (JSC::intlAvailableLocales):
+        (JSC::intlCollatorAvailableLocales):
+        (JSC::isUnicodeLocaleIdentifierType):
+        (JSC::supportedLocales):
+        (JSC::intlDateTimeFormatAvailableLocales): Deleted.
+        (JSC::intlNumberFormatAvailableLocales): Deleted.
+        * runtime/IntlObject.h:
+        (JSC::intlDateTimeFormatAvailableLocales):
+        (JSC::intlNumberFormatAvailableLocales):
+        (JSC::intlPluralRulesAvailableLocales):
+        (JSC::intlRelativeTimeFormatAvailableLocales):
+        Perform three corrections for Intl classes:
+          1. Collator should be the only class with unique "available locales".
+             [unum|udat]_getAvailable exist but they've deferred to uloc_getAvailable for 20 years.
+          2. isUnicodeLocaleIdentifierType isn't just `alphanum{3,8}` but rather `alphanum{3,8} (sep alphanum{3,8})*`.
+             This is my own mistake from r239941.
+          3. supportedLocalesOf entries should not be frozen.
+             Changed in https://github.com/tc39/ecma402/pull/278.
+
+        * tools/JSDollarVM.cpp:
+        (JSC::functionICUVersion):
+        (JSC::JSDollarVM::finishCreation):
+        Add $vm.icuVersion so that we can add per-line skips to stress tests.
+
 2020-04-19  Yusuke Suzuki  <[email protected]>
 
         [JSC] SlowPathCall is not supported by callOperation in Windows

Modified: trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist (260348 => 260349)


--- trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist	2020-04-20 05:15:35 UTC (rev 260349)
@@ -142,6 +142,8 @@
 $(PROJECT_DIR)/runtime/IntlObject.cpp
 $(PROJECT_DIR)/runtime/IntlPluralRulesConstructor.cpp
 $(PROJECT_DIR)/runtime/IntlPluralRulesPrototype.cpp
+$(PROJECT_DIR)/runtime/IntlRelativeTimeFormatConstructor.cpp
+$(PROJECT_DIR)/runtime/IntlRelativeTimeFormatPrototype.cpp
 $(PROJECT_DIR)/runtime/JSDataViewPrototype.cpp
 $(PROJECT_DIR)/runtime/JSGlobalObject.cpp
 $(PROJECT_DIR)/runtime/JSInternalPromiseConstructor.cpp

Modified: trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist (260348 => 260349)


--- trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist	2020-04-20 05:15:35 UTC (rev 260349)
@@ -33,6 +33,8 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlObject.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlPluralRulesConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlPluralRulesPrototype.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlRelativeTimeFormatConstructor.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlRelativeTimeFormatPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/JSCBuiltins.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/JSDataViewPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/JSGlobalObject.lut.h

Modified: trunk/Source/_javascript_Core/DerivedSources.make (260348 => 260349)


--- trunk/Source/_javascript_Core/DerivedSources.make	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/DerivedSources.make	2020-04-20 05:15:35 UTC (rev 260349)
@@ -153,6 +153,8 @@
     IntlObject.lut.h \
     IntlPluralRulesConstructor.lut.h \
     IntlPluralRulesPrototype.lut.h \
+    IntlRelativeTimeFormatConstructor.lut.h \
+    IntlRelativeTimeFormatPrototype.lut.h \
     JSDataViewPrototype.lut.h \
     JSGlobalObject.lut.h \
     JSInternalPromiseConstructor.lut.h \

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (260348 => 260349)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-04-20 05:15:35 UTC (rev 260349)
@@ -4334,6 +4334,12 @@
 		A1E0451B1C25B4B100BB663C /* StringPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = StringPrototype.js; sourceTree = "<group>"; };
 		A1FE1EB01C2C537E00A289FF /* DatePrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = DatePrototype.js; sourceTree = "<group>"; };
 		A27958D7FA1142B0AC9E364D /* WasmContextInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmContextInlines.h; sourceTree = "<group>"; };
+		A3BF884B24480BDE001B9F35 /* IntlRelativeTimeFormatPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormatPrototype.cpp; sourceTree = "<group>"; };
+		A3BF884C24480BDF001B9F35 /* IntlRelativeTimeFormatPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormatPrototype.h; sourceTree = "<group>"; };
+		A3BF884D24480BDF001B9F35 /* IntlRelativeTimeFormatConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormatConstructor.cpp; sourceTree = "<group>"; };
+		A3BF884E24480BE0001B9F35 /* IntlRelativeTimeFormatConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormatConstructor.h; sourceTree = "<group>"; };
+		A3BF884F24480BE0001B9F35 /* IntlRelativeTimeFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormat.cpp; sourceTree = "<group>"; };
+		A3BF885024480BE1001B9F35 /* IntlRelativeTimeFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormat.h; sourceTree = "<group>"; };
 		A3FF9BC52234746600B1A9AB /* YarrFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrFlags.h; path = yarr/YarrFlags.h; sourceTree = "<group>"; };
 		A3FF9BC62234746600B1A9AB /* YarrFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrFlags.cpp; path = yarr/YarrFlags.cpp; sourceTree = "<group>"; };
 		A503FA13188E0FAF00110F14 /* _javascript_CallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = _javascript_CallFrame.cpp; sourceTree = "<group>"; };
@@ -7265,6 +7271,12 @@
 				7D5FB19020744BF1005DDF64 /* IntlPluralRulesConstructor.h */,
 				7D5FB19120744BF1005DDF64 /* IntlPluralRulesPrototype.cpp */,
 				7D5FB18D20744AE8005DDF64 /* IntlPluralRulesPrototype.h */,
+				A3BF884F24480BE0001B9F35 /* IntlRelativeTimeFormat.cpp */,
+				A3BF885024480BE1001B9F35 /* IntlRelativeTimeFormat.h */,
+				A3BF884D24480BDF001B9F35 /* IntlRelativeTimeFormatConstructor.cpp */,
+				A3BF884E24480BE0001B9F35 /* IntlRelativeTimeFormatConstructor.h */,
+				A3BF884B24480BDE001B9F35 /* IntlRelativeTimeFormatPrototype.cpp */,
+				A3BF884C24480BDF001B9F35 /* IntlRelativeTimeFormatPrototype.h */,
 				0F275F2C1ECE079600620D47 /* Intrinsic.cpp */,
 				86BF642A148DB2B5004DE36A /* Intrinsic.h */,
 				8B9F6D551D5912FA001C739F /* IterationKind.h */,

Modified: trunk/Source/_javascript_Core/Sources.txt (260348 => 260349)


--- trunk/Source/_javascript_Core/Sources.txt	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/Sources.txt	2020-04-20 05:15:35 UTC (rev 260349)
@@ -819,6 +819,9 @@
 runtime/IntlPluralRules.cpp
 runtime/IntlPluralRulesConstructor.cpp
 runtime/IntlPluralRulesPrototype.cpp
+runtime/IntlRelativeTimeFormat.cpp
+runtime/IntlRelativeTimeFormatConstructor.cpp
+runtime/IntlRelativeTimeFormatPrototype.cpp
 runtime/IteratorOperations.cpp
 runtime/IteratorPrototype.cpp
 runtime/JSArray.cpp

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -49,6 +49,7 @@
     macro(Promise) \
     macro(Reflect) \
     macro(RegExp) \
+    macro(RelativeTimeFormat) \
     macro(RemotePlayback) \
     macro(Set) \
     macro(SharedArrayBuffer) \
@@ -178,6 +179,7 @@
     macro(stack) \
     macro(stackTraceLimit) \
     macro(sticky) \
+    macro(style) \
     macro(subarray) \
     macro(summary) \
     macro(target) \
@@ -193,6 +195,7 @@
     macro(toLocaleString) \
     macro(toPrecision) \
     macro(toString) \
+    macro(type) \
     macro(uid) \
     macro(unicode) \
     macro(usage) \

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1029,7 +1029,6 @@
         return throwOutOfMemoryError(globalObject, scope);
 
     auto resultString = String(result.data(), resultLength);
-    auto typePropertyName = Identifier::fromString(vm, "type");
     auto literalString = jsNontrivialString(vm, "literal"_s);
 
     int32_t previousEndIndex = 0;
@@ -1043,7 +1042,7 @@
         if (previousEndIndex < beginIndex) {
             auto value = jsString(vm, resultString.substring(previousEndIndex, beginIndex - previousEndIndex));
             JSObject* part = constructEmptyObject(globalObject);
-            part->putDirect(vm, typePropertyName, literalString);
+            part->putDirect(vm, vm.propertyNames->type, literalString);
             part->putDirect(vm, vm.propertyNames->value, value);
             parts->push(globalObject, part);
             RETURN_IF_EXCEPTION(scope, { });
@@ -1054,7 +1053,7 @@
             auto type = jsString(vm, partTypeString(UDateFormatField(fieldType)));
             auto value = jsString(vm, resultString.substring(beginIndex, endIndex - beginIndex));
             JSObject* part = constructEmptyObject(globalObject);
-            part->putDirect(vm, typePropertyName, type);
+            part->putDirect(vm, vm.propertyNames->type, type);
             part->putDirect(vm, vm.propertyNames->value, value);
             parts->push(globalObject, part);
             RETURN_IF_EXCEPTION(scope, { });

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -2,6 +2,7 @@
  * Copyright (C) 2015 Andy VanWagoner ([email protected])
  * Copyright (C) 2016 Sukolsak Sakshuwong ([email protected])
  * Copyright (C) 2016-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -195,7 +196,7 @@
 
     m_numberingSystem = result.get("nu"_s);
 
-    String styleString = intlStringOption(globalObject, options, Identifier::fromString(vm, "style"), { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal");
+    String styleString = intlStringOption(globalObject, options, vm.propertyNames->style, { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal");
     RETURN_IF_EXCEPTION(scope, void());
     if (styleString == "decimal")
         m_style = Style::Decimal;
@@ -441,7 +442,7 @@
     JSObject* options = constructEmptyObject(globalObject);
     options->putDirect(vm, vm.propertyNames->locale, jsString(vm, m_locale));
     options->putDirect(vm, vm.propertyNames->numberingSystem, jsString(vm, m_numberingSystem));
-    options->putDirect(vm, Identifier::fromString(vm, "style"), jsNontrivialString(vm, styleString(m_style)));
+    options->putDirect(vm, vm.propertyNames->style, jsNontrivialString(vm, styleString(m_style)));
     if (m_style == Style::Currency) {
         options->putDirect(vm, Identifier::fromString(vm, "currency"), jsNontrivialString(vm, m_currency));
         options->putDirect(vm, Identifier::fromString(vm, "currencyDisplay"), jsNontrivialString(vm, currencyDisplayString(m_currencyDisplay)));
@@ -503,6 +504,52 @@
     return "unknown"_s;
 }
 
+void IntlNumberFormat::formatToPartsInternal(JSGlobalObject* globalObject, double value, const String& formatted, UFieldPositionIterator* iterator, JSArray* parts, JSString* unit)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto stringLength = formatted.length();
+
+    int32_t literalFieldType = -1;
+    auto literalField = IntlNumberFormatField(literalFieldType, stringLength);
+    Vector<IntlNumberFormatField, 32> fields(stringLength, literalField);
+    int32_t beginIndex = 0;
+    int32_t endIndex = 0;
+    auto fieldType = ufieldpositer_next(iterator, &beginIndex, &endIndex);
+    while (fieldType >= 0) {
+        auto size = endIndex - beginIndex;
+        for (auto i = beginIndex; i < endIndex; ++i) {
+            // Only override previous value if new value is more specific.
+            if (fields[i].size >= size)
+                fields[i] = IntlNumberFormatField(fieldType, size);
+        }
+        fieldType = ufieldpositer_next(iterator, &beginIndex, &endIndex);
+    }
+
+    auto literalString = jsNontrivialString(vm, "literal"_s);
+    Identifier unitName;
+    if (unit)
+        unitName = Identifier::fromString(vm, "unit");
+
+    size_t currentIndex = 0;
+    while (currentIndex < stringLength) {
+        auto startIndex = currentIndex;
+        auto fieldType = fields[currentIndex].type;
+        while (currentIndex < stringLength && fields[currentIndex].type == fieldType)
+            ++currentIndex;
+        auto partType = fieldType == literalFieldType ? literalString : jsString(vm, partTypeString(UNumberFormatFields(fieldType), value));
+        auto partValue = jsSubstring(vm, formatted, startIndex, currentIndex - startIndex);
+        JSObject* part = constructEmptyObject(globalObject);
+        part->putDirect(vm, vm.propertyNames->type, partType);
+        part->putDirect(vm, vm.propertyNames->value, partValue);
+        if (unit)
+            part->putDirect(vm, unitName, unit);
+        parts->push(globalObject, part);
+        RETURN_IF_EXCEPTION(scope, void());
+    }
+}
+
 JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, double value)
 {
     VM& vm = globalObject->vm();
@@ -520,7 +567,6 @@
     if (U_FAILURE(status))
         return throwTypeError(globalObject, scope, "failed to open field position iterator"_s);
 
-    status = U_ZERO_ERROR;
     Vector<UChar, 32> result(32);
     auto resultLength = unum_formatDoubleForFields(m_numberFormat.get(), value, result.data(), result.size(), fieldItr.get(), &status);
     if (status == U_BUFFER_OVERFLOW_ERROR) {
@@ -531,46 +577,15 @@
     if (U_FAILURE(status))
         return throwTypeError(globalObject, scope, "failed to format a number."_s);
 
-    int32_t literalFieldType = -1;
-    auto literalField = IntlNumberFormatField(literalFieldType, resultLength);
-    Vector<IntlNumberFormatField> fields(resultLength, literalField);
-    int32_t beginIndex = 0;
-    int32_t endIndex = 0;
-    auto fieldType = ufieldpositer_next(fieldItr.get(), &beginIndex, &endIndex);
-    while (fieldType >= 0) {
-        auto size = endIndex - beginIndex;
-        for (auto i = beginIndex; i < endIndex; ++i) {
-            // Only override previous value if new value is more specific.
-            if (fields[i].size >= size)
-                fields[i] = IntlNumberFormatField(fieldType, size);
-        }
-        fieldType = ufieldpositer_next(fieldItr.get(), &beginIndex, &endIndex);
-    }
+    auto resultString = String(result.data(), resultLength);
 
     JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
     if (!parts)
         return throwOutOfMemoryError(globalObject, scope);
-    unsigned index = 0;
 
-    auto resultString = String(result.data(), resultLength);
-    auto typePropertyName = Identifier::fromString(vm, "type");
-    auto literalString = jsNontrivialString(vm, "literal"_s);
+    formatToPartsInternal(globalObject, value, resultString, fieldItr.get(), parts);
+    RETURN_IF_EXCEPTION(scope, { });
 
-    int32_t currentIndex = 0;
-    while (currentIndex < resultLength) {
-        auto startIndex = currentIndex;
-        auto fieldType = fields[currentIndex].type;
-        while (currentIndex < resultLength && fields[currentIndex].type == fieldType)
-            ++currentIndex;
-        auto partType = fieldType == literalFieldType ? literalString : jsString(vm, partTypeString(UNumberFormatFields(fieldType), value));
-        auto partValue = jsSubstring(vm, resultString, startIndex, currentIndex - startIndex);
-        JSObject* part = constructEmptyObject(globalObject);
-        part->putDirect(vm, typePropertyName, partType);
-        part->putDirect(vm, vm.propertyNames->value, partValue);
-        parts->putDirectIndex(globalObject, index++, part);
-        RETURN_IF_EXCEPTION(scope, { });
-    }
-
     return parts;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Andy VanWagoner ([email protected])
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -57,12 +58,14 @@
     void initializeNumberFormat(JSGlobalObject*, JSValue locales, JSValue optionsValue);
     JSValue format(JSGlobalObject*, double);
     JSValue format(JSGlobalObject*, JSBigInt*);
-    JSValue formatToParts(JSGlobalObject*, double value);
+    JSValue formatToParts(JSGlobalObject*, double);
     JSObject* resolvedOptions(JSGlobalObject*);
 
     JSBoundFunction* boundFormat() const { return m_boundFormat.get(); }
     void setBoundFormat(VM&, JSBoundFunction*);
 
+    static void formatToPartsInternal(JSGlobalObject*, double, const String& formatted, UFieldPositionIterator*, JSArray*, JSString* unit = nullptr);
+
 protected:
     IntlNumberFormat(VM&, Structure*);
     void finishCreation(VM&);

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -2,6 +2,7 @@
  * Copyright (C) 2015 Andy VanWagoner ([email protected])
  * Copyright (C) 2015 Sukolsak Sakshuwong ([email protected])
  * Copyright (C) 2016-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,6 +40,8 @@
 #include "IntlNumberFormatPrototype.h"
 #include "IntlPluralRulesConstructor.h"
 #include "IntlPluralRulesPrototype.h"
+#include "IntlRelativeTimeFormatConstructor.h"
+#include "IntlRelativeTimeFormatPrototype.h"
 #include "JSCInlines.h"
 #include "JSCJSValueInlines.h"
 #include "Lookup.h"
@@ -45,9 +48,7 @@
 #include "ObjectPrototype.h"
 #include "Options.h"
 #include <unicode/ucol.h>
-#include <unicode/udat.h>
 #include <unicode/uloc.h>
-#include <unicode/unum.h>
 #include <unicode/unumsys.h>
 #include <wtf/Assertions.h>
 #include <wtf/Language.h>
@@ -114,17 +115,26 @@
 const ClassInfo IntlObject::s_info = { "Object", &Base::s_info, &intlObjectTable, nullptr, CREATE_METHOD_TABLE(IntlObject) };
 
 IntlObject::IntlObject(VM& vm, Structure* structure)
-    : JSNonFinalObject(vm, structure)
+    : Base(vm, structure)
 {
 }
 
-IntlObject* IntlObject::create(VM& vm, Structure* structure)
+IntlObject* IntlObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
 {
     IntlObject* object = new (NotNull, allocateCell<IntlObject>(vm.heap)) IntlObject(vm, structure);
-    object->finishCreation(vm);
+    object->finishCreation(vm, globalObject);
     return object;
 }
 
+void IntlObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+    Base::finishCreation(vm);
+    if (Options::useIntlRelativeTimeFormat()) {
+        auto* relativeTimeFormatConstructor = IntlRelativeTimeFormatConstructor::create(vm, IntlRelativeTimeFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlRelativeTimeFormatPrototype*>(globalObject->relativeTimeFormatStructure()->storedPrototypeObject()));
+        putDirectWithoutTransition(vm, vm.propertyNames->RelativeTimeFormat, relativeTimeFormatConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    }
+}
+
 Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 {
     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
@@ -164,7 +174,7 @@
         availableLocales.add(zh_TW_String.get());
 }
 
-const HashSet<String>& intlCollatorAvailableLocales()
+const HashSet<String>& intlAvailableLocales()
 {
     static NeverDestroyed<HashSet<String>> cachedAvailableLocales;
     HashSet<String>& availableLocales = cachedAvailableLocales.get();
@@ -172,9 +182,9 @@
     static std::once_flag initializeOnce;
     std::call_once(initializeOnce, [&] {
         ASSERT(availableLocales.isEmpty());
-        int32_t count = ucol_countAvailable();
+        int32_t count = uloc_countAvailable();
         for (int32_t i = 0; i < count; ++i) {
-            String locale = convertICULocaleToBCP47LanguageTag(ucol_getAvailable(i));
+            String locale = convertICULocaleToBCP47LanguageTag(uloc_getAvailable(i));
             if (!locale.isEmpty())
                 availableLocales.add(locale);
         }
@@ -183,7 +193,7 @@
     return availableLocales;
 }
 
-const HashSet<String>& intlDateTimeFormatAvailableLocales()
+const HashSet<String>& intlCollatorAvailableLocales()
 {
     static NeverDestroyed<HashSet<String>> cachedAvailableLocales;
     HashSet<String>& availableLocales = cachedAvailableLocales.get();
@@ -191,9 +201,9 @@
     static std::once_flag initializeOnce;
     std::call_once(initializeOnce, [&] {
         ASSERT(availableLocales.isEmpty());
-        int32_t count = udat_countAvailable();
+        int32_t count = ucol_countAvailable();
         for (int32_t i = 0; i < count; ++i) {
-            String locale = convertICULocaleToBCP47LanguageTag(udat_getAvailable(i));
+            String locale = convertICULocaleToBCP47LanguageTag(ucol_getAvailable(i));
             if (!locale.isEmpty())
                 availableLocales.add(locale);
         }
@@ -202,25 +212,6 @@
     return availableLocales;
 }
 
-const HashSet<String>& intlNumberFormatAvailableLocales()
-{
-    static NeverDestroyed<HashSet<String>> cachedAvailableLocales;
-    HashSet<String>& availableLocales = cachedAvailableLocales.get();
-
-    static std::once_flag initializeOnce;
-    std::call_once(initializeOnce, [&] {
-        ASSERT(availableLocales.isEmpty());
-        int32_t count = unum_countAvailable();
-        for (int32_t i = 0; i < count; ++i) {
-            String locale = convertICULocaleToBCP47LanguageTag(unum_getAvailable(i));
-            if (!locale.isEmpty())
-                availableLocales.add(locale);
-        }
-        addMissingScriptLocales(availableLocales);
-    });
-    return availableLocales;
-}
-
 bool intlBooleanOption(JSGlobalObject* globalObject, JSValue options, PropertyName property, bool& usesFallback)
 {
     // GetOption (options, property, type="boolean", values, fallback)
@@ -328,13 +319,15 @@
 {
     ASSERT(!string.isNull());
 
-    auto length = string.length();
-    if (length < 3 || length > 8)
-        return false;
+    for (auto part : string.splitAllowingEmptyEntries('-')) {
+        auto length = part.length();
+        if (length < 3 || length > 8)
+            return false;
 
-    for (auto character : string.codeUnits()) {
-        if (!isASCIIAlphanumeric(character))
-            return false;
+        for (auto character : part.codeUnits()) {
+            if (!isASCIIAlphanumeric(character))
+                return false;
+        }
     }
 
     return true;
@@ -979,8 +972,6 @@
     RETURN_IF_EXCEPTION(scope, JSValue());
 
     PropertyDescriptor desc;
-    desc.setConfigurable(false);
-    desc.setWritable(false);
 
     size_t len = keys.size();
     for (size_t i = 0; i < len; ++i) {

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.h (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2015 Andy VanWagoner ([email protected])
  * Copyright (C) 2019-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,7 +44,7 @@
         return &vm.plainObjectSpace;
     }
 
-    static IntlObject* create(VM&, Structure*);
+    static IntlObject* create(VM&, JSGlobalObject*, Structure*);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_INFO;
@@ -50,13 +51,16 @@
 
 private:
     IntlObject(VM&, Structure*);
+    void finishCreation(VM&, JSGlobalObject*);
 };
 
 String defaultLocale(JSGlobalObject*);
+const HashSet<String>& intlAvailableLocales();
 const HashSet<String>& intlCollatorAvailableLocales();
-const HashSet<String>& intlDateTimeFormatAvailableLocales();
-const HashSet<String>& intlNumberFormatAvailableLocales();
-inline const HashSet<String>& intlPluralRulesAvailableLocales() { return intlNumberFormatAvailableLocales(); }
+inline const HashSet<String>& intlDateTimeFormatAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlNumberFormatAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlPluralRulesAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlRelativeTimeFormatAvailableLocales() { return intlAvailableLocales(); }
 
 bool intlBooleanOption(JSGlobalObject*, JSValue options, PropertyName, bool& usesFallback);
 String intlStringOption(JSGlobalObject*, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback);

Modified: trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -127,7 +127,7 @@
         return;
     }
 
-    String typeString = intlStringOption(globalObject, options, Identifier::fromString(vm, "type"), { "cardinal", "ordinal" }, "type must be \"cardinal\" or \"ordinal\"", "cardinal");
+    String typeString = intlStringOption(globalObject, options, vm.propertyNames->type, { "cardinal", "ordinal" }, "type must be \"cardinal\" or \"ordinal\"", "cardinal");
     RETURN_IF_EXCEPTION(scope, void());
     m_type = typeString == "ordinal" ? UPLURAL_TYPE_ORDINAL : UPLURAL_TYPE_CARDINAL;
 
@@ -201,7 +201,7 @@
 
     JSObject* options = constructEmptyObject(globalObject);
     options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale));
-    options->putDirect(vm, Identifier::fromString(vm, "type"), jsNontrivialString(vm, m_type == UPLURAL_TYPE_ORDINAL ? "ordinal"_s : "cardinal"_s));
+    options->putDirect(vm, vm.propertyNames->type, jsNontrivialString(vm, m_type == UPLURAL_TYPE_ORDINAL ? "ordinal"_s : "cardinal"_s));
     options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
     options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
     options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));

Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp (0 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntlRelativeTimeFormat.h"
+
+#include "Error.h"
+#include "IntlNumberFormat.h"
+#include "IntlObject.h"
+#include "JSCInlines.h"
+#include "ObjectConstructor.h"
+
+namespace JSC {
+
+const ClassInfo IntlRelativeTimeFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormat) };
+
+constexpr const char* relevantExtensionKeys[1] = { "nu" };
+
+struct UFieldPositionIteratorDeleter {
+    void operator()(UFieldPositionIterator* iterator) const
+    {
+        if (iterator)
+            ufieldpositer_close(iterator);
+    }
+};
+
+void IntlRelativeTimeFormat::URelativeDateTimeFormatterDeleter::operator()(URelativeDateTimeFormatter* relativeDateTimeFormatter) const
+{
+    if (relativeDateTimeFormatter)
+        ureldatefmt_close(relativeDateTimeFormatter);
+}
+
+void IntlRelativeTimeFormat::UNumberFormatDeleter::operator()(UNumberFormat* numberFormat) const
+{
+    if (numberFormat)
+        unum_close(numberFormat);
+}
+
+IntlRelativeTimeFormat* IntlRelativeTimeFormat::create(VM& vm, Structure* structure)
+{
+    auto* format = new (NotNull, allocateCell<IntlRelativeTimeFormat>(vm.heap)) IntlRelativeTimeFormat(vm, structure);
+    format->finishCreation(vm);
+    return format;
+}
+
+Structure* IntlRelativeTimeFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlRelativeTimeFormat::IntlRelativeTimeFormat(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void IntlRelativeTimeFormat::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(vm, info()));
+}
+
+void IntlRelativeTimeFormat::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    auto* thisObject = jsCast<IntlRelativeTimeFormat*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+    Base::visitChildren(thisObject, visitor);
+}
+
+static Vector<String> localeData(const String& locale, size_t keyIndex)
+{
+    // The index of the extension key "nu" in relevantExtensionKeys is 0.
+    ASSERT_UNUSED(keyIndex, !keyIndex);
+    return numberingSystemsForLocale(locale);
+}
+
+// https://tc39.es/ecma402/#sec-InitializeRelativeTimeFormat
+void IntlRelativeTimeFormat::initializeRelativeTimeFormat(JSGlobalObject* globalObject, JSValue locales, JSValue optionsValue)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Vector<String> requestedLocales = canonicalizeLocaleList(globalObject, locales);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    JSObject* options;
+    if (optionsValue.isUndefined())
+        options = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
+    else {
+        options = optionsValue.toObject(globalObject);
+        RETURN_IF_EXCEPTION(scope, void());
+    }
+
+    HashMap<String, String> opt;
+    String localeMatcher = intlStringOption(globalObject, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
+    RETURN_IF_EXCEPTION(scope, void());
+    opt.add(vm.propertyNames->localeMatcher.string(), localeMatcher);
+
+    String numberingSystem = intlStringOption(globalObject, options, vm.propertyNames->numberingSystem, { }, nullptr, nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!numberingSystem.isNull()) {
+        if (!isUnicodeLocaleIdentifierType(numberingSystem)) {
+            throwRangeError(globalObject, scope, "numberingSystem is not a well-formed numbering system value"_s);
+            return;
+        }
+        opt.add("nu"_s, numberingSystem);
+    }
+
+    const HashSet<String>& availableLocales = intlRelativeTimeFormatAvailableLocales();
+    HashMap<String, String> resolved = resolveLocale(globalObject, availableLocales, requestedLocales, opt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData);
+    m_locale = resolved.get(vm.propertyNames->locale.string());
+    if (m_locale.isEmpty()) {
+        throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat due to invalid locale"_s);
+        return;
+    }
+
+    m_numberingSystem = resolved.get("nu"_s);
+    CString dataLocaleWithExtensions = makeString(resolved.get("dataLocale"_s), "-u-nu-", m_numberingSystem).utf8();
+
+    String style = intlStringOption(globalObject, options, vm.propertyNames->style, { "long", "short", "narrow" }, "style must be either \"long\", \"short\", or \"narrow\"", "long");
+    RETURN_IF_EXCEPTION(scope, void());
+    if (style == "long")
+        m_style = UDAT_STYLE_LONG;
+    else if (style == "short")
+        m_style = UDAT_STYLE_SHORT;
+    else if (style == "narrow")
+        m_style = UDAT_STYLE_NARROW;
+    else
+        ASSERT_NOT_REACHED();
+
+    String numeric = intlStringOption(globalObject, options, vm.propertyNames->numeric, { "always", "auto" }, "numeric must be either \"always\" or \"auto\"", "always");
+    RETURN_IF_EXCEPTION(scope, void());
+    m_numeric = (numeric == "always");
+
+    UErrorCode status = U_ZERO_ERROR;
+    m_numberFormat = std::unique_ptr<UNumberFormat, UNumberFormatDeleter>(unum_open(UNUM_DECIMAL, nullptr, 0, dataLocaleWithExtensions.data(), nullptr, &status));
+    if (UNLIKELY(U_FAILURE(status))) {
+        throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat"_s);
+        return;
+    }
+
+    m_relativeDateTimeFormatter = std::unique_ptr<URelativeDateTimeFormatter, URelativeDateTimeFormatterDeleter>(ureldatefmt_open(dataLocaleWithExtensions.data(), m_numberFormat.get(), m_style, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status));
+    if (UNLIKELY(U_FAILURE(status))) {
+        throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat"_s);
+        return;
+    }
+}
+
+static ASCIILiteral styleString(UDateRelativeDateTimeFormatterStyle style)
+{
+    switch (style) {
+    case UDAT_STYLE_LONG:
+        return "long"_s;
+    case UDAT_STYLE_SHORT:
+        return "short"_s;
+    case UDAT_STYLE_NARROW:
+        return "narrow"_s;
+    }
+    ASSERT_NOT_REACHED();
+    return ASCIILiteral::null();
+}
+
+static ASCIILiteral numericString(bool numeric)
+{
+    return numeric ? "always"_s : "auto"_s;
+}
+
+// https://tc39.es/ecma402/#sec-intl.relativetimeformat.prototype.resolvedoptions
+JSObject* IntlRelativeTimeFormat::resolvedOptions(JSGlobalObject* globalObject)
+{
+    VM& vm = globalObject->vm();
+    JSObject* options = constructEmptyObject(globalObject);
+    options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale));
+    options->putDirect(vm, vm.propertyNames->style, jsNontrivialString(vm, styleString(m_style)));
+    options->putDirect(vm, vm.propertyNames->numeric, jsNontrivialString(vm, numericString(m_numeric)));
+    options->putDirect(vm, vm.propertyNames->numberingSystem, jsNontrivialString(vm, m_numberingSystem));
+    return options;
+}
+
+static StringView singularUnit(StringView unit)
+{
+    // Plurals are allowed, but thankfully they're all just a simple -s.
+    return unit.endsWith("s") ? unit.left(unit.length() - 1) : unit;
+}
+
+// https://tc39.es/ecma402/#sec-singularrelativetimeunit
+static Optional<URelativeDateTimeUnit> relativeTimeUnitType(StringView unit)
+{
+    StringView singular = singularUnit(unit);
+
+    if (singular == "second")
+        return UDAT_REL_UNIT_SECOND;
+    if (singular == "minute")
+        return UDAT_REL_UNIT_MINUTE;
+    if (singular == "hour")
+        return UDAT_REL_UNIT_HOUR;
+    if (singular == "day")
+        return UDAT_REL_UNIT_DAY;
+    if (singular == "week")
+        return UDAT_REL_UNIT_WEEK;
+    if (singular == "month")
+        return UDAT_REL_UNIT_MONTH;
+    if (singular == "quarter")
+        return UDAT_REL_UNIT_QUARTER;
+    if (singular == "year")
+        return UDAT_REL_UNIT_YEAR;
+
+    return WTF::nullopt;
+}
+
+String IntlRelativeTimeFormat::formatInternal(JSGlobalObject* globalObject, double value, StringView unit)
+{
+    ASSERT(m_relativeDateTimeFormatter);
+
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (!std::isfinite(value)) {
+        throwRangeError(globalObject, scope, "number argument must be finite"_s);
+        return String();
+    }
+
+    auto unitType = relativeTimeUnitType(unit);
+    if (!unitType) {
+        throwRangeError(globalObject, scope, "unit argument is not a recognized unit type"_s);
+        return String();
+    }
+
+    auto formatRelativeTime = m_numeric ? ureldatefmt_formatNumeric : ureldatefmt_format;
+
+    UErrorCode status = U_ZERO_ERROR;
+    Vector<UChar, 32> result(32);
+    auto resultLength = formatRelativeTime(m_relativeDateTimeFormatter.get(), value, unitType.value(), result.data(), result.size(), &status);
+    if (status == U_BUFFER_OVERFLOW_ERROR) {
+        status = U_ZERO_ERROR;
+        result.grow(resultLength);
+        formatRelativeTime(m_relativeDateTimeFormatter.get(), value, unitType.value(), result.data(), resultLength, &status);
+    }
+    if (UNLIKELY(U_FAILURE(status))) {
+        throwTypeError(globalObject, scope, "failed to format relative time"_s);
+        return String();
+    }
+
+    return String(result.data(), resultLength);
+}
+
+// https://tc39.es/ecma402/#sec-FormatRelativeTime
+JSValue IntlRelativeTimeFormat::format(JSGlobalObject* globalObject, double value, StringView unit)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String result = formatInternal(globalObject, value, unit);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    return jsString(vm, result);
+}
+
+// https://tc39.es/ecma402/#sec-FormatRelativeTimeToParts
+JSValue IntlRelativeTimeFormat::formatToParts(JSGlobalObject* globalObject, double value, StringView unit)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String formattedRelativeTime = formatInternal(globalObject, value, unit);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    UErrorCode status = U_ZERO_ERROR;
+    auto iterator = std::unique_ptr<UFieldPositionIterator, UFieldPositionIteratorDeleter>(ufieldpositer_open(&status));
+    ASSERT(U_SUCCESS(status));
+
+    double absValue = std::abs(value);
+
+    Vector<UChar, 32> buffer(32);
+    auto numberLength = unum_formatDoubleForFields(m_numberFormat.get(), absValue, buffer.data(), buffer.size(), iterator.get(), &status);
+    if (status == U_BUFFER_OVERFLOW_ERROR) {
+        status = U_ZERO_ERROR;
+        buffer.grow(numberLength);
+        unum_formatDoubleForFields(m_numberFormat.get(), absValue, buffer.data(), numberLength, iterator.get(), &status);
+    }
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format relative time"_s);
+
+    auto formattedNumber = String(buffer.data(), numberLength);
+
+    JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
+    if (!parts)
+        return throwOutOfMemoryError(globalObject, scope);
+
+    JSString* literalString = jsNontrivialString(vm, "literal"_s);
+
+    // We only have one input number, so our relative time will have at most one numeric substring,
+    // but we need to list all of the numeric parts separately.
+    size_t numberEnd = 0;
+    size_t numberStart = formattedRelativeTime.find(formattedNumber);
+    if (numberStart != notFound) {
+        numberEnd = numberStart + numberLength;
+
+        // Add initial literal if there is one.
+        if (numberStart) {
+            JSObject* part = constructEmptyObject(globalObject);
+            part->putDirect(vm, vm.propertyNames->type, literalString);
+            part->putDirect(vm, vm.propertyNames->value, jsSubstring(vm, formattedRelativeTime, 0, numberStart));
+            parts->push(globalObject, part);
+            RETURN_IF_EXCEPTION(scope, { });
+        }
+
+        IntlNumberFormat::formatToPartsInternal(globalObject, absValue, formattedNumber, iterator.get(), parts, jsString(vm, singularUnit(unit).toString()));
+        RETURN_IF_EXCEPTION(scope, { });
+    }
+
+    // Add final literal if there is one.
+    auto stringLength = formattedRelativeTime.length();
+    if (numberEnd != stringLength) {
+        JSObject* part = constructEmptyObject(globalObject);
+        part->putDirect(vm, vm.propertyNames->type, literalString);
+        part->putDirect(vm, vm.propertyNames->value, jsSubstring(vm, formattedRelativeTime, numberEnd, stringLength - numberEnd));
+        parts->push(globalObject, part);
+        RETURN_IF_EXCEPTION(scope, { });
+    }
+
+    return parts;
+}
+
+} // namespace JSC

Copied: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h (from rev 260348, trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h) (0 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSObject.h"
+#include <unicode/ufieldpositer.h>
+#include <unicode/ureldatefmt.h>
+
+namespace JSC {
+
+class IntlRelativeTimeFormat final : public JSNonFinalObject {
+public:
+    using Base = JSNonFinalObject;
+
+    static constexpr bool needsDestruction = true;
+
+    static void destroy(JSCell* cell)
+    {
+        static_cast<IntlRelativeTimeFormat*>(cell)->IntlRelativeTimeFormat::~IntlRelativeTimeFormat();
+    }
+
+    template<typename CellType, SubspaceAccess mode>
+    static IsoSubspace* subspaceFor(VM& vm)
+    {
+        return vm.intlRelativeTimeFormatSpace<mode>();
+    }
+
+    static IntlRelativeTimeFormat* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+    void initializeRelativeTimeFormat(JSGlobalObject*, JSValue locales, JSValue options);
+    JSValue format(JSGlobalObject*, double, StringView unitString);
+    JSValue formatToParts(JSGlobalObject*, double, StringView unitString);
+    JSObject* resolvedOptions(JSGlobalObject*);
+
+private:
+    IntlRelativeTimeFormat(VM&, Structure*);
+    void finishCreation(VM&);
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    String formatInternal(JSGlobalObject*, double, StringView unit);
+
+    struct URelativeDateTimeFormatterDeleter {
+        void operator()(URelativeDateTimeFormatter*) const;
+    };
+    struct UNumberFormatDeleter {
+        void operator()(UNumberFormat*) const;
+    };
+
+    std::unique_ptr<URelativeDateTimeFormatter, URelativeDateTimeFormatterDeleter> m_relativeDateTimeFormatter;
+    std::unique_ptr<UNumberFormat, UNumberFormatDeleter> m_numberFormat;
+
+    String m_locale;
+    String m_numberingSystem;
+    UDateRelativeDateTimeFormatterStyle m_style { UDAT_STYLE_LONG };
+    bool m_numeric { true };
+};
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.cpp (0 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntlRelativeTimeFormatConstructor.h"
+
+#include "Error.h"
+#include "IntlObject.h"
+#include "IntlRelativeTimeFormat.h"
+#include "IntlRelativeTimeFormatPrototype.h"
+#include "JSCInlines.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlRelativeTimeFormatConstructor);
+
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatConstructorFuncSupportedLocalesOf(JSGlobalObject*, CallFrame*);
+
+}
+
+#include "IntlRelativeTimeFormatConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlRelativeTimeFormatConstructor::s_info = { "Function", &InternalFunction::s_info, &relativeTimeFormatConstructorTable, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormatConstructor) };
+
+/* Source for IntlRelativeTimeFormatConstructor.lut.h
+@begin relativeTimeFormatConstructorTable
+  supportedLocalesOf             IntlRelativeTimeFormatConstructorFuncSupportedLocalesOf             DontEnum|Function 1
+@end
+*/
+
+IntlRelativeTimeFormatConstructor* IntlRelativeTimeFormatConstructor::create(VM& vm, Structure* structure, IntlRelativeTimeFormatPrototype* relativeTimeFormatPrototype)
+{
+    auto* constructor = new (NotNull, allocateCell<IntlRelativeTimeFormatConstructor>(vm.heap)) IntlRelativeTimeFormatConstructor(vm, structure);
+    constructor->finishCreation(vm, relativeTimeFormatPrototype);
+    return constructor;
+}
+
+Structure* IntlRelativeTimeFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlRelativeTimeFormat(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL constructIntlRelativeTimeFormat(JSGlobalObject*, CallFrame*);
+
+IntlRelativeTimeFormatConstructor::IntlRelativeTimeFormatConstructor(VM& vm, Structure* structure)
+    : Base(vm, structure, callIntlRelativeTimeFormat, constructIntlRelativeTimeFormat)
+{
+}
+
+void IntlRelativeTimeFormatConstructor::finishCreation(VM& vm, IntlRelativeTimeFormatPrototype* relativeTimeFormatPrototype)
+{
+    Base::finishCreation(vm, "RelativeTimeFormat"_s, NameAdditionMode::WithoutStructureTransition);
+    putDirectWithoutTransition(vm, vm.propertyNames->prototype, relativeTimeFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
+    relativeTimeFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
+static EncodedJSValue JSC_HOST_CALL constructIntlRelativeTimeFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    Structure* structure = InternalFunction::createSubclassStructure(globalObject, callFrame->jsCallee(), callFrame->newTarget(), jsCast<IntlRelativeTimeFormatConstructor*>(callFrame->jsCallee())->relativeTimeFormatStructure(vm));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    IntlRelativeTimeFormat* relativeTimeFormat = IntlRelativeTimeFormat::create(vm, structure);
+    ASSERT(relativeTimeFormat);
+
+    scope.release();
+    relativeTimeFormat->initializeRelativeTimeFormat(globalObject, callFrame->argument(0), callFrame->argument(1));
+    return JSValue::encode(relativeTimeFormat);
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
+static EncodedJSValue JSC_HOST_CALL callIntlRelativeTimeFormat(JSGlobalObject* globalObject, CallFrame*)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "RelativeTimeFormat"));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.supportedLocalesOf
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatConstructorFuncSupportedLocalesOf(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto& availableLocales = intlRelativeTimeFormatAvailableLocales();
+
+    auto requestedLocales = canonicalizeLocaleList(globalObject, callFrame->argument(0));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(supportedLocales(globalObject, availableLocales, requestedLocales, callFrame->argument(1))));
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.h (0 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "InternalFunction.h"
+#include "IntlObject.h"
+
+namespace JSC {
+
+class IntlRelativeTimeFormatPrototype;
+
+class IntlRelativeTimeFormatConstructor final : public InternalFunction {
+public:
+    using Base = InternalFunction;
+    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+    static IntlRelativeTimeFormatConstructor* create(VM&, Structure*, IntlRelativeTimeFormatPrototype*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+    Structure* relativeTimeFormatStructure(VM&) const { return globalObject()->relativeTimeFormatStructure(); }
+
+protected:
+    void finishCreation(VM&, IntlRelativeTimeFormatPrototype*);
+
+private:
+    IntlRelativeTimeFormatConstructor(VM&, Structure*);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlRelativeTimeFormatConstructor, InternalFunction);
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.cpp (0 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntlRelativeTimeFormatPrototype.h"
+
+#include "Error.h"
+#include "IntlRelativeTimeFormat.h"
+#include "JSCInlines.h"
+#include "JSObjectInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormat(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormatToParts(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncResolvedOptions(JSGlobalObject*, CallFrame*);
+
+}
+
+#include "IntlRelativeTimeFormatPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlRelativeTimeFormatPrototype::s_info = { "Object", &Base::s_info, &relativeTimeFormatPrototypeTable, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormatPrototype) };
+
+/* Source for IntlRelativeTimeFormatPrototype.lut.h
+@begin relativeTimeFormatPrototypeTable
+  format           IntlRelativeTimeFormatPrototypeFuncFormat           DontEnum|Function 2
+  formatToParts    IntlRelativeTimeFormatPrototypeFuncFormatToParts    DontEnum|Function 2
+  resolvedOptions  IntlRelativeTimeFormatPrototypeFuncResolvedOptions  DontEnum|Function 0
+@end
+*/
+
+IntlRelativeTimeFormatPrototype* IntlRelativeTimeFormatPrototype::create(VM& vm, Structure* structure)
+{
+    auto* object = new (NotNull, allocateCell<IntlRelativeTimeFormatPrototype>(vm.heap)) IntlRelativeTimeFormatPrototype(vm, structure);
+    object->finishCreation(vm);
+    return object;
+}
+
+Structure* IntlRelativeTimeFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlRelativeTimeFormatPrototype::IntlRelativeTimeFormatPrototype(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void IntlRelativeTimeFormatPrototype::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsNontrivialString(vm, "Intl.RelativeTimeFormat"_s), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype.format
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* relativeTimeFormat = jsDynamicCast<IntlRelativeTimeFormat*>(vm, callFrame->thisValue());
+    if (!relativeTimeFormat)
+        return JSValue::encode(throwTypeError(globalObject, scope, "Intl.RelativeTimeFormat.prototype.format called on value that's not an object initialized as a RelativeTimeFormat"_s));
+
+    double value = callFrame->argument(0).toNumber(globalObject);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    String unit = callFrame->argument(1).toWTFString(globalObject);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(relativeTimeFormat->format(globalObject, value, unit)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype.formatToParts
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormatToParts(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* relativeTimeFormat = jsDynamicCast<IntlRelativeTimeFormat*>(vm, callFrame->thisValue());
+    if (!relativeTimeFormat)
+        return JSValue::encode(throwTypeError(globalObject, scope, "Intl.RelativeTimeFormat.prototype.formatToParts called on value that's not an object initialized as a RelativeTimeFormat"_s));
+
+    double value = callFrame->argument(0).toNumber(globalObject);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    String unit = callFrame->argument(1).toWTFString(globalObject);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(relativeTimeFormat->formatToParts(globalObject, value, unit)));
+}
+
+// https://tc39.es/ecma402/#sec-intl.relativetimeformat.prototype.resolvedoptions
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncResolvedOptions(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* relativeTimeFormat = jsDynamicCast<IntlRelativeTimeFormat*>(vm, callFrame->thisValue());
+    if (!relativeTimeFormat)
+        return JSValue::encode(throwTypeError(globalObject, scope, "Intl.RelativeTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a RelativeTimeFormat"_s));
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(relativeTimeFormat->resolvedOptions(globalObject)));
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.h (0 => 260349)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class IntlRelativeTimeFormatPrototype final : public JSNonFinalObject {
+public:
+    using Base = JSNonFinalObject;
+    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+    template<typename CellType, SubspaceAccess>
+    static IsoSubspace* subspaceFor(VM& vm)
+    {
+        STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlRelativeTimeFormatPrototype, Base);
+        return &vm.plainObjectSpace;
+    }
+
+    static IntlRelativeTimeFormatPrototype* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+protected:
+    void finishCreation(VM&);
+
+private:
+    IntlRelativeTimeFormatPrototype(VM&, Structure*);
+};
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -86,6 +86,8 @@
 #include "IntlObject.h"
 #include "IntlPluralRules.h"
 #include "IntlPluralRulesPrototype.h"
+#include "IntlRelativeTimeFormat.h"
+#include "IntlRelativeTimeFormatPrototype.h"
 #include "IteratorPrototype.h"
 #include "JSAPIWrapperObject.h"
 #include "JSArrayBuffer.h"
@@ -959,6 +961,12 @@
             IntlPluralRulesPrototype* pluralRulesPrototype = IntlPluralRulesPrototype::create(init.vm, globalObject, IntlPluralRulesPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
             init.set(IntlPluralRules::createStructure(init.vm, globalObject, pluralRulesPrototype));
         });
+    m_relativeTimeFormatStructure.initLater(
+        [] (const Initializer<Structure>& init) {
+            JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+            IntlRelativeTimeFormatPrototype* relativeTimeFormatPrototype = IntlRelativeTimeFormatPrototype::create(init.vm, IntlRelativeTimeFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+            init.set(IntlRelativeTimeFormat::createStructure(init.vm, globalObject, relativeTimeFormatPrototype));
+        });
     m_defaultCollator.initLater(
         [] (const Initializer<IntlCollator>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -970,7 +978,7 @@
             init.set(collator);
         });
 
-    IntlObject* intl = IntlObject::create(vm, IntlObject::createStructure(vm, this, m_objectPrototype.get()));
+    IntlObject* intl = IntlObject::create(vm, this, IntlObject::createStructure(vm, this, m_objectPrototype.get()));
     putDirectWithoutTransition(vm, vm.propertyNames->Intl, intl, static_cast<unsigned>(PropertyAttribute::DontEnum));
 
     m_moduleLoader.initLater(
@@ -1769,6 +1777,7 @@
     thisObject->m_numberFormatStructure.visit(visitor);
     thisObject->m_dateTimeFormatStructure.visit(visitor);
     thisObject->m_pluralRulesStructure.visit(visitor);
+    thisObject->m_relativeTimeFormatStructure.visit(visitor);
 
     visitor.append(thisObject->m_nullGetterFunction);
     visitor.append(thisObject->m_nullSetterFunction);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -294,6 +294,7 @@
     LazyProperty<JSGlobalObject, Structure> m_numberFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_pluralRulesStructure;
+    LazyProperty<JSGlobalObject, Structure> m_relativeTimeFormatStructure;
 
     WriteBarrier<NullGetterFunction> m_nullGetterFunction;
     WriteBarrier<NullSetterFunction> m_nullSetterFunction;
@@ -788,6 +789,7 @@
     Structure* numberFormatStructure() { return m_numberFormatStructure.get(this); }
     Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
     Structure* pluralRulesStructure() { return m_pluralRulesStructure.get(this); }
+    Structure* relativeTimeFormatStructure() { return m_relativeTimeFormatStructure.get(this); }
 
     JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);
     JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const;

Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/OptionsList.h	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -484,6 +484,7 @@
     v(Bool, useWebAssemblyMultiValues, true, Normal, "Allow types from the wasm mulit-values spec.") \
     v(Bool, useWeakRefs, false, Normal, "Expose the WeakRef constructor.") \
     v(Bool, useBigInt, true, Normal, "If true, we will enable BigInt support.") \
+    v(Bool, useIntlRelativeTimeFormat, false, Normal, "Expose the Intl.RelativeTimeFormat constructor.") \
     v(Bool, useArrayAllocationProfiling, true, Normal, "If true, we will use our normal array allocation profiling. If false, the allocation profile will always claim to be undecided.") \
     v(Bool, forcePolyProto, false, Normal, "If true, create_this will always create an object with a poly proto structure.") \
     v(Bool, forceMiniVMMode, false, Normal, "If true, it will force mini VM mode on.") \

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -77,6 +77,7 @@
 #include "IntlDateTimeFormat.h"
 #include "IntlNumberFormat.h"
 #include "IntlPluralRules.h"
+#include "IntlRelativeTimeFormat.h"
 #include "IsoHeapCellType.h"
 #include "IsoInlinedHeapCellType.h"
 #include "JITCode.h"
@@ -340,6 +341,7 @@
     , intlDateTimeFormatHeapCellType(IsoHeapCellType::create<IntlDateTimeFormat>())
     , intlNumberFormatHeapCellType(IsoHeapCellType::create<IntlNumberFormat>())
     , intlPluralRulesHeapCellType(IsoHeapCellType::create<IntlPluralRules>())
+    , intlRelativeTimeFormatHeapCellType(IsoHeapCellType::create<IntlRelativeTimeFormat>())
 #if ENABLE(WEBASSEMBLY)
     , webAssemblyCodeBlockHeapCellType(IsoHeapCellType::create<JSWebAssemblyCodeBlock>())
     , webAssemblyFunctionHeapCellType(IsoHeapCellType::create<WebAssemblyFunction>())
@@ -1511,6 +1513,7 @@
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlDateTimeFormatSpace, intlDateTimeFormatHeapCellType.get(), IntlDateTimeFormat)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlNumberFormatSpace, intlNumberFormatHeapCellType.get(), IntlNumberFormat)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlPluralRulesSpace, intlPluralRulesHeapCellType.get(), IntlPluralRules)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlRelativeTimeFormatSpace, intlRelativeTimeFormatHeapCellType.get(), IntlRelativeTimeFormat)
 #if ENABLE(WEBASSEMBLY)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(jsToWasmICCalleeSpace, cellHeapCellType.get(), JSToWasmICCallee)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(webAssemblyCodeBlockSpace, webAssemblyCodeBlockHeapCellType.get(), JSWebAssemblyCodeBlock) // Hash:0x9ad995cd

Modified: trunk/Source/_javascript_Core/runtime/VM.h (260348 => 260349)


--- trunk/Source/_javascript_Core/runtime/VM.h	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2020-04-20 05:15:35 UTC (rev 260349)
@@ -128,6 +128,7 @@
 class IntlDateTimeFormat;
 class IntlNumberFormat;
 class IntlPluralRules;
+class IntlRelativeTimeFormat;
 class JSAPIGlobalObject;
 class JSAPIWrapperGlobalObject;
 class JSAPIWrapperObject;
@@ -401,6 +402,7 @@
     std::unique_ptr<IsoHeapCellType> intlDateTimeFormatHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlNumberFormatHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlPluralRulesHeapCellType;
+    std::unique_ptr<IsoHeapCellType> intlRelativeTimeFormatHeapCellType;
 #if ENABLE(WEBASSEMBLY)
     std::unique_ptr<IsoHeapCellType> webAssemblyCodeBlockHeapCellType;
     std::unique_ptr<IsoHeapCellType> webAssemblyFunctionHeapCellType;
@@ -557,6 +559,7 @@
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlDateTimeFormatSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlNumberFormatSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlPluralRulesSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlRelativeTimeFormatSpace)
 #if ENABLE(WEBASSEMBLY)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(jsToWasmICCalleeSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(webAssemblyCodeBlockSpace)

Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (260348 => 260349)


--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2020-04-20 05:15:35 UTC (rev 260349)
@@ -53,6 +53,7 @@
 #include "TypeProfilerLog.h"
 #include "VMInspector.h"
 #include "WasmCapabilities.h"
+#include <unicode/uversion.h>
 #include <wtf/Atomics.h>
 #include <wtf/CPUTime.h>
 #include <wtf/DataLog.h>
@@ -2977,6 +2978,13 @@
     return JSValue::encode(jsUndefined());
 }
 
+static EncodedJSValue JSC_HOST_CALL functionICUVersion(JSGlobalObject*, CallFrame*)
+{
+    UVersionInfo versionInfo;
+    u_getVersion(versionInfo);
+    return JSValue::encode(jsNumber(versionInfo[0]));
+}
+
 void JSDollarVM::finishCreation(VM& vm)
 {
     DollarVMAssertScope assertScope;
@@ -3114,6 +3122,7 @@
     addFunction(vm, "rejectPromiseAsHandled", functionRejectPromiseAsHandled, 1);
 
     addFunction(vm, "setUserPreferredLanguages", functionSetUserPreferredLanguages, 1);
+    addFunction(vm, "icuVersion", functionICUVersion, 0);
 
     m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure.set(vm, this, ObjectDoingSideEffectPutWithoutCorrectSlotStatus::createStructure(vm, globalObject, jsNull()));
 }

Modified: trunk/Tools/ChangeLog (260348 => 260349)


--- trunk/Tools/ChangeLog	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Tools/ChangeLog	2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,3 +1,13 @@
+2020-04-19  Ross Kirsling  <[email protected]>
+
+        [ECMA-402] Intl.RelativeTimeFormat missing in WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=209770
+
+        Reviewed by Darin Adler.
+
+        * Scripts/run-jsc-stress-tests:
+        Add runIntlRelativeTimeFormatEnabled.
+
 2020-04-19  Don Olmstead  <[email protected]>
 
         [CMake] Consolidate TestNetscapePlugin build

Modified: trunk/Tools/Scripts/run-jsc-stress-tests (260348 => 260349)


--- trunk/Tools/Scripts/run-jsc-stress-tests	2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Tools/Scripts/run-jsc-stress-tests	2020-04-20 05:15:35 UTC (rev 260349)
@@ -710,6 +710,10 @@
     run("big-int-enabled-baseline", "--useBigInt=true", "--useDFGJIT=0", *optionalTestSpecificOptions)
 end
 
+def runIntlRelativeTimeFormatEnabled(*optionalTestSpecificOptions)
+    run("intl-relativetimeformat-enabled", "--useIntlRelativeTimeFormat=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
+end
+
 def runFTLNoCJIT(*optionalTestSpecificOptions)
     run("misc-ftl-no-cjit", *(FTL_OPTIONS + NO_CJIT_OPTIONS + optionalTestSpecificOptions))
 end
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to