diff --git a/JSTests/stress/getbyoffset-cse-consistency-2.js b/JSTests/stress/getbyoffset-cse-consistency-2.js new file mode 100644 index 000000000000..987376d6085f --- /dev/null +++ b/JSTests/stress/getbyoffset-cse-consistency-2.js @@ -0,0 +1,45 @@ + +let a = {"x": 3}; +a.y1 = 3.3; + +let b = {}; +let res = 42; +b.__defineGetter__("y2", function () { + res = 43; + return {}; +}); +b.x = 1.1; + +let c = {}; +c.slot_1 = 1.1; + +function func(flag, arg0, arg1) { + let tmp = b; + if (flag) { + tmp = a; + } + if (arg1 > 100) { + return; + } + for (let i = 0; i < 2; i++) { + if (flag) { + var x = tmp.x; + } else { + var x = tmp.x; + } + arg0.y = 3.3; + } + "" + x; + c.slot_1 = x; +} + +for (let i = 0; i < 0x100000; i++) { + func(i % 2, {}, i); +} + +b.x +func(0, {}, 1); +c.slot_1 + +if (res == 43) + throw "BAD!"; diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h index 4d8b60e65dc0..6cb2412c2d20 100644 --- a/Source/JavaScriptCore/dfg/DFGClobberize.h +++ b/Source/JavaScriptCore/dfg/DFGClobberize.h @@ -1476,7 +1476,17 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu unsigned identifierNumber = node->storageAccessData().identifierNumber; AbstractHeap heap(NamedProperties, identifierNumber); read(heap); - def(HeapLocation(NamedPropertyLoc, heap, node->child2(), &node->storageAccessData()), LazyNode(node)); + + // Since LICM might break the uniqueness assumption of HeapLocation for + // *byOffset nodes. Then, the HeapLocation constructor with an extra state + // is introduced and applied in this phase in order to resolve the potential + // HeapLocation collisions for *byteOffset nodes after LICM phase. Note + // that the constructor with an extra state should be used only after LICM + // since it might affect performance. + if (graph.m_planStage >= PlanStage::LICMAndLater) + def(HeapLocation(NamedPropertyLoc, heap, node->child2(), &node->storageAccessData()), LazyNode(node)); + else + def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node)); return; } @@ -1485,7 +1495,10 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu read(JSObject_butterfly); AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber); read(heap); - def(HeapLocation(NamedPropertyLoc, heap, node->child1(), &node->multiGetByOffsetData()), LazyNode(node)); + if (graph.m_planStage >= PlanStage::LICMAndLater) + def(HeapLocation(NamedPropertyLoc, heap, node->child1(), &node->multiGetByOffsetData()), LazyNode(node)); + else + def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node)); return; } @@ -1498,7 +1511,10 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu write(JSCell_structureID); if (node->multiPutByOffsetData().reallocatesStorage()) write(JSObject_butterfly); - def(HeapLocation(NamedPropertyLoc, heap, node->child1(), &node->multiPutByOffsetData()), LazyNode(node->child2().node())); + if (graph.m_planStage >= PlanStage::LICMAndLater) + def(HeapLocation(NamedPropertyLoc, heap, node->child1(), &node->multiPutByOffsetData()), LazyNode(node->child2().node())); + else + def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node())); return; } @@ -1520,7 +1536,10 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu unsigned identifierNumber = node->storageAccessData().identifierNumber; AbstractHeap heap(NamedProperties, identifierNumber); write(heap); - def(HeapLocation(NamedPropertyLoc, heap, node->child2(), &node->storageAccessData()), LazyNode(node->child3().node())); + if (graph.m_planStage >= PlanStage::LICMAndLater) + def(HeapLocation(NamedPropertyLoc, heap, node->child2(), &node->storageAccessData()), LazyNode(node->child3().node())); + else + def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node())); return; } diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h index afdc10a8a058..3e069dbcf751 100644 --- a/Source/JavaScriptCore/dfg/DFGCommon.h +++ b/Source/JavaScriptCore/dfg/DFGCommon.h @@ -252,7 +252,8 @@ inline KillStatus killStatusForDoesKill(bool doesKill) enum class PlanStage { Initial, - AfterFixup + AfterFixup, + LICMAndLater }; // If possible, this will acquire a lock to make sure that if multiple threads diff --git a/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp b/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp index fb4d87bd4aa6..9a4a7b80aa88 100644 --- a/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp @@ -63,6 +63,9 @@ class LICMPhase : public Phase { bool run() { + ASSERT(m_graph.m_planStage <= PlanStage::LICMAndLater); + m_graph.m_planStage = PlanStage::LICMAndLater; + DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA); m_graph.ensureSSADominators();