Title: [258887] trunk
Revision
258887
Author
[email protected]
Date
2020-03-23 16:28:46 -0700 (Mon, 23 Mar 2020)

Log Message

[JSC] Caller of Delete IC should emit write-barrier onto owner
https://bugs.webkit.org/show_bug.cgi?id=209392
<rdar://problem/60683173>

Reviewed by Saam Barati.

JSTests:

* stress/delete-ic-requires-write-barrier.js: Added.
(foo):

Source/_javascript_Core:

DeleteIC can change Structure of the owner cell in the fast path. However it is not emitting write-barrier,
while we are writing a Structure cell id into a JSObject's header.
In this patch,

    1. Emit write-barrier in baseline. Be careful about when emitting write-barrier since it clobbers registers.
    2. DFG and FTL recognize DeleteById / DeleteByVal in DFGStoreBarrierInsertionPhase.
    3. DFGStoreBarrierInsertionPhase only accepts nodes which base is speculated as a Cell. Current DeleteById / DeleteByVal
       can have UntypedUse base value, but we miss emitting write-barrier DeleteById / DeleteByVal with UntypedUse in the fast path.
       In this patch, we optimize DeleteById / DeleteByVal only when we speculate child1 as a cell. We can take the further
       steps after fixing this bug, e.g. (1) accepting UntypedUse in store-barrier-insertion[1] or (2) emitting write-barrier
       if child1's speculation is UntypedUse. For now, we fix the bug by taking a generic path when child1 is not speculated
       as a cell. And we can optimize it in a separate change[2].

This is following the design of PutIC.
Currently, we use ShouldFilterBase for emitWriteBarrier. But we could use UnconditionalWriteBarrier here since
we already filter non-cells in Baseline's hot path. I filed it as a separate bug in [3].

[1]: https://bugs.webkit.org/show_bug.cgi?id=209396
[2]: https://bugs.webkit.org/show_bug.cgi?id=209397
[3]: https://bugs.webkit.org/show_bug.cgi?id=209395

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileDeleteById):
(JSC::DFG::SpeculativeJIT::compileDeleteByVal):
* dfg/DFGStoreBarrierInsertionPhase.cpp:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileDeleteById):
(JSC::FTL::DFG::LowerDFGToB3::compileDeleteByVal):
* jit/JIT.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitPutByValWithCachedId):
(JSC::JIT::emit_op_del_by_id):
(JSC::JIT::emit_op_del_by_val):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::emitWriteBarrier):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitPutByValWithCachedId):
(JSC::JIT::emit_op_put_by_id):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (258886 => 258887)


--- trunk/JSTests/ChangeLog	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/JSTests/ChangeLog	2020-03-23 23:28:46 UTC (rev 258887)
@@ -1,5 +1,16 @@
 2020-03-23  Yusuke Suzuki  <[email protected]>
 
+        [JSC] Caller of Delete IC should emit write-barrier onto owner
+        https://bugs.webkit.org/show_bug.cgi?id=209392
+        <rdar://problem/60683173>
+
+        Reviewed by Saam Barati.
+
+        * stress/delete-ic-requires-write-barrier.js: Added.
+        (foo):
+
+2020-03-23  Yusuke Suzuki  <[email protected]>
+
         [JSC] DFG OSR exit cannot find StructureStubInfo for put_by_val if CodeBlock is once converved from Baseline to LLInt
         https://bugs.webkit.org/show_bug.cgi?id=209327
         <rdar://problem/60631061>

Added: trunk/JSTests/stress/delete-ic-requires-write-barrier.js (0 => 258887)


--- trunk/JSTests/stress/delete-ic-requires-write-barrier.js	                        (rev 0)
+++ trunk/JSTests/stress/delete-ic-requires-write-barrier.js	2020-03-23 23:28:46 UTC (rev 258887)
@@ -0,0 +1,19 @@
+//@ runDefault("--collectContinuously=1", "--forceMiniVMMode=1", "--verifyHeap=1", "--forceEagerCompilation=1", "--useConcurrentJIT=0")
+function foo() {
+  const a0 = [1,2,3];
+  let zero = 0;
+  for (let i=0; i<100000; i++) {
+    const zero2 = zero;
+    const a1 = [1];
+    const a2 = [a1];
+    const o = {
+      x: a0,
+      y: Object
+    };
+    a2.z = a2;
+    delete o.x;
+    zero.q
+  }
+}
+
+foo();

