Title: [275261] trunk/Source
Revision
275261
Author
wei...@apple.com
Date
2021-03-30 19:55:38 -0700 (Tue, 30 Mar 2021)

Log Message

JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap should be sets, not maps, and should use both the identifier and function pointer as the key
https://bugs.webkit.org/show_bug.cgi?id=223613

Reviewed by Saam Barati.

Source/_javascript_Core:

- Adds a generic WeakGCSet class to go with the existing WeakGCMap.
- Renames WeakGCMapBase to WeakGCHashTable, moves it to its own file
  and now uses it as the base class of both WeakGCSet and WeakGCMap.
- Replaces JSGlobalObject's customGetterFunctionMap/customSetterFunctionMap
  with customGetterFunctionSet/customSetterFunctionSet, using the new
  WeakGCSet, and updates them to use both the function pointer and
  property name for the key, rather than just the function pointer which
  is what the previous code did. This allows multiple custom functions
  to use the same underlying function pointer as long as they have distinct
  property names, which is going to be used to optimize the bindings for
  CSSStyleDeclaration.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
Add new files.

* heap/Heap.cpp:
(JSC::Heap::runEndPhase):
(JSC::Heap::pruneStaleEntriesFromWeakGCHashTables):
(JSC::Heap::registerWeakGCHashTable):
(JSC::Heap::unregisterWeakGCHashTable):
(JSC::Heap::pruneStaleEntriesFromWeakGCMaps): Deleted.
(JSC::Heap::registerWeakGCMap): Deleted.
(JSC::Heap::unregisterWeakGCMap): Deleted.
* heap/Heap.h:
Update for new name. WeakGCMapBase -> WeakGCHashTable.

* runtime/JSCInlines.h:
Add WeakGCSetInlines.h

* runtime/JSCustomGetterFunction.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
(JSC::JSCustomGetterFunction::JSCustomGetterFunction):
(JSC::JSCustomGetterFunction::create):
* runtime/JSCustomGetterFunction.h:
* runtime/JSCustomSetterFunction.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
(JSC::JSCustomSetterFunction::JSCustomSetterFunction):
(JSC::JSCustomSetterFunction::create):
* runtime/JSCustomSetterFunction.h:
Add helper type CustomFunctionPointer and helper function customFunctionPointer()
to allow some generic hashing code to run on either JSCustomGetterFunction
or JSCustomSetterFunction.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::WeakCustomGetterOrSetterHash::hash):
(JSC::JSGlobalObject::WeakCustomGetterOrSetterHash::equal):
(JSC::JSGlobalObject::customGetterFunctionSet):
(JSC::JSGlobalObject::customSetterFunctionSet):
(JSC::JSGlobalObject::customGetterFunctionMap): Deleted.
(JSC::JSGlobalObject::customSetterFunctionMap): Deleted.
Replace m_customGetterFunctionMap/m_customSetterFunctionMap with
m_customGetterFunctionSet/m_customSetterFunctionSet. As the key is included
in the value, it saves space to use a set rather than a map. We now also
hash and compare both the function pointer and the property name to allow
sharing implementations.

* runtime/JSObject.cpp:
(JSC::WeakCustomGetterOrSetterHashTranslator::hash):
(JSC::WeakCustomGetterOrSetterHashTranslator::equal):
(JSC::createCustomGetterFunction):
(JSC::createCustomSetterFunction):
Update creation functions to use the new sets, making use of the
ensureValue function and a HashTranslator allowing the use of a
std::pair<PropertyName, FunctionPointer> as an alternative lookup
key. This allows us to avoid creating the JSCustomGetterFunction/JSCustomSetterFunction
pointer if one with the same property name and function pointer are
already in the set.

* runtime/WeakGCHashTable.h: Added.
(JSC::WeakGCHashTable::~WeakGCHashTable):
Moved from WeakGCMap and renamed as it is now the base of both
WeakGCMap and WeakGCSet.

* runtime/WeakGCMap.h:
Update to use new WeakGCHashTable base class.

* runtime/WeakGCMapInlines.h:
(JSC::KeyTraitsArg>::WeakGCMap):
(JSC::KeyTraitsArg>::~WeakGCMap):
Update for new Heap function names for WeakGCHashTable.

* runtime/WeakGCSet.h: Added.
* runtime/WeakGCSetInlines.h: Added.
(JSC::TraitsArg>::WeakGCSet):
(JSC::TraitsArg>::~WeakGCSet):
(JSC::TraitsArg>::find):
(JSC::TraitsArg>::find const):
(JSC::TraitsArg>::contains const):
(JSC::TraitsArg>::pruneStaleEntries):
Added a minimal WeakGCSet based on WeakGCMap.

Source/WTF:

