<!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>[194856] 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/194856">194856</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-01-11 09:25:03 -0800 (Mon, 11 Jan 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make it easier to introduce exotic instructions to Air
https://bugs.webkit.org/show_bug.cgi?id=152953

Reviewed by Benjamin Poulain.

Currently, you can define new &quot;opcodes&quot; in Air using either:

1) New opcode declared in AirOpcode.opcodes.
2) Patch opcode with a new implementation of Air::Special.

With (1), you are limited to fixed-argument-length instructions. There are other
restrictions as well, like that you can only use the roles that the AirOpcode syntax
supports.

With (2), you can do anything you like, but the instruction will be harder to match
since it will share the same opcode as any other Patch. Also, the instruction will have
the Special argument, which means more busy-work when creating the instruction and
validating it.

This introduces an in-between facility called &quot;custom&quot;. This replaces what AirOpcode
previously called &quot;special&quot;. A custom instruction is one whose behavior is defined by a
FooCustom struct with some static methods. Calls to those methods are emitted by
opcode_generator.rb.

The &quot;custom&quot; facility is powerful enough to be used to implement Patch, with the caveat
that we now treat the Patch instruction specially in a few places. Those places were
already effectively treating it specially by assuming that only Patch instructions have
a Special as their first argument.

This will let me implement the Shuffle instruction (bug 152952), which I think is needed
for performance work.

* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/air/AirCustom.h: Added.
(JSC::B3::Air::PatchCustom::forEachArg):
(JSC::B3::Air::PatchCustom::isValidFormStatic):
(JSC::B3::Air::PatchCustom::isValidForm):
(JSC::B3::Air::PatchCustom::admitsStack):
(JSC::B3::Air::PatchCustom::hasNonArgNonControlEffects):
(JSC::B3::Air::PatchCustom::generate):
* b3/air/AirHandleCalleeSaves.cpp:
(JSC::B3::Air::handleCalleeSaves):
* b3/air/AirInst.h:
* b3/air/AirInstInlines.h:
(JSC::B3::Air::Inst::forEach):
(JSC::B3::Air::Inst::extraClobberedRegs):
(JSC::B3::Air::Inst::extraEarlyClobberedRegs):
(JSC::B3::Air::Inst::forEachDefWithExtraClobberedRegs):
(JSC::B3::Air::Inst::reportUsedRegisters):
(JSC::B3::Air::Inst::hasSpecial): Deleted.
* b3/air/AirOpcode.opcodes:
* b3/air/AirReportUsedRegisters.cpp:
(JSC::B3::Air::reportUsedRegisters):
* b3/air/opcode_generator.rb:</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="#trunkSourceJavaScriptCoreb3airAirHandleCalleeSavescpp">trunk/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInsth">trunk/Source/JavaScriptCore/b3/air/AirInst.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInstInlinesh">trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirReportUsedRegisterscpp">trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airopcode_generatorrb">trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCustomh">trunk/Source/JavaScriptCore/b3/air/AirCustom.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -1,5 +1,62 @@
</span><span class="cx"> 2016-01-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Make it easier to introduce exotic instructions to Air
+        https://bugs.webkit.org/show_bug.cgi?id=152953
+
+        Reviewed by Benjamin Poulain.
+
+        Currently, you can define new &quot;opcodes&quot; in Air using either:
+
+        1) New opcode declared in AirOpcode.opcodes.
+        2) Patch opcode with a new implementation of Air::Special.
+
+        With (1), you are limited to fixed-argument-length instructions. There are other
+        restrictions as well, like that you can only use the roles that the AirOpcode syntax
+        supports.
+
+        With (2), you can do anything you like, but the instruction will be harder to match
+        since it will share the same opcode as any other Patch. Also, the instruction will have
+        the Special argument, which means more busy-work when creating the instruction and
+        validating it.
+
+        This introduces an in-between facility called &quot;custom&quot;. This replaces what AirOpcode
+        previously called &quot;special&quot;. A custom instruction is one whose behavior is defined by a
+        FooCustom struct with some static methods. Calls to those methods are emitted by
+        opcode_generator.rb.
+
+        The &quot;custom&quot; facility is powerful enough to be used to implement Patch, with the caveat
+        that we now treat the Patch instruction specially in a few places. Those places were
+        already effectively treating it specially by assuming that only Patch instructions have
+        a Special as their first argument.
+
+        This will let me implement the Shuffle instruction (bug 152952), which I think is needed
+        for performance work.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/air/AirCustom.h: Added.
+        (JSC::B3::Air::PatchCustom::forEachArg):
+        (JSC::B3::Air::PatchCustom::isValidFormStatic):
+        (JSC::B3::Air::PatchCustom::isValidForm):
+        (JSC::B3::Air::PatchCustom::admitsStack):
+        (JSC::B3::Air::PatchCustom::hasNonArgNonControlEffects):
+        (JSC::B3::Air::PatchCustom::generate):
+        * b3/air/AirHandleCalleeSaves.cpp:
+        (JSC::B3::Air::handleCalleeSaves):
+        * b3/air/AirInst.h:
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::Inst::forEach):
+        (JSC::B3::Air::Inst::extraClobberedRegs):
+        (JSC::B3::Air::Inst::extraEarlyClobberedRegs):
+        (JSC::B3::Air::Inst::forEachDefWithExtraClobberedRegs):
+        (JSC::B3::Air::Inst::reportUsedRegisters):
+        (JSC::B3::Air::Inst::hasSpecial): Deleted.
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirReportUsedRegisters.cpp:
+        (JSC::B3::Air::reportUsedRegisters):
+        * b3/air/opcode_generator.rb:
+
+2016-01-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Turn Check(true) into Patchpoint() followed by Oops
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=152968
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -103,6 +103,7 @@
</span><span class="cx">                 0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */; };
</span><span class="cx">                 0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F10F1A21C420BF0001C07D2 /* AirCustom.h */; };
</ins><span class="cx">                 0F12DE0F1979D5FD0006FF4E /* ExceptionFuzz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F12DE0D1979D5FD0006FF4E /* ExceptionFuzz.cpp */; };
</span><span class="cx">                 0F12DE101979D5FD0006FF4E /* ExceptionFuzz.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F12DE0E1979D5FD0006FF4E /* ExceptionFuzz.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F136D4D174AD69E0075B354 /* DeferGC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F136D4B174AD69B0075B354 /* DeferGC.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -2243,6 +2244,7 @@
</span><span class="cx">                 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutDirectIndexMode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SparseArrayValueMap.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntCallLinkInfo.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F10F1A21C420BF0001C07D2 /* AirCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirCustom.h; path = b3/air/AirCustom.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F12DE0D1979D5FD0006FF4E /* ExceptionFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionFuzz.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F12DE0E1979D5FD0006FF4E /* ExceptionFuzz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionFuzz.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F136D4B174AD69B0075B354 /* DeferGC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeferGC.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4793,6 +4795,7 @@
</span><span class="cx">                                 0FEC854F1BDACDC70080FF74 /* AirCCallSpecial.h */,
</span><span class="cx">                                 0FEC85501BDACDC70080FF74 /* AirCode.cpp */,
</span><span class="cx">                                 0FEC85511BDACDC70080FF74 /* AirCode.h */,
</span><ins>+                                0F10F1A21C420BF0001C07D2 /* AirCustom.h */,
</ins><span class="cx">                                 0F4570361BE44C910062A629 /* AirEliminateDeadCode.cpp */,
</span><span class="cx">                                 0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */,
</span><span class="cx">                                 262D85B41C0D650F006ACB61 /* AirFixPartialRegisterStalls.cpp */,
</span><span class="lines">@@ -7443,6 +7446,7 @@
</span><span class="cx">                                 142E3136134FF0A600AFADB5 /* HandleSet.h in Headers */,
</span><span class="cx">                                 142E3138134FF0A600AFADB5 /* HandleStack.h in Headers */,
</span><span class="cx">                                 1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */,
</span><ins>+                                0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */,
</ins><span class="cx">                                 14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
</span><span class="cx">                                 0F32BD111BB34F190093A57F /* HeapHelperPool.h in Headers */,
</span><span class="cx">                                 C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCustomh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirCustom.h (0 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCustom.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirCustom.h        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -0,0 +1,104 @@
</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 AirCustom_h
+#define AirCustom_h
+
+#if ENABLE(B3_JIT)
+
+#include &quot;AirInst.h&quot;
+#include &quot;AirSpecial.h&quot;
+
+namespace JSC { namespace B3 { namespace Air {
+
+// This defines the behavior of custom instructions - i.e. those whose behavior cannot be
+// described using AirOpcode.opcodes. If you define an opcode as &quot;custom Foo&quot; in that file, then
+// you will need to create a &quot;struct FooCustom&quot; here that implements the custom behavior
+// methods.
+//
+// The customizability granted by the custom instruction mechanism is strictly less than what
+// you get using the Patch instruction and implementing a Special. However, that path requires
+// allocating a Special object and ensuring that it's the first operand. For many instructions,
+// that is not as convenient as using Custom, which makes the instruction look like any other
+// instruction. Note that both of those extra powers of the Patch instruction happen because we
+// special-case that instruction in many phases and analyses. Non-special-cased behaviors of
+// Patch are implemented using the custom instruction mechanism.
+//
+// Specials are still more flexible if you need to list extra clobbered registers and you'd like
+// that to be expressed as a bitvector rather than an arglist. They are also more flexible if
+// you need to carry extra state around with the instruction. Also, Specials mean that you
+// always have access to Code&amp; even in methods that don't take a GenerationContext.
+
+struct PatchCustom {
+    template&lt;typename Functor&gt;
+    static void forEachArg(Inst&amp; inst, const Functor&amp; functor)
+    {
+        // This is basically bogus, but it works for analyses that model Special as an
+        // immediate.
+        functor(inst.args[0], Arg::Use, Arg::GP, Arg::pointerWidth());
+        
+        inst.args[0].special()-&gt;forEachArg(inst, scopedLambda&lt;Inst::EachArgCallback&gt;(functor));
+    }
+
+    template&lt;typename... Arguments&gt;
+    static bool isValidFormStatic(Arguments...)
+    {
+        return false;
+    }
+
+    static bool isValidForm(Inst&amp; inst)
+    {
+        if (inst.args.size() &lt; 1)
+            return false;
+        if (!inst.args[0].isSpecial())
+            return false;
+        return inst.args[0].special()-&gt;isValid(inst);
+    }
+
+    static bool admitsStack(Inst&amp; inst, unsigned argIndex)
+    {
+        if (!argIndex)
+            return false;
+        return inst.args[0].special()-&gt;admitsStack(inst, argIndex);
+    }
+
+    static bool hasNonArgNonControlEffects(Inst&amp; inst)
+    {
+        return inst.args[0].special()-&gt;hasNonArgNonControlEffects();
+    }
+
+    static CCallHelpers::Jump generate(
+        Inst&amp; inst, CCallHelpers&amp; jit, GenerationContext&amp; context)
+    {
+        return inst.args[0].special()-&gt;generate(inst, jit, context);
+    }
+};
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
+#endif // AirCustom_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirHandleCalleeSavescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp        2016-01-11 17:25:03 UTC (rev 194856)
</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">@@ -49,7 +49,7 @@
</span><span class="cx">                     usedCalleeSaves.set(tmp.reg());
</span><span class="cx">                 });
</span><span class="cx"> 
</span><del>-            if (inst.hasSpecial())
</del><ins>+            if (inst.opcode == Patch)
</ins><span class="cx">                 usedCalleeSaves.merge(inst.extraClobberedRegs());
</span><span class="cx">         }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInsth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInst.h (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInst.h        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/b3/air/AirInst.h        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -119,11 +119,8 @@
</span><span class="cx">     template&lt;typename Thing, typename Functor&gt;
</span><span class="cx">     void forEach(const Functor&amp;);
</span><span class="cx"> 
</span><del>-    // Returns true if this instruction has a Special*. This unlocks some extra functionality.
-    bool hasSpecial() const;
-
</del><span class="cx">     // Reports any additional registers clobbered by this operation. Note that for efficiency,
</span><del>-    // extraClobberedRegs() only works if hasSpecial() returns true.
</del><ins>+    // extraClobberedRegs() only works for the Patch opcode.
</ins><span class="cx">     const RegisterSet&amp; extraClobberedRegs();
</span><span class="cx">     const RegisterSet&amp; extraEarlyClobberedRegs();
</span><span class="cx"> 
</span><span class="lines">@@ -141,7 +138,7 @@
</span><span class="cx">     static void forEachDefWithExtraClobberedRegs(Inst* prevInst, Inst* nextInst, const Functor&amp;);
</span><span class="cx"> 
</span><span class="cx">     // Use this to report which registers are live. This should be done just before codegen. Note
</span><del>-    // that for efficiency, reportUsedRegisters() only works if hasSpecial() returns true.
</del><ins>+    // that for efficiency, reportUsedRegisters() only works for the Patch opcode.
</ins><span class="cx">     void reportUsedRegisters(const RegisterSet&amp;);
</span><span class="cx"> 
</span><span class="cx">     // Is this instruction in one of the valid forms right now? This function is auto-generated by
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInstInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -96,20 +96,15 @@
</span><span class="cx">     ForEach&lt;Thing&gt;::forEach(*this, functor);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline bool Inst::hasSpecial() const
-{
-    return args.size() &amp;&amp; args[0].isSpecial();
-}
-
</del><span class="cx"> inline const RegisterSet&amp; Inst::extraClobberedRegs()
</span><span class="cx"> {
</span><del>-    ASSERT(hasSpecial());
</del><ins>+    ASSERT(opcode == Patch);
</ins><span class="cx">     return args[0].special()-&gt;extraClobberedRegs(*this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline const RegisterSet&amp; Inst::extraEarlyClobberedRegs()
</span><span class="cx"> {
</span><del>-    ASSERT(hasSpecial());
</del><ins>+    ASSERT(opcode == Patch);
</ins><span class="cx">     return args[0].special()-&gt;extraEarlyClobberedRegs(*this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -146,12 +141,12 @@
</span><span class="cx">         functor(Thing(reg), regDefRole, type, Arg::conservativeWidth(type));
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    if (prevInst &amp;&amp; prevInst-&gt;hasSpecial()) {
</del><ins>+    if (prevInst &amp;&amp; prevInst-&gt;opcode == Patch) {
</ins><span class="cx">         regDefRole = Arg::Def;
</span><span class="cx">         prevInst-&gt;extraClobberedRegs().forEach(reportReg);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (nextInst &amp;&amp; nextInst-&gt;hasSpecial()) {
</del><ins>+    if (nextInst &amp;&amp; nextInst-&gt;opcode == Patch) {
</ins><span class="cx">         regDefRole = Arg::EarlyDef;
</span><span class="cx">         nextInst-&gt;extraEarlyClobberedRegs().forEach(reportReg);
</span><span class="cx">     }
</span><span class="lines">@@ -159,7 +154,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline void Inst::reportUsedRegisters(const RegisterSet&amp; usedRegisters)
</span><span class="cx"> {
</span><del>-    ASSERT(hasSpecial());
</del><ins>+    ASSERT(opcode == Patch);
</ins><span class="cx">     args[0].special()-&gt;reportUsedRegisters(*this, usedRegisters);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -674,5 +674,5 @@
</span><span class="cx"> 
</span><span class="cx"> # Air allows for exotic behavior. A Patch's behavior is determined entirely by the Special operand,
</span><span class="cx"> # which must be the first operand.
</span><del>-special Patch
</del><ins>+custom Patch
</ins><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirReportUsedRegisterscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> 
</span><span class="cx">         for (unsigned instIndex = block-&gt;size(); instIndex--;) {
</span><span class="cx">             Inst&amp; inst = block-&gt;at(instIndex);
</span><del>-            if (inst.hasSpecial()) {
</del><ins>+            if (inst.opcode == Patch) {
</ins><span class="cx">                 RegisterSet registerSet;
</span><span class="cx">                 for (Reg reg : localCalc.live())
</span><span class="cx">                     registerSet.set(reg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airopcode_generatorrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb (194855 => 194856)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2016-01-11 17:18:07 UTC (rev 194855)
+++ trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2016-01-11 17:25:03 UTC (rev 194856)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env ruby
</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">@@ -26,14 +26,14 @@
</span><span class="cx"> require &quot;pathname&quot;
</span><span class="cx"> 
</span><span class="cx"> class Opcode
</span><del>-    attr_reader :name, :special, :overloads
</del><ins>+    attr_reader :name, :custom, :overloads
</ins><span class="cx">     attr_reader :attributes
</span><span class="cx"> 
</span><del>-    def initialize(name, special)
</del><ins>+    def initialize(name, custom)
</ins><span class="cx">         @name = name
</span><del>-        @special = special
</del><ins>+        @custom = custom
</ins><span class="cx">         @attributes = {}
</span><del>-        unless special
</del><ins>+        unless custom
</ins><span class="cx">             @overloads = []
</span><span class="cx">         end
</span><span class="cx">     end
</span><span class="lines">@@ -72,18 +72,18 @@
</span><span class="cx"> 
</span><span class="cx"> class Kind
</span><span class="cx">     attr_reader :name
</span><del>-    attr_accessor :special
</del><ins>+    attr_accessor :custom
</ins><span class="cx"> 
</span><span class="cx">     def initialize(name)
</span><span class="cx">         @name = name
</span><del>-        @special = false
</del><ins>+        @custom = false
</ins><span class="cx">     end
</span><span class="cx"> 
</span><span class="cx">     def ==(other)
</span><span class="cx">         if other.is_a? String
</span><span class="cx">             @name == other
</span><span class="cx">         else
</span><del>-            @name == other.name and @special == other.special
</del><ins>+            @name == other.name and @custom == other.custom
</ins><span class="cx">         end
</span><span class="cx">     end
</span><span class="cx"> 
</span><span class="lines">@@ -203,7 +203,7 @@
</span><span class="cx"> 
</span><span class="cx"> def isKeyword(token)
</span><span class="cx">     isRole(token) or isGF(token) or isKind(token) or isArch(token) or isWidth(token) or
</span><del>-        token == &quot;special&quot; or token == &quot;as&quot;
</del><ins>+        token == &quot;custom&quot; or token == &quot;as&quot;
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def isIdentifier(token)
</span><span class="lines">@@ -342,11 +342,11 @@
</span><span class="cx">         loop {
</span><span class="cx">             break if @idx &gt;= @tokens.length
</span><span class="cx"> 
</span><del>-            if token == &quot;special&quot;
-                consume(&quot;special&quot;)
</del><ins>+            if token == &quot;custom&quot;
+                consume(&quot;custom&quot;)
</ins><span class="cx">                 opcodeName = consumeIdentifier
</span><span class="cx"> 
</span><del>-                parseError(&quot;Cannot overload a special opcode&quot;) if result[opcodeName]
</del><ins>+                parseError(&quot;Cannot overload a custom opcode&quot;) if result[opcodeName]
</ins><span class="cx"> 
</span><span class="cx">                 result[opcodeName] = Opcode.new(opcodeName, true)
</span><span class="cx">             else
</span><span class="lines">@@ -356,7 +356,7 @@
</span><span class="cx"> 
</span><span class="cx">                 if result[opcodeName]
</span><span class="cx">                     opcode = result[opcodeName]
</span><del>-                    parseError(&quot;Cannot overload a special opcode&quot;) if opcode.special
</del><ins>+                    parseError(&quot;Cannot overload a custom opcode&quot;) if opcode.custom
</ins><span class="cx">                 else
</span><span class="cx">                     opcode = Opcode.new(opcodeName, false)
</span><span class="cx">                     result[opcodeName] = opcode
</span><span class="lines">@@ -410,7 +410,7 @@
</span><span class="cx"> 
</span><span class="cx">                             if token == &quot;*&quot;
</span><span class="cx">                                 parseError(&quot;Can only apply * to Tmp&quot;) unless kinds[-1].name == &quot;Tmp&quot;
</span><del>-                                kinds[-1].special = true
</del><ins>+                                kinds[-1].custom = true
</ins><span class="cx">                                 consume(&quot;*&quot;)
</span><span class="cx">                             end
</span><span class="cx"> 
</span><span class="lines">@@ -549,7 +549,7 @@
</span><span class="cx">     $opcodes.values.each {
</span><span class="cx">         | opcode |
</span><span class="cx">         outp.puts &quot;case #{opcode.name}:&quot;
</span><del>-        if opcode.special
</del><ins>+        if opcode.custom
</ins><span class="cx">             yield opcode, nil
</span><span class="cx">         else
</span><span class="cx">             needOverloadSwitch = ((opcode.overloads.size != 1) or speed == :safe)
</span><span class="lines">@@ -576,7 +576,7 @@
</span><span class="cx"> def matchInstOverloadForm(outp, speed, inst)
</span><span class="cx">     matchInstOverload(outp, speed, inst) {
</span><span class="cx">         | opcode, overload |
</span><del>-        if opcode.special
</del><ins>+        if opcode.custom
</ins><span class="cx">             yield opcode, nil, nil
</span><span class="cx">         else
</span><span class="cx">             columnGetter = proc {
</span><span class="lines">@@ -612,8 +612,8 @@
</span><span class="cx"> 
</span><span class="cx"> writeH(&quot;OpcodeUtils&quot;) {
</span><span class="cx">     | outp |
</span><ins>+    outp.puts &quot;#include \&quot;AirCustom.h\&quot;&quot;
</ins><span class="cx">     outp.puts &quot;#include \&quot;AirInst.h\&quot;&quot;
</span><del>-    outp.puts &quot;#include \&quot;AirSpecial.h\&quot;&quot;
</del><span class="cx">     outp.puts &quot;namespace JSC { namespace B3 { namespace Air {&quot;
</span><span class="cx">     
</span><span class="cx">     outp.puts &quot;inline bool opgenHiddenTruth() { return true; }&quot;
</span><span class="lines">@@ -629,9 +629,8 @@
</span><span class="cx">     outp.puts &quot;{&quot;
</span><span class="cx">     matchInstOverload(outp, :fast, &quot;this&quot;) {
</span><span class="cx">         | opcode, overload |
</span><del>-        if opcode.special
-            outp.puts &quot;functor(args[0], Arg::Use, Arg::GP, Arg::pointerWidth()); // This is basically bogus, but it works for analyses that model Special as an immediate.&quot;
-            outp.puts &quot;args[0].special()-&gt;forEachArg(*this, scopedLambda&lt;EachArgCallback&gt;(functor));&quot;
</del><ins>+        if opcode.custom
+            outp.puts &quot;#{opcode.name}Custom::forEachArg(*this, functor);&quot;
</ins><span class="cx">         else
</span><span class="cx">             overload.signature.each_with_index {
</span><span class="cx">                 | arg, index |
</span><span class="lines">@@ -670,8 +669,10 @@
</span><span class="cx">     $opcodes.values.each {
</span><span class="cx">         | opcode |
</span><span class="cx">         outp.puts &quot;case #{opcode.name}:&quot;
</span><del>-        outp.puts &quot;switch (sizeof...(Arguments)) {&quot;
-        unless opcode.special
</del><ins>+        if opcode.custom
+            outp.puts &quot;OPGEN_RETURN(#{opcode.name}Custom::isValidFormStatic(arguments...));&quot;
+        else
+            outp.puts &quot;switch (sizeof...(Arguments)) {&quot;
</ins><span class="cx">             opcode.overloads.each {
</span><span class="cx">                 | overload |
</span><span class="cx">                 outp.puts &quot;case #{overload.signature.length}:&quot;
</span><span class="lines">@@ -679,8 +680,8 @@
</span><span class="cx">                 filter = proc { false }
</span><span class="cx">                 callback = proc {
</span><span class="cx">                     | form |
</span><del>-                    notSpecial = (not form.kinds.detect { | kind | kind.special })
-                    if notSpecial
</del><ins>+                    notCustom = (not form.kinds.detect { | kind | kind.custom })
+                    if notCustom
</ins><span class="cx">                         beginArchs(outp, form.archs)
</span><span class="cx">                         outp.puts &quot;OPGEN_RETURN(true);&quot;
</span><span class="cx">                         endArchs(outp, form.archs)
</span><span class="lines">@@ -689,11 +690,11 @@
</span><span class="cx">                 matchForms(outp, :safe, overload.forms, 0, columnGetter, filter, callback)
</span><span class="cx">                 outp.puts &quot;break;&quot;
</span><span class="cx">             }
</span><ins>+            outp.puts &quot;default:&quot;
+            outp.puts &quot;break;&quot;
+            outp.puts &quot;}&quot;
</ins><span class="cx">         end
</span><del>-        outp.puts &quot;default:&quot;
</del><span class="cx">         outp.puts &quot;break;&quot;
</span><del>-        outp.puts &quot;}&quot;
-        outp.puts &quot;break;&quot;
</del><span class="cx">     }
</span><span class="cx">     outp.puts &quot;default:&quot;
</span><span class="cx">     outp.puts &quot;break;&quot;
</span><span class="lines">@@ -766,12 +767,8 @@
</span><span class="cx">     outp.puts &quot;{&quot;
</span><span class="cx">     matchInstOverloadForm(outp, :safe, &quot;this&quot;) {
</span><span class="cx">         | opcode, overload, form |
</span><del>-        if opcode.special
-            outp.puts &quot;if (args.size() &lt; 1)&quot;
-            outp.puts &quot;return false;&quot;
-            outp.puts &quot;if (!args[0].isSpecial())&quot;
-            outp.puts &quot;return false;&quot;
-            outp.puts &quot;OPGEN_RETURN(args[0].special()-&gt;isValid(*this));&quot;
</del><ins>+        if opcode.custom
+            outp.puts &quot;OPGEN_RETURN(#{opcode.name}Custom::isValidForm(*this));&quot;
</ins><span class="cx">         else
</span><span class="cx">             beginArchs(outp, form.archs)
</span><span class="cx">             needsMoreValidation = false
</span><span class="lines">@@ -779,7 +776,7 @@
</span><span class="cx">                 | index |
</span><span class="cx">                 arg = overload.signature[index]
</span><span class="cx">                 kind = form.kinds[index]
</span><del>-                needsMoreValidation |= kind.special
</del><ins>+                needsMoreValidation |= kind.custom
</ins><span class="cx"> 
</span><span class="cx">                 # Some kinds of Args reqire additional validation.
</span><span class="cx">                 case kind.name
</span><span class="lines">@@ -821,10 +818,8 @@
</span><span class="cx">         | opcode |
</span><span class="cx">         outp.puts &quot;case #{opcode.name}:&quot;
</span><span class="cx"> 
</span><del>-        if opcode.special
-            outp.puts &quot;if (!argIndex)&quot;
-            outp.puts &quot;return false;&quot;
-            outp.puts &quot;OPGEN_RETURN(args[0].special()-&gt;admitsStack(*this, argIndex));&quot;
</del><ins>+        if opcode.custom
+            outp.puts &quot;OPGEN_RETURN(#{opcode.name}Custom::admitsStack(*this, argIndex));&quot;
</ins><span class="cx">         else
</span><span class="cx">             # Switch on the argIndex.
</span><span class="cx">             outp.puts &quot;switch (argIndex) {&quot;
</span><span class="lines">@@ -967,17 +962,13 @@
</span><span class="cx">     if foundTrue
</span><span class="cx">         outp.puts &quot;return true;&quot;
</span><span class="cx">     end
</span><del>-    foundTrue = false
</del><span class="cx">     $opcodes.values.each {
</span><span class="cx">         | opcode |
</span><del>-        if opcode.special
</del><ins>+        if opcode.custom
</ins><span class="cx">             outp.puts &quot;case #{opcode.name}:&quot;
</span><del>-            foundTrue = true
</del><ins>+            outp.puts &quot;return #{opcode.name}Custom::hasNonArgNonControlEffects(*this);&quot;
</ins><span class="cx">         end
</span><span class="cx">     }
</span><del>-    if foundTrue
-        outp.puts &quot;return args[0].special()-&gt;hasNonArgNonControlEffects();&quot;
-    end
</del><span class="cx">     outp.puts &quot;default:&quot;
</span><span class="cx">     outp.puts &quot;return false;&quot;
</span><span class="cx">     outp.puts &quot;}&quot;
</span><span class="lines">@@ -997,17 +988,13 @@
</span><span class="cx">     if foundTrue
</span><span class="cx">         outp.puts &quot;return true;&quot;
</span><span class="cx">     end
</span><del>-    foundTrue = false
</del><span class="cx">     $opcodes.values.each {
</span><span class="cx">         | opcode |
</span><del>-        if opcode.special
</del><ins>+        if opcode.custom
</ins><span class="cx">             outp.puts &quot;case #{opcode.name}:&quot;
</span><del>-            foundTrue = true
</del><ins>+            outp.puts &quot;return #{opcode.name}Custom::hasNonArgNonControlEffects(*this);&quot;
</ins><span class="cx">         end
</span><span class="cx">     }
</span><del>-    if foundTrue
-        outp.puts &quot;return args[0].special()-&gt;hasNonArgNonControlEffects();&quot;
-    end
</del><span class="cx">     outp.puts &quot;default:&quot;
</span><span class="cx">     outp.puts &quot;return false;&quot;
</span><span class="cx">     outp.puts &quot;}&quot;
</span><span class="lines">@@ -1020,8 +1007,8 @@
</span><span class="cx">     outp.puts &quot;CCallHelpers::Jump result;&quot;
</span><span class="cx">     matchInstOverloadForm(outp, :fast, &quot;this&quot;) {
</span><span class="cx">         | opcode, overload, form |
</span><del>-        if opcode.special
-            outp.puts &quot;OPGEN_RETURN(args[0].special()-&gt;generate(*this, jit, context));&quot;
</del><ins>+        if opcode.custom
+            outp.puts &quot;OPGEN_RETURN(#{opcode.name}Custom::generate(*this, jit, context));&quot;
</ins><span class="cx">         else
</span><span class="cx">             beginArchs(outp, form.archs)
</span><span class="cx">             if form.altName
</span></span></pre>
</div>
</div>

</body>
</html>