Title: [266655] trunk
Revision
266655
Author
[email protected]
Date
2020-09-04 21:53:16 -0700 (Fri, 04 Sep 2020)

Log Message

[JSC] Align legacy Intl constructor behavior to spec
https://bugs.webkit.org/show_bug.cgi?id=216193

Reviewed by Darin Adler.

JSTests:

* stress/intl-datetimeformat.js:
* stress/intl-legacy-constructors.js: Added.
(shouldBe):
(shouldThrow):
(testLegacyConstructor):
* stress/intl-numberformat.js:

Source/_javascript_Core:

Legacy Intl constructors (Intl.DateTimeFormat and Intl.NumberFormat) have special handling when it is called via `Intl.DateTimeFormat()` form.
This allowed legacy Intl constructors to be used with prototype-based inheritance without using class syntax. This legacy behavior is later specified
explicitly in the spec. So we should align our implementation to the spec's one.

    1. When defining fallback formats, we need to put them into the property which is visible via Symbol("IntlLegacyConstructedSymbol").
    2. Even if the provided thisValue is IntlDateTimeFormat* / IntlNumberFormat*, we should create another instance and put it to Symbol("IntlLegacyConstructedSymbol") field.

* _javascript_Core.xcodeproj/project.pbxproj:
* builtins/BuiltinNames.cpp:
(JSC::BuiltinNames::BuiltinNames):
* builtins/BuiltinNames.h:
(JSC::BuiltinNames::intlLegacyConstructedSymbol const):
* runtime/CommonIdentifiers.h:
* runtime/IntlDateTimeFormat.h:
* runtime/IntlDateTimeFormatConstructor.cpp:
(JSC::IntlDateTimeFormatConstructor::finishCreation):
(JSC::callIntlDateTimeFormat):
* runtime/IntlDateTimeFormatInlines.h: Added.
(JSC::IntlDateTimeFormat::unwrapForOldFunctions):
* runtime/IntlDateTimeFormatPrototype.cpp:
(JSC::IntlDateTimeFormatPrototypeGetterFormat):
(JSC::IntlDateTimeFormatPrototypeFuncFormatToParts):
(JSC::IntlDateTimeFormatPrototypeFuncFormatRange):
(JSC::IntlDateTimeFormatPrototypeFuncResolvedOptions):
* runtime/IntlNumberFormat.h:
* runtime/IntlNumberFormatConstructor.cpp:
(JSC::IntlNumberFormatConstructor::finishCreation):
(JSC::callIntlNumberFormat):
* runtime/IntlNumberFormatInlines.h:
(JSC::IntlNumberFormat::unwrapForOldFunctions):
* runtime/IntlNumberFormatPrototype.cpp:
(JSC::IntlNumberFormatPrototypeGetterFormat):
(JSC::IntlNumberFormatPrototypeFuncFormatToParts):
(JSC::IntlNumberFormatPrototypeFuncResolvedOptions):
* runtime/IntlObject.cpp:
(JSC::createDateTimeFormatConstructor):
(JSC::createNumberFormatConstructor):
* runtime/IntlObjectInlines.h:
(JSC::constructIntlInstanceWithWorkaroundForLegacyIntlConstructor):
(JSC::unwrapForLegacyIntlConstructor):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::dateTimeFormatConstructor):
(JSC::JSGlobalObject::dateTimeFormatPrototype):
(JSC::JSGlobalObject::numberFormatConstructor):
(JSC::JSGlobalObject::numberFormatPrototype):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (266654 => 266655)


--- trunk/JSTests/ChangeLog	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/JSTests/ChangeLog	2020-09-05 04:53:16 UTC (rev 266655)
@@ -1,3 +1,17 @@
+2020-09-04  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Align legacy Intl constructor behavior to spec
+        https://bugs.webkit.org/show_bug.cgi?id=216193
+
+        Reviewed by Darin Adler.
+
+        * stress/intl-datetimeformat.js:
+        * stress/intl-legacy-constructors.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (testLegacyConstructor):
+        * stress/intl-numberformat.js:
+
 2020-09-04  Alexey Shvayka  <[email protected]>
 
         Array.prototype.push should always perform [[Set]] in strict mode

Modified: trunk/JSTests/stress/intl-datetimeformat.js (266654 => 266655)


--- trunk/JSTests/stress/intl-datetimeformat.js	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/JSTests/stress/intl-datetimeformat.js	2020-09-05 04:53:16 UTC (rev 266655)
@@ -560,8 +560,14 @@
     let legacy = Object.create(Intl.DateTimeFormat.prototype);
     let incompat = {};
     shouldBe(Intl.DateTimeFormat.apply(legacy), legacy);
+    legacy = Object.create(Intl.DateTimeFormat.prototype);
     shouldBe(Intl.DateTimeFormat.call(legacy, 'en-u-nu-arab', { timeZone: 'America/Los_Angeles' }).format(1451099872641), '١٢/٢٥/٢٠١٥');
     shouldBe(Intl.DateTimeFormat.apply(incompat) !== incompat, true);
