Title: [247004] releases/WebKitGTK/webkit-2.24
Revision
247004
Author
carlo...@webkit.org
Date
2019-07-01 04:04:33 -0700 (Mon, 01 Jul 2019)

Log Message

Merge r246740 - ArraySlice needs to keep the source array alive.
https://bugs.webkit.org/show_bug.cgi?id=197374
<rdar://problem/50304429>

Reviewed by Michael Saboff and Filip Pizlo.

JSTests:

* stress/array-slice-must-keep-source-array-alive.js: Added.

Source/_javascript_Core:

The implementation of the FTL ArraySlice intrinsics may GC while allocating the
result array and its butterfly.  Previously, ArraySlice already keeps the source
butterfly alive in order to copy from it to the new butterfly after the allocation.
Unfortunately, this is not enough.  We also need to keep the source array alive
so that GC will scan the values in the butterfly as well.  Note: the butterfly
does not have a visitChildren() method to do this scan.  It's the parent object's
responsibility to do the scanning.

This patch fixes this by introducing a keepAlive() utility method, and we use it
to keep the source array alive while allocating the result array and butterfly.

keepAlive() works by using a patchpoint to communicate to B3 that a value (the
source array in this case) is still in use.  It also uses a fence to keep B3 from
relocating the patchpoint, which may defeat the fix.

For the DFG's SpeculativeJIT::compileArraySlice(), we may have lucked out and the
source array cell is kept alive.  This patch makes it explicit that we should
keep its cell alive till after the result array has been allocated.

For the Baseline JIT and LLInt, we use the arrayProtoFuncSlice() runtime function
and there is no issue because the source array (in "thisObj") is in the element
copying loop that follows the allocation of the result array.  However, for
documentation purposes, this patch adds a call to HeapCell::use() to indicate that
the source array need to kept alive at least until after the allocation of the
result array.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArraySlice):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
(JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
(JSC::FTL::DFG::LowerDFGToB3::keepAlive):
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncSlice):

Modified Paths

Added Paths

Diff

Modified: releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog (247003 => 247004)


--- releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog	2019-07-01 11:04:28 UTC (rev 247003)
+++ releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog	2019-07-01 11:04:33 UTC (rev 247004)
@@ -1,3 +1,13 @@
+2019-06-21  Mark Lam  <mark....@apple.com>
+
+        ArraySlice needs to keep the source array alive.
+        https://bugs.webkit.org/show_bug.cgi?id=197374
+        <rdar://problem/50304429>
+
+        Reviewed by Michael Saboff and Filip Pizlo.
+
+        * stress/array-slice-must-keep-source-array-alive.js: Added.
+
 2019-06-22  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] ClassExpr should not store result in the middle of evaluation

Added: releases/WebKitGTK/webkit-2.24/JSTests/stress/array-slice-must-keep-source-array-alive.js (0 => 247004)


--- releases/WebKitGTK/webkit-2.24/JSTests/stress/array-slice-must-keep-source-array-alive.js	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.24/JSTests/stress/array-slice-must-keep-source-array-alive.js	2019-07-01 11:04:33 UTC (rev 247004)
@@ -0,0 +1,19 @@
+//@ runDefault("--useConcurrentGC=false", "--useConcurrentJIT=false", "--thresholdForFTLOptimizeAfterWarmUp=1000")
+
+var functions = [];
+
+function boo() {
+    functions.push(new Function("a", "return a"));
+    return functions.splice(0);
+}
+
+function test() {
+    functions = boo().slice();
+}
+
+noDFG(boo);
+noInline(boo);
+noInline(test);
+
+for (var i = 0; i < 10000; i++)
+    test();

Modified: releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/ChangeLog (247003 => 247004)


--- releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/ChangeLog	2019-07-01 11:04:28 UTC (rev 247003)
+++ releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/ChangeLog	2019-07-01 11:04:33 UTC (rev 247004)
@@ -1,3 +1,46 @@
+2019-06-24  Mark Lam  <mark....@apple.com>
+
+        ArraySlice needs to keep the source array alive.
+        https://bugs.webkit.org/show_bug.cgi?id=197374
+        <rdar://problem/50304429>
+
+        Reviewed by Michael Saboff and Filip Pizlo.
+
+        The implementation of the FTL ArraySlice intrinsics may GC while allocating the
+        result array and its butterfly.  Previously, ArraySlice already keeps the source
+        butterfly alive in order to copy from it to the new butterfly after the allocation.
+        Unfortunately, this is not enough.  We also need to keep the source array alive
+        so that GC will scan the values in the butterfly as well.  Note: the butterfly
+        does not have a visitChildren() method to do this scan.  It's the parent object's
+        responsibility to do the scanning.
+
+        This patch fixes this by introducing a keepAlive() utility method, and we use it
+        to keep the source array alive while allocating the result array and butterfly.
+
+        keepAlive() works by using a patchpoint to communicate to B3 that a value (the
+        source array in this case) is still in use.  It also uses a fence to keep B3 from
+        relocating the patchpoint, which may defeat the fix.
+
+        For the DFG's SpeculativeJIT::compileArraySlice(), we may have lucked out and the
+        source array cell is kept alive.  This patch makes it explicit that we should
+        keep its cell alive till after the result array has been allocated.
+
+        For the Baseline JIT and LLInt, we use the arrayProtoFuncSlice() runtime function
+        and there is no issue because the source array (in "thisObj") is in the element
+        copying loop that follows the allocation of the result array.  However, for
+        documentation purposes, this patch adds a call to HeapCell::use() to indicate that
+        the source array need to kept alive at least until after the allocation of the
+        result array.
+
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArraySlice):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
+        (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
+        (JSC::FTL::DFG::LowerDFGToB3::keepAlive):
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncSlice):
+
 2019-06-22  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] ClassExpr should not store result in the middle of evaluation

