<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[183708] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/183708">183708</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-05-01 18:59:46 -0700 (Fri, 01 May 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>FTL should use AI more
https://bugs.webkit.org/show_bug.cgi?id=144500

Reviewed by Oliver Hunt.
        
This makes our type check folding even more comprehensive by ensuring that even if the FTL
decides to emit some checks, it will still do another query to the abstract interpreter to
see if the check is necessary. This helps with cases where we decided early on to speculate
one way, but later proved a more specific type of the value in question, and the constant
folder didn't catch it.
        
This also makes it more natural to query the abstract interpreter. For example, if you just
want the proven type, you can now say provenType(node) or provenType(edge).

* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::alreadyChecked):
* dfg/DFGArrayMode.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber):
(JSC::FTL::LowerDFGToLLVM::compileToThis):
(JSC::FTL::LowerDFGToLLVM::compileValueAdd):
(JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub):
(JSC::FTL::LowerDFGToLLVM::compileArithPow):
(JSC::FTL::LowerDFGToLLVM::compileArithNegate):
(JSC::FTL::LowerDFGToLLVM::compileGetById):
(JSC::FTL::LowerDFGToLLVM::compileCheckArray):
(JSC::FTL::LowerDFGToLLVM::compilePutByVal):
(JSC::FTL::LowerDFGToLLVM::compileToStringOrCallStringConstructor):
(JSC::FTL::LowerDFGToLLVM::compileToPrimitive):
(JSC::FTL::LowerDFGToLLVM::compileStringCharAt):
(JSC::FTL::LowerDFGToLLVM::compileStringCharCodeAt):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::compileSwitch):
(JSC::FTL::LowerDFGToLLVM::compileIsBoolean):
(JSC::FTL::LowerDFGToLLVM::compileIsNumber):
(JSC::FTL::LowerDFGToLLVM::compileIsString):
(JSC::FTL::LowerDFGToLLVM::compileIsObject):
(JSC::FTL::LowerDFGToLLVM::compileInstanceOf):
(JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32):
(JSC::FTL::LowerDFGToLLVM::baseIndex):
(JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject):
(JSC::FTL::LowerDFGToLLVM::typedArrayLength):
(JSC::FTL::LowerDFGToLLVM::boolify):
(JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined):
(JSC::FTL::LowerDFGToLLVM::lowInt32):
(JSC::FTL::LowerDFGToLLVM::lowInt52):
(JSC::FTL::LowerDFGToLLVM::lowCell):
(JSC::FTL::LowerDFGToLLVM::lowBoolean):
(JSC::FTL::LowerDFGToLLVM::lowDouble):
(JSC::FTL::LowerDFGToLLVM::isCellOrMisc):
(JSC::FTL::LowerDFGToLLVM::isNotCellOrMisc):
(JSC::FTL::LowerDFGToLLVM::isNumber):
(JSC::FTL::LowerDFGToLLVM::isNotNumber):
(JSC::FTL::LowerDFGToLLVM::isNotCell):
(JSC::FTL::LowerDFGToLLVM::isCell):
(JSC::FTL::LowerDFGToLLVM::isNotMisc):
(JSC::FTL::LowerDFGToLLVM::isMisc):
(JSC::FTL::LowerDFGToLLVM::isNotBoolean):
(JSC::FTL::LowerDFGToLLVM::isBoolean):
(JSC::FTL::LowerDFGToLLVM::isNotOther):
(JSC::FTL::LowerDFGToLLVM::isOther):
(JSC::FTL::LowerDFGToLLVM::isProvenValue):
(JSC::FTL::LowerDFGToLLVM::isObject):
(JSC::FTL::LowerDFGToLLVM::isNotObject):
(JSC::FTL::LowerDFGToLLVM::isNotString):
(JSC::FTL::LowerDFGToLLVM::isString):
(JSC::FTL::LowerDFGToLLVM::isFunction):
(JSC::FTL::LowerDFGToLLVM::isNotFunction):
(JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
(JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID):
(JSC::FTL::LowerDFGToLLVM::speculateNotStringVar):
(JSC::FTL::LowerDFGToLLVM::abstractValue):
(JSC::FTL::LowerDFGToLLVM::provenType):
(JSC::FTL::LowerDFGToLLVM::provenValue):
(JSC::FTL::LowerDFGToLLVM::abstractStructure):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGArrayModecpp">trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGArrayModeh">trunk/Source/JavaScriptCore/dfg/DFGArrayMode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (183707 => 183708)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-05-02 01:44:54 UTC (rev 183707)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-05-02 01:59:46 UTC (rev 183708)
</span><span class="lines">@@ -1,3 +1,81 @@
</span><ins>+2015-05-01  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL should use AI more
+        https://bugs.webkit.org/show_bug.cgi?id=144500
+
+        Reviewed by Oliver Hunt.
+        
+        This makes our type check folding even more comprehensive by ensuring that even if the FTL
+        decides to emit some checks, it will still do another query to the abstract interpreter to
+        see if the check is necessary. This helps with cases where we decided early on to speculate
+        one way, but later proved a more specific type of the value in question, and the constant
+        folder didn't catch it.
+        
+        This also makes it more natural to query the abstract interpreter. For example, if you just
+        want the proven type, you can now say provenType(node) or provenType(edge).
+
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::alreadyChecked):
+        * dfg/DFGArrayMode.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber):
+        (JSC::FTL::LowerDFGToLLVM::compileToThis):
+        (JSC::FTL::LowerDFGToLLVM::compileValueAdd):
+        (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub):
+        (JSC::FTL::LowerDFGToLLVM::compileArithPow):
+        (JSC::FTL::LowerDFGToLLVM::compileArithNegate):
+        (JSC::FTL::LowerDFGToLLVM::compileGetById):
+        (JSC::FTL::LowerDFGToLLVM::compileCheckArray):
+        (JSC::FTL::LowerDFGToLLVM::compilePutByVal):
+        (JSC::FTL::LowerDFGToLLVM::compileToStringOrCallStringConstructor):
+        (JSC::FTL::LowerDFGToLLVM::compileToPrimitive):
+        (JSC::FTL::LowerDFGToLLVM::compileStringCharAt):
+        (JSC::FTL::LowerDFGToLLVM::compileStringCharCodeAt):
+        (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+        (JSC::FTL::LowerDFGToLLVM::compileSwitch):
+        (JSC::FTL::LowerDFGToLLVM::compileIsBoolean):
+        (JSC::FTL::LowerDFGToLLVM::compileIsNumber):
+        (JSC::FTL::LowerDFGToLLVM::compileIsString):
+        (JSC::FTL::LowerDFGToLLVM::compileIsObject):
+        (JSC::FTL::LowerDFGToLLVM::compileInstanceOf):
+        (JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32):
+        (JSC::FTL::LowerDFGToLLVM::baseIndex):
+        (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject):
+        (JSC::FTL::LowerDFGToLLVM::typedArrayLength):
+        (JSC::FTL::LowerDFGToLLVM::boolify):
+        (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined):
+        (JSC::FTL::LowerDFGToLLVM::lowInt32):
+        (JSC::FTL::LowerDFGToLLVM::lowInt52):
+        (JSC::FTL::LowerDFGToLLVM::lowCell):
+        (JSC::FTL::LowerDFGToLLVM::lowBoolean):
+        (JSC::FTL::LowerDFGToLLVM::lowDouble):
+        (JSC::FTL::LowerDFGToLLVM::isCellOrMisc):
+        (JSC::FTL::LowerDFGToLLVM::isNotCellOrMisc):
+        (JSC::FTL::LowerDFGToLLVM::isNumber):
+        (JSC::FTL::LowerDFGToLLVM::isNotNumber):
+        (JSC::FTL::LowerDFGToLLVM::isNotCell):
+        (JSC::FTL::LowerDFGToLLVM::isCell):
+        (JSC::FTL::LowerDFGToLLVM::isNotMisc):
+        (JSC::FTL::LowerDFGToLLVM::isMisc):
+        (JSC::FTL::LowerDFGToLLVM::isNotBoolean):
+        (JSC::FTL::LowerDFGToLLVM::isBoolean):
+        (JSC::FTL::LowerDFGToLLVM::isNotOther):
+        (JSC::FTL::LowerDFGToLLVM::isOther):
+        (JSC::FTL::LowerDFGToLLVM::isProvenValue):
+        (JSC::FTL::LowerDFGToLLVM::isObject):
+        (JSC::FTL::LowerDFGToLLVM::isNotObject):
+        (JSC::FTL::LowerDFGToLLVM::isNotString):
+        (JSC::FTL::LowerDFGToLLVM::isString):
+        (JSC::FTL::LowerDFGToLLVM::isFunction):
+        (JSC::FTL::LowerDFGToLLVM::isNotFunction):
+        (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
+        (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID):
+        (JSC::FTL::LowerDFGToLLVM::speculateNotStringVar):
+        (JSC::FTL::LowerDFGToLLVM::abstractValue):
+        (JSC::FTL::LowerDFGToLLVM::provenType):
+        (JSC::FTL::LowerDFGToLLVM::provenValue):
+        (JSC::FTL::LowerDFGToLLVM::abstractStructure):
+
</ins><span class="cx"> 2015-05-01  Martin Robinson  &lt;mrobinson@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         USE(...) macro should expect unprefixed variables
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGArrayModecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp (183707 => 183708)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp        2015-05-02 01:44:54 UTC (rev 183707)
+++ trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp        2015-05-02 01:59:46 UTC (rev 183708)
</span><span class="lines">@@ -328,7 +328,7 @@
</span><span class="cx">     return originalArrayStructure(graph, node-&gt;origin.semantic);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ArrayMode::alreadyChecked(Graph&amp; graph, Node* node, AbstractValue&amp; value, IndexingType shape) const
</del><ins>+bool ArrayMode::alreadyChecked(Graph&amp; graph, Node* node, const AbstractValue&amp; value, IndexingType shape) const
</ins><span class="cx"> {
</span><span class="cx">     switch (arrayClass()) {
</span><span class="cx">     case Array::OriginalArray: {
</span><span class="lines">@@ -375,7 +375,7 @@
</span><span class="cx">     } }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ArrayMode::alreadyChecked(Graph&amp; graph, Node* node, AbstractValue&amp; value) const
</del><ins>+bool ArrayMode::alreadyChecked(Graph&amp; graph, Node* node, const AbstractValue&amp; value) const
</ins><span class="cx"> {
</span><span class="cx">     switch (type()) {
</span><span class="cx">     case Array::Generic:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGArrayModeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGArrayMode.h (183707 => 183708)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGArrayMode.h        2015-05-02 01:44:54 UTC (rev 183707)
+++ trunk/Source/JavaScriptCore/dfg/DFGArrayMode.h        2015-05-02 01:59:46 UTC (rev 183708)
</span><span class="lines">@@ -223,7 +223,7 @@
</span><span class="cx">     
</span><span class="cx">     ArrayMode refine(Graph&amp;, Node*, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const;
</span><span class="cx">     
</span><del>-    bool alreadyChecked(Graph&amp;, Node*, AbstractValue&amp;) const;
</del><ins>+    bool alreadyChecked(Graph&amp;, Node*, const AbstractValue&amp;) const;
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     
</span><span class="lines">@@ -469,7 +469,7 @@
</span><span class="cx">         return arrayMode1 | arrayMode2;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool alreadyChecked(Graph&amp;, Node*, AbstractValue&amp;, IndexingType shape) const;
</del><ins>+    bool alreadyChecked(Graph&amp;, Node*, const AbstractValue&amp;, IndexingType shape) const;
</ins><span class="cx">     
</span><span class="cx">     union {
</span><span class="cx">         struct {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (183707 => 183708)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-05-02 01:44:54 UTC (rev 183707)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-05-02 01:59:46 UTC (rev 183708)
</span><span class="lines">@@ -1067,7 +1067,9 @@
</span><span class="cx">             LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;BooleanToNumber continuation&quot;));
</span><span class="cx">             
</span><span class="cx">             ValueFromBlock notBooleanResult = m_out.anchor(value);
</span><del>-            m_out.branch(isBoolean(value), unsure(booleanCase), unsure(continuation));
</del><ins>+            m_out.branch(
+                isBoolean(value, provenType(m_node-&gt;child1())),
+                unsure(booleanCase), unsure(continuation));
</ins><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
</span><span class="cx">             ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
</span><span class="lines">@@ -1174,7 +1176,8 @@
</span><span class="cx">         LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, (&quot;ToThis slow case&quot;));
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;ToThis continuation&quot;));
</span><span class="cx">         
</span><del>-        m_out.branch(isCell(value), usually(isCellCase), rarely(slowCase));
</del><ins>+        m_out.branch(
+            isCell(value, provenType(m_node-&gt;child1())), usually(isCellCase), rarely(slowCase));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
</span><span class="cx">         ValueFromBlock fastResult = m_out.anchor(value);
</span><span class="lines">@@ -1197,8 +1200,8 @@
</span><span class="cx">     void compileValueAdd()
</span><span class="cx">     {
</span><span class="cx">         J_JITOperation_EJJ operation;
</span><del>-        if (!(m_state.forNode(m_node-&gt;child1()).m_type &amp; SpecFullNumber)
-            &amp;&amp; !(m_state.forNode(m_node-&gt;child2()).m_type &amp; SpecFullNumber))
</del><ins>+        if (!(provenType(m_node-&gt;child1()) &amp; SpecFullNumber)
+            &amp;&amp; !(provenType(m_node-&gt;child2()) &amp; SpecFullNumber))
</ins><span class="cx">             operation = operationValueAddNotNumber;
</span><span class="cx">         else
</span><span class="cx">             operation = operationValueAdd;
</span><span class="lines">@@ -1258,8 +1261,8 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case Int52RepUse: {
</span><del>-            if (!m_state.forNode(m_node-&gt;child1()).couldBeType(SpecInt52)
-                &amp;&amp; !m_state.forNode(m_node-&gt;child2()).couldBeType(SpecInt52)) {
</del><ins>+            if (!abstractValue(m_node-&gt;child1()).couldBeType(SpecInt52)
+                &amp;&amp; !abstractValue(m_node-&gt;child2()).couldBeType(SpecInt52)) {
</ins><span class="cx">                 Int52Kind kind;
</span><span class="cx">                 LValue left = lowWhicheverInt52(m_node-&gt;child1(), kind);
</span><span class="cx">                 LValue right = lowInt52(m_node-&gt;child2(), kind);
</span><span class="lines">@@ -1719,7 +1722,7 @@
</span><span class="cx">             // If y is NaN, the result is NaN.
</span><span class="cx">             m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionExponentIsInfinity);
</span><span class="cx">             LValue exponentIsNaN;
</span><del>-            if (m_state.forNode(m_node-&gt;child2()).m_type &amp; SpecDoubleNaN)
</del><ins>+            if (provenType(m_node-&gt;child2()) &amp; SpecDoubleNaN)
</ins><span class="cx">                 exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
</span><span class="cx">             else
</span><span class="cx">                 exponentIsNaN = m_out.booleanFalse;
</span><span class="lines">@@ -1785,7 +1788,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case Int52RepUse: {
</span><del>-            if (!m_state.forNode(m_node-&gt;child1()).couldBeType(SpecInt52)) {
</del><ins>+            if (!abstractValue(m_node-&gt;child1()).couldBeType(SpecInt52)) {
</ins><span class="cx">                 Int52Kind kind;
</span><span class="cx">                 LValue value = lowWhicheverInt52(m_node-&gt;child1(), kind);
</span><span class="cx">                 LValue result = m_out.neg(value);
</span><span class="lines">@@ -2000,7 +2003,8 @@
</span><span class="cx">             LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, (&quot;GetById untyped not cell case&quot;));
</span><span class="cx">             LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;GetById untyped continuation&quot;));
</span><span class="cx">             
</span><del>-            m_out.branch(isCell(value), unsure(cellCase), unsure(notCellCase));
</del><ins>+            m_out.branch(
+                isCell(value, provenType(m_node-&gt;child1())), unsure(cellCase), unsure(notCellCase));
</ins><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
</span><span class="cx">             ValueFromBlock cellResult = m_out.anchor(getById(value));
</span><span class="lines">@@ -2096,7 +2100,7 @@
</span><span class="cx">         Edge edge = m_node-&gt;child1();
</span><span class="cx">         LValue cell = lowCell(edge);
</span><span class="cx">         
</span><del>-        if (m_node-&gt;arrayMode().alreadyChecked(m_graph, m_node, m_state.forNode(edge)))
</del><ins>+        if (m_node-&gt;arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge)))
</ins><span class="cx">             return;
</span><span class="cx">         
</span><span class="cx">         speculate(
</span><span class="lines">@@ -2555,7 +2559,7 @@
</span><span class="cx">                 TypedPointer elementPointer = m_out.baseIndex(
</span><span class="cx">                     m_node-&gt;arrayMode().type() == Array::Int32 ?
</span><span class="cx">                     m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
</span><del>-                    storage, m_out.zeroExtPtr(index), m_state.forNode(child2).m_value);
</del><ins>+                    storage, m_out.zeroExtPtr(index), provenValue(child2));
</ins><span class="cx">                 
</span><span class="cx">                 if (m_node-&gt;op() == PutByValAlias) {
</span><span class="cx">                     m_out.store64(value, elementPointer);
</span><span class="lines">@@ -2581,7 +2585,7 @@
</span><span class="cx">                 
</span><span class="cx">                 TypedPointer elementPointer = m_out.baseIndex(
</span><span class="cx">                     m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index),
</span><del>-                    m_state.forNode(child2).m_value);
</del><ins>+                    provenValue(child2));
</ins><span class="cx">                 
</span><span class="cx">                 if (m_node-&gt;op() == PutByValAlias) {
</span><span class="cx">                     m_out.storeDouble(value, elementPointer);
</span><span class="lines">@@ -3391,14 +3395,14 @@
</span><span class="cx">             if (m_node-&gt;child1().useKind() == CellUse)
</span><span class="cx">                 isCellPredicate = m_out.booleanTrue;
</span><span class="cx">             else
</span><del>-                isCellPredicate = this-&gt;isCell(value);
</del><ins>+                isCellPredicate = this-&gt;isCell(value, provenType(m_node-&gt;child1()));
</ins><span class="cx">             m_out.branch(isCellPredicate, unsure(isCell), unsure(notString));
</span><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(isCell, notString);
</span><span class="cx">             ValueFromBlock simpleResult = m_out.anchor(value);
</span><span class="cx">             LValue isStringPredicate;
</span><span class="cx">             if (m_node-&gt;child1()-&gt;prediction() &amp; SpecString) {
</span><del>-                isStringPredicate = isString(value);
</del><ins>+                isStringPredicate = isString(value, provenType(m_node-&gt;child1()));
</ins><span class="cx">             } else
</span><span class="cx">                 isStringPredicate = m_out.booleanFalse;
</span><span class="cx">             m_out.branch(isStringPredicate, unsure(continuation), unsure(notString));
</span><span class="lines">@@ -3434,11 +3438,14 @@
</span><span class="cx">         Vector&lt;ValueFromBlock, 3&gt; results;
</span><span class="cx">         
</span><span class="cx">         results.append(m_out.anchor(value));
</span><del>-        m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
</del><ins>+        m_out.branch(
+            isCell(value, provenType(m_node-&gt;child1())), unsure(isCellCase), unsure(continuation));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, isObjectCase);
</span><span class="cx">         results.append(m_out.anchor(value));
</span><del>-        m_out.branch(isObject(value), unsure(isObjectCase), unsure(continuation));
</del><ins>+        m_out.branch(
+            isObject(value, provenType(m_node-&gt;child1())),
+            unsure(isObjectCase), unsure(continuation));
</ins><span class="cx">         
</span><span class="cx">         m_out.appendTo(isObjectCase, continuation);
</span><span class="cx">         results.append(m_out.anchor(vmCall(
</span><span class="lines">@@ -3554,7 +3561,7 @@
</span><span class="cx">         ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt(
</span><span class="cx">             m_out.load8(m_out.baseIndex(
</span><span class="cx">                 m_heaps.characters8, storage, m_out.zeroExtPtr(index),
</span><del>-                m_state.forNode(m_node-&gt;child2()).m_value)),
</del><ins>+                provenValue(m_node-&gt;child2()))),
</ins><span class="cx">             m_out.int32));
</span><span class="cx">         m_out.jump(bitsContinuation);
</span><span class="cx">             
</span><span class="lines">@@ -3563,7 +3570,7 @@
</span><span class="cx">         ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt(
</span><span class="cx">             m_out.load16(m_out.baseIndex(
</span><span class="cx">                 m_heaps.characters16, storage, m_out.zeroExtPtr(index),
</span><del>-                m_state.forNode(m_node-&gt;child2()).m_value)),
</del><ins>+                provenValue(m_node-&gt;child2()))),
</ins><span class="cx">             m_out.int32));
</span><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.aboveOrEqual(char16Bit.value(), m_out.constInt32(0x100)),
</span><span class="lines">@@ -3644,7 +3651,7 @@
</span><span class="cx">         ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt(
</span><span class="cx">             m_out.load8(m_out.baseIndex(
</span><span class="cx">                 m_heaps.characters8, storage, m_out.zeroExtPtr(index),
</span><del>-                m_state.forNode(m_node-&gt;child2()).m_value)),
</del><ins>+                provenValue(m_node-&gt;child2()))),
</ins><span class="cx">             m_out.int32));
</span><span class="cx">         m_out.jump(continuation);
</span><span class="cx">             
</span><span class="lines">@@ -3653,7 +3660,7 @@
</span><span class="cx">         ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt(
</span><span class="cx">             m_out.load16(m_out.baseIndex(
</span><span class="cx">                 m_heaps.characters16, storage, m_out.zeroExtPtr(index),
</span><del>-                m_state.forNode(m_node-&gt;child2()).m_value)),
</del><ins>+                provenValue(m_node-&gt;child2()))),
</ins><span class="cx">             m_out.int32));
</span><span class="cx">         m_out.jump(continuation);
</span><span class="cx">         
</span><span class="lines">@@ -4006,11 +4013,15 @@
</span><span class="cx">             LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;CompareStrictEq StringIdent to NotStringVar continuation&quot;));
</span><span class="cx">             
</span><span class="cx">             ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
</span><del>-            m_out.branch(isCell(rightValue), unsure(isCellCase), unsure(continuation));
</del><ins>+            m_out.branch(
+                isCell(rightValue, provenType(rightEdge)),
+                unsure(isCellCase), unsure(continuation));
</ins><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
</span><span class="cx">             ValueFromBlock notStringResult = m_out.anchor(m_out.booleanFalse);
</span><del>-            m_out.branch(isString(rightValue), unsure(isStringCase), unsure(continuation));
</del><ins>+            m_out.branch(
+                isString(rightValue, provenType(rightEdge)),
+                unsure(isStringCase), unsure(continuation));
</ins><span class="cx">             
</span><span class="cx">             m_out.appendTo(isStringCase, continuation);
</span><span class="cx">             LValue right = m_out.loadPtr(rightValue, m_heaps.JSString_value);
</span><span class="lines">@@ -4323,7 +4334,7 @@
</span><span class="cx">                 
</span><span class="cx">                 m_out.appendTo(isNotInt, isDouble);
</span><span class="cx">                 m_out.branch(
</span><del>-                    isCellOrMisc(boxedValue),
</del><ins>+                    isCellOrMisc(boxedValue, provenType(m_node-&gt;child1())),
</ins><span class="cx">                     usually(lowBlock(data-&gt;fallThrough.block)), rarely(isDouble));
</span><span class="cx">                 
</span><span class="cx">                 m_out.appendTo(isDouble, innerLastNext);
</span><span class="lines">@@ -4368,13 +4379,13 @@
</span><span class="cx">                 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, (&quot;Switch/SwitchChar is string&quot;));
</span><span class="cx">                 
</span><span class="cx">                 m_out.branch(
</span><del>-                    isNotCell(unboxedValue),
</del><ins>+                    isNotCell(unboxedValue, provenType(m_node-&gt;child1())),
</ins><span class="cx">                     unsure(lowBlock(data-&gt;fallThrough.block)), unsure(isCellCase));
</span><span class="cx">                 
</span><span class="cx">                 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
</span><span class="cx">                 LValue cellValue = unboxedValue;
</span><span class="cx">                 m_out.branch(
</span><del>-                    isNotString(cellValue),
</del><ins>+                    isNotString(cellValue, provenType(m_node-&gt;child1())),
</ins><span class="cx">                     unsure(lowBlock(data-&gt;fallThrough.block)), unsure(isStringCase));
</span><span class="cx">                 
</span><span class="cx">                 m_out.appendTo(isStringCase, lastNext);
</span><span class="lines">@@ -4466,12 +4477,13 @@
</span><span class="cx">                 LBasicBlock isStringBlock = FTL_NEW_BLOCK(m_out, (&quot;Switch/SwitchString Untyped string case&quot;));
</span><span class="cx">                 
</span><span class="cx">                 m_out.branch(
</span><del>-                    isCell(value), unsure(isCellBlock), unsure(lowBlock(data-&gt;fallThrough.block)));
</del><ins>+                    isCell(value, provenType(m_node-&gt;child1())),
+                    unsure(isCellBlock), unsure(lowBlock(data-&gt;fallThrough.block)));
</ins><span class="cx">                 
</span><span class="cx">                 LBasicBlock lastNext = m_out.appendTo(isCellBlock, isStringBlock);
</span><span class="cx">                 
</span><span class="cx">                 m_out.branch(
</span><del>-                    isString(value),
</del><ins>+                    isString(value, provenType(m_node-&gt;child1())),
</ins><span class="cx">                     unsure(isStringBlock), unsure(lowBlock(data-&gt;fallThrough.block)));
</span><span class="cx">                 
</span><span class="cx">                 m_out.appendTo(isStringBlock, lastNext);
</span><span class="lines">@@ -4499,7 +4511,8 @@
</span><span class="cx">                 LValue value = lowJSValue(m_node-&gt;child1());
</span><span class="cx">                 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, (&quot;Switch/SwitchCell cell case&quot;));
</span><span class="cx">                 m_out.branch(
</span><del>-                    isCell(value), unsure(cellCase), unsure(lowBlock(data-&gt;fallThrough.block)));
</del><ins>+                    isCell(value, provenType(m_node-&gt;child1())),
+                    unsure(cellCase), unsure(lowBlock(data-&gt;fallThrough.block)));
</ins><span class="cx">                 m_out.appendTo(cellCase);
</span><span class="cx">                 cell = value;
</span><span class="cx">                 break;
</span><span class="lines">@@ -4562,12 +4575,12 @@
</span><span class="cx">     
</span><span class="cx">     void compileIsBoolean()
</span><span class="cx">     {
</span><del>-        setBoolean(isBoolean(lowJSValue(m_node-&gt;child1())));
</del><ins>+        setBoolean(isBoolean(lowJSValue(m_node-&gt;child1()), provenType(m_node-&gt;child1())));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileIsNumber()
</span><span class="cx">     {
</span><del>-        setBoolean(isNumber(lowJSValue(m_node-&gt;child1())));
</del><ins>+        setBoolean(isNumber(lowJSValue(m_node-&gt;child1()), provenType(m_node-&gt;child1())));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileIsString()
</span><span class="lines">@@ -4578,10 +4591,11 @@
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;IsString continuation&quot;));
</span><span class="cx">         
</span><span class="cx">         ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
</span><del>-        m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
</del><ins>+        m_out.branch(
+            isCell(value, provenType(m_node-&gt;child1())), unsure(isCellCase), unsure(continuation));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
</span><del>-        ValueFromBlock cellResult = m_out.anchor(isString(value));
</del><ins>+        ValueFromBlock cellResult = m_out.anchor(isString(value, provenType(m_node-&gt;child1())));
</ins><span class="cx">         m_out.jump(continuation);
</span><span class="cx">         
</span><span class="cx">         m_out.appendTo(continuation, lastNext);
</span><span class="lines">@@ -4596,10 +4610,11 @@
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;IsObject continuation&quot;));
</span><span class="cx"> 
</span><span class="cx">         ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
</span><del>-        m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
</del><ins>+        m_out.branch(
+            isCell(value, provenType(m_node-&gt;child1())), unsure(isCellCase), unsure(continuation));
</ins><span class="cx"> 
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
</span><del>-        ValueFromBlock cellResult = m_out.anchor(isObject(value));
</del><ins>+        ValueFromBlock cellResult = m_out.anchor(isObject(value, provenType(m_node-&gt;child1())));
</ins><span class="cx">         m_out.jump(continuation);
</span><span class="cx"> 
</span><span class="cx">         m_out.appendTo(continuation, lastNext);
</span><span class="lines">@@ -4674,7 +4689,7 @@
</span><span class="cx">         
</span><span class="cx">         LValue condition;
</span><span class="cx">         if (m_node-&gt;child1().useKind() == UntypedUse)
</span><del>-            condition = isCell(cell);
</del><ins>+            condition = isCell(cell, provenType(m_node-&gt;child1()));
</ins><span class="cx">         else
</span><span class="cx">             condition = m_out.booleanTrue;
</span><span class="cx">         
</span><span class="lines">@@ -4683,7 +4698,7 @@
</span><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, loop);
</span><span class="cx">         
</span><del>-        speculate(BadType, noValue(), 0, isNotObject(prototype));
</del><ins>+        speculate(BadType, noValue(), 0, isNotObject(prototype, provenType(m_node-&gt;child2())));
</ins><span class="cx">         
</span><span class="cx">         ValueFromBlock originalValue = m_out.anchor(cell);
</span><span class="cx">         m_out.jump(loop);
</span><span class="lines">@@ -5368,7 +5383,8 @@
</span><span class="cx">             m_out.jump(continuation);
</span><span class="cx">         } else {
</span><span class="cx">             m_out.appendTo(notIntCase, doubleCase);
</span><del>-            m_out.branch(isCellOrMisc(value), unsure(notNumberCase), unsure(doubleCase));
</del><ins>+            m_out.branch(
+                isCellOrMisc(value, provenType(edge)), unsure(notNumberCase), unsure(doubleCase));
</ins><span class="cx">             
</span><span class="cx">             m_out.appendTo(doubleCase, notNumberCase);
</span><span class="cx">             results.append(m_out.anchor(doubleToInt32(unboxDouble(value))));
</span><span class="lines">@@ -5534,7 +5550,7 @@
</span><span class="cx">     TypedPointer baseIndex(IndexedAbstractHeap&amp; heap, LValue storage, LValue index, Edge edge, ptrdiff_t offset = 0)
</span><span class="cx">     {
</span><span class="cx">         return m_out.baseIndex(
</span><del>-            heap, storage, m_out.zeroExtPtr(index), m_state.forNode(edge).m_value, offset);
</del><ins>+            heap, storage, m_out.zeroExtPtr(index), provenValue(edge), offset);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compare(
</span><span class="lines">@@ -5582,7 +5598,9 @@
</span><span class="cx">         LBasicBlock leftNotCellCase = FTL_NEW_BLOCK(m_out, (&quot;CompareEqObjectOrOtherToObject left not cell case&quot;));
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;CompareEqObjectOrOtherToObject continuation&quot;));
</span><span class="cx">         
</span><del>-        m_out.branch(isCell(leftValue), unsure(leftCellCase), unsure(leftNotCellCase));
</del><ins>+        m_out.branch(
+            isCell(leftValue, provenType(leftChild)),
+            unsure(leftCellCase), unsure(leftNotCellCase));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(leftCellCase, leftNotCellCase);
</span><span class="cx">         speculateTruthyObject(leftChild, leftValue, SpecObject | (~SpecCell));
</span><span class="lines">@@ -5871,8 +5889,7 @@
</span><span class="cx">     
</span><span class="cx">     LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode, LValue base)
</span><span class="cx">     {
</span><del>-        JSArrayBufferView* view = m_graph.tryGetFoldableView(
-            m_state.forNode(baseEdge).m_value, arrayMode);
</del><ins>+        JSArrayBufferView* view = m_graph.tryGetFoldableView(provenValue(baseEdge), arrayMode);
</ins><span class="cx">         if (view)
</span><span class="cx">             return m_out.constInt32(view-&gt;length());
</span><span class="cx">         return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length);
</span><span class="lines">@@ -5909,7 +5926,9 @@
</span><span class="cx">             LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, (&quot;Boolify untyped fast case&quot;));
</span><span class="cx">             LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;Boolify untyped continuation&quot;));
</span><span class="cx">             
</span><del>-            m_out.branch(isNotBoolean(value), rarely(slowCase), usually(fastCase));
</del><ins>+            m_out.branch(
+                isNotBoolean(value, provenType(m_node-&gt;child1())),
+                rarely(slowCase), usually(fastCase));
</ins><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
</span><span class="cx">             ValueFromBlock fastResult = m_out.anchor(unboxBoolean(value));
</span><span class="lines">@@ -5951,7 +5970,7 @@
</span><span class="cx">         LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, (&quot;EqualNullOrUndefined primitive case&quot;));
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;EqualNullOrUndefined continuation&quot;));
</span><span class="cx">         
</span><del>-        m_out.branch(isNotCell(value), unsure(primitiveCase), unsure(cellCase));
</del><ins>+        m_out.branch(isNotCell(value, provenType(edge)), unsure(primitiveCase), unsure(cellCase));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
</span><span class="cx">         
</span><span class="lines">@@ -6003,7 +6022,7 @@
</span><span class="cx">             primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined));
</span><span class="cx">             break;
</span><span class="cx">         case EqualNullOrUndefined:
</span><del>-            primitiveResult = isOther(value);
</del><ins>+            primitiveResult = isOther(value, provenType(edge));
</ins><span class="cx">             break;
</span><span class="cx">         case SpeculateNullOrUndefined:
</span><span class="cx">             FTL_TYPE_CHECK(
</span><span class="lines">@@ -6471,7 +6490,7 @@
</span><span class="cx">             return result;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        DFG_ASSERT(m_graph, m_node, !(m_state.forNode(edge).m_type &amp; SpecInt32));
</del><ins>+        DFG_ASSERT(m_graph, m_node, !(provenType(edge) &amp; SpecInt32));
</ins><span class="cx">         terminate(Uncountable);
</span><span class="cx">         return m_out.int32Zero;
</span><span class="cx">     }
</span><span class="lines">@@ -6505,7 +6524,7 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        DFG_ASSERT(m_graph, m_node, !m_state.forNode(edge).m_type);
</del><ins>+        DFG_ASSERT(m_graph, m_node, !provenType(edge));
</ins><span class="cx">         terminate(Uncountable);
</span><span class="cx">         return m_out.int64Zero;
</span><span class="cx">     }
</span><span class="lines">@@ -6572,7 +6591,7 @@
</span><span class="cx">             return uncheckedValue;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        DFG_ASSERT(m_graph, m_node, !(m_state.forNode(edge).m_type &amp; SpecCell));
</del><ins>+        DFG_ASSERT(m_graph, m_node, !(provenType(edge) &amp; SpecCell));
</ins><span class="cx">         terminate(Uncountable);
</span><span class="cx">         return m_out.intPtrZero;
</span><span class="cx">     }
</span><span class="lines">@@ -6641,7 +6660,7 @@
</span><span class="cx">             return result;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        DFG_ASSERT(m_graph, m_node, !(m_state.forNode(edge).m_type &amp; SpecBoolean));
</del><ins>+        DFG_ASSERT(m_graph, m_node, !(provenType(edge) &amp; SpecBoolean));
</ins><span class="cx">         terminate(Uncountable);
</span><span class="cx">         return m_out.booleanFalse;
</span><span class="cx">     }
</span><span class="lines">@@ -6653,7 +6672,7 @@
</span><span class="cx">         LoweredNodeValue value = m_doubleValues.get(edge.node());
</span><span class="cx">         if (isValid(value))
</span><span class="cx">             return value.value();
</span><del>-        DFG_ASSERT(m_graph, m_node, !m_state.forNode(edge).m_type);
</del><ins>+        DFG_ASSERT(m_graph, m_node, !provenType(edge));
</ins><span class="cx">         terminate(Uncountable);
</span><span class="cx">         return m_out.doubleZero;
</span><span class="cx">     }
</span><span class="lines">@@ -6765,12 +6784,16 @@
</span><span class="cx">         return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isCellOrMisc(LValue jsValue)
</del><ins>+    LValue isCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, SpecCell | SpecMisc))
+            return proven;
</ins><span class="cx">         return m_out.testIsZero64(jsValue, m_tagTypeNumber);
</span><span class="cx">     }
</span><del>-    LValue isNotCellOrMisc(LValue jsValue)
</del><ins>+    LValue isNotCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, ~(SpecCell | SpecMisc)))
+            return proven;
</ins><span class="cx">         return m_out.testNonZero64(jsValue, m_tagTypeNumber);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -6864,43 +6887,59 @@
</span><span class="cx">         return possibleResult;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isNumber(LValue jsValue)
</del><ins>+    LValue isNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, SpecFullNumber))
+            return proven;
</ins><span class="cx">         return isNotCellOrMisc(jsValue);
</span><span class="cx">     }
</span><del>-    LValue isNotNumber(LValue jsValue)
</del><ins>+    LValue isNotNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, ~SpecFullNumber))
+            return proven;
</ins><span class="cx">         return isCellOrMisc(jsValue);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isNotCell(LValue jsValue)
</del><ins>+    LValue isNotCell(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, ~SpecCell))
+            return proven;
</ins><span class="cx">         return m_out.testNonZero64(jsValue, m_tagMask);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isCell(LValue jsValue)
</del><ins>+    LValue isCell(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, SpecCell))
+            return proven;
</ins><span class="cx">         return m_out.testIsZero64(jsValue, m_tagMask);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isNotMisc(LValue value)
</del><ins>+    LValue isNotMisc(LValue value, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, ~SpecMisc))
+            return proven;
</ins><span class="cx">         return m_out.above(value, m_out.constInt64(TagBitTypeOther | TagBitBool | TagBitUndefined));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isMisc(LValue value)
</del><ins>+    LValue isMisc(LValue value, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, SpecMisc))
+            return proven;
</ins><span class="cx">         return m_out.bitNot(isNotMisc(value));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isNotBoolean(LValue jsValue)
</del><ins>+    LValue isNotBoolean(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, ~SpecBoolean))
+            return proven;
</ins><span class="cx">         return m_out.testNonZero64(
</span><span class="cx">             m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)),
</span><span class="cx">             m_out.constInt64(~1));
</span><span class="cx">     }
</span><del>-    LValue isBoolean(LValue jsValue)
</del><ins>+    LValue isBoolean(LValue jsValue, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, SpecBoolean))
+            return proven;
</ins><span class="cx">         return m_out.bitNot(isNotBoolean(jsValue));
</span><span class="cx">     }
</span><span class="cx">     LValue unboxBoolean(LValue jsValue)
</span><span class="lines">@@ -6915,18 +6954,31 @@
</span><span class="cx">             value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isNotOther(LValue value)
</del><ins>+    LValue isNotOther(LValue value, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, ~SpecOther))
+            return proven;
</ins><span class="cx">         return m_out.notEqual(
</span><span class="cx">             m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
</span><span class="cx">             m_out.constInt64(ValueNull));
</span><span class="cx">     }
</span><del>-    LValue isOther(LValue value)
</del><ins>+    LValue isOther(LValue value, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type, SpecOther))
+            return proven;
</ins><span class="cx">         return m_out.equal(
</span><span class="cx">             m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
</span><span class="cx">             m_out.constInt64(ValueNull));
</span><span class="cx">     }
</span><ins>+    
+    LValue isProvenValue(SpeculatedType provenType, SpeculatedType wantedType)
+    {
+        if (!(provenType &amp; ~wantedType))
+            return m_out.booleanTrue;
+        if (!(provenType &amp; wantedType))
+            return m_out.booleanFalse;
+        return nullptr;
+    }
</ins><span class="cx"> 
</span><span class="cx">     void speculate(Edge edge)
</span><span class="cx">     {
</span><span class="lines">@@ -7027,29 +7079,37 @@
</span><span class="cx">         jsValueToStrictInt52(edge, lowJSValue(edge, ManualOperandSpeculation));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isObject(LValue cell)
</del><ins>+    LValue isObject(LValue cell, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type &amp; SpecCell, SpecObject))
+            return proven;
</ins><span class="cx">         return m_out.aboveOrEqual(
</span><span class="cx">             m_out.load8(cell, m_heaps.JSCell_typeInfoType),
</span><span class="cx">             m_out.constInt8(ObjectType));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue isNotObject(LValue cell)
</del><ins>+    LValue isNotObject(LValue cell, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type &amp; SpecCell, ~SpecObject))
+            return proven;
</ins><span class="cx">         return m_out.below(
</span><span class="cx">             m_out.load8(cell, m_heaps.JSCell_typeInfoType),
</span><span class="cx">             m_out.constInt8(ObjectType));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue isNotString(LValue cell)
</del><ins>+    LValue isNotString(LValue cell, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type &amp; SpecCell, ~SpecString))
+            return proven;
</ins><span class="cx">         return m_out.notEqual(
</span><span class="cx">             m_out.load32(cell, m_heaps.JSCell_structureID),
</span><span class="cx">             m_out.constInt32(vm().stringStructure-&gt;id()));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isString(LValue cell)
</del><ins>+    LValue isString(LValue cell, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><ins>+        if (LValue proven = isProvenValue(type &amp; SpecCell, SpecString))
+            return proven;
</ins><span class="cx">         return m_out.equal(
</span><span class="cx">             m_out.load32(cell, m_heaps.JSCell_structureID),
</span><span class="cx">             m_out.constInt32(vm().stringStructure-&gt;id()));
</span><span class="lines">@@ -7105,8 +7165,18 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    LValue isFunction(LValue cell) { return isType(cell, JSFunctionType); }
-    LValue isNotFunction(LValue cell) { return isNotType(cell, JSFunctionType); }
</del><ins>+    LValue isFunction(LValue cell, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type &amp; SpecCell, SpecFunction))
+            return proven;
+        return isType(cell, JSFunctionType);
+    }
+    LValue isNotFunction(LValue cell, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type &amp; SpecCell, ~SpecFunction))
+            return proven;
+        return isNotType(cell, JSFunctionType);
+    }
</ins><span class="cx">     
</span><span class="cx">     LValue isType(LValue cell, JSType type)
</span><span class="cx">     {
</span><span class="lines">@@ -7151,7 +7221,7 @@
</span><span class="cx">         LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, (&quot;speculateObjectOrOther primitive case&quot;));
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;speculateObjectOrOther continuation&quot;));
</span><span class="cx">         
</span><del>-        m_out.branch(isNotCell(value), unsure(primitiveCase), unsure(cellCase));
</del><ins>+        m_out.branch(isNotCell(value, provenType(edge)), unsure(primitiveCase), unsure(cellCase));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
</span><span class="cx">         
</span><span class="lines">@@ -7251,7 +7321,7 @@
</span><span class="cx">         Structure* stringObjectStructure =
</span><span class="cx">             m_graph.globalObjectFor(m_node-&gt;origin.semantic)-&gt;stringObjectStructure();
</span><span class="cx">         
</span><del>-        if (m_state.forNode(edge).m_structure.isSubsetOf(StructureSet(stringObjectStructure)))
</del><ins>+        if (abstractStructure(edge).isSubsetOf(StructureSet(stringObjectStructure)))
</ins><span class="cx">             return;
</span><span class="cx">         
</span><span class="cx">         speculate(
</span><span class="lines">@@ -7314,10 +7384,10 @@
</span><span class="cx">         LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, (&quot;Speculate NotStringVar is string case&quot;));
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;Speculate NotStringVar continuation&quot;));
</span><span class="cx">         
</span><del>-        m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
</del><ins>+        m_out.branch(isCell(value, provenType(edge)), unsure(isCellCase), unsure(continuation));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
</span><del>-        m_out.branch(isString(value), unsure(isStringCase), unsure(continuation));
</del><ins>+        m_out.branch(isString(value, provenType(edge)), unsure(isStringCase), unsure(continuation));
</ins><span class="cx">         
</span><span class="cx">         m_out.appendTo(isStringCase, continuation);
</span><span class="cx">         speculateStringIdent(edge, value, m_out.loadPtr(value, m_heaps.JSString_value));
</span><span class="lines">@@ -7860,6 +7930,42 @@
</span><span class="cx">         return addressFor(operand, TagOffset);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    AbstractValue abstractValue(Node* node)
+    {
+        return m_state.forNode(node);
+    }
+    AbstractValue abstractValue(Edge edge)
+    {
+        return abstractValue(edge.node());
+    }
+    
+    SpeculatedType provenType(Node* node)
+    {
+        return abstractValue(node).m_type;
+    }
+    SpeculatedType provenType(Edge edge)
+    {
+        return provenType(edge.node());
+    }
+    
+    JSValue provenValue(Node* node)
+    {
+        return abstractValue(node).m_value;
+    }
+    JSValue provenValue(Edge edge)
+    {
+        return provenValue(edge.node());
+    }
+    
+    StructureAbstractValue abstractStructure(Node* node)
+    {
+        return abstractValue(node).m_structure;
+    }
+    StructureAbstractValue abstractStructure(Edge edge)
+    {
+        return abstractStructure(edge.node());
+    }
+    
</ins><span class="cx">     void crash()
</span><span class="cx">     {
</span><span class="cx">         crash(m_highBlock-&gt;index, m_node-&gt;index());
</span></span></pre>
</div>
</div>

</body>
</html>