+    shouldThrow(() => {
+        let legacy = Object.create(Intl.DateTimeFormat.prototype);
+        Intl.DateTimeFormat.call(legacy);
+        Intl.DateTimeFormat.call(legacy, 'en-u-nu-arab');
+    }, TypeError);
 }
 
 // ECMA-402 4th edition 15.4 Intl.DateTimeFormat.prototype.formatToParts

Added: trunk/JSTests/stress/intl-legacy-constructors.js (0 => 266655)


--- trunk/JSTests/stress/intl-legacy-constructors.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-legacy-constructors.js	2020-09-05 04:53:16 UTC (rev 266655)
@@ -0,0 +1,100 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+function shouldThrow(func, errorType) {
+    let error;
+    try {
+        func();
+    } catch (e) {
+        error = e;
+    }
+
+    if (!(error instanceof errorType))
+        throw new Error(`Expected ${errorType.name}!`);
+}
+
+function testLegacyConstructor(constructor, wrongOptions)
+{
+    let symbol = null;
+    {
+        let object = new constructor();
+        let newObject = constructor.call(object);
+        shouldBe(object, newObject);
+        let symbols = Object.getOwnPropertySymbols(newObject);
+        shouldBe(symbols.length, 1);
+        shouldBe(symbols[0].description, `IntlLegacyConstructedSymbol`);
+        shouldBe(newObject[symbols[0]] instanceof constructor, true);
+        symbol = symbols[0];
+        let descriptor = Object.getOwnPropertyDescriptor(newObject, symbol);
+        shouldBe(descriptor.writable, false);
+        shouldBe(descriptor.enumerable, false);
+        shouldBe(descriptor.configurable, false);
+    }
+    {
+        let object = new constructor();
+        Object.freeze(object);
+        shouldThrow(() => constructor.call(object), TypeError);
+    }
+    {
+        let object = {
+            __proto__: constructor.prototype,
+            [symbol]: new constructor()
+        };
+        shouldBe(typeof constructor.prototype.resolvedOptions.call(object), `object`);
+        shouldThrow(() => {
+            constructor.prototype.formatToParts.call(object);
+        }, TypeError);
+    }
+    {
+        let object = { __proto__: constructor.prototype };
+        shouldThrow(() => {
+            constructor.call(object, 'en', wrongOptions);
+        }, RangeError);
+    }
+    {
+        Object.defineProperty(constructor, Symbol.hasInstance, {
+            value: function () { throw new Error("this should not be called"); },
+            writable: true,
+            configurable: true,
+            enumerable: true,
+        });
+        let object = new constructor();
+        let newObject = constructor.call(object);
+        shouldBe(object === newObject, true); // Symbol.hasInstance should be ignored for legacy constructor.
+    }
+    {
+        let object = {
+            [symbol]: new constructor()
+        };
+        Object.defineProperty(constructor, Symbol.hasInstance, {
+            value: function () { return true; },
+            writable: true,
+            configurable: true,
+            enumerable: true,
+        });
+        shouldThrow(() => {
+            constructor.prototype.resolvedOptions.call(object);
+        }, TypeError);
+        shouldThrow(() => {
+            constructor.prototype.formatToParts.call(object);
+        }, TypeError);
+    }
+    {
+        let object = { __proto__: constructor.prototype };
+        Object.defineProperty(constructor, Symbol.hasInstance, {
+            value: function () { throw new Error("this will not be called"); },
+            writable: true,
+            configurable: true,
+            enumerable: true,
+        });
+        shouldThrow(() => {
+            constructor.call(object, 'en', wrongOptions);
+        }, RangeError);
+        constructor.call(object, 'en');
+    }
+}
+
+testLegacyConstructor(Intl.NumberFormat, { style: "wrong" });
+testLegacyConstructor(Intl.DateTimeFormat, { timeStyle: "wrong" });

Modified: trunk/JSTests/stress/intl-numberformat.js (266654 => 266655)


--- trunk/JSTests/stress/intl-numberformat.js	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/JSTests/stress/intl-numberformat.js	2020-09-05 04:53:16 UTC (rev 266655)
@@ -443,8 +443,14 @@
     let legacy = Object.create(Intl.NumberFormat.prototype);
     let incompat = {};
     shouldBe(Intl.NumberFormat.apply(legacy), legacy);
+    legacy = Object.create(Intl.NumberFormat.prototype);
     shouldBe(Intl.NumberFormat.call(legacy, 'en-u-nu-arab').format(1.2345), '١٫٢٣٥');
     shouldBe(Intl.NumberFormat.apply(incompat) !== incompat, true);
+    shouldThrow(() => {
+        let legacy = Object.create(Intl.NumberFormat.prototype);
+        Intl.NumberFormat.call(legacy);
+        Intl.NumberFormat.call(legacy, 'en-u-nu-arab');
+    }, TypeError);
 }
 
 // BigInt tests

Modified: trunk/Source/_javascript_Core/ChangeLog (266654 => 266655)