Modified: trunk/Source/_javascript_Core/ChangeLog (258886 => 258887)


--- trunk/Source/_javascript_Core/ChangeLog	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-03-23 23:28:46 UTC (rev 258887)
@@ -1,5 +1,54 @@
 2020-03-23  Yusuke Suzuki  <[email protected]>
 
+        [JSC] Caller of Delete IC should emit write-barrier onto owner
+        https://bugs.webkit.org/show_bug.cgi?id=209392
+        <rdar://problem/60683173>
+
+        Reviewed by Saam Barati.
+
+        DeleteIC can change Structure of the owner cell in the fast path. However it is not emitting write-barrier,
+        while we are writing a Structure cell id into a JSObject's header.
+        In this patch,
+
+            1. Emit write-barrier in baseline. Be careful about when emitting write-barrier since it clobbers registers.
+            2. DFG and FTL recognize DeleteById / DeleteByVal in DFGStoreBarrierInsertionPhase.
+            3. DFGStoreBarrierInsertionPhase only accepts nodes which base is speculated as a Cell. Current DeleteById / DeleteByVal
+               can have UntypedUse base value, but we miss emitting write-barrier DeleteById / DeleteByVal with UntypedUse in the fast path.
+               In this patch, we optimize DeleteById / DeleteByVal only when we speculate child1 as a cell. We can take the further
+               steps after fixing this bug, e.g. (1) accepting UntypedUse in store-barrier-insertion[1] or (2) emitting write-barrier
+               if child1's speculation is UntypedUse. For now, we fix the bug by taking a generic path when child1 is not speculated
+               as a cell. And we can optimize it in a separate change[2].
+
+        This is following the design of PutIC.
+        Currently, we use ShouldFilterBase for emitWriteBarrier. But we could use UnconditionalWriteBarrier here since
+        we already filter non-cells in Baseline's hot path. I filed it as a separate bug in [3].
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=209396
+        [2]: https://bugs.webkit.org/show_bug.cgi?id=209397
+        [3]: https://bugs.webkit.org/show_bug.cgi?id=209395
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDeleteById):
+        (JSC::DFG::SpeculativeJIT::compileDeleteByVal):
+        * dfg/DFGStoreBarrierInsertionPhase.cpp:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileDeleteById):
+        (JSC::FTL::DFG::LowerDFGToB3::compileDeleteByVal):
+        * jit/JIT.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitPutByValWithCachedId):
+        (JSC::JIT::emit_op_del_by_id):
+        (JSC::JIT::emit_op_del_by_val):
+        (JSC::JIT::emit_op_put_by_id):
+        (JSC::JIT::emitWriteBarrier):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emitPutByValWithCachedId):
+        (JSC::JIT::emit_op_put_by_id):
+
+2020-03-23  Yusuke Suzuki  <[email protected]>
+
         [JSC] DFG OSR exit cannot find StructureStubInfo for put_by_val if CodeBlock is once converved from Baseline to LLInt
         https://bugs.webkit.org/show_bug.cgi?id=209327
         <rdar://problem/60631061>

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (258886 => 258887)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2020-03-23 23:28:46 UTC (rev 258887)
@@ -1620,10 +1620,13 @@
 
         case DeleteByVal: {
 #if USE(JSVALUE64)
-            if (node->child2()->shouldSpeculateCell())
-                fixEdge<CellUse>(node->child2());
+            if (node->child1()->shouldSpeculateCell()) {
+                fixEdge<CellUse>(node->child1());
+                if (node->child2()->shouldSpeculateCell())
+                    fixEdge<CellUse>(node->child2());
+            }
 #endif
-            FALLTHROUGH;
+            break;
         }
 
         case DeleteById: {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (258886 => 258887)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2020-03-23 23:28:46 UTC (rev 258887)
@@ -5441,83 +5441,112 @@
 
 void SpeculativeJIT::compileDeleteById(Node* node)
 {
-    speculate(node, node->child1());
+    if (node->child1().useKind() == CellUse) {
+        SpeculateCellOperand base(this, node->child1());
+        GPRTemporary result(this);
+        GPRTemporary scratch(this);
 
-    GPRTemporary result(this);
-    GPRTemporary scratch(this);
-    JSValueOperand base(this, node->child1(), ManualOperandSpeculation);
+        auto* property = identifierUID(node->identifierNumber());
+        JITCompiler::JumpList slowCases;
 
-    auto* property = identifierUID(node->identifierNumber());
-    JITCompiler::JumpList slowCases;
+        GPRReg baseGPR = base.gpr();
+        GPRReg scratchGPR = scratch.gpr();
+        GPRReg resultGPR = result.gpr();
 
-    JSValueRegs baseRegs = base.jsValueRegs();
-    GPRReg scratchGPR = scratch.gpr();
-    GPRReg resultGPR = result.gpr();
+        CodeOrigin codeOrigin = node->origin.semantic;
+        CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
+        RegisterSet usedRegisters = this->usedRegisters();
 
-    if (needsTypeCheck(node->child1(), SpecCell))
-        slowCases.append(m_jit.branchIfNotCell(baseRegs));
+        JITDelByIdGenerator gen(
+            m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
+            JSValueRegs(baseGPR), resultGPR, scratchGPR);
 
-    CodeOrigin codeOrigin = node->origin.semantic;
-    CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
-    RegisterSet usedRegisters = this->usedRegisters();
+        gen.generateFastPath(m_jit);
+        slowCases.append(gen.slowPathJump());
 
-    JITDelByIdGenerator gen(
-        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
-        baseRegs, resultGPR, scratchGPR);
+        std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
+            slowCases, this, operationDeleteByIdOptimize,
+            resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), JSValueRegs(baseGPR), property);
 
-    gen.generateFastPath(m_jit);
-    slowCases.append(gen.slowPathJump());
+        m_jit.addDelById(gen, slowPath.get());
+        addSlowPathGenerator(WTFMove(slowPath));
 
-    std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
-        slowCases, this, operationDeleteByIdOptimize,
-        resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), baseRegs, property);
+        unblessedBooleanResult(resultGPR, node);
+        return;
+    }
 
