Title: [266567] trunk
Revision
266567
Author
ysuz...@apple.com
Date
2020-09-03 18:03:33 -0700 (Thu, 03 Sep 2020)

Log Message

[JSC] Cache toString / valueOf / @@toPrimitive for major cases
https://bugs.webkit.org/show_bug.cgi?id=216061

Reviewed by Saam Barati.

JSTests:

* stress/delete-cached-to-primitive-property.js: Added.
(shouldBe):
(object.__proto__.Symbol.toPrimitive):
* stress/delete-cached-to-string-property.js: Added.
(shouldBe):
(object.__proto__.toString):
* stress/delete-cached-value-of-property.js: Added.
(shouldBe):
(shouldThrow):
(object.__proto__.valueOf):
* stress/hide-cached-to-primitive-property.js: Added.
(shouldBe):
(object.__proto__.Symbol.toPrimitive):
* stress/hide-cached-to-string-property.js: Added.
(shouldBe):
(object.__proto__.toString):
* stress/hide-cached-value-of-property.js: Added.
(shouldBe):
(object.__proto__.valueOf):
* stress/replace-cached-to-primitive-property.js: Added.
(shouldBe):
(object.__proto__.Symbol.toPrimitive):
* stress/replace-cached-to-string-property.js: Added.
(shouldBe):
(object.__proto__.toString):
* stress/replace-cached-value-of-property.js: Added.
(shouldBe):
(object.__proto__.valueOf):

Source/_javascript_Core:

When toPrimitive is called, we need to look-up three properties at most to perform operation. And these special properties do not have caching mechanism at all.
We found that Speedometer2/EmberJS-Debug-TodoMVC is using very much time for this property look-up. We should have caching mechanism in StructureRareData, which
should be similar to @@toStringTag & Object#toString caching mechanism.

This patch generalizes @@toStringTag & Object#toString caching mechanism as SpecialPropertyCache. And we accelerate toString / valueOf / @@toPrimitive look-ups in
toPrimitive with this caching mechanism.

This patch improved Speedometer2/EmberJS-Debug-TodoMVC by 10%.

* _javascript_Core.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecode/Watchpoint.cpp:
* bytecode/Watchpoint.h:
* runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp: Renamed from Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp.
(JSC::CachedSpecialPropertyAdaptiveStructureWatchpoint::CachedSpecialPropertyAdaptiveStructureWatchpoint):
(JSC::CachedSpecialPropertyAdaptiveStructureWatchpoint::install):
(JSC::CachedSpecialPropertyAdaptiveStructureWatchpoint::fireInternal):
* runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.h: Renamed from Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.h.
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::objectProtoToStringFunction const):
* runtime/JSObject.cpp:
(JSC::callToPrimitiveFunction):
(JSC::JSObject::ordinaryToPrimitive const):
(JSC::JSObject::toPrimitive const):
* runtime/ObjectPrototype.cpp:
(JSC::ObjectPrototype::finishCreation):
(JSC::objectProtoFuncToString):
* runtime/Structure.h:
* runtime/StructureInlines.h:
(JSC::Structure::cacheSpecialProperty):
(JSC::Structure::setObjectToStringValue): Deleted.
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::visitChildren):
(JSC::StructureRareData::ensureSpecialPropertyCacheSlow):
(JSC::StructureRareData::giveUpOnSpecialPropertyCache):
(JSC::StructureRareData::cacheSpecialPropertySlow):
(JSC::StructureRareData::clearCachedSpecialProperty):
(JSC::StructureRareData::finalizeUnconditionally):
(JSC::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint):
(JSC::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::isValid const):
(JSC::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::handleFire):
(JSC::StructureRareData::setObjectToStringValue): Deleted.
(JSC::StructureRareData::clearObjectToStringValue): Deleted.
(JSC::ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint): Deleted.
(JSC::ObjectToStringAdaptiveInferredPropertyValueWatchpoint::isValid const): Deleted.
(JSC::ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire): Deleted.
* runtime/StructureRareData.h:
* runtime/StructureRareDataInlines.h:
(JSC::StructureRareData::cachedSpecialProperty const):
(JSC::StructureRareData::canCacheSpecialProperty):
(JSC::StructureRareData::ensureSpecialPropertyCache):
(JSC::StructureRareData::cacheSpecialProperty):
(JSC::StructureRareData::objectToStringValue const): Deleted.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/JSTests/ChangeLog (266566 => 266567)


--- trunk/JSTests/ChangeLog	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/JSTests/ChangeLog	2020-09-04 01:03:33 UTC (rev 266567)
@@ -1,3 +1,39 @@
+2020-09-02  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Cache toString / valueOf / @@toPrimitive for major cases
+        https://bugs.webkit.org/show_bug.cgi?id=216061
+
+        Reviewed by Saam Barati.
+
+        * stress/delete-cached-to-primitive-property.js: Added.
+        (shouldBe):
+        (object.__proto__.Symbol.toPrimitive):
+        * stress/delete-cached-to-string-property.js: Added.
+        (shouldBe):
+        (object.__proto__.toString):
+        * stress/delete-cached-value-of-property.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (object.__proto__.valueOf):
+        * stress/hide-cached-to-primitive-property.js: Added.
+        (shouldBe):
+        (object.__proto__.Symbol.toPrimitive):
+        * stress/hide-cached-to-string-property.js: Added.
+        (shouldBe):
+        (object.__proto__.toString):
+        * stress/hide-cached-value-of-property.js: Added.
+        (shouldBe):
+        (object.__proto__.valueOf):
+        * stress/replace-cached-to-primitive-property.js: Added.
+        (shouldBe):
+        (object.__proto__.Symbol.toPrimitive):
+        * stress/replace-cached-to-string-property.js: Added.
+        (shouldBe):
+        (object.__proto__.toString):
+        * stress/replace-cached-value-of-property.js: Added.
+        (shouldBe):
+        (object.__proto__.valueOf):
+
 2020-09-03  Ross Kirsling  <ross.kirsl...@sony.com>
 
         [JSC] Add missing detached buffer errors for DataView

Added: trunk/JSTests/stress/delete-cached-to-primitive-property.js (0 => 266567)


--- trunk/JSTests/stress/delete-cached-to-primitive-property.js	                        (rev 0)
+++ trunk/JSTests/stress/delete-cached-to-primitive-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {
+    __proto__: {
+        [Symbol.toPrimitive]: function () {
+            return 42;
+        }
+    }
+};
+
+shouldBe(object + 42, 84);
+shouldBe(object + 42, 84);
+delete object.__proto__[Symbol.toPrimitive];
+shouldBe(object + 42, `[object Object]42`);

Added: trunk/JSTests/stress/delete-cached-to-string-property.js (0 => 266567)


--- trunk/JSTests/stress/delete-cached-to-string-property.js	                        (rev 0)
+++ trunk/JSTests/stress/delete-cached-to-string-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {
+    __proto__: {
+        toString: function () {
+            return "Hey";
+        }
+    }
+};
+
+shouldBe(object + 42, `Hey42`);
+shouldBe(object + 42, `Hey42`);
+delete object.__proto__.toString;
+shouldBe(object + 42, `[object Object]42`);