--- trunk/Source/_javascript_Core/ChangeLog	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-09-05 04:53:16 UTC (rev 266655)
@@ -1,3 +1,59 @@
+2020-09-04  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Align legacy Intl constructor behavior to spec
+        https://bugs.webkit.org/show_bug.cgi?id=216193
+
+        Reviewed by Darin Adler.
+
+        Legacy Intl constructors (Intl.DateTimeFormat and Intl.NumberFormat) have special handling when it is called via `Intl.DateTimeFormat()` form.
+        This allowed legacy Intl constructors to be used with prototype-based inheritance without using class syntax. This legacy behavior is later specified
+        explicitly in the spec. So we should align our implementation to the spec's one.
+
+            1. When defining fallback formats, we need to put them into the property which is visible via Symbol("IntlLegacyConstructedSymbol").
+            2. Even if the provided thisValue is IntlDateTimeFormat* / IntlNumberFormat*, we should create another instance and put it to Symbol("IntlLegacyConstructedSymbol") field.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * builtins/BuiltinNames.cpp:
+        (JSC::BuiltinNames::BuiltinNames):
+        * builtins/BuiltinNames.h:
+        (JSC::BuiltinNames::intlLegacyConstructedSymbol const):
+        * runtime/CommonIdentifiers.h:
+        * runtime/IntlDateTimeFormat.h:
+        * runtime/IntlDateTimeFormatConstructor.cpp:
+        (JSC::IntlDateTimeFormatConstructor::finishCreation):
+        (JSC::callIntlDateTimeFormat):
+        * runtime/IntlDateTimeFormatInlines.h: Added.
+        (JSC::IntlDateTimeFormat::unwrapForOldFunctions):
+        * runtime/IntlDateTimeFormatPrototype.cpp:
+        (JSC::IntlDateTimeFormatPrototypeGetterFormat):
+        (JSC::IntlDateTimeFormatPrototypeFuncFormatToParts):
+        (JSC::IntlDateTimeFormatPrototypeFuncFormatRange):
+        (JSC::IntlDateTimeFormatPrototypeFuncResolvedOptions):
+        * runtime/IntlNumberFormat.h:
+        * runtime/IntlNumberFormatConstructor.cpp:
+        (JSC::IntlNumberFormatConstructor::finishCreation):
+        (JSC::callIntlNumberFormat):
+        * runtime/IntlNumberFormatInlines.h:
+        (JSC::IntlNumberFormat::unwrapForOldFunctions):
+        * runtime/IntlNumberFormatPrototype.cpp:
+        (JSC::IntlNumberFormatPrototypeGetterFormat):
+        (JSC::IntlNumberFormatPrototypeFuncFormatToParts):
+        (JSC::IntlNumberFormatPrototypeFuncResolvedOptions):
+        * runtime/IntlObject.cpp:
+        (JSC::createDateTimeFormatConstructor):
+        (JSC::createNumberFormatConstructor):
+        * runtime/IntlObjectInlines.h:
+        (JSC::constructIntlInstanceWithWorkaroundForLegacyIntlConstructor):
+        (JSC::unwrapForLegacyIntlConstructor):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::dateTimeFormatConstructor):
+        (JSC::JSGlobalObject::dateTimeFormatPrototype):
+        (JSC::JSGlobalObject::numberFormatConstructor):
+        (JSC::JSGlobalObject::numberFormatPrototype):
+
 2020-09-04  Alexey Shvayka  <[email protected]>
 
         Array.prototype.push should always perform [[Set]] in strict mode

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (266654 => 266655)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-09-05 04:53:16 UTC (rev 266655)
@@ -1849,6 +1849,7 @@
 		E36B767022F8D61900D09818 /* WasmOMGForOSREntryPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = E36B766F22F8D61100D09818 /* WasmOMGForOSREntryPlan.h */; };
 		E36CC9472086314F0051FFD6 /* WasmCreationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = E36CC9462086314F0051FFD6 /* WasmCreationMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E36EDCE524F0975700E60DA2 /* Concurrency.h in Headers */ = {isa = PBXBuildFile; fileRef = E36EDCE424F0975700E60DA2 /* Concurrency.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E3750CC82502E87E006A0AAB /* IntlDateTimeFormatInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3750CC72502E87E006A0AAB /* IntlDateTimeFormatInlines.h */; };
 		E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = E3794E741B77EB97005543AE /* ModuleAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E383500A2390D93B0036316D /* WasmGlobal.h in Headers */ = {isa = PBXBuildFile; fileRef = E38350092390D9370036316D /* WasmGlobal.h */; };
 		E3850B15226ED641009ABF9C /* DFGMinifiedIDInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3850B14226ED63E009ABF9C /* DFGMinifiedIDInlines.h */; };
@@ -5049,6 +5050,7 @@
 		E36B766F22F8D61100D09818 /* WasmOMGForOSREntryPlan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WasmOMGForOSREntryPlan.h; sourceTree = "<group>"; };
 		E36CC9462086314F0051FFD6 /* WasmCreationMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmCreationMode.h; sourceTree = "<group>"; };
 		E36EDCE424F0975700E60DA2 /* Concurrency.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Concurrency.h; sourceTree = "<group>"; };
+		E3750CC72502E87E006A0AAB /* IntlDateTimeFormatInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlDateTimeFormatInlines.h; sourceTree = "<group>"; };
 		E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleAnalyzer.cpp; sourceTree = "<group>"; };
 		E3794E741B77EB97005543AE /* ModuleAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleAnalyzer.h; sourceTree = "<group>"; };
 		E37CFB2D22F27C57009A7B38 /* WasmCompilationMode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WasmCompilationMode.cpp; sourceTree = "<group>"; };
@@ -7318,6 +7320,7 @@
 				A1587D681B4DC14100D69849 /* IntlDateTimeFormat.h */,
 				A1587D691B4DC14100D69849 /* IntlDateTimeFormatConstructor.cpp */,
 				A1587D6A1B4DC14100D69849 /* IntlDateTimeFormatConstructor.h */,