-    m_jit.addDelById(gen, slowPath.get());
-    addSlowPathGenerator(WTFMove(slowPath));
+    // FIXME: We should use IC even if child1 is UntypedUse. In that case, we should emit write-barrier after the fast path of IC.
+    // https://bugs.webkit.org/show_bug.cgi?id=209397
+    ASSERT(node->child1().useKind() == UntypedUse);
+    JSValueOperand base(this, node->child1());
 
+    JSValueRegs baseRegs = base.jsValueRegs();
+
+    flushRegisters();
+    GPRFlushedCallResult result(this);
+    GPRReg resultGPR = result.gpr();
+    callOperation(operationDeleteByIdGeneric, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), nullptr, baseRegs, identifierUID(node->identifierNumber()));
+    m_jit.exceptionCheck();
+
     unblessedBooleanResult(resultGPR, node);
 }
 
 void SpeculativeJIT::compileDeleteByVal(Node* node)
 {
-    speculate(node, node->child1());
-    speculate(node, node->child2());
+    if (node->child1().useKind() == CellUse) {
+        speculate(node, node->child2());
 
-    GPRTemporary result(this);
-    GPRTemporary scratch(this);
-    JSValueOperand base(this, node->child1(), ManualOperandSpeculation);
-    JSValueOperand key(this, node->child2(), ManualOperandSpeculation);
+        SpeculateCellOperand base(this, node->child1());
+        JSValueOperand key(this, node->child2(), ManualOperandSpeculation);
+        GPRTemporary result(this);
+        GPRTemporary scratch(this);
 
-    JITCompiler::JumpList slowCases;
+        JITCompiler::JumpList slowCases;
 
-    JSValueRegs baseRegs = base.jsValueRegs();
-    JSValueRegs keyRegs = key.jsValueRegs();
-    GPRReg scratchGPR = scratch.gpr();
-    GPRReg resultGPR = result.gpr();
+        GPRReg baseGPR = base.gpr();
+        JSValueRegs keyRegs = key.jsValueRegs();
+        GPRReg scratchGPR = scratch.gpr();
+        GPRReg resultGPR = result.gpr();
 
-    if (needsTypeCheck(node->child1(), SpecCell))
-        slowCases.append(m_jit.branchIfNotCell(baseRegs));
-    if (needsTypeCheck(node->child2(), SpecCell))
-        slowCases.append(m_jit.branchIfNotCell(keyRegs));
+        if (needsTypeCheck(node->child2(), SpecCell))
+            slowCases.append(m_jit.branchIfNotCell(keyRegs));
 
-    CodeOrigin codeOrigin = node->origin.semantic;
-    CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
-    RegisterSet usedRegisters = this->usedRegisters();
+        CodeOrigin codeOrigin = node->origin.semantic;
+        CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
+        RegisterSet usedRegisters = this->usedRegisters();
 
-    JITDelByValGenerator gen(
-        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
-        baseRegs, keyRegs, resultGPR, scratchGPR);
+        JITDelByValGenerator gen(
+            m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
+            JSValueRegs(baseGPR), keyRegs, resultGPR, scratchGPR);
 
-    gen.generateFastPath(m_jit);
-    slowCases.append(gen.slowPathJump());
+        gen.generateFastPath(m_jit);
+        slowCases.append(gen.slowPathJump());
 
-    std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
-        slowCases, this, operationDeleteByValOptimize,
-        resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), baseRegs, keyRegs);
+        std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
+            slowCases, this, operationDeleteByValOptimize,
+            resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), JSValueRegs(baseGPR), keyRegs);
 