Adds a heterogenous HashSet::ensure, which allows lazy construction of the value to
insert into the HashSet only if the heterogenous key (e.g. a key + HashTranslator
that are not the same as the HashSet's ValueType) does not match any item in the
set. For example given a set of ExpensiveToConstruct, but uniquely identifiable
by CheapToConstruct:

    HashSet<ExpensiveToConstruct> hashSet;
    ...
    struct Translator {
        static unsigned hash(const CheapToConstruct& key)
        {
            return key.hash();
        }
        static bool equal(const ExpensiveToConstruct& a, const CheapToConstruct& b)
        {
            return a == b;
        }
    };

    hashSet.ensure<Translator>(CheapToConstruct { ... }, [] {
        return ExpensiveToConstruct { ... };
    });

This will be used by the custom getter/setter sets to avoid constructing the GC objects
unless they are really needed.

Also took the opertunity to replace some typedefs with usings, and fixed some comments.

* wtf/HashSet.h:
(WTF::Traits>::ensure):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (275260 => 275261)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2021-03-31 02:55:38 UTC (rev 275261)
@@ -1098,8 +1098,11 @@
     runtime/VMTraps.h
     runtime/VarOffset.h
     runtime/Watchdog.h
+    runtime/WeakGCHashTable.h
     runtime/WeakGCMap.h
     runtime/WeakGCMapInlines.h
+    runtime/WeakGCSet.h
+    runtime/WeakGCSetInlines.h
     runtime/WriteBarrier.h
     runtime/WriteBarrierInlines.h
 

Modified: trunk/Source/_javascript_Core/ChangeLog (275260 => 275261)


--- trunk/Source/_javascript_Core/ChangeLog	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-03-31 02:55:38 UTC (rev 275261)
@@ -1,3 +1,104 @@
+2021-03-30  Sam Weinig  <wei...@apple.com>
+
+        JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap should be sets, not maps, and should use both the identifier and function pointer as the key
+        https://bugs.webkit.org/show_bug.cgi?id=223613
+
+        Reviewed by Saam Barati.
+
+        - Adds a generic WeakGCSet class to go with the existing WeakGCMap.
+        - Renames WeakGCMapBase to WeakGCHashTable, moves it to its own file
+          and now uses it as the base class of both WeakGCSet and WeakGCMap.
+        - Replaces JSGlobalObject's customGetterFunctionMap/customSetterFunctionMap
+          with customGetterFunctionSet/customSetterFunctionSet, using the new
+          WeakGCSet, and updates them to use both the function pointer and 
+          property name for the key, rather than just the function pointer which
+          is what the previous code did. This allows multiple custom functions
+          to use the same underlying function pointer as long as they have distinct
+          property names, which is going to be used to optimize the bindings for
+          CSSStyleDeclaration.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        Add new files.
+
+        * heap/Heap.cpp:
+        (JSC::Heap::runEndPhase):
+        (JSC::Heap::pruneStaleEntriesFromWeakGCHashTables):
+        (JSC::Heap::registerWeakGCHashTable):
+        (JSC::Heap::unregisterWeakGCHashTable):
+        (JSC::Heap::pruneStaleEntriesFromWeakGCMaps): Deleted.
+        (JSC::Heap::registerWeakGCMap): Deleted.
+        (JSC::Heap::unregisterWeakGCMap): Deleted.
+        * heap/Heap.h:
+        Update for new name. WeakGCMapBase -> WeakGCHashTable.
+
+        * runtime/JSCInlines.h:
+        Add WeakGCSetInlines.h
+
+        * runtime/JSCustomGetterFunction.cpp:
+        (JSC::JSC_DEFINE_HOST_FUNCTION):
+        (JSC::JSCustomGetterFunction::JSCustomGetterFunction):
+        (JSC::JSCustomGetterFunction::create):
+        * runtime/JSCustomGetterFunction.h:
+        * runtime/JSCustomSetterFunction.cpp:
+        (JSC::JSC_DEFINE_HOST_FUNCTION):
+        (JSC::JSCustomSetterFunction::JSCustomSetterFunction):
+        (JSC::JSCustomSetterFunction::create):
+        * runtime/JSCustomSetterFunction.h:
+        Add helper type CustomFunctionPointer and helper function customFunctionPointer()
+        to allow some generic hashing code to run on either JSCustomGetterFunction
+        or JSCustomSetterFunction.
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::JSGlobalObject):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::WeakCustomGetterOrSetterHash::hash):
+        (JSC::JSGlobalObject::WeakCustomGetterOrSetterHash::equal):
+        (JSC::JSGlobalObject::customGetterFunctionSet):
+        (JSC::JSGlobalObject::customSetterFunctionSet):
+        (JSC::JSGlobalObject::customGetterFunctionMap): Deleted.
+        (JSC::JSGlobalObject::customSetterFunctionMap): Deleted.
+        Replace m_customGetterFunctionMap/m_customSetterFunctionMap with 
+        m_customGetterFunctionSet/m_customSetterFunctionSet. As the key is included
+        in the value, it saves space to use a set rather than a map. We now also
+        hash and compare both the function pointer and the property name to allow
+        sharing implementations.
+
+        * runtime/JSObject.cpp:
+        (JSC::WeakCustomGetterOrSetterHashTranslator::hash):
+        (JSC::WeakCustomGetterOrSetterHashTranslator::equal):
+        (JSC::createCustomGetterFunction):
+        (JSC::createCustomSetterFunction):
+        Update creation functions to use the new sets, making use of the
+        ensureValue function and a HashTranslator allowing the use of a
+        std::pair<PropertyName, FunctionPointer> as an alternative lookup
+        key. This allows us to avoid creating the JSCustomGetterFunction/JSCustomSetterFunction
+        pointer if one with the same property name and function pointer are
+        already in the set.
+
+        * runtime/WeakGCHashTable.h: Added.
+        (JSC::WeakGCHashTable::~WeakGCHashTable):
+        Moved from WeakGCMap and renamed as it is now the base of both
+        WeakGCMap and WeakGCSet.
+ 
+        * runtime/WeakGCMap.h:
+        Update to use new WeakGCHashTable base class.
+
+        * runtime/WeakGCMapInlines.h:
+        (JSC::KeyTraitsArg>::WeakGCMap):
+        (JSC::KeyTraitsArg>::~WeakGCMap):
+        Update for new Heap function names for WeakGCHashTable.
+
+        * runtime/WeakGCSet.h: Added.
+        * runtime/WeakGCSetInlines.h: Added.
+        (JSC::TraitsArg>::WeakGCSet):
+        (JSC::TraitsArg>::~WeakGCSet):
+        (JSC::TraitsArg>::find):
+        (JSC::TraitsArg>::find const):
+        (JSC::TraitsArg>::contains const):
+        (JSC::TraitsArg>::pruneStaleEntries):
+        Added a minimal WeakGCSet based on WeakGCMap. 
+
 2021-03-30  Mark Lam  <mark....@apple.com>
 
         Add disableForwardingVPrintfStdErrToOSLog() and use it in the jsc shell.

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (275260 => 275261)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2021-03-31 02:55:38 UTC (rev 275261)
@@ -1729,6 +1729,9 @@
 		BCD2034C0E17135E002C7E82 /* DatePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203480E17135E002C7E82 /* DatePrototype.h */; };
 		BCD203E80E1718F4002C7E82 /* DatePrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */; };
 		BCDE3AB80E6C82F5001453A7 /* Structure.h in Headers */ = {isa = PBXBuildFile; fileRef = BCDE3AB10E6C82CF001453A7 /* Structure.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		BCE2FAFB260916EF000A510F /* WeakGCSet.h in Headers */ = {isa = PBXBuildFile; fileRef = BCE2FAFA260916EF000A510F /* WeakGCSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		BCE2FAFD260916FF000A510F /* WeakGCSetInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = BCE2FAFC260916FF000A510F /* WeakGCSetInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		BCE2FAFF26091782000A510F /* WeakGCHashTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCE2FAFE26091782000A510F /* WeakGCHashTable.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BCF605140E203EF800B9A64D /* ArgList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF605120E203EF800B9A64D /* ArgList.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BDFCB2BBE90F41349E1B0BED /* JSSourceCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3032175DF1AD47D8998B34E1 /* JSSourceCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -4893,6 +4896,9 @@
 		BCDD51E90FB8DF74004A8BDC /* JITOpcodes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITOpcodes.cpp; sourceTree = "<group>"; };
 		BCDE3AB00E6C82CF001453A7 /* Structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Structure.cpp; sourceTree = "<group>"; };
 		BCDE3AB10E6C82CF001453A7 /* Structure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Structure.h; sourceTree = "<group>"; };
+		BCE2FAFA260916EF000A510F /* WeakGCSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeakGCSet.h; sourceTree = "<group>"; };
+		BCE2FAFC260916FF000A510F /* WeakGCSetInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeakGCSetInlines.h; sourceTree = "<group>"; };
+		BCE2FAFE26091782000A510F /* WeakGCHashTable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeakGCHashTable.h; sourceTree = "<group>"; };
 		BCF605110E203EF800B9A64D /* ArgList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArgList.cpp; sourceTree = "<group>"; };
 		BCF605120E203EF800B9A64D /* ArgList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgList.h; sourceTree = "<group>"; };
 		BCFD8C900EEB2EE700283848 /* JumpTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JumpTable.cpp; sourceTree = "<group>"; };
@@ -7895,8 +7901,11 @@
 				FE6F56DD1E64E92000D17801 /* VMTraps.h */,
 				FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */,
 				FED94F2C171E3E2300BE77A4 /* Watchdog.h */,
+				BCE2FAFE26091782000A510F /* WeakGCHashTable.h */,
 				14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
 				AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */,
+				BCE2FAFA260916EF000A510F /* WeakGCSet.h */,
+				BCE2FAFC260916FF000A510F /* WeakGCSetInlines.h */,
 				A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */,
 				A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */,
 				E3A32BC51FC8312D007D7E76 /* WeakMapImpl.cpp */,
@@ -9218,6 +9227,7 @@
 				8BC0648B1E1ABA9400B2B8CA /* AsyncGeneratorFunctionConstructor.h in Headers */,
 				8BC0648A1E1ABA7B00B2B8CA /* AsyncGeneratorFunctionPrototype.h in Headers */,
 				8BC064921E1ADCC400B2B8CA /* AsyncGeneratorPrototype.h in Headers */,
+				BCE2FAFF26091782000A510F /* WeakGCHashTable.h in Headers */,
 				8B3BF5E41E3D368B0076A87A /* AsyncGeneratorPrototype.lut.h in Headers */,
 				8BC064961E1D845C00B2B8CA /* AsyncIteratorPrototype.h in Headers */,
 				6A38CFAA1E32B5AB0060206F /* AsyncStackTrace.h in Headers */,
@@ -9682,6 +9692,7 @@
 				14386A751DD69895008652C4 /* DirectEvalExecutable.h in Headers */,
 				0F37308F1C0CD68500052BFA /* DisallowMacroScratchRegisterUsage.h in Headers */,
 				FE54DEFF1E8D76FA00A892C5 /* DisallowScope.h in Headers */,
+				BCE2FAFB260916EF000A510F /* WeakGCSet.h in Headers */,
 				FE54DEFB1E8C6D8800A892C5 /* DisallowVMEntry.h in Headers */,
 				0FF42731158EBD54004CB9FF /* Disassembler.h in Headers */,
 				E31618131EC5FE170006A218 /* DOMAnnotation.h in Headers */,
@@ -10339,6 +10350,7 @@
 				14F79F70216EAFD200046D39 /* Opcode.h in Headers */,
 				FE64872E2141D04800AB0D3E /* OpcodeInlines.h in Headers */,
 				14A4680D216FA56A000D2B1A /* OpcodeSize.h in Headers */,
+				BCE2FAFD260916FF000A510F /* WeakGCSetInlines.h in Headers */,
 				0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */,
 				A70447EA17A0BD4600F5898E /* OperandsInlines.h in Headers */,
 				BC18C4480E16F5CD00B34460 /* Operations.h in Headers */,

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (275260 => 275261)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2021-03-31 02:55:38 UTC (rev 275261)
@@ -1510,7 +1510,7 @@
         m_structureIDTable.flushOldTables();
 
         reapWeakHandles();
-        pruneStaleEntriesFromWeakGCMaps();
+        pruneStaleEntriesFromWeakGCHashTables();
         sweepArrayBuffers();
         snapshotUnswept();
         finalizeUnconditionalFinalizers(); // We rely on these unconditional finalizers running before clearCurrentlyExecuting since CodeBlock's finalizer relies on querying currently executing.
@@ -2217,12 +2217,12 @@
     m_objectSpace.reapWeakSets();
 }
 
-void Heap::pruneStaleEntriesFromWeakGCMaps()
+void Heap::pruneStaleEntriesFromWeakGCHashTables()
 {
     if (!m_collectionScope || m_collectionScope.value() != CollectionScope::Full)
         return;
-    for (WeakGCMapBase* weakGCMap : m_weakGCMaps)
-        weakGCMap->pruneStaleEntries();
+    for (auto* weakGCHashTable : m_weakGCHashTables)
+        weakGCHashTable->pruneStaleEntries();
 }
 
 void Heap::sweepArrayBuffers()
@@ -2674,14 +2674,14 @@
     collectIfNecessaryOrDefer();
 }
 
