Title: [261215] trunk
Revision
261215
Author
ross.kirsl...@sony.com
Date
2020-05-05 23:01:07 -0700 (Tue, 05 May 2020)

Log Message

[ECMA-402] Implement Intl.Locale
https://bugs.webkit.org/show_bug.cgi?id=209772

Reviewed by Darin Adler and Saam Barati.

JSTests:

* stress/intl-locale.js: Added.
* stress/intl-locale-as-intl-param.js: Added.

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

* test262/expectations.yaml:
Mark known failures.
None of these should be specific to Intl.Locale.

Source/_javascript_Core:

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

This is effectively a wrapper class for all the pieces of uloc.h that ECMA-402 cares about.
(If we used the C++ API, there's a LocaleBuilder that would make this much easier, but in sticking to the C API,
it's basically an object that has an ICU localeID as data and uloc_* functions as methods / getters.
Furthermore, there's no way to modify said data, so every method / getter can be lazy and cache its result.)

Usage example:
  >>> locale = new Intl.Locale('ja', { region: 'JP', calendar: 'japanese', numeric: false })
  "ja-JP-u-ca-japanese-kn-false"
  >>> locale.baseName
  "ja-JP"

Intl.Locale can be used anywhere that Intl APIs accept locale strings as input parameters,
and is moreover hoped to be the class by which future Web APIs will handle the current locale.

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

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* _javascript_Core.xcodeproj/project.pbxproj:
* Sources.txt:
* runtime/CommonIdentifiers.h:
* runtime/IntlLocale.cpp: Added.
* runtime/IntlLocale.h: Added.
* runtime/IntlLocaleConstructor.cpp: Added.
* runtime/IntlLocaleConstructor.h: Added.
* runtime/IntlLocalePrototype.cpp: Added.
* runtime/IntlLocalePrototype.h: Added.
* runtime/IntlObject.cpp:
(JSC::IntlObject::finishCreation):
(JSC::localeIDBufferForLanguageTag): Added.
(JSC::languageTagForLocaleID): Renamed from JSC::convertICULocaleToBCP47LanguageTag.
(JSC::intlAvailableLocales):
(JSC::intlCollatorAvailableLocales):
(JSC::canonicalizeLanguageTag):
(JSC::canonicalizeLocaleList):
(JSC::defaultLocale):
* runtime/IntlObject.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::collatorStructure):
(JSC::JSGlobalObject::numberFormatStructure):
(JSC::JSGlobalObject::localeStructure):
* runtime/OptionsList.h:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:

Tools:

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

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (261214 => 261215)


--- trunk/JSTests/ChangeLog	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/JSTests/ChangeLog	2020-05-06 06:01:07 UTC (rev 261215)
@@ -1,3 +1,20 @@
+2020-05-05  Ross Kirsling  <ross.kirsl...@sony.com>
+
+        [ECMA-402] Implement Intl.Locale
+        https://bugs.webkit.org/show_bug.cgi?id=209772
+
+        Reviewed by Darin Adler and Saam Barati.
+
+        * stress/intl-locale.js: Added.
+        * stress/intl-locale-as-intl-param.js: Added.
+
+        * test262/config.yaml:
+        Enable Intl.Locale feature with flag.
+
+        * test262/expectations.yaml:
+        Mark known failures.
+        None of these should be specific to Intl.Locale.
+
 2020-05-05  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Implement BigInt.asIntN and BigInt.asUintN

Added: trunk/JSTests/stress/intl-locale-as-intl-param.js (0 => 261215)