-    m_jit.addDelByVal(gen, slowPath.get());
-    addSlowPathGenerator(WTFMove(slowPath));
+        m_jit.addDelByVal(gen, slowPath.get());
+        addSlowPathGenerator(WTFMove(slowPath));
 
+        unblessedBooleanResult(resultGPR, node);
+        return;
+    }
+
+    // FIXME: We should use IC even if child1 is UntypedUse. In that case, we should emit write-barrier after the fast path of IC.
+    // https://bugs.webkit.org/show_bug.cgi?id=209397
+    JSValueOperand base(this, node->child1());
+    JSValueOperand key(this, node->child2());
+
+    JSValueRegs baseRegs = base.jsValueRegs();
+    JSValueRegs keyRegs = key.jsValueRegs();
+
+    flushRegisters();
+    GPRFlushedCallResult result(this);
+    GPRReg resultGPR = result.gpr();
+    callOperation(operationDeleteByValGeneric, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), nullptr, baseRegs, keyRegs);
+    m_jit.exceptionCheck();
+
     unblessedBooleanResult(resultGPR, node);
 }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGStoreBarrierInsertionPhase.cpp (258886 => 258887)


--- trunk/Source/_javascript_Core/dfg/DFGStoreBarrierInsertionPhase.cpp	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/dfg/DFGStoreBarrierInsertionPhase.cpp	2020-03-23 23:28:46 UTC (rev 258887)
@@ -274,6 +274,16 @@
                 break;
             }
 
