[INTL] Improve spec & test262 compliance for Intl APIs
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 13 May 2018 14:28:39 +0000 (14:28 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 13 May 2018 14:28:39 +0000 (14:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185578

Patch by Andy VanWagoner <andy@vanwagoner.family> on 2018-05-13
Reviewed by Yusuke Suzuki.

JSTests:

Remove intl402 failures that have been fixed.

* test262/expectations.yaml:
* stress/regress-178385.js: toStringTag is configurable, but not writable.

Source/JavaScriptCore:

Use putDirectIndex over push for lists to arrays.
Update default options to construct with a null prototype.
Define constructor and toStringTag on prototypes.
Add proper time clipping.
Remove some outdated comment spec text, use url instead.

* runtime/IntlCollator.cpp:
(JSC::IntlCollator::initializeCollator):
* runtime/IntlCollatorConstructor.cpp:
(JSC::IntlCollatorConstructor::finishCreation):
* runtime/IntlCollatorPrototype.cpp:
(JSC::IntlCollatorPrototype::finishCreation):
* runtime/IntlDateTimeFormatConstructor.cpp:
(JSC::IntlDateTimeFormatConstructor::finishCreation):
* runtime/IntlDateTimeFormatPrototype.cpp:
(JSC::IntlDateTimeFormatPrototype::finishCreation):
(JSC::IntlDateTimeFormatFuncFormatDateTime):
(JSC::IntlDateTimeFormatPrototypeFuncFormatToParts):
* runtime/IntlNumberFormat.cpp:
(JSC::IntlNumberFormat::initializeNumberFormat):
* runtime/IntlNumberFormatConstructor.cpp:
(JSC::IntlNumberFormatConstructor::finishCreation):
* runtime/IntlNumberFormatPrototype.cpp:
(JSC::IntlNumberFormatPrototype::finishCreation):
* runtime/IntlObject.cpp:
(JSC::lookupSupportedLocales):
(JSC::supportedLocales):
(JSC::intlObjectFuncGetCanonicalLocales):
* runtime/IntlPluralRules.cpp:
(JSC::IntlPluralRules::resolvedOptions):
* runtime/IntlPluralRulesConstructor.cpp:
(JSC::IntlPluralRulesConstructor::finishCreation):

LayoutTests:

Update Intl tests for prototype changes.

* js/intl-collator-expected.txt:
* js/intl-datetimeformat-expected.txt:
* js/intl-numberformat-expected.txt:
* js/script-tests/intl-collator.js:
* js/script-tests/intl-datetimeformat.js:
* js/script-tests/intl-numberformat.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231740 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
JSTests/ChangeLog
JSTests/stress/regress-178385.js
JSTests/test262/expectations.yaml
LayoutTests/ChangeLog
LayoutTests/js/intl-collator-expected.txt
LayoutTests/js/intl-datetimeformat-expected.txt
LayoutTests/js/intl-numberformat-expected.txt
LayoutTests/js/script-tests/intl-collator.js
LayoutTests/js/script-tests/intl-datetimeformat.js
LayoutTests/js/script-tests/intl-numberformat.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/IntlCollator.cpp
Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp
Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp
Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp
Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp
Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
Source/JavaScriptCore/runtime/IntlObject.cpp
Source/JavaScriptCore/runtime/IntlPluralRules.cpp
Source/JavaScriptCore/runtime/IntlPluralRulesConstructor.cpp

index 52141b3..018348a 100644 (file)
@@ -1,3 +1,15 @@
+2018-05-13  Andy VanWagoner  <andy@vanwagoner.family>
+
+        [INTL] Improve spec & test262 compliance for Intl APIs
+        https://bugs.webkit.org/show_bug.cgi?id=185578
+
+        Reviewed by Yusuke Suzuki.
+
+        Remove intl402 failures that have been fixed.
+
+        * test262/expectations.yaml:
+        * stress/regress-178385.js: toStringTag is configurable, but not writable.
+
 2018-05-11  Caio Lima  <ticaiolima@gmail.com>
 
         [ESNext][BigInt] Implement support for "*" operation
index 43a6145..10a2048 100644 (file)
@@ -6,7 +6,7 @@ try {
     var str0 = new String('@hBg');
     var collat3 = new Intl.Collator();
     str10 = str0.padEnd(0x7FFFFFFC, 1);
-    collat3[Symbol.toStringTag] = str10;
+    Object.defineProperty(collat3, Symbol.toStringTag, { value: str10 });
     collat3.toLocaleString();
 } catch (e) {
     exception = e;
index 9978219..ff3bd38 100644 (file)
@@ -1853,54 +1853,27 @@ test/built-ins/parseInt/S15.1.2.2_A2_T10_U180E.js:
 test/harness/assert-throws-early-referenceerror.js:
   default: 'Test262Error: Function: 1 = 1; Expected a ReferenceError to be thrown but no exception was thrown at all'
   strict mode: 'Test262Error: Function: 1 = 1; Expected a ReferenceError to be thrown but no exception was thrown at all'
-test/intl402/Collator/default-options-object-prototype.js:
-  default: 'Test262Error: Expected SameValue(«base», Â«variant») to be true'
-  strict mode: 'Test262Error: Expected SameValue(«base», Â«variant») to be true'
 test/intl402/Collator/length.js:
   default: 'Test262Error: Expected obj[length] to have configurable:true.'
   strict mode: 'Test262Error: Expected obj[length] to have configurable:true.'
 test/intl402/Collator/prototype/compare/compare-function-name.js:
   default: 'Test262Error: Expected SameValue(«true», Â«false») to be true'
   strict mode: 'Test262Error: Expected SameValue(«true», Â«false») to be true'
-test/intl402/Collator/prototype/constructor/prop-desc.js:
-  default: "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(obj, name).enumerable')"
-  strict mode: "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(obj, name).enumerable')"
-test/intl402/Collator/prototype/constructor/value.js:
-  default: 'Test262Error: Intl.Collator.prototype.constructor is not the same as Intl.Collator Expected SameValue(«function Object() {'
-  strict mode: 'Test262Error: Intl.Collator.prototype.constructor is not the same as Intl.Collator Expected SameValue(«function Object() {'
 test/intl402/Collator/unicode-ext-seq-in-private-tag.js:
   default: 'Test262Error: Expected SameValue(«phonebk», Â«default») to be true'
   strict mode: 'Test262Error: Expected SameValue(«phonebk», Â«default») to be true'
 test/intl402/DateTimeFormat/length.js:
   default: 'Test262Error: Expected obj[length] to have configurable:true.'
   strict mode: 'Test262Error: Expected obj[length] to have configurable:true.'
-test/intl402/DateTimeFormat/prototype/constructor/prop-desc.js:
-  default: "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(obj, name).enumerable')"
-  strict mode: "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(obj, name).enumerable')"
-test/intl402/DateTimeFormat/prototype/constructor/value.js:
-  default: 'Test262Error: Intl.DateTimeFormat.prototype.constructor is not the same as Intl.DateTimeFormat Expected SameValue(«function Object() {'
-  strict mode: 'Test262Error: Intl.DateTimeFormat.prototype.constructor is not the same as Intl.DateTimeFormat Expected SameValue(«function Object() {'
 test/intl402/DateTimeFormat/prototype/format/format-function-name.js:
   default: 'Test262Error: Expected SameValue(«true», Â«false») to be true'
   strict mode: 'Test262Error: Expected SameValue(«true», Â«false») to be true'
 test/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js:
   default: "Test262Error: Internal error: Didn't find Gregorian calendar Expected SameValue(«gregorian», Â«gregory») to be true"
   strict mode: "Test262Error: Internal error: Didn't find Gregorian calendar Expected SameValue(«gregorian», Â«gregory») to be true"
-test/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.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/DateTimeFormat/prototype/format/time-clip-to-integer.js:
-  default: 'Test262Error: format(-0.9) Expected SameValue(«8:59:59 PM», Â«9:00:00 PM») to be true'
-  strict mode: 'Test262Error: format(-0.9) Expected SameValue(«8:59:59 PM», Â«9:00:00 PM») to be true'
 test/intl402/DateTimeFormat/prototype/formatToParts/length.js:
   default: 'Test262Error: Expected SameValue(«0», Â«1») to be true'
   strict mode: 'Test262Error: Expected SameValue(«0», Â«1») to be true'
-test/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.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/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js:
-  default: 'Test262Error: formatToParts(-0.9) Expected SameValue(«8:59:59 PM», Â«9:00:00 PM») to be true'
-  strict mode: 'Test262Error: formatToParts(-0.9) Expected SameValue(«8:59:59 PM», Â«9:00:00 PM») to be true'
 test/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js:
   default: 'Test262Error: Invalid calendar: gregorian Expected SameValue(«-1», Â«-1») to be false'
   strict mode: 'Test262Error: Invalid calendar: gregorian Expected SameValue(«-1», Â«-1») to be false'
@@ -1985,24 +1958,12 @@ test/intl402/Locale/prototype/prop-desc.js:
 test/intl402/Locale/prototype/toStringTag.js:
   default: "TypeError: undefined is not an object (evaluating 'Intl.Locale.prototype')"
   strict mode: "TypeError: undefined is not an object (evaluating 'Intl.Locale.prototype')"
-test/intl402/Number/prototype/toLocaleString/default-options-object-prototype.js:
-  default: 'Test262Error: Expected SameValue(«1.2», Â«1.23») to be true'
-  strict mode: 'Test262Error: Expected SameValue(«1.2», Â«1.23») to be true'
 test/intl402/Number/prototype/toLocaleString/returns-same-results-as-NumberFormat.js:
   default: 'Error: Failed to format a number.'
   strict mode: 'Error: Failed to format a number.'
-test/intl402/NumberFormat/default-options-object-prototype.js:
-  default: 'Test262Error: Expected SameValue(«1», Â«3») to be true'
-  strict mode: 'Test262Error: Expected SameValue(«1», Â«3») to be true'
 test/intl402/NumberFormat/length.js:
   default: 'Test262Error: Expected obj[length] to have configurable:true.'
   strict mode: 'Test262Error: Expected obj[length] to have configurable:true.'
-test/intl402/NumberFormat/prototype/constructor/prop-desc.js:
-  default: "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(obj, name).enumerable')"
-  strict mode: "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(obj, name).enumerable')"
-test/intl402/NumberFormat/prototype/constructor/value.js:
-  default: 'Test262Error: Intl.NumberFormat.prototype.constructor is not the same as Intl.NumberFormat Expected SameValue(«function Object() {'
-  strict mode: 'Test262Error: Intl.NumberFormat.prototype.constructor is not the same as Intl.NumberFormat Expected SameValue(«function Object() {'
 test/intl402/NumberFormat/prototype/format/bound-to-numberformat-instance.js:
   default: 'Error: Failed to format a number.'
   strict mode: 'Error: Failed to format a number.'
@@ -2042,12 +2003,6 @@ test/intl402/PluralRules/default-options-object-prototype.js:
 test/intl402/PluralRules/length.js:
   default: 'Test262Error: Expected obj[length] to have configurable:true.'
   strict mode: 'Test262Error: Expected obj[length] to have configurable:true.'
-test/intl402/PluralRules/prototype/constructor/prop-desc.js:
-  default: 'Test262Error: Expected obj[constructor] to have configurable:true.'
-  strict mode: 'Test262Error: Expected obj[constructor] to have configurable:true.'
-test/intl402/String/prototype/localeCompare/default-options-object-prototype.js:
-  default: 'Test262Error: Expected SameValue(«0», Â«-1») to be true'
-  strict mode: 'Test262Error: Expected SameValue(«0», Â«-1») to be true'
 test/intl402/TypedArray/prototype/toLocaleString/calls-toLocaleString-number-elements.js:
   default: 'Test262Error: Expected SameValue(«0», Â«à¹\90.à¹\90à¹\90à¹\90») to be true (Testing with Float64Array.)'
   strict mode: 'Test262Error: Expected SameValue(«0», Â«à¹\90.à¹\90à¹\90à¹\90») to be true (Testing with Float64Array.)'
@@ -2057,15 +2012,6 @@ test/intl402/fallback-locales-are-supported.js:
 test/intl402/language-tags-canonicalized.js:
   default: 'Test262Error: For de-DD got de-DD; expected de-DE. (Testing with Collator.)'
   strict mode: 'Test262Error: For de-DD got de-DD; expected de-DE. (Testing with Collator.)'
-test/intl402/supportedLocalesOf-returned-array-elements-are-frozen.js:
-  default: 'Test262Error: Property length of object returned by SupportedLocales is writable. Expected SameValue(«true», Â«false») to be true (Testing with Collator.)'
-  strict mode: 'Test262Error: Property length of object returned by SupportedLocales is writable. Expected SameValue(«true», Â«false») to be true (Testing with Collator.)'
-test/intl402/supportedLocalesOf-taint-Array-2.js:
-  default: 'Test262Error: Client code can adversely affect behavior: setter for 0. (Testing with Collator.)'
-  strict mode: 'Test262Error: Client code can adversely affect behavior: setter for 0. (Testing with Collator.)'
-test/intl402/supportedLocalesOf-taint-Array.js:
-  default: 'Test262Error: Client code can adversely affect behavior: setter for 0. (Testing with Collator.)'
-  strict mode: 'Test262Error: Client code can adversely affect behavior: setter for 0. (Testing with Collator.)'
 test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-arguments.js:
   default: 'Test262Error: Expected obj[0] to have enumerable:false.'
 test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-param.js:
index 98916bf..2ce1d0a 100644 (file)
@@ -1,3 +1,19 @@
+2018-05-13  Andy VanWagoner  <andy@vanwagoner.family>
+
+        [INTL] Improve spec & test262 compliance for Intl APIs
+        https://bugs.webkit.org/show_bug.cgi?id=185578
+
+        Reviewed by Yusuke Suzuki.
+
+        Update Intl tests for prototype changes.
+
+        * js/intl-collator-expected.txt:
+        * js/intl-datetimeformat-expected.txt:
+        * js/intl-numberformat-expected.txt:
+        * js/script-tests/intl-collator.js:
+        * js/script-tests/intl-datetimeformat.js:
+        * js/script-tests/intl-numberformat.js:
+
 2018-05-13  Dirk Schulze  <krit@webkit.org>
 
         Implement SVGGeometryElement's isPointInFill and isPointInStroke
index 6374352..c483dad 100644 (file)
@@ -130,9 +130,13 @@ PASS Intl.Collator.supportedLocalesOf('x-12345-12345-en-US') did not throw excep
 PASS Intl.Collator.supportedLocalesOf('x-en-US-12345-12345') did not throw exception.
 PASS Intl.Collator.supportedLocalesOf('x-en-u-foo') did not throw exception.
 PASS Intl.Collator.supportedLocalesOf('x-en-u-foo-u-bar') did not throw exception.
-PASS Intl.Collator.prototype.constructor is Object
 PASS Object.getPrototypeOf(Intl.Collator.prototype) is Object.prototype
+PASS Intl.Collator.prototype.constructor is Intl.Collator
+PASS Intl.Collator.prototype[Symbol.toStringTag] is 'Object'
 PASS Object.prototype.toString.call(Intl.Collator.prototype) is '[object Object]'
+PASS Object.getOwnPropertyDescriptor(Intl.Collator.prototype, Symbol.toStringTag).writable is false
+PASS Object.getOwnPropertyDescriptor(Intl.Collator.prototype, Symbol.toStringTag).enumerable is false
+PASS Object.getOwnPropertyDescriptor(Intl.Collator.prototype, Symbol.toStringTag).configurable is true
 PASS defaultCollator.compare is an instance of Function
 PASS Object.getOwnPropertyDescriptor(Intl.Collator.prototype, 'compare').get is an instance of Function
 PASS Object.getOwnPropertyDescriptor(Intl.Collator.prototype, 'compare').set is undefined
index 9afa11d..7c857cc 100644 (file)
@@ -62,9 +62,13 @@ PASS Intl.DateTimeFormat.supportedLocalesOf('x-12345-12345-en-US') did not throw
 PASS Intl.DateTimeFormat.supportedLocalesOf('x-en-US-12345-12345') did not throw exception.
 PASS Intl.DateTimeFormat.supportedLocalesOf('x-en-u-foo') did not throw exception.
 PASS Intl.DateTimeFormat.supportedLocalesOf('x-en-u-foo-u-bar') did not throw exception.
-PASS Intl.DateTimeFormat.prototype.constructor is Object
 PASS Object.getPrototypeOf(Intl.DateTimeFormat.prototype) is Object.prototype
+PASS Intl.DateTimeFormat.prototype.constructor is Intl.DateTimeFormat
+PASS Intl.DateTimeFormat.prototype[Symbol.toStringTag] is 'Object'
 PASS Object.prototype.toString.call(Intl.DateTimeFormat.prototype) is '[object Object]'
+PASS Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, Symbol.toStringTag).writable is false
+PASS Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, Symbol.toStringTag).enumerable is false
+PASS Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, Symbol.toStringTag).configurable is true
 PASS defaultDTFormat.format is an instance of Function
 PASS Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, 'format').get is an instance of Function
 PASS Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, 'format').set is undefined