-void Heap::registerWeakGCMap(WeakGCMapBase* weakGCMap)
+void Heap::registerWeakGCHashTable(WeakGCHashTable* weakGCHashTable)
 {
-    m_weakGCMaps.add(weakGCMap);
+    m_weakGCHashTables.add(weakGCHashTable);
 }
 
-void Heap::unregisterWeakGCMap(WeakGCMapBase* weakGCMap)
+void Heap::unregisterWeakGCHashTable(WeakGCHashTable* weakGCHashTable)
 {
-    m_weakGCMaps.remove(weakGCMap);
+    m_weakGCHashTables.remove(weakGCHashTable);
 }
 
 void Heap::didAllocateBlock(size_t capacity)

Modified: trunk/Source/_javascript_Core/heap/Heap.h (275260 => 275261)


--- trunk/Source/_javascript_Core/heap/Heap.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -87,7 +87,7 @@
 class SweepingScope;
 class VM;
 class VerifierSlotVisitor;
-class WeakGCMapBase;
+class WeakGCHashTable;
 struct CurrentThreadState;
 
 #ifdef JSC_GLIB_API_ENABLED
@@ -289,8 +289,8 @@
     void releaseSoon(std::unique_ptr<JSCGLibWrapperObject>&&);
 #endif
 
-    JS_EXPORT_PRIVATE void registerWeakGCMap(WeakGCMapBase* weakGCMap);
-    JS_EXPORT_PRIVATE void unregisterWeakGCMap(WeakGCMapBase* weakGCMap);
+    JS_EXPORT_PRIVATE void registerWeakGCHashTable(WeakGCHashTable*);
+    JS_EXPORT_PRIVATE void unregisterWeakGCHashTable(WeakGCHashTable*);
 
     void addLogicallyEmptyWeakBlock(WeakBlock*);
 
