Diff
Modified: branches/safari-604-branch/JSTests/ChangeLog (223678 => 223679)
--- branches/safari-604-branch/JSTests/ChangeLog 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/JSTests/ChangeLog 2017-10-19 06:07:36 UTC (rev 223679)
@@ -1,5 +1,19 @@
2017-10-18 Jason Marcell <[email protected]>
+ Cherry-pick r221607. rdar://problem/35041474
+
+ 2017-09-04 Saam Barati <[email protected]>
+
+ typeCheckHoistingPhase may emit a CheckStructure on the empty value which leads to a dereference of zero on 64 bit platforms
+ https://bugs.webkit.org/show_bug.cgi?id=176317
+
+ Reviewed by Keith Miller.
+
+ * stress/dont-crash-when-hoist-check-structure-on-tdz.js: Added.
+ (Foo):
+
+2017-10-18 Jason Marcell <[email protected]>
+
Cherry-pick r223614. rdar://problem/34920288
2017-10-18 Mark Lam <[email protected]>
Added: branches/safari-604-branch/JSTests/stress/dont-crash-when-hoist-check-structure-on-tdz.js (0 => 223679)
--- branches/safari-604-branch/JSTests/stress/dont-crash-when-hoist-check-structure-on-tdz.js (rev 0)
+++ branches/safari-604-branch/JSTests/stress/dont-crash-when-hoist-check-structure-on-tdz.js 2017-10-19 06:07:36 UTC (rev 223679)
@@ -0,0 +1,28 @@
+class Foo extends Object {
+ constructor(c1, c2) {
+ if (c1)
+ super();
+ let arrow = () => {
+ if (c2)
+ this.foo = 20;
+ else
+ this.foo = 40;
+ };
+ noInline(arrow);
+ arrow();
+ }
+}
+noInline(Foo);
+
+for (let i = 0; i < 1000; ++i)
+ new Foo(true, !!(i%2));
+
+let threw = false;
+try {
+ new Foo(false, true);
+} catch {
+ threw = true;
+} finally {
+ if (!threw)
+ throw new Error("Bad")
+}
Modified: branches/safari-604-branch/Source/_javascript_Core/ChangeLog (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/ChangeLog 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/ChangeLog 2017-10-19 06:07:36 UTC (rev 223679)
@@ -1,5 +1,67 @@
2017-10-18 Jason Marcell <[email protected]>
+ Cherry-pick r221607. rdar://problem/35041474
+
+ 2017-09-04 Saam Barati <[email protected]>
+
+ typeCheckHoistingPhase may emit a CheckStructure on the empty value which leads to a dereference of zero on 64 bit platforms
+ https://bugs.webkit.org/show_bug.cgi?id=176317
+
+ Reviewed by Keith Miller.
+
+ It turns out that TypeCheckHoistingPhase may hoist a CheckStructure up to
+ the SetLocal of a particular value where the value is the empty JSValue.
+ On 64-bit platforms, the empty value is zero. This means that the empty value
+ passes a cell check. This will lead to a crash when we dereference null to load
+ the value's structure. This patch teaches TypeCheckHoistingPhase to be conservative
+ in the structure checks it hoists. On 64-bit platforms, instead of emitting a
+ CheckStructure node, we now emit a CheckStructureOrEmpty node. This node allows
+ the empty value to flow through. If the value isn't empty, it'll perform the normal
+ structure check that CheckStructure performs. For now, we only emit CheckStructureOrEmpty
+ on 64-bit platforms since a cell check on 32-bit platforms does not allow the empty
+ value to flow through.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGArgumentsEliminationPhase.cpp:
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertCheckStructureOrEmptyToCheckStructure):
+ (JSC::DFG::Node::hasStructureSet):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGObjectAllocationSinkingPhase.cpp:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::SafeToExecuteEdge::SafeToExecuteEdge):
+ (JSC::DFG::SafeToExecuteEdge::operator()):
+ (JSC::DFG::SafeToExecuteEdge::maySeeEmptyChild):
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::emitStructureCheck):
+ (JSC::DFG::SpeculativeJIT::compileCheckStructure):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGTypeCheckHoistingPhase.cpp:
+ (JSC::DFG::TypeCheckHoistingPhase::run):
+ * dfg/DFGValidate.cpp:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCheckStructureOrEmpty):
+
+2017-10-18 Jason Marcell <[email protected]>
+
Cherry-pick r223409. rdar://problem/34792148
2017-10-16 JF Bastien <[email protected]>
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2017-10-19 06:07:36 UTC (rev 223679)
@@ -2327,6 +2327,18 @@
filter(value, set, admittedTypes);
break;
}
+
+ case CheckStructureOrEmpty: {
+ AbstractValue& value = forNode(node->child1());
+
+ bool mayBeEmpty = value.m_type & SpecEmpty;
+ if (!mayBeEmpty)
+ m_state.setFoundConstants(true);
+
+ SpeculatedType admittedTypes = mayBeEmpty ? SpecEmpty : SpecNone;
+ filter(value, node->structureSet(), admittedTypes);
+ break;
+ }
case CheckStructureImmediate: {
// FIXME: This currently can only reason about one structure at a time.
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -367,6 +367,7 @@
escapeBasedOnArrayMode(node->arrayMode(), node->child1(), node);
break;
+ case CheckStructureOrEmpty:
case CheckStructure: {
if (!m_candidates.contains(node->child1().node()))
break;
@@ -1091,6 +1092,7 @@
break;
}
+ case CheckStructureOrEmpty:
case CheckStructure:
if (!isEliminatedAllocation(node->child1().node()))
break;
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGClobberize.h (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGClobberize.h 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGClobberize.h 2017-10-19 06:07:36 UTC (rev 223679)
@@ -945,6 +945,7 @@
return;
}
+ case CheckStructureOrEmpty:
case CheckStructure:
read(JSCell_structureID);
return;
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -139,7 +139,15 @@
// See: https://bugs.webkit.org/show_bug.cgi?id=174844
break;
}
-
+
+ case CheckStructureOrEmpty: {
+ const AbstractValue& value = m_state.forNode(node->child1());
+ if (value.m_type & SpecEmpty)
+ break;
+ node->convertCheckStructureOrEmptyToCheckStructure();
+ changed = true;
+ FALLTHROUGH;
+ }
case CheckStructure:
case ArrayifyToStructure: {
AbstractValue& value = m_state.forNode(node->child1());
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGDoesGC.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -113,6 +113,8 @@
case DeleteById:
case DeleteByVal:
case CheckStructure:
+ case CheckStructureOrEmpty:
+ case CheckStructureImmediate:
case GetExecutable:
case GetButterfly:
case CheckSubClass:
@@ -254,7 +256,6 @@
case GetMyArgumentByValOutOfBounds:
case ForwardVarargs:
case PutHint:
- case CheckStructureImmediate:
case PutStack:
case KillStack:
case GetStack:
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -1555,6 +1555,7 @@
case GetVectorLength:
case PutHint:
case CheckStructureImmediate:
+ case CheckStructureOrEmpty:
case MaterializeNewObject:
case MaterializeCreateActivation:
case PutStack:
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGNode.h (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGNode.h 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGNode.h 2017-10-19 06:07:36 UTC (rev 223679)
@@ -422,6 +422,12 @@
m_opInfo = set;
}
+ void convertCheckStructureOrEmptyToCheckStructure()
+ {
+ ASSERT(op() == CheckStructureOrEmpty);
+ setOpAndDefaultFlags(CheckStructure);
+ }
+
void convertToCheckStructureImmediate(Node* structure)
{
ASSERT(op() == CheckStructure);
@@ -1623,6 +1629,7 @@
{
switch (op()) {
case CheckStructure:
+ case CheckStructureOrEmpty:
case CheckStructureImmediate:
case MaterializeNewObject:
return true;
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGNodeType.h (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGNodeType.h 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGNodeType.h 2017-10-19 06:07:36 UTC (rev 223679)
@@ -200,6 +200,7 @@
macro(DeleteById, NodeResultBoolean | NodeMustGenerate) \
macro(DeleteByVal, NodeResultBoolean | NodeMustGenerate) \
macro(CheckStructure, NodeMustGenerate) \
+ macro(CheckStructureOrEmpty, NodeMustGenerate) \
macro(GetExecutable, NodeResultJS) \
macro(PutStructure, NodeMustGenerate) \
macro(AllocatePropertyStorage, NodeMustGenerate | NodeResultStorage) \
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -886,6 +886,7 @@
m_heap.escape(node->child1().node());
break;
+ case CheckStructureOrEmpty:
case CheckStructure: {
Allocation* allocation = m_heap.onlyLocalAllocation(node->child1().node());
if (allocation && allocation->isObjectAllocation()) {
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -1053,6 +1053,7 @@
case GetMyArgumentByValOutOfBounds:
case PutHint:
case CheckStructureImmediate:
+ case CheckStructureOrEmpty:
case MaterializeNewObject:
case MaterializeCreateActivation:
case PutStack:
@@ -1065,8 +1066,7 @@
case RecordRegExpCachedResult:
case LazyJSConstant:
case CallDOM: {
- // This node should never be visible at this stage of compilation. It is
- // inserted by fixup(), which follows this phase.
+ // This node should never be visible at this stage of compilation.
DFG_CRASH(m_graph, m_currentNode, "Unexpected node during prediction propagation");
break;
}
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSafeToExecute.h (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2017-10-19 06:07:36 UTC (rev 223679)
@@ -36,12 +36,13 @@
public:
SafeToExecuteEdge(AbstractStateType& state)
: m_state(state)
- , m_result(true)
{
}
void operator()(Node*, Edge edge)
{
+ m_maySeeEmptyChild |= !!(m_state.forNode(edge).m_type & SpecEmpty);
+
switch (edge.useKind()) {
case UntypedUse:
case Int32Use:
@@ -110,9 +111,11 @@
}
bool result() const { return m_result; }
+ bool maySeeEmptyChild() const { return m_maySeeEmptyChild; }
private:
AbstractStateType& m_state;
- bool m_result;
+ bool m_result { true };
+ bool m_maySeeEmptyChild { false };
};
// Determines if it's safe to execute a node within the given abstract state. This may
@@ -134,6 +137,24 @@
if (!safeToExecuteEdge.result())
return false;
+ if (safeToExecuteEdge.maySeeEmptyChild()) {
+ // We conservatively assume if the empty value flows into a node,
+ // it might not be able to handle it (e.g, crash). In general, the bytecode generator
+ // emits code in such a way that most node types don't need to worry about the empty value
+ // because they will never see it. However, code motion has to consider the empty
+ // value so it does not insert/move nodes to a place where they will crash. E.g, the
+ // type check hoisting phase needs to insert CheckStructureOrEmpty instead of CheckStructure
+ // for hoisted structure checks because it can not guarantee that a particular local is not
+ // the empty value.
+ switch (node->op()) {
+ case CheckNotEmpty:
+ case CheckStructureOrEmpty:
+ break;
+ default:
+ return false;
+ }
+ }
+
// NOTE: This tends to lie when it comes to effectful nodes, because it knows that they aren't going to
// get hoisted anyway.
@@ -213,6 +234,7 @@
case DefineDataProperty:
case DefineAccessorProperty:
case CheckStructure:
+ case CheckStructureOrEmpty:
case GetExecutable:
case GetButterfly:
case CallDOMGetter:
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -7783,7 +7783,7 @@
cellResult(resultGPR, node);
}
-void SpeculativeJIT::compileCheckStructure(Node* node, GPRReg cellGPR, GPRReg tempGPR)
+void SpeculativeJIT::emitStructureCheck(Node* node, GPRReg cellGPR, GPRReg tempGPR)
{
ASSERT(node->structureSet().size());
@@ -7828,7 +7828,7 @@
case CellUse:
case KnownCellUse: {
SpeculateCellOperand cell(this, node->child1());
- compileCheckStructure(node, cell.gpr(), InvalidGPRReg);
+ emitStructureCheck(node, cell.gpr(), InvalidGPRReg);
noResult(node);
return;
}
@@ -7846,7 +7846,7 @@
m_jit.branchIfNotOther(valueRegs, tempGPR));
JITCompiler::Jump done = m_jit.jump();
cell.link(&m_jit);
- compileCheckStructure(node, valueRegs.payloadGPR(), tempGPR);
+ emitStructureCheck(node, valueRegs.payloadGPR(), tempGPR);
done.link(&m_jit);
noResult(node);
return;
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2017-10-19 06:07:36 UTC (rev 223679)
@@ -2850,8 +2850,8 @@
void compileIsObjectOrNull(Node*);
void compileIsFunction(Node*);
void compileTypeOf(Node*);
- void compileCheckStructure(Node*, GPRReg cellGPR, GPRReg tempGPR);
void compileCheckStructure(Node*);
+ void emitStructureCheck(Node*, GPRReg cellGPR, GPRReg tempGPR);
void compilePutAccessorById(Node*);
void compilePutGetterSetterById(Node*);
void compilePutAccessorByVal(Node*);
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -5631,6 +5631,10 @@
unreachable(node);
break;
+ case CheckStructureOrEmpty:
+ DFG_CRASH(m_jit.graph(), node, "CheckStructureOrEmpty only used in 64-bit DFG");
+ break;
+
case LastNodeType:
case Phi:
case Upsilon:
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -4620,6 +4620,22 @@
break;
}
+ case CheckStructureOrEmpty: {
+ SpeculateCellOperand cell(this, node->child1());
+ GPRReg cellGPR = cell.gpr();
+ MacroAssembler::Jump isEmpty;
+ if (m_interpreter.forNode(node->child1()).m_type & SpecEmpty)
+ isEmpty = m_jit.branchTest64(MacroAssembler::Zero, cellGPR);
+
+ emitStructureCheck(node, cellGPR, InvalidGPRReg);
+
+ if (isEmpty.isSet())
+ isEmpty.link(&m_jit);
+
+ noResult(node);
+ break;
+ }
+
case CheckStructure: {
compileCheckStructure(node);
break;
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -177,8 +177,14 @@
Edge child1 = node->child1();
if (iter->value.m_structure) {
+ // Note: On 64-bit platforms, cell checks allow the empty value to flow through.
+ // This means that this structure check may see the empty value as input. We need
+ // to emit a node that explicitly handles the empty value. Most of the time, CheckStructureOrEmpty
+ // will be folded to CheckStructure because AI proves that the incoming value is
+ // definitely not empty.
+ static_assert(is64Bit() || !(SpecCellCheck & SpecEmpty), "");
insertionSet.insertNode(
- indexForChecks, SpecNone, CheckStructure,
+ indexForChecks, SpecNone, is64Bit() ? CheckStructureOrEmpty : CheckStructure,
originForChecks.withSemantic(origin.semantic),
OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
Edge(child1.node(), CellUse));
Modified: branches/safari-604-branch/Source/_javascript_Core/dfg/DFGValidate.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/dfg/DFGValidate.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/dfg/DFGValidate.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -269,6 +269,11 @@
VALIDATE((node), !!node->child1());
VALIDATE((node), !!node->cellOperand()->value() && node->cellOperand()->value().isCell());
break;
+ case CheckStructureOrEmpty:
+ VALIDATE((node), is64Bit());
+ VALIDATE((node), !!node->child1());
+ VALIDATE((node), node->child1().useKind() == CellUse);
+ break;
case CheckStructure:
case StringFromCharCode:
VALIDATE((node), !!node->child1());
Modified: branches/safari-604-branch/Source/_javascript_Core/ftl/FTLCapabilities.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -65,6 +65,7 @@
case BitLShift:
case BitURShift:
case CheckStructure:
+ case CheckStructureOrEmpty:
case DoubleAsInt32:
case ArrayifyToStructure:
case PutStructure:
Modified: branches/safari-604-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (223678 => 223679)
--- branches/safari-604-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2017-10-19 05:44:33 UTC (rev 223678)
+++ branches/safari-604-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2017-10-19 06:07:36 UTC (rev 223679)
@@ -606,6 +606,9 @@
case CheckStructure:
compileCheckStructure();
break;
+ case CheckStructureOrEmpty:
+ compileCheckStructureOrEmpty();
+ break;
case CheckCell:
compileCheckCell();
break;
@@ -2705,6 +2708,39 @@
return;
}
}
+
+ void compileCheckStructureOrEmpty()
+ {
+ ExitKind exitKind;
+ if (m_node->child1()->hasConstant())
+ exitKind = BadConstantCache;
+ else
+ exitKind = BadCache;
+
+ LValue cell = lowCell(m_node->child1());
+ bool maySeeEmptyValue = m_interpreter.forNode(m_node->child1()).m_type & SpecEmpty;
+ LBasicBlock notEmpty;
+ LBasicBlock continuation;
+ LBasicBlock lastNext;
+ if (maySeeEmptyValue) {
+ notEmpty = m_out.newBlock();
+ continuation = m_out.newBlock();
+ m_out.branch(m_out.isZero64(cell), unsure(continuation), unsure(notEmpty));
+ lastNext = m_out.appendTo(notEmpty, continuation);
+ }
+
+ checkStructure(
+ m_out.load32(cell, m_heaps.JSCell_structureID), jsValueValue(cell),
+ exitKind, m_node->structureSet(),
+ [&] (RegisteredStructure structure) {
+ return weakStructureID(structure);
+ });
+
+ if (maySeeEmptyValue) {
+ m_out.jump(continuation);
+ m_out.appendTo(continuation, lastNext);
+ }
+ }
void compileCheckCell()
{