+            case DeleteById:
+            case DeleteByVal: {
+                // If child1 is not a cell-speculated, we call a generic implementation which emits write-barrier in C++ side.
+                // FIXME: We should consider accept base:UntypedUse.
+                // https://bugs.webkit.org/show_bug.cgi?id=209396
+                if (isCell(m_node->child1().useKind()))
+                    considerBarrier(m_node->child1());
+                break;
+            }
+
             case RecordRegExpCachedResult: {
                 considerBarrier(m_graph.varArgChild(m_node, 0));
                 break;
@@ -473,6 +483,7 @@
         
         // FIXME: We could support StoreBarrier(UntypedUse:). That would be sort of cool.
         // But right now we don't need it.
+        // https://bugs.webkit.org/show_bug.cgi?id=209396
 
         DFG_ASSERT(m_graph, m_node, isCell(base.useKind()), m_node->op(), base.useKind());
         

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (258886 => 258887)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2020-03-23 23:28:46 UTC (rev 258887)
@@ -5257,16 +5257,20 @@
 
     void compileDeleteById()
     {
-        LValue base;
-
         switch (m_node->child1().useKind()) {
         case CellUse: {
-            base = lowCell(m_node->child1());
+            LValue base = lowCell(m_node->child1());
+            compileDelBy<DelByKind::Normal>(base, m_graph.identifiers()[m_node->identifierNumber()]);
             break;
         }
 
         case UntypedUse: {
-            base = lowJSValue(m_node->child1());
+            // FIXME: We should use IC even if child1 is UntypedUse. In that case, we should emit write-barrier after tha fast path of IC.
+            // https://bugs.webkit.org/show_bug.cgi?id=209397
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+            LValue base = lowJSValue(m_node->child1());
+            auto uid = m_graph.identifiers()[m_node->identifierNumber()];
+            setBoolean(m_out.notZero64(vmCall(Int64, operationDeleteByIdGeneric, weakPointer(globalObject), m_out.intPtrZero, base, m_out.constIntPtr(uid))));
             break;
         }
 
@@ -5274,39 +5278,41 @@
             DFG_CRASH(m_graph, m_node, "Bad use kind");
             return;
         }
-        compileDelBy<DelByKind::Normal>(base, m_graph.identifiers()[m_node->identifierNumber()]);
     }
 
     void compileDeleteByVal()
     {
-        LValue base;
-        LValue subscript;
-
         switch (m_node->child1().useKind()) {
         case CellUse: {
-            base = lowCell(m_node->child1());
-            break;
-        }
+            LValue base = lowCell(m_node->child1());
+            LValue subscript;
+            switch (m_node->child2().useKind()) {
+            case CellUse: {
+                subscript = lowCell(m_node->child2());
+                break;
+            }
 
-        case UntypedUse: {
-            base = lowJSValue(m_node->child1());
-            break;
-        }
+            case UntypedUse: {
+                subscript = lowJSValue(m_node->child2());
+                break;
+            }
 
-        default:
-            DFG_CRASH(m_graph, m_node, "Bad use kind");
+            default:
+                DFG_CRASH(m_graph, m_node, "Bad use kind");
+                return;
+            }
+            compileDelBy<DelByKind::NormalByVal>(base, subscript);
             return;
         }
 
-        switch (m_node->child2().useKind()) {
-        case CellUse: {
-            subscript = lowCell(m_node->child2());
-            break;
-        }
-
         case UntypedUse: {
-            subscript = lowJSValue(m_node->child2());
-            break;
+            // FIXME: We should use IC even if child1 is UntypedUse. In that case, we should emit write-barrier after tha fast path of IC.
+            // https://bugs.webkit.org/show_bug.cgi?id=209397
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+            LValue base = lowJSValue(m_node->child1());
+            LValue subscript = lowJSValue(m_node->child2());
+            setBoolean(m_out.notZero64(vmCall(Int64, operationDeleteByValGeneric, weakPointer(globalObject), m_out.intPtrZero, base, subscript)));
+            return;
         }
 
         default:
@@ -5313,7 +5319,6 @@
             DFG_CRASH(m_graph, m_node, "Bad use kind");
             return;
         }
-        compileDelBy<DelByKind::NormalByVal>(base, subscript);
     }
     
     void compileArrayPush()

Modified: trunk/Source/_javascript_Core/jit/JIT.h (258886 => 258887)


--- trunk/Source/_javascript_Core/jit/JIT.h	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2020-03-23 23:28:46 UTC (rev 258887)
@@ -341,6 +341,7 @@
         enum WriteBarrierMode { UnconditionalWriteBarrier, ShouldFilterBase, ShouldFilterValue, ShouldFilterBaseAndValue };
         // value register in write barrier is used before any scratch registers
         // so may safely be the same as either of the scratch registers.
+        void emitWriteBarrier(VirtualRegister owner, WriteBarrierMode);
         void emitWriteBarrier(VirtualRegister owner, VirtualRegister value, WriteBarrierMode);
         void emitWriteBarrier(JSCell* owner, VirtualRegister value, WriteBarrierMode);
         void emitWriteBarrier(JSCell* owner);

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (258886 => 258887)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2020-03-23 23:28:46 UTC (rev 258887)
@@ -289,7 +289,10 @@
         m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
         JSValueRegs(regT0), JSValueRegs(regT1), regT2, m_codeBlock->ecmaMode(), putKind);
     gen.generateFastPath(*this);
-    emitWriteBarrier(base, value, ShouldFilterBase);
+    // IC can write new Structure without write-barrier if a base is cell.
+    // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.
+    // https://bugs.webkit.org/show_bug.cgi?id=209395
+    emitWriteBarrier(base, ShouldFilterBase);
     doneCases.append(jump());
 
     Label coldPathBegin = label();
@@ -400,6 +403,12 @@
 
     boxBoolean(regT0, JSValueRegs(regT0));
     emitPutVirtualRegister(dst, JSValueRegs(regT0));