index ca3587d..54460e8 100644 (file)
@@ -130,9 +130,13 @@ PASS Intl.NumberFormat.supportedLocalesOf('x-12345-12345-en-US') did not throw e
 PASS Intl.NumberFormat.supportedLocalesOf('x-en-US-12345-12345') did not throw exception.
 PASS Intl.NumberFormat.supportedLocalesOf('x-en-u-foo') did not throw exception.
 PASS Intl.NumberFormat.supportedLocalesOf('x-en-u-foo-u-bar') did not throw exception.
-PASS Intl.NumberFormat.prototype.constructor is Object
 PASS Object.getPrototypeOf(Intl.NumberFormat.prototype) is Object.prototype
+PASS Intl.NumberFormat.prototype.constructor is Intl.NumberFormat
+PASS Intl.NumberFormat.prototype[Symbol.toStringTag] is 'Object'
 PASS Object.prototype.toString.call(Intl.NumberFormat.prototype) is '[object Object]'
+PASS Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, Symbol.toStringTag).writable is false
+PASS Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, Symbol.toStringTag).enumerable is false
+PASS Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, Symbol.toStringTag).configurable is true
 PASS defaultNFormat.format is an instance of Function
 PASS Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, 'format').get is an instance of Function
 PASS Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, 'format').set is undefined
