Diff
Modified: trunk/JSTests/ChangeLog (221606 => 221607)
--- trunk/JSTests/ChangeLog 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/JSTests/ChangeLog 2017-09-05 04:10:53 UTC (rev 221607)
@@ -1,3 +1,13 @@
+2017-09-04 Saam Barati <sbar...@apple.com>
+
+ 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-09-03 Yusuke Suzuki <utatane....@gmail.com>
[DFG][FTL] Efficiently execute number#toString()
Added: trunk/JSTests/stress/dont-crash-when-hoist-check-structure-on-tdz.js (0 => 221607)
--- trunk/JSTests/stress/dont-crash-when-hoist-check-structure-on-tdz.js (rev 0)
+++ trunk/JSTests/stress/dont-crash-when-hoist-check-structure-on-tdz.js 2017-09-05 04:10:53 UTC (rev 221607)
@@ -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: trunk/Source/_javascript_Core/ChangeLog (221606 => 221607)
--- trunk/Source/_javascript_Core/ChangeLog 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-09-05 04:10:53 UTC (rev 221607)
@@ -1,5 +1,63 @@
2017-09-04 Saam Barati <sbar...@apple.com>
+ 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-09-04 Saam Barati <sbar...@apple.com>
+
Support compiling catch in the FTL
https://bugs.webkit.org/show_bug.cgi?id=175396
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2017-09-05 04:10:53 UTC (rev 221607)
@@ -2406,6 +2406,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: trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -370,6 +370,7 @@
escapeBasedOnArrayMode(node->arrayMode(), node->child1(), node);
break;
+ case CheckStructureOrEmpty:
case CheckStructure: {
if (!m_candidates.contains(node->child1().node()))
break;
@@ -1096,6 +1097,7 @@
break;
}
+ case CheckStructureOrEmpty:
case CheckStructure:
if (!isEliminatedAllocation(node->child1().node()))
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2017-09-05 04:10:53 UTC (rev 221607)
@@ -958,6 +958,7 @@
return;
}
+ case CheckStructureOrEmpty:
case CheckStructure:
read(JSCell_structureID);
return;
Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -161,7 +161,14 @@
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: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -115,6 +115,8 @@
case DeleteById:
case DeleteByVal:
case CheckStructure:
+ case CheckStructureOrEmpty:
+ case CheckStructureImmediate:
case GetExecutable:
case GetButterfly:
case GetButterflyWithoutCaging:
@@ -263,7 +265,6 @@
case GetMyArgumentByValOutOfBounds:
case ForwardVarargs:
case PutHint:
- case CheckStructureImmediate:
case PutStack:
case KillStack:
case GetStack:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -1583,6 +1583,7 @@
case GetVectorLength:
case PutHint:
case CheckStructureImmediate:
+ case CheckStructureOrEmpty:
case MaterializeNewObject:
case MaterializeCreateActivation:
case PutStack:
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2017-09-05 04:10:53 UTC (rev 221607)
@@ -432,6 +432,12 @@
m_opInfo = set;
}
+ void convertCheckStructureOrEmptyToCheckStructure()
+ {
+ ASSERT(op() == CheckStructureOrEmpty);
+ setOpAndDefaultFlags(CheckStructure);
+ }
+
void convertToCheckStructureImmediate(Node* structure)
{
ASSERT(op() == CheckStructure);
@@ -1716,6 +1722,7 @@
{
switch (op()) {
case CheckStructure:
+ case CheckStructureOrEmpty:
case CheckStructureImmediate:
case MaterializeNewObject:
return true;
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2017-09-05 04:10:53 UTC (rev 221607)
@@ -203,6 +203,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: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -892,6 +892,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: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -1069,6 +1069,7 @@
case GetMyArgumentByValOutOfBounds:
case PutHint:
case CheckStructureImmediate:
+ case CheckStructureOrEmpty:
case MaterializeNewObject:
case MaterializeCreateActivation:
case PutStack:
@@ -1081,8 +1082,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: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2017-09-05 04:10:53 UTC (rev 221607)
@@ -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.
@@ -214,6 +235,7 @@
case DefineDataProperty:
case DefineAccessorProperty:
case CheckStructure:
+ case CheckStructureOrEmpty:
case GetExecutable:
case GetButterfly:
case GetButterflyWithoutCaging:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -7891,7 +7891,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());
@@ -7936,7 +7936,7 @@
case CellUse:
case KnownCellUse: {
SpeculateCellOperand cell(this, node->child1());
- compileCheckStructure(node, cell.gpr(), InvalidGPRReg);
+ emitStructureCheck(node, cell.gpr(), InvalidGPRReg);
noResult(node);
return;
}
@@ -7954,7 +7954,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: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2017-09-05 04:10:53 UTC (rev 221607)
@@ -2906,8 +2906,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: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -5658,6 +5658,10 @@
break;
}
+ case CheckStructureOrEmpty:
+ DFG_CRASH(m_jit.graph(), node, "CheckStructureOrEmpty only used in 64-bit DFG");
+ break;
+
case LastNodeType:
case Phi:
case Upsilon:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -4634,6 +4634,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: trunk/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -178,8 +178,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: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -277,6 +277,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: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -65,6 +65,7 @@
case BitLShift:
case BitURShift:
case CheckStructure:
+ case CheckStructureOrEmpty:
case DoubleAsInt32:
case ArrayifyToStructure:
case PutStructure:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (221606 => 221607)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2017-09-05 03:44:05 UTC (rev 221606)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2017-09-05 04:10:53 UTC (rev 221607)
@@ -644,6 +644,9 @@
case CheckStructure:
compileCheckStructure();
break;
+ case CheckStructureOrEmpty:
+ compileCheckStructureOrEmpty();
+ break;
case CheckCell:
compileCheckCell();
break;
@@ -2763,6 +2766,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()
{