<!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>[206136] 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/206136">206136</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-09-19 18:05:50 -0700 (Mon, 19 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make HasOwnProperty faster
https://bugs.webkit.org/show_bug.cgi?id=161708

Reviewed by Geoffrey Garen.

JSTests:

* microbenchmarks/has-own-property-name-cache.js: Added.
(foo):
* stress/has-own-property-cache-basics.js: Added.
(assert):
(foo):
* stress/has-own-property-name-cache-string-keys.js: Added.
(assert):
(foo):
* stress/has-own-property-name-cache-symbol-keys.js: Added.
(assert):
(foo):
* stress/has-own-property-name-cache-symbols-and-strings.js: Added.
(assert):
(foo):

Source/JavaScriptCore:

This patch adds a cache for HasOwnProperty. The cache holds tuples
of {StructureID, UniquedStringImpl*, boolean} where the boolean indicates
the result of performing hasOwnProperty on an object with StructureID and
UniquedStringImpl*. If the cache contains an item, we can be guaranteed
that it contains the same result as performing hasOwnProperty on an
object O with a given structure and key. To guarantee this, we only add
items into the cache when the Structure of the given item is cacheable.

The caching strategy is simple: when adding new items into the cache,
we will evict any item that was in the location that the new item
is hashed into. We also clear the cache on every GC. This strategy
proves to be successful on speedometer, which sees a cache hit rate
over 90%. This caching strategy is now inlined into the DFG/FTL JITs
by now recognizing hasOwnProperty as an intrinsic with the corresponding
HasOwnProperty node. The goal of the node is to emit inlined code for
the cache lookup to prevent the overhead of the call for the common
case where we get a cache hit.

I'm seeing around a 1% to 1.5% percent improvement on Speedometer on
my machine. Hopefully the perf bots agree with my machine.

This patch also speeds up the microbenchmark I added by 2.5x.

* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::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):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
* heap/Heap.cpp:
(JSC::Heap::collectImpl):
* jit/JITOperations.h:
* runtime/HasOwnPropertyCache.h: Added.
(JSC::HasOwnPropertyCache::Entry::offsetOfStructureID):
(JSC::HasOwnPropertyCache::Entry::offsetOfImpl):
(JSC::HasOwnPropertyCache::Entry::offsetOfResult):
(JSC::HasOwnPropertyCache::operator delete):
(JSC::HasOwnPropertyCache::create):
(JSC::HasOwnPropertyCache::hash):
(JSC::HasOwnPropertyCache::get):
(JSC::HasOwnPropertyCache::tryAdd):
(JSC::HasOwnPropertyCache::clear):
(JSC::VM::ensureHasOwnPropertyCache):
* runtime/Intrinsic.h:
* runtime/JSObject.h:
* runtime/JSObjectInlines.h:
(JSC::JSObject::hasOwnProperty):
* runtime/ObjectPrototype.cpp:
(JSC::ObjectPrototype::finishCreation):
(JSC::objectProtoFuncHasOwnProperty):
* runtime/Symbol.h:
* runtime/VM.cpp:
* runtime/VM.h:
(JSC::VM::hasOwnPropertyCache):</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="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</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="#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="#trunkSourceJavaScriptCoredfgDFGOperationsh">trunk/Source/JavaScriptCore/dfg/DFGOperations.h</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="#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="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h</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="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationsh">trunk/Source/JavaScriptCore/jit/JITOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIntrinsich">trunk/Source/JavaScriptCore/runtime/Intrinsic.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectInlinesh">trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeObjectPrototypecpp">trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeSymbolh">trunk/Source/JavaScriptCore/runtime/Symbol.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMcpp">trunk/Source/JavaScriptCore/runtime/VM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMh">trunk/Source/JavaScriptCore/runtime/VM.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsmicrobenchmarkshasownpropertynamecachejs">trunk/JSTests/microbenchmarks/has-own-property-name-cache.js</a></li>
<li><a href="#trunkJSTestsstresshasownpropertycachebasicsjs">trunk/JSTests/stress/has-own-property-cache-basics.js</a></li>
<li><a href="#trunkJSTestsstresshasownpropertynamecachestringkeysjs">trunk/JSTests/stress/has-own-property-name-cache-string-keys.js</a></li>
<li><a href="#trunkJSTestsstresshasownpropertynamecachesymbolkeysjs">trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js</a></li>
<li><a href="#trunkJSTestsstresshasownpropertynamecachesymbolsandstringsjs">trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeHasOwnPropertyCacheh">trunk/Source/JavaScriptCore/runtime/HasOwnPropertyCache.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/JSTests/ChangeLog        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2016-09-19  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        Make HasOwnProperty faster
+        https://bugs.webkit.org/show_bug.cgi?id=161708
+
+        Reviewed by Geoffrey Garen.
+
+        * microbenchmarks/has-own-property-name-cache.js: Added.
+        (foo):
+        * stress/has-own-property-cache-basics.js: Added.
+        (assert):
+        (foo):
+        * stress/has-own-property-name-cache-string-keys.js: Added.
+        (assert):
+        (foo):
+        * stress/has-own-property-name-cache-symbol-keys.js: Added.
+        (assert):
+        (foo):
+        * stress/has-own-property-name-cache-symbols-and-strings.js: Added.
+        (assert):
+        (foo):
+
</ins><span class="cx"> 2016-09-19  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Make the rounding-related nodes support any type
</span></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkshasownpropertynamecachejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/has-own-property-name-cache.js (0 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/has-own-property-name-cache.js                                (rev 0)
+++ trunk/JSTests/microbenchmarks/has-own-property-name-cache.js        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+let objs = [
+    {
+        __proto__: { 
+            foo: 25
+        },
+        bar: 50,
+        baz: 75,
+        jaz: 80,
+    },
+    {
+        __proto__: { 
+            bar: 25
+        },
+        baz: 75,
+        kaz: 80,
+        bar: 50,
+        jaz: 80,
+    },
+    {
+        __proto__: { 
+            bar: 25,
+            jaz: 50
+        },
+        bar: 50,
+        baz: 75,
+        kaz: 80,
+        jaz: 80,
+        foo: 55
+    }
+];
+
+function foo(o) {
+    for (let p in o)
+        o.hasOwnProperty(p);
+
+}
+noInline(foo);
+
+let start = Date.now();
+for (let i = 0; i &lt; 1000000; ++i) {
+    foo(objs[i % objs.length]);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);
</ins></span></pre></div>
<a id="trunkJSTestsstresshasownpropertycachebasicsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/has-own-property-cache-basics.js (0 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/has-own-property-cache-basics.js                                (rev 0)
+++ trunk/JSTests/stress/has-own-property-cache-basics.js        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion.&quot;)
+}
+noInline(assert);
+
+let objs = [
+    {f: 50},
+    {f: 50, g: 70},
+    {g: 50, f: 70},
+    {h: 50, f: 70},
+    {z: 50, f: 70},
+    {k: 50, f: 70},
+];
+
+let s1 = Symbol();
+let s2 = Symbol();
+for (let o of objs)
+    o[s1] = &quot;foo&quot;;
+
+function foo(o) {
+    assert(o.hasOwnProperty(&quot;f&quot;));
+    assert(!o.hasOwnProperty(&quot;ff&quot;));
+    assert(o.hasOwnProperty(s1));
+    assert(!o.hasOwnProperty(s2));
+}
+noInline(foo);
+
+for (let i = 0; i &lt; 40000; ++i) {
+    foo(objs[i % objs.length]);
+}
</ins></span></pre></div>
<a id="trunkJSTestsstresshasownpropertynamecachestringkeysjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/has-own-property-name-cache-string-keys.js (0 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/has-own-property-name-cache-string-keys.js                                (rev 0)
+++ trunk/JSTests/stress/has-own-property-name-cache-string-keys.js        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion.&quot;);
+}
+noInline(assert);
+
+let objs = [];
+let keyPool = [];
+const numKeys = 800;
+for (let i = 0; i &lt; numKeys; ++i)
+    keyPool.push(i + &quot;foo&quot;);
+
+for (let i = 0; i &lt; 10000; i++) {
+    let num = (Math.random() * numKeys) | 0;
+    let o = {};
+    for (let i = 0; i &lt; num; ++i) {
+        o[keyPool[i]] = 25; 
+    }
+    objs.push(o);
+}
+
+function foo(o) {
+    let props = Object.getOwnPropertyNames(o);
+    for (let i = 0; i &lt; props.length; ++i) {
+        let s = props[i];
+        assert(o.hasOwnProperty(s));
+    }
+}
+noInline(foo);
+
+let start = Date.now();
+for (let o of objs) {
+    foo(o);
+}
+const verbose = false;
+if (verbose)
+    print(Date.now() - start);
</ins></span></pre></div>
<a id="trunkJSTestsstresshasownpropertynamecachesymbolkeysjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js (0 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js                                (rev 0)
+++ trunk/JSTests/stress/has-own-property-name-cache-symbol-keys.js        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion.&quot;);
+}
+noInline(assert);
+
+let objs = [];
+let symbolPool = [];
+const numSymbols = 800;
+for (let i = 0; i &lt; numSymbols; ++i)
+    symbolPool.push(Symbol());
+
+for (let i = 0; i &lt; 10000; i++) {
+    let num = (Math.random() * numSymbols) | 0;
+    let o = {};
+    for (let i = 0; i &lt; num; ++i) {
+        o[symbolPool[i]] = 25; 
+    }
+    objs.push(o);
+}
+
+function foo(o) {
+    let props = Object.getOwnPropertySymbols(o);
+    for (let i = 0; i &lt; props.length; ++i) {
+        let s = props[i];
+        assert(o.hasOwnProperty(s));
+    }
+}
+noInline(foo);
+
+let start = Date.now();
+for (let o of objs) {
+    foo(o);
+}
</ins></span></pre></div>
<a id="trunkJSTestsstresshasownpropertynamecachesymbolsandstringsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js (0 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js                                (rev 0)
+++ trunk/JSTests/stress/has-own-property-name-cache-symbols-and-strings.js        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+
+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion.&quot;);
+}
+noInline(assert);
+
+let objs = [];
+let keyPool = [];
+let symbolPool = [];
+const numKeys = 500;
+for (let i = 0; i &lt; numKeys; ++i) {
+    keyPool.push(i + &quot;foo&quot;);
+    symbolPool.push(Symbol(&quot;Foo&quot;));
+}
+
+for (let i = 0; i &lt; 10000; i++) {
+    let num = (Math.random() * numKeys) | 0;
+    let o = {};
+    for (let i = 0; i &lt; num; ++i) {
+        o[keyPool[i]] = 25; 
+        o[symbolPool[i]] = 40; 
+    }
+    objs.push(o);
+}
+
+let time = 0;
+function foo(o) {
+    let props = Object.getOwnPropertyNames(o);
+    props.push(...Object.getOwnPropertySymbols(o));
+    let start = Date.now();
+    for (let i = 0; i &lt; props.length; ++i) {
+        let s = props[i];
+        assert(o.hasOwnProperty(s));
+    }
+    time += Date.now() - start;
+}
+noInline(foo);
+
+for (let o of objs) {
+    foo(o);
+}
+const verbose = false;
+if (verbose)
+    print(time);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -1,3 +1,90 @@
</span><ins>+2016-09-19  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        Make HasOwnProperty faster
+        https://bugs.webkit.org/show_bug.cgi?id=161708
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds a cache for HasOwnProperty. The cache holds tuples
+        of {StructureID, UniquedStringImpl*, boolean} where the boolean indicates
+        the result of performing hasOwnProperty on an object with StructureID and
+        UniquedStringImpl*. If the cache contains an item, we can be guaranteed
+        that it contains the same result as performing hasOwnProperty on an
+        object O with a given structure and key. To guarantee this, we only add
+        items into the cache when the Structure of the given item is cacheable.
+
+        The caching strategy is simple: when adding new items into the cache,
+        we will evict any item that was in the location that the new item
+        is hashed into. We also clear the cache on every GC. This strategy
+        proves to be successful on speedometer, which sees a cache hit rate
+        over 90%. This caching strategy is now inlined into the DFG/FTL JITs
+        by now recognizing hasOwnProperty as an intrinsic with the corresponding
+        HasOwnProperty node. The goal of the node is to emit inlined code for
+        the cache lookup to prevent the overhead of the call for the common
+        case where we get a cache hit.
+
+        I'm seeing around a 1% to 1.5% percent improvement on Speedometer on
+        my machine. Hopefully the perf bots agree with my machine.
+
+        This patch also speeds up the microbenchmark I added by 2.5x.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::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):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
+        * heap/Heap.cpp:
+        (JSC::Heap::collectImpl):
+        * jit/JITOperations.h:
+        * runtime/HasOwnPropertyCache.h: Added.
+        (JSC::HasOwnPropertyCache::Entry::offsetOfStructureID):
+        (JSC::HasOwnPropertyCache::Entry::offsetOfImpl):
+        (JSC::HasOwnPropertyCache::Entry::offsetOfResult):
+        (JSC::HasOwnPropertyCache::operator delete):
+        (JSC::HasOwnPropertyCache::create):
+        (JSC::HasOwnPropertyCache::hash):
+        (JSC::HasOwnPropertyCache::get):
+        (JSC::HasOwnPropertyCache::tryAdd):
+        (JSC::HasOwnPropertyCache::clear):
+        (JSC::VM::ensureHasOwnPropertyCache):
+        * runtime/Intrinsic.h:
+        * runtime/JSObject.h:
+        * runtime/JSObjectInlines.h:
+        (JSC::JSObject::hasOwnProperty):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::ObjectPrototype::finishCreation):
+        (JSC::objectProtoFuncHasOwnProperty):
+        * runtime/Symbol.h:
+        * runtime/VM.cpp:
+        * runtime/VM.h:
+        (JSC::VM::hasOwnPropertyCache):
+
</ins><span class="cx"> 2016-09-19  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Make the rounding-related nodes support any type
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -1334,6 +1334,7 @@
</span><span class="cx">                 79CFC6F01C33B10000C768EA /* LLIntPCRanges.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 79D5CD5A1C1106A900CECA07 /* SamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */; };
</span><span class="cx">                 79D5CD5B1C1106A900CECA07 /* SamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 79D5CD591C1106A900CECA07 /* SamplingProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */; };
</span><span class="cx">                 79EE0C001B4AFB85000385C9 /* VariableEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 79F8FC1E1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79F8FC1C1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp */; };
</span><span class="lines">@@ -3578,6 +3579,7 @@
</span><span class="cx">                 79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntPCRanges.h; path = llint/LLIntPCRanges.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingProfiler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 79D5CD591C1106A900CECA07 /* SamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingProfiler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HasOwnPropertyCache.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableEnvironment.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableEnvironment.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 79F8FC1C1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMaximalFlushInsertionPhase.cpp; path = dfg/DFGMaximalFlushInsertionPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5805,6 +5807,7 @@
</span><span class="cx">                                 BC337BDE0E1AF0B80076918A /* GetterSetter.h */,
</span><span class="cx">                                 79A0907D1D768465008B889B /* HashMapImpl.cpp */,
</span><span class="cx">                                 79A0907E1D768465008B889B /* HashMapImpl.h */,
</span><ins>+                                79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */,
</ins><span class="cx">                                 933A349D038AE80F008635CE /* Identifier.cpp */,
</span><span class="cx">                                 933A349A038AE7C6008635CE /* Identifier.h */,
</span><span class="cx">                                 8606DDE918DA44AB00A383D0 /* IdentifierInlines.h */,
</span><span class="lines">@@ -8288,6 +8291,7 @@
</span><span class="cx">                                 0FF42748158EBE91004CB9FF /* udis86_syn.h in Headers */,
</span><span class="cx">                                 0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */,
</span><span class="cx">                                 A7E5AB391799E4B200D2833D /* UDis86Disassembler.h in Headers */,
</span><ins>+                                79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */,
</ins><span class="cx">                                 A7A8AF4117ADB5F3005AB174 /* Uint16Array.h in Headers */,
</span><span class="cx">                                 866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */,
</span><span class="cx">                                 A7A8AF4217ADB5F3005AB174 /* Uint32Array.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -2665,6 +2665,12 @@
</span><span class="cx">         forNode(node).setType(SpecBoolean);
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+
+    case HasOwnProperty: {
+        clobberWorld(node-&gt;origin.semantic, clobberLimit);
+        forNode(node).setType(SpecBoolean);
+        break;
+    }
</ins><span class="cx">             
</span><span class="cx">     case GetEnumerableLength: {
</span><span class="cx">         forNode(node).setType(SpecInt32Only);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -2561,6 +2561,26 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case HasOwnPropertyIntrinsic: {
+        if (argumentCountIncludingThis != 2)
+            return false;
+
+        // This can be racy, that's fine. We know that once we observe that this is created,
+        // that it will never be destroyed until the VM is destroyed. It's unlikely that
+        // we'd ever get to the point where we inline this as an intrinsic without the
+        // cache being created, however, it's possible if we always throw exceptions inside
+        // hasOwnProperty.
+        if (!m_vm-&gt;hasOwnPropertyCache())
+            return false;
+
+        insertChecks();
+        Node* object = get(virtualRegisterForArgument(0, registerOffset));
+        Node* key = get(virtualRegisterForArgument(1, registerOffset));
+        Node* result = addToGraph(HasOwnProperty, object, key);
+        set(VirtualRegister(resultOperand), result);
+        return true;
+    }
+
</ins><span class="cx">     default:
</span><span class="cx">         return false;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -501,6 +501,7 @@
</span><span class="cx">     case ConstructForwardVarargs:
</span><span class="cx">     case ToPrimitive:
</span><span class="cx">     case In:
</span><ins>+    case HasOwnProperty:
</ins><span class="cx">     case ValueAdd:
</span><span class="cx">     case SetFunctionName:
</span><span class="cx">     case GetDynamicVar:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -173,6 +173,7 @@
</span><span class="cx">     case ToString:
</span><span class="cx">     case CallStringConstructor:
</span><span class="cx">     case In:
</span><ins>+    case HasOwnProperty:
</ins><span class="cx">     case Jump:
</span><span class="cx">     case Branch:
</span><span class="cx">     case Switch:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -1311,6 +1311,22 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case HasOwnProperty: {
+            fixEdge&lt;ObjectUse&gt;(node-&gt;child1());
+#if CPU(X86) &amp;&amp; USE(JSVALUE32_64)
+            // We don't have enough registers to do anything interesting on x86.
+            fixEdge&lt;UntypedUse&gt;(node-&gt;child2());
+#else
+            if (node-&gt;child2()-&gt;shouldSpeculateString())
+                fixEdge&lt;StringUse&gt;(node-&gt;child2());
+            else if (node-&gt;child2()-&gt;shouldSpeculateSymbol())
+                fixEdge&lt;SymbolUse&gt;(node-&gt;child2());
+            else
+                fixEdge&lt;UntypedUse&gt;(node-&gt;child2());
+#endif
+            break;
+        }
+
</ins><span class="cx">         case Check: {
</span><span class="cx">             m_graph.doToChildren(
</span><span class="cx">                 node,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -331,6 +331,7 @@
</span><span class="cx">     macro(ProfileType, NodeMustGenerate) \
</span><span class="cx">     macro(ProfileControlFlow, NodeMustGenerate) \
</span><span class="cx">     macro(SetFunctionName, NodeMustGenerate) \
</span><ins>+    macro(HasOwnProperty, NodeResultBoolean) \
</ins><span class="cx">     \
</span><span class="cx">     macro(CreateActivation, NodeResultJS) \
</span><span class="cx">     \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> #include &quot;FTLForOSREntryJITCode.h&quot;
</span><span class="cx"> #include &quot;FTLOSREntry.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;HostCallReturnValue.h&quot;
</span><span class="cx"> #include &quot;Interpreter.h&quot;
</span><span class="cx"> #include &quot;JIT.h&quot;
</span><span class="lines">@@ -1673,6 +1674,28 @@
</span><span class="cx">     return sizeOfVarargs(exec, arguments, firstVarArgOffset);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+int32_t JIT_OPERATION operationHasOwnProperty(ExecState* exec, JSObject* thisObject, EncodedJSValue encodedKey)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue key = JSValue::decode(encodedKey);
+    Identifier propertyName = key.toPropertyKey(exec);
+    if (UNLIKELY(scope.exception()))
+        return false;
+
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
+    bool result = thisObject-&gt;hasOwnProperty(exec, propertyName.impl(), slot);
+    if (UNLIKELY(scope.exception()))
+        return false;
+
+    HasOwnPropertyCache* hasOwnPropertyCache = vm.hasOwnPropertyCache();
+    ASSERT(hasOwnPropertyCache);
+    hasOwnPropertyCache-&gt;tryAdd(vm, slot, thisObject, propertyName.impl(), result);
+    return result;
+}
+
</ins><span class="cx"> void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -177,6 +177,8 @@
</span><span class="cx"> int32_t JIT_OPERATION operationSizeOfVarargs(ExecState*, EncodedJSValue arguments, int32_t firstVarArgOffset);
</span><span class="cx"> void JIT_OPERATION operationLoadVarargs(ExecState*, int32_t firstElementDest, EncodedJSValue arguments, int32_t offset, int32_t length, int32_t mandatoryMinimum);
</span><span class="cx"> 
</span><ins>+int32_t JIT_OPERATION operationHasOwnProperty(ExecState*, JSObject*, EncodedJSValue);
+
</ins><span class="cx"> JSCell* JIT_OPERATION operationResolveScope(ExecState*, JSScope*, UniquedStringImpl*);
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetDynamicVar(ExecState*, JSObject* scope, UniquedStringImpl*, unsigned);
</span><span class="cx"> void JIT_OPERATION operationPutDynamicVar(ExecState*, JSObject* scope, EncodedJSValue, UniquedStringImpl*, unsigned);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -910,6 +910,10 @@
</span><span class="cx">             setPrediction(SpecBoolean);
</span><span class="cx">             break;
</span><span class="cx"> 
</span><ins>+        case HasOwnProperty:
+            setPrediction(SpecBoolean);
+            break;
+
</ins><span class="cx">         case GetEnumerableLength: {
</span><span class="cx">             setPrediction(SpecInt32Only);
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -284,6 +284,7 @@
</span><span class="cx">     case NewStringObject:
</span><span class="cx">     case MakeRope:
</span><span class="cx">     case In:
</span><ins>+    case HasOwnProperty:
</ins><span class="cx">     case CreateActivation:
</span><span class="cx">     case CreateDirectArguments:
</span><span class="cx">     case CreateScopedArguments:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -982,6 +982,11 @@
</span><span class="cx">         m_jit.setupArgumentsWithExecState(TrustedImmPtr(index), arg1);
</span><span class="cx">         return appendCallSetResult(operation, result);
</span><span class="cx">     }
</span><ins>+    JITCompiler::Call callOperation(Z_JITOperation_EOI operation, GPRReg result, GPRReg obj, GPRReg impl)
+    {
+        m_jit.setupArgumentsWithExecState(obj, impl);
+        return appendCallSetResult(operation, result);
+    }
</ins><span class="cx">     JITCompiler::Call callOperation(P_JITOperation_ESt operation, GPRReg result, Structure* structure)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
</span><span class="lines">@@ -1309,19 +1314,21 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> #if USE(JSVALUE64)
</span><del>-
</del><ins>+    JITCompiler::Call callOperation(Z_JITOperation_EOJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallSetResult(operation, result);
+    }
</ins><span class="cx">     JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
</span><span class="cx">         return appendCallSetResult(operation, result);
</span><span class="cx">     }
</span><del>-
</del><span class="cx">     JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(arg1.gpr(), arg2.gpr(), mathIC);
</span><span class="cx">         return appendCallSetResult(operation, result.gpr());
</span><span class="cx">     }
</span><del>-
</del><span class="cx">     JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg result, GPRReg arg1, GPRReg arg2, UniquedStringImpl* uid)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(uid));
</span><span class="lines">@@ -1749,7 +1756,11 @@
</span><span class="cx">         return appendCallSetResult(operation, result);
</span><span class="cx">     }
</span><span class="cx"> #else // USE(JSVALUE32_64)
</span><del>-
</del><ins>+    JITCompiler::Call callOperation(Z_JITOperation_EOJ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR());
+        return appendCallSetResult(operation, result);
+    }
</ins><span class="cx">     JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2, GPRReg arg3)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), arg3);
</span><span class="lines">@@ -3522,6 +3533,8 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class SpeculateCellOperand {
</span><ins>+    WTF_MAKE_NONCOPYABLE(SpeculateCellOperand);
+
</ins><span class="cx"> public:
</span><span class="cx">     explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</span><span class="cx">         : m_jit(jit)
</span><span class="lines">@@ -3536,6 +3549,16 @@
</span><span class="cx">             gpr();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    explicit SpeculateCellOperand(SpeculateCellOperand&amp;&amp; other)
+    {
+        m_jit = other.m_jit;
+        m_edge = other.m_edge;
+        m_gprOrInvalid = other.m_gprOrInvalid;
+
+        other.m_gprOrInvalid = InvalidGPRReg;
+        other.m_edge = Edge();
+    }
+
</ins><span class="cx">     ~SpeculateCellOperand()
</span><span class="cx">     {
</span><span class="cx">         if (!m_edge)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include &quot;DFGSlowPathGenerator.h&quot;
</span><span class="cx"> #include &quot;DirectArguments.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;HashMapImpl.h&quot;
</span><span class="cx"> #include &quot;JSEnvironmentRecord.h&quot;
</span><span class="cx"> #include &quot;JSLexicalEnvironment.h&quot;
</span><span class="lines">@@ -4888,6 +4889,122 @@
</span><span class="cx">         compileIn(node);
</span><span class="cx">         break;
</span><span class="cx"> 
</span><ins>+    case HasOwnProperty: {
+#if CPU(X86)
+        ASSERT(node-&gt;child2().useKind() == UntypedUse);
+        SpeculateCellOperand object(this, node-&gt;child1());
+        JSValueOperand key(this, node-&gt;child2());
+        GPRTemporary result(this, Reuse, object);
+
+        JSValueRegs keyRegs = key.jsValueRegs();
+        GPRReg objectGPR = object.gpr();
+        GPRReg resultGPR = result.gpr();
+        flushRegisters();
+        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyRegs);
+        booleanResult(resultGPR, node);
+#else
+        SpeculateCellOperand object(this, node-&gt;child1());
+        GPRTemporary uniquedStringImpl(this);
+        GPRTemporary temp(this);
+        GPRTemporary hash(this);
+        GPRTemporary structureID(this);
+        GPRTemporary result(this);
+
+        Optional&lt;SpeculateCellOperand&gt; keyAsCell;
+        Optional&lt;JSValueOperand&gt; keyAsValue;
+        JSValueRegs keyRegs;
+        if (node-&gt;child2().useKind() == UntypedUse) {
+            keyAsValue = JSValueOperand(this, node-&gt;child2());
+            keyRegs = keyAsValue-&gt;jsValueRegs();
+        } else {
+            ASSERT(node-&gt;child2().useKind() == StringUse || node-&gt;child2().useKind() == SymbolUse);
+            keyAsCell = SpeculateCellOperand(this, node-&gt;child2());
+            keyRegs = JSValueRegs::payloadOnly(keyAsCell-&gt;gpr());
+        }
+
+        GPRReg objectGPR = object.gpr();
+        GPRReg implGPR = uniquedStringImpl.gpr();
+        GPRReg tempGPR = temp.gpr();
+        GPRReg hashGPR = hash.gpr();
+        GPRReg structureIDGPR = structureID.gpr();
+        GPRReg resultGPR = result.gpr();
+
+        speculateObject(node-&gt;child1());
+
+        MacroAssembler::JumpList slowPath;
+        switch (node-&gt;child2().useKind()) {
+        case SymbolUse: {
+            speculateSymbol(node-&gt;child2(), keyRegs.payloadGPR());
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), Symbol::offsetOfSymbolImpl()), implGPR);
+            break;
+        }
+        case StringUse: {
+            speculateString(node-&gt;child2(), keyRegs.payloadGPR());
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            break;
+        }
+        case UntypedUse: {
+            slowPath.append(m_jit.branchIfNotCell(keyRegs));
+            auto isNotString = m_jit.branchIfNotString(keyRegs.payloadGPR());
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            auto hasUniquedImpl = m_jit.jump();
+
+            isNotString.link(&amp;m_jit);
+            slowPath.append(m_jit.branchIfNotSymbol(keyRegs.payloadGPR()));
+            m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), Symbol::offsetOfSymbolImpl()), implGPR);
+
+            hasUniquedImpl.link(&amp;m_jit);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
+        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
+        // ever load the result from the cache if the cache entry matches what we are querying for.
+        // So we either get super lucky and use zero for the hash and somehow collide with the entity
+        // we're looking for, or we realize we're comparing against another entity, and go to the
+        // slow path anyways.
+        m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
+        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
+        m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
+        m_jit.add32(structureIDGPR, hashGPR);
+        m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
+        m_jit.mul32(TrustedImm32(sizeof(HasOwnPropertyCache::Entry)), hashGPR, hashGPR);
+        ASSERT(m_jit.vm()-&gt;hasOwnPropertyCache());
+        m_jit.move(TrustedImmPtr(m_jit.vm()-&gt;hasOwnPropertyCache()), tempGPR);
+        slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual, 
+            MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
+        m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
+        m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
+        slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
+        auto done = m_jit.jump();
+
+        slowPath.link(&amp;m_jit);
+        silentSpillAllRegisters(resultGPR);
+        if (node-&gt;child2().useKind() != UntypedUse) {
+            m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), tempGPR);
+            keyRegs = JSValueRegs(tempGPR, keyRegs.payloadGPR());
+        }
+        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyRegs);
+        silentFillAllRegisters(resultGPR);
+        m_jit.exceptionCheck();
+
+        done.link(&amp;m_jit);
+        booleanResult(resultGPR, node);
+#endif // CPU(X86)
+        break;
+    }
+
</ins><span class="cx">     case StoreBarrier: {
</span><span class="cx">         compileStoreBarrier(node);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> #include &quot;DFGSlowPathGenerator.h&quot;
</span><span class="cx"> #include &quot;DirectArguments.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;JSEnvironmentRecord.h&quot;
</span><span class="cx"> #include &quot;JSLexicalEnvironment.h&quot;
</span><span class="lines">@@ -4628,7 +4629,7 @@
</span><span class="cx">         m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
</span><span class="cx">         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
</span><span class="cx">         m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
</span><del>-        m_jit.urshift64(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
</del><ins>+        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
</ins><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><span class="lines">@@ -4935,6 +4936,106 @@
</span><span class="cx">     case In:
</span><span class="cx">         compileIn(node);
</span><span class="cx">         break;
</span><ins>+
+    case HasOwnProperty: {
+        SpeculateCellOperand object(this, node-&gt;child1());
+        GPRTemporary uniquedStringImpl(this);
+        GPRTemporary temp(this);
+        GPRTemporary hash(this);
+        GPRTemporary structureID(this);
+        GPRTemporary result(this);
+
+        Optional&lt;SpeculateCellOperand&gt; keyAsCell;
+        Optional&lt;JSValueOperand&gt; keyAsValue;
+        GPRReg keyGPR;
+        if (node-&gt;child2().useKind() == UntypedUse) {
+            keyAsValue = JSValueOperand(this, node-&gt;child2());
+            keyGPR = keyAsValue-&gt;gpr();
+        } else {
+            ASSERT(node-&gt;child2().useKind() == StringUse || node-&gt;child2().useKind() == SymbolUse);
+            keyAsCell = SpeculateCellOperand(this, node-&gt;child2());
+            keyGPR = keyAsCell-&gt;gpr();
+        }
+
+        GPRReg objectGPR = object.gpr();
+        GPRReg implGPR = uniquedStringImpl.gpr();
+        GPRReg tempGPR = temp.gpr();
+        GPRReg hashGPR = hash.gpr();
+        GPRReg structureIDGPR = structureID.gpr();
+        GPRReg resultGPR = result.gpr();
+
+        speculateObject(node-&gt;child1());
+
+        MacroAssembler::JumpList slowPath;
+        switch (node-&gt;child2().useKind()) {
+        case SymbolUse: {
+            speculateSymbol(node-&gt;child2(), keyGPR);
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
+            break;
+        }
+        case StringUse: {
+            speculateString(node-&gt;child2(), keyGPR);
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            break;
+        }
+        case UntypedUse: {
+            slowPath.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
+            auto isNotString = m_jit.branchIfNotString(keyGPR);
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
+            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
+            slowPath.append(m_jit.branchTest32(
+                MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
+                MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
+            auto hasUniquedImpl = m_jit.jump();
+
+            isNotString.link(&amp;m_jit);
+            slowPath.append(m_jit.branchIfNotSymbol(keyGPR));
+            m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
+
+            hasUniquedImpl.link(&amp;m_jit);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
+        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
+        // ever load the result from the cache if the cache entry matches what we are querying for.
+        // So we either get super lucky and use zero for the hash and somehow collide with the entity
+        // we're looking for, or we realize we're comparing against another entity, and go to the
+        // slow path anyways.
+        m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
+        m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
+        m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
+        m_jit.add32(structureIDGPR, hashGPR);
+        m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
+        static_assert(sizeof(HasOwnPropertyCache::Entry) == 16, &quot;Strong assumption of that here.&quot;);
+        m_jit.lshift32(TrustedImm32(4), hashGPR);
+        ASSERT(m_jit.vm()-&gt;hasOwnPropertyCache());
+        m_jit.move(TrustedImmPtr(m_jit.vm()-&gt;hasOwnPropertyCache()), tempGPR);
+        slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual, 
+            MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
+        m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
+        m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
+        slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
+        auto done = m_jit.jump();
+
+        slowPath.link(&amp;m_jit);
+        silentSpillAllRegisters(resultGPR);
+        callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyGPR);
+        silentFillAllRegisters(resultGPR);
+        m_jit.exceptionCheck();
+
+        done.link(&amp;m_jit);
+        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
+        jsValueResult(resultGPR, node, DataFormatJSBoolean);
+        break;
+    }
</ins><span class="cx">         
</span><span class="cx">     case CountExecution:
</span><span class="cx">         m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node-&gt;executionCounter()-&gt;address()));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -309,6 +309,10 @@
</span><span class="cx">                     // while the inline one will not take a storage child at all.
</span><span class="cx">                     // https://bugs.webkit.org/show_bug.cgi?id=159602
</span><span class="cx">                     break;
</span><ins>+                case HasOwnProperty: {
+                    VALIDATE((node), !!m_graph.m_vm.hasOwnPropertyCache());
+                    break;
+                }
</ins><span class="cx">                 default:
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -31,9 +31,11 @@
</span><span class="cx"> #include &quot;B3Value.h&quot;
</span><span class="cx"> #include &quot;DFGArrayMode.h&quot;
</span><span class="cx"> #include &quot;FTLAbstractHeap.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;IndexingType.h&quot;
</span><span class="cx"> #include &quot;JSMap.h&quot;
</span><span class="cx"> #include &quot;JSSet.h&quot;
</span><ins>+#include &quot;Symbol.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace FTL {
</span><span class="cx"> 
</span><span class="lines">@@ -110,6 +112,7 @@
</span><span class="cx">     macro(HashMapImpl_buffer,  HashMapImpl&lt;HashMapBucket&lt;HashMapBucketDataKey&gt;&gt;::offsetOfBuffer()) \
</span><span class="cx">     macro(HashMapBucket_value, HashMapBucket&lt;HashMapBucketDataKeyValue&gt;::offsetOfValue()) \
</span><span class="cx">     macro(HashMapBucket_key, HashMapBucket&lt;HashMapBucketDataKeyValue&gt;::offsetOfKey()) \
</span><ins>+    macro(Symbol_symbolImpl, Symbol::offsetOfSymbolImpl()) \
</ins><span class="cx"> 
</span><span class="cx"> #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
</span><span class="cx">     macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \
</span><span class="lines">@@ -128,7 +131,8 @@
</span><span class="cx">     macro(scopedArgumentsTableArguments, 0, sizeof(int32_t)) \
</span><span class="cx">     macro(singleCharacterStrings, 0, sizeof(JSString*)) \
</span><span class="cx">     macro(structureTable, 0, sizeof(Structure*)) \
</span><del>-    macro(variables, 0, sizeof(Register))
</del><ins>+    macro(variables, 0, sizeof(Register)) \
+    macro(HasOwnPropertyCache, 0, sizeof(HasOwnPropertyCache::Entry)) \
</ins><span class="cx">     
</span><span class="cx"> #define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \
</span><span class="cx">     macro(properties)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -181,6 +181,7 @@
</span><span class="cx">     case ThrowReferenceError:
</span><span class="cx">     case Unreachable:
</span><span class="cx">     case In:
</span><ins>+    case HasOwnProperty:
</ins><span class="cx">     case IsCellWithType:
</span><span class="cx">     case MapHash:
</span><span class="cx">     case GetMapBucket:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -632,6 +632,9 @@
</span><span class="cx">         case In:
</span><span class="cx">             compileIn();
</span><span class="cx">             break;
</span><ins>+        case HasOwnProperty:
+            compileHasOwnProperty();
+            break;
</ins><span class="cx">         case PutById:
</span><span class="cx">         case PutByIdDirect:
</span><span class="cx">         case PutByIdFlush:
</span><span class="lines">@@ -6772,6 +6775,108 @@
</span><span class="cx">         setJSValue(vmCall(Int64, m_out.operation(operationGenericIn), m_callFrame, cell, lowJSValue(m_node-&gt;child1())));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void compileHasOwnProperty()
+    {
+        LBasicBlock slowCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+        LBasicBlock lastNext = nullptr;
+
+        LValue object = lowObject(m_node-&gt;child1());
+        LValue uniquedStringImpl;
+        LValue keyAsValue = nullptr;
+        switch (m_node-&gt;child2().useKind()) {
+        case StringUse: {
+            LBasicBlock isNonEmptyString = m_out.newBlock();
+            LBasicBlock isAtomicString = m_out.newBlock();
+
+            keyAsValue = lowString(m_node-&gt;child2());
+            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
+            m_out.branch(m_out.notNull(uniquedStringImpl), usually(isNonEmptyString), rarely(slowCase));
+
+            lastNext = m_out.appendTo(isNonEmptyString, isAtomicString);
+            LValue isNotAtomic = m_out.testIsZero32(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
+            m_out.branch(isNotAtomic, rarely(slowCase), usually(isAtomicString));
+
+            m_out.appendTo(isAtomicString, slowCase);
+            break;
+        }
+        case SymbolUse: {
+            keyAsValue = lowSymbol(m_node-&gt;child2());
+            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.Symbol_symbolImpl);
+            lastNext = m_out.insertNewBlocksBefore(slowCase);
+            break;
+        }
+        case UntypedUse: {
+            LBasicBlock isCellCase = m_out.newBlock();
+            LBasicBlock isStringCase = m_out.newBlock();
+            LBasicBlock notStringCase = m_out.newBlock();
+            LBasicBlock isNonEmptyString = m_out.newBlock();
+            LBasicBlock isSymbolCase = m_out.newBlock();
+            LBasicBlock hasUniquedStringImpl = m_out.newBlock();
+
+            keyAsValue = lowJSValue(m_node-&gt;child2());
+            m_out.branch(isCell(keyAsValue), usually(isCellCase), rarely(slowCase));
+
+            lastNext = m_out.appendTo(isCellCase, isStringCase);
+            m_out.branch(isString(keyAsValue), unsure(isStringCase), unsure(notStringCase));
+
+            m_out.appendTo(isStringCase, isNonEmptyString);
+            LValue implFromString = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
+            ValueFromBlock stringResult = m_out.anchor(implFromString);
+            m_out.branch(m_out.notNull(implFromString), usually(isNonEmptyString), rarely(slowCase));
+
+            m_out.appendTo(isNonEmptyString, notStringCase);
+            LValue isNotAtomic = m_out.testIsZero32(m_out.load32(implFromString, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
+            m_out.branch(isNotAtomic, rarely(slowCase), usually(hasUniquedStringImpl));
+
+            m_out.appendTo(notStringCase, isSymbolCase);
+            m_out.branch(isSymbol(keyAsValue), unsure(isSymbolCase), unsure(slowCase));
+
+            m_out.appendTo(isSymbolCase, hasUniquedStringImpl);
+            ValueFromBlock symbolResult = m_out.anchor(m_out.loadPtr(keyAsValue, m_heaps.Symbol_symbolImpl));
+            m_out.jump(hasUniquedStringImpl);
+
+            m_out.appendTo(hasUniquedStringImpl, slowCase);
+            uniquedStringImpl = m_out.phi(pointerType(), stringResult, symbolResult);
+            break;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        ASSERT(keyAsValue);
+
+        // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
+        // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
+        // ever load the result from the cache if the cache entry matches what we are querying for.
+        // So we either get super lucky and use zero for the hash and somehow collide with the entity
+        // we're looking for, or we realize we're comparing against another entity, and go to the
+        // slow path anyways.
+        LValue hash = m_out.lShr(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
+
+        LValue structureID = m_out.load32(object, m_heaps.JSCell_structureID);
+        LValue index = m_out.add(hash, structureID);
+        index = m_out.zeroExtPtr(m_out.bitAnd(index, m_out.constInt32(HasOwnPropertyCache::mask)));
+        ASSERT(vm().hasOwnPropertyCache());
+        LValue cache = m_out.constIntPtr(vm().hasOwnPropertyCache());
+
+        IndexedAbstractHeap&amp; heap = m_heaps.HasOwnPropertyCache;
+        LValue sameStructureID = m_out.equal(structureID, m_out.load32(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfStructureID())));
+        LValue sameImpl = m_out.equal(uniquedStringImpl, m_out.loadPtr(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfImpl())));
+        ValueFromBlock fastResult = m_out.anchor(m_out.load8ZeroExt32(m_out.baseIndex(heap, cache, index, JSValue(), HasOwnPropertyCache::Entry::offsetOfResult())));
+        LValue cacheHit = m_out.bitAnd(sameStructureID, sameImpl);
+
+        m_out.branch(m_out.notZero32(cacheHit), usually(continuation), rarely(slowCase));
+
+        m_out.appendTo(slowCase, continuation);
+        ValueFromBlock slowResult;
+        slowResult = m_out.anchor(vmCall(Int32, m_out.operation(operationHasOwnProperty), m_callFrame, object, keyAsValue));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setBoolean(m_out.phi(Int32, fastResult, slowResult));
+    }
+
</ins><span class="cx">     void compileOverridesHasInstance()
</span><span class="cx">     {
</span><span class="cx">         JSFunction* defaultHasInstanceFunction = jsCast&lt;JSFunction*&gt;(m_node-&gt;cellOperand()-&gt;value());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;GCActivityCallback.h&quot;
</span><span class="cx"> #include &quot;GCIncomingRefCountedSetInlines.h&quot;
</span><span class="cx"> #include &quot;GCTypeMap.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;HeapHelperPool.h&quot;
</span><span class="cx"> #include &quot;HeapIterationScope.h&quot;
</span><span class="cx"> #include &quot;HeapProfiler.h&quot;
</span><span class="lines">@@ -1022,6 +1023,9 @@
</span><span class="cx">         stopAllocation();
</span><span class="cx">         prepareForMarking();
</span><span class="cx">         flushWriteBarrierBuffer();
</span><ins>+
+        if (HasOwnPropertyCache* cache = vm()-&gt;hasOwnPropertyCache())
+            cache-&gt;clear();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     markRoots(gcStartTime, stackOrigin, stackTop, calleeSavedRegisters);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -221,6 +221,8 @@
</span><span class="cx"> typedef int32_t (JIT_OPERATION *Z_JITOperation_EJOJ)(ExecState*, EncodedJSValue, JSObject*, EncodedJSValue);
</span><span class="cx"> typedef int32_t (JIT_OPERATION *Z_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
</span><span class="cx"> typedef int32_t (JIT_OPERATION *Z_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
</span><ins>+typedef int32_t (JIT_OPERATION *Z_JITOperation_EOI)(ExecState*, JSObject*, UniquedStringImpl*);
+typedef int32_t (JIT_OPERATION *Z_JITOperation_EOJ)(ExecState*, JSObject*, EncodedJSValue);
</ins><span class="cx"> typedef size_t (JIT_OPERATION *S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
</span><span class="cx"> typedef size_t (JIT_OPERATION *S_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
</span><span class="cx"> typedef size_t (JIT_OPERATION *S_JITOperation_EGJJ)(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeHasOwnPropertyCacheh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/runtime/HasOwnPropertyCache.h (0 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/HasOwnPropertyCache.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/runtime/HasOwnPropertyCache.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -0,0 +1,124 @@
</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. 
+ */
+
+#pragma once
+
+#include &quot;JSProxy.h&quot;
+#include &quot;PropertySlot.h&quot;
+#include &quot;Structure.h&quot;
+
+namespace JSC {
+
+class HasOwnPropertyCache {
+    static const uint32_t size = 2 * 1024;
+    static_assert(!(size &amp; (size - 1)), &quot;size should be a power of two.&quot;);
+public:
+    static const uint32_t mask = size - 1;
+
+    struct Entry {
+        static ptrdiff_t offsetOfStructureID() { return OBJECT_OFFSETOF(Entry, structureID); }
+        static ptrdiff_t offsetOfImpl() { return OBJECT_OFFSETOF(Entry, impl); }
+        static ptrdiff_t offsetOfResult() { return OBJECT_OFFSETOF(Entry, result); }
+
+        UniquedStringImpl* impl;
+        StructureID structureID;
+        bool result;
+    };
+
+    HasOwnPropertyCache() = delete;
+
+    void operator delete(void* cache)
+    {
+        fastFree(cache);
+    }
+
+    static HasOwnPropertyCache* create()
+    {
+        size_t allocationSize = sizeof(Entry) * size;
+        HasOwnPropertyCache* result = static_cast&lt;HasOwnPropertyCache*&gt;(fastMalloc(allocationSize));
+        result-&gt;clear();
+        return result;
+    }
+
+    ALWAYS_INLINE static uint32_t hash(StructureID structureID, UniquedStringImpl* impl)
+    {
+        return bitwise_cast&lt;uint32_t&gt;(structureID) + impl-&gt;hash();
+    }
+
+    ALWAYS_INLINE Optional&lt;bool&gt; get(Structure* structure, PropertyName propName)
+    {
+        UniquedStringImpl* impl = propName.uid();
+        StructureID id = structure-&gt;id();
+        uint32_t index = HasOwnPropertyCache::hash(id, impl) &amp; mask;
+        Entry&amp; entry = bitwise_cast&lt;Entry*&gt;(this)[index];
+        if (entry.structureID == id &amp;&amp; entry.impl == impl)
+            return entry.result;
+        return Nullopt;
+    }
+
+    ALWAYS_INLINE void tryAdd(VM&amp; vm, PropertySlot&amp; slot, JSObject* object, PropertyName propName, bool result)
+    {
+        if (parseIndex(propName))
+            return;
+
+        if (!slot.isCacheable() &amp;&amp; !slot.isUnset())
+            return;
+
+        if (object-&gt;type() == PureForwardingProxyType || object-&gt;type() == ImpureProxyType)
+            return;
+
+        Structure* structure = object-&gt;structure(vm);
+        if (!structure-&gt;typeInfo().prohibitsPropertyCaching()
+            &amp;&amp; structure-&gt;propertyAccessesAreCacheable()
+            &amp;&amp; (!slot.isUnset() || structure-&gt;propertyAccessesAreCacheableForAbsence())) {
+            if (structure-&gt;isDictionary()) {
+                if (structure-&gt;hasBeenFlattenedBefore())
+                    return;
+                object-&gt;flattenDictionaryObject(vm);
+            }
+
+            ASSERT(!result == slot.isUnset());
+
+            UniquedStringImpl* impl = propName.uid();
+            StructureID id = structure-&gt;id();
+            uint32_t index = HasOwnPropertyCache::hash(id, impl) &amp; mask;
+            bitwise_cast&lt;Entry*&gt;(this)[index] = Entry{ impl, id, result };
+        }
+    }
+
+    void clear()
+    {
+        memset(this, 0, sizeof(Entry) * size);
+    }
+};
+
+ALWAYS_INLINE HasOwnPropertyCache* VM::ensureHasOwnPropertyCache()
+{
+    if (UNLIKELY(!m_hasOwnPropertyCache))
+        m_hasOwnPropertyCache = std::unique_ptr&lt;HasOwnPropertyCache&gt;(HasOwnPropertyCache::create());
+    return m_hasOwnPropertyCache.get();
+}
+
+} // namespace JSC
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIntrinsich"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Intrinsic.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Intrinsic.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/Intrinsic.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -65,6 +65,7 @@
</span><span class="cx">     JSMapGetIntrinsic,
</span><span class="cx">     JSMapHasIntrinsic,
</span><span class="cx">     JSSetHasIntrinsic,
</span><ins>+    HasOwnPropertyIntrinsic,
</ins><span class="cx"> 
</span><span class="cx">     // Getter intrinsics.
</span><span class="cx">     TypedArrayLengthIntrinsic,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -523,6 +523,7 @@
</span><span class="cx">     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
</span><span class="cx">     bool hasPropertyGeneric(ExecState*, PropertyName, PropertySlot::InternalMethodType) const;
</span><span class="cx">     bool hasPropertyGeneric(ExecState*, unsigned propertyName, PropertySlot::InternalMethodType) const;
</span><ins>+    bool hasOwnProperty(ExecState*, PropertyName, PropertySlot&amp;) const;
</ins><span class="cx">     bool hasOwnProperty(ExecState*, PropertyName) const;
</span><span class="cx">     bool hasOwnProperty(ExecState*, unsigned) const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -199,14 +199,20 @@
</span><span class="cx"> 
</span><span class="cx"> // HasOwnProperty(O, P) from section 7.3.11 in the spec.
</span><span class="cx"> // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty
</span><del>-ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
</del><ins>+ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot&amp; slot) const
</ins><span class="cx"> {
</span><del>-    PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
</del><ins>+    ASSERT(slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty);
</ins><span class="cx">     if (LIKELY(const_cast&lt;JSObject*&gt;(this)-&gt;methodTable(exec-&gt;vm())-&gt;getOwnPropertySlot == JSObject::getOwnPropertySlot))
</span><span class="cx">         return JSObject::getOwnPropertySlot(const_cast&lt;JSObject*&gt;(this), exec, propertyName, slot);
</span><span class="cx">     return const_cast&lt;JSObject*&gt;(this)-&gt;methodTable(exec-&gt;vm())-&gt;getOwnPropertySlot(const_cast&lt;JSObject*&gt;(this), exec, propertyName, slot);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
+{
+    PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+    return hasOwnProperty(exec, propertyName, slot);
+}
+
</ins><span class="cx"> ALWAYS_INLINE bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const
</span><span class="cx"> {
</span><span class="cx">     PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeObjectPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;Error.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;JSFunction.h&quot;
</span><span class="cx"> #include &quot;JSString.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="lines">@@ -60,7 +61,7 @@
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;toString, objectProtoFuncToString, DontEnum, 0);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;valueOf, objectProtoFuncValueOf, DontEnum, 0);
</span><del>-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1);
</del><ins>+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1, HasOwnPropertyIntrinsic);
</ins><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;__defineGetter__, objectProtoFuncDefineGetter, DontEnum, 2);
</span><span class="lines">@@ -97,9 +98,24 @@
</span><span class="cx">     if (UNLIKELY(scope.exception()))
</span><span class="cx">         return JSValue::encode(jsUndefined());
</span><span class="cx">     JSObject* thisObject = thisValue.toObject(exec);
</span><del>-    if (!thisObject)
</del><ins>+    if (UNLIKELY(!thisObject))
</ins><span class="cx">         return JSValue::encode(JSValue());
</span><del>-    return JSValue::encode(jsBoolean(thisObject-&gt;hasOwnProperty(exec, propertyName)));
</del><ins>+
+    Structure* structure = thisObject-&gt;structure(vm);
+    HasOwnPropertyCache* hasOwnPropertyCache = vm.ensureHasOwnPropertyCache();
+    if (Optional&lt;bool&gt; result = hasOwnPropertyCache-&gt;get(structure, propertyName)) {
+        ASSERT(*result == thisObject-&gt;hasOwnProperty(exec, propertyName));
+        ASSERT(!scope.exception());
+        return JSValue::encode(jsBoolean(*result));
+    }
+
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::GetOwnProperty);
+    bool result = thisObject-&gt;hasOwnProperty(exec, propertyName, slot);
+    if (UNLIKELY(scope.exception()))
+        return JSValue::encode(jsUndefined());
+
+    hasOwnPropertyCache-&gt;tryAdd(vm, slot, thisObject, propertyName, result);
+    return JSValue::encode(jsBoolean(result));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeSymbolh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Symbol.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Symbol.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/Symbol.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -59,6 +59,12 @@
</span><span class="cx">     JSObject* toObject(ExecState*, JSGlobalObject*) const;
</span><span class="cx">     double toNumber(ExecState*) const;
</span><span class="cx"> 
</span><ins>+    static ptrdiff_t offsetOfSymbolImpl()
+    {
+        // PrivateName is just a Ref&lt;SymbolImpl&gt; which can just be used as a SymbolImpl*.
+        return OBJECT_OFFSETOF(Symbol, m_privateName);
+    }
+
</ins><span class="cx"> protected:
</span><span class="cx">     static void destroy(JSCell*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.cpp (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.cpp        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/VM.cpp        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx"> #include &quot;FunctionConstructor.h&quot;
</span><span class="cx"> #include &quot;GCActivityCallback.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><ins>+#include &quot;HasOwnPropertyCache.h&quot;
</ins><span class="cx"> #include &quot;Heap.h&quot;
</span><span class="cx"> #include &quot;HeapIterationScope.h&quot;
</span><span class="cx"> #include &quot;HeapProfiler.h&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.h (206135 => 206136)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.h        2016-09-20 01:02:40 UTC (rev 206135)
+++ trunk/Source/JavaScriptCore/runtime/VM.h        2016-09-20 01:05:50 UTC (rev 206136)
</span><span class="lines">@@ -89,6 +89,7 @@
</span><span class="cx"> class HandleStack;
</span><span class="cx"> class TypeProfiler;
</span><span class="cx"> class TypeProfilerLog;
</span><ins>+class HasOwnPropertyCache;
</ins><span class="cx"> class HeapProfiler;
</span><span class="cx"> class Identifier;
</span><span class="cx"> class Interpreter;
</span><span class="lines">@@ -554,6 +555,10 @@
</span><span class="cx">     BumpPointerAllocator m_regExpAllocator;
</span><span class="cx">     ConcurrentJITLock m_regExpAllocatorLock;
</span><span class="cx"> 
</span><ins>+    std::unique_ptr&lt;HasOwnPropertyCache&gt; m_hasOwnPropertyCache;
+    ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.get(); }
+    HasOwnPropertyCache* ensureHasOwnPropertyCache();
+
</ins><span class="cx"> #if ENABLE(REGEXP_TRACING)
</span><span class="cx">     typedef ListHashSet&lt;RegExp*&gt; RTTraceList;
</span><span class="cx">     RTTraceList* m_rtTraceList;
</span></span></pre>
</div>
</div>

</body>
</html>