<!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>[225154] trunk</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/225154">225154</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2017-11-26 23:51:16 -0800 (Sun, 26 Nov 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[DFG] Add NormalizeMapKey DFG IR
https://bugs.webkit.org/show_bug.cgi?id=179912

Reviewed by Saam Barati.

JSTests:

* stress/map-untyped-normalize-cse.js: Added.
(shouldBe):
(test):
* stress/map-untyped-normalize.js: Added.
(shouldBe):
(test):
* stress/set-untyped-normalize-cse.js: Added.
(shouldBe):
(set return.set has.set has):
* stress/set-untyped-normalize.js: Added.
(shouldBe):
(set return.set has):

Source/JavaScriptCore:

This patch introduces NormalizeMapKey DFG node. It executes what normalizeMapKey does in inlined manner.
By separating this from MapHash and Map/Set related operations, we can perform CSE onto that, and we
do not need to call normalizeMapKey conservatively in DFG operations.
This can reduce slow path case in Untyped GetMapBucket since we can normalize keys in DFG/FTL.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupNormalizeMapKey):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNormalizeMapKey):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
(JSC::FTL::DFG::LowerDFGToB3::compileNormalizeMapKey):
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):
* runtime/HashMapImpl.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeHashMapImplh">trunk/Source/JavaScriptCore/runtime/HashMapImpl.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressmapuntypednormalizecsejs">trunk/JSTests/stress/map-untyped-normalize-cse.js</a></li>
<li><a href="#trunkJSTestsstressmapuntypednormalizejs">trunk/JSTests/stress/map-untyped-normalize.js</a></li>
<li><a href="#trunkJSTestsstressnormalizemapkeyconstantfoldingjs">trunk/JSTests/stress/normalize-map-key-constant-folding.js</a></li>
<li><a href="#trunkJSTestsstresssetuntypednormalizecsejs">trunk/JSTests/stress/set-untyped-normalize-cse.js</a></li>
<li><a href="#trunkJSTestsstresssetuntypednormalizejs">trunk/JSTests/stress/set-untyped-normalize.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/JSTests/ChangeLog     2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2017-11-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG] Add NormalizeMapKey DFG IR
+        https://bugs.webkit.org/show_bug.cgi?id=179912
+
+        Reviewed by Saam Barati.
+
+        * stress/map-untyped-normalize-cse.js: Added.
+        (shouldBe):
+        (test):
+        * stress/map-untyped-normalize.js: Added.
+        (shouldBe):
+        (test):
+        * stress/set-untyped-normalize-cse.js: Added.
+        (shouldBe):
+        (set return.set has.set has):
+        * stress/set-untyped-normalize.js: Added.
+        (shouldBe):
+        (set return.set has):
+
</ins><span class="cx"> 2017-11-26  Yusuke Suzuki  <utatane.tea@gmail.com>
</span><span class="cx"> 
</span><span class="cx">         [FTL] Support DeleteById and DeleteByVal
</span></span></pre></div>
<a id="trunkJSTestsstressmapuntypednormalizecsejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/map-untyped-normalize-cse.js (0 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/map-untyped-normalize-cse.js                                (rev 0)
+++ trunk/JSTests/stress/map-untyped-normalize-cse.js   2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let map = new Map();
+for (let key of keys)
+    map.set(key, i++);
+
+function test(map, key)
+{
+    return map.get(key) + map.get(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        let result = j + j;
+        j++
+        shouldBe(test(map, key), result);
+    }
+}
+shouldBe(test(map, 0.0), 2);
</ins></span></pre></div>
<a id="trunkJSTestsstressmapuntypednormalizejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/map-untyped-normalize.js (0 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/map-untyped-normalize.js                            (rev 0)
+++ trunk/JSTests/stress/map-untyped-normalize.js       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let map = new Map();
+for (let key of keys)
+    map.set(key, i++);
+
+function test(map, key)
+{
+    return map.get(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        shouldBe(test(map, key), j++);
+    }
+}
+shouldBe(test(map, 0.0), 1);
</ins></span></pre></div>
<a id="trunkJSTestsstressnormalizemapkeyconstantfoldingjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/normalize-map-key-constant-folding.js (0 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/normalize-map-key-constant-folding.js                               (rev 0)
+++ trunk/JSTests/stress/normalize-map-key-constant-folding.js  2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+function test(i)
+{
+    var map = new Map();
+    var key = "Hello";
+    if (i & 0x1)
+        key = 42;
+    map.set(key, 42);
+    return map;
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i)
+    test(i);
</ins></span></pre></div>
<a id="trunkJSTestsstresssetuntypednormalizecsejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/set-untyped-normalize-cse.js (0 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/set-untyped-normalize-cse.js                                (rev 0)
+++ trunk/JSTests/stress/set-untyped-normalize-cse.js   2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let set = new Set();
+for (let key of keys)
+    set.add(key);
+
+function test(set, key)
+{
+    return set.has(key) + set.has(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        shouldBe(test(set, key), 2);
+    }
+}
+shouldBe(test(set, 0.0), 2);
</ins></span></pre></div>
<a id="trunkJSTestsstresssetuntypednormalizejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/set-untyped-normalize.js (0 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/set-untyped-normalize.js                            (rev 0)
+++ trunk/JSTests/stress/set-untyped-normalize.js       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var keys = [
+    "Cappuccino",
+    -0.0,
+    Symbol("Cocoa"),
+    42,
+    -42,
+    null,
+    undefined,
+    420.5,
+    0xffffffff,
+    0x80000000,
+    -1,
+    -2147483648,
+    {},
+    [],
+    false,
+    true,
+    NaN,
+];
+
+let i = 0;
+let set = new Set();
+for (let key of keys)
+    set.add(key);
+
+function test(set, key)
+{
+    return set.has(key);
+}
+noInline(test);
+
+for (let i = 0; i < 1e4; ++i) {
+    let j = 0;
+    for (let key of keys) {
+        shouldBe(test(set, key), true);
+    }
+}
+shouldBe(test(set, 0.0), true);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/ChangeLog       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -1,3 +1,47 @@
</span><ins>+2017-11-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG] Add NormalizeMapKey DFG IR
+        https://bugs.webkit.org/show_bug.cgi?id=179912
+
+        Reviewed by Saam Barati.
+
+        This patch introduces NormalizeMapKey DFG node. It executes what normalizeMapKey does in inlined manner.
+        By separating this from MapHash and Map/Set related operations, we can perform CSE onto that, and we
+        do not need to call normalizeMapKey conservatively in DFG operations.
+        This can reduce slow path case in Untyped GetMapBucket since we can normalize keys in DFG/FTL.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupNormalizeMapKey):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNormalizeMapKey):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNormalizeMapKey):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):
+        * runtime/HashMapImpl.h:
+
</ins><span class="cx"> 2017-11-26  Yusuke Suzuki  <utatane.tea@gmail.com>
</span><span class="cx"> 
</span><span class="cx">         [FTL] Support DeleteById and DeleteByVal
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h  2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h     2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -1099,6 +1099,23 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case NormalizeMapKey: {
+        if (JSValue key = forNode(node->child1()).value()) {
+            setConstant(node, *m_graph.freeze(normalizeMapKey(key)));
+            break;
+        }
+
+        SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
+        if (!(forNode(node->child1()).m_type & typeMaybeNormalized)) {
+            m_state.setFoundConstants(true);
+            forNode(node) = forNode(node->child1());
+            break;
+        }
+
+        forNode(node).makeHeapTop();
+        break;
+    }
+
</ins><span class="cx">     case StringSlice: {
</span><span class="cx">         forNode(node).setType(m_graph, SpecString);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp    2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -2873,8 +2873,9 @@
</span><span class="cx">         insertChecks();
</span><span class="cx">         Node* map = get(virtualRegisterForArgument(0, registerOffset));
</span><span class="cx">         Node* key = get(virtualRegisterForArgument(1, registerOffset));
</span><del>-        Node* hash = addToGraph(MapHash, key);
-        Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(key), Edge(hash));
</del><ins>+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+        Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(normalizedKey), Edge(hash));
</ins><span class="cx">         Node* result = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket);
</span><span class="cx">         set(VirtualRegister(resultOperand), result);
</span><span class="cx">         return true;
</span><span class="lines">@@ -2888,9 +2889,10 @@
</span><span class="cx">         insertChecks();
</span><span class="cx">         Node* mapOrSet = get(virtualRegisterForArgument(0, registerOffset));
</span><span class="cx">         Node* key = get(virtualRegisterForArgument(1, registerOffset));
</span><del>-        Node* hash = addToGraph(MapHash, key);
</del><ins>+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
</ins><span class="cx">         UseKind useKind = intrinsic == JSSetHasIntrinsic ? SetObjectUse : MapObjectUse;
</span><del>-        Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(key), Edge(hash));
</del><ins>+        Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(normalizedKey), Edge(hash));
</ins><span class="cx">         JSCell* sentinel = nullptr;
</span><span class="cx">         if (intrinsic == JSMapHasIntrinsic)
</span><span class="cx">             sentinel = m_vm->sentinelMapBucket.get();
</span><span class="lines">@@ -2911,8 +2913,9 @@
</span><span class="cx">         insertChecks();
</span><span class="cx">         Node* base = get(virtualRegisterForArgument(0, registerOffset));
</span><span class="cx">         Node* key = get(virtualRegisterForArgument(1, registerOffset));
</span><del>-        Node* hash = addToGraph(MapHash, key);
-        addToGraph(SetAdd, base, key, hash);
</del><ins>+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+        addToGraph(SetAdd, base, normalizedKey, hash);
</ins><span class="cx">         set(VirtualRegister(resultOperand), base);
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="lines">@@ -2925,10 +2928,12 @@
</span><span class="cx">         Node* base = get(virtualRegisterForArgument(0, registerOffset));
</span><span class="cx">         Node* key = get(virtualRegisterForArgument(1, registerOffset));
</span><span class="cx">         Node* value = get(virtualRegisterForArgument(2, registerOffset));
</span><del>-        Node* hash = addToGraph(MapHash, key);
</del><span class="cx"> 
</span><ins>+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+
</ins><span class="cx">         addVarArgChild(base);
</span><del>-        addVarArgChild(key);
</del><ins>+        addVarArgChild(normalizedKey);
</ins><span class="cx">         addVarArgChild(value);
</span><span class="cx">         addVarArgChild(hash);
</span><span class="cx">         addToGraph(Node::VarArg, MapSet, OpInfo(0), OpInfo(0));
</span><span class="lines">@@ -2992,8 +2997,9 @@
</span><span class="cx">         insertChecks();
</span><span class="cx">         Node* map = get(virtualRegisterForArgument(0, registerOffset));
</span><span class="cx">         Node* key = get(virtualRegisterForArgument(1, registerOffset));
</span><del>-        Node* hash = addToGraph(MapHash, key);
-        Node* result = addToGraph(WeakMapGet, OpInfo(), OpInfo(prediction), map, key, hash);
</del><ins>+        Node* normalizedKey = addToGraph(NormalizeMapKey, key);
+        Node* hash = addToGraph(MapHash, normalizedKey);
+        Node* result = addToGraph(WeakMapGet, OpInfo(), OpInfo(prediction), map, normalizedKey, hash);
</ins><span class="cx">         set(VirtualRegister(resultOperand), result);
</span><span class="cx">         return true;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h  2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h     2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -1591,6 +1591,10 @@
</span><span class="cx">         def(PureValue(node));
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    case NormalizeMapKey:
+        def(PureValue(node));
+        return;
+
</ins><span class="cx">     case GetMapBucket: {
</span><span class="cx">         Edge& mapEdge = node->child1();
</span><span class="cx">         Edge& keyEdge = node->child2();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp      2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp 2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -635,6 +635,16 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            case NormalizeMapKey: {
+                SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
+                if (m_state.forNode(node->child1()).m_type & typeMaybeNormalized)
+                    break;
+
+                node->convertToIdentity();
+                changed = true;
+                break;
+            }
+
</ins><span class="cx">             case ParseInt: {
</span><span class="cx">                 AbstractValue& value = m_state.forNode(node->child1());
</span><span class="cx">                 if (!value.m_type || (value.m_type & ~SpecInt32Only))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp    2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -203,6 +203,7 @@
</span><span class="cx">     case CheckTraps:
</span><span class="cx">     case StringFromCharCode:
</span><span class="cx">     case MapHash:
</span><ins>+    case NormalizeMapKey:
</ins><span class="cx">     case GetMapBucket:
</span><span class="cx">     case GetMapBucketHead:
</span><span class="cx">     case GetMapBucketNext:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp   2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -1940,6 +1940,11 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case NormalizeMapKey: {
+            fixupNormalizeMapKey(node);
+            break;
+        }
+
</ins><span class="cx">         case WeakMapGet: {
</span><span class="cx">             fixEdge<WeakMapObjectUse>(node->child1());
</span><span class="cx">             fixEdge<ObjectUse>(node->child2());
</span><span class="lines">@@ -3203,6 +3208,47 @@
</span><span class="cx">         fixEdge<Int32Use>(node->child2());
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void fixupNormalizeMapKey(Node* node)
+    {
+        if (node->child1()->shouldSpeculateBoolean()) {
+            fixEdge<BooleanUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateInt32()) {
+            fixEdge<Int32Use>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateSymbol()) {
+            fixEdge<SymbolUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateObject()) {
+            fixEdge<ObjectUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateString()) {
+            fixEdge<StringUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        if (node->child1()->shouldSpeculateCell()) {
+            fixEdge<CellUse>(node->child1());
+            node->convertToIdentity();
+            return;
+        }
+
+        fixEdge<UntypedUse>(node->child1());
+    }
+
</ins><span class="cx">     bool attemptToMakeCallDOM(Node* node)
</span><span class="cx">     {
</span><span class="cx">         if (m_graph.hasExitSite(node->origin.semantic, BadType))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h    2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -435,6 +435,7 @@
</span><span class="cx">     macro(ToIndexString, NodeResultJS) \
</span><span class="cx">     /* Nodes for JSMap and JSSet */ \
</span><span class="cx">     macro(MapHash, NodeResultInt32) \
</span><ins>+    macro(NormalizeMapKey, NodeResultJS) \
</ins><span class="cx">     macro(GetMapBucket, NodeResultJS) \
</span><span class="cx">     macro(GetMapBucketHead, NodeResultJS) \
</span><span class="cx">     macro(GetMapBucketNext, NodeResultJS) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp   2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -2533,7 +2533,7 @@
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&vm, exec);
</span><span class="cx"> 
</span><del>-    return jsMapHash(exec, vm, normalizeMapKey(JSValue::decode(input)));
</del><ins>+    return jsMapHash(exec, vm, JSValue::decode(input));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash)
</span><span class="lines">@@ -2540,7 +2540,7 @@
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&vm, exec);
</span><del>-    JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, normalizeMapKey(JSValue::decode(key)), hash);
</del><ins>+    JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, JSValue::decode(key), hash);
</ins><span class="cx">     if (!bucket)
</span><span class="cx">         return vm.sentinelMapBucket.get();
</span><span class="cx">     return *bucket;
</span><span class="lines">@@ -2550,19 +2550,17 @@
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&vm, exec);
</span><del>-    JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, normalizeMapKey(JSValue::decode(key)), hash);
</del><ins>+    JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, JSValue::decode(key), hash);
</ins><span class="cx">     if (!bucket)
</span><span class="cx">         return vm.sentinelSetBucket.get();
</span><span class="cx">     return *bucket;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// FIXME: Add NormalizeMapKey DFG node.
-// https://bugs.webkit.org/show_bug.cgi?id=179912
</del><span class="cx"> void JIT_OPERATION operationSetAdd(ExecState* exec, JSCell* set, EncodedJSValue key, int32_t hash)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&vm, exec);
</span><del>-    jsCast<JSSet*>(set)->addNormalized(exec, normalizeMapKey(JSValue::decode(key)), JSValue(), hash);
</del><ins>+    jsCast<JSSet*>(set)->addNormalized(exec, JSValue::decode(key), JSValue(), hash);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JIT_OPERATION operationMapSet(ExecState* exec, JSCell* map, EncodedJSValue key, EncodedJSValue value, int32_t hash)
</span><span class="lines">@@ -2569,7 +2567,7 @@
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&vm, exec);
</span><del>-    jsCast<JSMap*>(map)->addNormalized(exec, normalizeMapKey(JSValue::decode(key)), JSValue::decode(value), hash);
</del><ins>+    jsCast<JSMap*>(map)->addNormalized(exec, JSValue::decode(key), JSValue::decode(value), hash);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(ExecState* exec, JSObject* thisObject)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp   2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -462,6 +462,13 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case NormalizeMapKey: {
+            SpeculatedType prediction = node->child1()->prediction();
+            if (prediction)
+                changed |= mergePrediction(prediction);
+            break;
+        }
+
</ins><span class="cx">         default:
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="lines">@@ -1024,6 +1031,7 @@
</span><span class="cx">         case GetByVal:
</span><span class="cx">         case ToThis:
</span><span class="cx">         case ToPrimitive: 
</span><ins>+        case NormalizeMapKey:
</ins><span class="cx">         case AtomicsAdd:
</span><span class="cx">         case AtomicsAnd:
</span><span class="cx">         case AtomicsCompareExchange:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h       2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h  2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -416,6 +416,7 @@
</span><span class="cx">     case ResolveScopeForHoistingFuncDeclInEval:
</span><span class="cx">     case ResolveScope:
</span><span class="cx">     case MapHash:
</span><ins>+    case NormalizeMapKey:
</ins><span class="cx">     case StringSlice:
</span><span class="cx">     case ToLowerCase:
</span><span class="cx">     case GetMapBucket:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp    2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp       2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -10737,6 +10737,47 @@
</span><span class="cx">     m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::compileNormalizeMapKey(Node* node)
+{
+    ASSERT(node->child1().useKind() == UntypedUse);
+    JSValueOperand key(this, node->child1());
+    JSValueRegsTemporary result(this, Reuse, key);
+    GPRTemporary scratch(this);
+    FPRTemporary doubleValue(this);
+    FPRTemporary temp(this);
+
+    JSValueRegs keyRegs = key.jsValueRegs();
+    JSValueRegs resultRegs = result.regs();
+    GPRReg scratchGPR = scratch.gpr();
+    FPRReg doubleValueFPR = doubleValue.fpr();
+    FPRReg tempFPR = temp.fpr();
+
+    CCallHelpers::JumpList passThroughCases;
+
+    passThroughCases.append(m_jit.branchIfNotNumber(keyRegs, scratchGPR));
+    passThroughCases.append(m_jit.branchIfInt32(keyRegs));
+
+#if USE(JSVALUE64)
+    m_jit.unboxDoubleWithoutAssertions(keyRegs.gpr(), scratchGPR, doubleValueFPR);
+#else
+    unboxDouble(keyRegs.tagGPR(), keyRegs.payloadGPR(), doubleValueFPR, tempFPR);
+#endif
+    passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqualOrUnordered, doubleValueFPR, doubleValueFPR));
+
+    m_jit.truncateDoubleToInt32(doubleValueFPR, scratchGPR);
+    m_jit.convertInt32ToDouble(scratchGPR, tempFPR);
+    passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqual, doubleValueFPR, tempFPR));
+
+    m_jit.boxInt32(scratchGPR, resultRegs);
+    auto done = m_jit.jump();
+
+    passThroughCases.link(&m_jit);
+    m_jit.moveValueRegs(keyRegs, resultRegs);
+
+    done.link(&m_jit);
+    jsValueResult(resultRegs, node);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileGetMapBucketHead(Node* node)
</span><span class="cx"> {
</span><span class="cx">     SpeculateCellOperand map(this, node->child1());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h      2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h 2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -2894,6 +2894,7 @@
</span><span class="cx">     void compileCallDOMGetter(Node*);
</span><span class="cx">     void compileCallDOM(Node*);
</span><span class="cx">     void compileCheckSubClass(Node*);
</span><ins>+    void compileNormalizeMapKey(Node*);
</ins><span class="cx">     void compileGetMapBucketHead(Node*);
</span><span class="cx">     void compileGetMapBucketNext(Node*);
</span><span class="cx">     void compileSetAdd(Node*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp       2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp  2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -4822,6 +4822,11 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case NormalizeMapKey: {
+        compileNormalizeMapKey(node);
+        break;
+    }
+
</ins><span class="cx">     case GetMapBucket: {
</span><span class="cx">         SpeculateCellOperand map(this, node->child1());
</span><span class="cx">         JSValueOperand key(this, node->child2());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp  2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp     2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -5072,7 +5072,7 @@
</span><span class="cx"> 
</span><span class="cx">         MacroAssembler::JumpList straightHash;
</span><span class="cx">         MacroAssembler::JumpList done;
</span><del>-        auto isNotCell = m_jit.branchIfNotCell(inputGPR);
</del><ins>+        straightHash.append(m_jit.branchIfNotCell(inputGPR));
</ins><span class="cx">         MacroAssembler::JumpList slowPath;
</span><span class="cx">         straightHash.append(m_jit.branch8(MacroAssembler::NotEqual, MacroAssembler::Address(inputGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType)));
</span><span class="cx">         m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
</span><span class="lines">@@ -5082,11 +5082,6 @@
</span><span class="cx">         slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
</span><span class="cx">         done.append(m_jit.jump());
</span><span class="cx"> 
</span><del>-        isNotCell.link(&m_jit);
-        straightHash.append(m_jit.branchIfNotNumber(inputGPR));
-        straightHash.append(m_jit.branchIfInt32(JSValueRegs(inputGPR)));
-        slowPath.append(m_jit.jump());
-
</del><span class="cx">         straightHash.link(&m_jit);
</span><span class="cx">         m_jit.move(inputGPR, resultGPR);
</span><span class="cx">         m_jit.wangsInt64Hash(resultGPR, tempGPR);
</span><span class="lines">@@ -5102,6 +5097,12 @@
</span><span class="cx">         int32Result(resultGPR, node);
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+
+    case NormalizeMapKey: {
+        compileNormalizeMapKey(node);
+        break;
+    }
+
</ins><span class="cx">     case GetMapBucket: {
</span><span class="cx">         SpeculateCellOperand map(this, node->child1());
</span><span class="cx">         JSValueOperand key(this, node->child2(), ManualOperandSpeculation);
</span><span class="lines">@@ -5182,7 +5183,8 @@
</span><span class="cx">         }
</span><span class="cx">         case UntypedUse: { 
</span><span class="cx">             done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR)); // They're definitely the same value, we found the bucket we were looking for!
</span><del>-            auto oneIsntCell = m_jit.branchIfNotCell(JSValueRegs(bucketGPR));
</del><ins>+            // The input key and bucket's key are already normalized. So if 64-bit compare fails and one is not a cell, they're definitely not equal.
+            loopAround.append(m_jit.branchIfNotCell(JSValueRegs(bucketGPR)));
</ins><span class="cx">             // first is a cell here.
</span><span class="cx">             loopAround.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
</span><span class="cx">             // Both are cells here.
</span><span class="lines">@@ -5193,14 +5195,6 @@
</span><span class="cx">                 JITCompiler::Address(keyGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType)));
</span><span class="cx">             // The first is a string, but the second is not, we continue to loop around.
</span><span class="cx">             loopAround.append(m_jit.jump());
</span><del>-
-            oneIsntCell.link(&m_jit);
-            // We've already done a 64-bit compare at this point, so if one is not a number, they're definitely not equal.
-            loopAround.append(m_jit.branchIfNotNumber(bucketGPR));
-            loopAround.append(m_jit.branchIfNotNumber(keyGPR));
-            // Both are definitely numbers. If we see a double, we go to the slow path.
-            slowPathCases.append(m_jit.branchIfNotInt32(bucketGPR));
-            slowPathCases.append(m_jit.branchIfNotInt32(keyGPR));
</del><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp      2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp 2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -202,6 +202,7 @@
</span><span class="cx">     case HasOwnProperty:
</span><span class="cx">     case IsCellWithType:
</span><span class="cx">     case MapHash:
</span><ins>+    case NormalizeMapKey:
</ins><span class="cx">     case GetMapBucket:
</span><span class="cx">     case GetMapBucketHead:
</span><span class="cx">     case GetMapBucketNext:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp      2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp 2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -1043,6 +1043,9 @@
</span><span class="cx">         case MapHash:
</span><span class="cx">             compileMapHash();
</span><span class="cx">             break;
</span><ins>+        case NormalizeMapKey:
+            compileNormalizeMapKey();
+            break;
</ins><span class="cx">         case GetMapBucket:
</span><span class="cx">             compileGetMapBucket();
</span><span class="cx">             break;
</span><span class="lines">@@ -8527,16 +8530,14 @@
</span><span class="cx">         LValue value = lowJSValue(m_node->child1());
</span><span class="cx"> 
</span><span class="cx">         LBasicBlock isCellCase = m_out.newBlock();
</span><del>-        LBasicBlock notCell = m_out.newBlock();
</del><span class="cx">         LBasicBlock slowCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock straightHash = m_out.newBlock();
</span><del>-        LBasicBlock isNumberCase = m_out.newBlock();
</del><span class="cx">         LBasicBlock isStringCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock nonEmptyStringCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock continuation = m_out.newBlock();
</span><span class="cx"> 
</span><span class="cx">         m_out.branch(
</span><del>-            isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(notCell));
</del><ins>+            isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(straightHash));
</ins><span class="cx"> 
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
</span><span class="cx">         LValue isString = m_out.equal(m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoType), m_out.constInt32(StringType));
</span><span class="lines">@@ -8548,20 +8549,12 @@
</span><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.equal(stringImpl, m_out.constIntPtr(0)), rarely(slowCase), usually(nonEmptyStringCase));
</span><span class="cx"> 
</span><del>-        m_out.appendTo(nonEmptyStringCase, notCell);
</del><ins>+        m_out.appendTo(nonEmptyStringCase, straightHash);
</ins><span class="cx">         LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
</span><span class="cx">         ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash);
</span><span class="cx">         m_out.branch(m_out.equal(hash, m_out.constInt32(0)),
</span><span class="cx">             unsure(slowCase), unsure(continuation));
</span><span class="cx"> 
</span><del>-        m_out.appendTo(notCell, isNumberCase);
-        m_out.branch(
-            isNumber(value), unsure(isNumberCase), unsure(straightHash));
-
-        m_out.appendTo(isNumberCase, straightHash);
-        m_out.branch(
-            isInt32(value), unsure(straightHash), unsure(slowCase));
-
</del><span class="cx">         m_out.appendTo(straightHash, slowCase);
</span><span class="cx">         ValueFromBlock fastResult = m_out.anchor(wangsInt64Hash(value));
</span><span class="cx">         m_out.jump(continuation);
</span><span class="lines">@@ -8575,6 +8568,42 @@
</span><span class="cx">         setInt32(m_out.phi(Int32, fastResult, slowResult, nonEmptyStringHashResult));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void compileNormalizeMapKey()
+    {
+        ASSERT(m_node->child1().useKind() == UntypedUse);
+
+        LBasicBlock isNumberCase = m_out.newBlock();
+        LBasicBlock notInt32NumberCase = m_out.newBlock();
+        LBasicBlock notNaNCase = m_out.newBlock();
+        LBasicBlock convertibleCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(isNumberCase);
+
+        LValue key = lowJSValue(m_node->child1());
+        ValueFromBlock fastResult = m_out.anchor(key);
+        m_out.branch(isNotNumber(key), unsure(continuation), unsure(isNumberCase));
+
+        m_out.appendTo(isNumberCase, notInt32NumberCase);
+        m_out.branch(isInt32(key), unsure(continuation), unsure(notInt32NumberCase));
+
+        m_out.appendTo(notInt32NumberCase, notNaNCase);
+        LValue doubleValue = unboxDouble(key);
+        m_out.branch(m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue), unsure(continuation), unsure(notNaNCase));
+
+        m_out.appendTo(notNaNCase, convertibleCase);
+        LValue integerValue = m_out.doubleToInt(doubleValue);
+        LValue integerValueConvertedToDouble = m_out.intToDouble(integerValue);
+        m_out.branch(m_out.doubleNotEqualOrUnordered(doubleValue, integerValueConvertedToDouble), unsure(continuation), unsure(convertibleCase));
+
+        m_out.appendTo(convertibleCase, continuation);
+        ValueFromBlock slowResult = m_out.anchor(boxInt32(integerValue));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(Int64, fastResult, slowResult));
+    }
+
</ins><span class="cx">     void compileGetMapBucket()
</span><span class="cx">     {
</span><span class="cx">         LBasicBlock loopStart = m_out.newBlock();
</span><span class="lines">@@ -8676,10 +8705,6 @@
</span><span class="cx">             LBasicBlock bucketKeyIsCell = m_out.newBlock();
</span><span class="cx">             LBasicBlock bothAreCells = m_out.newBlock();
</span><span class="cx">             LBasicBlock bucketKeyIsString = m_out.newBlock();
</span><del>-            LBasicBlock bucketKeyNotCell = m_out.newBlock();
-            LBasicBlock bucketKeyIsNumber = m_out.newBlock();
-            LBasicBlock bothAreNumbers = m_out.newBlock();
-            LBasicBlock bucketKeyIsInt32 = m_out.newBlock();
</del><span class="cx"> 
</span><span class="cx">             m_out.branch(m_out.equal(key, bucketKey),
</span><span class="cx">                 unsure(continuation), unsure(notBitEqual));
</span><span class="lines">@@ -8686,7 +8711,7 @@
</span><span class="cx"> 
</span><span class="cx">             m_out.appendTo(notBitEqual, bucketKeyIsCell);
</span><span class="cx">             m_out.branch(isCell(bucketKey),
</span><del>-                unsure(bucketKeyIsCell), unsure(bucketKeyNotCell));
</del><ins>+                unsure(bucketKeyIsCell), unsure(loopAround));
</ins><span class="cx"> 
</span><span class="cx">             m_out.appendTo(bucketKeyIsCell, bothAreCells);
</span><span class="cx">             m_out.branch(isCell(key),
</span><span class="lines">@@ -8696,25 +8721,9 @@
</span><span class="cx">             m_out.branch(isString(bucketKey),
</span><span class="cx">                 unsure(bucketKeyIsString), unsure(loopAround));
</span><span class="cx"> 
</span><del>-            m_out.appendTo(bucketKeyIsString, bucketKeyNotCell);
</del><ins>+            m_out.appendTo(bucketKeyIsString, loopAround);
</ins><span class="cx">             m_out.branch(isString(key),
</span><span class="cx">                 unsure(slowPath), unsure(loopAround));
</span><del>-
-            m_out.appendTo(bucketKeyNotCell, bucketKeyIsNumber);
-            m_out.branch(isNotNumber(bucketKey),
-                unsure(loopAround), unsure(bucketKeyIsNumber));
-
-            m_out.appendTo(bucketKeyIsNumber, bothAreNumbers);
-            m_out.branch(isNotNumber(key),
-                unsure(loopAround), unsure(bothAreNumbers));
-
-            m_out.appendTo(bothAreNumbers, bucketKeyIsInt32);
-            m_out.branch(isNotInt32(bucketKey),
-                unsure(slowPath), unsure(bucketKeyIsInt32));
-
-            m_out.appendTo(bucketKeyIsInt32, loopAround);
-            m_out.branch(isNotInt32(key),
-                unsure(slowPath), unsure(loopAround));
</del><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeHashMapImplh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/HashMapImpl.h (225153 => 225154)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/HashMapImpl.h        2017-11-27 03:45:57 UTC (rev 225153)
+++ trunk/Source/JavaScriptCore/runtime/HashMapImpl.h   2017-11-27 07:51:16 UTC (rev 225154)
</span><span class="lines">@@ -233,6 +233,8 @@
</span><span class="cx">     return sameValue(exec, a, b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// Note that normalization is inlined in DFG's NormalizeMapKey.
+// Keep in sync with the implementation of DFG and FTL normalization.
</ins><span class="cx"> ALWAYS_INLINE JSValue normalizeMapKey(JSValue key)
</span><span class="cx"> {
</span><span class="cx">     if (!key.isNumber())
</span></span></pre>
</div>
</div>

</body>
</html>