Modified: trunk/Source/_javascript_Core/ChangeLog (183751 => 183752)
--- trunk/Source/_javascript_Core/ChangeLog 2015-05-04 18:26:00 UTC (rev 183751)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-05-04 18:37:58 UTC (rev 183752)
@@ -1,3 +1,30 @@
+2015-05-04 Basile Clement <[email protected]>
+
+ Object allocation not sinking properly through CheckStructure
+ https://bugs.webkit.org/show_bug.cgi?id=144465
+
+ Reviewed by Filip Pizlo.
+
+ Currently, sinking an allocation through a CheckStructure will
+ completely ignore all structure checking, which is obviously wrong.
+
+ A CheckStructureImmediate node type was present for that purpose, but
+ the CheckStructures were not properly replaced. This ensures that
+ CheckStructure nodes are replaced by CheckStructureImmediate nodes when
+ sunk through, and that structure checking happens correctly.
+
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToCheckStructureImmediate): Added.
+ (JSC::DFG::Node::hasStructureSet):
+ * dfg/DFGObjectAllocationSinkingPhase.cpp:
+ (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileCheckStructure):
+ (JSC::FTL::LowerDFGToLLVM::compileCheckStructureImmediate):
+ (JSC::FTL::LowerDFGToLLVM::checkStructure):
+ * tests/stress/sink_checkstructure.js: Added.
+ (foo):
+
2015-05-01 Geoffrey Garen <[email protected]>
REGRESSION(r183570): jslib-traverse-jquery is 22% slower
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (183751 => 183752)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2015-05-04 18:26:00 UTC (rev 183751)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2015-05-04 18:37:58 UTC (rev 183752)
@@ -414,6 +414,13 @@
setOpAndDefaultFlags(CheckStructure);
m_opInfo = bitwise_cast<uintptr_t>(set);
}
+
+ void convertToCheckStructureImmediate(Node* structure)
+ {
+ ASSERT(op() == CheckStructure);
+ m_op = CheckStructureImmediate;
+ children.setChild1(Edge(structure, CellUse));
+ }
void replaceWith(Node* other)
{
@@ -1334,6 +1341,7 @@
{
switch (op()) {
case CheckStructure:
+ case CheckStructureImmediate:
return true;
default:
return false;
Modified: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (183751 => 183752)
--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2015-05-04 18:26:00 UTC (rev 183751)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2015-05-04 18:37:58 UTC (rev 183752)
@@ -728,8 +728,17 @@
m_localMapping.set(location, value.node());
},
[&] (PromotedHeapLocation location) {
- if (m_sinkCandidates.contains(location.base()))
- node->replaceWith(resolve(block, location));
+ if (m_sinkCandidates.contains(location.base())) {
+ switch (node->op()) {
+ case CheckStructure:
+ node->convertToCheckStructureImmediate(resolve(block, location));
+ break;
+
+ default:
+ node->replaceWith(resolve(block, location));
+ break;
+ }
+ }
});
}
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (183751 => 183752)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2015-05-04 18:26:00 UTC (rev 183751)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2015-05-04 18:37:58 UTC (rev 183752)
@@ -1882,7 +1882,11 @@
LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
- checkStructure(structureID, jsValueValue(cell), exitKind, m_node->structureSet());
+ checkStructure(
+ structureID, jsValueValue(cell), exitKind, m_node->structureSet(),
+ [this] (Structure* structure) {
+ return weakStructureID(structure);
+ });
}
void compileCheckCell()
@@ -5089,8 +5093,12 @@
void compileCheckStructureImmediate()
{
- LValue structureID = lowCell(m_node->child1());
- checkStructure(structureID, noValue(), BadCache, m_node->structureSet());
+ LValue structure = lowCell(m_node->child1());
+ checkStructure(
+ structure, noValue(), BadCache, m_node->structureSet(),
+ [this] (Structure* structure) {
+ return weakStructure(structure);
+ });
}
void compileMaterializeNewObject()
@@ -5430,14 +5438,15 @@
return getArgumentsStart(m_node->origin.semantic.inlineCallFrame);
}
+ template<typename Functor>
void checkStructure(
- LValue structureID, const FormattedValue& formattedValue, ExitKind exitKind,
- const StructureSet& set)
+ LValue structureDiscriminant, const FormattedValue& formattedValue, ExitKind exitKind,
+ const StructureSet& set, const Functor& weakStructureDiscriminant)
{
if (set.size() == 1) {
speculate(
exitKind, formattedValue, 0,
- m_out.notEqual(structureID, weakStructureID(set[0])));
+ m_out.notEqual(structureDiscriminant, weakStructureDiscriminant(set[0])));
return;
}
@@ -5447,14 +5456,14 @@
for (unsigned i = 0; i < set.size() - 1; ++i) {
LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("checkStructure nextStructure"));
m_out.branch(
- m_out.equal(structureID, weakStructureID(set[i])),
+ m_out.equal(structureDiscriminant, weakStructureDiscriminant(set[i])),
unsure(continuation), unsure(nextStructure));
m_out.appendTo(nextStructure);
}
speculate(
exitKind, formattedValue, 0,
- m_out.notEqual(structureID, weakStructureID(set.last())));
+ m_out.notEqual(structureDiscriminant, weakStructureDiscriminant(set.last())));
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
Added: trunk/Source/_javascript_Core/tests/stress/sink_checkstructure.js (0 => 183752)
--- trunk/Source/_javascript_Core/tests/stress/sink_checkstructure.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink_checkstructure.js 2015-05-04 18:37:58 UTC (rev 183752)
@@ -0,0 +1,17 @@
+function foo(p, q) {
+ var o = {};
+ if (p) o.f = 42;
+ if (q) { o.f++; return o; }
+}
+noInline(foo);
+
+var expected = foo(false, true).f;
+
+for (var i = 0; i < 1000000; i++) {
+ foo(true, true);
+}
+
+var result = foo(false, true).f;
+
+if (!Object.is(result, expected))
+ throw "Error: expected " + expected + "; FTL produced " + result;