<!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>[153208] 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/153208">153208</a></dd>
<dt>Author</dt> <dd>oliver@apple.com</dd>
<dt>Date</dt> <dd>2013-07-24 21:02:00 -0700 (Wed, 24 Jul 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>fourthTier: Clean up AbstractValue
https://bugs.webkit.org/show_bug.cgi?id=117217

Reviewed by Oliver Hunt.

This started as an attempt to make it so that when AbstractValue becomes empty,
its m_type always becomes SpecNone. I wanted this to happen naturally. That turns
out to be basically impossible, since AbstractValue is a set that is dynamically
computed from the intersection of several internal sets: so the value becomes
empty when any of the sets go empty. It's OK if we're imprecise here because it's
always safe for the AbstractValue to seem to overapproximate the set of values
that we see. So I mostly gave up on cleaning up that aspect of AbstractValue. But
while trying to make this happen, I encountered two bugs:

- filterValueByType() ignores the case when m_type contravenes m_value. Namely,
  we might filter the AbstractValue against a SpeculatedType leading to m_value
  becoming inconsistent with the new m_type. This change fixes that case. This
  wasn't a symptomatic bug but it was a silly oversight.

- filterFuturePossibleStructure() was never right. The one call to this method,
  in filter(Graph&amp;, const StructureSet&amp;), assumed that the previous notions of
  what structures the value could have in the future were still relevant. This
  could lead to a bug where we:

  1) CheckStructure(@foo, S1)

     Where S1 has a valid watchpoint. Now @foo's abstract value will have current
     and future structure = S1.

  2) Clobber the world.

     Now @foo's abstract value will have current structure = TOP, and future
     possible structure = S1.

  3) CheckStructure(@foo, S2)

     Now @foo's abstract value will have current structure = S2 and future
     possible structure = S1 intersect S2 = BOTTOM.

  Now we will think that any subsequent watchpoint on @foo is valid because the
  value is effectively BOTTOM. That would only be correct if we had actually set
  a watchpoint on S1. If we had done so, then (3) would only pass (i.e. @foo
  would only have structure S2) if S1's watchpoint fired, in which case (3)
  wouldn't have been reachable. But we didn't actually set a watchpoint on S1:
  we just observed that we *could* have set the watchpoint. Hence future possible
  structure should only be set to either the known structure at compile-time, or
  it should be the structure we just checked; in both cases it should only be set
  if the structure is watchable.

Then, in addition to all of this, I changed AbstractValue's filtering methods to
call clear() if the AbstractValue is effectively clear. This is just meant to
simplify the recognition of truly empty AbstractValues, but doesn't actually have
any other implications.