+
+    // IC can write new Structure without write-barrier if a base is cell.
+    // We should emit write-barrier at the end of sequence since write-barrier clobbers registers.
+    // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.
+    // https://bugs.webkit.org/show_bug.cgi?id=209395
+    emitWriteBarrier(base, ShouldFilterBase);
 }
 
 void JIT::emitSlow_op_del_by_id(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -443,6 +452,12 @@
 
     boxBoolean(regT0, JSValueRegs(regT0));
     emitPutVirtualRegister(dst, JSValueRegs(regT0));
+
+    // We should emit write-barrier at the end of sequence since write-barrier clobbers registers.
+    // IC can write new Structure without write-barrier if a base is cell.
+    // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.
+    // https://bugs.webkit.org/show_bug.cgi?id=209395
+    emitWriteBarrier(base, ShouldFilterBase);
 }
 
 void JIT::emitSlow_op_del_by_val(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -654,10 +669,12 @@
     
     gen.generateFastPath(*this);
     addSlowCase(gen.slowPathJump());
+    m_putByIds.append(gen);
     
-    emitWriteBarrier(baseVReg, valueVReg, ShouldFilterBase);
-
-    m_putByIds.append(gen);
+    // IC can write new Structure without write-barrier if a base is cell.
+    // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.
+    // https://bugs.webkit.org/show_bug.cgi?id=209395
+    emitWriteBarrier(baseVReg, ShouldFilterBase);
 }
 
 void JIT::emitSlow_op_put_by_id(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -1176,6 +1193,7 @@
 
 void JIT::emitWriteBarrier(VirtualRegister owner, VirtualRegister value, WriteBarrierMode mode)
 {
+    // value may be invalid VirtualRegister if mode is UnconditionalWriteBarrier or ShouldFilterBase.
     Jump valueNotCell;
     if (mode == ShouldFilterValue || mode == ShouldFilterBaseAndValue) {
         emitGetVirtualRegister(value, regT0);
@@ -1242,6 +1260,7 @@
 
 void JIT::emitWriteBarrier(VirtualRegister owner, VirtualRegister value, WriteBarrierMode mode)
 {
+    // value may be invalid VirtualRegister if mode is UnconditionalWriteBarrier or ShouldFilterBase.
     Jump valueNotCell;
     if (mode == ShouldFilterValue || mode == ShouldFilterBaseAndValue) {
         emitLoadTag(value, regT0);
@@ -1279,6 +1298,12 @@
 
 #endif // USE(JSVALUE64)
 
+void JIT::emitWriteBarrier(VirtualRegister owner, WriteBarrierMode mode)
+{
+    ASSERT(mode == UnconditionalWriteBarrier || mode == ShouldFilterBase);
+    emitWriteBarrier(owner, VirtualRegister(), mode);
+}
+
 void JIT::emitWriteBarrier(JSCell* owner)
 {
     Jump ownerIsRememberedOrInEden = barrierBranch(vm(), owner, regT0);

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (258886 => 258887)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2020-03-23 23:21:34 UTC (rev 258886)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2020-03-23 23:28:46 UTC (rev 258887)
@@ -366,7 +366,12 @@
 
     // Write barrier breaks the registers. So after issuing the write barrier,
     // reload the registers.
-    emitWriteBarrier(base, value, ShouldFilterBase);
+    //
+    // IC can write new Structure without write-barrier if a base is cell.
+    // We are emitting write-barrier before writing here but this is OK since 32bit JSC does not have concurrent GC.
+    // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.
+    // https://bugs.webkit.org/show_bug.cgi?id=209395
+    emitWriteBarrier(base, ShouldFilterBase);
     emitLoadPayload(base, regT0);
     emitLoad(value, regT3, regT2);
 
@@ -610,10 +615,12 @@
     
     gen.generateFastPath(*this);
     addSlowCase(gen.slowPathJump());
+    m_putByIds.append(gen);
     
-    emitWriteBarrier(base, value, ShouldFilterBase);
-
-    m_putByIds.append(gen);
+    // IC can write new Structure without write-barrier if a base is cell.
+    // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.
+    // https://bugs.webkit.org/show_bug.cgi?id=209395
+    emitWriteBarrier(base, ShouldFilterBase);
 }
 
 void JIT::emitSlow_op_put_by_id(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to