index 3782b2e..cb3ccf3 100644 (file)
@@ -215,10 +215,21 @@ for (var validLanguageTag of validLanguageTags) {
 
 // 10.3 Properties of the Intl.Collator Prototype Object
 
-// is a plain object
-shouldBe("Intl.Collator.prototype.constructor", "Object");
+// The Intl.Collator prototype object is itself an ordinary object.
 shouldBe("Object.getPrototypeOf(Intl.Collator.prototype)", "Object.prototype");
+
+// 10.3.1 Intl.Collator.prototype.constructor
+// The initial value of Intl.Collator.prototype.constructor is the intrinsic object %Collator%.
+shouldBe("Intl.Collator.prototype.constructor", "Intl.Collator");
+
+// 10.3.2 Intl.Collator.prototype [ @@toStringTag ]
+// The initial value of the @@toStringTag property is the string value "Object".
+shouldBe("Intl.Collator.prototype[Symbol.toStringTag]", "'Object'");
 shouldBe("Object.prototype.toString.call(Intl.Collator.prototype)", "'[object Object]'");
+// This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+shouldBeFalse("Object.getOwnPropertyDescriptor(Intl.Collator.prototype, Symbol.toStringTag).writable");
+shouldBeFalse("Object.getOwnPropertyDescriptor(Intl.Collator.prototype, Symbol.toStringTag).enumerable");
+shouldBeTrue("Object.getOwnPropertyDescriptor(Intl.Collator.prototype, Symbol.toStringTag).configurable");
 
 // 10.3.3 Intl.Collator.prototype.compare
 
index cbeec6c..a006993 100644 (file)
@@ -99,14 +99,25 @@ for (var validLanguageTag of validLanguageTags) {
     shouldNotThrow("Intl.DateTimeFormat.supportedLocalesOf('" + validLanguageTag + "')");
 }
 
-// 12.3 Properties of the Intl.DateTimeFormat Prototype Object
+// 12.4 Properties of the Intl.DateTimeFormat Prototype Object
 
-// is a plain object
-shouldBe("Intl.DateTimeFormat.prototype.constructor", "Object");
+// The Intl.DateTimeFormat prototype object is itself an ordinary object.
 shouldBe("Object.getPrototypeOf(Intl.DateTimeFormat.prototype)", "Object.prototype");
+
+// 12.4.1 Intl.DateTimeFormat.prototype.constructor
+// The initial value of Intl.DateTimeFormat.prototype.constructor is the intrinsic object %DateTimeFormat%.
+shouldBe("Intl.DateTimeFormat.prototype.constructor", "Intl.DateTimeFormat");
+
+// 12.4.2 Intl.DateTimeFormat.prototype [ @@toStringTag ]
+// The initial value of the @@toStringTag property is the string value "Object".
+shouldBe("Intl.DateTimeFormat.prototype[Symbol.toStringTag]", "'Object'");
 shouldBe("Object.prototype.toString.call(Intl.DateTimeFormat.prototype)", "'[object Object]'");
+// This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+shouldBeFalse("Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, Symbol.toStringTag).writable");
+shouldBeFalse("Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, Symbol.toStringTag).enumerable");
+shouldBeTrue("Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, Symbol.toStringTag).configurable");
 
-// 12.3.3 Intl.DateTimeFormat.prototype.format
+// 12.4.3 Intl.DateTimeFormat.prototype.format
 
 // This named accessor property returns a function that formats a date according to the effective locale and the formatting options of this DateTimeFormat object.
 var defaultDTFormat = Intl.DateTimeFormat();
@@ -601,4 +612,3 @@ shouldBe(`JSON.stringify(
   {"type":"literal","value":" "},
   {"type":"timeZoneName","value":"Pacific Standard Time"}
 ])`)
-
index dd15e73..aa2af9f 100644 (file)
@@ -215,14 +215,25 @@ for (var validLanguageTag of validLanguageTags) {
     shouldNotThrow("Intl.NumberFormat.supportedLocalesOf('" + validLanguageTag + "')");
 }
 
-// 11.3 Properties of the Intl.NumberFormat Prototype Object
+// 11.4 Properties of the Intl.NumberFormat Prototype Object
 
-// is a plain object
-shouldBe("Intl.NumberFormat.prototype.constructor", "Object");
+// The Intl.NumberFormat prototype object is itself an ordinary object.
 shouldBe("Object.getPrototypeOf(Intl.NumberFormat.prototype)", "Object.prototype");
+
+// 11.4.1 Intl.NumberFormat.prototype.constructor
+// The initial value of Intl.NumberFormat.prototype.constructor is the intrinsic object %NumberFormat%.
+shouldBe("Intl.NumberFormat.prototype.constructor", "Intl.NumberFormat");
+
+// 11.4.2 Intl.NumberFormat.prototype [ @@toStringTag ]
+// The initial value of the @@toStringTag property is the string value "Object".
+shouldBe("Intl.NumberFormat.prototype[Symbol.toStringTag]", "'Object'");
 shouldBe("Object.prototype.toString.call(Intl.NumberFormat.prototype)", "'[object Object]'");
+// This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+shouldBeFalse("Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, Symbol.toStringTag).writable");
+shouldBeFalse("Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, Symbol.toStringTag).enumerable");
+shouldBeTrue("Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, Symbol.toStringTag).configurable");
 
-// 11.3.3 Intl.NumberFormat.prototype.format
+// 11.4.3 Intl.NumberFormat.prototype.format
 
 // This named accessor property returns a function that formats a number according to the effective locale and the formatting options of this NumberFormat object.
 var defaultNFormat = Intl.NumberFormat();
index e76ffa3..01f57c7 100644 (file)
@@ -1,3 +1,43 @@
+2018-05-13  Andy VanWagoner  <andy@vanwagoner.family>
+
+        [INTL] Improve spec & test262 compliance for Intl APIs
+        https://bugs.webkit.org/show_bug.cgi?id=185578
+
+        Reviewed by Yusuke Suzuki.
+
+        Use putDirectIndex over push for lists to arrays.
+        Update default options to construct with a null prototype.
+        Define constructor and toStringTag on prototypes.
+        Add proper time clipping.
+        Remove some outdated comment spec text, use url instead.
+
+        * runtime/IntlCollator.cpp:
+        (JSC::IntlCollator::initializeCollator):
+        * runtime/IntlCollatorConstructor.cpp:
+        (JSC::IntlCollatorConstructor::finishCreation):
+        * runtime/IntlCollatorPrototype.cpp:
+        (JSC::IntlCollatorPrototype::finishCreation):
+        * runtime/IntlDateTimeFormatConstructor.cpp:
+        (JSC::IntlDateTimeFormatConstructor::finishCreation):
+        * runtime/IntlDateTimeFormatPrototype.cpp:
+        (JSC::IntlDateTimeFormatPrototype::finishCreation):
+        (JSC::IntlDateTimeFormatFuncFormatDateTime):
+        (JSC::IntlDateTimeFormatPrototypeFuncFormatToParts):
+        * runtime/IntlNumberFormat.cpp:
+        (JSC::IntlNumberFormat::initializeNumberFormat):
+        * runtime/IntlNumberFormatConstructor.cpp:
+        (JSC::IntlNumberFormatConstructor::finishCreation):
+        * runtime/IntlNumberFormatPrototype.cpp:
+        (JSC::IntlNumberFormatPrototype::finishCreation):
+        * runtime/IntlObject.cpp:
+        (JSC::lookupSupportedLocales):
+        (JSC::supportedLocales):
+        (JSC::intlObjectFuncGetCanonicalLocales):
+        * runtime/IntlPluralRules.cpp:
+        (JSC::IntlPluralRules::resolvedOptions):
+        * runtime/IntlPluralRulesConstructor.cpp:
+        (JSC::IntlPluralRulesConstructor::finishCreation):
+
 2018-05-11  Caio Lima  <ticaiolima@gmail.com>
 
         [ESNext][BigInt] Implement support for "*" operation
index 7208b2d..f735086 100644 (file)
@@ -178,32 +178,22 @@ void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue
     VM& vm = state.vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    // 10.1.1 InitializeCollator (collator, locales, options) (ECMA-402 2.0)
-    // 1. If collator has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception.
-    // 2. Set collator.[[initializedIntlObject]] to true.
+    // 10.1.1 InitializeCollator (collator, locales, options) (ECMA-402)
+    // https://tc39.github.io/ecma402/#sec-initializecollator
 
-    // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
     auto requestedLocales = canonicalizeLocaleList(state, locales);
-    // 4. ReturnIfAbrupt(requestedLocales).
     RETURN_IF_EXCEPTION(scope, void());
 
-    // 5. If options is undefined, then
     JSObject* options;
-    if (optionsValue.isUndefined()) {
-        // a. Let options be ObjectCreate(%ObjectPrototype%).
-        options = constructEmptyObject(&state);
-    } else { // 6. Else
-        // a. Let options be ToObject(options).
+    if (optionsValue.isUndefined())
+        options = constructEmptyObject(&state, state.lexicalGlobalObject()->nullPrototypeObjectStructure());
+    else {
         options = optionsValue.toObject(&state);
-        // b. ReturnIfAbrupt(options).
         RETURN_IF_EXCEPTION(scope, void());
     }
 
-    // 7. Let u be GetOption(options, "usage", "string", «"sort", "search"», "sort").
     String usageString = intlStringOption(state, options, vm.propertyNames->usage, { "sort", "search" }, "usage must be either \"sort\" or \"search\"", "sort");
-    // 8. ReturnIfAbrupt(u).
     RETURN_IF_EXCEPTION(scope, void());
-    // 9. Set collator.[[usage]] to u.
     if (usageString == "sort")
         m_usage = Usage::Sort;
     else if (usageString == "search")
@@ -211,37 +201,14 @@ void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue
     else
         ASSERT_NOT_REACHED();
 
-    // 10. If u is "sort", then
-    // a. Let localeData be the value of %Collator%.[[sortLocaleData]];
-    // 11. Else
-    // a. Let localeData be the value of %Collator%.[[searchLocaleData]].
-    Vector<String> (*localeData)(const String&, size_t);
-    if (m_usage == Usage::Sort)
-        localeData = sortLocaleData;
-    else
-        localeData = searchLocaleData;
+    auto localeData = (m_usage == Usage::Sort) ? sortLocaleData : searchLocaleData;
 
-    // 12. Let opt be a new Record.
     HashMap<String, String> opt;
 
-    // 13. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
     String matcher = intlStringOption(state, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
-    // 14. ReturnIfAbrupt(matcher).
     RETURN_IF_EXCEPTION(scope, void());
-    // 15. Set opt.[[localeMatcher]] to matcher.
     opt.add(ASCIILiteral("localeMatcher"), matcher);
 
-    // 16. For each row in Table 1, except the header row, do:
-    // a. Let key be the name given in the Key column of the row.
-    // b. Let prop be the name given in the Property column of the row.
-    // c. Let type be the string given in the Type column of the row.
-    // d. Let list be a List containing the Strings given in the Values column of the row, or undefined if no strings are given.
-    // e. Let value be GetOption(options, prop, type, list, undefined).
-    // f. ReturnIfAbrupt(value).
-    // g. If the string given in the Type column of the row is "boolean" and value is not undefined, then
-    //    i. Let value be ToString(value).
-    //    ii. ReturnIfAbrupt(value).
-    // h. Set opt.[[<key>]] to value.
     {
         String numericString;
         bool usesFallback;
@@ -257,35 +224,15 @@ void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue
         opt.add(ASCIILiteral("kf"), caseFirst);
     }
 
-    // 17. Let relevantExtensionKeys be the value of %Collator%.[[relevantExtensionKeys]].
-    // 18. Let r be ResolveLocale(%Collator%.[[availableLocales]], requestedLocales, opt, relevantExtensionKeys, localeData).
     auto& availableLocales = state.jsCallee()->globalObject()->intlCollatorAvailableLocales();
     auto result = resolveLocale(state, availableLocales, requestedLocales, opt, relevantCollatorExtensionKeys, WTF_ARRAY_LENGTH(relevantCollatorExtensionKeys), localeData);
 
-    // 19. Set collator.[[locale]] to the value of r.[[locale]].
     m_locale = result.get(ASCIILiteral("locale"));
     if (m_locale.isEmpty()) {
         throwTypeError(&state, scope, ASCIILiteral("failed to initialize Collator due to invalid locale"));
         return;
     }
 
-    // 20. Let k be 0.
-    // 21. Let lenValue be Get(relevantExtensionKeys, "length").
-    // 22. Let len be ToLength(lenValue).
-    // 23. Repeat while k < len:
-    // a. Let Pk be ToString(k).
-    // b. Let key be Get(relevantExtensionKeys, Pk).
-    // c. ReturnIfAbrupt(key).
-    // d. If key is "co", then
-    //    i. Let property be "collation".
-    //    ii. Let value be the value of r.[[co]].
-    //    iii. If value is null, let value be "default".
-    // e. Else use the row of Table 1 that contains the value of key in the Key column:
-    //    i. Let property be the name given in the Property column of the row.
-    //    ii. Let value be the value of r.[[<key>]].
-    //    iii. If the name given in the Type column of the row is "boolean", let value be the result of comparing value with "true".
-    // f. Set collator.[[<property>]] to value.
-    // g. Increase k by 1.
     const String& collation = result.get(ASCIILiteral("co"));
     m_collation = collation.isNull() ? ASCIILiteral("default") : collation;
     m_numeric = result.get(ASCIILiteral("kn")) == "true";
@@ -298,18 +245,8 @@ void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue
     else
         m_caseFirst = CaseFirst::False;
 
-    // 24. Let s be GetOption(options, "sensitivity", "string", «"base", "accent", "case", "variant"», undefined).
     String sensitivityString = intlStringOption(state, options, vm.propertyNames->sensitivity, { "base", "accent", "case", "variant" }, "sensitivity must be either \"base\", \"accent\", \"case\", or \"variant\"", nullptr);
-    // 25. ReturnIfAbrupt(s).
     RETURN_IF_EXCEPTION(scope, void());
-    // 26. If s is undefined, then
-    // a. If u is "sort", then let s be "variant".
-    // b. Else
-    //    i. Let dataLocale be the value of r.[[dataLocale]].
-    //    ii. Let dataLocaleData be Get(localeData, dataLocale).
-    //    iii. Let s be Get(dataLocaleData, "sensitivity").
-    //    10.2.3 "[[searchLocaleData]][locale] must have a sensitivity property with a String value equal to "base", "accent", "case", or "variant" for all locale values."
-    // 27. Set collator.[[sensitivity]] to s.
     if (sensitivityString == "base")
         m_sensitivity = Sensitivity::Base;
     else if (sensitivityString == "accent")
@@ -319,21 +256,14 @@ void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue
     else
         m_sensitivity = Sensitivity::Variant;
 
-    // 28. Let ip be GetOption(options, "ignorePunctuation", "boolean", undefined, false).
     bool usesFallback;
     bool ignorePunctuation = intlBooleanOption(state, options, vm.propertyNames->ignorePunctuation, usesFallback);
     if (usesFallback)
         ignorePunctuation = false;
-    // 29. ReturnIfAbrupt(ip).
     RETURN_IF_EXCEPTION(scope, void());
-    // 30. Set collator.[[ignorePunctuation]] to ip.
     m_ignorePunctuation = ignorePunctuation;
 
-    // 31. Set collator.[[boundCompare]] to undefined.
-    // 32. Set collator.[[initializedCollator]] to true.
     m_initializedCollator = true;
-
-    // 33. Return collator.
 }
 
 void IntlCollator::createCollator(ExecState& state)
index 78f189f..86ae3f0 100644 (file)
@@ -82,6 +82,7 @@ void IntlCollatorConstructor::finishCreation(VM& vm, IntlCollatorPrototype* coll
     Base::finishCreation(vm, ASCIILiteral("Collator"));
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, collatorPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
+    collatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
     m_collatorStructure.set(vm, this, collatorStructure);
 }
 
index ad59c8e..bf47529 100644 (file)
@@ -74,6 +74,8 @@ IntlCollatorPrototype::IntlCollatorPrototype(VM& vm, Structure* structure)
 void IntlCollatorPrototype::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
+
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Object"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
 }
 
 static EncodedJSValue JSC_HOST_CALL IntlCollatorFuncCompare(ExecState* state)
index 2919ece..5351e43 100644 (file)
@@ -82,6 +82,7 @@ void IntlDateTimeFormatConstructor::finishCreation(VM& vm, IntlDateTimeFormatPro
     Base::finishCreation(vm, ASCIILiteral("DateTimeFormat"));
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, dateTimeFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
+    dateTimeFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
     m_dateTimeFormatStructure.set(vm, this, dateTimeFormatStructure);
 }
 
index 4724b2b..9b7971a 100644 (file)
@@ -37,6 +37,7 @@
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSObjectInlines.h"
+#include <wtf/DateMath.h>
 
 namespace JSC {
 
@@ -87,33 +88,29 @@ void IntlDateTimeFormatPrototype::finishCreation(VM& vm, JSGlobalObject* globalO
 #else
     UNUSED_PARAM(globalObject);
 #endif
+
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Object"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
 }
 
 static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatFuncFormatDateTime(ExecState* state)
 {
     VM& vm = state->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    // 12.3.4 DateTime Format Functions (ECMA-402 2.0)
-    // 1. Let dtf be the this value.
-    // 2. Assert: Type(dtf) is Object and dtf has an [[initializedDateTimeFormat]] internal slot whose value is true.
+    // 12.1.7 DateTime Format Functions (ECMA-402)
+    // https://tc39.github.io/ecma402/#sec-formatdatetime
+
     IntlDateTimeFormat* format = jsCast<IntlDateTimeFormat*>(state->thisValue());
 
     JSValue date = state->argument(0);
     double value;
 
-    // 3. If date is not provided or is undefined, then
-    if (date.isUndefined()) {
-        // a. Let x be %Date_now%().
+    if (date.isUndefined())
         value = JSValue::decode(dateNow(state)).toNumber(state);
-    } else {
-        // 4. Else
-        // a. Let x be ToNumber(date).
-        value = date.toNumber(state);
-        // b. ReturnIfAbrupt(x).
+    else {
+        value = WTF::timeClip(date.toNumber(state));
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
     }
 
-    // 5. Return FormatDateTime(dtf, x).
     scope.release();
     return JSValue::encode(format->format(*state, value));
 }
@@ -175,7 +172,7 @@ EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncFormatToParts(ExecSt
     if (date.isUndefined())
         value = JSValue::decode(dateNow(state)).toNumber(state);
     else {
-        value = date.toNumber(state);
+        value = WTF::timeClip(date.toNumber(state));
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
     }
 
index 185ac36..b18fd0f 100644 (file)
@@ -157,62 +157,42 @@ static unsigned computeCurrencyDigits(const String& currency)
 
 void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales, JSValue optionsValue)
 {
-    // 11.1.1 InitializeNumberFormat (numberFormat, locales, options) (ECMA-402 2.0)
     VM& vm = state.vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    // 1. If numberFormat has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception.
-    // 2. Set numberFormat.[[initializedIntlObject]] to true.
+    // 11.1.2 InitializeNumberFormat (numberFormat, locales, options) (ECMA-402)
+    // https://tc39.github.io/ecma402/#sec-initializenumberformat
 
-    // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
     auto requestedLocales = canonicalizeLocaleList(state, locales);
-    // 4. ReturnIfAbrupt(requestedLocales).
     RETURN_IF_EXCEPTION(scope, void());
 
-    // 5. If options is undefined, then
     JSObject* options;
-    if (optionsValue.isUndefined()) {
-        // a. Let options be ObjectCreate(%ObjectPrototype%).
-        options = constructEmptyObject(&state);
-    } else { // 6. Else
-        // a. Let options be ToObject(options).
+    if (optionsValue.isUndefined())
+        options = constructEmptyObject(&state, state.lexicalGlobalObject()->nullPrototypeObjectStructure());
+    else {
         options = optionsValue.toObject(&state);
-        // b. ReturnIfAbrupt(options).
         RETURN_IF_EXCEPTION(scope, void());
     }
 
-    // 7. Let opt be a new Record.
     HashMap<String, String> opt;
 
-    // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
     String matcher = intlStringOption(state, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
-    // 9. ReturnIfAbrupt(matcher).
     RETURN_IF_EXCEPTION(scope, void());
-    // 10. Set opt.[[localeMatcher]] to matcher.
     opt.add(ASCIILiteral("localeMatcher"), matcher);
 
-    // 11. Let localeData be %NumberFormat%.[[localeData]].
-    // 12. Let r be ResolveLocale(%NumberFormat%.[[availableLocales]], requestedLocales, opt, %NumberFormat%.[[relevantExtensionKeys]], localeData).
     auto& availableLocales = state.jsCallee()->globalObject()->intlNumberFormatAvailableLocales();
     auto result = resolveLocale(state, availableLocales, requestedLocales, opt, relevantNumberExtensionKeys, WTF_ARRAY_LENGTH(relevantNumberExtensionKeys), IntlNFInternal::localeData);
 
-    // 13. Set numberFormat.[[locale]] to the value of r.[[locale]].
     m_locale = result.get(ASCIILiteral("locale"));
     if (m_locale.isEmpty()) {
         throwTypeError(&state, scope, ASCIILiteral("failed to initialize NumberFormat due to invalid locale"));
         return;
     }
 
-    // 14. Set numberFormat.[[numberingSystem]] to the value of r.[[nu]].
     m_numberingSystem = result.get(ASCIILiteral("nu"));
 
-    // 15. Let dataLocale be r.[[dataLocale]].
-
-    // 16. Let s be GetOption(options, "style", "string", « "decimal", "percent", "currency"», "decimal").
     String styleString = intlStringOption(state, options, Identifier::fromString(&vm, "style"), { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal");
-    // 17. ReturnIfAbrupt(s).
     RETURN_IF_EXCEPTION(scope, void());
-    // 18. Set numberFormat.[[style]] to s.
     if (styleString == "decimal")
         m_style = Style::Decimal;
     else if (styleString == "percent")
@@ -222,13 +202,9 @@ void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales,
     else
         ASSERT_NOT_REACHED();
 
-    // 19. Let c be GetOption(options, "currency", "string", undefined, undefined).
     String currency = intlStringOption(state, options, Identifier::fromString(&vm, "currency"), { }, nullptr, nullptr);
-    // 20. ReturnIfAbrupt(c).
     RETURN_IF_EXCEPTION(scope, void());
-    // 21. If c is not undefined, then
     if (!currency.isNull()) {
-        // a. If the result of IsWellFormedCurrencyCode(c), is false, then throw a RangeError exception.
         if (currency.length() != 3 || !currency.isAllSpecialCharacters<isASCIIAlpha>()) {
             throwException(&state, scope, createRangeError(&state, ASCIILiteral("currency is not a well-formed currency code")));
             return;
@@ -237,26 +213,18 @@ void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales,
 
     unsigned currencyDigits = 0;
     if (m_style == Style::Currency) {
-        // 22. If s is "currency" and c is undefined, throw a TypeError exception.
         if (currency.isNull()) {
             throwTypeError(&state, scope, ASCIILiteral("currency must be a string"));
             return;
         }
 
-        // 23. If s is "currency", then
-        // a. Let c be converting c to upper case as specified in 6.1.
         currency = currency.convertToASCIIUppercase();
-        // b. Set numberFormat.[[currency]] to c.
         m_currency = currency;
-        // c. Let cDigits be CurrencyDigits(c)
         currencyDigits = computeCurrencyDigits(currency);
     }
 
-    // 24. Let cd be GetOption(options, "currencyDisplay", "string", «"code", "symbol", "name"», "symbol").
     String currencyDisplayString = intlStringOption(state, options, Identifier::fromString(&vm, "currencyDisplay"), { "code", "symbol", "name" }, "currencyDisplay must be either \"code\", \"symbol\", or \"name\"", "symbol");
-    // 25. ReturnIfAbrupt(cd).
     RETURN_IF_EXCEPTION(scope, void());
-    // 26. If s is "currency", set numberFormat.[[currencyDisplay]] to cd.
     if (m_style == Style::Currency) {
         if (currencyDisplayString == "code")
             m_currencyDisplay = CurrencyDisplay::Code;
@@ -268,88 +236,51 @@ void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales,
             ASSERT_NOT_REACHED();
     }
 
-    // 27. Let mnid be GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1).
-    // 28. ReturnIfAbrupt(mnid).
-    // 29. Set numberFormat.[[minimumIntegerDigits]] to mnid.
     unsigned minimumIntegerDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumIntegerDigits"), 1, 21, 1);
     RETURN_IF_EXCEPTION(scope, void());
     m_minimumIntegerDigits = minimumIntegerDigits;
 
-    // 30. If s is "currency", let mnfdDefault be cDigits; else let mnfdDefault be 0.
     unsigned minimumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : 0;
 
-    // 31. Let mnfd be GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault).
-    // 32. ReturnIfAbrupt(mnfd).
-    // 33. Set numberFormat.[[minimumFractionDigits]] to mnfd.
     unsigned minimumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault);
     RETURN_IF_EXCEPTION(scope, void());
     m_minimumFractionDigits = minimumFractionDigits;
 
-    // 34. If s is "currency", let mxfdDefault be max(mnfd, cDigits);
     unsigned maximumFractionDigitsDefault;
     if (m_style == Style::Currency)
         maximumFractionDigitsDefault = std::max(minimumFractionDigits, currencyDigits);
-    else if (m_style == Style::Percent) // else if s is "percent", let mxfdDefault be max(mnfd, 0);
+    else if (m_style == Style::Percent)
         maximumFractionDigitsDefault = minimumFractionDigits;
-    else // else let mxfdDefault be max(mnfd, 3).
+    else
         maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u);
 
-    // 35. Let mxfd be GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault).
-    // 36. ReturnIfAbrupt(mxfd).
-    // 37. Set numberFormat.[[maximumFractionDigits]] to mxfd.
     unsigned maximumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault);
     RETURN_IF_EXCEPTION(scope, void());
     m_maximumFractionDigits = maximumFractionDigits;
 
-    // 38. Let mnsd be Get(options, "minimumSignificantDigits").
     JSValue minimumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "minimumSignificantDigits"));
-    // 39. ReturnIfAbrupt(mnsd).
     RETURN_IF_EXCEPTION(scope, void());
 
-    // 40. Let mxsd be Get(options, "maximumSignificantDigits").
     JSValue maximumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "maximumSignificantDigits"));
-    // 41. ReturnIfAbrupt(mxsd).
     RETURN_IF_EXCEPTION(scope, void());
 
-    // 42. If mnsd is not undefined or mxsd is not undefined, then
     if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) {
-        // a. Let mnsd be GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1).
         unsigned minimumSignificantDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumSignificantDigits"), 1, 21, 1);
-        // b. ReturnIfAbrupt(mnsd).
         RETURN_IF_EXCEPTION(scope, void());
-        // c. Let mxsd be GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21).
         unsigned maximumSignificantDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21);
-        // d. ReturnIfAbrupt(mxsd).
         RETURN_IF_EXCEPTION(scope, void());
-        // e. Set numberFormat.[[minimumSignificantDigits]] to mnsd.
         m_minimumSignificantDigits = minimumSignificantDigits;
-        // f. Set numberFormat.[[maximumSignificantDigits]] to mxsd.
         m_maximumSignificantDigits = maximumSignificantDigits;
     }
 
-    // 43. Let g be GetOption(options, "useGrouping", "boolean", undefined, true).
     bool usesFallback;
     bool useGrouping = intlBooleanOption(state, options, Identifier::fromString(&vm, "useGrouping"), usesFallback);
     if (usesFallback)
         useGrouping = true;
-    // 44. ReturnIfAbrupt(g).
     RETURN_IF_EXCEPTION(scope, void());
-    // 45. Set numberFormat.[[useGrouping]] to g.
     m_useGrouping = useGrouping;
 
-    // Steps 46 - 51 are not necessary to our implementation.
-    // 46. Let dataLocaleData be Get(localeData, dataLocale).
-    // 47. Let patterns be Get(dataLocaleData, "patterns").
-    // 48. Assert: patterns is an object (see 11.2.3).
-    // 49. Let stylePatterns be Get(patterns, s).
-    // 50. Set numberFormat.[[positivePattern]] to Get(stylePatterns, "positivePattern").
-    // 51. Set numberFormat.[[negativePattern]] to Get(stylePatterns, "negativePattern").
-
-    // 52. Set numberFormat.[[boundFormat]] to undefined.
-    // 53. Set numberFormat.[[initializedNumberFormat]] to true.
     m_initializedNumberFormat = true;
-
-    // 54. Return numberFormat.
 }
 
 void IntlNumberFormat::createNumberFormat(ExecState& state)