Added: trunk/JSTests/stress/delete-cached-value-of-property.js (0 => 266567)


--- trunk/JSTests/stress/delete-cached-value-of-property.js	                        (rev 0)
+++ trunk/JSTests/stress/delete-cached-value-of-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,35 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+var object = {
+    __proto__: {
+        toString: undefined,
+        valueOf: function () {
+            return 42;
+        }
+    }
+};
+
+shouldBe(object + 42, 84);
+shouldBe(object + 42, 84);
+delete object.__proto__.valueOf;
+shouldThrow(() => {
+    object + 42;
+}, `TypeError: No default value`);

Added: trunk/JSTests/stress/hide-cached-to-primitive-property.js (0 => 266567)


--- trunk/JSTests/stress/hide-cached-to-primitive-property.js	                        (rev 0)
+++ trunk/JSTests/stress/hide-cached-to-primitive-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,13 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+object.__proto__ = {};
+shouldBe(object + 42, `[object Object]42`);
+shouldBe(object + 42, `[object Object]42`);
+object.__proto__[Symbol.toPrimitive] = function () {
+    return 42;
+};
+shouldBe(object + 42, 84);

Added: trunk/JSTests/stress/hide-cached-to-string-property.js (0 => 266567)


--- trunk/JSTests/stress/hide-cached-to-string-property.js	                        (rev 0)
+++ trunk/JSTests/stress/hide-cached-to-string-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,13 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+object.__proto__ = {};
+shouldBe(object + 42, `[object Object]42`);
+shouldBe(object + 42, `[object Object]42`);
+object.__proto__.toString = function () {
+    return "Hey";
+};
+shouldBe(object + 42, `Hey42`);

Added: trunk/JSTests/stress/hide-cached-value-of-property.js (0 => 266567)


--- trunk/JSTests/stress/hide-cached-value-of-property.js	                        (rev 0)
+++ trunk/JSTests/stress/hide-cached-value-of-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,14 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+object.__proto__ = {};
+shouldBe(object + 42, `[object Object]42`);
+shouldBe(object + 42, `[object Object]42`);
+object.__proto__.toString = undefined;
+object.__proto__.valueOf = function () {
+    return 42;
+};
+shouldBe(object + 42, 84);

Added: trunk/JSTests/stress/replace-cached-to-primitive-property.js (0 => 266567)


--- trunk/JSTests/stress/replace-cached-to-primitive-property.js	                        (rev 0)
+++ trunk/JSTests/stress/replace-cached-to-primitive-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+object.__proto__ = {
+    [Symbol.toPrimitive]: function () {
+        return 42;
+    }
+};
+shouldBe(object + 42, 84);
+shouldBe(object + 42, 84);
+object.__proto__[Symbol.toPrimitive] = function () {
+    return 45;
+};
+shouldBe(object + 42, 87);

Added: trunk/JSTests/stress/replace-cached-to-string-property.js (0 => 266567)


--- trunk/JSTests/stress/replace-cached-to-string-property.js	                        (rev 0)
+++ trunk/JSTests/stress/replace-cached-to-string-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+object.__proto__ = {
+    toString: function () {
+        return "Hi";
+    }
+};
+shouldBe(object + 42, `Hi42`);
+shouldBe(object + 42, `Hi42`);
+object.__proto__.toString = function () {
+    return "Hey";
+};
+shouldBe(object + 42, `Hey42`);

Added: trunk/JSTests/stress/replace-cached-value-of-property.js (0 => 266567)


--- trunk/JSTests/stress/replace-cached-value-of-property.js	                        (rev 0)
+++ trunk/JSTests/stress/replace-cached-value-of-property.js	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+object.__proto__ = {
+    toString: undefined,
+    valueOf: function () {
+        return 42;
+    }
+};
+shouldBe(object + 42, 84);
+shouldBe(object + 42, 84);
+object.__proto__.valueOf = function () {
+    return 43;
+};
+shouldBe(object + 42, 85);

Modified: trunk/Source/_javascript_Core/ChangeLog (266566 => 266567)


--- trunk/Source/_javascript_Core/ChangeLog	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-09-04 01:03:33 UTC (rev 266567)
@@ -1,3 +1,67 @@
+2020-09-02  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Cache toString / valueOf / @@toPrimitive for major cases
+        https://bugs.webkit.org/show_bug.cgi?id=216061
+
+        Reviewed by Saam Barati.
+
+        When toPrimitive is called, we need to look-up three properties at most to perform operation. And these special properties do not have caching mechanism at all.
+        We found that Speedometer2/EmberJS-Debug-TodoMVC is using very much time for this property look-up. We should have caching mechanism in StructureRareData, which
+        should be similar to @@toStringTag & Object#toString caching mechanism.
+
+        This patch generalizes @@toStringTag & Object#toString caching mechanism as SpecialPropertyCache. And we accelerate toString / valueOf / @@toPrimitive look-ups in
+        toPrimitive with this caching mechanism.
+
+        This patch improved Speedometer2/EmberJS-Debug-TodoMVC by 10%.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * bytecode/Watchpoint.cpp:
+        * bytecode/Watchpoint.h:
+        * runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp: Renamed from Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp.
+        (JSC::CachedSpecialPropertyAdaptiveStructureWatchpoint::CachedSpecialPropertyAdaptiveStructureWatchpoint):
+        (JSC::CachedSpecialPropertyAdaptiveStructureWatchpoint::install):
+        (JSC::CachedSpecialPropertyAdaptiveStructureWatchpoint::fireInternal):
+        * runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.h: Renamed from Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.h.
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::objectProtoToStringFunction const):
+        * runtime/JSObject.cpp:
+        (JSC::callToPrimitiveFunction):
+        (JSC::JSObject::ordinaryToPrimitive const):
+        (JSC::JSObject::toPrimitive const):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::ObjectPrototype::finishCreation):
+        (JSC::objectProtoFuncToString):
+        * runtime/Structure.h:
+        * runtime/StructureInlines.h:
+        (JSC::Structure::cacheSpecialProperty):
+        (JSC::Structure::setObjectToStringValue): Deleted.
+        * runtime/StructureRareData.cpp:
+        (JSC::StructureRareData::visitChildren):
+        (JSC::StructureRareData::ensureSpecialPropertyCacheSlow):
+        (JSC::StructureRareData::giveUpOnSpecialPropertyCache):
+        (JSC::StructureRareData::cacheSpecialPropertySlow):
+        (JSC::StructureRareData::clearCachedSpecialProperty):
+        (JSC::StructureRareData::finalizeUnconditionally):
+        (JSC::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint):
+        (JSC::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::isValid const):
+        (JSC::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::handleFire):
+        (JSC::StructureRareData::setObjectToStringValue): Deleted.
+        (JSC::StructureRareData::clearObjectToStringValue): Deleted.
+        (JSC::ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint): Deleted.
+        (JSC::ObjectToStringAdaptiveInferredPropertyValueWatchpoint::isValid const): Deleted.
+        (JSC::ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire): Deleted.
+        * runtime/StructureRareData.h:
+        * runtime/StructureRareDataInlines.h:
+        (JSC::StructureRareData::cachedSpecialProperty const):
+        (JSC::StructureRareData::canCacheSpecialProperty):
+        (JSC::StructureRareData::ensureSpecialPropertyCache):
+        (JSC::StructureRareData::cacheSpecialProperty):
+        (JSC::StructureRareData::objectToStringValue const): Deleted.
+
 2020-09-03  Saam Barati  <sbar...@apple.com>
 
         Sampling profiler should dump hash as part of the top function key to prevent incorrectly grouping nameless functions together

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (266566 => 266567)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-09-04 01:03:33 UTC (rev 266567)
@@ -1862,7 +1862,7 @@
 		E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E39D8B2E23021E2600265852 /* WasmOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D8B2D23021E1E00265852 /* WasmOperations.h */; };
 		E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		E39EEAF322812450008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */; };
