<!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>[184328] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/184328">184328</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2015-05-13 21:19:18 -0700 (Wed, 13 May 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/180595">r180595</a>): same-callee profiling no longer works
https://bugs.webkit.org/show_bug.cgi?id=144787

Reviewed by Filip Pizlo.

This patch introduces a DFG optimization to use NewObject node when the callee of op_create_this is
always the same JSFunction. This condition doesn't hold when the byte code creates multiple
JSFunction objects at runtime as in: function y() { return function () {} }; new y(); new y();

To enable this optimization, LLint and baseline JIT now store the last callee we saw in the newly
added fourth operand of op_create_this. We use this JSFunction's structure in DFG after verifying
our speculation that the callee is the same. To avoid recompiling the same code for different callee
objects in the polymorphic case, the special value of seenMultipleCalleeObjects() is set in
LLint and baseline JIT when multiple callees are observed.

Tests: stress/create-this-with-callee-variants.js

* bytecode/BytecodeList.json: Increased the number of operands to 5.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode): Dump the newly added callee cache.
(JSC::CodeBlock::finalizeUnconditionally): Clear the callee cache if the callee is no longer alive.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitCreateThis): Add the instruction to propertyAccessInstructions so that
we can clear the callee cache in CodeBlock::finalizeUnconditionally. Also initialize the newly added
operand.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock): Implement the optimization. Speculate the actual callee to
match the cache. Use the cached callee's structure if the speculation succeeds. Otherwise, OSR exit.
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_create_this): Go to the slow path to update the cache unless it's already marked
as seenMultipleCalleeObjects() to indicate the polymorphic behavior and/or we've OSR exited here.
(JSC::JIT::emitSlow_op_create_this):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_create_this): Ditto.
(JSC::JIT::emitSlow_op_create_this):
* llint/LowLevelInterpreter32_64.asm:
(_llint_op_create_this): Ditto.
* llint/LowLevelInterpreter64.asm:
(_llint_op_create_this): Ditto.
* runtime/CommonSlowPaths.cpp:
(slow_path_create_this): Set the callee cache to the actual callee if it's not set. If the cache has
been set to a JSFunction* different from the actual callee, set it to seenMultipleCalleeObjects().
* runtime/JSCell.h:
(JSC::JSCell::seenMultipleCalleeObjects): Added.
* runtime/WriteBarrier.h:
(JSC::WriteBarrierBase::unvalidatedGet): Removed the compile guard around it.
* tests/stress/create-this-with-callee-variants.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeListjson">trunk/Source/JavaScriptCore/bytecode/BytecodeList.json</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp">trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellh">trunk/Source/JavaScriptCore/runtime/JSCell.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeWriteBarrierh">trunk/Source/JavaScriptCore/runtime/WriteBarrier.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstresscreatethiswithcalleevariantsjs">trunk/Source/JavaScriptCore/tests/stress/create-this-with-callee-variants.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -1,3 +1,53 @@
</span><ins>+2015-05-13  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        REGRESSION(r180595): same-callee profiling no longer works
+        https://bugs.webkit.org/show_bug.cgi?id=144787
+
+        Reviewed by Filip Pizlo.
+
+        This patch introduces a DFG optimization to use NewObject node when the callee of op_create_this is
+        always the same JSFunction. This condition doesn't hold when the byte code creates multiple
+        JSFunction objects at runtime as in: function y() { return function () {} }; new y(); new y();
+
+        To enable this optimization, LLint and baseline JIT now store the last callee we saw in the newly
+        added fourth operand of op_create_this. We use this JSFunction's structure in DFG after verifying
+        our speculation that the callee is the same. To avoid recompiling the same code for different callee
+        objects in the polymorphic case, the special value of seenMultipleCalleeObjects() is set in
+        LLint and baseline JIT when multiple callees are observed.
+
+        Tests: stress/create-this-with-callee-variants.js
+
+        * bytecode/BytecodeList.json: Increased the number of operands to 5.
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode): Dump the newly added callee cache.
+        (JSC::CodeBlock::finalizeUnconditionally): Clear the callee cache if the callee is no longer alive.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitCreateThis): Add the instruction to propertyAccessInstructions so that
+        we can clear the callee cache in CodeBlock::finalizeUnconditionally. Also initialize the newly added
+        operand.
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock): Implement the optimization. Speculate the actual callee to
+        match the cache. Use the cached callee's structure if the speculation succeeds. Otherwise, OSR exit.
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_create_this): Go to the slow path to update the cache unless it's already marked
+        as seenMultipleCalleeObjects() to indicate the polymorphic behavior and/or we've OSR exited here.
+        (JSC::JIT::emitSlow_op_create_this):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_create_this): Ditto.
+        (JSC::JIT::emitSlow_op_create_this):
+        * llint/LowLevelInterpreter32_64.asm:
+        (_llint_op_create_this): Ditto.
+        * llint/LowLevelInterpreter64.asm:
+        (_llint_op_create_this): Ditto.
+        * runtime/CommonSlowPaths.cpp:
+        (slow_path_create_this): Set the callee cache to the actual callee if it's not set. If the cache has
+        been set to a JSFunction* different from the actual callee, set it to seenMultipleCalleeObjects().
+        * runtime/JSCell.h:
+        (JSC::JSCell::seenMultipleCalleeObjects): Added.
+        * runtime/WriteBarrier.h:
+        (JSC::WriteBarrierBase::unvalidatedGet): Removed the compile guard around it.
+        * tests/stress/create-this-with-callee-variants.js: Added.
+
</ins><span class="cx"> 2015-05-13  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Clean up some possible RefPtr to PassRefPtr churn
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeListjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeList.json (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeList.json        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeList.json        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -9,7 +9,7 @@
</span><span class="cx">             { &quot;name&quot; : &quot;op_create_direct_arguments&quot;, &quot;length&quot; : 2 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_create_scoped_arguments&quot;, &quot;length&quot; : 3 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_create_out_of_band_arguments&quot;, &quot;length&quot; : 2 },
</span><del>-            { &quot;name&quot; : &quot;op_create_this&quot;, &quot;length&quot; : 4 },
</del><ins>+            { &quot;name&quot; : &quot;op_create_this&quot;, &quot;length&quot; : 5 },
</ins><span class="cx">             { &quot;name&quot; : &quot;op_to_this&quot;, &quot;length&quot; : 4 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_check_tdz&quot;, &quot;length&quot; : 2 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_new_object&quot;, &quot;length&quot; : 4 },
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -795,8 +795,9 @@
</span><span class="cx">             int r0 = (++it)-&gt;u.operand;
</span><span class="cx">             int r1 = (++it)-&gt;u.operand;
</span><span class="cx">             unsigned inferredInlineCapacity = (++it)-&gt;u.operand;
</span><ins>+            unsigned cachedFunction = (++it)-&gt;u.operand;
</ins><span class="cx">             printLocationAndOp(out, exec, location, it, &quot;create_this&quot;);
</span><del>-            out.printf(&quot;%s, %s, %u&quot;, registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity);
</del><ins>+            out.printf(&quot;%s, %s, %u, %u&quot;, registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity, cachedFunction);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_to_this: {
</span><span class="lines">@@ -2569,6 +2570,18 @@
</span><span class="cx">                 curInstruction[3].u.toThisStatus = merge(
</span><span class="cx">                     curInstruction[3].u.toThisStatus, ToThisClearedByGC);
</span><span class="cx">                 break;
</span><ins>+            case op_create_this: {
+                auto&amp; cacheWriteBarrier = curInstruction[4].u.jsCell;
+                if (!cacheWriteBarrier || cacheWriteBarrier.unvalidatedGet() == JSCell::seenMultipleCalleeObjects())
+                    break;
+                JSCell* cachedFunction = cacheWriteBarrier.get();
+                if (Heap::isMarked(cachedFunction))
+                    break;
+                if (Options::verboseOSR())
+                    dataLogF(&quot;Clearing LLInt create_this with cached callee %p.\n&quot;, cachedFunction);
+                cacheWriteBarrier.clear();
+                break;
+            }
</ins><span class="cx">             case op_resolve_scope: {
</span><span class="cx">                 // Right now this isn't strictly necessary. Any symbol tables that this will refer to
</span><span class="cx">                 // are for outer functions, and we refer to those functions strongly, and they refer
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -1675,10 +1675,12 @@
</span><span class="cx">     size_t begin = instructions().size();
</span><span class="cx">     m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3);
</span><span class="cx"> 
</span><ins>+    m_codeBlock-&gt;addPropertyAccessInstruction(instructions().size());
</ins><span class="cx">     emitOpcode(op_create_this); 
</span><span class="cx">     instructions().append(m_thisRegister.index()); 
</span><span class="cx">     instructions().append(m_thisRegister.index()); 
</span><span class="cx">     instructions().append(0);
</span><ins>+    instructions().append(0);
</ins><span class="cx">     return dst;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -2679,8 +2679,25 @@
</span><span class="cx">         case op_create_this: {
</span><span class="cx">             int calleeOperand = currentInstruction[2].u.operand;
</span><span class="cx">             Node* callee = get(VirtualRegister(calleeOperand));
</span><ins>+
+            JSFunction* function = callee-&gt;dynamicCastConstant&lt;JSFunction*&gt;();
+            if (!function) {
+                JSCell* cachedFunction = currentInstruction[4].u.jsCell.unvalidatedGet();
+                if (cachedFunction
+                    &amp;&amp; cachedFunction != JSCell::seenMultipleCalleeObjects()
+                    &amp;&amp; !m_inlineStackTop-&gt;m_exitProfile.hasExitSite(m_currentIndex, BadCell)) {
+                    ASSERT(cachedFunction-&gt;inherits(JSFunction::info()));
+
+                    FrozenValue* frozen = m_graph.freeze(cachedFunction);
+                    addToGraph(CheckCell, OpInfo(frozen), callee);
+                    set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(JSConstant, OpInfo(frozen)));
+
+                    function = static_cast&lt;JSFunction*&gt;(cachedFunction);
+                }
+            }
+
</ins><span class="cx">             bool alreadyEmitted = false;
</span><del>-            if (JSFunction* function = callee-&gt;dynamicCastConstant&lt;JSFunction*&gt;()) {
</del><ins>+            if (function) {
</ins><span class="cx">                 if (FunctionRareData* rareData = function-&gt;rareData()) {
</span><span class="cx">                     if (Structure* structure = rareData-&gt;allocationStructure()) {
</span><span class="cx">                         m_graph.freeze(rareData);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -705,11 +705,13 @@
</span><span class="cx"> void JIT::emit_op_create_this(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     int callee = currentInstruction[2].u.operand;
</span><ins>+    WriteBarrierBase&lt;JSCell&gt;* cachedFunction = &amp;currentInstruction[4].u.jsCell;
</ins><span class="cx">     RegisterID calleeReg = regT0;
</span><del>-    RegisterID rareDataReg = regT0;
</del><ins>+    RegisterID rareDataReg = regT4;
</ins><span class="cx">     RegisterID resultReg = regT0;
</span><span class="cx">     RegisterID allocatorReg = regT1;
</span><span class="cx">     RegisterID structureReg = regT2;
</span><ins>+    RegisterID cachedFunctionReg = regT4;
</ins><span class="cx">     RegisterID scratchReg = regT3;
</span><span class="cx"> 
</span><span class="cx">     emitGetVirtualRegister(callee, calleeReg);
</span><span class="lines">@@ -719,6 +721,11 @@
</span><span class="cx">     loadPtr(Address(rareDataReg, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
</span><span class="cx">     addSlowCase(branchTestPtr(Zero, allocatorReg));
</span><span class="cx"> 
</span><ins>+    loadPtr(cachedFunction, cachedFunctionReg);
+    Jump hasSeenMultipleCallees = branchPtr(Equal, cachedFunctionReg, TrustedImmPtr(JSCell::seenMultipleCalleeObjects()));
+    addSlowCase(branchPtr(NotEqual, calleeReg, cachedFunctionReg));
+    hasSeenMultipleCallees.link(this);
+
</ins><span class="cx">     emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
</span><span class="cx">     emitPutVirtualRegister(currentInstruction[1].u.operand);
</span><span class="cx"> }
</span><span class="lines">@@ -728,6 +735,7 @@
</span><span class="cx">     linkSlowCase(iter); // doesn't have rare data
</span><span class="cx">     linkSlowCase(iter); // doesn't have an allocation profile
</span><span class="cx">     linkSlowCase(iter); // allocation failed
</span><ins>+    linkSlowCase(iter); // cached function didn't match
</ins><span class="cx"> 
</span><span class="cx">     JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_create_this);
</span><span class="cx">     slowPathCall.call();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -936,11 +936,13 @@
</span><span class="cx"> void JIT::emit_op_create_this(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     int callee = currentInstruction[2].u.operand;
</span><ins>+    WriteBarrierBase&lt;JSCell&gt;* cachedFunction = &amp;currentInstruction[4].u.jsCell;
</ins><span class="cx">     RegisterID calleeReg = regT0;
</span><del>-    RegisterID rareDataReg = regT0;
</del><ins>+    RegisterID rareDataReg = regT4;
</ins><span class="cx">     RegisterID resultReg = regT0;
</span><span class="cx">     RegisterID allocatorReg = regT1;
</span><span class="cx">     RegisterID structureReg = regT2;
</span><ins>+    RegisterID cachedFunctionReg = regT4;
</ins><span class="cx">     RegisterID scratchReg = regT3;
</span><span class="cx"> 
</span><span class="cx">     emitLoadPayload(callee, calleeReg);
</span><span class="lines">@@ -950,6 +952,11 @@
</span><span class="cx">     loadPtr(Address(rareDataReg, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
</span><span class="cx">     addSlowCase(branchTestPtr(Zero, allocatorReg));
</span><span class="cx"> 
</span><ins>+    loadPtr(cachedFunction, cachedFunctionReg);
+    Jump hasSeenMultipleCallees = branchPtr(Equal, cachedFunctionReg, TrustedImmPtr(JSCell::seenMultipleCalleeObjects()));
+    addSlowCase(branchPtr(NotEqual, calleeReg, cachedFunctionReg));
+    hasSeenMultipleCallees.link(this);
+
</ins><span class="cx">     emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
</span><span class="cx">     emitStoreCell(currentInstruction[1].u.operand, resultReg);
</span><span class="cx"> }
</span><span class="lines">@@ -959,6 +966,7 @@
</span><span class="cx">     linkSlowCase(iter); // doesn't have rare data
</span><span class="cx">     linkSlowCase(iter); // doesn't have an allocation profile
</span><span class="cx">     linkSlowCase(iter); // allocation failed
</span><ins>+    linkSlowCase(iter); // cached function didn't match
</ins><span class="cx"> 
</span><span class="cx">     JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_create_this);
</span><span class="cx">     slowPathCall.call();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -745,15 +745,19 @@
</span><span class="cx">     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t4], t1
</span><span class="cx">     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t4], t2
</span><span class="cx">     btpz t1, .opCreateThisSlow
</span><ins>+    loadpFromInstruction(4, t4)
+    bpeq t4, 1, .hasSeenMultipleCallee
+    bpneq t4, t0, .opCreateThisSlow
+.hasSeenMultipleCallee:
</ins><span class="cx">     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
</span><span class="cx">     loadi 4[PC], t1
</span><span class="cx">     storei CellTag, TagOffset[cfr, t1, 8]
</span><span class="cx">     storei t0, PayloadOffset[cfr, t1, 8]
</span><del>-    dispatch(4)
</del><ins>+    dispatch(5)
</ins><span class="cx"> 
</span><span class="cx"> .opCreateThisSlow:
</span><span class="cx">     callSlowPath(_slow_path_create_this)
</span><del>-    dispatch(4)
</del><ins>+    dispatch(5)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _llint_op_to_this:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -631,14 +631,18 @@
</span><span class="cx">     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_allocator[t4], t1
</span><span class="cx">     loadp FunctionRareData::m_allocationProfile + ObjectAllocationProfile::m_structure[t4], t2
</span><span class="cx">     btpz t1, .opCreateThisSlow
</span><ins>+    loadpFromInstruction(4, t4)
+    bpeq t4, 1, .hasSeenMultipleCallee
+    bpneq t4, t0, .opCreateThisSlow
+.hasSeenMultipleCallee:
</ins><span class="cx">     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
</span><span class="cx">     loadisFromInstruction(1, t1)
</span><span class="cx">     storeq t0, [cfr, t1, 8]
</span><del>-    dispatch(4)
</del><ins>+    dispatch(5)
</ins><span class="cx"> 
</span><span class="cx"> .opCreateThisSlow:
</span><span class="cx">     callSlowPath(_slow_path_create_this)
</span><del>-    dispatch(4)
</del><ins>+    dispatch(5)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _llint_op_to_this:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -235,6 +235,12 @@
</span><span class="cx">     ASSERT(constructor-&gt;methodTable()-&gt;getConstructData(constructor, constructData) == ConstructTypeJS);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    auto&amp; cacheWriteBarrier = pc[4].u.jsCell;
+    if (!cacheWriteBarrier)
+        cacheWriteBarrier.set(exec-&gt;vm(), exec-&gt;codeBlock()-&gt;ownerExecutable(), constructor);
+    else if (cacheWriteBarrier.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() &amp;&amp; cacheWriteBarrier.get() != constructor)
+        cacheWriteBarrier.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects());
+
</ins><span class="cx">     size_t inlineCapacity = pc[3].u.operand;
</span><span class="cx">     Structure* structure = constructor-&gt;rareData(exec, inlineCapacity)-&gt;allocationProfile()-&gt;structure();
</span><span class="cx">     RETURN(constructEmptyObject(exec, structure));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCell.h (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCell.h        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/runtime/JSCell.h        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -74,6 +74,8 @@
</span><span class="cx"> 
</span><span class="cx">     static const bool needsDestruction = false;
</span><span class="cx"> 
</span><ins>+    static JSCell* seenMultipleCalleeObjects() { return bitwise_cast&lt;JSCell*&gt;(static_cast&lt;uintptr_t&gt;(1)); }
+
</ins><span class="cx">     enum CreatingEarlyCellTag { CreatingEarlyCell };
</span><span class="cx">     JSCell(CreatingEarlyCellTag);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeWriteBarrierh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/WriteBarrier.h (184327 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/WriteBarrier.h        2015-05-14 04:07:45 UTC (rev 184327)
+++ trunk/Source/JavaScriptCore/runtime/WriteBarrier.h        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -126,9 +126,7 @@
</span><span class="cx">         this-&gt;m_cell = reinterpret_cast&lt;JSCell*&gt;(value);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-#if ENABLE(GC_VALIDATION)
</del><span class="cx">     T* unvalidatedGet() const { return reinterpret_cast&lt;T*&gt;(static_cast&lt;void*&gt;(m_cell)); }
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     JSCell* m_cell;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresscreatethiswithcalleevariantsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/create-this-with-callee-variants.js (0 => 184328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/create-this-with-callee-variants.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/create-this-with-callee-variants.js        2015-05-14 04:19:18 UTC (rev 184328)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+function createInLoop(x, count) {
+    noInline(x)
+    for (var i = 0; i &lt; 5000; i++) {
+        var obj = new x;
+        if (!(obj instanceof x))
+            throw &quot;Failed to instantiate the right object&quot;;
+    }
+}
+
+function y() { return function () {} }
+
+createInLoop(y());
+
+function z() { return function () {} }
+
+createInLoop(z());
+createInLoop(z());
+createInLoop(z());
</ins></span></pre>
</div>
</div>

</body>
</html>