+				E3750CC72502E87E006A0AAB /* IntlDateTimeFormatInlines.h */,
 				A1587D6B1B4DC14100D69849 /* IntlDateTimeFormatPrototype.cpp */,
 				A1587D6C1B4DC14100D69849 /* IntlDateTimeFormatPrototype.h */,
 				E353C11624AA4CB5003FBDF3 /* IntlDisplayNames.cpp */,
@@ -9829,6 +9832,7 @@
 				A1587D6E1B4DC14100D69849 /* IntlDateTimeFormat.h in Headers */,
 				A1587D701B4DC14100D69849 /* IntlDateTimeFormatConstructor.h in Headers */,
 				A1587D751B4DC1C600D69849 /* IntlDateTimeFormatConstructor.lut.h in Headers */,
+				E3750CC82502E87E006A0AAB /* IntlDateTimeFormatInlines.h in Headers */,
 				A1587D721B4DC14100D69849 /* IntlDateTimeFormatPrototype.h in Headers */,
 				A1587D761B4DC1C600D69849 /* IntlDateTimeFormatPrototype.lut.h in Headers */,
 				E353C11D24AA4CB7003FBDF3 /* IntlDisplayNames.h in Headers */,

Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/builtins/BuiltinNames.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -41,6 +41,8 @@
 JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_BUILTIN_STATIC_SYMBOLS)
 #undef INITIALIZE_BUILTIN_STATIC_SYMBOLS
 
+SymbolImpl::StaticSymbolImpl intlLegacyConstructedSymbol { "IntlLegacyConstructedSymbol" };
+
 #define INITIALIZE_BUILTIN_PRIVATE_NAMES(name) SymbolImpl::StaticSymbolImpl name##PrivateName { #name, SymbolImpl::s_flagIsPrivate };
 JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_BUILTIN_PRIVATE_NAMES)
 JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_BUILTIN_PRIVATE_NAMES)
@@ -76,6 +78,7 @@
     JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_BUILTIN_NAMES_IN_JSC)
     JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_BUILTIN_NAMES_IN_JSC)
     JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_BUILTIN_SYMBOLS_IN_JSC)
+    , m_intlLegacyConstructedSymbol(JSC::Identifier::fromUid(vm, &static_cast<SymbolImpl&>(Symbols::intlLegacyConstructedSymbol)))
     , m_dollarVMName(Identifier::fromString(vm, "$vm"))
     , m_dollarVMPrivateName(Identifier::fromUid(vm, &static_cast<SymbolImpl&>(Symbols::dollarVMPrivateName)))
     , m_polyProtoPrivateName(Identifier::fromUid(vm, &static_cast<SymbolImpl&>(Symbols::polyProtoPrivateName)))

Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (266654 => 266655)


--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -111,7 +111,6 @@
     macro(nextMethod) \
     macro(asyncGeneratorQueueItemNext) \
     macro(dateTimeFormat) \
-    macro(intlSubstituteValue) \
     macro(this) \
     macro(thisTimeValue) \
     macro(newTargetLocal) \
@@ -211,6 +210,7 @@
     const JSC::Identifier& dollarVMPublicName() const { return m_dollarVMName; }
     const JSC::Identifier& dollarVMPrivateName() const { return m_dollarVMPrivateName; }
     const JSC::Identifier& polyProtoName() const { return m_polyProtoPrivateName; }
+    const JSC::Identifier& intlLegacyConstructedSymbol() const { return m_intlLegacyConstructedSymbol; }
 
 private:
     void checkPublicToPrivateMapConsistency(UniquedStringImpl* privateName);
@@ -219,6 +219,7 @@
     JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_NAMES_IN_JSC)
     JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_NAMES_IN_JSC)
     JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOLS_IN_JSC)
+    const JSC::Identifier m_intlLegacyConstructedSymbol;
     const JSC::Identifier m_dollarVMName;
     const JSC::Identifier m_dollarVMPrivateName;
     const JSC::Identifier m_polyProtoPrivateName;

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -335,6 +335,7 @@
 #define JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL(name) const Identifier name##Symbol;
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL)
 #undef JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL
+        const Identifier intlLegacyConstructedSymbol;
 
 #define JSC_IDENTIFIER_DECLARE_PRIVATE_FIELD_GLOBAL(name) const Identifier name##PrivateField;
         JSC_COMMON_IDENTIFIERS_EACH_PRIVATE_FIELD(JSC_IDENTIFIER_DECLARE_PRIVATE_FIELD_GLOBAL)

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.h (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -67,6 +67,8 @@
     JSBoundFunction* boundFormat() const { return m_boundFormat.get(); }
     void setBoundFormat(VM&, JSBoundFunction*);
 
+    static IntlDateTimeFormat* unwrapForOldFunctions(JSGlobalObject*, JSValue);
+
 private:
     IntlDateTimeFormat(VM&, Structure*);
     void finishCreation(VM&);

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatConstructor.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatConstructor.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatConstructor.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -77,7 +77,6 @@
     Base::finishCreation(vm, "DateTimeFormat"_s, NameAdditionMode::WithoutStructureTransition);
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, dateTimeFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
-    dateTimeFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
 }
 
 static EncodedJSValue JSC_HOST_CALL constructIntlDateTimeFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
