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