[DFG][FTL] WeakMap#set should have DFG node
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jan 2018 09:25:35 +0000 (09:25 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jan 2018 09:25:35 +0000 (09:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180015

Reviewed by Saam Barati.

JSTests:

* stress/weakmap-set-change-get.js: Added.
(shouldBe):
(test):
* stress/weakmap-set-cse.js: Added.
(shouldBe):
(test):
* stress/weakset-add-change-get.js: Added.
(shouldBe):
* stress/weakset-add-cse.js: Added.
(shouldBe):

Source/JavaScriptCore:

This patch adds WeakMapSet and WeakSetAdd DFG nodes to handle them efficiently in DFG and FTL.
We also define CSE rules for them. Now, WeakMapSet and WeakSetAdd can offer the results of
the subsequent WeakMapGet if CSE allows.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addVarArgChild):
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
WeakMap operations do not cause GC.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileWeakSetAdd):
(JSC::DFG::SpeculativeJIT::compileWeakMapSet):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileWeakSetAdd):
(JSC::FTL::DFG::LowerDFGToB3::compileWeakMapSet):
* jit/JITOperations.h:
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/WeakMapPrototype.cpp:
(JSC::WeakMapPrototype::finishCreation):
* runtime/WeakSetPrototype.cpp:
(JSC::WeakSetPrototype::finishCreation):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227723 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
JSTests/ChangeLog
JSTests/stress/weakmap-set-change-get.js [new file with mode: 0644]
JSTests/stress/weakmap-set-cse.js [new file with mode: 0644]
JSTests/stress/weakset-add-change-get.js [new file with mode: 0644]
JSTests/stress/weakset-add-cse.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/runtime/Intrinsic.cpp
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/WeakMapImpl.h
Source/JavaScriptCore/runtime/WeakMapPrototype.cpp
Source/JavaScriptCore/runtime/WeakSetPrototype.cpp

index 270a1828582330a6d592a6ae7cb8e93677813564..d77face1893a5847bd49835d6a406f20e15ade15 100644 (file)
@@ -1,3 +1,21 @@
+2018-01-29  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG][FTL] WeakMap#set should have DFG node
+        https://bugs.webkit.org/show_bug.cgi?id=180015
+
+        Reviewed by Saam Barati.
+
+        * stress/weakmap-set-change-get.js: Added.
+        (shouldBe):
+        (test):
+        * stress/weakmap-set-cse.js: Added.
+        (shouldBe):
+        (test):
+        * stress/weakset-add-change-get.js: Added.
+        (shouldBe):
+        * stress/weakset-add-cse.js: Added.
+        (shouldBe):
+
 2018-01-27  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         DFG strength reduction fails to convert NumberToStringWithValidRadixConstant for 0 to constant '0'