+		E39EEAF322812450008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E39EEAF22281244C008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.h */; };
 		E39FEBE32339C5D900B40AB0 /* JSAsyncGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = E39FEBE22339C5D400B40AB0 /* JSAsyncGenerator.h */; };
 		E3A0531A21342B680022EC14 /* WasmStreamingParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531621342B660022EC14 /* WasmStreamingParser.h */; };
 		E3A0531C21342B680022EC14 /* WasmSectionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531821342B670022EC14 /* WasmSectionParser.h */; };
@@ -5075,8 +5075,8 @@
 		E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; };
 		E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = "<group>"; };
 		E39E030D22D9EA3E00408C18 /* WebAssembly.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = WebAssembly.js; sourceTree = "<group>"; };
-		E39EEAF12281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectToStringAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
-		E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjectToStringAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; };
+		E39EEAF12281244C008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
+		E39EEAF22281244C008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CachedSpecialPropertyAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; };
 		E39FEBE12339C5D400B40AB0 /* JSAsyncGenerator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSAsyncGenerator.cpp; sourceTree = "<group>"; };
 		E39FEBE22339C5D400B40AB0 /* JSAsyncGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSAsyncGenerator.h; sourceTree = "<group>"; };
 		E3A0531621342B660022EC14 /* WasmStreamingParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmStreamingParser.h; sourceTree = "<group>"; };
@@ -7128,6 +7128,8 @@
 				FE8DE54C23AC1E86005C9142 /* CacheableIdentifierInlines.h */,
 				148B1419225DD1E900D6E998 /* CachedBytecode.cpp */,
 				144CA34F221F037900817789 /* CachedBytecode.h */,
+				E39EEAF12281244C008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp */,
+				E39EEAF22281244C008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.h */,
 				14DAFA4521E3B871004B68F7 /* CachedTypes.cpp */,
 				143BE26521C857770020CD17 /* CachedTypes.h */,
 				148B141B225DD1EA00D6E998 /* CachePayload.cpp */,
@@ -7612,8 +7614,6 @@
 				E3C295DC1ED2CBAA00D3016F /* ObjectPropertyChangeAdaptiveWatchpoint.h */,
 				BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */,
 				BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */,
-				E39EEAF12281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.cpp */,
-				E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */,
 				F692A8770255597D01FF60F7 /* Operations.cpp */,
 				F692A8780255597D01FF60F7 /* Operations.h */,
 				0FE228EA1436AB2300196C48 /* Options.cpp */,
@@ -9266,6 +9266,7 @@
 				FE8DE54D23AC1E86005C9142 /* CacheableIdentifierInlines.h in Headers */,
 				144CA3502224180100817789 /* CachedBytecode.h in Headers */,
 				65B8392E1BACAD360044E824 /* CachedRecovery.h in Headers */,
+				E39EEAF322812450008474F4 /* CachedSpecialPropertyAdaptiveStructureWatchpoint.h in Headers */,
 				14F09C2A2231923100CF88EB /* CachedTypes.h in Headers */,
 				1409ECC1225E178C00BEDD54 /* CachePayload.h in Headers */,
 				1409ECC0225E178100BEDD54 /* CacheUpdate.h in Headers */,
@@ -10199,7 +10200,6 @@
 				0FD3E40A1B618B6600C80E1E /* ObjectPropertyCondition.h in Headers */,
 				0FD3E40C1B618B6600C80E1E /* ObjectPropertyConditionSet.h in Headers */,
 				BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */,
-				E39EEAF322812450008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h in Headers */,
 				E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
 				14F79F70216EAFD200046D39 /* Opcode.h in Headers */,
 				FE64872E2141D04800AB0D3E /* OpcodeInlines.h in Headers */,

Modified: trunk/Source/_javascript_Core/Sources.txt (266566 => 266567)


--- trunk/Source/_javascript_Core/Sources.txt	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/Sources.txt	2020-09-04 01:03:33 UTC (rev 266567)
@@ -740,6 +740,7 @@
 runtime/CacheUpdate.cpp
 runtime/CacheableIdentifier.cpp
 runtime/CachedBytecode.cpp
+runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp
 runtime/CachedTypes.cpp
 runtime/CatchScope.cpp
 runtime/ClassInfo.cpp
@@ -939,7 +940,6 @@
 runtime/ObjectConstructor.cpp
 runtime/ObjectInitializationScope.cpp
 runtime/ObjectPrototype.cpp
-runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp
 runtime/Operations.cpp
 runtime/Options.cpp
 runtime/PredictionFileCreatingFuzzerAgent.cpp

Modified: trunk/Source/_javascript_Core/bytecode/Watchpoint.cpp (266566 => 266567)


--- trunk/Source/_javascript_Core/bytecode/Watchpoint.cpp	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/bytecode/Watchpoint.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -27,12 +27,12 @@
 #include "Watchpoint.h"
 
 #include "AdaptiveInferredPropertyValueWatchpointBase.h"
+#include "CachedSpecialPropertyAdaptiveStructureWatchpoint.h"
 #include "CodeBlockJettisoningWatchpoint.h"
 #include "DFGAdaptiveStructureWatchpoint.h"
 #include "FunctionRareData.h"
 #include "HeapInlines.h"
 #include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
-#include "ObjectToStringAdaptiveStructureWatchpoint.h"
 #include "StructureStubClearingWatchpoint.h"
 #include "VM.h"
 

Modified: trunk/Source/_javascript_Core/bytecode/Watchpoint.h (266566 => 266567)


--- trunk/Source/_javascript_Core/bytecode/Watchpoint.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/bytecode/Watchpoint.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -114,7 +114,7 @@
     macro(CodeBlockJettisoning, CodeBlockJettisoningWatchpoint) \
     macro(LLIntPrototypeLoadAdaptiveStructure, LLIntPrototypeLoadAdaptiveStructureWatchpoint) \
     macro(FunctionRareDataAllocationProfileClearing, FunctionRareData::AllocationProfileClearingWatchpoint) \