--- trunk/JSTests/stress/intl-locale-as-intl-param.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-locale-as-intl-param.js	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,45 @@
+//@ runIntlLocaleEnabled("--useIntlRelativeTimeFormat=true")
+
+const tag = 'ja-Hant-KR-u-ca-buddhist-co-eor-hc-h11-kf-lower-kn-false-nu-thai';
+const locale = new Intl.Locale(tag);
+
+function shouldBeSameWithTagOrLocale(func) {
+    const actual = func(locale);
+    const expected = func(tag);
+    if (actual !== expected)
+        throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+shouldBeSameWithTagOrLocale(tagOrLocale => tagOrLocale.toString());
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.Locale(tagOrLocale).toString());
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.getCanonicalLocales(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.getCanonicalLocales(['en', tagOrLocale, 'fr'])));
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.Collator.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.Collator.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.Collator(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.DateTimeFormat.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.DateTimeFormat.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.DateTimeFormat(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.NumberFormat.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.NumberFormat.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.NumberFormat(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.PluralRules.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.PluralRules.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.PluralRules(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.RelativeTimeFormat(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => [3].toLocaleString(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 3n.toLocaleString(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Date(0).toLocaleString(tagOrLocale, { timeZone: 'UTC' }));
+shouldBeSameWithTagOrLocale(tagOrLocale => 3..toLocaleString(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 'ä'.localeCompare('a', tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 'Æ'.toLocaleLowerCase(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 'æ'.toLocaleUpperCase(tagOrLocale));

Added: trunk/JSTests/stress/intl-locale.js (0 => 261215)


--- trunk/JSTests/stress/intl-locale.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-locale.js	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,226 @@
+//@ runIntlLocaleEnabled
+
+function shouldBe(actual, expected) {
+    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.Locale instanceof Function, true);
+shouldBe(Intl.Locale.length, 1);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale, 'prototype').writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale, 'prototype').enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale, 'prototype').configurable, false);
+
+shouldThrow(() => Intl.Locale(), TypeError);
+shouldThrow(() => Intl.Locale.call({}), TypeError);
+
+shouldThrow(() => new Intl.Locale(), TypeError);
+shouldThrow(() => new Intl.Locale(5), TypeError);
+shouldThrow(() => new Intl.Locale(''), RangeError);
+shouldThrow(() => new Intl.Locale('a'), RangeError);
+shouldThrow(() => new Intl.Locale('abcdefghij'), RangeError);
+shouldThrow(() => new Intl.Locale('#$'), RangeError);
+shouldThrow(() => new Intl.Locale('en-@-abc'), RangeError);
+shouldThrow(() => new Intl.Locale('en-u'), RangeError);
+shouldThrow(() => new Intl.Locale('en-u-kn-true-u-ko-true'), RangeError);
+shouldThrow(() => new Intl.Locale('en-x'), RangeError);
+shouldThrow(() => new Intl.Locale('en-*'), RangeError);
+shouldThrow(() => new Intl.Locale('en-'), RangeError);
+shouldThrow(() => new Intl.Locale('en--US'), RangeError);
+shouldThrow(() => new Intl.Locale(['en', 'ja']), RangeError);
+shouldThrow(() => new Intl.Locale({}), RangeError);
+shouldThrow(() => new Intl.Locale({ toString() { throw new Error(); } }), Error);
+shouldNotThrow(() => new Intl.Locale({ toString() { return 'en'; } }));
+
+shouldThrow(() => new Intl.Locale('en', null), TypeError);
+
+shouldBe(new Intl.Locale('en') instanceof Intl.Locale, true);
+
+{
+    class DerivedLocale extends Intl.Locale {}
+
+    const dl = new DerivedLocale('en');
+    shouldBe(dl instanceof DerivedLocale, true);
+    shouldBe(dl instanceof Intl.Locale, true);
+    shouldBe(dl.maximize, Intl.Locale.prototype.maximize);
+    shouldBe(Object.getPrototypeOf(dl), DerivedLocale.prototype);
+    shouldBe(Object.getPrototypeOf(DerivedLocale.prototype), Intl.Locale.prototype);
+}
+
+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(() => new Intl.Locale(validLanguageTag));
+
+shouldBe(Object.getPrototypeOf(Intl.Locale.prototype), Object.prototype);
+
+shouldBe(Intl.Locale.prototype.constructor, Intl.Locale);
+
+shouldBe(Intl.Locale.prototype[Symbol.toStringTag], 'Intl.Locale');
+shouldBe(Object.prototype.toString.call(Intl.Locale.prototype), '[object Intl.Locale]');
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale.prototype, Symbol.toStringTag).writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale.prototype, Symbol.toStringTag).enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale.prototype, Symbol.toStringTag).configurable, true);
+
+shouldBe(Intl.Locale.prototype.maximize.length, 0);
+shouldBe(Intl.Locale.prototype.minimize.length, 0);
+shouldBe(Intl.Locale.prototype.toString.length, 0);
+shouldThrow(() => Intl.Locale.prototype.maximize.call({ toString() { return 'en'; } }), TypeError);
+shouldThrow(() => Intl.Locale.prototype.minimize.call({ toString() { return 'en'; } }), TypeError);
+shouldThrow(() => Intl.Locale.prototype.toString.call({ toString() { return 'en'; } }), TypeError);
+shouldThrow(() => Intl.Locale.prototype.baseName, TypeError);
+shouldThrow(() => Intl.Locale.prototype.calendar, TypeError);
+shouldThrow(() => Intl.Locale.prototype.caseFirst, TypeError);
+shouldThrow(() => Intl.Locale.prototype.collation, TypeError);
+shouldThrow(() => Intl.Locale.prototype.hourCycle, TypeError);
+shouldThrow(() => Intl.Locale.prototype.numeric, TypeError);
+shouldThrow(() => Intl.Locale.prototype.numberingSystem, TypeError);
+shouldThrow(() => Intl.Locale.prototype.language, TypeError);
+shouldThrow(() => Intl.Locale.prototype.script, TypeError);
+shouldThrow(() => Intl.Locale.prototype.region, TypeError);
+
+shouldBe(new Intl.Locale('en').maximize(), 'en-Latn-US');
+shouldBe(new Intl.Locale('en-Latn-US').maximize(), 'en-Latn-US');
+shouldBe(new Intl.Locale('en-u-nu-thai-x-foo').maximize(), 'en-Latn-US-u-nu-thai-x-foo');
+shouldBe(new Intl.Locale('ja').maximize(), 'ja-Jpan-JP');
+shouldBe(new Intl.Locale('zh').maximize(), 'zh-Hans-CN');
+shouldBe(new Intl.Locale('zh-Hant').maximize(), 'zh-Hant-TW');
+shouldBe(new Intl.Locale('zh', { script: 'Hant' }).maximize(), 'zh-Hant-TW');
+
+shouldBe(new Intl.Locale('en').minimize(), 'en');
+shouldBe(new Intl.Locale('en-Latn-US').minimize(), 'en');
+shouldBe(new Intl.Locale('en-Latn-US-u-nu-thai-x-foo').minimize(), 'en-u-nu-thai-x-foo');
+shouldBe(new Intl.Locale('ja-Jpan-JP').minimize(), 'ja');
+shouldBe(new Intl.Locale('zh-Hans-CN').minimize(), 'zh');
+shouldBe(new Intl.Locale('zh-Hant-TW').minimize(), 'zh-TW');
+shouldBe(new Intl.Locale('zh', { script: 'Hant', region: 'TW' }).minimize(), 'zh-TW');
+
+shouldBe(new Intl.Locale('en').toString(), 'en');
+shouldBe(new Intl.Locale('En-laTn-us-variAnt-fOObar-1abc-U-kn-tRue-A-aa-aaa-x-RESERVED').toString(), 'en-Latn-US-variant-foobar-1abc-a-aa-aaa-u-kn-true-x-reserved');
+shouldBe(new Intl.Locale('cel-gaulish', { script: 'Arab', numberingSystem: 'gujr' }).toString(), 'xtg-Arab-u-nu-gujr-x-cel-gaulish');
+shouldBe(new Intl.Locale('en-Latn-US-u-ca-gregory-co-phonebk-hc-h12-kf-upper-kn-nu-latn').toString(), 'en-Latn-US-u-ca-gregory-co-phonebk-hc-h12-kf-upper-kn-true-nu-latn');
+
+const options = {
+    calendar: 'buddhist',
+    caseFirst: 'lower',
+    collation: 'eor',
+    hourCycle: 'h11',
+    numeric: false,
+    numberingSystem: 'thai',
+    language: 'ja',
+    script: 'Hant',
+    region: 'KR'
+};
+const expected = 'ja-Hant-KR-u-ca-buddhist-co-eor-hc-h11-kf-lower-kn-false-nu-thai';
+shouldBe(new Intl.Locale('en', options).toString(), expected);
+shouldBe(new Intl.Locale('en-Latn-US-u-ca-gregory-co-phonebk-hc-h12-kf-upper-kn-nu-latn', options).toString(), expected);
+
+shouldBe(new Intl.Locale('en').baseName, 'en');
+shouldBe(new Intl.Locale('en-Latn').baseName, 'en-Latn');
+shouldBe(new Intl.Locale('en-US').baseName, 'en-US');
+shouldBe(new Intl.Locale('en-Latn-US').baseName, 'en-Latn-US');
+shouldBe(new Intl.Locale('en-variant-u-kn').baseName, 'en-variant');
+shouldBe(new Intl.Locale('en-Latn-variant-u-kn').baseName, 'en-Latn-variant');
+shouldBe(new Intl.Locale('en-variant-u-kn', { script: 'Latn' }).baseName, 'en-Latn-variant');
+shouldBe(new Intl.Locale('en-US-variant-u-kn').baseName, 'en-US-variant');
+shouldBe(new Intl.Locale('en-variant-u-kn', { region: 'US' }).baseName, 'en-US-variant');
+shouldBe(new Intl.Locale('en-Latn-US-variant-u-kn').baseName, 'en-Latn-US-variant');
+shouldBe(new Intl.Locale('en-variant-u-kn', { script: 'Latn', region: 'US' }).baseName, 'en-Latn-US-variant');
+
+shouldBe(new Intl.Locale('en').calendar, undefined);
+shouldBe(new Intl.Locale('en-u-ca-japanese').calendar, 'japanese');
+shouldBe(new Intl.Locale('en', { calendar: 'japanese' }).calendar, 'japanese');
+shouldBe(new Intl.Locale('en-u-ca-japanese', { calendar: 'dangi' }).calendar, 'dangi');
+shouldBe(new Intl.Locale('en-u-ca-islamicc').calendar, 'islamic-civil');
+shouldBe(new Intl.Locale('en', { calendar: 'islamicc' }).calendar, 'islamic-civil');
+shouldThrow(() => new Intl.Locale('en', { calendar: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { calendar: 'ng' }), RangeError);
+
+shouldBe(new Intl.Locale('en').collation, undefined);
+shouldBe(new Intl.Locale('en-u-co-phonebk').collation, 'phonebk');
+shouldBe(new Intl.Locale('en', { collation: 'phonebk' }).collation, 'phonebk');
+shouldBe(new Intl.Locale('en-u-co-phonebk', { collation: 'eor' }).collation, 'eor');
+shouldThrow(() => new Intl.Locale('en', { collation: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { collation: 'ng' }), RangeError);
+
+shouldBe(new Intl.Locale('en').caseFirst, undefined);
+shouldBe(new Intl.Locale('en-u-kf-upper').caseFirst, 'upper');
+shouldBe(new Intl.Locale('en', { caseFirst: 'upper' }).caseFirst, 'upper');
+shouldBe(new Intl.Locale('en-u-kf-upper', { caseFirst: 'lower' }).caseFirst, 'lower');
+shouldThrow(() => new Intl.Locale('en', { caseFirst: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { caseFirst: 'bad' }), RangeError);
+
+shouldBe(new Intl.Locale('en').numeric, false);
+shouldBe(new Intl.Locale('en-u-kn').numeric, true);
+shouldBe(new Intl.Locale('en-u-kn-true').numeric, true);
+shouldBe(new Intl.Locale('en', { numeric: true }).numeric, true);
+shouldBe(new Intl.Locale('en-u-kn', { numeric: false }).numeric, false);
+shouldBe(new Intl.Locale('en-u-kn-true', { numeric: false }).numeric, false);
+shouldThrow(() => new Intl.Locale('en', { get numeric() { throw new Error(); } }), Error);
+
+shouldBe(new Intl.Locale('en').hourCycle, undefined);
+shouldBe(new Intl.Locale('en-u-hc-h11').hourCycle, 'h11');
+shouldBe(new Intl.Locale('en', { hourCycle: 'h11' }).hourCycle, 'h11');
+shouldBe(new Intl.Locale('en-u-hc-h11', { hourCycle: 'h23' }).hourCycle, 'h23');
+shouldThrow(() => new Intl.Locale('en', { hourCycle: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { hourCycle: 'bad' }), RangeError);
+
+shouldBe(new Intl.Locale('en').numberingSystem, undefined);
+shouldBe(new Intl.Locale('en-u-nu-hanidec').numberingSystem, 'hanidec');
+shouldBe(new Intl.Locale('en', { numberingSystem: 'hanidec' }).numberingSystem, 'hanidec');
+shouldBe(new Intl.Locale('en-u-nu-hanidec', { numberingSystem: 'gujr' }).numberingSystem, 'gujr');
+shouldThrow(() => new Intl.Locale('en', { numberingSystem: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { numberingSystem: 'ng' }), RangeError);
+
+shouldBe(new Intl.Locale('en-Latn-US').language, 'en');
+shouldBe(new Intl.Locale('en', { language: 'ar' }).language, 'ar');
+shouldBe(new Intl.Locale('cel-gaulish').language, 'xtg');
+shouldThrow(() => new Intl.Locale('en', { language: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { language: 'fail' }), RangeError);
+
+shouldBe(new Intl.Locale('en-Latn-US').script, 'Latn');
+shouldBe(new Intl.Locale('en-US').script, undefined);
+shouldBe(new Intl.Locale('en-Latn', { script: 'Kore' }).script, 'Kore');
+shouldThrow(() => new Intl.Locale('en', { script: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { script: 'bad' }), RangeError);
+
+shouldBe(new Intl.Locale('en-Latn-US').region, 'US');
+shouldBe(new Intl.Locale('en-Latn').region, undefined);
+shouldBe(new Intl.Locale('en-US', { region: 'KR' }).region, 'KR');
+shouldThrow(() => new Intl.Locale('en', { region: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { region: 'fail' }), RangeError);

Modified: trunk/JSTests/test262/config.yaml (261214 => 261215)


--- trunk/JSTests/test262/config.yaml	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/JSTests/test262/config.yaml	2020-05-06 06:01:07 UTC (rev 261215)
@@ -2,6 +2,7 @@
 ---
 flags:
   BigInt: useBigInt
+  Intl.Locale: useIntlLocale
   Intl.RelativeTimeFormat: useIntlRelativeTimeFormat
   WeakRef: useWeakRefs
   class-fields-public: usePublicClassFields
@@ -30,7 +31,6 @@
     - Intl.DateTimeFormat-fractionalSecondDigits
     - Intl.DisplayNames
     - Intl.ListFormat
-    - Intl.Locale
     - Intl.NumberFormat-unified
     - Intl.Segmenter
   paths:

Modified: trunk/JSTests/test262/expectations.yaml (261214 => 261215)


--- trunk/JSTests/test262/expectations.yaml	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/JSTests/test262/expectations.yaml	2020-05-06 06:01:07 UTC (rev 261215)
@@ -1716,6 +1716,57 @@
 test/intl402/Intl/getCanonicalLocales/unicode-ext-key-with-digit.js:
   default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
   strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-apply-options-canonicalizes-twice.js:
+  default: 'Test262Error: Expected SameValue(«ru-Armn-SU», «ru-Armn-AM») to be true'
+  strict mode: 'Test262Error: Expected SameValue(«ru-Armn-SU», «ru-Armn-AM») to be true'
+test/intl402/Locale/constructor-non-iana-canon.js:
+  default: 'Test262Error: new Intl.Locale("mo").maximize().toString() returns "ro-Latn-RO" Expected SameValue(«ro», «ro-Latn-RO») to be true'
+  strict mode: 'Test262Error: new Intl.Locale("mo").maximize().toString() returns "ro-Latn-RO" Expected SameValue(«ro», «ro-Latn-RO») to be true'
+test/intl402/Locale/constructor-options-language-valid-undefined.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-options-language-valid.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-options-numeric-undefined.js:
+  default: 'Test262Error: new Intl.Locale("en-u-kn-true", {numeric: undefined}).toString() returns "en-u-kn" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+  strict mode: 'Test262Error: new Intl.Locale("en-u-kn-true", {numeric: undefined}).toString() returns "en-u-kn" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+test/intl402/Locale/constructor-options-numeric-valid.js:
+  default: 'Test262Error: new Intl.Locale("en", {numeric: true}).toString() returns "true" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+  strict mode: 'Test262Error: new Intl.Locale("en", {numeric: true}).toString() returns "true" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+test/intl402/Locale/constructor-options-region-valid.js:
+  default: "Test262Error: new Intl.Locale('en', {region: \"554\"}).toString() returns \"en-NZ\" Expected SameValue(«en-554», «en-NZ») to be true"
+  strict mode: "Test262Error: new Intl.Locale('en', {region: \"554\"}).toString() returns \"en-NZ\" Expected SameValue(«en-554», «en-NZ») to be true"
+test/intl402/Locale/constructor-parse-twice.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-tag.js:
+  default: 'Test262Error: new Intl.Locale("sl-ROZAJ-BISKE-1994").toString() returns "sl-1994-biske-rozaj" Expected SameValue(«sl-rozaj-biske-1994», «sl-1994-biske-rozaj») to be true'
+  strict mode: 'Test262Error: new Intl.Locale("sl-ROZAJ-BISKE-1994").toString() returns "sl-1994-biske-rozaj" Expected SameValue(«sl-rozaj-biske-1994», «sl-1994-biske-rozaj») to be true'
+test/intl402/Locale/extensions-grandfathered.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/extensions-private.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/getters-grandfathered.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/getters.js:
+  default: 'Test262Error: Expected SameValue(«de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-true-kn-false-nu-latn», «de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-kn-false-nu-latn») to be true'
+  strict mode: 'Test262Error: Expected SameValue(«de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-true-kn-false-nu-latn», «de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-kn-false-nu-latn») to be true'
+test/intl402/Locale/invalid-tag-throws.js:
+  default: 'Test262Error: no-nyn is an invalid tag value Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: no-nyn is an invalid tag value Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/likely-subtags-grandfathered.js:
+  default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+  strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/likely-subtags.js:
+  default: 'Test262Error: "en-u-co".maximize() should be "en-Latn-US-u-co" Expected SameValue(«en-Latn-US-u-co-yes», «en-Latn-US-u-co») to be true'
+  strict mode: 'Test262Error: "en-u-co".maximize() should be "en-Latn-US-u-co" Expected SameValue(«en-Latn-US-u-co-yes», «en-Latn-US-u-co») to be true'
+test/intl402/Locale/prototype/minimize/removing-likely-subtags-first-adds-likely-subtags.js:
+  default: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») to be true'
+  strict mode: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») 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'

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (261214 => 261215)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2020-05-06 06:01:07 UTC (rev 261215)
@@ -70,6 +70,7 @@
     runtime/IntlCollatorPrototype.cpp
     runtime/IntlDateTimeFormatConstructor.cpp
     runtime/IntlDateTimeFormatPrototype.cpp
+    runtime/IntlLocalePrototype.cpp
     runtime/IntlNumberFormatConstructor.cpp
     runtime/IntlNumberFormatPrototype.cpp
     runtime/IntlObject.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (261214 => 261215)


--- trunk/Source/_javascript_Core/ChangeLog	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-05-06 06:01:07 UTC (rev 261215)
@@ -1,3 +1,63 @@
+2020-05-05  Ross Kirsling  <ross.kirsl...@sony.com>
+
+        [ECMA-402] Implement Intl.Locale
+        https://bugs.webkit.org/show_bug.cgi?id=209772
+
+        Reviewed by Darin Adler and Saam Barati.
+
+        This patch implements the recent ECMA-402 feature Intl.Locale.
+
+        This is effectively a wrapper class for all the pieces of uloc.h that ECMA-402 cares about.
+        (If we used the C++ API, there's a LocaleBuilder that would make this much easier, but in sticking to the C API,
+        it's basically an object that has an ICU localeID as data and uloc_* functions as methods / getters.
+        Furthermore, there's no way to modify said data, so every method / getter can be lazy and cache its result.)
+
+        Usage example:
+          >>> locale = new Intl.Locale('ja', { region: 'JP', calendar: 'japanese', numeric: false })
+          "ja-JP-u-ca-japanese-kn-false"
+          >>> locale.baseName
+          "ja-JP"
+
+        Intl.Locale can be used anywhere that Intl APIs accept locale strings as input parameters,
+        and is moreover hoped to be the class by which future Web APIs will handle the current locale.
+
+        This feature is runtime-guarded by the `useIntlLocale` option.
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * runtime/CommonIdentifiers.h:
+        * runtime/IntlLocale.cpp: Added.
+        * runtime/IntlLocale.h: Added.
+        * runtime/IntlLocaleConstructor.cpp: Added.
+        * runtime/IntlLocaleConstructor.h: Added.
+        * runtime/IntlLocalePrototype.cpp: Added.
+        * runtime/IntlLocalePrototype.h: Added.
+        * runtime/IntlObject.cpp:
+        (JSC::IntlObject::finishCreation):
+        (JSC::localeIDBufferForLanguageTag): Added.
+        (JSC::languageTagForLocaleID): Renamed from JSC::convertICULocaleToBCP47LanguageTag.
+        (JSC::intlAvailableLocales):
+        (JSC::intlCollatorAvailableLocales):
+        (JSC::canonicalizeLanguageTag):
+        (JSC::canonicalizeLocaleList):
+        (JSC::defaultLocale):
+        * runtime/IntlObject.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::collatorStructure):
+        (JSC::JSGlobalObject::numberFormatStructure):
+        (JSC::JSGlobalObject::localeStructure):
+        * runtime/OptionsList.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+
 2020-05-05  Keith Miller  <keith_mil...@apple.com>
 
         clobberize validator should use branchTest8 directly.

Modified: trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist (261214 => 261215)


--- trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist	2020-05-06 06:01:07 UTC (rev 261215)
@@ -136,6 +136,7 @@
 $(PROJECT_DIR)/runtime/IntlCollatorPrototype.cpp
 $(PROJECT_DIR)/runtime/IntlDateTimeFormatConstructor.cpp
 $(PROJECT_DIR)/runtime/IntlDateTimeFormatPrototype.cpp
+$(PROJECT_DIR)/runtime/IntlLocalePrototype.cpp
 $(PROJECT_DIR)/runtime/IntlNumberFormatConstructor.cpp
 $(PROJECT_DIR)/runtime/IntlNumberFormatPrototype.cpp
 $(PROJECT_DIR)/runtime/IntlObject.cpp

Modified: trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist (261214 => 261215)


--- trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist	2020-05-06 06:01:07 UTC (rev 261215)
@@ -27,6 +27,7 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlCollatorPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDateTimeFormatConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDateTimeFormatPrototype.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlLocalePrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlNumberFormatConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlNumberFormatPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlObject.lut.h

Modified: trunk/Source/_javascript_Core/DerivedSources.make (261214 => 261215)


--- trunk/Source/_javascript_Core/DerivedSources.make	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/DerivedSources.make	2020-05-06 06:01:07 UTC (rev 261215)
@@ -147,6 +147,7 @@
     IntlCollatorPrototype.lut.h \
     IntlDateTimeFormatConstructor.lut.h \
     IntlDateTimeFormatPrototype.lut.h \
+    IntlLocalePrototype.lut.h \
     IntlNumberFormatConstructor.lut.h \
     IntlNumberFormatPrototype.lut.h \
     IntlObject.lut.h \

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (261214 => 261215)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-05-06 06:01:07 UTC (rev 261215)
@@ -4333,6 +4333,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>"; };
+		A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlLocale.h; sourceTree = "<group>"; };
+		A3AFF92C245A3CFA00C9BA3B /* IntlLocaleConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlLocaleConstructor.h; sourceTree = "<group>"; };
+		A3AFF92D245A3CFA00C9BA3B /* IntlLocale.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlLocale.cpp; sourceTree = "<group>"; };
+		A3AFF92E245A3CFB00C9BA3B /* IntlLocalePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlLocalePrototype.cpp; sourceTree = "<group>"; };
+		A3AFF92F245A3CFB00C9BA3B /* IntlLocaleConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlLocaleConstructor.cpp; sourceTree = "<group>"; };
+		A3AFF930245A3CFC00C9BA3B /* IntlLocalePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlLocalePrototype.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>"; };
@@ -7254,6 +7260,12 @@
 				A1587D6A1B4DC14100D69849 /* IntlDateTimeFormatConstructor.h */,
 				A1587D6B1B4DC14100D69849 /* IntlDateTimeFormatPrototype.cpp */,
 				A1587D6C1B4DC14100D69849 /* IntlDateTimeFormatPrototype.h */,
+				A3AFF92D245A3CFA00C9BA3B /* IntlLocale.cpp */,
+				A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */,
+				A3AFF92F245A3CFB00C9BA3B /* IntlLocaleConstructor.cpp */,
+				A3AFF92C245A3CFA00C9BA3B /* IntlLocaleConstructor.h */,
+				A3AFF92E245A3CFB00C9BA3B /* IntlLocalePrototype.cpp */,
+				A3AFF930245A3CFC00C9BA3B /* IntlLocalePrototype.h */,
 				A1D792F61B43864B004516F5 /* IntlNumberFormat.cpp */,
 				A1D792F71B43864B004516F5 /* IntlNumberFormat.h */,
 				A1D792F81B43864B004516F5 /* IntlNumberFormatConstructor.cpp */,

Modified: trunk/Source/_javascript_Core/Sources.txt (261214 => 261215)


--- trunk/Source/_javascript_Core/Sources.txt	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/Sources.txt	2020-05-06 06:01:07 UTC (rev 261215)
@@ -812,6 +812,9 @@
 runtime/IntlDateTimeFormat.cpp
 runtime/IntlDateTimeFormatConstructor.cpp
 runtime/IntlDateTimeFormatPrototype.cpp
+runtime/IntlLocale.cpp
+runtime/IntlLocaleConstructor.cpp
+runtime/IntlLocalePrototype.cpp
 runtime/IntlNumberFormat.cpp
 runtime/IntlNumberFormatConstructor.cpp
 runtime/IntlNumberFormatPrototype.cpp

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -40,6 +40,7 @@
     macro(Infinity) \
     macro(Intl) \
     macro(Loader) \
+    macro(Locale) \
     macro(Map) \
     macro(NaN) \
     macro(Number) \
@@ -137,6 +138,7 @@
     macro(isWatchpoint) \
     macro(jettisonReason) \
     macro(join) \
+    macro(language) \
     macro(lastIndex) \
     macro(length) \
     macro(line) \
@@ -166,8 +168,10 @@
     macro(propertyIsEnumerable) \
     macro(prototype) \
     macro(raw) \
+    macro(region) \
     macro(replace) \
     macro(resolve) \
+    macro(script) \
     macro(second) \
     macro(sensitivity) \
     macro(set) \

Added: trunk/Source/_javascript_Core/runtime/IntlLocale.cpp (0 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlLocale.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocale.cpp	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,491 @@
+/*
+ * 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 "IntlLocale.h"
+
+#include "Error.h"
+#include "IntlObject.h"
+#include "JSCInlines.h"
+#include "ObjectConstructor.h"
+#include <unicode/uloc.h>
+#include <wtf/unicode/icu/ICUHelpers.h>
+
+namespace JSC {
+
+const ClassInfo IntlLocale::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlLocale) };
+
+IntlLocale* IntlLocale::create(VM& vm, Structure* structure)
+{
+    auto* object = new (NotNull, allocateCell<IntlLocale>(vm.heap)) IntlLocale(vm, structure);
+    object->finishCreation(vm);
+    return object;
+}
+
+Structure* IntlLocale::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlLocale::IntlLocale(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void IntlLocale::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(vm, info()));
+}
+
+void IntlLocale::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    auto* thisObject = jsCast<IntlLocale*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+    Base::visitChildren(thisObject, visitor);
+}
+
+class LocaleIDBuilder final {
+public:
+    bool initialize(const CString&);
+    CString toCanonical();
+
+    void overrideLanguageScriptRegion(StringView language, StringView script, StringView region);
+    void setKeywordValue(ASCIILiteral key, StringView value);
+
+private:
+    Vector<char, 32> m_buffer;
+};
+
+bool LocaleIDBuilder::initialize(const CString& tag)
+{
+    m_buffer = localeIDBufferForLanguageTag(tag);
+    return m_buffer.size();
+}
+
+CString LocaleIDBuilder::toCanonical()
+{
+    ASSERT(m_buffer.size());
+
+    UErrorCode status = U_ZERO_ERROR;
+    Vector<char, 32> result(32);
+    auto resultLength = uloc_canonicalize(m_buffer.data(), result.data(), result.size(), &status);
+    if (needsToGrowToProduceBuffer(status)) {
+        result.grow(resultLength);
+        status = U_ZERO_ERROR;
+        uloc_canonicalize(m_buffer.data(), result.data(), resultLength, &status);
+    }
+    if (U_FAILURE(status))
+        return CString();
+
+    return CString(result.data(), resultLength);
+}
+
+// Because ICU's C API doesn't have set[Language|Script|Region] functions...
+void LocaleIDBuilder::overrideLanguageScriptRegion(StringView language, StringView script, StringView region)
+{
+    unsigned length = strlen(m_buffer.data());
+    ASSERT(length);
+
+    StringView localeIDView { m_buffer.data(), length };
+
+    auto endOfLanguageScriptRegionVariant = localeIDView.find(ULOC_KEYWORD_SEPARATOR);
+    if (endOfLanguageScriptRegionVariant == notFound)
+        endOfLanguageScriptRegionVariant = length;
+
+    Vector<StringView> subtags;
+    for (auto subtag : localeIDView.left(endOfLanguageScriptRegionVariant).splitAllowingEmptyEntries('_'))
+        subtags.append(subtag);
+
+    if (!language.isNull())
+        subtags[0] = language;
+
+    bool hasScript = subtags.size() > 1 && subtags[1].length() == 4;
+    if (!script.isNull()) {
+        if (hasScript)
+            subtags[1] = script;
+        else {
+            subtags.insert(1, script);
+            hasScript = true;
+        }
+    }
+
+    if (!region.isNull()) {
+        size_t index = hasScript ? 2 : 1;
+        bool hasRegion = subtags.size() > index && subtags[index].length() < 4;
+        if (hasRegion)
+            subtags[index] = region;
+        else
+            subtags.insert(index, region);
+    }
+
+    Vector<char, 32> buffer;
+    bool hasAppended = false;
+    for (auto subtag : subtags) {
+        if (hasAppended)
+            buffer.append('_');
+        else
+            hasAppended = true;
+
+        ASSERT(subtag.is8Bit() && subtag.isAllASCII());
+        buffer.append(reinterpret_cast<const char*>(subtag.characters8()), subtag.length());
+    }
+
+    if (endOfLanguageScriptRegionVariant != length) {
+        auto rest = localeIDView.right(length - endOfLanguageScriptRegionVariant);
+
+        ASSERT(rest.is8Bit() && rest.isAllASCII());
+        buffer.append(reinterpret_cast<const char*>(rest.characters8()), rest.length());
+    }
+
+    buffer.append('\0');
+    m_buffer.swap(buffer);
+}
+
+void LocaleIDBuilder::setKeywordValue(ASCIILiteral key, StringView value)
+{
+    ASSERT(m_buffer.size());
+
+    ASSERT(value.is8Bit() && value.isAllASCII());
+    CString rawValue { reinterpret_cast<const char*>(value.characters8()), value.length() };
+
+    UErrorCode status = U_ZERO_ERROR;
+    auto length = uloc_setKeywordValue(key.characters(), rawValue.data(), m_buffer.data(), m_buffer.size(), &status);
+    // uloc_setKeywordValue does not set U_STRING_NOT_TERMINATED_WARNING.
+    if (needsToGrowToProduceBuffer(status)) {
+        m_buffer.grow(length + 1);
+        status = U_ZERO_ERROR;
+        uloc_setKeywordValue(key.characters(), rawValue.data(), m_buffer.data(), length + 1, &status);
+    }
+    ASSERT(U_SUCCESS(status));
+}
+
+String IntlLocale::keywordValue(ASCIILiteral key, bool isBoolean) const
+{
+    UErrorCode status = U_ZERO_ERROR;
+    Vector<char, 32> buffer(32);
+    auto bufferLength = uloc_getKeywordValue(m_localeID.data(), key.characters(), buffer.data(), buffer.size(), &status);
+    if (needsToGrowToProduceCString(status)) {
+        buffer.grow(bufferLength + 1);
+        status = U_ZERO_ERROR;
+        uloc_getKeywordValue(m_localeID.data(), key.characters(), buffer.data(), bufferLength + 1, &status);
+    }
+    ASSERT(U_SUCCESS(status));
+
+    const char* value = !isBoolean ? uloc_toUnicodeLocaleType(key.characters(), buffer.data()) : buffer.data();
+    return value ? String(value) : emptyString();
+}
+
+// unicode_language_subtag = alpha{2,3} | alpha{5,8} ;
+static bool isUnicodeLanguageSubtag(StringView string)
+{
+    auto length = string.length();
+    return length >= 2 && length <= 8 && length != 4 && string.isAllSpecialCharacters<isASCIIAlpha>();
+}
+
+// unicode_script_subtag = alpha{4} ;
+static bool isUnicodeScriptSubtag(StringView string)
+{
+    return string.length() == 4 && string.isAllSpecialCharacters<isASCIIAlpha>();
+}
+
+// unicode_region_subtag = alpha{2} | digit{3} ;
+static bool isUnicodeRegionSubtag(StringView string)
+{
+    auto length = string.length();
+    return (length == 2 && string.isAllSpecialCharacters<isASCIIAlpha>())
+        || (length == 3 && string.isAllSpecialCharacters<isASCIIDigit>());
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale
+void IntlLocale::initializeLocale(JSGlobalObject* globalObject, JSValue tagValue, JSValue optionsValue)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String tag = tagValue.inherits<IntlLocale>(vm) ? jsCast<IntlLocale*>(tagValue)->toString() : tagValue.toWTFString(globalObject);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    JSValue options = optionsValue;
+    if (!optionsValue.isUndefined()) {
+        options = optionsValue.toObject(globalObject);
+        RETURN_IF_EXCEPTION(scope, void());
+    }
+
+    LocaleIDBuilder localeID;
+    if (!localeID.initialize(tag.utf8())) {
+        throwRangeError(globalObject, scope, "invalid language tag"_s);
+        return;
+    }
+
+    String language = intlStringOption(globalObject, options, vm.propertyNames->language, { }, nullptr, nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!language.isNull() && !isUnicodeLanguageSubtag(language)) {
+        throwRangeError(globalObject, scope, "language is not a well-formed language value"_s);
+        return;
+    }
+
+    String script = intlStringOption(globalObject, options, vm.propertyNames->script, { }, nullptr, nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!script.isNull() && !isUnicodeScriptSubtag(script)) {
+        throwRangeError(globalObject, scope, "script is not a well-formed script value"_s);
+        return;
+    }
+
+    String region = intlStringOption(globalObject, options, vm.propertyNames->region, { }, nullptr, nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!region.isNull() && !isUnicodeRegionSubtag(region)) {
+        throwRangeError(globalObject, scope, "region is not a well-formed region value"_s);
+        return;
+    }
+
+    if (!language.isNull() || !script.isNull() || !region.isNull())
+        localeID.overrideLanguageScriptRegion(language, script, region);
+
+    String calendar = intlStringOption(globalObject, options, vm.propertyNames->calendar, { }, nullptr, nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!calendar.isNull()) {
+        if (!isUnicodeLocaleIdentifierType(calendar)) {
+            throwRangeError(globalObject, scope, "calendar is not a well-formed calendar value"_s);
+            return;
+        }
+        localeID.setKeywordValue("calendar"_s, calendar);
+    }
+
+    String collation = intlStringOption(globalObject, options, vm.propertyNames->collation, { }, nullptr, nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!collation.isNull()) {
+        if (!isUnicodeLocaleIdentifierType(collation)) {
+            throwRangeError(globalObject, scope, "collation is not a well-formed collation value"_s);
+            return;
+        }
+        localeID.setKeywordValue("collation"_s, collation);
+    }
+
+    String hourCycle = intlStringOption(globalObject, options, vm.propertyNames->hourCycle, { "h11", "h12", "h23", "h24" }, "hourCycle must be \"h11\", \"h12\", \"h23\", or \"h24\"", nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!hourCycle.isNull())
+        localeID.setKeywordValue("hours"_s, hourCycle);
+
+    String caseFirst = intlStringOption(globalObject, options, vm.propertyNames->caseFirst, { "upper", "lower", "false" }, "caseFirst must be either \"upper\", \"lower\", or \"false\"", nullptr);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (!caseFirst.isNull())
+        localeID.setKeywordValue("colcasefirst"_s, caseFirst);
+
+    TriState numeric = intlBooleanOption(globalObject, options, vm.propertyNames->numeric);
+    RETURN_IF_EXCEPTION(scope, void());
+    if (numeric != TriState::Indeterminate)
+        localeID.setKeywordValue("colnumeric"_s, numeric == TriState::True ? "yes" : "no");
+
+    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;
+        }
+        localeID.setKeywordValue("numbers"_s, numberingSystem);
+    }
+
+    m_localeID = localeID.toCanonical();
+    if (m_localeID.isNull()) {
+        throwTypeError(globalObject, scope, "failed to initialize Locale"_s);
+        return;
+    }
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.maximize
+const String& IntlLocale::maximize()
+{
+    if (m_maximized.isNull()) {
+        UErrorCode status = U_ZERO_ERROR;
+        Vector<char, 32> buffer(32);
+        auto bufferLength = uloc_addLikelySubtags(m_localeID.data(), buffer.data(), buffer.size(), &status);
+        if (needsToGrowToProduceCString(status)) {
+            buffer.grow(bufferLength + 1);
+            status = U_ZERO_ERROR;
+            uloc_addLikelySubtags(m_localeID.data(), buffer.data(), bufferLength + 1, &status);
+        }
+        ASSERT(U_SUCCESS(status));
+
+        m_maximized = languageTagForLocaleID(buffer.data());
+    }
+    return m_maximized;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
+const String& IntlLocale::minimize()
+{
+    if (m_minimized.isNull()) {
+        UErrorCode status = U_ZERO_ERROR;
+        Vector<char, 32> buffer(32);
+        auto bufferLength = uloc_minimizeSubtags(m_localeID.data(), buffer.data(), buffer.size(), &status);
+        if (needsToGrowToProduceCString(status)) {
+            buffer.grow(bufferLength + 1);
+            status = U_ZERO_ERROR;
+            uloc_minimizeSubtags(m_localeID.data(), buffer.data(), bufferLength + 1, &status);
+        }
+        ASSERT(U_SUCCESS(status));
+
+        m_minimized = languageTagForLocaleID(buffer.data());
+    }
+    return m_minimized;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
+const String& IntlLocale::toString()
+{
+    if (m_fullString.isNull())
+        m_fullString = languageTagForLocaleID(m_localeID.data());
+    return m_fullString;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.baseName
+const String& IntlLocale::baseName()
+{
+    if (m_baseName.isNull()) {
+        UErrorCode status = U_ZERO_ERROR;
+        Vector<char, 32> buffer(32);
+        auto bufferLength = uloc_getBaseName(m_localeID.data(), buffer.data(), buffer.size(), &status);
+        if (needsToGrowToProduceCString(status)) {
+            buffer.grow(bufferLength + 1);
+            status = U_ZERO_ERROR;
+            uloc_getBaseName(m_localeID.data(), buffer.data(), bufferLength + 1, &status);
+        }
+        ASSERT(U_SUCCESS(status));
+
+        m_baseName = languageTagForLocaleID(buffer.data());
+    }
+    return m_baseName;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.language
+const String& IntlLocale::language()
+{
+    if (m_language.isNull()) {
+        UErrorCode status = U_ZERO_ERROR;
+        Vector<char, 8> buffer(8);
+        auto bufferLength = uloc_getLanguage(m_localeID.data(), buffer.data(), buffer.size(), &status);
+        if (needsToGrowToProduceBuffer(status)) {
+            buffer.grow(bufferLength);
+            status = U_ZERO_ERROR;
+            uloc_getLanguage(m_localeID.data(), buffer.data(), bufferLength, &status);
+        }
+        ASSERT(U_SUCCESS(status));
+
+        m_language = String(buffer.data(), bufferLength);
+    }
+    return m_language;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.script
+const String& IntlLocale::script()
+{
+    if (m_script.isNull()) {
+        UErrorCode status = U_ZERO_ERROR;
+        Vector<char, 4> buffer(4);
+        auto bufferLength = uloc_getScript(m_localeID.data(), buffer.data(), buffer.size(), &status);
+        if (needsToGrowToProduceBuffer(status)) {
+            buffer.grow(bufferLength);
+            status = U_ZERO_ERROR;
+            uloc_getScript(m_localeID.data(), buffer.data(), bufferLength, &status);
+        }
+        ASSERT(U_SUCCESS(status));
+
+        m_script = String(buffer.data(), bufferLength);
+    }
+    return m_script;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.region
+const String& IntlLocale::region()
+{
+    if (m_region.isNull()) {
+        UErrorCode status = U_ZERO_ERROR;
+        Vector<char, 3> buffer(3);
+        auto bufferLength = uloc_getCountry(m_localeID.data(), buffer.data(), buffer.size(), &status);
+        if (needsToGrowToProduceBuffer(status)) {
+            buffer.grow(bufferLength);
+            status = U_ZERO_ERROR;
+            uloc_getCountry(m_localeID.data(), buffer.data(), bufferLength, &status);
+        }
+        ASSERT(U_SUCCESS(status));
+
+        m_region = String(buffer.data(), bufferLength);
+    }
+    return m_region;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.calendar
+const String& IntlLocale::calendar()
+{
+    if (m_calendar.isNull())
+        m_calendar = keywordValue("calendar"_s);
+    return m_calendar;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.caseFirst
+const String& IntlLocale::caseFirst()
+{
+    if (m_caseFirst.isNull())
+        m_caseFirst = keywordValue("colcasefirst"_s);
+    return m_caseFirst;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.collation
+const String& IntlLocale::collation()
+{
+    if (m_collation.isNull())
+        m_collation = keywordValue("collation"_s);
+    return m_collation;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.hourCycle
+const String& IntlLocale::hourCycle()
+{
+    if (m_hourCycle.isNull())
+        m_hourCycle = keywordValue("hours"_s);
+    return m_hourCycle;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numberingSystem
+const String& IntlLocale::numberingSystem()
+{
+    if (m_numberingSystem.isNull())
+        m_numberingSystem = keywordValue("numbers"_s);
+    return m_numberingSystem;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numeric
+TriState IntlLocale::numeric()
+{
+    constexpr bool isBoolean = true;
+    if (m_numeric == TriState::Indeterminate)
+        m_numeric = triState(keywordValue("colnumeric"_s, isBoolean) == "yes");
+    return m_numeric;
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlLocale.h (0 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlLocale.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocale.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,93 @@
+/*
+ * 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 IntlLocale final : public JSNonFinalObject {
+public:
+    using Base = JSNonFinalObject;
+
+    static constexpr bool needsDestruction = true;
+
+    static void destroy(JSCell* cell)
+    {
+        static_cast<IntlLocale*>(cell)->IntlLocale::~IntlLocale();
+    }
+
+    template<typename CellType, SubspaceAccess mode>
+    static IsoSubspace* subspaceFor(VM& vm)
+    {
+        return vm.intlLocaleSpace<mode>();
+    }
+
+    static IntlLocale* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+    void initializeLocale(JSGlobalObject*, JSValue tagValue, JSValue optionsValue);
+    const String& maximize();
+    const String& minimize();
+    const String& toString();
+    const String& baseName();
+    const String& language();
+    const String& script();
+    const String& region();
+    const String& calendar();
+    const String& caseFirst();
+    const String& collation();
+    const String& hourCycle();
+    const String& numberingSystem();
+    TriState numeric();
+
+private:
+    IntlLocale(VM&, Structure*);
+    void finishCreation(VM&);
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    String keywordValue(ASCIILiteral, bool isBoolean = false) const;
+
+    CString m_localeID;
+
+    String m_maximized;
+    String m_minimized;
+    String m_fullString;
+    String m_baseName;
+    String m_language;
+    String m_script;
+    String m_region;
+    String m_calendar;
+    String m_caseFirst;
+    String m_collation;
+    String m_hourCycle;
+    String m_numberingSystem;
+    TriState m_numeric { TriState::Indeterminate };
+};
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.cpp (0 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.cpp	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,103 @@
+/*
+ * 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 "IntlLocaleConstructor.h"
+
+#include "Error.h"
+#include "IntlLocale.h"
+#include "IntlLocalePrototype.h"
+#include "IntlObject.h"
+#include "JSCInlines.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlLocaleConstructor);
+
+const ClassInfo IntlLocaleConstructor::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlLocaleConstructor) };
+
+IntlLocaleConstructor* IntlLocaleConstructor::create(VM& vm, Structure* structure, IntlLocalePrototype* localePrototype)
+{
+    auto* constructor = new (NotNull, allocateCell<IntlLocaleConstructor>(vm.heap)) IntlLocaleConstructor(vm, structure);
+    constructor->finishCreation(vm, localePrototype);
+    return constructor;
+}
+
+Structure* IntlLocaleConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlLocale(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL constructIntlLocale(JSGlobalObject*, CallFrame*);
+
+IntlLocaleConstructor::IntlLocaleConstructor(VM& vm, Structure* structure)
+    : Base(vm, structure, callIntlLocale, constructIntlLocale)
+{
+}
+
+void IntlLocaleConstructor::finishCreation(VM& vm, IntlLocalePrototype* localePrototype)
+{
+    Base::finishCreation(vm, "Locale"_s, NameAdditionMode::WithoutStructureTransition);
+    putDirectWithoutTransition(vm, vm.propertyNames->prototype, localePrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
+    localePrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale
+static EncodedJSValue JSC_HOST_CALL constructIntlLocale(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSObject* newTarget = asObject(callFrame->newTarget());
+    Structure* structure = newTarget == callFrame->jsCallee()
+        ? globalObject->localeStructure()
+        : InternalFunction::createSubclassStructure(globalObject, newTarget, getFunctionRealm(vm, newTarget)->localeStructure());
+    RETURN_IF_EXCEPTION(scope, { });
+
+    IntlLocale* locale = IntlLocale::create(vm, structure);
+    ASSERT(locale);
+
+    JSValue tag = callFrame->argument(0);
+    if (!tag.isString() && !tag.isObject())
+        return throwVMTypeError(globalObject, scope, "First argument to Intl.Locale must be a string or an object"_s);
+
+    scope.release();
+    locale->initializeLocale(globalObject, tag, callFrame->argument(1));
+    return JSValue::encode(locale);
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale
+static EncodedJSValue JSC_HOST_CALL callIntlLocale(JSGlobalObject* globalObject, CallFrame*)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "Locale"));
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.h (0 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,51 @@
+/*
+ * 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 IntlLocalePrototype;
+
+class IntlLocaleConstructor final : public InternalFunction {
+public:
+    using Base = InternalFunction;
+    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+    static IntlLocaleConstructor* create(VM&, Structure*, IntlLocalePrototype*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+private:
+    IntlLocaleConstructor(VM&, Structure*);
+    void finishCreation(VM&, IntlLocalePrototype*);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlLocaleConstructor, InternalFunction);
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.cpp (0 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.cpp	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,276 @@
+/*
+ * 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 "IntlLocalePrototype.h"
+
+#include "Error.h"
+#include "IntlLocale.h"
+#include "JSCInlines.h"
+#include "JSObjectInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMaximize(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMinimize(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncToString(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterBaseName(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCalendar(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCaseFirst(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCollation(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterHourCycle(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumeric(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumberingSystem(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterLanguage(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterScript(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterRegion(JSGlobalObject*, CallFrame*);
+
+}
+
+#include "IntlLocalePrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlLocalePrototype::s_info = { "Intl.Locale", &Base::s_info, &localePrototypeTable, nullptr, CREATE_METHOD_TABLE(IntlLocalePrototype) };
+
+/* Source for IntlLocalePrototype.lut.h
+@begin localePrototypeTable
+  maximize         IntlLocalePrototypeFuncMaximize           DontEnum|Function 0
+  minimize         IntlLocalePrototypeFuncMinimize           DontEnum|Function 0
+  toString         IntlLocalePrototypeFuncToString           DontEnum|Function 0
+  baseName         IntlLocalePrototypeGetterBaseName         DontEnum|Accessor
+  calendar         IntlLocalePrototypeGetterCalendar         DontEnum|Accessor
+  caseFirst        IntlLocalePrototypeGetterCaseFirst        DontEnum|Accessor
+  collation        IntlLocalePrototypeGetterCollation        DontEnum|Accessor
+  hourCycle        IntlLocalePrototypeGetterHourCycle        DontEnum|Accessor
+  numeric          IntlLocalePrototypeGetterNumeric          DontEnum|Accessor
+  numberingSystem  IntlLocalePrototypeGetterNumberingSystem  DontEnum|Accessor
+  language         IntlLocalePrototypeGetterLanguage         DontEnum|Accessor
+  script           IntlLocalePrototypeGetterScript           DontEnum|Accessor
+  region           IntlLocalePrototypeGetterRegion           DontEnum|Accessor
+@end
+*/
+
+IntlLocalePrototype* IntlLocalePrototype::create(VM& vm, Structure* structure)
+{
+    auto* object = new (NotNull, allocateCell<IntlLocalePrototype>(vm.heap)) IntlLocalePrototype(vm, structure);
+    object->finishCreation(vm);
+    return object;
+}
+
+Structure* IntlLocalePrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlLocalePrototype::IntlLocalePrototype(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void IntlLocalePrototype::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(vm, info()));
+    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.maximize
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMaximize(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.maximize called on value that's not an object initialized as a Locale"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, locale->maximize())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMinimize(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.minimize called on value that's not an object initialized as a Locale"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, locale->minimize())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncToString(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.toString called on value that's not an object initialized as a Locale"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(vm, locale->toString())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.baseName
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterBaseName(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.baseName called on value that's not an object initialized as a Locale"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(vm, locale->baseName())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.calendar
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCalendar(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.calendar called on value that's not an object initialized as a Locale"_s);
+
+    const String& calendar = locale->calendar();
+    RELEASE_AND_RETURN(scope, JSValue::encode(calendar.isEmpty() ? jsUndefined() : jsNontrivialString(vm, calendar)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.caseFirst
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCaseFirst(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.caseFirst called on value that's not an object initialized as a Locale"_s);
+
+    const String& caseFirst = locale->caseFirst();
+    RELEASE_AND_RETURN(scope, JSValue::encode(caseFirst.isEmpty() ? jsUndefined() : jsNontrivialString(vm, caseFirst)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.collation
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCollation(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.collation called on value that's not an object initialized as a Locale"_s);
+
+    const String& collation = locale->collation();
+    RELEASE_AND_RETURN(scope, JSValue::encode(collation.isEmpty() ? jsUndefined() : jsNontrivialString(vm, collation)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.hourCycle
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterHourCycle(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.hourCycle called on value that's not an object initialized as a Locale"_s);
+
+    const String& hourCycle = locale->hourCycle();
+    RELEASE_AND_RETURN(scope, JSValue::encode(hourCycle.isEmpty() ? jsUndefined() : jsNontrivialString(vm, hourCycle)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numeric
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumeric(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.numeric called on value that's not an object initialized as a Locale"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(locale->numeric() == TriState::True)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numberingSystem
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumberingSystem(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.numberingSystem called on value that's not an object initialized as a Locale"_s);
+
+    const String& numberingSystem = locale->numberingSystem();
+    RELEASE_AND_RETURN(scope, JSValue::encode(numberingSystem.isEmpty() ? jsUndefined() : jsNontrivialString(vm, numberingSystem)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.language
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterLanguage(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.language called on value that's not an object initialized as a Locale"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(vm, locale->language())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.script
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterScript(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.script called on value that's not an object initialized as a Locale"_s);
+
+    const String& script = locale->script();
+    RELEASE_AND_RETURN(scope, JSValue::encode(script.isEmpty() ? jsUndefined() : jsNontrivialString(vm, script)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.region
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterRegion(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+    if (!locale)
+        return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.region called on value that's not an object initialized as a Locale"_s);
+
+    const String& region = locale->region();
+    RELEASE_AND_RETURN(scope, JSValue::encode(region.isEmpty() ? jsUndefined() : jsNontrivialString(vm, region)));
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.h (0 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,54 @@
+/*
+ * 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 IntlLocalePrototype 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(IntlLocalePrototype, Base);
+        return &vm.plainObjectSpace;
+    }
+
+    static IntlLocalePrototype* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+private:
+    IntlLocalePrototype(VM&, Structure*);
+    void finishCreation(VM&);
+};
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-05-06 06:01:07 UTC (rev 261215)
@@ -35,6 +35,9 @@
 #include "IntlCollatorPrototype.h"
 #include "IntlDateTimeFormatConstructor.h"
 #include "IntlDateTimeFormatPrototype.h"
+#include "IntlLocale.h"
+#include "IntlLocaleConstructor.h"
+#include "IntlLocalePrototype.h"
 #include "IntlNumberFormatConstructor.h"
 #include "IntlNumberFormatPrototype.h"
 #include "IntlPluralRulesConstructor.h"
@@ -136,6 +139,10 @@
 void IntlObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
     Base::finishCreation(vm);
+    if (Options::useIntlLocale()) {
+        auto* localeConstructor = IntlLocaleConstructor::create(vm, IntlLocaleConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlLocalePrototype*>(globalObject->localeStructure()->storedPrototypeObject()));
+        putDirectWithoutTransition(vm, vm.propertyNames->Locale, localeConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    }
     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));
@@ -147,23 +154,47 @@
     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
 }
 
-static String convertICULocaleToBCP47LanguageTag(const char* localeID)
+Vector<char, 32> localeIDBufferForLanguageTag(const CString& tag)
 {
+    if (!tag.length())
+        return { };
+
     UErrorCode status = U_ZERO_ERROR;
     Vector<char, 32> buffer(32);
+    int32_t parsedLength;
+    auto bufferLength = uloc_forLanguageTag(tag.data(), buffer.data(), buffer.size(), &parsedLength, &status);
+    if (needsToGrowToProduceCString(status)) {
+        // Before ICU 64, there's a chance uloc_forLanguageTag will "buffer overflow" while requesting a *smaller* size.
+        buffer.resize(bufferLength + 1);
+        status = U_ZERO_ERROR;
+        uloc_forLanguageTag(tag.data(), buffer.data(), bufferLength + 1, &parsedLength, &status);
+    }
+    if (U_FAILURE(status) || parsedLength != static_cast<int32_t>(tag.length()))
+        return { };
+
+    ASSERT(buffer.contains('\0'));
+    return buffer;
+}
+
+String languageTagForLocaleID(const char* localeID, bool isImmortal)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    Vector<char, 32> buffer(32);
     auto length = uloc_toLanguageTag(localeID, buffer.data(), buffer.size(), false, &status);
     if (needsToGrowToProduceBuffer(status)) {
         buffer.grow(length);
         status = U_ZERO_ERROR;
-        uloc_toLanguageTag(localeID, buffer.data(), buffer.size(), false, &status);
+        uloc_toLanguageTag(localeID, buffer.data(), length, false, &status);
     }
-    if (!U_FAILURE(status)) {
-        // This is used to store into static variables that may be shared across 
-        // JSC execution threads. This must be immortal to make concurrent ref/deref
-        // safe.
+    if (U_FAILURE(status))
+        return String();
+
+    // This is used to store into static variables that may be shared across JSC execution threads.
+    // This must be immortal to make concurrent ref/deref safe.
+    if (isImmortal)
         return String(StringImpl::createStaticStringImpl(buffer.data(), length));
-    }
-    return String();
+
+    return String(buffer.data(), length);
 }
 
 const HashSet<String>& intlAvailableLocales()
@@ -174,9 +205,10 @@
     static std::once_flag initializeOnce;
     std::call_once(initializeOnce, [&] {
         ASSERT(availableLocales.isEmpty());
+        constexpr bool isImmortal = true;
         int32_t count = uloc_countAvailable();
         for (int32_t i = 0; i < count; ++i) {
-            String locale = convertICULocaleToBCP47LanguageTag(uloc_getAvailable(i));
+            String locale = languageTagForLocaleID(uloc_getAvailable(i), isImmortal);
             if (!locale.isEmpty())
                 availableLocales.add(locale);
         }
@@ -192,9 +224,10 @@
     static std::once_flag initializeOnce;
     std::call_once(initializeOnce, [&] {
         ASSERT(availableLocales.isEmpty());
+        constexpr bool isImmortal = true;
         int32_t count = ucol_countAvailable();
         for (int32_t i = 0; i < count; ++i) {
-            String locale = convertICULocaleToBCP47LanguageTag(ucol_getAvailable(i));
+            String locale = languageTagForLocaleID(ucol_getAvailable(i), isImmortal);
             if (!locale.isEmpty())
                 availableLocales.add(locale);
         }
@@ -316,40 +349,13 @@
 
 // https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag
 // https://tc39.es/ecma402/#sec-canonicalizeunicodelocaleid
-static String canonicalizeLanguageTag(const CString& input)
+static String canonicalizeLanguageTag(const CString& tag)
 {
-    if (!input.length())
+    auto buffer = localeIDBufferForLanguageTag(tag);
+    if (buffer.isEmpty())
         return String();
 
-    // We need to be careful with the output of uloc_forLanguageTag:
-    // - uloc_toLanguageTag doesn't take an input size param so we must ensure the string is null-terminated ourselves
-    // - before ICU 64, there's a chance that it will "buffer overflow" while requesting a *smaller* size
-    UErrorCode status = U_ZERO_ERROR;
-    Vector<char, 32> intermediate(32);
-    int32_t parsedLength;
-    auto intermediateLength = uloc_forLanguageTag(input.data(), intermediate.data(), intermediate.size(), &parsedLength, &status);
-    if (needsToGrowToProduceCString(status)) {
-        intermediate.resize(intermediateLength + 1);
-        status = U_ZERO_ERROR;
-        uloc_forLanguageTag(input.data(), intermediate.data(), intermediateLength + 1, &parsedLength, &status);
-    }
-    if (U_FAILURE(status) || parsedLength != static_cast<int32_t>(input.length()))
-        return String();
-
-    ASSERT(intermediate.contains('\0'));
-
-    status = U_ZERO_ERROR;
-    Vector<char, 32> result(32);
-    auto resultLength = uloc_toLanguageTag(intermediate.data(), result.data(), result.size(), false, &status);
-    if (needsToGrowToProduceBuffer(status)) {
-        result.grow(resultLength);
-        status = U_ZERO_ERROR;
-        uloc_toLanguageTag(intermediate.data(), result.data(), resultLength, false, &status);
-    }
-    if (U_FAILURE(status))
-        return String();
-
-    return String(result.data(), resultLength);
+    return languageTagForLocaleID(buffer.data());
 }
 
 Vector<String> canonicalizeLocaleList(JSGlobalObject* globalObject, JSValue locales)
@@ -366,7 +372,7 @@
         return seen;
 
     JSObject* localesObject;
-    if (locales.isString()) {
+    if (locales.isString() || locales.inherits<IntlLocale>(vm)) {
         JSArray* localesArray = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
         if (!localesArray) {
             throwOutOfMemoryError(globalObject, scope);
@@ -402,13 +408,18 @@
                 return { };
             }
 
-            JSString* tag = kValue.toString(globalObject);
-            RETURN_IF_EXCEPTION(scope, Vector<String>());
+            Expected<CString, UTF8ConversionError> rawTag;
+            if (kValue.inherits<IntlLocale>(vm))
+                rawTag = jsCast<IntlLocale*>(kValue)->toString().tryGetUtf8();
+            else {
+                JSString* tag = kValue.toString(globalObject);
+                RETURN_IF_EXCEPTION(scope, Vector<String>());
 
-            auto tagValue = tag->value(globalObject);
-            RETURN_IF_EXCEPTION(scope, Vector<String>());
+                auto tagValue = tag->value(globalObject);
+                RETURN_IF_EXCEPTION(scope, Vector<String>());
 
-            auto rawTag = tagValue.tryGetUtf8();
+                rawTag = tagValue.tryGetUtf8();
+            }
             if (!rawTag) {
                 if (rawTag.error() == UTF8ConversionError::OutOfMemory)
                     throwOutOfMemoryError(globalObject, scope);
@@ -417,7 +428,7 @@
 
             String canonicalizedTag = canonicalizeLanguageTag(rawTag.value());
             if (canonicalizedTag.isNull()) {
-                String errorMessage = tryMakeString("invalid language tag: ", tagValue);
+                String errorMessage = tryMakeString("invalid language tag: ", rawTag->data());
                 if (UNLIKELY(!errorMessage)) {
                     throwException(globalObject, scope, createOutOfMemoryError(globalObject));
                     return { };
@@ -483,7 +494,8 @@
     static NeverDestroyed<String> icuDefaultLocalString;
     static std::once_flag initializeOnce;
     std::call_once(initializeOnce, [&] {
-        icuDefaultLocalString.get() = convertICULocaleToBCP47LanguageTag(uloc_getDefault());
+        constexpr bool isImmortal = true;
+        icuDefaultLocalString.get() = languageTagForLocaleID(uloc_getDefault(), isImmortal);
     });
     if (!icuDefaultLocalString->isEmpty())
         return icuDefaultLocalString.get();

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.h (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -68,6 +68,8 @@
 String intlStringOption(JSGlobalObject*, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback);
 unsigned intlNumberOption(JSGlobalObject*, JSValue options, PropertyName, unsigned minimum, unsigned maximum, unsigned fallback);
 unsigned intlDefaultNumberOption(JSGlobalObject*, JSValue, PropertyName, unsigned minimum, unsigned maximum, unsigned fallback);
+Vector<char, 32> localeIDBufferForLanguageTag(const CString&);
+String languageTagForLocaleID(const char*, bool isImmortal = false);
 Vector<String> canonicalizeLocaleList(JSGlobalObject*, JSValue locales);
 HashMap<String, String> resolveLocale(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, const HashMap<String, String>& options, const char* const relevantExtensionKeys[], size_t relevantExtensionKeyCount, Vector<String> (*localeData)(const String&, size_t));
 JSValue supportedLocales(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, JSValue options);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-05-06 06:01:07 UTC (rev 261215)
@@ -81,6 +81,8 @@
 #include "IntlCollatorPrototype.h"
 #include "IntlDateTimeFormat.h"
 #include "IntlDateTimeFormatPrototype.h"
+#include "IntlLocale.h"
+#include "IntlLocalePrototype.h"
 #include "IntlNumberFormat.h"
 #include "IntlNumberFormatPrototype.h"
 #include "IntlObject.h"
@@ -943,6 +945,18 @@
             IntlCollatorPrototype* collatorPrototype = IntlCollatorPrototype::create(init.vm, globalObject, IntlCollatorPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
             init.set(IntlCollator::createStructure(init.vm, globalObject, collatorPrototype));
         });
+    m_dateTimeFormatStructure.initLater(
+        [] (const Initializer<Structure>& init) {
+            JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+            IntlDateTimeFormatPrototype* dateTimeFormatPrototype = IntlDateTimeFormatPrototype::create(init.vm, globalObject, IntlDateTimeFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+            init.set(IntlDateTimeFormat::createStructure(init.vm, globalObject, dateTimeFormatPrototype));
+        });
+    m_localeStructure.initLater(
+        [] (const Initializer<Structure>& init) {
+            JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+            IntlLocalePrototype* localePrototype = IntlLocalePrototype::create(init.vm, IntlLocalePrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+            init.set(IntlLocale::createStructure(init.vm, globalObject, localePrototype));
+        });
     m_numberFormatStructure.initLater(
         [] (const Initializer<Structure>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -949,12 +963,6 @@
             IntlNumberFormatPrototype* numberFormatPrototype = IntlNumberFormatPrototype::create(init.vm, globalObject, IntlNumberFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
             init.set(IntlNumberFormat::createStructure(init.vm, globalObject, numberFormatPrototype));
         });
-    m_dateTimeFormatStructure.initLater(
-        [] (const Initializer<Structure>& init) {
-            JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
-            IntlDateTimeFormatPrototype* dateTimeFormatPrototype = IntlDateTimeFormatPrototype::create(init.vm, globalObject, IntlDateTimeFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
-            init.set(IntlDateTimeFormat::createStructure(init.vm, globalObject, dateTimeFormatPrototype));
-        });
     m_pluralRulesStructure.initLater(
         [] (const Initializer<Structure>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -1775,8 +1783,9 @@
 
     thisObject->m_defaultCollator.visit(visitor);
     thisObject->m_collatorStructure.visit(visitor);
+    thisObject->m_dateTimeFormatStructure.visit(visitor);
     thisObject->m_numberFormatStructure.visit(visitor);
-    thisObject->m_dateTimeFormatStructure.visit(visitor);
+    thisObject->m_localeStructure.visit(visitor);
     thisObject->m_pluralRulesStructure.visit(visitor);
     thisObject->m_relativeTimeFormatStructure.visit(visitor);
 

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -291,8 +291,9 @@
 
     LazyProperty<JSGlobalObject, IntlCollator> m_defaultCollator;
     LazyProperty<JSGlobalObject, Structure> m_collatorStructure;
+    LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
+    LazyProperty<JSGlobalObject, Structure> m_localeStructure;
     LazyProperty<JSGlobalObject, Structure> m_numberFormatStructure;
-    LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_pluralRulesStructure;
     LazyProperty<JSGlobalObject, Structure> m_relativeTimeFormatStructure;
 
@@ -786,8 +787,9 @@
     Structure* webAssemblyWrapperFunctionStructure() const { return m_webAssemblyWrapperFunctionStructure.get(this); }
 #endif // ENABLE(WEBASSEMBLY)
     Structure* collatorStructure() { return m_collatorStructure.get(this); }
+    Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
     Structure* numberFormatStructure() { return m_numberFormatStructure.get(this); }
-    Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
+    Structure* localeStructure() { return m_localeStructure.get(this); }
     Structure* pluralRulesStructure() { return m_pluralRulesStructure.get(this); }
     Structure* relativeTimeFormatStructure() { return m_relativeTimeFormatStructure.get(this); }
 

Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/OptionsList.h	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -486,6 +486,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, useIntlLocale, false, Normal, "Expose the Intl.Locale constructor.") \
     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.") \

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2020-05-06 06:01:07 UTC (rev 261215)
@@ -75,6 +75,7 @@
 #include "Interpreter.h"
 #include "IntlCollator.h"
 #include "IntlDateTimeFormat.h"
+#include "IntlLocale.h"
 #include "IntlNumberFormat.h"
 #include "IntlPluralRules.h"
 #include "IntlRelativeTimeFormat.h"
@@ -339,6 +340,7 @@
 #endif
     , intlCollatorHeapCellType(IsoHeapCellType::create<IntlCollator>())
     , intlDateTimeFormatHeapCellType(IsoHeapCellType::create<IntlDateTimeFormat>())
+    , intlLocaleHeapCellType(IsoHeapCellType::create<IntlLocale>())
     , intlNumberFormatHeapCellType(IsoHeapCellType::create<IntlNumberFormat>())
     , intlPluralRulesHeapCellType(IsoHeapCellType::create<IntlPluralRules>())
     , intlRelativeTimeFormatHeapCellType(IsoHeapCellType::create<IntlRelativeTimeFormat>())
@@ -1510,6 +1512,7 @@
 #endif
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlCollatorSpace, intlCollatorHeapCellType.get(), IntlCollator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlDateTimeFormatSpace, intlDateTimeFormatHeapCellType.get(), IntlDateTimeFormat)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlLocaleSpace, intlLocaleHeapCellType.get(), IntlLocale)
 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)

Modified: trunk/Source/_javascript_Core/runtime/VM.h (261214 => 261215)


--- trunk/Source/_javascript_Core/runtime/VM.h	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2020-05-06 06:01:07 UTC (rev 261215)
@@ -126,6 +126,7 @@
 class Interpreter;
 class IntlCollator;
 class IntlDateTimeFormat;
+class IntlLocale;
 class IntlNumberFormat;
 class IntlPluralRules;
 class IntlRelativeTimeFormat;
@@ -400,6 +401,7 @@
 #endif
     std::unique_ptr<IsoHeapCellType> intlCollatorHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlDateTimeFormatHeapCellType;
+    std::unique_ptr<IsoHeapCellType> intlLocaleHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlNumberFormatHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlPluralRulesHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlRelativeTimeFormatHeapCellType;
@@ -557,6 +559,7 @@
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(withScopeSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlCollatorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlDateTimeFormatSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlLocaleSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlNumberFormatSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlPluralRulesSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlRelativeTimeFormatSpace)

Modified: trunk/Tools/ChangeLog (261214 => 261215)


--- trunk/Tools/ChangeLog	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Tools/ChangeLog	2020-05-06 06:01:07 UTC (rev 261215)
@@ -1,3 +1,13 @@
+2020-05-05  Ross Kirsling  <ross.kirsl...@sony.com>
+
+        [ECMA-402] Implement Intl.Locale
+        https://bugs.webkit.org/show_bug.cgi?id=209772
+
+        Reviewed by Darin Adler and Saam Barati.
+
+        * Scripts/run-jsc-stress-tests:
+        Add runIntlLocaleEnabled.
+
 2020-05-05  Saam Barati  <sbar...@apple.com>
 
         Don't use the DebugHeap for catalyst

Modified: trunk/Tools/Scripts/run-jsc-stress-tests (261214 => 261215)


--- trunk/Tools/Scripts/run-jsc-stress-tests	2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Tools/Scripts/run-jsc-stress-tests	2020-05-06 06:01:07 UTC (rev 261215)
@@ -715,6 +715,10 @@
     run("big-int-enabled-baseline", "--useBigInt=true", "--useDFGJIT=0", *optionalTestSpecificOptions)
 end
 
+def runIntlLocaleEnabled(*optionalTestSpecificOptions)
+    run("intl-locale-enabled", "--useIntlLocale=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
+end
+
 def runIntlRelativeTimeFormatEnabled(*optionalTestSpecificOptions)
     run("intl-relativetimeformat-enabled", "--useIntlRelativeTimeFormat=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
 end
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to