@@ -526,7 +526,7 @@
     void endMarking();
 
     void reapWeakHandles();
-    void pruneStaleEntriesFromWeakGCMaps();
+    void pruneStaleEntriesFromWeakGCHashTables();
     void sweepArrayBuffers();
     void snapshotUnswept();
     void deleteSourceProviderCaches();
@@ -689,7 +689,7 @@
 #endif
     unsigned m_deferralDepth { 0 };
 
-    HashSet<WeakGCMapBase*> m_weakGCMaps;
+    HashSet<WeakGCHashTable*> m_weakGCHashTables;
     
     std::unique_ptr<MarkStackArray> m_sharedCollectorMarkStack;
     std::unique_ptr<MarkStackArray> m_sharedMutatorMarkStack;

Modified: trunk/Source/_javascript_Core/runtime/JSCInlines.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSCInlines.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSCInlines.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -54,3 +54,4 @@
 #include "StructureInlines.h"
 #include "ThrowScope.h"
 #include "WeakGCMapInlines.h"
+#include "WeakGCSetInlines.h"

Modified: trunk/Source/_javascript_Core/runtime/JSCustomGetterFunction.cpp (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSCustomGetterFunction.cpp	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSCustomGetterFunction.cpp	2021-03-31 02:55:38 UTC (rev 275261)
@@ -40,7 +40,7 @@
 
     JSCustomGetterFunction* customGetterFunction = jsCast<JSCustomGetterFunction*>(callFrame->jsCallee());
     JSValue thisValue = callFrame->thisValue();
-    GetValueFunc getter = customGetterFunction->getter();
+    auto getter = customGetterFunction->getter();
 
     if (auto domAttribute = customGetterFunction->domAttribute()) {
         if (!thisValue.inherits(vm, domAttribute->classInfo))
@@ -50,7 +50,7 @@
     RELEASE_AND_RETURN(scope, getter(globalObject, JSValue::encode(thisValue), customGetterFunction->propertyName()));
 }
 
-JSCustomGetterFunction::JSCustomGetterFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, const PropertyName& propertyName, GetValueFunc getter, Optional<DOMAttributeAnnotation> domAttribute)
+JSCustomGetterFunction::JSCustomGetterFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, const PropertyName& propertyName, CustomFunctionPointer getter, Optional<DOMAttributeAnnotation> domAttribute)
     : Base(vm, executable, globalObject, structure)
     , m_propertyName(Identifier::fromUid(vm, propertyName.uid()))
     , m_getter(getter)
@@ -58,7 +58,7 @@
 {
 }
 
-JSCustomGetterFunction* JSCustomGetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, GetValueFunc getter, Optional<DOMAttributeAnnotation> domAttribute)
+JSCustomGetterFunction* JSCustomGetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, CustomFunctionPointer getter, Optional<DOMAttributeAnnotation> domAttribute)
 {
     ASSERT(getter);
     NativeExecutable* executable = vm.getHostFunction(customGetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));

Modified: trunk/Source/_javascript_Core/runtime/JSCustomGetterFunction.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSCustomGetterFunction.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSCustomGetterFunction.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -34,6 +34,8 @@
     typedef JSFunction Base;
     static constexpr unsigned StructureFlags = Base::StructureFlags;
 
+    using CustomFunctionPointer = GetValueFunc;
+
     static constexpr bool needsDestruction = true;
     static void destroy(JSCell*);
 
@@ -49,19 +51,20 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
     }
 
-    JS_EXPORT_PRIVATE static JSCustomGetterFunction* create(VM&, JSGlobalObject*, const PropertyName&, GetValueFunc, Optional<DOMAttributeAnnotation> = WTF::nullopt);
+    JS_EXPORT_PRIVATE static JSCustomGetterFunction* create(VM&, JSGlobalObject*, const PropertyName&, CustomFunctionPointer, Optional<DOMAttributeAnnotation> = WTF::nullopt);
 
     DECLARE_EXPORT_INFO;
 
     const Identifier& propertyName() const { return m_propertyName; }
-    GetValueFunc getter() const { return m_getter; };
+    CustomFunctionPointer getter() const { return m_getter; };
+    CustomFunctionPointer customFunctionPointer() const { return m_getter; };
     Optional<DOMAttributeAnnotation> domAttribute() const { return m_domAttribute; };
 
 private:
-    JSCustomGetterFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*, const PropertyName&, GetValueFunc, Optional<DOMAttributeAnnotation>);
+    JSCustomGetterFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*, const PropertyName&, CustomFunctionPointer, Optional<DOMAttributeAnnotation>);
 
     Identifier m_propertyName;
-    GetValueFunc m_getter;
+    CustomFunctionPointer m_getter;
     Optional<DOMAttributeAnnotation> m_domAttribute;
 };
 