-    macro(ObjectToStringAdaptiveStructure, ObjectToStringAdaptiveStructureWatchpoint)
+    macro(CachedSpecialPropertyAdaptiveStructure, CachedSpecialPropertyAdaptiveStructureWatchpoint)
 
 #if ENABLE(JIT)
 #define JSC_WATCHPOINT_TYPES_WITHOUT_DFG(macro) \

Copied: trunk/Source/_javascript_Core/runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp (from rev 266565, trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp) (0 => 266567)


--- trunk/Source/_javascript_Core/runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019-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. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CachedSpecialPropertyAdaptiveStructureWatchpoint.h"
+
+#include "JSCellInlines.h"
+#include "StructureRareData.h"
+
+namespace JSC {
+
+CachedSpecialPropertyAdaptiveStructureWatchpoint::CachedSpecialPropertyAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
+    : Watchpoint(Watchpoint::Type::CachedSpecialPropertyAdaptiveStructure)
+    , m_structureRareData(structureRareData)
+    , m_key(key)
+{
+    RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
+    RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint());
+}
+
+void CachedSpecialPropertyAdaptiveStructureWatchpoint::install(VM& vm)
+{
+    RELEASE_ASSERT(m_key.isWatchable());
+
+    m_key.object()->structure(vm)->addTransitionWatchpoint(this);
+}
+
+void CachedSpecialPropertyAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&)
+{
+    if (!m_structureRareData->isLive())
+        return;
+
+    if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
+        install(vm);
+        return;
+    }
+
+    CachedSpecialPropertyKey key = CachedSpecialPropertyKey::ToStringTag;
+    if (m_key.uid() == vm.propertyNames->toStringTagSymbol.impl())
+        key = CachedSpecialPropertyKey::ToStringTag;
+    else if (m_key.uid() == vm.propertyNames->toString.impl())
+        key = CachedSpecialPropertyKey::ToString;
+    else if (m_key.uid() == vm.propertyNames->valueOf.impl())
+        key = CachedSpecialPropertyKey::ValueOf;
+    else {
+        ASSERT(m_key.uid() == vm.propertyNames->toPrimitiveSymbol.impl());
+        key = CachedSpecialPropertyKey::ToPrimitive;
+    }
+
+    m_structureRareData->clearCachedSpecialProperty(key);
+}
+
+} // namespace JSC

Copied: trunk/Source/_javascript_Core/runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.h (from rev 266565, trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.h) (0 => 266567)


--- trunk/Source/_javascript_Core/runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/CachedSpecialPropertyAdaptiveStructureWatchpoint.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019-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. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ObjectPropertyCondition.h"
+#include "PackedCellPtr.h"
+#include "StructureRareData.h"
+#include "Watchpoint.h"
+
+namespace JSC {
+
+class StructureRareData;
+
+class CachedSpecialPropertyAdaptiveStructureWatchpoint final : public Watchpoint {
+public:
+    CachedSpecialPropertyAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
+
+    void install(VM&);
+
+    const ObjectPropertyCondition& key() const { return m_key; }
+
+    void fireInternal(VM&, const FireDetail&);
+    
+private:
+    // Own destructor may not be called. Keep members trivially destructible.
+    JSC_WATCHPOINT_FIELD(PackedCellPtr<StructureRareData>, m_structureRareData);
+    JSC_WATCHPOINT_FIELD(ObjectPropertyCondition, m_key);
+};
+
+}

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -610,6 +610,10 @@
     JSFunction* applyFunction = nullptr;
     JSFunction* hasInstanceSymbolFunction = nullptr;
     m_functionPrototype->addFunctionProperties(vm, this, &callFunction, &applyFunction, &hasInstanceSymbolFunction);
+    m_objectProtoToStringFunction.initLater(
+        [] (const Initializer<JSFunction>& init) {
+            init.set(JSFunction::create(init.vm, init.owner, 0, init.vm.propertyNames->toString.string(), objectProtoFuncToString, NoIntrinsic));
+        });
     m_arrayProtoToStringFunction.initLater(
         [] (const Initializer<JSFunction>& init) {
             init.set(JSFunction::create(init.vm, init.owner, 0, init.vm.propertyNames->toString.string(), arrayProtoFuncToString, NoIntrinsic));
@@ -1895,6 +1899,7 @@
 
     thisObject->m_parseIntFunction.visit(visitor);
     thisObject->m_parseFloatFunction.visit(visitor);
+    thisObject->m_objectProtoToStringFunction.visit(visitor);
     thisObject->m_arrayProtoToStringFunction.visit(visitor);
     thisObject->m_arrayProtoValuesFunction.visit(visitor);
     thisObject->m_evalFunction.visit(visitor);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -313,6 +313,7 @@
     LazyProperty<JSGlobalObject, JSFunction> m_parseIntFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_parseFloatFunction;
 
+    LazyProperty<JSGlobalObject, JSFunction> m_objectProtoToStringFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_arrayProtoToStringFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_arrayProtoValuesFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_evalFunction;
@@ -633,6 +634,7 @@
 
     JSFunction* evalFunction() const { return m_evalFunction.get(this); }
     JSFunction* throwTypeErrorFunction() const;
+    JSFunction* objectProtoToStringFunction() const { return m_objectProtoToStringFunction.get(this); }
     JSFunction* arrayProtoToStringFunction() const { return m_arrayProtoToStringFunction.get(this); }
     JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(this); }
     JSFunction* arrayProtoValuesFunctionConcurrently() const { return m_arrayProtoValuesFunction.getConcurrently(); }

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -2144,33 +2144,46 @@
     }
 }
 
-enum class TypeHintMode { TakesHint, DoesNotTakeHint };
-
-template<TypeHintMode mode = TypeHintMode::DoesNotTakeHint>
+template<CachedSpecialPropertyKey key>
 static ALWAYS_INLINE JSValue callToPrimitiveFunction(JSGlobalObject* globalObject, const JSObject* object, PropertyName propertyName, PreferredPrimitiveType hint)
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
-    // FIXME: Remove this when we have fixed: rdar://problem/33451840
-    // https://bugs.webkit.org/show_bug.cgi?id=187109.
-    constexpr bool debugNullStructure = mode == TypeHintMode::TakesHint;
-    bool hasProperty = const_cast<JSObject*>(object)->getPropertySlot<debugNullStructure>(globalObject, propertyName, slot);
-    RETURN_IF_EXCEPTION(scope, scope.exception());
-    JSValue function = hasProperty ? slot.getValue(globalObject, propertyName) : jsUndefined();
-    RETURN_IF_EXCEPTION(scope, scope.exception());
-    if (function.isUndefinedOrNull() && mode == TypeHintMode::TakesHint)
+    JSValue function = object->structure(vm)->cachedSpecialProperty(key);
+    if (!function) {
+        PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
+        // FIXME: Remove this when we have fixed: rdar://problem/33451840
+        // https://bugs.webkit.org/show_bug.cgi?id=187109.
+        constexpr bool debugNullStructure = key == CachedSpecialPropertyKey::ToPrimitive;
+        bool hasProperty = const_cast<JSObject*>(object)->getPropertySlot<debugNullStructure>(globalObject, propertyName, slot);
+        RETURN_IF_EXCEPTION(scope, scope.exception());
+        function = hasProperty ? slot.getValue(globalObject, propertyName) : jsUndefined();
+        RETURN_IF_EXCEPTION(scope, scope.exception());
+        object->structure(vm)->cacheSpecialProperty(globalObject, vm, function, key, slot);
+        RETURN_IF_EXCEPTION(scope, scope.exception());
+    }
+    if (function.isUndefinedOrNull())
         return JSValue();
