<!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>[203365] trunk/Source</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/203365">203365</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-07-18 12:51:45 -0700 (Mon, 18 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>RegisterSet should use a Bitmap instead of a BitVector so that it never allocates memory and is trivial to copy
https://bugs.webkit.org/show_bug.cgi?id=159863

Reviewed by Saam Barati.
        
Source/JavaScriptCore:

Switch RegisterSet set to Bitmap because Bitmap doesn't ever allocate memory and can be
assigned by memcpy. This should be a performance improvement for compiler code that does a
lot of things with RegisterSet. For example, it's one of the fundamental data structures in
Air. The previous use of BitVector meant that almost every operation on RegisterSet would
have a slow path call. On ARM64, it would mean memory allocation for any RegisterSet that
used all available registers.
        
This meant adding even more GPR/FPR reflection to the MacroAssembler API: we now have consts
called numGPRs and numFPRs. This is necessary to statically size the Bitmap in RegisterSet.
        
Here's the breakdown of sizes of RegisterSet on different CPUs:
        
x86-32: 8 bits (GPRs) + 8 bits (FPRs) + 1 bit (is deleted) = 1x uint32_t.
x86-64: 16 bits + 16 bits + 1 bit = 2x uint32_t.
ARMv7: 16 bits + 16 bits + 1 bit = 2x uint32_t.
ARM64: 32 bits + 32 bits + 1 bit = 3x uint32_t.

* assembler/MacroAssemblerARM.h:
* assembler/MacroAssemblerARM64.h:
* assembler/MacroAssemblerARMv7.h:
* assembler/MacroAssemblerX86.h:
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::scratchRegister):
* assembler/MacroAssemblerX86_64.h:
* jit/RegisterSet.h:
(JSC::RegisterSet::set):
(JSC::RegisterSet::get):
(JSC::RegisterSet::setAll):
(JSC::RegisterSet::merge):
(JSC::RegisterSet::filter):
(JSC::RegisterSet::exclude):
(JSC::RegisterSet::numberOfSetRegisters):
(JSC::RegisterSet::RegisterSet):
(JSC::RegisterSet::isEmptyValue):
(JSC::RegisterSet::isDeletedValue):
(JSC::RegisterSet::operator==):
(JSC::RegisterSet::operator!=):
(JSC::RegisterSet::hash):
(JSC::RegisterSet::forEach):
(JSC::RegisterSet::setMany):

Source/WTF:

Give Bitmap all of the power of BitVector (except for automatic resizing). This means a
variant of set() that takes a bool, and a bunch of helper methods (merge, filter, exclude,
forEachSetBit, ==, !=, and hash).