* bytecode/StructureSet.h:
(JSC::StructureSet::dump):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::filter):
(DFG):
(JSC::DFG::AbstractValue::filterArrayModes):
(JSC::DFG::AbstractValue::filterValueByType):
(JSC::DFG::AbstractValue::filterArrayModesByType):
(JSC::DFG::AbstractValue::shouldBeClear):
(JSC::DFG::AbstractValue::normalizeClarity):
(JSC::DFG::AbstractValue::checkConsistency):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::isClear):
(AbstractValue):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeStructureSeth">trunk/Source/JavaScriptCore/bytecode/StructureSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractValuecpp">trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractValueh">trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (153207 => 153208)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2013-07-25 04:01:59 UTC (rev 153207)
+++ trunk/Source/JavaScriptCore/ChangeLog        2013-07-25 04:02:00 UTC (rev 153208)
</span><span class="lines">@@ -1,3 +1,81 @@
</span><ins>+2013-06-05  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Unreviewed, fix release build.
+
+        * interpreter/Interpreter.cpp:
+        * jit/JITStubs.cpp:
+
+2013-06-04  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        fourthTier: Clean up AbstractValue
+        https://bugs.webkit.org/show_bug.cgi?id=117217
+
+        Reviewed by Oliver Hunt.
+        
+        This started as an attempt to make it so that when AbstractValue becomes empty,
+        its m_type always becomes SpecNone. I wanted this to happen naturally. That turns
+        out to be basically impossible, since AbstractValue is a set that is dynamically
+        computed from the intersection of several internal sets: so the value becomes
+        empty when any of the sets go empty. It's OK if we're imprecise here because it's
+        always safe for the AbstractValue to seem to overapproximate the set of values
+        that we see. So I mostly gave up on cleaning up that aspect of AbstractValue. But
+        while trying to make this happen, I encountered two bugs:
+        
+        - filterValueByType() ignores the case when m_type contravenes m_value. Namely,
+          we might filter the AbstractValue against a SpeculatedType leading to m_value
+          becoming inconsistent with the new m_type. This change fixes that case. This
+          wasn't a symptomatic bug but it was a silly oversight.
+        
+        - filterFuturePossibleStructure() was never right. The one call to this method,
+          in filter(Graph&amp;, const StructureSet&amp;), assumed that the previous notions of
+          what structures the value could have in the future were still relevant. This
+          could lead to a bug where we:
+          
+          1) CheckStructure(@foo, S1)
+          
+             Where S1 has a valid watchpoint. Now @foo's abstract value will have current
+             and future structure = S1.
+          
+          2) Clobber the world.
+          
+             Now @foo's abstract value will have current structure = TOP, and future
+             possible structure = S1.
+          
+          3) CheckStructure(@foo, S2)
+          
+             Now @foo's abstract value will have current structure = S2 and future
+             possible structure = S1 intersect S2 = BOTTOM.
+          
+          Now we will think that any subsequent watchpoint on @foo is valid because the
+          value is effectively BOTTOM. That would only be correct if we had actually set
+          a watchpoint on S1. If we had done so, then (3) would only pass (i.e. @foo
+          would only have structure S2) if S1's watchpoint fired, in which case (3)
+          wouldn't have been reachable. But we didn't actually set a watchpoint on S1:
+          we just observed that we *could* have set the watchpoint. Hence future possible
+          structure should only be set to either the known structure at compile-time, or
+          it should be the structure we just checked; in both cases it should only be set
+          if the structure is watchable.
+        
+        Then, in addition to all of this, I changed AbstractValue's filtering methods to
+        call clear() if the AbstractValue is effectively clear. This is just meant to
+        simplify the recognition of truly empty AbstractValues, but doesn't actually have
+        any other implications.
+
+        * bytecode/StructureSet.h:
+        (JSC::StructureSet::dump):
+        * dfg/DFGAbstractValue.cpp:
+        (JSC::DFG::AbstractValue::filter):
+        (DFG):
+        (JSC::DFG::AbstractValue::filterArrayModes):
+        (JSC::DFG::AbstractValue::filterValueByType):
+        (JSC::DFG::AbstractValue::filterArrayModesByType):
+        (JSC::DFG::AbstractValue::shouldBeClear):
+        (JSC::DFG::AbstractValue::normalizeClarity):
+        (JSC::DFG::AbstractValue::checkConsistency):
+        * dfg/DFGAbstractValue.h:
+        (JSC::DFG::AbstractValue::isClear):
+        (AbstractValue):
+
</ins><span class="cx"> 2013-06-04  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         The DFG JIT should populate frame bytecodeOffsets on OSR exit.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeStructureSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/StructureSet.h (153207 => 153208)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/StructureSet.h        2013-07-25 04:01:59 UTC (rev 153207)
+++ trunk/Source/JavaScriptCore/bytecode/StructureSet.h        2013-07-25 04:02:00 UTC (rev 153208)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include &quot;SpeculatedType.h&quot;
</span><span class="cx"> #include &quot;Structure.h&quot;
</span><span class="cx"> #include &lt;stdio.h&gt;
</span><ins>+#include &lt;wtf/CommaPrinter.h&gt;
</ins><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -161,15 +162,13 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void dump(FILE* out)
</del><ins>+    void dump(PrintStream&amp; out) const
</ins><span class="cx">     {
</span><del>-        fprintf(out, &quot;[&quot;);
-        for (size_t i = 0; i &lt; m_structures.size(); ++i) {
-            if (i)
-                fprintf(out, &quot;, &quot;);
-            fprintf(out, &quot;%p&quot;, m_structures[i]);
-        }
-        fprintf(out, &quot;]&quot;);
</del><ins>+        CommaPrinter comma;
+        out.print(&quot;[&quot;);
+        for (size_t i = 0; i &lt; m_structures.size(); ++i)
+            out.print(comma, RawPointer(m_structures[i]));
+        out.print(&quot;]&quot;);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (153207 => 153208)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp        2013-07-25 04:01:59 UTC (rev 153207)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp        2013-07-25 04:02:00 UTC (rev 153208)
</span><span class="lines">@@ -79,7 +79,7 @@
</span><span class="cx">     m_arrayModes = asArrayModes(structure-&gt;indexingType());
</span><span class="cx">     m_type = speculationFromStructure(structure);
</span><span class="cx">     m_value = JSValue();
</span><del>-        
</del><ins>+    
</ins><span class="cx">     checkConsistency();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -88,28 +88,58 @@
</span><span class="cx">     // FIXME: This could be optimized for the common case of m_type not
</span><span class="cx">     // having structures, array modes, or a specific value.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=109663
</span><ins>+    
</ins><span class="cx">     m_type &amp;= other.speculationFromStructures();
</span><span class="cx">     m_arrayModes &amp;= other.arrayModesFromStructures();
</span><span class="cx">     m_currentKnownStructure.filter(other);
</span><del>-    if (m_currentKnownStructure.isClear())
-        m_futurePossibleStructure.clear();
-    else if (m_currentKnownStructure.hasSingleton())
-        filterFuturePossibleStructure(graph, m_currentKnownStructure.singleton());
-        
</del><ins>+    
</ins><span class="cx">     // It's possible that prior to the above two statements we had (Foo, TOP), where
</span><span class="cx">     // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
</span><span class="cx">     // case, we will now have (None, [someStructure]). In general, we need to make
</span><span class="cx">     // sure that new information gleaned from the SpeculatedType needs to be fed back
</span><span class="cx">     // into the information gleaned from the StructureSet.
</span><span class="cx">     m_currentKnownStructure.filter(m_type);
</span><del>-    m_futurePossibleStructure.filter(m_type);
</del><ins>+    
+    if (m_currentKnownStructure.hasSingleton())
+        setFuturePossibleStructure(graph, m_currentKnownStructure.singleton());
</ins><span class="cx">         
</span><span class="cx">     filterArrayModesByType();
</span><span class="cx">     filterValueByType();
</span><del>-        
</del><ins>+    normalizeClarity();
+    
</ins><span class="cx">     checkConsistency();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AbstractValue::filterArrayModes(ArrayModes arrayModes)
+{
+    ASSERT(arrayModes);
+    
+    m_type &amp;= SpecCell;
+    m_arrayModes &amp;= arrayModes;
+    normalizeClarity();
+    
+    checkConsistency();
+}
+
+void AbstractValue::filter(SpeculatedType type)
+{
+    if (type == SpecTop)
+        return;
+    m_type &amp;= type;
+    
+    // It's possible that prior to this filter() call we had, say, (Final, TOP), and
+    // the passed type is Array. At this point we'll have (None, TOP). The best way
+    // to ensure that the structure filtering does the right thing is to filter on
+    // the new type (None) rather than the one passed (Array).
+    m_currentKnownStructure.filter(m_type);
+    m_futurePossibleStructure.filter(m_type);
+    filterArrayModesByType();
+    filterValueByType();
+    normalizeClarity();
+    
+    checkConsistency();
+}
+
</ins><span class="cx"> void AbstractValue::setFuturePossibleStructure(Graph&amp; graph, Structure* structure)
</span><span class="cx"> {
</span><span class="cx">     if (graph.watchpoints().isStillValid(structure-&gt;transitionWatchpointSet()))
</span><span class="lines">@@ -118,12 +148,78 @@
</span><span class="cx">         m_futurePossibleStructure.makeTop();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AbstractValue::filterFuturePossibleStructure(Graph&amp; graph, Structure* structure)
</del><ins>+void AbstractValue::filterValueByType()
</ins><span class="cx"> {
</span><del>-    if (graph.watchpoints().isStillValid(structure-&gt;transitionWatchpointSet()))
-        m_futurePossibleStructure.filter(StructureAbstractValue(structure));
</del><ins>+    // We could go further, and ensure that if the futurePossibleStructure contravenes
+    // the value, then we could clear both of those things. But that's unlikely to help
+    // in any realistic scenario, so we don't do it. Simpler is better.
+
+    if (!!m_type) {
+        // The type is still non-empty. It may be that the new type renders
+        // the value empty because it contravenes the constant value we had.
+        if (m_value &amp;&amp; !validateType(m_value))
+            clear();
+        return;
+    }
+    
+    // The type has been rendered empty. That means that the value must now be invalid,
+    // as well.
+    ASSERT(!m_value || !validateType(m_value));
+    m_value = JSValue();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AbstractValue::filterArrayModesByType()
+{
+    if (!(m_type &amp; SpecCell))
+        m_arrayModes = 0;
+    else if (!(m_type &amp; ~SpecArray))
+        m_arrayModes &amp;= ALL_ARRAY_ARRAY_MODES;
+    else if (!(m_type &amp; SpecArray))
+        m_arrayModes &amp;= ALL_NON_ARRAY_ARRAY_MODES;
+}
+
+bool AbstractValue::shouldBeClear() const
+{
+    if (m_type == SpecNone)
+        return true;
+    
+    if (!(m_type &amp; ~SpecCell)
+        &amp;&amp; (!m_arrayModes
+            || m_currentKnownStructure.isClear()))
+        return true;
+    
+    return false;
+}
+
+void AbstractValue::normalizeClarity()
+{
+    // It's useful to be able to quickly check if an abstract value is clear.
+    // This normalizes everything to make that easy.
+    
+    if (shouldBeClear())
+        clear();
+}
+
+void AbstractValue::checkConsistency() const
+{
+    if (!(m_type &amp; SpecCell)) {
+        ASSERT(m_currentKnownStructure.isClear());
+        ASSERT(m_futurePossibleStructure.isClear());
+        ASSERT(!m_arrayModes);
+    }
+    
+    if (isClear())
+        ASSERT(!m_value);
+    
+    if (!!m_value)
+        ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
+    
+    // Note that it's possible for a prediction like (Final, []). This really means that
+    // the value is bottom and that any code that uses the value is unreachable. But
+    // we don't want to get pedantic about this as it would only increase the computational
+    // complexity of the code.
+}
+
</ins><span class="cx"> void AbstractValue::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     out.print(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.h (153207 => 153208)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.h        2013-07-25 04:01:59 UTC (rev 153207)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.h        2013-07-25 04:02:00 UTC (rev 153208)
</span><span class="lines">@@ -57,13 +57,7 @@
</span><span class="cx">         checkConsistency();
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool isClear() const
-    {
-        bool result = m_type == SpecNone &amp;&amp; !m_arrayModes &amp;&amp; m_currentKnownStructure.isClear() &amp;&amp; m_futurePossibleStructure.isClear();
-        if (result)
-            ASSERT(!m_value);
-        return result;
-    }
</del><ins>+    bool isClear() const { return m_type == SpecNone; }
</ins><span class="cx">     
</span><span class="cx">     void makeTop()
</span><span class="cx">     {
</span><span class="lines">@@ -190,36 +184,9 @@
</span><span class="cx">     
</span><span class="cx">     void filter(Graph&amp;, const StructureSet&amp;);
</span><span class="cx">     
</span><del>-    void filterArrayModes(ArrayModes arrayModes)
-    {
-        ASSERT(arrayModes);
-        
-        m_type &amp;= SpecCell;
-        m_arrayModes &amp;= arrayModes;
-        
-        // I could do more fancy filtering here. But it probably won't make any difference.
-        
-        checkConsistency();
-    }
</del><ins>+    void filterArrayModes(ArrayModes arrayModes);
</ins><span class="cx">     
</span><del>-    void filter(SpeculatedType type)
-    {
-        if (type == SpecTop)
-            return;
-        m_type &amp;= type;
-        
-        // It's possible that prior to this filter() call we had, say, (Final, TOP), and
-        // the passed type is Array. At this point we'll have (None, TOP). The best way
-        // to ensure that the structure filtering does the right thing is to filter on
-        // the new type (None) rather than the one passed (Array).
-        m_currentKnownStructure.filter(m_type);
-        m_futurePossibleStructure.filter(m_type);
-        
-        filterArrayModesByType();
-        filterValueByType();
-        
-        checkConsistency();
-    }
</del><ins>+    void filter(SpeculatedType type);
</ins><span class="cx">     
</span><span class="cx">     void filterByValue(JSValue value)
</span><span class="cx">     {
</span><span class="lines">@@ -280,25 +247,7 @@
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void checkConsistency() const
-    {
-        if (!(m_type &amp; SpecCell)) {
-            ASSERT(m_currentKnownStructure.isClear());
-            ASSERT(m_futurePossibleStructure.isClear());
-            ASSERT(!m_arrayModes);
-        }
-        
-        if (isClear())
-            ASSERT(!m_value);
-        
-        if (!!m_value)
-            ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
-        
-        // Note that it's possible for a prediction like (Final, []). This really means that
-        // the value is bottom and that any code that uses the value is unreachable. But
-        // we don't want to get pedantic about this as it would only increase the computational
-        // complexity of the code.
-    }
</del><ins>+    void checkConsistency() const;
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     
</span><span class="lines">@@ -314,7 +263,7 @@
</span><span class="cx">     //    y = x.f;
</span><span class="cx">     //
</span><span class="cx">     //    Where x will later have a new property added to it, 'g'. Because of the
</span><del>-    //    known but not-yet-executed property addition, x's currently structure will
</del><ins>+    //    known but not-yet-executed property addition, x's current structure will
</ins><span class="cx">     //    not be watchpointable; hence we have no way of statically bounding the set
</span><span class="cx">     //    of possible structures that x may have if a clobbering event happens. So,
</span><span class="cx">     //    x's m_currentKnownStructure will be whatever structure we check to get
</span><span class="lines">@@ -410,45 +359,12 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void setFuturePossibleStructure(Graph&amp;, Structure* structure);
</span><del>-    void filterFuturePossibleStructure(Graph&amp;, Structure* structure);
</del><span class="cx"> 
</span><del>-    // We could go further, and ensure that if the futurePossibleStructure contravenes
-    // the value, then we could clear both of those things. But that's unlikely to help
-    // in any realistic scenario, so we don't do it. Simpler is better.
-    void filterValueByType()
-    {
-        if (!!m_type) {
-            // The type is still non-empty. This implies that regardless of what filtering
-            // was done, we either didn't have a value to begin with, or that value is still
-            // valid.
-            ASSERT(!m_value || validateType(m_value));
-            return;
-        }
-        
-        // The type has been rendered empty. That means that the value must now be invalid,
-        // as well.
-        ASSERT(!m_value || !validateType(m_value));
-        m_value = JSValue();
-    }
</del><ins>+    void filterValueByType();
+    void filterArrayModesByType();
</ins><span class="cx">     
</span><del>-    void filterArrayModesByType()
-    {
-        if (!(m_type &amp; SpecCell))
-            m_arrayModes = 0;
-        else if (!(m_type &amp; ~SpecArray))
-            m_arrayModes &amp;= ALL_ARRAY_ARRAY_MODES;
-
-        // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
-        // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
-        // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
-        // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
-        // type system they are arrays (since they expose the magical length
-        // property and are otherwise allocated using array allocation). Hence the
-        // following would be wrong:
-        //
-        // if (!(m_type &amp; SpecArray))
-        //    m_arrayModes &amp;= ALL_NON_ARRAY_ARRAY_MODES;
-    }
</del><ins>+    bool shouldBeClear() const;
+    void normalizeClarity();
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre>
</div>
</div>

</body>
</html>