+
+    // Add optimizations for frequently called functions.
+    // https://bugs.webkit.org/show_bug.cgi?id=216084
+    if constexpr (key == CachedSpecialPropertyKey::ToString) {
+        if (function == globalObject->objectProtoToStringFunction()) {
+            if (auto result = object->structure(vm)->cachedSpecialProperty(CachedSpecialPropertyKey::ToStringTag))
+                return result;
+        }
+    }
+
     auto callData = getCallData(vm, function);
     if (callData.type == CallData::Type::None) {
-        if (mode == TypeHintMode::TakesHint)
+        if constexpr (key == CachedSpecialPropertyKey::ToPrimitive)
             throwTypeError(globalObject, scope, "Symbol.toPrimitive is not a function, undefined, or null"_s);
         return scope.exception();
     }
 
     MarkedArgumentBuffer callArgs;
-    if (mode == TypeHintMode::TakesHint) {
+    if constexpr (key == CachedSpecialPropertyKey::ToPrimitive) {
         JSString* hintString = nullptr;
         switch (hint) {
         case NoPreference:
@@ -2190,8 +2203,11 @@
     JSValue result = call(globalObject, function, callData, const_cast<JSObject*>(object), callArgs);
     RETURN_IF_EXCEPTION(scope, scope.exception());
     ASSERT(!result.isGetterSetter());
-    if (result.isObject())
-        return mode == TypeHintMode::DoesNotTakeHint ? JSValue() : throwTypeError(globalObject, scope, "Symbol.toPrimitive returned an object"_s);
+    if (result.isObject()) {
+        if constexpr (key == CachedSpecialPropertyKey::ToPrimitive)
+            return throwTypeError(globalObject, scope, "Symbol.toPrimitive returned an object"_s);
+        return JSValue();
+    }
     return result;
 }
 
@@ -2203,25 +2219,27 @@
 
     // Make sure that whatever default value methods there are on object's prototype chain are
     // being watched.
+    // FIXME: Remove this hack for DFG.
+    // https://bugs.webkit.org/show_bug.cgi?id=216117
     for (const JSObject* object = this; object; object = object->structure(vm)->storedPrototypeObject(object))
         object->structure(vm)->startWatchingInternalPropertiesIfNecessary(vm);
 
     JSValue value;
     if (hint == PreferString) {
-        value = callToPrimitiveFunction(globalObject, this, vm.propertyNames->toString, hint);
+        value = callToPrimitiveFunction<CachedSpecialPropertyKey::ToString>(globalObject, this, vm.propertyNames->toString, hint);
         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
         if (value)
             return value;
-        value = callToPrimitiveFunction(globalObject, this, vm.propertyNames->valueOf, hint);
+        value = callToPrimitiveFunction<CachedSpecialPropertyKey::ValueOf>(globalObject, this, vm.propertyNames->valueOf, hint);
         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
         if (value)
             return value;
     } else {
-        value = callToPrimitiveFunction(globalObject, this, vm.propertyNames->valueOf, hint);
+        value = callToPrimitiveFunction<CachedSpecialPropertyKey::ValueOf>(globalObject, this, vm.propertyNames->valueOf, hint);
         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
         if (value)
             return value;
-        value = callToPrimitiveFunction(globalObject, this, vm.propertyNames->toString, hint);
+        value = callToPrimitiveFunction<CachedSpecialPropertyKey::ToString>(globalObject, this, vm.propertyNames->toString, hint);
         EXCEPTION_ASSERT(!scope.exception() || scope.exception() == value.asCell());
         if (value)
             return value;
@@ -2242,7 +2260,7 @@
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    JSValue value = callToPrimitiveFunction<TypeHintMode::TakesHint>(globalObject, this, vm.propertyNames->toPrimitiveSymbol, preferredType);
+    JSValue value = callToPrimitiveFunction<CachedSpecialPropertyKey::ToPrimitive>(globalObject, this, vm.propertyNames->toPrimitiveSymbol, preferredType);
     RETURN_IF_EXCEPTION(scope, { });
     if (value)
         return value;

Modified: trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -53,7 +53,7 @@
     Base::finishCreation(vm);
     ASSERT(inherits(vm, info()));
     
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
+    putDirectWithoutTransition(vm, vm.propertyNames->toString, globalObject->objectProtoToStringFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, HasOwnPropertyIntrinsic);
@@ -325,7 +325,7 @@
         return JSValue::encode(jsUndefined());
 
     Integrity::auditStructureID(vm, thisObject->structureID());
-    auto result = thisObject->structure(vm)->objectToStringValue();
+    auto result = thisObject->structure(vm)->cachedSpecialProperty(CachedSpecialPropertyKey::ToStringTag);
     if (result)
         return JSValue::encode(result);
 
@@ -350,7 +350,7 @@
 
     JSString* jsResult = jsString(globalObject, vm.smallStrings.objectStringStart(), jsTag, vm.smallStrings.singleCharacterString(']'));
     RETURN_IF_EXCEPTION(scope, { });
-    thisObject->structure(vm)->setObjectToStringValue(globalObject, vm, jsResult, slot);
+    thisObject->structure(vm)->cacheSpecialProperty(globalObject, vm, jsResult, CachedSpecialPropertyKey::ToStringTag, slot);
     return JSValue::encode(jsResult);
 }
 

Deleted: trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ObjectToStringAdaptiveStructureWatchpoint.h"
-
-#include "JSCellInlines.h"
-#include "StructureRareData.h"
-
-namespace JSC {
-
-ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
-    : Watchpoint(Watchpoint::Type::ObjectToStringAdaptiveStructure)
-    , m_structureRareData(structureRareData)
-    , m_key(key)
-{
-    RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
-    RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint());
-}
-
-void ObjectToStringAdaptiveStructureWatchpoint::install(VM& vm)
-{
-    RELEASE_ASSERT(m_key.isWatchable());
-
-    m_key.object()->structure(vm)->addTransitionWatchpoint(this);
-}
-
-void ObjectToStringAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&)
-{
-    if (!m_structureRareData->isLive())
-        return;
-
-    if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
-        install(vm);
-        return;
-    }
-
-    m_structureRareData->clearObjectToStringValue();
-}
-
-} // namespace JSC

