<!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>[202502] 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/202502">202502</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-06-27 11:35:09 -0700 (Mon, 27 Jun 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3 should not use Nops when deleting unreachable code
https://bugs.webkit.org/show_bug.cgi?id=159120
rdar://problem/26500743

Reviewed by Michael Saboff.
        
Prior to this change, transformations that obviated the need for some value could choose
from these ways to kill it:
        
- replaceWithIdentity() if we're replacing with another value.
- replaceWithNop() if the type is Void or if we know that we'll fix any users of this
  value.
- deleteValue() if the code is unreachable.
        
The bug here is that reduceStrength() was being clever about how to get rid of a value.
reduceStrength() may find a Check that must always exit. The goal is to remove any code
dominated by the Check. But it would be awkward to eagerly delete all of the blocks
dominated by this one. So this code took a much simpler approach: it would
replaceWithNop() for all of the values in this block after the Check and it would replace
the terminal with Oops.
        
But this corrupts the IR in a subtle way: some of those values may have been non-Void but
now they are Nops so they are Void. reduceStrength() will not yet realize that the blocks
dominated by the one with the Check are unreachable, so it will run all sorts of
optimizations on those blocks. This could have probably manifested as many different kinds
of badness, but the way I found out about this issue was through a crash in
IntRange::top(Type) when inlined into ReduceStrength::rangeFor(). We'd die in a switch
statement over a child's type.
        
We could fix this by making rangeFor() tolerate Void. But I think that this would be
dangerous. There could easily be other places in reduceStrength() that assume that value's
children are non-Void. So, this change fixes the Check optimization and adds mechanisms to
prevent other optimizations from breaking the children-are-not-Void rule.
        
This introduces two high-level changes:
        
- It's no longer legal to replaceWithNop() if the value is not Void. This change alone
  would cause reduceStrength() to instacrash in its Check optimization. Almost all other
  uses of replaceWithNop() were already following this rule, so they were fine. One other
  place was using replaceWithNop() on non-Void values after arranging for them to no
  longer have any parents. That was changed to call replaceWithNopIgnoringType(), which
  doesn't have any type assertions.
        
- For reduceStrength() there is a new Value::replaceWithBottom() method that works with
  Void or non-Void and behaves like you would want replaceWithNop() to behave: if you know
  that the code is unreachable then it produces something that is guaranteed to be deleted
  by later optimizations, and if it's not unreachable, then it's guaranteed to be compiled
  to something harmless and cheap. This means replacing the value with an identity that
  points to a bottom constant (the 0 for whatever type we have), or just replacing it with
  Nop if it's Void.
        
This also adds a test case for the reason why we do this: we may have two blocks, where
the first block unconditionally exits while dominating the second block. The second block
references values in the part of the first block that is unreachable. In trunk, this test
would assert in ReduceStrength::rangeFor() because the CheckAdd in the second block would
reference a Nop in the first block.
        
This fixes a high volume crash in ReduceStrength::rangeFor(). This crash was very
confusing. Even though we were crashing at a RELEASE_ASSERT_NOT_REACHED() in a switch
statement in IntRange::top(Type), clang was merging that trap with the trap it used for
Vector OOB. The top of the stack in crash dumps looked like:
        
    JSC::B3::(anonymous namespace)::ReduceStrength::rangeFor(JSC::B3::Value*, unsigned int) + 4477 (Vector.h:655)
        
Where Vector.h:655 is:
        
    OverflowHandler::overflowed();

But this crash was not at Vector.h:655. It was at B3ReduceStrength.cpp:121. The two lines
are both traps, so they got merged despite differences in debug info. This bug would have
been so much easier to fix if I had the right line number.