Modified: releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (247003 => 247004)


--- releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2019-07-01 11:04:28 UTC (rev 247003)
+++ releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2019-07-01 11:04:33 UTC (rev 247004)
@@ -8186,17 +8186,18 @@
         }
     }
 
-
     GPRTemporary temp3(this);
     GPRReg tempValue = temp3.gpr();
+
     {
+        // We need to keep the source array alive at least until after we're done
+        // with anything that can GC (e.g. allocating the result array below).
         SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0));
+
         m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue);
         // We can ignore the writability of the cell since we won't write to the source.
         m_jit.and32(TrustedImm32(AllWritableArrayTypesAndHistory), tempValue);
-    }
 
-    {
         JSValueRegsTemporary emptyValue(this);
         JSValueRegs emptyValueRegs = emptyValue.regs();
 

Modified: releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (247003 => 247004)


--- releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2019-07-01 11:04:28 UTC (rev 247003)
+++ releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2019-07-01 11:04:33 UTC (rev 247004)
@@ -4909,6 +4909,7 @@
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
 
+        LValue sourceArray = lowCell(m_graph.varArgChild(m_node, 0));
         LValue sourceStorage = lowStorage(m_graph.varArgChild(m_node, m_node->numChildren() - 1));
         LValue inputLength = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
 
@@ -4934,7 +4935,7 @@
 
         ArrayValues arrayResult;
         {
-            LValue indexingType = m_out.load8ZeroExt32(lowCell(m_graph.varArgChild(m_node, 0)), m_heaps.JSCell_indexingTypeAndMisc);
+            LValue indexingType = m_out.load8ZeroExt32(sourceArray, m_heaps.JSCell_indexingTypeAndMisc);
             // We can ignore the writability of the cell since we won't write to the source.
             indexingType = m_out.bitAnd(indexingType, m_out.constInt32(AllWritableArrayTypesAndHistory));
             // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
@@ -4949,6 +4950,9 @@
             arrayResult = allocateJSArray(resultLength, resultLength, structure, indexingType, false, false);
         }
 
+        // Keep the sourceArray alive at least until after anything that can GC.
+        keepAlive(sourceArray);
+
         LBasicBlock loop = m_out.newBlock();
         LBasicBlock continuation = m_out.newBlock();
 
@@ -13466,7 +13470,7 @@
         }
         
         ValueFromBlock noButterfly = m_out.anchor(m_out.intPtrZero);
-        
+
         LValue predicate;
         if (shouldLargeArraySizeCreateArrayStorage)
             predicate = m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
@@ -13476,16 +13480,16 @@
         m_out.branch(predicate, rarely(largeCase), usually(fastCase));
         
         m_out.appendTo(fastCase, largeCase);
-            
+
         LValue payloadSize =
             m_out.shl(m_out.zeroExt(vectorLength, pointerType()), m_out.constIntPtr(3));
-            
+
         LValue butterflySize = m_out.add(
             payloadSize, m_out.constIntPtr(sizeof(IndexingHeader)));
-            
+
         LValue allocator = allocatorForSize(vm().jsValueGigacageAuxiliarySpace, butterflySize, failCase);
         LValue startOfStorage = allocateHeapCell(allocator, failCase);
-            
+
         LValue butterfly = m_out.add(startOfStorage, m_out.constIntPtr(sizeof(IndexingHeader)));
         
         m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
@@ -16996,7 +17000,16 @@
             return false;
         return true;
     }
-    
+
+    void keepAlive(LValue value)
+    {
+        PatchpointValue* patchpoint = m_out.patchpoint(Void);
+        patchpoint->effects = Effects::none();
+        patchpoint->effects.writesLocalState = true;
+        patchpoint->append(value, ValueRep::ColdAny);
+        patchpoint->setGenerator([=] (CCallHelpers&, const StackmapGenerationParams&) { });
+    }
+
     void addWeakReference(JSCell* target)
     {
         m_graph.m_plan.weakReferences().addLazily(target);

Modified: releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/runtime/ArrayPrototype.cpp (247003 => 247004)


--- releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2019-07-01 11:04:28 UTC (rev 247003)
+++ releases/WebKitGTK/webkit-2.24/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2019-07-01 11:04:33 UTC (rev 247004)
@@ -1004,6 +1004,10 @@
         RETURN_IF_EXCEPTION(scope, { });
     }
 
+    // Document that we need to keep the source array alive until after anything
+    // that can GC (e.g. allocating the result array).
+    thisObj->use();
+
     unsigned n = 0;
     for (unsigned k = begin; k < end; k++, n++) {
         JSValue v = getProperty(exec, thisObj, k);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to