Deleted: trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.h (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/ObjectToStringAdaptiveStructureWatchpoint.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "ObjectPropertyCondition.h"
-#include "PackedCellPtr.h"
-#include "StructureRareData.h"
-#include "Watchpoint.h"
-
-namespace JSC {
-
-class StructureRareData;
-
-class ObjectToStringAdaptiveStructureWatchpoint final : public Watchpoint {
-public:
-    ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
-
-    void install(VM&);
-
-    const ObjectPropertyCondition& key() const { return m_key; }
-
-    void fireInternal(VM&, const FireDetail&);
-    
-private:
-    // Own destructor may not be called. Keep members trivially destructible.
-    JSC_WATCHPOINT_FIELD(PackedCellPtr<StructureRareData>, m_structureRareData);
-    JSC_WATCHPOINT_FIELD(ObjectPropertyCondition, m_key);
-};
-
-}

Modified: trunk/Source/_javascript_Core/runtime/Structure.h (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/Structure.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/Structure.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -529,15 +529,14 @@
 
     void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
 
-    JSString* objectToStringValue()
+    JSValue cachedSpecialProperty(CachedSpecialPropertyKey key)
     {
         if (!hasRareData())
-            return nullptr;
-        return rareData()->objectToStringValue();
+            return JSValue();
+        return rareData()->cachedSpecialProperty(key);
     }
+    void cacheSpecialProperty(JSGlobalObject*, VM&, JSValue, CachedSpecialPropertyKey, const PropertySlot&);
 
-    void setObjectToStringValue(JSGlobalObject*, VM&, JSString* value, const PropertySlot& toStringTagSymbolSlot);
-
     const ClassInfo* classInfo() const { return m_classInfo; }
 
     static ptrdiff_t structureIDOffset()

Modified: trunk/Source/_javascript_Core/runtime/StructureInlines.h (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/StructureInlines.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/StructureInlines.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -427,11 +427,11 @@
     return currentCapacity * outOfLineGrowthFactor;
 }
 
-inline void Structure::setObjectToStringValue(JSGlobalObject* globalObject, VM& vm, JSString* value, const PropertySlot& toStringTagSymbolSlot)
+inline void Structure::cacheSpecialProperty(JSGlobalObject* globalObject, VM& vm, JSValue value, CachedSpecialPropertyKey key, const PropertySlot& slot)
 {
     if (!hasRareData())
         allocateRareData(vm);
-    rareData()->setObjectToStringValue(globalObject, vm, this, value, toStringTagSymbolSlot);
+    rareData()->cacheSpecialProperty(globalObject, vm, this, value, key, slot);
 }
 
 template<Structure::ShouldPin shouldPin, typename Func>

Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.cpp (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/StructureRareData.cpp	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.cpp	2020-09-04 01:03:33 UTC (rev 266567)
@@ -27,12 +27,12 @@
 #include "StructureRareData.h"
 
 #include "AdaptiveInferredPropertyValueWatchpointBase.h"
+#include "CachedSpecialPropertyAdaptiveStructureWatchpoint.h"
 #include "JSImmutableButterfly.h"
 #include "JSObjectInlines.h"
 #include "JSPropertyNameEnumerator.h"
 #include "JSString.h"
 #include "ObjectPropertyConditionSet.h"
-#include "ObjectToStringAdaptiveStructureWatchpoint.h"
 #include "StructureChain.h"
 #include "StructureInlines.h"
 #include "StructureRareDataInlines.h"
@@ -74,7 +74,10 @@
 
     Base::visitChildren(thisObject, visitor);
     visitor.append(thisObject->m_previous);
-    visitor.appendUnbarriered(thisObject->objectToStringValue());
+    if (thisObject->m_specialPropertyCache) {
+        for (unsigned index = 0; index < numberOfCachedSpecialPropertyKeys; ++index)
+            visitor.appendUnbarriered(thisObject->cachedSpecialProperty(static_cast<CachedSpecialPropertyKey>(index)));
+    }
     visitor.append(thisObject->m_cachedPropertyNameEnumerator);
     for (unsigned index = 0; index < numberOfCachedPropertyNames; ++index) {
         auto* cached = thisObject->m_cachedPropertyNames[index].unvalidatedGet();
@@ -83,12 +86,12 @@
     }
 }
 
-// ----------- Object.prototype.toString() helper watchpoint classes -----------
+// ----------- Cached special properties helper watchpoint classes -----------
 
-class ObjectToStringAdaptiveInferredPropertyValueWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
+class CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
 public:
     typedef AdaptiveInferredPropertyValueWatchpointBase Base;
-    ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
+    CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
 
 private:
     bool isValid() const final;
@@ -97,33 +100,61 @@
     StructureRareData* m_structureRareData;
 };
 
-void StructureRareData::setObjectToStringValue(JSGlobalObject* globalObject, VM& vm, Structure* ownStructure, JSString* value, const PropertySlot& toStringTagSymbolSlot)
+SpecialPropertyCacheEntry::~SpecialPropertyCacheEntry() = default;
+
+SpecialPropertyCache& StructureRareData::ensureSpecialPropertyCacheSlow()
 {
-    if (canCacheObjectToStringValue())
-        return;
+    ASSERT(!isCompilationThread() && !Thread::mayBeGCThread());
+    ASSERT(!m_specialPropertyCache);
+    auto cache = makeUnique<SpecialPropertyCache>();
+    WTF::storeStoreFence(); // Expose valid struct for concurrent threads including concurrent compilers.
+    m_specialPropertyCache = WTFMove(cache);
+    return *m_specialPropertyCache.get();
+}
 
+inline void StructureRareData::giveUpOnSpecialPropertyCache(CachedSpecialPropertyKey key)
+{
+    ensureSpecialPropertyCache().m_cache[static_cast<unsigned>(key)].m_value.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects());
+}
+
+void StructureRareData::cacheSpecialPropertySlow(JSGlobalObject* globalObject, VM& vm, Structure* ownStructure, JSValue value, CachedSpecialPropertyKey key, const PropertySlot& slot)
+{
+    UniquedStringImpl* uid = nullptr;
+    switch (key) {
+    case CachedSpecialPropertyKey::ToStringTag:
+        uid = vm.propertyNames->toStringTagSymbol.impl();
+        break;
+    case CachedSpecialPropertyKey::ToString:
+        uid = vm.propertyNames->toString.impl();
+        break;
+    case CachedSpecialPropertyKey::ValueOf:
+        uid = vm.propertyNames->valueOf.impl();
+        break;
+    case CachedSpecialPropertyKey::ToPrimitive:
+        uid = vm.propertyNames->toPrimitiveSymbol.impl();
+        break;
+    }
     ObjectPropertyConditionSet conditionSet;
-    if (toStringTagSymbolSlot.isValue()) {
-        // We don't handle the own property case of Symbol.toStringTag because we would never know if a new
-        // object transitioning to the same structure had the same value stored in Symbol.toStringTag.
+    if (slot.isValue()) {
+        // We don't handle the own property case of special properties (toString, valueOf, @@toPrimitive, @@toStringTag) because we would never know if a new
+        // object transitioning to the same structure had the same value stored in that property.
         // Additionally, this is a super unlikely case anyway.
-        if (!toStringTagSymbolSlot.isCacheable() || toStringTagSymbolSlot.slotBase()->structure(vm) == ownStructure)
+        if (!slot.isCacheable() || slot.slotBase()->structure(vm) == ownStructure)
             return;
 
-
-        // This will not create a condition for the current structure but that is good because we know the Symbol.toStringTag
+        // This will not create a condition for the current structure but that is good because we know that property
         // is not on the ownStructure so we will transisition if one is added and this cache will no longer be used.
-        prepareChainForCaching(globalObject, ownStructure, toStringTagSymbolSlot.slotBase());
-        conditionSet = generateConditionsForPrototypePropertyHit(vm, this, globalObject, ownStructure, toStringTagSymbolSlot.slotBase(), vm.propertyNames->toStringTagSymbol.impl());
+        prepareChainForCaching(globalObject, ownStructure, slot.slotBase());
+        conditionSet = generateConditionsForPrototypePropertyHit(vm, this, globalObject, ownStructure, slot.slotBase(), uid);
         ASSERT(!conditionSet.isValid() || conditionSet.hasOneSlotBaseCondition());
-    } else if (toStringTagSymbolSlot.isUnset()) {
+    } else if (slot.isUnset()) {
         prepareChainForCaching(globalObject, ownStructure, nullptr);
-        conditionSet = generateConditionsForPropertyMiss(vm, this, globalObject, ownStructure, vm.propertyNames->toStringTagSymbol.impl());
+        conditionSet = generateConditionsForPropertyMiss(vm, this, globalObject, ownStructure, uid);
     } else
         return;
 
     if (!conditionSet.isValid()) {
-        giveUpOnObjectToStringValueCache();
+        giveUpOnSpecialPropertyCache(key);
         return;
     }
 
@@ -136,67 +167,90 @@
 
             // The equivalence condition won't be watchable if we have already seen a replacement.
             if (!equivCondition.isWatchable()) {
-                giveUpOnObjectToStringValueCache();
+                giveUpOnSpecialPropertyCache(key);
                 return;
             }
         } else if (!condition.isWatchable()) {
-            giveUpOnObjectToStringValueCache();
+            giveUpOnSpecialPropertyCache(key);
             return;
         }
     }
 
     ASSERT(conditionSet.structuresEnsureValidity());