* b3/B3BottomProvider.h: Added. This is a utility for creating bottom values.
(JSC::B3::BottomProvider::BottomProvider):
(JSC::B3::BottomProvider::operator()):
* b3/B3InsertionSet.cpp: Optimized adding bottom values a bit. We will no longer create pointless duplicates.
(JSC::B3::InsertionSet::insertBottom):
(JSC::B3::InsertionSet::execute):
(JSC::B3::InsertionSet::bottomForType):
* b3/B3InsertionSet.h:
* b3/B3MoveConstants.cpp: Use replaceWithNopIgnoringType() because we *know* that we can replaceWithNop even for non-Void.
* b3/B3Procedure.h:
* b3/B3ReduceStrength.cpp: Use replaceWithBottom().
* b3/B3ReduceStrength.h:
* b3/B3TypeMap.h: I figured if I wrote type-casing code like this once then I'd never want to write it again.
* b3/B3Value.cpp:
(JSC::B3::Value::replaceWithIdentity):
(JSC::B3::Value::replaceWithNop):
(JSC::B3::Value::replaceWithNopIgnoringType):
* b3/B3Value.h:
* b3/B3ValueInlines.h:
(JSC::B3::Value::replaceWithBottom): This is the new method of killing unreachable code.
(JSC::B3::Value::as):
* b3/testb3.cpp: Add new tests!
(JSC::B3::testLateRegister):
(JSC::B3::testReduceStrengthCheckBottomUseInAnotherBlock):
(JSC::B3::zero):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3InsertionSetcpp">trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3InsertionSeth">trunk/Source/JavaScriptCore/b3/B3InsertionSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3MoveConstantscpp">trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Procedureh">trunk/Source/JavaScriptCore/b3/B3Procedure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthh">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valuecpp">trunk/Source/JavaScriptCore/b3/B3Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ValueInlinesh">trunk/Source/JavaScriptCore/b3/B3ValueInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3B3BottomProviderh">trunk/Source/JavaScriptCore/b3/B3BottomProvider.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3TypeMaph">trunk/Source/JavaScriptCore/b3/B3TypeMap.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -1,3 +1,104 @@
</span><ins>+2016-06-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should not use Nops when deleting unreachable code
+        https://bugs.webkit.org/show_bug.cgi?id=159120
+        rdar://problem/26500743
+
+        Reviewed by Michael Saboff.
+        
+        Prior to this change, transformations that obviated the need for some value could choose
+        from these ways to kill it:
+        
+        - replaceWithIdentity() if we're replacing with another value.
+        - replaceWithNop() if the type is Void or if we know that we'll fix any users of this
+          value.
+        - deleteValue() if the code is unreachable.
+        
+        The bug here is that reduceStrength() was being clever about how to get rid of a value.
+        reduceStrength() may find a Check that must always exit. The goal is to remove any code
+        dominated by the Check. But it would be awkward to eagerly delete all of the blocks
+        dominated by this one. So this code took a much simpler approach: it would
+        replaceWithNop() for all of the values in this block after the Check and it would replace
+        the terminal with Oops.
+        
+        But this corrupts the IR in a subtle way: some of those values may have been non-Void but
+        now they are Nops so they are Void. reduceStrength() will not yet realize that the blocks
+        dominated by the one with the Check are unreachable, so it will run all sorts of
+        optimizations on those blocks. This could have probably manifested as many different kinds
+        of badness, but the way I found out about this issue was through a crash in
+        IntRange::top(Type) when inlined into ReduceStrength::rangeFor(). We'd die in a switch
+        statement over a child's type.
+        
+        We could fix this by making rangeFor() tolerate Void. But I think that this would be
+        dangerous. There could easily be other places in reduceStrength() that assume that value's
+        children are non-Void. So, this change fixes the Check optimization and adds mechanisms to
+        prevent other optimizations from breaking the children-are-not-Void rule.
+        
+        This introduces two high-level changes:
+        
+        - It's no longer legal to replaceWithNop() if the value is not Void. This change alone
+          would cause reduceStrength() to instacrash in its Check optimization. Almost all other
+          uses of replaceWithNop() were already following this rule, so they were fine. One other
+          place was using replaceWithNop() on non-Void values after arranging for them to no
+          longer have any parents. That was changed to call replaceWithNopIgnoringType(), which
+          doesn't have any type assertions.
+        
+        - For reduceStrength() there is a new Value::replaceWithBottom() method that works with
+          Void or non-Void and behaves like you would want replaceWithNop() to behave: if you know
+          that the code is unreachable then it produces something that is guaranteed to be deleted
+          by later optimizations, and if it's not unreachable, then it's guaranteed to be compiled
+          to something harmless and cheap. This means replacing the value with an identity that
+          points to a bottom constant (the 0 for whatever type we have), or just replacing it with
+          Nop if it's Void.
+        
+        This also adds a test case for the reason why we do this: we may have two blocks, where
+        the first block unconditionally exits while dominating the second block. The second block
+        references values in the part of the first block that is unreachable. In trunk, this test
+        would assert in ReduceStrength::rangeFor() because the CheckAdd in the second block would
+        reference a Nop in the first block.
+        
+        This fixes a high volume crash in ReduceStrength::rangeFor(). This crash was very
+        confusing. Even though we were crashing at a RELEASE_ASSERT_NOT_REACHED() in a switch
+        statement in IntRange::top(Type), clang was merging that trap with the trap it used for
+        Vector OOB. The top of the stack in crash dumps looked like:
+        
+            JSC::B3::(anonymous namespace)::ReduceStrength::rangeFor(JSC::B3::Value*, unsigned int) + 4477 (Vector.h:655)
+        
+        Where Vector.h:655 is:
+        
+            OverflowHandler::overflowed();
+
+        But this crash was not at Vector.h:655. It was at B3ReduceStrength.cpp:121. The two lines
+        are both traps, so they got merged despite differences in debug info. This bug would have
+        been so much easier to fix if I had the right line number.
+
+        * b3/B3BottomProvider.h: Added. This is a utility for creating bottom values.
+        (JSC::B3::BottomProvider::BottomProvider):
+        (JSC::B3::BottomProvider::operator()):
+        * b3/B3InsertionSet.cpp: Optimized adding bottom values a bit. We will no longer create pointless duplicates.
+        (JSC::B3::InsertionSet::insertBottom):
+        (JSC::B3::InsertionSet::execute):
+        (JSC::B3::InsertionSet::bottomForType):
+        * b3/B3InsertionSet.h:
+        * b3/B3MoveConstants.cpp: Use replaceWithNopIgnoringType() because we *know* that we can replaceWithNop even for non-Void.
+        * b3/B3Procedure.h:
+        * b3/B3ReduceStrength.cpp: Use replaceWithBottom().
+        * b3/B3ReduceStrength.h:
+        * b3/B3TypeMap.h: I figured if I wrote type-casing code like this once then I'd never want to write it again.
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::replaceWithIdentity):
+        (JSC::B3::Value::replaceWithNop):
+        (JSC::B3::Value::replaceWithNopIgnoringType):
+        * b3/B3Value.h:
+        * b3/B3ValueInlines.h:
+        (JSC::B3::Value::replaceWithBottom): This is the new method of killing unreachable code.
+        (JSC::B3::Value::as):
+        * b3/testb3.cpp: Add new tests!
+        (JSC::B3::testLateRegister):
+        (JSC::B3::testReduceStrengthCheckBottomUseInAnotherBlock):
+        (JSC::B3::zero):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2016-06-27  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION: Web Inspector: Text search broken in resources with &lt;CR&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -2004,6 +2004,8 @@
</span><span class="cx">                 DCF3D56B1CD29472003D5C65 /* LazyClassStructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */; };
</span><span class="cx">                 DCF3D56C1CD29475003D5C65 /* LazyProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5671CD29468003D5C65 /* LazyProperty.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 DCF3D56D1CD29476003D5C65 /* LazyPropertyInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5681CD29468003D5C65 /* LazyPropertyInlines.h */; };
</span><ins>+                DCFDFBD91D1F5D9B00FE3D72 /* B3BottomProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */; };
+                DCFDFBDA1D1F5D9E00FE3D72 /* B3TypeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */; };
</ins><span class="cx">                 DE26E9031CB5DD0500D2BE82 /* BuiltinExecutableCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = DE26E9021CB5DD0500D2BE82 /* BuiltinExecutableCreator.h */; };
</span><span class="cx">                 DE26E9071CB5DEFB00D2BE82 /* BuiltinExecutableCreator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE26E9061CB5DD9600D2BE82 /* BuiltinExecutableCreator.cpp */; };
</span><span class="cx">                 DE5A0A001BA3AC3E003D4424 /* IntrinsicEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */; };
</span><span class="lines">@@ -4223,6 +4225,8 @@
</span><span class="cx">                 DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyClassStructureInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DCF3D5671CD29468003D5C65 /* LazyProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyProperty.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DCF3D5681CD29468003D5C65 /* LazyPropertyInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyPropertyInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3BottomProvider.h; path = b3/B3BottomProvider.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3TypeMap.h; path = b3/B3TypeMap.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 DE26E9021CB5DD0500D2BE82 /* BuiltinExecutableCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BuiltinExecutableCreator.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DE26E9061CB5DD9600D2BE82 /* BuiltinExecutableCreator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BuiltinExecutableCreator.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntrinsicEmitter.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4671,6 +4675,7 @@
</span><span class="cx">                                 0F338E171BF286EA0013C88F /* B3BlockInsertionSet.cpp */,
</span><span class="cx">                                 0F338E181BF286EA0013C88F /* B3BlockInsertionSet.h */,
</span><span class="cx">                                 0FEC84BA1BDACDAC0080FF74 /* B3BlockWorklist.h */,
</span><ins>+                                DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */,
</ins><span class="cx">                                 0F6B8ADE1C4EFE1700969052 /* B3BreakCriticalEdges.cpp */,
</span><span class="cx">                                 0F6B8ADF1C4EFE1700969052 /* B3BreakCriticalEdges.h */,
</span><span class="cx">                                 0F338DF71BE96AA80013C88F /* B3CCallValue.cpp */,
</span><span class="lines">@@ -4789,6 +4794,7 @@
</span><span class="cx">                                 0F45703F1BE584CA0062A629 /* B3TimingScope.h */,
</span><span class="cx">                                 0FEC84F11BDACDAC0080FF74 /* B3Type.cpp */,
</span><span class="cx">                                 0FEC84F21BDACDAC0080FF74 /* B3Type.h */,
</span><ins>+                                DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */,
</ins><span class="cx">                                 0FEC84F31BDACDAC0080FF74 /* B3UpsilonValue.cpp */,
</span><span class="cx">                                 0FEC84F41BDACDAC0080FF74 /* B3UpsilonValue.h */,
</span><span class="cx">                                 0FEC84F51BDACDAC0080FF74 /* B3UseCounts.cpp */,
</span><span class="lines">@@ -7104,6 +7110,7 @@
</span><span class="cx">                                 99DA00A51BD5993100F4575C /* builtins_templates.py in Headers */,
</span><span class="cx">                                 41DEA1321B9F3163006D65DD /* BuiltinUtils.h in Headers */,
</span><span class="cx">                                 9E72940B190F0514001A91B5 /* BundlePath.h in Headers */,
</span><ins>+                                DCFDFBD91D1F5D9B00FE3D72 /* B3BottomProvider.h in Headers */,
</ins><span class="cx">                                 0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */,
</span><span class="cx">                                 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */,
</span><span class="cx">                                 C2FCAE1117A9C24E0034C735 /* BytecodeBasicBlock.h in Headers */,
</span><span class="lines">@@ -7390,6 +7397,7 @@
</span><span class="cx">                                 0F63943F15C75F19006A597C /* DFGTypeCheckHoistingPhase.h in Headers */,
</span><span class="cx">                                 0FBE0F7716C1DB120082C5E8 /* DFGUnificationPhase.h in Headers */,
</span><span class="cx">                                 0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */,
</span><ins>+                                DCFDFBDA1D1F5D9E00FE3D72 /* B3TypeMap.h in Headers */,
</ins><span class="cx">                                 0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */,
</span><span class="cx">                                 0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */,
</span><span class="cx">                                 0F0123331944EA1B00843A0C /* DFGValueStrength.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3BottomProviderh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/B3BottomProvider.h (0 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3BottomProvider.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/B3BottomProvider.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef B3BottomProvider_h
+#define B3BottomProvider_h
+
+#if ENABLE(B3_JIT)
+
+#include &quot;B3InsertionSet.h&quot;
+
+namespace JSC { namespace B3 {
+
+// This exists because we cannot convert values to constants in-place.
+// FIXME: https://bugs.webkit.org/show_bug.cgi?id=159119
+
+class BottomProvider {
+public:
+    BottomProvider(InsertionSet&amp; insertionSet, size_t index)
+        : m_insertionSet(&amp;insertionSet)
+        , m_index(index)
+    {
+    }
+    
+    Value* operator()(Origin origin, Type type) const
+    {
+        return m_insertionSet-&gt;insertBottom(m_index, origin, type);
+    }
+    
+private:
+    InsertionSet* m_insertionSet;
+    size_t m_index;
+};
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3BottomProvider_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3InsertionSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -47,7 +47,10 @@
</span><span class="cx"> 
</span><span class="cx"> Value* InsertionSet::insertBottom(size_t index, Origin origin, Type type)
</span><span class="cx"> {
</span><del>-    return insertValue(index, m_procedure.addBottom(origin, type));
</del><ins>+    Value*&amp; bottom = m_bottomForType[type];
+    if (!bottom)
+        bottom = insertValue(index, m_procedure.addBottom(origin, type));
+    return bottom;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Value* InsertionSet::insertBottom(size_t index, Value* likeValue)
</span><span class="lines">@@ -59,6 +62,7 @@
</span><span class="cx"> {
</span><span class="cx">     bubbleSort(m_insertions.begin(), m_insertions.end());
</span><span class="cx">     executeInsertions(block-&gt;m_values, m_insertions);
</span><ins>+    m_bottomForType = TypeMap&lt;Value*&gt;();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3InsertionSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3InsertionSet.h (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3InsertionSet.h        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3InsertionSet.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;B3Origin.h&quot;
</span><span class="cx"> #include &quot;B3Type.h&quot;
</span><ins>+#include &quot;B3TypeMap.h&quot;
</ins><span class="cx"> #include &lt;wtf/Insertion.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -77,6 +78,8 @@
</span><span class="cx"> private:
</span><span class="cx">     Procedure&amp; m_procedure;
</span><span class="cx">     Vector&lt;Insertion, 8&gt; m_insertions;
</span><ins>+
+    TypeMap&lt;Value*&gt; m_bottomForType;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MoveConstantscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -125,7 +125,7 @@
</span><span class="cx">                 if (valueForConstant.get(key) == value)
</span><span class="cx">                     value = m_proc.add&lt;Value&gt;(Nop, value-&gt;origin());
</span><span class="cx">                 else
</span><del>-                    value-&gt;replaceWithNop();
</del><ins>+                    value-&gt;replaceWithNopIgnoringType();
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Procedureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Procedure.h (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Procedure.h        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3Procedure.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx">     Value* addBoolConstant(Origin, TriState);
</span><span class="cx"> 
</span><span class="cx">     void resetValueOwners();
</span><del>-    void resetReachability();
</del><ins>+    JS_EXPORT_PRIVATE void resetReachability();
</ins><span class="cx"> 
</span><span class="cx">     // This destroys CFG analyses. If we ask for them again, we will recompute them. Usually you
</span><span class="cx">     // should call this anytime you call resetReachability().
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -1716,7 +1716,7 @@
</span><span class="cx"> 
</span><span class="cx">                 // Replace the rest of the block with an Oops.
</span><span class="cx">                 for (unsigned i = m_index + 1; i &lt; m_block-&gt;size() - 1; ++i)
</span><del>-                    m_block-&gt;at(i)-&gt;replaceWithNop();
</del><ins>+                    m_block-&gt;at(i)-&gt;replaceWithBottom(m_insertionSet, m_index);
</ins><span class="cx">                 m_block-&gt;last()-&gt;as&lt;ControlValue&gt;()-&gt;convertToOops();
</span><span class="cx">                 m_block-&gt;last()-&gt;setOrigin(checkValue-&gt;origin());
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.h (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.h        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 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">@@ -40,7 +40,7 @@
</span><span class="cx"> // add sophisticated optimizations to it. For that reason we have full CSE in a different phase, for
</span><span class="cx"> // example.
</span><span class="cx"> 
</span><del>-bool reduceStrength(Procedure&amp;);
</del><ins>+JS_EXPORT_PRIVATE bool reduceStrength(Procedure&amp;);
</ins><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3TypeMaph"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/B3TypeMap.h (0 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3TypeMap.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/B3TypeMap.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -0,0 +1,102 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef B3TypeMap_h
+#define B3TypeMap_h
+
+#if ENABLE(B3_JIT)
+
+#include &quot;B3Type.h&quot;
+#include &lt;wtf/PrintStream.h&gt;
+
+namespace JSC { namespace B3 {
+
+template&lt;typename T&gt;
+class TypeMap {
+public:
+    TypeMap()
+        : m_void()
+        , m_int32()
+        , m_int64()
+        , m_float()
+        , m_double()
+    {
+    }
+    
+    T&amp; at(Type type)
+    {
+        switch (type) {
+        case Void:
+            return m_void;
+        case Int32:
+            return m_int32;
+        case Int64:
+            return m_int64;
+        case Float:
+            return m_float;
+        case Double:
+            return m_double;
+        }
+    }
+    
+    const T&amp; at(Type type) const
+    {
+        return bitwise_cast&lt;TypeMap*&gt;(this)-&gt;at(type);
+    }
+    
+    T&amp; operator[](Type type)
+    {
+        return at(type);
+    }
+    
+    const T&amp; operator[](Type type) const
+    {
+        return at(type);
+    }
+    
+    void dump(PrintStream&amp; out) const
+    {
+        out.print(
+            &quot;{void = &quot;, m_void,
+            &quot;, int32 = &quot;, m_int32,
+            &quot;, int64 = &quot;, m_int64,
+            &quot;, float = &quot;, m_float,
+            &quot;, double = &quot;, m_double, &quot;}&quot;);
+    }
+    
+private:
+    T m_void;
+    T m_int32;
+    T m_int64;
+    T m_float;
+    T m_double;
+};
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3TypeMap_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;B3ArgumentRegValue.h&quot;
</span><ins>+#include &quot;B3BottomProvider.h&quot;
</ins><span class="cx"> #include &quot;B3CCallValue.h&quot;
</span><span class="cx"> #include &quot;B3ControlValue.h&quot;
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="lines">@@ -60,7 +61,7 @@
</span><span class="cx">     ASSERT(m_type == value-&gt;m_type);
</span><span class="cx"> 
</span><span class="cx">     if (m_type == Void) {
</span><del>-        replaceWithNop();
</del><ins>+        replaceWithNopIgnoringType();
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -79,8 +80,19 @@
</span><span class="cx">     this-&gt;m_index = index;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Value::replaceWithBottom(InsertionSet&amp; insertionSet, size_t index)
+{
+    replaceWithBottom(BottomProvider(insertionSet, index));
+}
+
</ins><span class="cx"> void Value::replaceWithNop()
</span><span class="cx"> {
</span><ins>+    RELEASE_ASSERT(m_type == Void);
+    replaceWithNopIgnoringType();
+}
+
+void Value::replaceWithNopIgnoringType()
+{
</ins><span class="cx">     unsigned index = m_index;
</span><span class="cx">     Origin origin = m_origin;
</span><span class="cx">     BasicBlock* owner = this-&gt;owner;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> 
</span><span class="cx"> class BasicBlock;
</span><span class="cx"> class CheckValue;
</span><ins>+class InsertionSet;
</ins><span class="cx"> class PhiChildren;
</span><span class="cx"> class Procedure;
</span><span class="cx"> 
</span><span class="lines">@@ -83,8 +84,30 @@
</span><span class="cx">     AdjacencyList&amp; children() { return m_children; } 
</span><span class="cx">     const AdjacencyList&amp; children() const { return m_children; }
</span><span class="cx"> 
</span><ins>+    // If you want to replace all uses of this value with a different value, then replace this
+    // value with Identity. Then do a pass of performSubstitution() on all of the values that use
+    // this one. Usually we do all of this in one pass in pre-order, which ensures that the
+    // X-&gt;replaceWithIdentity() calls happen before the performSubstitution() calls on X's users.
</ins><span class="cx">     void replaceWithIdentity(Value*);
</span><ins>+    
+    // It's often necessary to kill a value. It's tempting to replace the value with Nop or to
+    // just remove it. But unless you are sure that the value is Void, you will probably still
+    // have other values that use this one. Sure, you may kill those later, or you might not. This
+    // method lets you kill a value safely. It will replace Void values with Nop and non-Void
+    // values with Identities on bottom constants. For this reason, this takes a callback that is
+    // responsible for creating bottoms. There's a utility for this, see B3BottomProvider.h. You
+    // can also access that utility using replaceWithBottom(InsertionSet&amp;, size_t).
+    template&lt;typename BottomProvider&gt;
+    void replaceWithBottom(const BottomProvider&amp;);
+    
+    void replaceWithBottom(InsertionSet&amp;, size_t index);
+
+    // Use this if you want to kill a value and you are sure that the value is Void.
</ins><span class="cx">     void replaceWithNop();
</span><ins>+    
+    // Use this if you want to kill a value and you are sure that nobody is using it anymore.
+    void replaceWithNopIgnoringType();
+    
</ins><span class="cx">     void replaceWithPhi();
</span><span class="cx"> 
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueInlines.h (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueInlines.h        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/B3ValueInlines.h        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -41,6 +41,20 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 {
</span><span class="cx"> 
</span><ins>+template&lt;typename BottomProvider&gt;
+void Value::replaceWithBottom(const BottomProvider&amp; bottomProvider)
+{
+    if (m_type == Void) {
+        replaceWithNop();
+        return;
+    }
+    
+    if (isConstant())
+        return;
+    
+    replaceWithIdentity(bottomProvider(m_origin, m_type));
+}
+
</ins><span class="cx"> template&lt;typename T&gt;
</span><span class="cx"> T* Value::as()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (202501 => 202502)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-06-27 18:35:09 UTC (rev 202502)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include &quot;B3MathExtras.h&quot;
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><ins>+#include &quot;B3ReduceStrength.h&quot;
</ins><span class="cx"> #include &quot;B3SlotBaseValue.h&quot;
</span><span class="cx"> #include &quot;B3StackSlot.h&quot;
</span><span class="cx"> #include &quot;B3StackmapGenerationParams.h&quot;
</span><span class="lines">@@ -12050,6 +12051,39 @@
</span><span class="cx">     CHECK(invoke&lt;uint64_t&gt;(*code) == result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testReduceStrengthCheckBottomUseInAnotherBlock()
+{
+    Procedure proc;
+    
+    BasicBlock* one = proc.addBlock();
+    BasicBlock* two = proc.addBlock();
+    
+    CheckValue* check = one-&gt;appendNew&lt;CheckValue&gt;(
+        proc, Check, Origin(), one-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 1));
+    check-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp;) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+
+            jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    Value* arg = one-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    one-&gt;appendNew&lt;ControlValue&gt;(proc, Jump, Origin(), FrequentedBlock(two));
+    
+    check = two-&gt;appendNew&lt;CheckValue&gt;(
+        proc, CheckAdd, Origin(), arg,
+        two-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 1));
+    check-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp;, const StackmapGenerationParams&amp;) {
+            CHECK(!&quot;Should not execute&quot;);
+        });
+    two-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), check);
+    
+    proc.resetReachability();
+    reduceStrength(proc);
+}
+
</ins><span class="cx"> // Make sure the compiler does not try to optimize anything out.
</span><span class="cx"> NEVER_INLINE double zero()
</span><span class="cx"> {
</span><span class="lines">@@ -13449,11 +13483,10 @@
</span><span class="cx">     RUN(testLShiftSelf64());
</span><span class="cx"> 
</span><span class="cx">     RUN(testPatchpointDoubleRegs());
</span><del>-
</del><span class="cx">     RUN(testSpillDefSmallerThanUse());
</span><span class="cx">     RUN(testSpillUseLargerThanDef());
</span><del>-
</del><span class="cx">     RUN(testLateRegister());
</span><ins>+    RUN(testReduceStrengthCheckBottomUseInAnotherBlock());
</ins><span class="cx"> 
</span><span class="cx">     if (tasks.isEmpty())
</span><span class="cx">         usage();
</span></span></pre>
</div>
</div>

</body>
</html>