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)