Modified: trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.cpp (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.cpp	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.cpp	2021-03-31 02:55:38 UTC (rev 275261)
@@ -36,12 +36,12 @@
 JSC_DEFINE_HOST_FUNCTION(customSetterFunctionCall, (JSGlobalObject* globalObject, CallFrame* callFrame))
 {
     auto customSetterFunction = jsCast<JSCustomSetterFunction*>(callFrame->jsCallee());
-    PutValueFunc setter = customSetterFunction->setter();
+    auto setter = customSetterFunction->setter();
     setter(globalObject, JSValue::encode(callFrame->thisValue()), JSValue::encode(callFrame->argument(0)), customSetterFunction->propertyName());
     return JSValue::encode(jsUndefined());
 }
 
-JSCustomSetterFunction::JSCustomSetterFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, const PropertyName& propertyName, PutValueFunc setter)
+JSCustomSetterFunction::JSCustomSetterFunction(VM& vm, NativeExecutable* executable, JSGlobalObject* globalObject, Structure* structure, const PropertyName& propertyName, CustomFunctionPointer setter)
     : Base(vm, executable, globalObject, structure)
     , m_propertyName(Identifier::fromUid(vm, propertyName.uid()))
     , m_setter(setter)
@@ -48,7 +48,7 @@
 {
 }
 
-JSCustomSetterFunction* JSCustomSetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, PutValueFunc setter)
+JSCustomSetterFunction* JSCustomSetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, CustomFunctionPointer setter)
 {
     ASSERT(setter);
     NativeExecutable* executable = vm.getHostFunction(customSetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));

Modified: trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -34,6 +34,8 @@
     typedef JSFunction Base;
     static constexpr unsigned StructureFlags = Base::StructureFlags;
 
+    using CustomFunctionPointer = PutValueFunc;
+
     static constexpr bool needsDestruction = true;
     static void destroy(JSCell*);
 
@@ -49,18 +51,19 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
     }
 
-    JS_EXPORT_PRIVATE static JSCustomSetterFunction* create(VM&, JSGlobalObject*, const PropertyName&, PutValueFunc);
+    JS_EXPORT_PRIVATE static JSCustomSetterFunction* create(VM&, JSGlobalObject*, const PropertyName&, CustomFunctionPointer);
 
     DECLARE_EXPORT_INFO;
 
     const Identifier& propertyName() const { return m_propertyName; }
-    PutValueFunc setter() const { return m_setter; };
+    CustomFunctionPointer setter() const { return m_setter; };
+    CustomFunctionPointer customFunctionPointer() const { return m_setter; };
 
 private:
-    JSCustomSetterFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*, const PropertyName&, PutValueFunc);
+    JSCustomSetterFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*, const PropertyName&, CustomFunctionPointer);
 
     Identifier m_propertyName;
-    PutValueFunc m_setter;
+    CustomFunctionPointer m_setter;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2021-03-31 02:55:38 UTC (rev 275261)
@@ -507,8 +507,8 @@
     , m_numberToStringWatchpointSet(IsWatched)
     , m_runtimeFlags()
     , m_stackTraceLimit(Options::defaultErrorStackTraceLimit())
-    , m_customGetterFunctionMap(vm)
-    , m_customSetterFunctionMap(vm)
+    , m_customGetterFunctionSet(vm)
+    , m_customSetterFunctionSet(vm)
     , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
 {
 }

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -35,8 +35,8 @@
 #include "JSPromise.h"
 #include "JSSegmentedVariableObject.h"
 #include "JSWeakObjectMapRefInternal.h"
+#include "LazyClassStructure.h"
 #include "LazyProperty.h"
-#include "LazyClassStructure.h"
 #include "NumberPrototype.h"
 #include "ParserModes.h"
 #include "RegExpGlobalData.h"
@@ -45,6 +45,7 @@
 #include "SymbolPrototype.h"
 #include "VM.h"
 #include "Watchpoint.h"
+#include "WeakGCSet.h"
 #include <_javascript_Core/JSBase.h>
 #include <array>
 #include <wtf/HashSet.h>
@@ -546,8 +547,6 @@
     bool isMapPrototypeSetFastAndNonObservable();
     bool isSetPrototypeAddFastAndNonObservable();
 
-    WeakGCMap<GetValueFunc, JSCustomGetterFunction>& customGetterFunctionMap() { return m_customGetterFunctionMap; }
-    WeakGCMap<PutValueFunc, JSCustomSetterFunction>& customSetterFunctionMap() { return m_customSetterFunctionMap; }
 
 #if ENABLE(DFG_JIT)
     using ReferencedGlobalPropertyWatchpointSets = HashMap<RefPtr<UniquedStringImpl>, Ref<WatchpointSet>, IdentifierRepHash>;
@@ -563,9 +562,22 @@
     RuntimeFlags m_runtimeFlags;
     ConsoleClient* m_consoleClient { nullptr };
     Optional<unsigned> m_stackTraceLimit;
-    WeakGCMap<GetValueFunc, JSCustomGetterFunction> m_customGetterFunctionMap;
-    WeakGCMap<PutValueFunc, JSCustomSetterFunction> m_customSetterFunctionMap;
 
+    template<typename T>
+    struct WeakCustomGetterOrSetterHash {
+        static unsigned hash(const Weak<T>&);
+        static bool equal(const Weak<T>&, const Weak<T>&);
+        static unsigned hash(const PropertyName&, typename T::CustomFunctionPointer);
+
+        static constexpr bool safeToCompareToEmptyOrDeleted = false;
+    };
+
+    WeakGCSet<JSCustomGetterFunction, WeakCustomGetterOrSetterHash<JSCustomGetterFunction>> m_customGetterFunctionSet;
+    WeakGCSet<JSCustomSetterFunction, WeakCustomGetterOrSetterHash<JSCustomSetterFunction>> m_customSetterFunctionSet;
+
+    WeakGCSet<JSCustomGetterFunction, WeakCustomGetterOrSetterHash<JSCustomGetterFunction>>& customGetterFunctionSet() { return m_customGetterFunctionSet; }
+    WeakGCSet<JSCustomSetterFunction, WeakCustomGetterOrSetterHash<JSCustomSetterFunction>>& customSetterFunctionSet() { return m_customSetterFunctionSet; }
+
 #if ASSERT_ENABLED
     const JSGlobalObject* m_globalObjectAtDebuggerEntry { nullptr };
 #endif

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectInlines.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectInlines.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectInlines.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -29,6 +29,8 @@
 
 #include "ArrayConstructor.h"
 #include "ArrayPrototype.h"
