Diff
Modified: trunk/LayoutTests/ChangeLog (197924 => 197925)
--- trunk/LayoutTests/ChangeLog 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/LayoutTests/ChangeLog 2016-03-10 05:28:34 UTC (rev 197925)
@@ -1,3 +1,18 @@
+2016-03-09 Andy VanWagoner <[email protected]>
+
+ [INTL] Intl Constructors not web compatible with Object.create usage
+ https://bugs.webkit.org/show_bug.cgi?id=153679
+
+ Reviewed by Darin Adler.
+
+ Add tests for Object.create + contructor.call initialization of NumberFormat
+ and DateTimeFormat objects.
+
+ * js/intl-datetimeformat-expected.txt:
+ * js/intl-numberformat-expected.txt:
+ * js/script-tests/intl-datetimeformat.js:
+ * js/script-tests/intl-numberformat.js:
+
2016-03-09 Ryosuke Niwa <[email protected]>
defineElement should upgrade existing unresolved custom elements
Modified: trunk/LayoutTests/js/intl-datetimeformat-expected.txt (197924 => 197925)
--- trunk/LayoutTests/js/intl-datetimeformat-expected.txt 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/LayoutTests/js/intl-datetimeformat-expected.txt 2016-03-10 05:28:34 UTC (rev 197925)
@@ -2147,6 +2147,9 @@
var resolved = Intl.DateTimeFormat("zh-TW", options).resolvedOptions();
Object.keys(options).every(option => resolved[option] != null) is true
PASS typeof Intl.DateTimeFormat("zh-TW", { hour: "numeric", minute: "numeric" }).format() === "string" is true
+PASS var legacy = Object.create(Intl.DateTimeFormat.prototype);Intl.DateTimeFormat.apply(legacy) is legacy
+PASS var legacy = Object.create(Intl.DateTimeFormat.prototype);Intl.DateTimeFormat.call(legacy, 'en-u-nu-arab', { timeZone: 'America/Los_Angeles' }).format(1451099872641) is '١٢/٢٥/٢٠١٥'
+PASS var incompat = {};Intl.DateTimeFormat.apply(incompat) is not incompat
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/intl-numberformat-expected.txt (197924 => 197925)
--- trunk/LayoutTests/js/intl-numberformat-expected.txt 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/LayoutTests/js/intl-numberformat-expected.txt 2016-03-10 05:28:34 UTC (rev 197925)
@@ -194,6 +194,9 @@
PASS Intl.NumberFormat.prototype.resolvedOptions() === Intl.NumberFormat.prototype.resolvedOptions() is false
PASS Intl.NumberFormat.prototype.resolvedOptions.call(5) threw exception TypeError: Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat.
PASS var options = Intl.NumberFormat.prototype.resolvedOptions(); delete options['locale']; JSON.stringify(options) is '{"numberingSystem":"latn","style":"decimal","minimumIntegerDigits":1,"minimumFractionDigits":0,"maximumFractionDigits":3,"useGrouping":true}'
+PASS var legacy = Object.create(Intl.NumberFormat.prototype);Intl.NumberFormat.apply(legacy) is legacy
+PASS var legacy = Object.create(Intl.NumberFormat.prototype);Intl.NumberFormat.call(legacy, 'en-u-nu-arab').format(1.2345) is '١٫٢٣٥'
+PASS var incompat = {};Intl.NumberFormat.apply(incompat) is not incompat
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/script-tests/intl-datetimeformat.js (197924 => 197925)
--- trunk/LayoutTests/js/script-tests/intl-datetimeformat.js 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/LayoutTests/js/script-tests/intl-datetimeformat.js 2016-03-10 05:28:34 UTC (rev 197925)
@@ -497,3 +497,9 @@
Object.keys(options).every(option => resolved[option] != null)`);
shouldBeTrue(`typeof Intl.DateTimeFormat("${locale}", { hour: "numeric", minute: "numeric" }).format() === "string"`);
}
+
+// Legacy compatibility with ECMA-402 1.0
+let legacyInit = "var legacy = Object.create(Intl.DateTimeFormat.prototype);";
+shouldBe(legacyInit + "Intl.DateTimeFormat.apply(legacy)", "legacy");
+shouldBe(legacyInit + "Intl.DateTimeFormat.call(legacy, 'en-u-nu-arab', { timeZone: 'America/Los_Angeles' }).format(1451099872641)", "'١٢/٢٥/٢٠١٥'");
+shouldNotBe("var incompat = {};Intl.DateTimeFormat.apply(incompat)", "incompat");
Modified: trunk/LayoutTests/js/script-tests/intl-numberformat.js (197924 => 197925)
--- trunk/LayoutTests/js/script-tests/intl-numberformat.js 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/LayoutTests/js/script-tests/intl-numberformat.js 2016-03-10 05:28:34 UTC (rev 197925)
@@ -338,3 +338,9 @@
// Returns the default options.
shouldBe("var options = Intl.NumberFormat.prototype.resolvedOptions(); delete options['locale']; JSON.stringify(options)", '\'{"numberingSystem":"latn","style":"decimal","minimumIntegerDigits":1,"minimumFractionDigits":0,"maximumFractionDigits":3,"useGrouping":true}\'');
+
+// Legacy compatibility with ECMA-402 1.0
+let legacyInit = "var legacy = Object.create(Intl.NumberFormat.prototype);";
+shouldBe(legacyInit + "Intl.NumberFormat.apply(legacy)", "legacy");
+shouldBe(legacyInit + "Intl.NumberFormat.call(legacy, 'en-u-nu-arab').format(1.2345)", "'١٫٢٣٥'");
+shouldNotBe("var incompat = {};Intl.NumberFormat.apply(incompat)", "incompat");
Modified: trunk/Source/_javascript_Core/ChangeLog (197924 => 197925)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-10 05:28:34 UTC (rev 197925)
@@ -1,3 +1,39 @@
+2016-03-09 Andy VanWagoner <[email protected]>
+
+ [INTL] Intl Constructors not web compatible with Object.create usage
+ https://bugs.webkit.org/show_bug.cgi?id=153679
+
+ Reviewed by Darin Adler.
+
+ Add workaround for initializing NumberFormat and DateTimeFormat objects
+ using Object.create followed by constructor.call. This is necessary for
+ backwards compatibility with libraries relying on v1 behavior of Intl
+ constructors.
+
+ Collator does not get the workaround, since polyfills do not include it,
+ and there are not any known instances of v2 incompatible libraries.
+
+ The workaround involves checking for an object that inherits from the
+ *Format constructor, but was not actually initialized with that type. A
+ substitute instance is created and attached to the object using a private
+ name. The prototype functions then check for the private property to use
+ in place of the original object.
+
+ Since this behavior is not part of the v2 spec, it should be removed as
+ soon as the incompatible behavior is no longer in common use.
+
+ * runtime/CommonIdentifiers.h:
+ * runtime/IntlDateTimeFormatConstructor.cpp:
+ (JSC::callIntlDateTimeFormat):
+ * runtime/IntlDateTimeFormatPrototype.cpp:
+ (JSC::IntlDateTimeFormatPrototypeGetterFormat):
+ (JSC::IntlDateTimeFormatPrototypeFuncResolvedOptions):
+ * runtime/IntlNumberFormatConstructor.cpp:
+ (JSC::callIntlNumberFormat):
+ * runtime/IntlNumberFormatPrototype.cpp:
+ (JSC::IntlNumberFormatPrototypeGetterFormat):
+ (JSC::IntlNumberFormatPrototypeFuncResolvedOptions):
+
2016-03-09 Saam barati <[email protected]>
Add proper JSON.stringify support for Proxy when the target is an array
Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (197924 => 197925)
--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2016-03-10 05:28:34 UTC (rev 197925)
@@ -359,6 +359,7 @@
macro(Collator) \
macro(DateTimeFormat) \
macro(NumberFormat) \
+ macro(intlSubstituteValue) \
macro(thisTimeValue) \
macro(newTargetLocal) \
macro(derivedConstructor) \
Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatConstructor.cpp (197924 => 197925)
--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatConstructor.cpp 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatConstructor.cpp 2016-03-10 05:28:34 UTC (rev 197925)
@@ -117,17 +117,35 @@
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
// NewTarget is always undefined when called as a function.
- // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%).
VM& vm = state->vm();
- IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, jsCast<IntlDateTimeFormatConstructor*>(state->callee()));
+ IntlDateTimeFormatConstructor* callee = jsCast<IntlDateTimeFormatConstructor*>(state->callee());
+ // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
+ JSValue thisValue = state->thisValue();
+ IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(thisValue);
+ if (!dateTimeFormat) {
+ JSValue prototype = callee->getDirect(vm, vm.propertyNames->prototype);
+ if (JSObject::defaultHasInstance(state, thisValue, prototype)) {
+ JSObject* thisObject = thisValue.toObject(state);
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ dateTimeFormat = IntlDateTimeFormat::create(vm, callee);
+ dateTimeFormat->initializeDateTimeFormat(*state, state->argument(0), state->argument(1));
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ thisObject->putDirect(vm, vm.propertyNames->intlSubstituteValuePrivateName, dateTimeFormat);
+ return JSValue::encode(thisValue);
+ }
+ }
+
+ // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%).
// 3. ReturnIfAbrupt(dateTimeFormat).
- ASSERT(dateTimeFormat);
+ dateTimeFormat = IntlDateTimeFormat::create(vm, callee);
// 4. Return InitializeDateTimeFormat(dateTimeFormat, locales, options).
- JSValue locales = state->argument(0);
- JSValue options = state->argument(1);
- dateTimeFormat->initializeDateTimeFormat(*state, locales, options);
+ dateTimeFormat->initializeDateTimeFormat(*state, state->argument(0), state->argument(1));
return JSValue::encode(dateTimeFormat);
}
Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatPrototype.cpp (197924 => 197925)
--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatPrototype.cpp 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatPrototype.cpp 2016-03-10 05:28:34 UTC (rev 197925)
@@ -117,6 +117,11 @@
// 12.3.3 Intl.DateTimeFormat.prototype.format (ECMA-402 2.0)
// 1. Let dtf be this DateTimeFormat object.
IntlDateTimeFormat* dtf = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
+
+ // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
+ if (!dtf)
+ dtf = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue().get(state, state->vm().propertyNames->intlSubstituteValuePrivateName));
+
// 2. ReturnIfAbrupt(dtf).
if (!dtf)
return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.DateTimeFormat.prototype.format called on value that's not an object initialized as a DateTimeFormat")));
@@ -148,7 +153,12 @@
{
// 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0)
IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
+
+ // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
if (!dateTimeFormat)
+ dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue().get(state, state->vm().propertyNames->intlSubstituteValuePrivateName));
+
+ if (!dateTimeFormat)
return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.DateTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a DateTimeFormat")));
return JSValue::encode(dateTimeFormat->resolvedOptions(*state));
Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormatConstructor.cpp (197924 => 197925)
--- trunk/Source/_javascript_Core/runtime/IntlNumberFormatConstructor.cpp 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormatConstructor.cpp 2016-03-10 05:28:34 UTC (rev 197925)
@@ -117,17 +117,35 @@
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
// NewTarget is always undefined when called as a function.
- // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%).
+ // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
VM& vm = state->vm();
- IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, jsCast<IntlNumberFormatConstructor*>(state->callee()));
+ IntlNumberFormatConstructor* callee = jsCast<IntlNumberFormatConstructor*>(state->callee());
+ JSValue thisValue = state->thisValue();
+ IntlNumberFormat* numberFormat = jsDynamicCast<IntlNumberFormat*>(thisValue);
+ if (!numberFormat) {
+ JSValue prototype = callee->getDirect(vm, vm.propertyNames->prototype);
+ if (JSObject::defaultHasInstance(state, thisValue, prototype)) {
+ JSObject* thisObject = thisValue.toObject(state);
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ numberFormat = IntlNumberFormat::create(vm, callee);
+ numberFormat->initializeNumberFormat(*state, state->argument(0), state->argument(1));
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ thisObject->putDirect(vm, vm.propertyNames->intlSubstituteValuePrivateName, numberFormat);
+ return JSValue::encode(thisValue);
+ }
+ }
+
+ // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%).
// 3. ReturnIfAbrupt(numberFormat).
- ASSERT(numberFormat);
+ numberFormat = IntlNumberFormat::create(vm, callee);
// 4. Return InitializeNumberFormat(numberFormat, locales, options).
- JSValue locales = state->argument(0);
- JSValue options = state->argument(1);
- numberFormat->initializeNumberFormat(*state, locales, options);
+ numberFormat->initializeNumberFormat(*state, state->argument(0), state->argument(1));
return JSValue::encode(numberFormat);
}
Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormatPrototype.cpp (197924 => 197925)
--- trunk/Source/_javascript_Core/runtime/IntlNumberFormatPrototype.cpp 2016-03-10 05:27:07 UTC (rev 197924)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormatPrototype.cpp 2016-03-10 05:28:34 UTC (rev 197925)
@@ -106,7 +106,12 @@
// 11.3.3 Intl.NumberFormat.prototype.format (ECMA-402 2.0)
// 1. Let nf be this NumberFormat object.
IntlNumberFormat* nf = jsDynamicCast<IntlNumberFormat*>(state->thisValue());
+
+ // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
if (!nf)
+ nf = jsDynamicCast<IntlNumberFormat*>(state->thisValue().get(state, state->vm().propertyNames->intlSubstituteValuePrivateName));
+
+ if (!nf)
return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat")));
JSBoundFunction* boundFormat = nf->boundFormat();
@@ -136,7 +141,12 @@
{
// 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0)
IntlNumberFormat* numberFormat = jsDynamicCast<IntlNumberFormat*>(state->thisValue());
+
+ // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
if (!numberFormat)
+ numberFormat = jsDynamicCast<IntlNumberFormat*>(state->thisValue().get(state, state->vm().propertyNames->intlSubstituteValuePrivateName));
+
+ if (!numberFormat)
return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat")));
return JSValue::encode(numberFormat->resolvedOptions(*state));