+    auto& cache = ensureSpecialPropertyCache().m_cache[static_cast<unsigned>(key)];
     for (ObjectPropertyCondition condition : conditionSet) {
         if (condition.condition().kind() == PropertyCondition::Presence) {
-            m_objectToStringAdaptiveInferredValueWatchpoint = makeUnique<ObjectToStringAdaptiveInferredPropertyValueWatchpoint>(equivCondition, this);
-            m_objectToStringAdaptiveInferredValueWatchpoint->install(vm);
+            cache.m_equivalenceWatchpoint = makeUnique<CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint>(equivCondition, this);
+            cache.m_equivalenceWatchpoint->install(vm);
         } else
-            m_objectToStringAdaptiveWatchpointSet.add(condition, this)->install(vm);
+            cache.m_missWatchpoints.add(condition, this)->install(vm);
     }
-
-    m_objectToStringValue.set(vm, this, value);
+    cache.m_value.set(vm, this, value);
 }
 
-void StructureRareData::clearObjectToStringValue()
+void StructureRareData::clearCachedSpecialProperty(CachedSpecialPropertyKey key)
 {
-    m_objectToStringAdaptiveWatchpointSet.clear();
-    m_objectToStringAdaptiveInferredValueWatchpoint.reset();
-    if (!canCacheObjectToStringValue())
-        m_objectToStringValue.clear();
+    auto* objectToStringCache = m_specialPropertyCache.get();
+    if (!objectToStringCache)
+        return;
+    auto& cache = objectToStringCache->m_cache[static_cast<unsigned>(key)];
+    cache.m_missWatchpoints.clear();
+    cache.m_equivalenceWatchpoint.reset();
+    if (cache.m_value.get() != JSCell::seenMultipleCalleeObjects())
+        cache.m_value.clear();
 }
 
 void StructureRareData::finalizeUnconditionally(VM& vm)
 {
-    if (m_objectToStringAdaptiveInferredValueWatchpoint) {
-        if (!m_objectToStringAdaptiveInferredValueWatchpoint->key().isStillLive(vm)) {
-            clearObjectToStringValue();
-            return;
-        }
+    if (m_specialPropertyCache) {
+        auto clearCacheIfInvalidated = [&](CachedSpecialPropertyKey key) {
+            auto& cache = m_specialPropertyCache->m_cache[static_cast<unsigned>(key)];
+            if (cache.m_equivalenceWatchpoint) {
+                if (!cache.m_equivalenceWatchpoint->key().isStillLive(vm)) {
+                    clearCachedSpecialProperty(key);
+                    return;
+                }
+            }
+            for (auto* watchpoint : cache.m_missWatchpoints) {
+                if (!watchpoint->key().isStillLive(vm)) {
+                    clearCachedSpecialProperty(key);
+                    return;
+                }
+            }
+        };
+
+        for (unsigned index = 0; index < numberOfCachedSpecialPropertyKeys; ++index)
+            clearCacheIfInvalidated(static_cast<CachedSpecialPropertyKey>(index));
     }
-    for (auto* watchpoint : m_objectToStringAdaptiveWatchpointSet) {
-        if (!watchpoint->key().isStillLive(vm)) {
-            clearObjectToStringValue();
-            return;
-        }
-    }
 }
 
 // ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
 
-ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
+CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
     : Base(key)
     , m_structureRareData(structureRareData)
 {
 }
 
-bool ObjectToStringAdaptiveInferredPropertyValueWatchpoint::isValid() const
+bool CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::isValid() const
 {
     return m_structureRareData->isLive();
 }
 
-void ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire(VM&, const FireDetail&)
+void CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint::handleFire(VM& vm, const FireDetail&)
 {
-    m_structureRareData->clearObjectToStringValue();
+    CachedSpecialPropertyKey key = CachedSpecialPropertyKey::ToStringTag;
+    if (this->key().uid() == vm.propertyNames->toStringTagSymbol.impl())
+        key = CachedSpecialPropertyKey::ToStringTag;
+    else if (this->key().uid() == vm.propertyNames->toString.impl())
+        key = CachedSpecialPropertyKey::ToString;
+    else if (this->key().uid() == vm.propertyNames->valueOf.impl())
+        key = CachedSpecialPropertyKey::ValueOf;
+    else {
+        ASSERT(this->key().uid() == vm.propertyNames->toPrimitiveSymbol.impl());
+        key = CachedSpecialPropertyKey::ToPrimitive;
+    }
+    m_structureRareData->clearCachedSpecialProperty(key);
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.h (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/StructureRareData.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -35,8 +35,9 @@
 
 class JSPropertyNameEnumerator;
 class Structure;
-class ObjectToStringAdaptiveInferredPropertyValueWatchpoint;
-class ObjectToStringAdaptiveStructureWatchpoint;
+class CachedSpecialPropertyAdaptiveStructureWatchpoint;
+class CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint;
+struct SpecialPropertyCache;
 enum class CachedPropertyNamesKind : uint8_t {
     Keys = 0,
     GetOwnPropertyNames,
@@ -43,6 +44,14 @@
 };
 static constexpr unsigned numberOfCachedPropertyNames = 2;
 
+enum class CachedSpecialPropertyKey : uint8_t {
+    ToStringTag = 0,
+    ToString,
+    ValueOf,
+    ToPrimitive,
+};
+static constexpr unsigned numberOfCachedSpecialPropertyKeys = 4;
+
 class StructureRareData final : public JSCell {
 public:
     typedef JSCell Base;
@@ -70,11 +79,8 @@
     void setPreviousID(VM&, Structure*);
     void clearPreviousID();
 
-    JSString* objectToStringValue() const;
-    void setObjectToStringValue(JSGlobalObject*, VM&, Structure* baseStructure, JSString* value, const PropertySlot& toStringTagSymbolSlot);
-    void giveUpOnObjectToStringValueCache() { m_objectToStringValue.setWithoutWriteBarrier(objectToStringCacheGiveUpMarker()); }
-    bool canCacheObjectToStringValue() { return m_objectToStringValue.unvalidatedGet() == objectToStringCacheGiveUpMarker(); }
-    static JSString* objectToStringCacheGiveUpMarker() { return bitwise_cast<JSString*>(static_cast<uintptr_t>(1)); }
+    JSValue cachedSpecialProperty(CachedSpecialPropertyKey) const;
+    void cacheSpecialProperty(JSGlobalObject*, VM&, Structure* baseStructure, JSValue, CachedSpecialPropertyKey, const PropertySlot&);
 
     JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
     void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
@@ -102,15 +108,20 @@
 
 private:
     friend class Structure;
-    friend class ObjectToStringAdaptiveStructureWatchpoint;
-    friend class ObjectToStringAdaptiveInferredPropertyValueWatchpoint;
+    friend class CachedSpecialPropertyAdaptiveStructureWatchpoint;
+    friend class CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint;
 
-    void clearObjectToStringValue();
-
     StructureRareData(VM&, Structure*);
 
+    void clearCachedSpecialProperty(CachedSpecialPropertyKey);
+    void cacheSpecialPropertySlow(JSGlobalObject*, VM&, Structure* baseStructure, JSValue, CachedSpecialPropertyKey, const PropertySlot&);
+
+    SpecialPropertyCache& ensureSpecialPropertyCache();
+    SpecialPropertyCache& ensureSpecialPropertyCacheSlow();
+    bool canCacheSpecialProperty(CachedSpecialPropertyKey);
+    void giveUpOnSpecialPropertyCache(CachedSpecialPropertyKey);
+
     WriteBarrier<Structure> m_previous;
-    WriteBarrier<JSString> m_objectToStringValue;
     // FIXME: We should have some story for clearing these property names caches in GC.
     // https://bugs.webkit.org/show_bug.cgi?id=192659
     WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator;
@@ -118,8 +129,7 @@
 
     typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap;
     std::unique_ptr<PropertyWatchpointMap> m_replacementWatchpointSets;
-    Bag<ObjectToStringAdaptiveStructureWatchpoint> m_objectToStringAdaptiveWatchpointSet;
-    std::unique_ptr<ObjectToStringAdaptiveInferredPropertyValueWatchpoint> m_objectToStringAdaptiveInferredValueWatchpoint;
+    std::unique_ptr<SpecialPropertyCache> m_specialPropertyCache;
     Box<InlineWatchpointSet> m_polyProtoWatchpoint;
 
     PropertyOffset m_maxOffset;

Modified: trunk/Source/_javascript_Core/runtime/StructureRareDataInlines.h (266566 => 266567)


--- trunk/Source/_javascript_Core/runtime/StructureRareDataInlines.h	2020-09-04 01:02:12 UTC (rev 266566)
+++ trunk/Source/_javascript_Core/runtime/StructureRareDataInlines.h	2020-09-04 01:03:33 UTC (rev 266567)
@@ -32,6 +32,21 @@
 
 namespace JSC {
 
+// FIXME: Use ObjectPropertyConditionSet instead.
+// https://bugs.webkit.org/show_bug.cgi?id=216112
+struct SpecialPropertyCacheEntry {
+    WTF_MAKE_STRUCT_FAST_ALLOCATED;
+    ~SpecialPropertyCacheEntry();
+    Bag<CachedSpecialPropertyAdaptiveStructureWatchpoint> m_missWatchpoints;
+    std::unique_ptr<CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint> m_equivalenceWatchpoint;
+    WriteBarrier<Unknown> m_value;
+};
+
+struct SpecialPropertyCache {
+    WTF_MAKE_STRUCT_FAST_ALLOCATED;
+    SpecialPropertyCacheEntry m_cache[numberOfCachedSpecialPropertyKeys];
+};
+
 inline void StructureRareData::setPreviousID(VM& vm, Structure* structure)
 {
     m_previous.set(vm, this, structure);
@@ -42,13 +57,18 @@
     m_previous.clear();
 }
 
-inline JSString* StructureRareData::objectToStringValue() const
+inline JSValue StructureRareData::cachedSpecialProperty(CachedSpecialPropertyKey key) const
 {
-    auto* value = m_objectToStringValue.unvalidatedGet();
-    if (value == objectToStringCacheGiveUpMarker())
-        return nullptr;
-    if (value)
-        validateCell(value);
+    auto* cache = m_specialPropertyCache.get();
+    if (!cache)
+        return JSValue();
+    JSValue value = cache->m_cache[static_cast<unsigned>(key)].m_value.get();
+    if (value == JSCell::seenMultipleCalleeObjects())
+        return JSValue();
+#if ASSERT_ENABLED
+    if (value && value.isCell())
+        validateCell(value.asCell());
+#endif
     return value;
 }
 
@@ -96,4 +116,28 @@
     m_cachedPropertyNames[static_cast<unsigned>(kind)].set(vm, this, butterfly);
 }
 
+inline bool StructureRareData::canCacheSpecialProperty(CachedSpecialPropertyKey key)
+{
+    ASSERT(!isCompilationThread() && !Thread::mayBeGCThread());
+    auto* cache = m_specialPropertyCache.get();
+    if (!cache)
+        return true;
+    return cache->m_cache[static_cast<unsigned>(key)].m_value.get() != JSCell::seenMultipleCalleeObjects();
+}
+
+inline SpecialPropertyCache& StructureRareData::ensureSpecialPropertyCache()
+{
+    ASSERT(!isCompilationThread() && !Thread::mayBeGCThread());
+    if (auto* cache = m_specialPropertyCache.get())
+        return *cache;
+    return ensureSpecialPropertyCacheSlow();
+}
+
+inline void StructureRareData::cacheSpecialProperty(JSGlobalObject* globalObject, VM& vm, Structure* ownStructure, JSValue value, CachedSpecialPropertyKey key, const PropertySlot& slot)
+{
+    if (!canCacheSpecialProperty(key))
+        return;
+    return cacheSpecialPropertySlow(globalObject, vm, ownStructure, value, key, slot);
+}
+
 } // namespace JSC
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to