diff --git a/JSTests/stress/weakmap-set-change-get.js b/JSTests/stress/weakmap-set-change-get.js
new file mode 100644 (file)
index 0000000..b511e58
--- /dev/null
@@ -0,0 +1,27 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test()
+{
+    var key1 = {};
+    var map = new WeakMap();
+    var res1 = map.get(key1);
+    map.set(key1, 20);
+    var res2 = map.get(key1);
+    map.set(key1, 400);
+    var res3 = map.get(key1);
+    map.delete(key1);
+    var res4 = map.get(key1);
+    return [res1, res2, res3, res4];
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var [res1, res2, res3, res4] = test();
+    shouldBe(res1, undefined);
+    shouldBe(res2, 20);
+    shouldBe(res3, 400);
+    shouldBe(res4, undefined);
+}
diff --git a/JSTests/stress/weakmap-set-cse.js b/JSTests/stress/weakmap-set-cse.js
new file mode 100644 (file)
index 0000000..f5f0493
--- /dev/null
@@ -0,0 +1,22 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test()
+{
+    var key1 = {};
+    var map = new WeakMap();
+    var r1 = map.get(key1);
+    map.set(key1, 42);
+    var r2 = map.get(key1);
+    return [r1, r2];
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    let [r1, r2] = test();
+    shouldBe(r1, undefined);
+    shouldBe(r2, 42);
+}
diff --git a/JSTests/stress/weakset-add-change-get.js b/JSTests/stress/weakset-add-change-get.js
new file mode 100644 (file)
index 0000000..78fabef
--- /dev/null
@@ -0,0 +1,24 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test()
+{
+    var key1 = {};
+    var set = new WeakSet();
+    var res1 = set.has(key1);
+    set.add(key1);
+    var res2 = set.has(key1);
+    set.delete(key1);
+    var res3 = set.has(key1);
+    return [res1, res2, res3];
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    var [res1, res2, res3] = test();
+    shouldBe(res1, false);
+    shouldBe(res2, true);
+    shouldBe(res3, false);
+}
diff --git a/JSTests/stress/weakset-add-cse.js b/JSTests/stress/weakset-add-cse.js
new file mode 100644 (file)
index 0000000..d0c4cea
--- /dev/null
@@ -0,0 +1,22 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test()
+{
+    var key1 = {};
+    var set = new WeakSet();
+    var r1 = set.has(key1);
+    set.add(key1);
+    var r2 = set.has(key1);
+    return [r1, r2];
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i) {
+    let [r1, r2] = test();
+    shouldBe(r1, false);
+    shouldBe(r2, true);
+}
index 3a258f6cb64e1aabf689afb1d14112651e8cc80a..fcbb9e5468b74d2c6afb7992d86161f72a00f192 100644 (file)
@@ -1,3 +1,57 @@
+2018-01-29  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG][FTL] WeakMap#set should have DFG node
+        https://bugs.webkit.org/show_bug.cgi?id=180015
+
+        Reviewed by Saam Barati.
+
+        This patch adds WeakMapSet and WeakSetAdd DFG nodes to handle them efficiently in DFG and FTL.
+        We also define CSE rules for them. Now, WeakMapSet and WeakSetAdd can offer the results of
+        the subsequent WeakMapGet if CSE allows.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addVarArgChild):
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        WeakMap operations do not cause GC.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileWeakSetAdd):
+        (JSC::DFG::SpeculativeJIT::compileWeakMapSet):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileWeakSetAdd):
+        (JSC::FTL::DFG::LowerDFGToB3::compileWeakMapSet):
+        * jit/JITOperations.h:
+        * runtime/Intrinsic.cpp:
+        (JSC::intrinsicName):
+        * runtime/Intrinsic.h:
+        * runtime/WeakMapPrototype.cpp:
+        (JSC::WeakMapPrototype::finishCreation):
+        * runtime/WeakSetPrototype.cpp:
+        (JSC::WeakSetPrototype::finishCreation):
+
 2018-01-28  Filip Pizlo  <fpizlo@apple.com>
 
         LargeAllocation should do the same distancing as MarkedBlock
index 4effcb00062082b53d58a2f036cfcc5efac320da..837bec4bc6aecf850f2a689653a1629e53b36cfa 100644 (file)
@@ -1164,6 +1164,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
         break;
 
+    case WeakSetAdd:
+    case WeakMapSet:
+        break;
+
     case WeakMapGet:
         forNode(node).makeBytecodeTop();
         break;
index 31f89822a765059748eed85f4e630df28b9c0388..fd66009ff33d6fa7cff0c1464b429b4e78bdfed3 100644 (file)
@@ -759,6 +759,12 @@ private:
         m_graph.m_varArgChildren.append(Edge(child));
         m_numPassedVarArgs++;
     }
+
+    void addVarArgChild(Edge child)
+    {
+        m_graph.m_varArgChildren.append(child);
+        m_numPassedVarArgs++;
+    }
     
     Node* addCallWithoutSettingResult(
         NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset,
@@ -3002,6 +3008,47 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin
         return true;
     }
 