+#include "JSCustomGetterFunction.h"
+#include "JSCustomSetterFunction.h"
 #include "JSFunction.h"
 #include "LinkTimeConstant.h"
 #include "ObjectPrototype.h"
@@ -124,4 +126,29 @@
     return globalObject->vm();
 }
 
+template<typename T>
+inline unsigned JSGlobalObject::WeakCustomGetterOrSetterHash<T>::hash(const Weak<T>& value)
+{
+    if (!value)
+        return 0;
+    return hash(value->propertyName(), value->customFunctionPointer());
+}
+
+template<typename T>
+inline bool JSGlobalObject::WeakCustomGetterOrSetterHash<T>::equal(const Weak<T>& a, const Weak<T>& b)
+{
+    if (!a || !b)
+        return false;
+    return a == b;
+}
+
+template<typename T>
+inline unsigned JSGlobalObject::WeakCustomGetterOrSetterHash<T>::hash(const PropertyName& propertyName, typename T::CustomFunctionPointer functionPointer)
+{
+    unsigned hash = DefaultHash<typename T::CustomFunctionPointer>::hash(functionPointer);
+    if (!propertyName.isNull())
+        hash = WTF::pairIntHash(hash, propertyName.uid()->existingSymbolAwareHash());
+    return hash;
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2021-03-31 02:55:38 UTC (rev 275261)
@@ -3521,12 +3521,33 @@
     return Butterfly::createOrGrowPropertyStorage(butterfly(), vm, this, structure(vm), oldSize, newSize);
 }
 