index 2b30503..274703c 100644 (file)
@@ -82,6 +82,7 @@ void IntlNumberFormatConstructor::finishCreation(VM& vm, IntlNumberFormatPrototy
     Base::finishCreation(vm, ASCIILiteral("NumberFormat"));
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
+    numberFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
     m_numberFormatStructure.set(vm, this, numberFormatStructure);
 }
 
index 5cf177d..f8be6bc 100644 (file)
@@ -76,6 +76,8 @@ IntlNumberFormatPrototype::IntlNumberFormatPrototype(VM& vm, Structure* structur
 void IntlNumberFormatPrototype::finishCreation(VM& vm, Structure*)
 {
     Base::finishCreation(vm);
+
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Object"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
 }
 
 static EncodedJSValue JSC_HOST_CALL IntlNumberFormatFuncFormatNumber(ExecState* state)
index 86f938a..ac74d7a 100644 (file)
@@ -799,12 +799,13 @@ static JSArray* lookupSupportedLocales(ExecState& state, const HashSet<String>&
         return nullptr;
     }
 
+    unsigned index = 0;
     for (size_t k = 0; k < len; ++k) {
         const String& locale = requestedLocales[k];
         String noExtensionsLocale = removeUnicodeLocaleExtension(locale);
         String availableLocale = bestAvailableLocale(availableLocales, noExtensionsLocale);
         if (!availableLocale.isNull()) {
-            subset->push(&state, jsString(&state, locale));
+            subset->putDirectIndex(&state, index++, jsString(&state, locale));
             RETURN_IF_EXCEPTION(scope, nullptr);
         }
     }
@@ -854,6 +855,7 @@ JSValue supportedLocales(ExecState& state, const HashSet<String>& availableLocal
         supportedLocales->defineOwnProperty(supportedLocales, &state, keys[i], desc, true);
         RETURN_IF_EXCEPTION(scope, JSValue());
     }
+    supportedLocales->defineOwnProperty(supportedLocales, &state, vm.propertyNames->length, desc, true);
 
     return supportedLocales;
 }