@@ -111,7 +110,7 @@
 
     // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
     // https://bugs.webkit.org/show_bug.cgi?id=153679
-    return JSValue::encode(constructIntlInstanceWithWorkaroundForLegacyIntlConstructor<IntlDateTimeFormat>(globalObject, callFrame->thisValue(), callFrame->jsCallee(), [&] (VM& vm) {
+    return JSValue::encode(constructIntlInstanceWithWorkaroundForLegacyIntlConstructor(globalObject, callFrame->thisValue(), callFrame->jsCallee(), [&] (VM& vm) {
         // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%).
         // 3. ReturnIfAbrupt(dateTimeFormat).
         IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, globalObject->dateTimeFormatStructure());

Added: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatInlines.h (0 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatInlines.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatInlines.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * 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. ``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
+ * 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 "BuiltinNames.h"
+#include "IntlDateTimeFormat.h"
+#include "IntlObjectInlines.h"
+#include "JSGlobalObject.h"
+
+namespace JSC  {
+
+// https://tc39.es/ecma402/#sec-unwrapdatetimeformat
+inline IntlDateTimeFormat* IntlDateTimeFormat::unwrapForOldFunctions(JSGlobalObject* globalObject, JSValue thisValue)
+{
+    return unwrapForLegacyIntlConstructor<IntlDateTimeFormat>(globalObject, thisValue, globalObject->dateTimeFormatConstructor());
+}
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatPrototype.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatPrototype.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormatPrototype.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -29,7 +29,7 @@
 
 #include "BuiltinNames.h"
 #include "DateConstructor.h"
-#include "IntlDateTimeFormat.h"
+#include "IntlDateTimeFormatInlines.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include <wtf/DateMath.h>
@@ -111,18 +111,10 @@
 
     // 12.3.3 Intl.DateTimeFormat.prototype.format (ECMA-402 2.0)
     // 1. Let dtf be this DateTimeFormat object.
-    IntlDateTimeFormat* dtf = jsDynamicCast<IntlDateTimeFormat*>(vm, callFrame->thisValue());
-
-    // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
-    // https://bugs.webkit.org/show_bug.cgi?id=153679
-    if (!dtf) {
-        JSValue value = callFrame->thisValue().get(globalObject, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        dtf = jsDynamicCast<IntlDateTimeFormat*>(vm, value);
-    }
-
+    auto* dtf = IntlDateTimeFormat::unwrapForOldFunctions(globalObject, callFrame->thisValue());
+    RETURN_IF_EXCEPTION(scope, { });
     // 2. ReturnIfAbrupt(dtf).
-    if (!dtf)
+    if (UNLIKELY(!dtf))
         return JSValue::encode(throwTypeError(globalObject, scope, "Intl.DateTimeFormat.prototype.format called on value that's not an object initialized as a DateTimeFormat"_s));
 
     JSBoundFunction* boundFormat = dtf->boundFormat();
@@ -150,8 +142,9 @@
     // 15.4 Intl.DateTimeFormat.prototype.formatToParts (ECMA-402 4.0)
     // https://tc39.github.io/ecma402/#sec-Intl.DateTimeFormat.prototype.formatToParts
 
-    IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(vm, callFrame->thisValue());
-    if (!dateTimeFormat)
+    // Do not use unwrapForOldFunctions.
+    auto* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(vm, callFrame->thisValue());
+    if (UNLIKELY(!dateTimeFormat))
         return JSValue::encode(throwTypeError(globalObject, scope, "Intl.DateTimeFormat.prototype.formatToParts called on value that's not an object initialized as a DateTimeFormat"_s));
 
     JSValue date = callFrame->argument(0);
@@ -173,8 +166,9 @@
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(vm, callFrame->thisValue());
-    if (!dateTimeFormat)
+    // Do not use unwrapForOldFunctions.
+    auto* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(vm, callFrame->thisValue());
+    if (UNLIKELY(!dateTimeFormat))
         return JSValue::encode(throwTypeError(globalObject, scope, "Intl.DateTimeFormat.prototype.formatRange called on value that's not an object initialized as a DateTimeFormat"_s));
 
     JSValue startDateValue = callFrame->argument(0);
@@ -199,17 +193,10 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     // 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0)
-    IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(vm, callFrame->thisValue());
 
-    // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
-    // https://bugs.webkit.org/show_bug.cgi?id=153679
-    if (!dateTimeFormat) {
-        JSValue value = callFrame->thisValue().get(globalObject, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(vm, value);
-    }
-
-    if (!dateTimeFormat)
+    auto* dateTimeFormat = IntlDateTimeFormat::unwrapForOldFunctions(globalObject, callFrame->thisValue());
+    RETURN_IF_EXCEPTION(scope, { });
+    if (UNLIKELY(!dateTimeFormat))
         return JSValue::encode(throwTypeError(globalObject, scope, "Intl.DateTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a DateTimeFormat"_s));
 
     RELEASE_AND_RETURN(scope, JSValue::encode(dateTimeFormat->resolvedOptions(globalObject)));

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -91,6 +91,8 @@
 
     static ASCIILiteral notationString(IntlNotation);
 
+    static IntlNumberFormat* unwrapForOldFunctions(JSGlobalObject*, JSValue);
+
 private:
     IntlNumberFormat(VM&, Structure*);
     void finishCreation(VM&);

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormatConstructor.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormatConstructor.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormatConstructor.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -77,7 +77,6 @@
     Base::finishCreation(vm, "NumberFormat"_s, NameAdditionMode::WithoutStructureTransition);
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
-    numberFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
 }
 
 static EncodedJSValue JSC_HOST_CALL constructIntlNumberFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
@@ -111,7 +110,7 @@
 
     // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
     // https://bugs.webkit.org/show_bug.cgi?id=153679
-    return JSValue::encode(constructIntlInstanceWithWorkaroundForLegacyIntlConstructor<IntlNumberFormat>(globalObject, callFrame->thisValue(), callFrame->jsCallee(), [&] (VM& vm) {
+    return JSValue::encode(constructIntlInstanceWithWorkaroundForLegacyIntlConstructor(globalObject, callFrame->thisValue(), callFrame->jsCallee(), [&] (VM& vm) {
         // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%).
         // 3. ReturnIfAbrupt(numberFormat).
         IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, globalObject->numberFormatStructure());

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormatInlines.h (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormatInlines.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormatInlines.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -25,8 +25,9 @@
 
 #pragma once
 
+#include "BuiltinNames.h"
 #include "IntlNumberFormat.h"
-#include "IntlObject.h"
+#include "IntlObjectInlines.h"
 #include "JSGlobalObject.h"
 
 namespace JSC  {
@@ -105,4 +106,10 @@
     UFieldPositionIterator& m_iterator;
 };
 
+// https://tc39.es/ecma402/#sec-unwrapnumberformat
+inline IntlNumberFormat* IntlNumberFormat::unwrapForOldFunctions(JSGlobalObject* globalObject, JSValue thisValue)
+{
+    return unwrapForLegacyIntlConstructor<IntlNumberFormat>(globalObject, thisValue, globalObject->numberFormatConstructor());
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormatPrototype.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormatPrototype.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormatPrototype.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -114,19 +114,10 @@
 
     // 11.3.3 Intl.NumberFormat.prototype.format (ECMA-402 2.0)
     // 1. Let nf be this NumberFormat object.
-    IntlNumberFormat* nf = jsDynamicCast<IntlNumberFormat*>(vm, callFrame->thisValue());
+    auto* nf = IntlNumberFormat::unwrapForOldFunctions(globalObject, callFrame->thisValue());
+    if (UNLIKELY(!nf))
+        return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat"_s));
 
-    // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
-    // https://bugs.webkit.org/show_bug.cgi?id=153679
-    if (!nf) {
-        JSValue value = callFrame->thisValue().get(globalObject, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        nf = jsDynamicCast<IntlNumberFormat*>(vm, value);
-    }
-
-    if (!nf)
-        return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat"_s));
-    
     JSBoundFunction* boundFormat = nf->boundFormat();
     // 2. If nf.[[boundFormat]] is undefined,
     if (!boundFormat) {
@@ -152,8 +143,9 @@
     // Intl.NumberFormat.prototype.formatToParts (ECMA-402)
     // https://tc39.github.io/ecma402/#sec-intl.numberformat.prototype.formattoparts
 
-    IntlNumberFormat* numberFormat = jsDynamicCast<IntlNumberFormat*>(vm, callFrame->thisValue());
-    if (!numberFormat)
+    // Do not use unwrapForOldFunctions.
+    auto* numberFormat = jsDynamicCast<IntlNumberFormat*>(vm, callFrame->thisValue());
+    if (UNLIKELY(!numberFormat))
         return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.formatToParts called on value that's not an object initialized as a NumberFormat"_s));
 
     double value = callFrame->argument(0).toNumber(globalObject);
@@ -168,17 +160,9 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0)
-    IntlNumberFormat* numberFormat = jsDynamicCast<IntlNumberFormat*>(vm, callFrame->thisValue());
 
-    // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
-    // https://bugs.webkit.org/show_bug.cgi?id=153679
-    if (!numberFormat) {
-        JSValue value = callFrame->thisValue().get(globalObject, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        numberFormat = jsDynamicCast<IntlNumberFormat*>(vm, value);
-    }
-
-    if (!numberFormat)
+    auto* numberFormat = IntlNumberFormat::unwrapForOldFunctions(globalObject, callFrame->thisValue());
+    if (UNLIKELY(!numberFormat))
         return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat"_s));
 
     RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->resolvedOptions(globalObject)));

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -83,7 +83,7 @@
 {
     IntlObject* intlObject = jsCast<IntlObject*>(object);
     JSGlobalObject* globalObject = intlObject->globalObject(vm);
-    return IntlDateTimeFormatConstructor::create(vm, IntlDateTimeFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlDateTimeFormatPrototype*>(globalObject->dateTimeFormatStructure()->storedPrototypeObject()));
+    return globalObject->dateTimeFormatConstructor();
 }
 
 static JSValue createDisplayNamesConstructor(VM& vm, JSObject* object)
@@ -104,7 +104,7 @@
 {
     IntlObject* intlObject = jsCast<IntlObject*>(object);
     JSGlobalObject* globalObject = intlObject->globalObject(vm);
-    return IntlNumberFormatConstructor::create(vm, IntlNumberFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlNumberFormatPrototype*>(globalObject->numberFormatStructure()->storedPrototypeObject()));
+    return globalObject->numberFormatConstructor();
 }
 
 static JSValue createPluralRulesConstructor(VM& vm, JSObject* object)

Modified: trunk/Source/_javascript_Core/runtime/IntlObjectInlines.h (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/IntlObjectInlines.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/IntlObjectInlines.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -28,6 +28,7 @@
 
 #include "BuiltinNames.h"
 #include "IntlObject.h"
+#include "JSBoundFunction.h"
 #include "JSObject.h"
 #include <unicode/ucol.h>
 
@@ -56,7 +57,7 @@
     return String();
 }
 
-template<typename IntlInstance, typename Constructor, typename Factory>
+template<typename Constructor, typename Factory>
 JSValue constructIntlInstanceWithWorkaroundForLegacyIntlConstructor(JSGlobalObject* globalObject, JSValue thisValue, Constructor* callee, Factory factory)
 {
     // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
@@ -64,24 +65,53 @@
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    if (!jsDynamicCast<IntlInstance*>(vm, thisValue)) {
-        JSValue prototype = callee->getDirect(vm, vm.propertyNames->prototype);
-        bool hasInstance = JSObject::defaultHasInstance(globalObject, thisValue, prototype);
+    auto* instance = factory(vm);
+    RETURN_IF_EXCEPTION(scope, JSValue());
+
+    if (thisValue.isObject()) {
+        JSObject* thisObject = asObject(thisValue);
+        ASSERT(!callee->template inherits<JSBoundFunction>(vm));
+        JSValue prototype = callee->getDirect(vm, vm.propertyNames->prototype); // Passed constructors always have `prototype` which cannot be deleted.
+        ASSERT(prototype);
+        bool hasInstance = JSObject::defaultHasInstance(globalObject, thisObject, prototype);
         RETURN_IF_EXCEPTION(scope, JSValue());
         if (hasInstance) {
-            JSObject* thisObject = thisValue.toObject(globalObject);
-            RETURN_IF_EXCEPTION(scope, JSValue());
-
-            IntlInstance* instance = factory(vm);
-            RETURN_IF_EXCEPTION(scope, JSValue());
-
-            thisObject->putDirect(vm, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName(), instance);
+            PropertyDescriptor descriptor(instance, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
+            scope.release();
+            thisObject->methodTable(vm)->defineOwnProperty(thisObject, globalObject, vm.propertyNames->builtinNames().intlLegacyConstructedSymbol(), descriptor, true);
             return thisObject;
         }
     }
-    RELEASE_AND_RETURN(scope, factory(vm));
+    return instance;
 }
 
+template<typename InstanceType>
+InstanceType* unwrapForLegacyIntlConstructor(JSGlobalObject* globalObject, JSValue thisValue, JSObject* constructor)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
+    if (UNLIKELY(!thisObject))
+        return nullptr;
+
+    auto* instance = jsDynamicCast<InstanceType*>(vm, thisObject);
+    if (LIKELY(instance))
+        return instance;
+
+    ASSERT(!constructor->template inherits<JSBoundFunction>(vm));
+    JSValue prototype = constructor->getDirect(vm, vm.propertyNames->prototype); // Passed constructors always have `prototype` which cannot be deleted.
+    ASSERT(prototype);
+    bool hasInstance = JSObject::defaultHasInstance(globalObject, thisObject, prototype);
+    RETURN_IF_EXCEPTION(scope, nullptr);
+    if (!hasInstance)
+        return nullptr;
+
+    JSValue value = thisObject->get(globalObject, vm.propertyNames->builtinNames().intlLegacyConstructedSymbol());
+    RETURN_IF_EXCEPTION(scope, nullptr);
+    return jsDynamicCast<InstanceType*>(vm, value);
+}
+
 template<typename ResultType>
 ResultType intlOption(JSGlobalObject* globalObject, JSValue options, PropertyName property, std::initializer_list<std::pair<ASCIILiteral, ResultType>> values, ASCIILiteral notFoundMessage, ResultType fallback)
 {

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-09-05 04:53:16 UTC (rev 266655)
@@ -74,6 +74,7 @@
 #include "IntlCollator.h"
 #include "IntlCollatorPrototype.h"
 #include "IntlDateTimeFormat.h"
+#include "IntlDateTimeFormatConstructor.h"
 #include "IntlDateTimeFormatPrototype.h"
 #include "IntlDisplayNames.h"
 #include "IntlDisplayNamesPrototype.h"
@@ -80,6 +81,7 @@
 #include "IntlLocale.h"
 #include "IntlLocalePrototype.h"
 #include "IntlNumberFormat.h"
+#include "IntlNumberFormatConstructor.h"
 #include "IntlNumberFormatPrototype.h"
 #include "IntlObject.h"
 #include "IntlPluralRules.h"
@@ -998,12 +1000,6 @@
             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_displayNamesStructure.initLater(
         [] (const Initializer<Structure>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -1016,12 +1012,6 @@
             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);
-            IntlNumberFormatPrototype* numberFormatPrototype = IntlNumberFormatPrototype::create(init.vm, globalObject, IntlNumberFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
-            init.set(IntlNumberFormat::createStructure(init.vm, globalObject, numberFormatPrototype));
-        });
     m_pluralRulesStructure.initLater(
         [] (const Initializer<Structure>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -1052,6 +1042,20 @@
             IntlSegmentsPrototype* segmentsPrototype = IntlSegmentsPrototype::create(init.vm, globalObject, IntlSegmentsPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
             init.set(IntlSegments::createStructure(init.vm, globalObject, segmentsPrototype));
         });
+
+    m_dateTimeFormatStructure.initLater(
+        [] (LazyClassStructure::Initializer& init) {
+            init.setPrototype(IntlDateTimeFormatPrototype::create(init.vm, init.global, IntlDateTimeFormatPrototype::createStructure(init.vm, init.global, init.global->objectPrototype())));
+            init.setStructure(IntlDateTimeFormat::createStructure(init.vm, init.global, init.prototype));
+            init.setConstructor(IntlDateTimeFormatConstructor::create(init.vm, IntlDateTimeFormatConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<IntlDateTimeFormatPrototype*>(init.prototype)));
+        });
+    m_numberFormatStructure.initLater(
+        [] (LazyClassStructure::Initializer& init) {
+            init.setPrototype(IntlNumberFormatPrototype::create(init.vm, init.global, IntlNumberFormatPrototype::createStructure(init.vm, init.global, init.global->objectPrototype())));
+            init.setStructure(IntlNumberFormat::createStructure(init.vm, init.global, init.prototype));
+            init.setConstructor(IntlNumberFormatConstructor::create(init.vm, IntlNumberFormatConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<IntlNumberFormatPrototype*>(init.prototype)));
+        });
+
     m_defaultCollator.initLater(
         [] (const Initializer<IntlCollator>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -1883,9 +1887,7 @@
 
     thisObject->m_defaultCollator.visit(visitor);
     thisObject->m_collatorStructure.visit(visitor);
-    thisObject->m_dateTimeFormatStructure.visit(visitor);
     thisObject->m_displayNamesStructure.visit(visitor);
-    thisObject->m_numberFormatStructure.visit(visitor);
     thisObject->m_localeStructure.visit(visitor);
     thisObject->m_pluralRulesStructure.visit(visitor);
     thisObject->m_relativeTimeFormatStructure.visit(visitor);
@@ -1892,6 +1894,8 @@
     thisObject->m_segmentIteratorStructure.visit(visitor);
     thisObject->m_segmenterStructure.visit(visitor);
     thisObject->m_segmentsStructure.visit(visitor);
+    thisObject->m_dateTimeFormatStructure.visit(visitor);
+    thisObject->m_numberFormatStructure.visit(visitor);
 
     visitor.append(thisObject->m_nullGetterFunction);
     visitor.append(thisObject->m_nullSetterFunction);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (266654 => 266655)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-09-05 04:07:47 UTC (rev 266654)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-09-05 04:53:16 UTC (rev 266655)
@@ -296,15 +296,15 @@
 
     LazyProperty<JSGlobalObject, IntlCollator> m_defaultCollator;
     LazyProperty<JSGlobalObject, Structure> m_collatorStructure;
-    LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_displayNamesStructure;
     LazyProperty<JSGlobalObject, Structure> m_localeStructure;
-    LazyProperty<JSGlobalObject, Structure> m_numberFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_pluralRulesStructure;
     LazyProperty<JSGlobalObject, Structure> m_relativeTimeFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_segmentIteratorStructure;
     LazyProperty<JSGlobalObject, Structure> m_segmenterStructure;
     LazyProperty<JSGlobalObject, Structure> m_segmentsStructure;
+    LazyClassStructure m_dateTimeFormatStructure;
+    LazyClassStructure m_numberFormatStructure;
 
     WriteBarrier<NullGetterFunction> m_nullGetterFunction;
     WriteBarrier<NullSetterFunction> m_nullSetterFunction;
@@ -818,6 +818,11 @@
     Structure* segmenterStructure() { return m_segmenterStructure.get(this); }
     Structure* segmentsStructure() { return m_segmentsStructure.get(this); }
 
+    JSObject* dateTimeFormatConstructor() { return m_dateTimeFormatStructure.constructor(this); }
+    JSObject* dateTimeFormatPrototype() { return m_dateTimeFormatStructure.prototype(this); }
+    JSObject* numberFormatConstructor() { return m_numberFormatStructure.constructor(this); }
+    JSObject* numberFormatPrototype() { return m_numberFormatStructure.prototype(this); }
+
     JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);
     JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to