+template<typename T>
+struct WeakCustomGetterOrSetterHashTranslator {
+    using BaseHash = JSGlobalObject::WeakCustomGetterOrSetterHash<T>;
+
+    using Key = std::pair<PropertyName, typename T::CustomFunctionPointer>;
+
+    static unsigned hash(const Key& key)
+    {
+        return BaseHash::hash(std::get<0>(key), std::get<1>(key));
+    }
+
+    static bool equal(const Weak<T>& a, const Key& b)
+    {
+        if (!a)
+            return false;
+        return a->propertyName() == std::get<0>(b) && a->customFunctionPointer() == std::get<1>(b);
+    }
+};
+
 static JSCustomGetterFunction* createCustomGetterFunction(JSGlobalObject* globalObject, VM& vm, PropertyName propertyName, GetValueFunc getValueFunc, Optional<DOMAttributeAnnotation> domAttribute)
 {
-    // WeakGCMap::ensureValue's functor must not invoke GC since GC can modify WeakGCMap in the middle of HashMap::ensure.
-    // We use DeferGC here (1) not to invoke GC when executing WeakGCMap::ensureValue and (2) to avoid looking up HashMap twice.
+    using Translator = WeakCustomGetterOrSetterHashTranslator<JSCustomGetterFunction>;
+
+    // WeakGCSet::ensureValue's functor must not invoke GC since GC can modify WeakGCSet in the middle of HashSet::ensure.
+    // We use DeferGC here (1) not to invoke GC when executing WeakGCSet::ensureValue and (2) to avoid looking up HashSet twice.
     DeferGC deferGC(vm.heap);
-    return globalObject->customGetterFunctionMap().ensureValue(getValueFunc, [&] {
+    return globalObject->customGetterFunctionSet().ensureValue<Translator>(std::make_pair(propertyName, getValueFunc), [&] {
         return JSCustomGetterFunction::create(vm, globalObject, propertyName, getValueFunc, domAttribute);
     });
 }
@@ -3533,10 +3554,12 @@
 
 static JSCustomSetterFunction* createCustomSetterFunction(JSGlobalObject* globalObject, VM& vm, PropertyName propertyName, PutValueFunc putValueFunc)
 {
-    // WeakGCMap::ensureValue's functor must not invoke GC since GC can modify WeakGCMap in the middle of HashMap::ensure.
-    // We use DeferGC here (1) not to invoke GC when executing WeakGCMap::ensureValue and (2) to avoid looking up HashMap twice.
+    using Translator = WeakCustomGetterOrSetterHashTranslator<JSCustomSetterFunction>;
+
+    // WeakGCSet::ensureValue's functor must not invoke GC since GC can modify WeakGCSet in the middle of HashSet::ensure.
+    // We use DeferGC here (1) not to invoke GC when executing WeakGCSet::ensureValue and (2) to avoid looking up HashSet twice.
     DeferGC deferGC(vm.heap);
-    return globalObject->customSetterFunctionMap().ensureValue(putValueFunc, [&] {
+    return globalObject->customSetterFunctionSet().ensureValue<Translator>(std::make_pair(propertyName, putValueFunc), [&] {
         return JSCustomSetterFunction::create(vm, globalObject, propertyName, putValueFunc);
     });
 }

Copied: trunk/Source/_javascript_Core/runtime/WeakGCHashTable.h (from rev 275260, trunk/Source/_javascript_Core/runtime/JSCustomSetterFunction.h) (0 => 275261)


--- trunk/Source/_javascript_Core/runtime/WeakGCHashTable.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/WeakGCHashTable.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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
+
+namespace JSC {
+
+class WeakGCHashTable {
+public:
+    virtual ~WeakGCHashTable() { }
+    virtual void pruneStaleEntries() = 0;
+};
+
+}

Modified: trunk/Source/_javascript_Core/runtime/WeakGCMap.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/WeakGCMap.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/WeakGCMap.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -27,6 +27,7 @@
 
 #include "DeferGC.h"
 #include "Weak.h"
+#include "WeakGCHashTable.h"
 #include <wtf/HashMap.h>
 
 namespace JSC {
@@ -33,15 +34,8 @@
 
 // A HashMap with Weak<JSCell> values, which automatically removes values once they're garbage collected.
 
-class WeakGCMapBase {
-public:
-    virtual ~WeakGCMapBase() { }
-    virtual void pruneStaleEntries() = 0;
-};
-
-template<typename KeyArg, typename ValueArg, typename HashArg = DefaultHash<KeyArg>,
-    typename KeyTraitsArg = HashTraits<KeyArg>>
-class WeakGCMap final : public WeakGCMapBase {
+template<typename KeyArg, typename ValueArg, typename HashArg = DefaultHash<KeyArg>, typename KeyTraitsArg = HashTraits<KeyArg>>
+class WeakGCMap final : public WeakGCHashTable {
     WTF_MAKE_FAST_ALLOCATED;
     typedef Weak<ValueArg> ValueType;
     typedef HashMap<KeyArg, ValueType, HashArg, KeyTraitsArg> HashMapType;

Modified: trunk/Source/_javascript_Core/runtime/WeakGCMapInlines.h (275260 => 275261)


--- trunk/Source/_javascript_Core/runtime/WeakGCMapInlines.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/_javascript_Core/runtime/WeakGCMapInlines.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -35,13 +35,13 @@
 inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::WeakGCMap(VM& vm)
     : m_vm(vm)
 {
-    vm.heap.registerWeakGCMap(this);
+    vm.heap.registerWeakGCHashTable(this);
 }
 
 template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg>
 inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::~WeakGCMap()
 {
-    m_vm.heap.unregisterWeakGCMap(this);
+    m_vm.heap.unregisterWeakGCHashTable(this);
 }
 
 template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg>

Added: trunk/Source/_javascript_Core/runtime/WeakGCSet.h (0 => 275261)


--- trunk/Source/_javascript_Core/runtime/WeakGCSet.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/WeakGCSet.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 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 "Weak.h"
+#include "WeakGCHashTable.h"
+#include <wtf/HashSet.h>
+
+namespace JSC {
+
+// A HashSet with Weak<JSCell> values, which automatically removes values once they're garbage collected.
+
+template<typename T>
+struct WeakGCSetHashTraits : HashTraits<Weak<T>> {
+    static constexpr bool hasIsReleasedWeakValueFunction = true;
+    static bool isReleasedWeakValue(const Weak<T>& value)
+    {
+        return !value.isHashTableDeletedValue() && !value.isHashTableEmptyValue() && !value;
+    }
+};
+
+template<typename ValueArg, typename HashArg = DefaultHash<Weak<ValueArg>>, typename TraitsArg = WeakGCSetHashTraits<ValueArg>>
+class WeakGCSet final : public WeakGCHashTable {
+    WTF_MAKE_FAST_ALLOCATED;
+    using ValueType = Weak<ValueArg>;
+    using HashSetType = HashSet<ValueType, HashArg, TraitsArg>;
+
+public:
+    using AddResult = typename HashSetType::AddResult;
+    using iterator = typename HashSetType::iterator;
+    using const_iterator = typename HashSetType::const_iterator;
+
+    explicit WeakGCSet(VM&);
+    ~WeakGCSet() final;
+
+    void clear()
+    {
+        m_set.clear();
+    }
+
+    template<typename HashTranslator, typename T, typename Functor>
+    ValueArg* ensureValue(T&& key, Functor&& functor)
+    {
+        // If functor invokes GC, GC can prune WeakGCSet, and manipulate HashSet while we are touching it in the ensure function.
+        // The functor must not invoke GC.
+        DisallowGC disallowGC;
+        
+        auto result = m_set.template ensure<HashTranslator>(std::forward<T>(key), std::forward<Functor>(functor));
+        return result.iterator->get();
+    }
+
+    inline iterator find(const ValueType& key);
+    inline const_iterator find(const ValueType& key) const;
+    inline bool contains(const ValueType&) const;
+
+private:
+    void pruneStaleEntries() final;
+
+    HashSetType m_set;
+    VM& m_vm;
+};
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/WeakGCSetInlines.h (0 => 275261)


--- trunk/Source/_javascript_Core/runtime/WeakGCSetInlines.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/WeakGCSetInlines.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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 "HeapInlines.h"
+#include "WeakGCSet.h"
+#include "WeakInlines.h"
+
+namespace JSC {
+
+template<typename ValueArg, typename HashArg, typename TraitsArg>
+inline WeakGCSet<ValueArg, HashArg, TraitsArg>::WeakGCSet(VM& vm)
+    : m_vm(vm)
+{
+    vm.heap.registerWeakGCHashTable(this);
+}
+
+template<typename ValueArg, typename HashArg, typename TraitsArg>
+inline WeakGCSet<ValueArg, HashArg, TraitsArg>::~WeakGCSet()
+{
+    m_vm.heap.unregisterWeakGCHashTable(this);
+}
+
+template<typename ValueArg, typename HashArg, typename TraitsArg>
+inline typename WeakGCSet<ValueArg, HashArg, TraitsArg>::iterator WeakGCSet<ValueArg, HashArg, TraitsArg>::find(const ValueType& value)
+{
+    iterator it = m_set.find(value);
+    iterator end = m_set.end();
+    if (it != end && !*it) // Found a zombie value.
+        return end;
+    return it;
+}
+
+template<typename ValueArg, typename HashArg, typename TraitsArg>
+inline typename WeakGCSet<ValueArg, HashArg, TraitsArg>::const_iterator WeakGCSet<ValueArg, HashArg, TraitsArg>::find(const ValueType& value) const
+{
+    return const_cast<WeakGCSet*>(this)->find(value);
+}
+
+template<typename ValueArg, typename HashArg, typename TraitsArg>
+inline bool WeakGCSet<ValueArg, HashArg, TraitsArg>::contains(const ValueType& value) const
+{
+    return find(value) != m_set.end();
+}
+
+template<typename ValueArg, typename HashArg, typename TraitsArg>
+NEVER_INLINE void WeakGCSet<ValueArg, HashArg, TraitsArg>::pruneStaleEntries()
+{
+    m_set.removeIf([](auto& entry) {
+        return !entry;
+    });
+}
+
+} // namespace JSC

Modified: trunk/Source/WTF/ChangeLog (275260 => 275261)


--- trunk/Source/WTF/ChangeLog	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/WTF/ChangeLog	2021-03-31 02:55:38 UTC (rev 275261)
@@ -1,3 +1,41 @@
+2021-03-30  Sam Weinig  <wei...@apple.com>
+
+        JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap should be sets, not maps, and should use both the identifier and function pointer as the key
+        https://bugs.webkit.org/show_bug.cgi?id=223613
+
+        Reviewed by Saam Barati.
+
+        Adds a heterogenous HashSet::ensure, which allows lazy construction of the value to
+        insert into the HashSet only if the heterogenous key (e.g. a key + HashTranslator
+        that are not the same as the HashSet's ValueType) does not match any item in the
+        set. For example given a set of ExpensiveToConstruct, but uniquely identifiable
+        by CheapToConstruct:
+        
+            HashSet<ExpensiveToConstruct> hashSet;
+            ...
+            struct Translator {
+                static unsigned hash(const CheapToConstruct& key)
+                {
+                    return key.hash();
+                }
+                static bool equal(const ExpensiveToConstruct& a, const CheapToConstruct& b)
+                {
+                    return a == b;
+                }
+            };
+            
+            hashSet.ensure<Translator>(CheapToConstruct { ... }, [] {
+                return ExpensiveToConstruct { ... };
+            });
+
+        This will be used by the custom getter/setter sets to avoid constructing the GC objects
+        unless they are really needed.
+
+        Also took the opertunity to replace some typedefs with usings, and fixed some comments.
+
+        * wtf/HashSet.h:
+        (WTF::Traits>::ensure):
+
 2021-03-30  Mark Lam  <mark....@apple.com>
 
         Add disableForwardingVPrintfStdErrToOSLog() and use it in the jsc shell.

Modified: trunk/Source/WTF/wtf/HashSet.h (275260 => 275261)


--- trunk/Source/WTF/wtf/HashSet.h	2021-03-31 02:52:37 UTC (rev 275260)
+++ trunk/Source/WTF/wtf/HashSet.h	2021-03-31 02:55:38 UTC (rev 275261)
@@ -33,36 +33,30 @@
 class HashSet final {
     WTF_MAKE_FAST_ALLOCATED;
 private:
-    typedef HashArg HashFunctions;
-    typedef TraitsArg ValueTraits;
-    typedef typename ValueTraits::TakeType TakeType;
+    using HashFunctions = HashArg;
+    using ValueTraits = TraitsArg;
+    using TakeType = typename ValueTraits::TakeType;
 
 public:
-    typedef typename ValueTraits::TraitType ValueType;
+    using ValueType = typename ValueTraits::TraitType;
 
 private:
-    typedef HashTable<ValueType, ValueType, IdentityExtractor,
-        HashFunctions, ValueTraits, ValueTraits> HashTableType;
+    using HashTableType = HashTable<ValueType, ValueType, IdentityExtractor, HashFunctions, ValueTraits, ValueTraits>;
 
 public:
-    /*
-     * Since figuring out the entries of an iterator is confusing, here is a cheat sheet:
-     * const KeyType& key = iterator->key;
-     */
-    typedef HashTableConstIteratorAdapter<HashTableType, ValueType> iterator;
-    typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
+    // HashSet iterators have the following structure:
+    //      const ValueType* get() const;
+    //      const ValueType& operator*() const;
+    //      const ValueType* operator->() const;
+    using iterator = HashTableConstIteratorAdapter<HashTableType, ValueType>;
+    using const_iterator = HashTableConstIteratorAdapter<HashTableType, ValueType>;
 
-    /*
-     * Since figuring out the entries of an AddResult is confusing, here is a cheat sheet:
-     * iterator iter = addResult.iterator;
-     * bool isNewEntry = addResult.isNewEntry;
-     */
-    typedef typename HashTableType::AddResult AddResult;
+    // HashSet AddResults have the following fields:
+    //      IteratorType iterator;
+    //      bool isNewEntry;
+    using AddResult = typename HashTableType::AddResult;
 
-    HashSet()
-    {
-    }
-
+    HashSet() = default;
     HashSet(std::initializer_list<ValueArg> initializerList)
     {
         for (const auto& value : initializerList)
@@ -93,6 +87,7 @@
     template<typename HashTranslator, typename T> iterator find(const T&) const;
     template<typename HashTranslator, typename T> bool contains(const T&) const;
 
+
     // The return value includes both an iterator to the added value's location,
     // and an isNewEntry bool that indicates if it is a new or existing entry in the set.
     AddResult add(const ValueType&);
@@ -110,6 +105,16 @@
     //   static translate(ValueType&, const T&, unsigned hashCode);
     template<typename HashTranslator, typename T> AddResult add(const T&);
     
+    // An alternate version of translated add(), ensure() will still do translation
+    // by hashing and comparing with some other type, to avoid the cost of type
+    // conversion if the object is already in the table, but rather than a static
+    // translate() function, uses the passed in functor to perform lazy creation of
+    // the value only if it is not already there. HashTranslator must have the following
+    // function members:
+    //   static unsigned hash(const T&);
+    //   static bool equal(const ValueType&, const T&);
+    template<typename HashTranslator, typename T, typename Functor> AddResult ensure(T&&, Functor&&);
+
     // Attempts to add a list of things to the set. Returns true if any of
     // them are new to the set. Returns false if the set is unchanged.
     template<typename IteratorType>
@@ -171,6 +176,16 @@
     }
 };
 
+template<typename ValueTraits, typename Translator>
+struct HashSetEnsureTranslatorAdaptor {
+    template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
+    template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
+    template<typename T, typename U, typename Functor> static void translate(T& location, U&&, Functor&& functor)
+    {
+        ValueTraits::assignToEmpty(location, functor());
+    }
+};
+
 template<typename T, typename U, typename V>
 inline void HashSet<T, U, V>::swap(HashSet& other)
 {
@@ -233,6 +248,13 @@
     return m_impl.template contains<HashSetTranslatorAdapter<HashTranslator>>(value);
 }
 
+template<typename Value, typename HashFunctions, typename Traits>
+template<typename HashTranslator, typename T, typename Functor>
+inline auto HashSet<Value, HashFunctions, Traits>::ensure(T&& key, Functor&& functor) -> AddResult
+{
+    return m_impl.template add<HashSetEnsureTranslatorAdaptor<Traits, HashTranslator>>(std::forward<T>(key), std::forward<Functor>(functor));
+}
+
 template<typename T, typename U, typename V>
 inline auto HashSet<T, U, V>::add(const ValueType& value) -> AddResult
 {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to