+    case JSWeakSetAddIntrinsic: {
+        if (argumentCountIncludingThis != 2)
+            return false;
+
+        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
+            return false;
+
+        insertChecks();
+        Node* base = get(virtualRegisterForArgument(0, registerOffset));
+        Node* key = get(virtualRegisterForArgument(1, registerOffset));
+        addToGraph(Check, Edge(key, ObjectUse));
+        Node* hash = addToGraph(MapHash, key);
+        addToGraph(WeakSetAdd, Edge(base, WeakSetObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use));
+        set(VirtualRegister(resultOperand), base);
+        return true;
+    }
+
+    case JSWeakMapSetIntrinsic: {
+        if (argumentCountIncludingThis != 3)
+            return false;
+
+        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
+            return false;
+
+        insertChecks();
+        Node* base = get(virtualRegisterForArgument(0, registerOffset));
+        Node* key = get(virtualRegisterForArgument(1, registerOffset));
+        Node* value = get(virtualRegisterForArgument(2, registerOffset));
+
+        addToGraph(Check, Edge(key, ObjectUse));
+        Node* hash = addToGraph(MapHash, key);
+
+        addVarArgChild(Edge(base, WeakMapObjectUse));
+        addVarArgChild(Edge(key, ObjectUse));
+        addVarArgChild(Edge(value));
+        addVarArgChild(Edge(hash, Int32Use));
+        addToGraph(Node::VarArg, WeakMapSet, OpInfo(0), OpInfo(0));
+        set(VirtualRegister(resultOperand), base);
+        return true;
+    }
+
     case HasOwnPropertyIntrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;
index 307db632d193fcd8d039a10b0fb16c3a0957b9d2..409968254463f05ddff087009f19000517b67042 100644 (file)
@@ -1672,6 +1672,23 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         return;
     }
 
+    case WeakSetAdd: {
+        Edge& mapEdge = node->child1();
+        Edge& keyEdge = node->child2();
+        write(JSWeakSetFields);
+        def(HeapLocation(WeakMapGetLoc, JSWeakSetFields, mapEdge, keyEdge), LazyNode(keyEdge.node()));
+        return;
+    }
+
+    case WeakMapSet: {
+        Edge& mapEdge = graph.varArgChild(node, 0);
+        Edge& keyEdge = graph.varArgChild(node, 1);
+        Edge& valueEdge = graph.varArgChild(node, 2);
+        write(JSWeakMapFields);
+        def(HeapLocation(WeakMapGetLoc, JSWeakMapFields, mapEdge, keyEdge), LazyNode(valueEdge.node()));
+        return;
+    }
+
     case ExtractValueFromWeakMapGet:
         def(PureValue(node));
         return;
index a4508c347be904f098034c3f2c53cda11941f881..209baf450438013bc12ef2915434fc575ce0b11d 100644 (file)
@@ -214,6 +214,8 @@ bool doesGC(Graph& graph, Node* node)
     case LoadValueFromMapBucket:
     case ExtractValueFromWeakMapGet:
     case WeakMapGet:
+    case WeakSetAdd:
+    case WeakMapSet:
     case Unreachable:
     case ExtractCatchLocal:
     case ExtractOSREntryLocal:
index 733492bc75fcfcce30bfc199c738f612b2f56e05..ad1ac4a2c88df7955d84c4ccafa8503d0cc2ae4f 100644 (file)
@@ -1979,6 +1979,20 @@ private:
             break;
         }
 