@@ -902,17 +904,17 @@ EncodedJSValue JSC_HOST_CALL intlObjectFuncGetCanonicalLocales(ExecState* state)
 
     Vector<String> localeList = canonicalizeLocaleList(*state, state->argument(0));
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    auto length = localeList.size();
 
     JSGlobalObject* globalObject = state->jsCallee()->globalObject();
-    JSArray* localeArray = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
+    JSArray* localeArray = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), length);
     if (!localeArray) {
         throwOutOfMemoryError(state, scope);
         return encodedJSValue();
     }
 
-    auto length = localeList.size();
     for (size_t i = 0; i < length; ++i) {
-        localeArray->push(state, jsString(state, localeList[i]));
+        localeArray->putDirectIndex(state, i, jsString(state, localeList[i]));
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
     }
     return JSValue::encode(localeArray);
index 7b838f6..4ded13b 100644 (file)
@@ -226,9 +226,10 @@ JSObject* IntlPluralRules::resolvedOptions(ExecState& exec)
     int32_t resultLength;
 
     // Category names are always ASCII, so use char[].
+    unsigned index = 0;
     while (const char* result = uenum_next(keywords.get(), &resultLength, &status)) {
         ASSERT(U_SUCCESS(status));
-        categories->push(&exec, jsNontrivialString(&exec, String(result, resultLength)));
+        categories->putDirectIndex(&exec, index++, jsNontrivialString(&exec, String(result, resultLength)));
         RETURN_IF_EXCEPTION(scope, { });
     }
     options->putDirect(vm, Identifier::fromString(&vm, "pluralCategories"), categories);
index 4a9e769..9e50a9b 100644 (file)
@@ -80,7 +80,7 @@ void IntlPluralRulesConstructor::finishCreation(VM& vm, IntlPluralRulesPrototype
     Base::finishCreation(vm, ASCIILiteral("PluralRules"));
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, pluralRulesPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
-    pluralRulesPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
+    pluralRulesPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
     m_pluralRulesStructure.set(vm, this, pluralRulesStructure);
 }