The liveness pruning done by ObjectAllocationSinkingPhase ignores the possibility of an object's bytecode liveness being longer than its DFG liveness
https://bugs.webkit.org/show_bug.cgi?id=144945

Reviewed by Michael Saboff.
        
We were making the mistake of using DFG liveness for object allocation sinking decisions.
This is wrong. In fact we almost never want to use DFG liveness directly. The only place
where that makes sense is pruning in DFG AI.
        
So, I created a CombinedLiveness class that combines the DFG liveness with bytecode
liveness.
        
In the process of doing this, I realized that the DFGForAllKills definition of combined
liveness at block tail was not strictly right; it was using the bytecode liveness at the
block terminal instead of the union of the bytecode live-at-heads of successor blocks. So,
I changed DFGForAllKills to work in terms of CombinedLiveness.
        
This allows me to unskip the test I added in r184260. I also added a new test that tries to
trigger this bug more directly.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGCombinedLiveness.cpp: Added.
(JSC::DFG::liveNodesAtHead):
(JSC::DFG::CombinedLiveness::CombinedLiveness):
* dfg/DFGCombinedLiveness.h: Added.
(JSC::DFG::CombinedLiveness::CombinedLiveness):
* dfg/DFGForAllKills.h:
(JSC::DFG::forAllKillsInBlock):
(JSC::DFG::forAllLiveNodesAtTail): Deleted.
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::performSinking):
(JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
* tests/stress/escape-object-in-diamond-then-exit.js: Added.
* tests/stress/sink-object-past-invalid-check-sneaky.js:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@184311 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp b/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp
new file mode 100644
index 0000000..ccf9433
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 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. ``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
+ * 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. 
+ */
+
+#include "config.h"
+#include "DFGCombinedLiveness.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGAvailabilityMap.h"
+#include "DFGBlockMapInlines.h"
+#include "FullBytecodeLiveness.h"
+#include "JSCInlines.h"
+
+namespace JSC { namespace DFG {
+
+HashSet<Node*> liveNodesAtHead(Graph& graph, BasicBlock* block)
+{
+    HashSet<Node*> seen;
+    for (Node* node : block->ssa->liveAtHead)
+        seen.add(node);
+    
+    AvailabilityMap& availabilityMap = block->ssa->availabilityAtHead;
+    graph.forAllLocalsLiveInBytecode(
+        block->firstOrigin().forExit,
+        [&] (VirtualRegister reg) {
+            availabilityMap.closeStartingWithLocal(
+                reg,
+                [&] (Node* node) -> bool {
+                    return seen.contains(node);
+                },
+                [&] (Node* node) -> bool {
+                    return seen.add(node).isNewEntry;
+                });
+        });
+    
+    return seen;
+}
+
+CombinedLiveness::CombinedLiveness(Graph& graph)
+    : liveAtHead(graph)
+    , liveAtTail(graph)
+{
+    // First compute the liveAtHead for each block.
+    for (BasicBlock* block : graph.blocksInNaturalOrder())
+        liveAtHead[block] = liveNodesAtHead(graph, block);
+    
+    // Now compute the liveAtTail by unifying the liveAtHead of the successors.
+    for (BasicBlock* block : graph.blocksInNaturalOrder()) {
+        for (BasicBlock* successor : block->successors()) {
+            for (Node* node : liveAtHead[successor])
+                liveAtTail[block].add(node);
+        }
+    }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+