+        case WeakSetAdd: {
+            fixEdge<WeakSetObjectUse>(node->child1());
+            fixEdge<ObjectUse>(node->child2());
+            fixEdge<Int32Use>(node->child3());
+            break;
+        }
+
+        case WeakMapSet: {
+            fixEdge<WeakMapObjectUse>(m_graph.varArgChild(node, 0));
+            fixEdge<ObjectUse>(m_graph.varArgChild(node, 1));
+            fixEdge<Int32Use>(m_graph.varArgChild(node, 3));
+            break;
+        }
+
         case DefineDataProperty: {
             fixEdge<CellUse>(m_graph.varArgChild(node, 0));
             Edge& propertyEdge = m_graph.varArgChild(node, 1);
index c33bb32057f7f17773bb301197b3a10484226ae5..335a493cd9c5eaad81246e6f8d7349276628feb8 100644 (file)
@@ -450,6 +450,8 @@ namespace JSC { namespace DFG {
     macro(MapSet, NodeMustGenerate | NodeHasVarArgs | NodeResultJS) \
     /* Nodes for JSWeakMap and JSWeakSet */ \
     macro(WeakMapGet, NodeResultJS) \
+    macro(WeakSetAdd, NodeMustGenerate) \
+    macro(WeakMapSet, NodeMustGenerate | NodeHasVarArgs) \
     macro(ExtractValueFromWeakMapGet, NodeResultJS) \
     \
     macro(StringSlice, NodeResultJS) \
index 21daef048cdc2ecc63b913269dfba903df46d9eb..4acf14df096a30913c1e1ee198331ea4d93660a8 100644 (file)
@@ -57,6 +57,8 @@
 #include "JSMap.h"
 #include "JSPropertyNameEnumerator.h"
 #include "JSSet.h"
+#include "JSWeakMap.h"
+#include "JSWeakSet.h"
 #include "ObjectConstructor.h"
 #include "Operations.h"
 #include "ParseInt.h"
@@ -2695,6 +2697,20 @@ JSCell* JIT_OPERATION operationMapSet(ExecState* exec, JSCell* map, EncodedJSVal
     return bucket;
 }
 
+void JIT_OPERATION operationWeakSetAdd(ExecState* exec, JSCell* set, JSCell* key, int32_t hash)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    jsCast<JSWeakSet*>(set)->add(vm, asObject(key), JSValue(), hash);
+}
+
+void JIT_OPERATION operationWeakMapSet(ExecState* exec, JSCell* map, JSCell* key, EncodedJSValue value, int32_t hash)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    jsCast<JSWeakMap*>(map)->add(vm, asObject(key), JSValue::decode(value), hash);
+}
+
 EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState* exec, JSObject* thisObject)
 {
     VM& vm = exec->vm();
index eeb6564f8a1d48e7718d9ba43be3385143dd6fea..adc2e458cd39e76760a78e6b814a594c928b2b4b 100644 (file)
@@ -170,6 +170,8 @@ JSCell* JIT_OPERATION operationCreateRest(ExecState*, Register* argumentStart, u
 JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, JSCell*, size_t) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationSetAdd(ExecState*, JSCell*, EncodedJSValue, int32_t) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationMapSet(ExecState*, JSCell*, EncodedJSValue, EncodedJSValue, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationWeakSetAdd(ExecState*, JSCell*, JSCell*, int32_t) WTF_INTERNAL;
+void JIT_OPERATION operationWeakMapSet(ExecState*, JSCell*, JSCell*, EncodedJSValue, int32_t) WTF_INTERNAL;
 double JIT_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
 size_t JIT_OPERATION operationObjectIsObject(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
 size_t JIT_OPERATION operationObjectIsFunction(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
index 93909630bc641ac50f228d030906577a1fcb182e..de4428b72d851837c3c049057cd7f1056208bd89 100644 (file)
@@ -1190,6 +1190,8 @@ private:
         case PutDynamicVar:
         case NukeStructureAndSetButterfly:
         case InitializeEntrypointArguments:
+        case WeakSetAdd:
+        case WeakMapSet:
             break;
             
         // This gets ignored because it only pretends to produce a value.
index b666fbc6f1a2d5638c9dffbe4fcdb4f7670afbe3..7a10fbe2e3fcebfebca2910303c02005c166b986 100644 (file)
@@ -431,6 +431,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case LoadValueFromMapBucket:
     case ExtractValueFromWeakMapGet:
     case WeakMapGet:
+    case WeakSetAdd:
+    case WeakMapSet:
     case AtomicsAdd:
     case AtomicsAnd:
     case AtomicsCompareExchange:
index 62f3da146eae60f286ae095c8c8f2308d4310b83..e7736d48c72079b42e85298c41d9875f3706af00 100644 (file)
@@ -11709,6 +11709,46 @@ void SpeculativeJIT::compileWeakMapGet(Node* node)
     jsValueResult(resultRegs, node);
 }
 
+void SpeculativeJIT::compileWeakSetAdd(Node* node)
+{
+    SpeculateCellOperand set(this, node->child1());
+    SpeculateCellOperand key(this, node->child2());
+    SpeculateInt32Operand hash(this, node->child3());
+
+    GPRReg setGPR = set.gpr();
+    GPRReg keyGPR = key.gpr();
+    GPRReg hashGPR = hash.gpr();
+
+    speculateWeakSetObject(node->child1(), setGPR);
+    speculateObject(node->child2(), keyGPR);
+
+    flushRegisters();
+    callOperation(operationWeakSetAdd, setGPR, keyGPR, hashGPR);
+    m_jit.exceptionCheck();
+    noResult(node);
+}
+
+void SpeculativeJIT::compileWeakMapSet(Node* node)
+{
+    SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
+    SpeculateCellOperand key(this, m_jit.graph().varArgChild(node, 1));
+    JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
+    SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
+
+    GPRReg mapGPR = map.gpr();
+    GPRReg keyGPR = key.gpr();
+    JSValueRegs valueRegs = value.jsValueRegs();
+    GPRReg hashGPR = hash.gpr();
+
+    speculateWeakMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
+    speculateObject(m_jit.graph().varArgChild(node, 1), keyGPR);
+
+    flushRegisters();
+    callOperation(operationWeakMapSet, mapGPR, keyGPR, valueRegs, hashGPR);
+    m_jit.exceptionCheck();
+    noResult(node);
+}
+
 void SpeculativeJIT::compileGetPrototypeOf(Node* node)
 {
     switch (node->child1().useKind()) {
index b45c89aa6b00e2df8496af0be5ddbf7bb79cfa5c..f2b46cb8ada29398ad7df2c48b7de30327393b80 100644 (file)
@@ -1262,6 +1262,11 @@ public:
         m_jit.setupArgumentsWithExecState(TrustedImmPtr::weakPointer(m_jit.graph(), arg1), arg2);
         return appendCall(operation);
     }
+    JITCompiler::Call callOperation(V_JITOperation_ECCZ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCall(operation);
+    }
 
     JITCompiler::Call callOperationWithCallFrameRollbackOnException(V_JITOperation_ECb operation, void* pointer)
     {
@@ -2006,6 +2011,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3.payloadGPR());
         return appendCall(operation);
     }
+    JITCompiler::Call callOperation(V_JITOperation_ECCJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3.payloadGPR(), arg4);
+        return appendCall(operation);
+    }
 
     JITCompiler::Call callOperation(Z_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1)
     {
@@ -2591,6 +2601,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3.payloadGPR(), arg3.tagGPR());
         return appendCall(operation);
     }
+    JITCompiler::Call callOperation(V_JITOperation_ECCJZ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3.payloadGPR(), arg3.tagGPR(), arg4);
+        return appendCall(operation);
+    }
 
     JITCompiler::Call callOperation(V_JITOperation_EPZJ operation, GPRReg arg1, GPRReg arg2, JSValueRegs arg3)
     {
@@ -2964,6 +2979,8 @@ public:
     void compileSetAdd(Node*);
     void compileMapSet(Node*);
     void compileWeakMapGet(Node*);
+    void compileWeakSetAdd(Node*);
+    void compileWeakMapSet(Node*);
     void compileLoadKeyFromMapBucket(Node*);
     void compileLoadValueFromMapBucket(Node*);
     void compileExtractValueFromWeakMapGet(Node*);
index dc0bcfc92f904c2389107a38d354388263539ffa..cdb015386d4ca0d9d99960cadb83dc40d8babc67 100644 (file)
@@ -4529,6 +4529,14 @@ void SpeculativeJIT::compile(Node* node)
         compileWeakMapGet(node);
         break;
 
+    case WeakSetAdd:
+        compileWeakSetAdd(node);
+        break;
+
+    case WeakMapSet:
+        compileWeakMapSet(node);
+        break;
+
     case Flush:
         break;
 
index 5e6555209da5a7adf980c9443963156bf4367ba1..d8b3cd6dbefa5ba1a1ebe3f7d50b5c50e5354ace 100644 (file)
@@ -4918,6 +4918,14 @@ void SpeculativeJIT::compile(Node* node)
         compileWeakMapGet(node);
         break;
 
+    case WeakSetAdd:
+        compileWeakSetAdd(node);
+        break;
+
+    case WeakMapSet:
+        compileWeakMapSet(node);
+        break;
+
     case StringSlice: {
         compileStringSlice(node);
         break;
index 0d35da6e9899d876afdbb13df7f3ebc331dfec3b..1aaa20df1aa40c9c59739b6637ac8aeac687cd20 100644 (file)
@@ -213,6 +213,8 @@ inline CapabilityLevel canCompile(Node* node)
     case SetAdd:
     case MapSet:
     case WeakMapGet:
+    case WeakSetAdd:
+    case WeakMapSet:
     case IsEmpty:
     case IsUndefined:
     case IsBoolean:
index 2460a4ddc97733178206a89efc8eba49f10f346d..1f3684044367a81a245ac77f1a0f9545e96677fb 100644 (file)
@@ -1094,6 +1094,12 @@ private:
         case WeakMapGet:
             compileWeakMapGet();
             break;
+        case WeakSetAdd:
+            compileWeakSetAdd();
+            break;
+        case WeakMapSet:
+            compileWeakMapSet();
+            break;
         case IsObject:
             compileIsObject();
             break;
@@ -9119,6 +9125,25 @@ private:
         setJSValue(result);
     }
 
+    void compileWeakSetAdd()
+    {
+        LValue set = lowWeakSetObject(m_node->child1());
+        LValue key = lowObject(m_node->child2());
+        LValue hash = lowInt32(m_node->child3());
+
+        vmCall(Void, m_out.operation(operationWeakSetAdd), m_callFrame, set, key, hash);
+    }
+
+    void compileWeakMapSet()
+    {
+        LValue map = lowWeakMapObject(m_graph.varArgChild(m_node, 0));
+        LValue key = lowObject(m_graph.varArgChild(m_node, 1));
+        LValue value = lowJSValue(m_graph.varArgChild(m_node, 2));
+        LValue hash = lowInt32(m_graph.varArgChild(m_node, 3));
+
+        vmCall(Void, m_out.operation(operationWeakMapSet), m_callFrame, map, key, value, hash);
+    }
+
     void compileIsObjectOrNull()
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
index a8c50bcd68b0156e866f9e53b44dafe21cbd3db8..4e85454816bed62b7ca0acb655d662c4258d2102 100644 (file)
@@ -280,6 +280,8 @@ typedef void (JIT_OPERATION *V_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
 typedef void (JIT_OPERATION *V_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef void (JIT_OPERATION *V_JITOperation_ECliJsf)(ExecState*, CallLinkInfo*, JSFunction*);
 typedef void (JIT_OPERATION *V_JITOperation_ECCJ)(ExecState*, JSCell*, JSCell*, EncodedJSValue);
+typedef void (JIT_OPERATION *V_JITOperation_ECCZ)(ExecState*, JSCell*, JSCell*, int32_t);
+typedef void (JIT_OPERATION *V_JITOperation_ECCJZ)(ExecState*, JSCell*, JSCell*, EncodedJSValue, int32_t);
 typedef void (JIT_OPERATION *V_JITOperation_EZSymtabJ)(ExecState*, int32_t, SymbolTable*, EncodedJSValue);
 typedef void (JIT_OPERATION *V_JITOperation_EJ)(ExecState*, EncodedJSValue);
 typedef void (JIT_OPERATION *V_JITOperation_EJCI)(ExecState*, EncodedJSValue, JSCell*, UniquedStringImpl*);
index 644151b0d5e692c2fbb96a9ba508206219d101a9..1e09ab10856685d617bd6966f30dc67220b29152 100644 (file)
@@ -169,8 +169,12 @@ const char* intrinsicName(Intrinsic intrinsic)
         return "JSWeakMapGetIntrinsic";
     case JSWeakMapHasIntrinsic:
         return "JSWeakMapHasIntrinsic";
+    case JSWeakMapSetIntrinsic:
+        return "JSWeakMapSetIntrinsic";
     case JSWeakSetHasIntrinsic:
         return "JSWeakSetHasIntrinsic";
+    case JSWeakSetAddIntrinsic:
+        return "JSWeakSetAddIntrinsic";
     case HasOwnPropertyIntrinsic:
         return "HasOwnPropertyIntrinsic";
     case AtomicsAddIntrinsic:
index bff96c0bcb4a5c369bacbc1157c8f7102bac2fae..788acec82866348ea38cf4c9348037e981b407d9 100644 (file)
@@ -97,7 +97,9 @@ enum Intrinsic {
     JSSetBucketKeyIntrinsic,
     JSWeakMapGetIntrinsic,
     JSWeakMapHasIntrinsic,
+    JSWeakMapSetIntrinsic,
     JSWeakSetHasIntrinsic,
+    JSWeakSetAddIntrinsic,
     HasOwnPropertyIntrinsic,
     AtomicsAddIntrinsic,
     AtomicsAndIntrinsic,
index 50c053cbe138272f272279d3fc78557eb7bb23be..1bf6350b08cdd106c7a8b6aee19658e53e879663 100644 (file)
@@ -221,6 +221,9 @@ public:
         makeAndSetNewBuffer();
     }
 
+    // WeakMap operations must not cause GC. We model operations in DFG based on this guarantee.
+    // This guarantee is ensured by DisallowGC.
+
     template <typename T = WeakMapBucketType>
     ALWAYS_INLINE typename std::enable_if<std::is_same<T, WeakMapBucket<WeakMapBucketDataKeyValue>>::value, JSValue>::type get(JSObject* key)
     {
index 9caeb59122404f7a90442323f2aec2fc0df7c4cb..f607636daffe346798727e695cd53f3b5d5195be 100644 (file)
@@ -47,7 +47,7 @@ void WeakMapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, protoFuncWeakMapDelete, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, protoFuncWeakMapGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSWeakMapGetIntrinsic);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, protoFuncWeakMapHas, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSWeakMapHasIntrinsic);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, protoFuncWeakMapSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, protoFuncWeakMapSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSWeakMapSetIntrinsic);
 
     putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakMap"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
 }
index 563e86c9afb2d4959b5cc014dc3cb72de45f3820..6486d2138e2f57a20e187b460e29243496204976 100644 (file)
@@ -45,7 +45,7 @@ void WeakSetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, protoFuncWeakSetDelete, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, protoFuncWeakSetHas, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSWeakSetHasIntrinsic);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->add, protoFuncWeakSetAdd, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->add, protoFuncWeakSetAdd, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSWeakSetAddIntrinsic);
 
     putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakSet"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
 }