* wtf/Bitmap.h:
(WTF::WordType&gt;::set):
(WTF::WordType&gt;::testAndSet):
(WTF::WordType&gt;::isFull):
(WTF::WordType&gt;::merge):
(WTF::WordType&gt;::filter):
(WTF::WordType&gt;::exclude):
(WTF::WordType&gt;::forEachSetBit):
(WTF::=):
(WTF::WordType&gt;::hash):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARMh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegisterSeth">trunk/Source/JavaScriptCore/jit/RegisterSet.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfBitmaph">trunk/Source/WTF/wtf/Bitmap.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2016-07-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        RegisterSet should use a Bitmap instead of a BitVector so that it never allocates memory and is trivial to copy
+        https://bugs.webkit.org/show_bug.cgi?id=159863
+
+        Reviewed by Saam Barati.
+        
+        Switch RegisterSet set to Bitmap because Bitmap doesn't ever allocate memory and can be
+        assigned by memcpy. This should be a performance improvement for compiler code that does a
+        lot of things with RegisterSet. For example, it's one of the fundamental data structures in
+        Air. The previous use of BitVector meant that almost every operation on RegisterSet would
+        have a slow path call. On ARM64, it would mean memory allocation for any RegisterSet that
+        used all available registers.
+        
+        This meant adding even more GPR/FPR reflection to the MacroAssembler API: we now have consts
+        called numGPRs and numFPRs. This is necessary to statically size the Bitmap in RegisterSet.
+        
+        Here's the breakdown of sizes of RegisterSet on different CPUs:
+        
+        x86-32: 8 bits (GPRs) + 8 bits (FPRs) + 1 bit (is deleted) = 1x uint32_t.
+        x86-64: 16 bits + 16 bits + 1 bit = 2x uint32_t.
+        ARMv7: 16 bits + 16 bits + 1 bit = 2x uint32_t.
+        ARM64: 32 bits + 32 bits + 1 bit = 3x uint32_t.
+
+        * assembler/MacroAssemblerARM.h:
+        * assembler/MacroAssemblerARM64.h:
+        * assembler/MacroAssemblerARMv7.h:
+        * assembler/MacroAssemblerX86.h:
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::scratchRegister):
+        * assembler/MacroAssemblerX86_64.h:
+        * jit/RegisterSet.h:
+        (JSC::RegisterSet::set):
+        (JSC::RegisterSet::get):
+        (JSC::RegisterSet::setAll):
+        (JSC::RegisterSet::merge):
+        (JSC::RegisterSet::filter):
+        (JSC::RegisterSet::exclude):
+        (JSC::RegisterSet::numberOfSetRegisters):
+        (JSC::RegisterSet::RegisterSet):
+        (JSC::RegisterSet::isEmptyValue):
+        (JSC::RegisterSet::isDeletedValue):
+        (JSC::RegisterSet::operator==):
+        (JSC::RegisterSet::operator!=):
+        (JSC::RegisterSet::hash):
+        (JSC::RegisterSet::forEach):
+        (JSC::RegisterSet::setMany):
+
</ins><span class="cx"> 2016-07-15  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         DFG and FTL should support op_call_eval
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -40,6 +40,9 @@
</span><span class="cx">     static const int DoubleConditionBitSpecial = 0x10;
</span><span class="cx">     COMPILE_ASSERT(!(DoubleConditionBitSpecial &amp; DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes);
</span><span class="cx"> public:
</span><ins>+    static const unsigned numGPRs = 16;
+    static const unsigned numFPRs = 16;
+    
</ins><span class="cx">     typedef ARMRegisters::FPRegisterID FPRegisterID;
</span><span class="cx"> 
</span><span class="cx">     enum RelationalCondition {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -37,6 +37,9 @@
</span><span class="cx"> 
</span><span class="cx"> class MacroAssemblerARM64 : public AbstractMacroAssembler&lt;ARM64Assembler, MacroAssemblerARM64&gt; {
</span><span class="cx"> public:
</span><ins>+    static const unsigned numGPRs = 32;
+    static const unsigned numFPRs = 32;
+    
</ins><span class="cx">     static const RegisterID dataTempRegister = ARM64Registers::ip0;
</span><span class="cx">     static const RegisterID memoryTempRegister = ARM64Registers::ip1;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -42,6 +42,9 @@
</span><span class="cx">     inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
</span><span class="cx"> 
</span><span class="cx"> public:
</span><ins>+    static const unsigned numGPRs = 16;
+    static const unsigned numFPRs = 16;
+    
</ins><span class="cx">     MacroAssemblerARMv7()
</span><span class="cx">         : m_makeJumpPatchable(false)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -34,6 +34,9 @@
</span><span class="cx"> 
</span><span class="cx"> class MacroAssemblerX86 : public MacroAssemblerX86Common {
</span><span class="cx"> public:
</span><ins>+    static const unsigned numGPRs = 8;
+    static const unsigned numFPRs = 8;
+    
</ins><span class="cx">     static const Scale ScalePtr = TimesFour;
</span><span class="cx"> 
</span><span class="cx">     using MacroAssemblerX86Common::add32;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx">         return s_scratchRegister;
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><del>-
</del><ins>+    
</ins><span class="cx"> protected:
</span><span class="cx">     static const int DoubleConditionBitInvert = 0x10;
</span><span class="cx">     static const int DoubleConditionBitSpecial = 0x20;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -38,6 +38,9 @@
</span><span class="cx"> 
</span><span class="cx"> class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
</span><span class="cx"> public:
</span><ins>+    static const unsigned numGPRs = 16;
+    static const unsigned numFPRs = 16;
+    
</ins><span class="cx">     static const Scale ScalePtr = TimesEight;
</span><span class="cx"> 
</span><span class="cx">     using MacroAssemblerX86Common::add32;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> #include &quot;MacroAssembler.h&quot;
</span><span class="cx"> #include &quot;Reg.h&quot;
</span><span class="cx"> #include &quot;TempRegisterSet.h&quot;
</span><del>-#include &lt;wtf/BitVector.h&gt;
</del><ins>+#include &lt;wtf/Bitmap.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -71,7 +71,7 @@
</span><span class="cx">     void set(Reg reg, bool value = true)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(!!reg);
</span><del>-        m_vector.set(reg.index(), value);
</del><ins>+        m_bits.set(reg.index(), value);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void set(JSValueRegs regs, bool value = true)
</span><span class="lines">@@ -90,9 +90,9 @@
</span><span class="cx">     bool get(Reg reg) const
</span><span class="cx">     {
</span><span class="cx">         ASSERT(!!reg);
</span><del>-        return m_vector.get(reg.index());
</del><ins>+        return m_bits.get(reg.index());
</ins><span class="cx">     }
</span><del>-
</del><ins>+    
</ins><span class="cx">     template&lt;typename Iterable&gt;
</span><span class="cx">     void setAll(const Iterable&amp; iterable)
</span><span class="cx">     {
</span><span class="lines">@@ -100,13 +100,13 @@
</span><span class="cx">             set(reg);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void merge(const RegisterSet&amp; other) { m_vector.merge(other.m_vector); }
-    void filter(const RegisterSet&amp; other) { m_vector.filter(other.m_vector); }
-    void exclude(const RegisterSet&amp; other) { m_vector.exclude(other.m_vector); }
</del><ins>+    void merge(const RegisterSet&amp; other) { m_bits.merge(other.m_bits); }
+    void filter(const RegisterSet&amp; other) { m_bits.filter(other.m_bits); }
+    void exclude(const RegisterSet&amp; other) { m_bits.exclude(other.m_bits); }
</ins><span class="cx">     
</span><span class="cx">     size_t numberOfSetGPRs() const;
</span><span class="cx">     size_t numberOfSetFPRs() const;
</span><del>-    size_t numberOfSetRegisters() const { return m_vector.bitCount(); }
</del><ins>+    size_t numberOfSetRegisters() const { return m_bits.count(); }
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     
</span><span class="lines">@@ -114,28 +114,40 @@
</span><span class="cx">     enum DeletedValueTag { DeletedValue };
</span><span class="cx">     
</span><span class="cx">     RegisterSet(EmptyValueTag)
</span><del>-        : m_vector(BitVector::EmptyValue)
</del><span class="cx">     {
</span><ins>+        m_bits.set(hashSpecialBitIndex);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     RegisterSet(DeletedValueTag)
</span><del>-        : m_vector(BitVector::DeletedValue)
</del><span class="cx">     {
</span><ins>+        m_bits.set(hashSpecialBitIndex);
+        m_bits.set(deletedBitIndex);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool isEmptyValue() const { return m_vector.isEmptyValue(); }
-    bool isDeletedValue() const { return m_vector.isDeletedValue(); }
</del><ins>+    bool isEmptyValue() const
+    {
+        return m_bits.get(hashSpecialBitIndex) &amp;&amp; !m_bits.get(deletedBitIndex);
+    }
</ins><span class="cx">     
</span><del>-    bool operator==(const RegisterSet&amp; other) const { return m_vector == other.m_vector; }
-    unsigned hash() const { return m_vector.hash(); }
-
-    template&lt;typename Functor&gt;
-    void forEach(const Functor&amp; functor) const
</del><ins>+    bool isDeletedValue() const
</ins><span class="cx">     {
</span><del>-        for (size_t index : m_vector)
-            functor(Reg::fromIndex(index));
</del><ins>+        return m_bits.get(hashSpecialBitIndex) &amp;&amp; m_bits.get(deletedBitIndex);
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    bool operator==(const RegisterSet&amp; other) const { return m_bits == other.m_bits; }
+    bool operator!=(const RegisterSet&amp; other) const { return m_bits != other.m_bits; }
+    
+    unsigned hash() const { return m_bits.hash(); }
+    
+    template&lt;typename Func&gt;
+    void forEach(const Func&amp; func) const
+    {
+        m_bits.forEachSetBit(
+            [&amp;] (size_t index) {
+                func(Reg::fromIndex(index));
+            });
+    }
+    
</ins><span class="cx"> private:
</span><span class="cx">     void setAny(Reg reg) { set(reg); }
</span><span class="cx">     void setAny(const RegisterSet&amp; set) { merge(set); }
</span><span class="lines">@@ -147,7 +159,13 @@
</span><span class="cx">         setMany(regs...);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    BitVector m_vector;
</del><ins>+    // These offsets mirror the logic in Reg.h.
+    static const unsigned gprOffset = 0;
+    static const unsigned fprOffset = gprOffset + MacroAssembler::numGPRs;
+    static const unsigned hashSpecialBitIndex = fprOffset + MacroAssembler::numFPRs;
+    static const unsigned deletedBitIndex = 0;
+    
+    Bitmap&lt;MacroAssembler::numGPRs + MacroAssembler::numFPRs + 1&gt; m_bits;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct RegisterSetHash {
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/WTF/ChangeLog        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2016-07-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        RegisterSet should use a Bitmap instead of a BitVector so that it never allocates memory and is trivial to copy
+        https://bugs.webkit.org/show_bug.cgi?id=159863
+
+        Reviewed by Saam Barati.
+        
+        Give Bitmap all of the power of BitVector (except for automatic resizing). This means a
+        variant of set() that takes a bool, and a bunch of helper methods (merge, filter, exclude,
+        forEachSetBit, ==, !=, and hash).
+
+        * wtf/Bitmap.h:
+        (WTF::WordType&gt;::set):
+        (WTF::WordType&gt;::testAndSet):
+        (WTF::WordType&gt;::isFull):
+        (WTF::WordType&gt;::merge):
+        (WTF::WordType&gt;::filter):
+        (WTF::WordType&gt;::exclude):
+        (WTF::WordType&gt;::forEachSetBit):
+        (WTF::=):
+        (WTF::WordType&gt;::hash):
+
</ins><span class="cx"> 2016-07-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WTF::Lock should be fair eventually
</span></span></pre></div>
<a id="trunkSourceWTFwtfBitmaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Bitmap.h (203364 => 203365)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Bitmap.h        2016-07-18 19:32:34 UTC (rev 203364)
+++ trunk/Source/WTF/wtf/Bitmap.h        2016-07-18 19:51:45 UTC (rev 203365)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- *  Copyright (C) 2010 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2010, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Lesser General Public
</span><span class="lines">@@ -39,6 +39,8 @@
</span><span class="cx"> template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode = BitmapNotAtomic, typename WordType = uint32_t&gt;
</span><span class="cx"> class Bitmap {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><ins>+    
+    static_assert(sizeof(WordType) &lt;= sizeof(unsigned), &quot;WordType must not be bigger than unsigned&quot;);
</ins><span class="cx"> public:
</span><span class="cx">     Bitmap();
</span><span class="cx"> 
</span><span class="lines">@@ -49,6 +51,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool get(size_t) const;
</span><span class="cx">     void set(size_t);
</span><ins>+    void set(size_t, bool);
</ins><span class="cx">     bool testAndSet(size_t);
</span><span class="cx">     bool testAndClear(size_t);
</span><span class="cx">     bool concurrentTestAndSet(size_t);
</span><span class="lines">@@ -60,6 +63,18 @@
</span><span class="cx">     size_t count(size_t = 0) const;
</span><span class="cx">     size_t isEmpty() const;
</span><span class="cx">     size_t isFull() const;
</span><ins>+    
+    void merge(const Bitmap&amp;);
+    void filter(const Bitmap&amp;);
+    void exclude(const Bitmap&amp;);
+    
+    template&lt;typename Func&gt;
+    void forEachSetBit(const Func&amp;) const;
+    
+    bool operator==(const Bitmap&amp;) const;
+    bool operator!=(const Bitmap&amp;) const;
+    
+    unsigned hash() const;
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     static const unsigned wordSize = sizeof(WordType) * 8;
</span><span class="lines">@@ -94,6 +109,15 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
</span><ins>+inline void Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::set(size_t n, bool value)
+{
+    if (value)
+        set(n);
+    else
+        clear(n);
+}
+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
</ins><span class="cx"> inline bool Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::testAndSet(size_t n)
</span><span class="cx"> {
</span><span class="cx">     WordType mask = one &lt;&lt; (n % wordSize);
</span><span class="lines">@@ -224,5 +248,71 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+inline void Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::merge(const Bitmap&amp; other)
+{
+    for (size_t i = 0; i &lt; words; ++i)
+        bits[i] |= other.bits[i];
</ins><span class="cx"> }
</span><ins>+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+inline void Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::filter(const Bitmap&amp; other)
+{
+    for (size_t i = 0; i &lt; words; ++i)
+        bits[i] &amp;= other.bits[i];
+}
+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+inline void Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::exclude(const Bitmap&amp; other)
+{
+    for (size_t i = 0; i &lt; words; ++i)
+        bits[i] &amp;= ~other.bits[i];
+}
+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+template&lt;typename Func&gt;
+inline void Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::forEachSetBit(const Func&amp; func) const
+{
+    for (size_t i = 0; i &lt; words; ++i) {
+        WordType word = bits[i];
+        if (!word)
+            continue;
+        size_t base = i * wordSize;
+        for (size_t j = 0; j &lt; wordSize; ++j) {
+            if (word &amp; 1)
+                func(base + j);
+            word &gt;&gt;= 1;
+        }
+    }
+}
+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+inline bool Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::operator==(const Bitmap&amp; other) const
+{
+    for (size_t i = 0; i &lt; words; ++i) {
+        if (bits[i] != other.bits[i])
+            return false;
+    }
+    return true;
+}
+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+inline bool Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::operator!=(const Bitmap&amp; other) const
+{
+    return !(*this == other);
+}
+
+template&lt;size_t bitmapSize, BitmapAtomicMode atomicMode, typename WordType&gt;
+inline unsigned Bitmap&lt;bitmapSize, atomicMode, WordType&gt;::hash() const
+{
+    unsigned result = 0;
+    for (size_t i = 0; i &lt; words; ++i)
+        result ^= IntHash&lt;WordType&gt;::hash(bits[i]);
+    return result;
+}
+
+} // namespace WTF
+
+using WTF::Bitmap;
+
</ins><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>