<!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>[170672] branches/ftlopt/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/170672">170672</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-07-01 15:40:05 -0700 (Tue, 01 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ftlopt] DFG bytecode parser should turn PutById with nothing but a Setter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to
https://bugs.webkit.org/show_bug.cgi?id=130756

Reviewed by Oliver Hunt.
        
The enables exposing the call to setters in the DFG, and then inlining it. Previously we
already supproted inlined-cached calls to setters from within put_by_id inline caches,
and the DFG could certainly emit such IC's. Now, if an IC had a setter call, then the DFG
will either emit the GetGetterSetterByOffset/GetSetter/Call combo, or it will do one
better and inline the call.
        
A lot of the core functionality was already available from the previous work to inline
getters. So, there are some refactorings in this patch that move preexisting
functionality around. For example, the work to figure out how the DFG should go about
getting to what we call the &quot;loaded value&quot; - i.e. the GetterSetter object reference in
the case of accessors - is now shared in ComplexGetStatus, and both GetByIdStatus and
PutByIdStatus use it. This means that we can keep the safety checks common.  This patch
also does additional refactorings in DFG::ByteCodeParser so that we can continue to reuse
handleCall() for all of the various kinds of calls we can now emit.
        
83% speed-up on getter-richards, 2% speed-up on box2d.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/ComplexGetStatus.cpp: Added.
(JSC::ComplexGetStatus::computeFor):
* bytecode/ComplexGetStatus.h: Added.
(JSC::ComplexGetStatus::ComplexGetStatus):
(JSC::ComplexGetStatus::skip):
(JSC::ComplexGetStatus::takesSlowPath):
(JSC::ComplexGetStatus::kind):
(JSC::ComplexGetStatus::attributes):
(JSC::ComplexGetStatus::specificValue):
(JSC::ComplexGetStatus::offset):
(JSC::ComplexGetStatus::chain):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeForStubInfo):
* bytecode/GetByIdVariant.cpp:
(JSC::GetByIdVariant::GetByIdVariant):
* bytecode/PolymorphicPutByIdList.h:
(JSC::PutByIdAccess::PutByIdAccess):
(JSC::PutByIdAccess::setter):
(JSC::PutByIdAccess::structure):
(JSC::PutByIdAccess::chainCount):
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):
(JSC::PutByIdStatus::computeForStubInfo):
(JSC::PutByIdStatus::makesCalls):
* bytecode/PutByIdStatus.h:
(JSC::PutByIdStatus::makesCalls): Deleted.
* bytecode/PutByIdVariant.cpp:
(JSC::PutByIdVariant::PutByIdVariant):
(JSC::PutByIdVariant::operator=):
(JSC::PutByIdVariant::replace):
(JSC::PutByIdVariant::transition):
(JSC::PutByIdVariant::setter):
(JSC::PutByIdVariant::writesStructures):
(JSC::PutByIdVariant::reallocatesStorage):
(JSC::PutByIdVariant::makesCalls):
(JSC::PutByIdVariant::dumpInContext):
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::PutByIdVariant):
(JSC::PutByIdVariant::structure):
(JSC::PutByIdVariant::oldStructure):
(JSC::PutByIdVariant::alternateBase):
(JSC::PutByIdVariant::specificValue):
(JSC::PutByIdVariant::callLinkStatus):
(JSC::PutByIdVariant::replace): Deleted.
(JSC::PutByIdVariant::transition): Deleted.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::handlePutById):
(JSC::DFG::ByteCodeParser::parseBlock):
* jit/Repatch.cpp:
(JSC::tryCachePutByID):
(JSC::tryBuildPutByIdList):
* runtime/IntendedStructureChain.cpp:
(JSC::IntendedStructureChain::takesSlowPathInDFGForImpureProperty):
* runtime/IntendedStructureChain.h:
* tests/stress/exit-from-setter.js: Added.
* tests/stress/poly-chain-setter.js: Added.
(Cons):
(foo):
(test):
* tests/stress/poly-chain-then-setter.js: Added.
(Cons1):
(Cons2):
(foo):
(test):
* tests/stress/poly-setter-combo.js: Added.
(Cons1):
(Cons2):
(foo):
(test):
(.test):
* tests/stress/poly-setter-then-self.js: Added.
(foo):
(test):
(.test):
* tests/stress/weird-setter-counter.js: Added.
(foo):
(test):
* tests/stress/weird-setter-counter-syntactic.js: Added.
(foo):
(test):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesftloptSourceJavaScriptCoreCMakeListstxt">branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreChangeLog">branches/ftlopt/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePolymorphicPutByIdListh">branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdStatush">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdVariantcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitRepatchcpp">branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChaincpp">branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChainh">branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeComplexGetStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeComplexGetStatush">branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressexitfromsetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-setter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolychainsetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-setter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolychainthensetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-setter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolysettercombojs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-combo.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolysetterthenselfjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-then-self.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressweirdsettercountersyntacticjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter-syntactic.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressweirdsettercounterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -67,6 +67,7 @@
</span><span class="cx">     bytecode/CodeBlockJettisoningWatchpoint.cpp
</span><span class="cx">     bytecode/CodeOrigin.cpp
</span><span class="cx">     bytecode/CodeType.cpp
</span><ins>+    bytecode/ComplerGetStatus.cpp
</ins><span class="cx">     bytecode/ConstantStructureCheck.cpp
</span><span class="cx">     bytecode/DFGExitProfile.cpp
</span><span class="cx">     bytecode/DeferredCompilationCallback.cpp
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -1,3 +1,117 @@
</span><ins>+2014-07-01  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG bytecode parser should turn PutById with nothing but a Setter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to
+        https://bugs.webkit.org/show_bug.cgi?id=130756
+
+        Reviewed by Oliver Hunt.
+        
+        The enables exposing the call to setters in the DFG, and then inlining it. Previously we
+        already supproted inlined-cached calls to setters from within put_by_id inline caches,
+        and the DFG could certainly emit such IC's. Now, if an IC had a setter call, then the DFG
+        will either emit the GetGetterSetterByOffset/GetSetter/Call combo, or it will do one
+        better and inline the call.
+        
+        A lot of the core functionality was already available from the previous work to inline
+        getters. So, there are some refactorings in this patch that move preexisting
+        functionality around. For example, the work to figure out how the DFG should go about
+        getting to what we call the &quot;loaded value&quot; - i.e. the GetterSetter object reference in
+        the case of accessors - is now shared in ComplexGetStatus, and both GetByIdStatus and
+        PutByIdStatus use it. This means that we can keep the safety checks common.  This patch
+        also does additional refactorings in DFG::ByteCodeParser so that we can continue to reuse
+        handleCall() for all of the various kinds of calls we can now emit.
+        
+        83% speed-up on getter-richards, 2% speed-up on box2d.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/ComplexGetStatus.cpp: Added.
+        (JSC::ComplexGetStatus::computeFor):
+        * bytecode/ComplexGetStatus.h: Added.
+        (JSC::ComplexGetStatus::ComplexGetStatus):
+        (JSC::ComplexGetStatus::skip):
+        (JSC::ComplexGetStatus::takesSlowPath):
+        (JSC::ComplexGetStatus::kind):
+        (JSC::ComplexGetStatus::attributes):
+        (JSC::ComplexGetStatus::specificValue):
+        (JSC::ComplexGetStatus::offset):
+        (JSC::ComplexGetStatus::chain):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeForStubInfo):
+        * bytecode/GetByIdVariant.cpp:
+        (JSC::GetByIdVariant::GetByIdVariant):
+        * bytecode/PolymorphicPutByIdList.h:
+        (JSC::PutByIdAccess::PutByIdAccess):
+        (JSC::PutByIdAccess::setter):
+        (JSC::PutByIdAccess::structure):
+        (JSC::PutByIdAccess::chainCount):
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeFromLLInt):
+        (JSC::PutByIdStatus::computeFor):
+        (JSC::PutByIdStatus::computeForStubInfo):
+        (JSC::PutByIdStatus::makesCalls):
+        * bytecode/PutByIdStatus.h:
+        (JSC::PutByIdStatus::makesCalls): Deleted.
+        * bytecode/PutByIdVariant.cpp:
+        (JSC::PutByIdVariant::PutByIdVariant):
+        (JSC::PutByIdVariant::operator=):
+        (JSC::PutByIdVariant::replace):
+        (JSC::PutByIdVariant::transition):
+        (JSC::PutByIdVariant::setter):
+        (JSC::PutByIdVariant::writesStructures):
+        (JSC::PutByIdVariant::reallocatesStorage):
+        (JSC::PutByIdVariant::makesCalls):
+        (JSC::PutByIdVariant::dumpInContext):
+        * bytecode/PutByIdVariant.h:
+        (JSC::PutByIdVariant::PutByIdVariant):
+        (JSC::PutByIdVariant::structure):
+        (JSC::PutByIdVariant::oldStructure):
+        (JSC::PutByIdVariant::alternateBase):
+        (JSC::PutByIdVariant::specificValue):
+        (JSC::PutByIdVariant::callLinkStatus):
+        (JSC::PutByIdVariant::replace): Deleted.
+        (JSC::PutByIdVariant::transition): Deleted.
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
+        (JSC::DFG::ByteCodeParser::addCall):
+        (JSC::DFG::ByteCodeParser::handleCall):
+        (JSC::DFG::ByteCodeParser::handleInlining):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::handlePutById):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * jit/Repatch.cpp:
+        (JSC::tryCachePutByID):
+        (JSC::tryBuildPutByIdList):
+        * runtime/IntendedStructureChain.cpp:
+        (JSC::IntendedStructureChain::takesSlowPathInDFGForImpureProperty):
+        * runtime/IntendedStructureChain.h:
+        * tests/stress/exit-from-setter.js: Added.
+        * tests/stress/poly-chain-setter.js: Added.
+        (Cons):
+        (foo):
+        (test):
+        * tests/stress/poly-chain-then-setter.js: Added.
+        (Cons1):
+        (Cons2):
+        (foo):
+        (test):
+        * tests/stress/poly-setter-combo.js: Added.
+        (Cons1):
+        (Cons2):
+        (foo):
+        (test):
+        (.test):
+        * tests/stress/poly-setter-then-self.js: Added.
+        (foo):
+        (test):
+        (.test):
+        * tests/stress/weird-setter-counter.js: Added.
+        (foo):
+        (test):
+        * tests/stress/weird-setter-counter-syntactic.js: Added.
+        (foo):
+        (test):
+
</ins><span class="cx"> 2014-06-30  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Merge r169121 from trunk.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -321,6 +321,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\CodeBlockJettisoningWatchpoint.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\CodeOrigin.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\CodeType.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\bytecode\ComplexGetStatus.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\ConstantStructureCheck.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\DeferredCompilationCallback.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\DFGExitProfile.cpp&quot; /&gt;
</span><span class="lines">@@ -858,6 +859,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\CodeOrigin.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\CodeType.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\Comment.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\bytecode\ComplexGetStatus.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\ConstantStructureCheck.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\DataFormat.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\DeferredCompilationCallback.h&quot; /&gt;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -337,6 +337,8 @@
</span><span class="cx">                 0F6B1CC918641DF800845D97 /* ArityCheckFailReturnThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */; };
</span><span class="cx">                 0F6B1CCA18641DF800845D97 /* ArityCheckFailReturnThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F6E845A19030BEF00562741 /* DFGVariableAccessData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */; };
</span><ins>+                0F6FC750196110A800E1D02D /* ComplexGetStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */; };
+                0F6FC751196110A800E1D02D /* ComplexGetStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */; };
</span><span class="cx">                 0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F714CA416EA92F000F3EBEB /* DFGBackwardsPropagationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */; };
</span><span class="lines">@@ -2512,6 +2514,8 @@
</span><span class="cx">                 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArityCheckFailReturnThunks.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArityCheckFailReturnThunks.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessData.cpp; path = dfg/DFGVariableAccessData.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexGetStatus.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexGetStatus.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitCompilerCommon.cpp; path = dfg/DFGOSRExitCompilerCommon.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitCompilerCommon.h; path = dfg/DFGOSRExitCompilerCommon.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBackwardsPropagationPhase.cpp; path = dfg/DFGBackwardsPropagationPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5379,6 +5383,8 @@
</span><span class="cx">                                 0FBD7E671447998F00481315 /* CodeOrigin.h */,
</span><span class="cx">                                 0F8F943F1667632D00D61971 /* CodeType.cpp */,
</span><span class="cx">                                 0F0B83A514BCF50400885B4F /* CodeType.h */,
</span><ins>+                                0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */,
+                                0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */,
</ins><span class="cx">                                 0F3D0BBA194A414300FC9CF9 /* ConstantStructureCheck.cpp */,
</span><span class="cx">                                 0F3D0BBB194A414300FC9CF9 /* ConstantStructureCheck.h */,
</span><span class="cx">                                 0F426A4A1460CD6B00131F8F /* DataFormat.h */,
</span><span class="lines">@@ -6585,6 +6591,7 @@
</span><span class="cx">                                 A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */,
</span><span class="cx">                                 BC18C4550E16F5CD00B34460 /* PropertySlot.h in Headers */,
</span><span class="cx">                                 0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */,
</span><ins>+                                0F6FC751196110A800E1D02D /* ComplexGetStatus.h in Headers */,
</ins><span class="cx">                                 BC18C4560E16F5CD00B34460 /* Protect.h in Headers */,
</span><span class="cx">                                 1474C33B16AA2D950062F01D /* PrototypeMap.h in Headers */,
</span><span class="cx">                                 0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */,
</span><span class="lines">@@ -8102,6 +8109,7 @@
</span><span class="cx">                                 FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */,
</span><span class="cx">                                 0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
</span><span class="cx">                                 1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */,
</span><ins>+                                0F6FC750196110A800E1D02D /* ComplexGetStatus.cpp in Sources */,
</ins><span class="cx">                                 14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */,
</span><span class="cx">                                 14F7256514EE265E00B1652B /* WeakHandleOwner.cpp in Sources */,
</span><span class="cx">                                 A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */,
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeComplexGetStatuscpp"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,88 @@
</span><ins>+/*
+ * Copyright (C) 2014 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. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;ComplexGetStatus.h&quot;
+
+#include &quot;JSCInlines.h&quot;
+
+namespace JSC {
+
+ComplexGetStatus ComplexGetStatus::computeFor(
+    CodeBlock* profiledBlock, Structure* headStructure, StructureChain* chain,
+    unsigned chainCount, StringImpl* uid)
+{
+    // FIXME: We should assert that we never see a structure that
+    // hasImpureGetOwnPropertySlot() but for which we don't
+    // newImpurePropertyFiresWatchpoints(). We're not at a point where we can do
+    // that, yet.
+    // https://bugs.webkit.org/show_bug.cgi?id=131810
+    
+    if (headStructure-&gt;takesSlowPathInDFGForImpureProperty())
+        return takesSlowPath();
+    
+    ComplexGetStatus result;
+    result.m_kind = Inlineable;
+    
+    JSCell* specificValue;
+    
+    if (chain) {
+        result.m_chain = adoptRef(new IntendedStructureChain(
+            profiledBlock, headStructure, chain, chainCount));
+        
+        if (!result.m_chain-&gt;isStillValid())
+            return skip();
+        
+        if (headStructure-&gt;takesSlowPathInDFGForImpureProperty()
+            || result.m_chain-&gt;takesSlowPathInDFGForImpureProperty())
+            return takesSlowPath();
+        
+        JSObject* currentObject = result.m_chain-&gt;terminalPrototype();
+        Structure* currentStructure = result.m_chain-&gt;last();
+        
+        ASSERT_UNUSED(currentObject, currentObject);
+        
+        result.m_offset = currentStructure-&gt;getConcurrently(
+            *profiledBlock-&gt;vm(), uid, result.m_attributes, specificValue);
+        if (currentStructure-&gt;isDictionary())
+            specificValue = 0;
+    } else {
+        result.m_offset = headStructure-&gt;getConcurrently(
+            *profiledBlock-&gt;vm(), uid, result.m_attributes, specificValue);
+        if (headStructure-&gt;isDictionary())
+            specificValue = 0;
+    }
+    
+    result.m_specificValue = specificValue;
+    
+    if (!isValidOffset(result.m_offset))
+        return takesSlowPath();
+    
+    return result;
+}
+
+} // namespace JSC
+
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeComplexGetStatush"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.h (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.h                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/ComplexGetStatus.h        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,120 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ComplexGetStatus_h
+#define ComplexGetStatus_h
+
+#include &quot;IntendedStructureChain.h&quot;
+#include &quot;JSCJSValue.h&quot;
+#include &quot;PropertyOffset.h&quot;
+
+namespace JSC {
+
+class CodeBlock;
+class StructureChain;
+
+// This class is useful for figuring out how to inline a cached get-like access. We
+// say &quot;get-like&quot; because this is appropriate for loading the GetterSetter object in
+// a put_by_id that hits a setter. Notably, this doesn't figure out how to call
+// accessors, or even whether they should be called. What it gives us, is a way of
+// determining how to load the value from the requested property (identified by a
+// StringImpl* uid) from an object of the given structure in the given CodeBlock,
+// assuming that such an access had already been cached by Repatch (and so Repatch had
+// already done a bunch of safety checks). This doesn't reexecute any checks that
+// Repatch would have executed, and for prototype chain accesses, it doesn't ask the
+// objects in the prototype chain whether their getOwnPropertySlot would attempt to
+// intercept the access - so this really is only appropriate if you already know that
+// one of the JITOperations had OK'd this for caching and that Repatch concurred.
+//
+// The typical use pattern is something like:
+//
+//     ComplexGetStatus status = ComplexGetStatus::computeFor(...);
+//     switch (status.kind()) {
+//     case ComplexGetStatus::ShouldSkip:
+//         // Handle the case where this kind of access is possibly safe but wouldn't
+//         // pass the required safety checks. For example, if an IC gives us a list of
+//         // accesses and one of them is ShouldSkip, then we should pretend as if it
+//         // wasn't even there.
+//         break;
+//     case ComplexGetStatus::TakesSlowPath:
+//         // This kind of access is not safe to inline. Bail out of any attempst to
+//         // inline.
+//         break;
+//     case ComplexGetStatus::Inlineable:
+//         // The good stuff goes here. If it's Inlineable then the other properties of
+//         // the 'status' object will tell you everything you need to know about how
+//         // to execute the get-like operation.
+//         break;
+//     }
+
+class ComplexGetStatus {
+public:
+    enum Kind {
+        ShouldSkip,
+        TakesSlowPath,
+        Inlineable
+    };
+    
+    ComplexGetStatus()
+        : m_kind(ShouldSkip)
+        , m_offset(invalidOffset)
+        , m_attributes(UINT_MAX)
+    {
+    }
+    
+    static ComplexGetStatus skip()
+    {
+        return ComplexGetStatus();
+    }
+    
+    static ComplexGetStatus takesSlowPath()
+    {
+        ComplexGetStatus result;
+        result.m_kind = TakesSlowPath;
+        return result;
+    }
+    
+    static ComplexGetStatus computeFor(
+        CodeBlock* profiledBlock, Structure* headStructure, StructureChain* chain,
+        unsigned chainCount, StringImpl* uid);
+    
+    Kind kind() const { return m_kind; }
+    unsigned attributes() const { return m_attributes; }
+    JSValue specificValue() const { return m_specificValue; }
+    PropertyOffset offset() const { return m_offset; }
+    IntendedStructureChain* chain() const { return m_chain.get(); }
+    
+private:
+    Kind m_kind;
+    PropertyOffset m_offset;
+    unsigned m_attributes;
+    JSValue m_specificValue;
+    RefPtr&lt;IntendedStructureChain&gt; m_chain;
+};
+
+} // namespace JSC
+
+#endif // ComplexGetStatus_h
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AccessorCallJITStubRoutine.h&quot;
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><ins>+#include &quot;ComplexGetStatus.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;JSScope.h&quot;
</span><span class="cx"> #include &quot;LLIntData.h&quot;
</span><span class="lines">@@ -176,86 +177,49 @@
</span><span class="cx">         for (unsigned listIndex = 0; listIndex &lt; list-&gt;size(); ++listIndex) {
</span><span class="cx">             Structure* structure = list-&gt;at(listIndex).structure();
</span><span class="cx">             
</span><del>-            // FIXME: We should assert that we never see a structure that
-            // hasImpureGetOwnPropertySlot() but for which we don't
-            // newImpurePropertyFiresWatchpoints(). We're not at a point where we can do
-            // that, yet.
-            // https://bugs.webkit.org/show_bug.cgi?id=131810
</del><ins>+            ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor(
+                profiledBlock, structure, list-&gt;at(listIndex).chain(),
+                list-&gt;at(listIndex).chainCount(), uid);
</ins><span class="cx">             
</span><del>-            if (structure-&gt;takesSlowPathInDFGForImpureProperty())
</del><ins>+            switch (complexGetStatus.kind()) {
+            case ComplexGetStatus::ShouldSkip:
+                continue;
+                
+            case ComplexGetStatus::TakesSlowPath:
</ins><span class="cx">                 return GetByIdStatus(slowPathState, true);
</span><del>-            
-            unsigned attributesIgnored;
-            JSCell* specificValue;
-            PropertyOffset myOffset;
-            RefPtr&lt;IntendedStructureChain&gt; chain;
-
-            if (list-&gt;at(listIndex).chain()) {
-                chain = adoptRef(new IntendedStructureChain(
-                    profiledBlock, structure, list-&gt;at(listIndex).chain(),
-                    list-&gt;at(listIndex).chainCount()));
</del><span class="cx">                 
</span><del>-                if (!chain-&gt;isStillValid()) {
-                    // This won't ever run again so skip it.
-                    continue;
</del><ins>+            case ComplexGetStatus::Inlineable: {
+                std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus;
+                switch (list-&gt;at(listIndex).type()) {
+                case GetByIdAccess::SimpleInline:
+                case GetByIdAccess::SimpleStub: {
+                    break;
</ins><span class="cx">                 }
</span><del>-                
-                if (structure-&gt;takesSlowPathInDFGForImpureProperty())
</del><ins>+                case GetByIdAccess::Getter: {
+                    AccessorCallJITStubRoutine* stub = static_cast&lt;AccessorCallJITStubRoutine*&gt;(
+                        list-&gt;at(listIndex).stubRoutine());
+                    callLinkStatus = std::make_unique&lt;CallLinkStatus&gt;(
+                        CallLinkStatus::computeFor(locker, *stub-&gt;m_callLinkInfo, callExitSiteData));
+                    break;
+                }
+                case GetByIdAccess::CustomGetter: {
+                    // FIXME: It would be totally sweet to support this at some point in the future.
+                    // https://bugs.webkit.org/show_bug.cgi?id=133052
</ins><span class="cx">                     return GetByIdStatus(slowPathState, true);
</span><del>-                
-                size_t chainSize = chain-&gt;size();
-                for (size_t i = 0; i &lt; chainSize; i++) {
-                    if (chain-&gt;at(i)-&gt;takesSlowPathInDFGForImpureProperty())
-                        return GetByIdStatus(slowPathState, true);
</del><span class="cx">                 }
</span><ins>+                default:
+                    RELEASE_ASSERT_NOT_REACHED();
+                }
</ins><span class="cx">                 
</span><del>-                JSObject* currentObject = chain-&gt;terminalPrototype();
-                Structure* currentStructure = chain-&gt;last();
</del><ins>+                GetByIdVariant variant(
+                    StructureSet(structure), complexGetStatus.offset(),
+                    complexGetStatus.specificValue(), complexGetStatus.chain(),
+                    std::move(callLinkStatus));
</ins><span class="cx">                 
</span><del>-                ASSERT_UNUSED(currentObject, currentObject);
-                
-                myOffset = currentStructure-&gt;getConcurrently(
-                    *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
-                if (currentStructure-&gt;isDictionary())
-                    specificValue = 0;
-            } else {
-                myOffset = structure-&gt;getConcurrently(
-                    *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
-                if (structure-&gt;isDictionary())
-                    specificValue = 0;
-            }
-            
-            if (!isValidOffset(myOffset))
-                return GetByIdStatus(slowPathState, true);
-            
-            std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus;
-            switch (list-&gt;at(listIndex).type()) {
-            case GetByIdAccess::SimpleInline:
-            case GetByIdAccess::SimpleStub: {
</del><ins>+                if (!result.appendVariant(variant))
+                    return GetByIdStatus(slowPathState, true);
</ins><span class="cx">                 break;
</span><del>-            }
-            case GetByIdAccess::Getter: {
-                AccessorCallJITStubRoutine* stub = static_cast&lt;AccessorCallJITStubRoutine*&gt;(
-                    list-&gt;at(listIndex).stubRoutine());
-                callLinkStatus = std::make_unique&lt;CallLinkStatus&gt;(
-                    CallLinkStatus::computeFor(locker, *stub-&gt;m_callLinkInfo, callExitSiteData));
-                break;
-            }
-            case GetByIdAccess::CustomGetter: {
-                // FIXME: It would be totally sweet to support this at some point in the future.
-                // https://bugs.webkit.org/show_bug.cgi?id=133052
-                return GetByIdStatus(slowPathState, true);
-            }
-            default:
-                RELEASE_ASSERT_NOT_REACHED();
-            }
-            
-            GetByIdVariant variant(
-                StructureSet(structure), myOffset, specificValue, chain.get(),
-                std::move(callLinkStatus));
-            
-            if (!result.appendVariant(variant))
-                return GetByIdStatus(slowPathState, true);
</del><ins>+            } }
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         return result;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -56,6 +56,7 @@
</span><span class="cx"> GetByIdVariant::~GetByIdVariant() { }
</span><span class="cx"> 
</span><span class="cx"> GetByIdVariant::GetByIdVariant(const GetByIdVariant&amp; other)
</span><ins>+    : GetByIdVariant()
</ins><span class="cx"> {
</span><span class="cx">     *this = other;
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePolymorphicPutByIdListh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx">     
</span><span class="cx">     PutByIdAccess()
</span><span class="cx">         : m_type(Invalid)
</span><ins>+        , m_chainCount(UINT_MAX)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -95,6 +96,7 @@
</span><span class="cx">         AccessType accessType,
</span><span class="cx">         Structure* structure,
</span><span class="cx">         StructureChain* chain,
</span><ins>+        unsigned chainCount,
</ins><span class="cx">         PutPropertySlot::PutValueFunc customSetter,
</span><span class="cx">         PassRefPtr&lt;JITStubRoutine&gt; stubRoutine)
</span><span class="cx">     {
</span><span class="lines">@@ -102,8 +104,10 @@
</span><span class="cx">         PutByIdAccess result;
</span><span class="cx">         result.m_oldStructure.set(vm, owner, structure);
</span><span class="cx">         result.m_type = accessType;
</span><del>-        if (chain)
</del><ins>+        if (chain) {
</ins><span class="cx">             result.m_chain.set(vm, owner, chain);
</span><ins>+            result.m_chainCount = chainCount;
+        }
</ins><span class="cx">         result.m_customSetter = customSetter;
</span><span class="cx">         result.m_stubRoutine = stubRoutine;
</span><span class="cx">         return result;
</span><span class="lines">@@ -132,7 +136,7 @@
</span><span class="cx">     
</span><span class="cx">     Structure* structure() const
</span><span class="cx">     {
</span><del>-        ASSERT(isReplace());
</del><ins>+        ASSERT(isReplace() || isSetter() || isCustom());
</ins><span class="cx">         return m_oldStructure.get();
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -148,6 +152,12 @@
</span><span class="cx">         return m_chain.get();
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    unsigned chainCount() const
+    {
+        ASSERT(isSetter() || isCustom());
+        return m_chainCount;
+    }
+    
</ins><span class="cx">     JITStubRoutine* stubRoutine() const
</span><span class="cx">     {
</span><span class="cx">         ASSERT(isTransition() || isReplace() || isSetter() || isCustom());
</span><span class="lines">@@ -169,6 +179,7 @@
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_oldStructure;
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_newStructure;
</span><span class="cx">     WriteBarrier&lt;StructureChain&gt; m_chain;
</span><ins>+    unsigned m_chainCount;
</ins><span class="cx">     PutPropertySlot::PutValueFunc m_customSetter;
</span><span class="cx">     RefPtr&lt;JITStubRoutine&gt; m_stubRoutine;
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -26,7 +26,9 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;PutByIdStatus.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;AccessorCallJITStubRoutine.h&quot;
</ins><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><ins>+#include &quot;ComplexGetStatus.h&quot;
</ins><span class="cx"> #include &quot;LLIntData.h&quot;
</span><span class="cx"> #include &quot;LowLevelInterpreter.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="lines">@@ -97,10 +99,11 @@
</span><span class="cx">     if (!isValidOffset(offset))
</span><span class="cx">         return PutByIdStatus(NoInformation);
</span><span class="cx">     
</span><del>-    return PutByIdVariant::transition(
-        structure, newStructure,
-        chain ? adoptRef(new IntendedStructureChain(profiledBlock, structure, chain)) : 0,
-        offset);
</del><ins>+    RefPtr&lt;IntendedStructureChain&gt; intendedChain;
+    if (chain)
+        intendedChain = adoptRef(new IntendedStructureChain(profiledBlock, structure, chain));
+    
+    return PutByIdVariant::transition(structure, newStructure, intendedChain.get(), offset);
</ins><span class="cx"> #else
</span><span class="cx">     return PutByIdStatus(NoInformation);
</span><span class="cx"> #endif
</span><span class="lines">@@ -119,7 +122,9 @@
</span><span class="cx">         return PutByIdStatus(TakesSlowPath);
</span><span class="cx">     
</span><span class="cx">     StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex));
</span><del>-    PutByIdStatus result = computeForStubInfo(locker, profiledBlock, stubInfo, uid);
</del><ins>+    PutByIdStatus result = computeForStubInfo(
+        locker, profiledBlock, stubInfo, uid,
+        CallLinkStatus::computeExitSiteData(locker, profiledBlock, bytecodeIndex));
</ins><span class="cx">     if (!result)
</span><span class="cx">         return computeFromLLInt(profiledBlock, bytecodeIndex, uid);
</span><span class="cx">     
</span><span class="lines">@@ -131,7 +136,9 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-PutByIdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJITLocker&amp;, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, StringImpl* uid)
</del><ins>+PutByIdStatus PutByIdStatus::computeForStubInfo(
+    const ConcurrentJITLocker&amp; locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo,
+    StringImpl* uid, CallLinkStatus::ExitSiteData callExitSiteData)
</ins><span class="cx"> {
</span><span class="cx">     if (!stubInfo || !stubInfo-&gt;seen)
</span><span class="cx">         return PutByIdStatus();
</span><span class="lines">@@ -159,13 +166,16 @@
</span><span class="cx">             stubInfo-&gt;u.putByIdTransition.structure-&gt;getConcurrently(
</span><span class="cx">                 *profiledBlock-&gt;vm(), uid);
</span><span class="cx">         if (isValidOffset(offset)) {
</span><ins>+            RefPtr&lt;IntendedStructureChain&gt; chain;
+            if (stubInfo-&gt;u.putByIdTransition.chain) {
+                chain = adoptRef(new IntendedStructureChain(
+                    profiledBlock, stubInfo-&gt;u.putByIdTransition.previousStructure.get(),
+                    stubInfo-&gt;u.putByIdTransition.chain.get()));
+            }
</ins><span class="cx">             return PutByIdVariant::transition(
</span><span class="cx">                 stubInfo-&gt;u.putByIdTransition.previousStructure.get(),
</span><span class="cx">                 stubInfo-&gt;u.putByIdTransition.structure.get(),
</span><del>-                stubInfo-&gt;u.putByIdTransition.chain ? adoptRef(new IntendedStructureChain(
-                    profiledBlock, stubInfo-&gt;u.putByIdTransition.previousStructure.get(),
-                    stubInfo-&gt;u.putByIdTransition.chain.get())) : 0,
-                offset);
</del><ins>+                chain.get(), offset);
</ins><span class="cx">         }
</span><span class="cx">         return PutByIdStatus(TakesSlowPath);
</span><span class="cx">     }
</span><span class="lines">@@ -176,17 +186,32 @@
</span><span class="cx">         PutByIdStatus result;
</span><span class="cx">         result.m_state = Simple;
</span><span class="cx">         
</span><ins>+        State slowPathState = TakesSlowPath;
</ins><span class="cx">         for (unsigned i = 0; i &lt; list-&gt;size(); ++i) {
</span><span class="cx">             const PutByIdAccess&amp; access = list-&gt;at(i);
</span><span class="cx">             
</span><span class="cx">             switch (access.type()) {
</span><ins>+            case PutByIdAccess::Setter:
+            case PutByIdAccess::CustomSetter:
+                slowPathState = MakesCalls;
+                break;
+            default:
+                break;
+            }
+        }
+        
+        for (unsigned i = 0; i &lt; list-&gt;size(); ++i) {
+            const PutByIdAccess&amp; access = list-&gt;at(i);
+            
+            PutByIdVariant variant;
+            
+            switch (access.type()) {
</ins><span class="cx">             case PutByIdAccess::Replace: {
</span><span class="cx">                 Structure* structure = access.structure();
</span><span class="cx">                 PropertyOffset offset = structure-&gt;getConcurrently(*profiledBlock-&gt;vm(), uid);
</span><span class="cx">                 if (!isValidOffset(offset))
</span><del>-                    return PutByIdStatus(TakesSlowPath);
-                if (!result.appendVariant(PutByIdVariant::replace(structure, offset)))
-                    return PutByIdStatus(TakesSlowPath);
</del><ins>+                    return PutByIdStatus(slowPathState);
+                variant = PutByIdVariant::replace(structure, offset);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="lines">@@ -194,7 +219,7 @@
</span><span class="cx">                 PropertyOffset offset =
</span><span class="cx">                     access.newStructure()-&gt;getConcurrently(*profiledBlock-&gt;vm(), uid);
</span><span class="cx">                 if (!isValidOffset(offset))
</span><del>-                    return PutByIdStatus(TakesSlowPath);
</del><ins>+                    return PutByIdStatus(slowPathState);
</ins><span class="cx">                 RefPtr&lt;IntendedStructureChain&gt; chain;
</span><span class="cx">                 if (access.chain()) {
</span><span class="cx">                     chain = adoptRef(new IntendedStructureChain(
</span><span class="lines">@@ -202,19 +227,48 @@
</span><span class="cx">                     if (!chain-&gt;isStillValid())
</span><span class="cx">                         continue;
</span><span class="cx">                 }
</span><del>-                bool ok = result.appendVariant(PutByIdVariant::transition(
-                    access.oldStructure(), access.newStructure(), chain.get(), offset));
-                if (!ok)
-                    return PutByIdStatus(TakesSlowPath);
</del><ins>+                variant = PutByIdVariant::transition(
+                    access.oldStructure(), access.newStructure(), chain.get(), offset);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            case PutByIdAccess::Setter:
</del><ins>+                
+            case PutByIdAccess::Setter: {
+                Structure* structure = access.structure();
+                
+                ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor(
+                    profiledBlock, structure, access.chain(), access.chainCount(), uid);
+                
+                switch (complexGetStatus.kind()) {
+                case ComplexGetStatus::ShouldSkip:
+                    continue;
+                    
+                case ComplexGetStatus::TakesSlowPath:
+                    return PutByIdStatus(slowPathState);
+                    
+                case ComplexGetStatus::Inlineable: {
+                    AccessorCallJITStubRoutine* stub = static_cast&lt;AccessorCallJITStubRoutine*&gt;(
+                        access.stubRoutine());
+                    std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus =
+                        std::make_unique&lt;CallLinkStatus&gt;(
+                            CallLinkStatus::computeFor(
+                                locker, *stub-&gt;m_callLinkInfo, callExitSiteData));
+                    
+                    variant = PutByIdVariant::setter(
+                        structure, complexGetStatus.offset(), complexGetStatus.specificValue(),
+                        complexGetStatus.chain(), std::move(callLinkStatus));
+                } }
+                break;
+            }
+                
</ins><span class="cx">             case PutByIdAccess::CustomSetter:
</span><span class="cx">                 return PutByIdStatus(MakesCalls);
</span><span class="cx"> 
</span><span class="cx">             default:
</span><del>-                return PutByIdStatus(TakesSlowPath);
</del><ins>+                return PutByIdStatus(slowPathState);
</ins><span class="cx">             }
</span><ins>+            
+            if (!result.appendVariant(variant))
+                return PutByIdStatus(slowPathState);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         return result;
</span><span class="lines">@@ -230,16 +284,20 @@
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     if (dfgBlock) {
</span><ins>+        CallLinkStatus::ExitSiteData exitSiteData;
</ins><span class="cx">         {
</span><span class="cx">             ConcurrentJITLocker locker(baselineBlock-&gt;m_lock);
</span><span class="cx">             if (hasExitSite(locker, baselineBlock, codeOrigin.bytecodeIndex, ExitFromFTL))
</span><span class="cx">                 return PutByIdStatus(TakesSlowPath);
</span><ins>+            exitSiteData = CallLinkStatus::computeExitSiteData(
+                locker, baselineBlock, codeOrigin.bytecodeIndex, ExitFromFTL);
</ins><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         PutByIdStatus result;
</span><span class="cx">         {
</span><span class="cx">             ConcurrentJITLocker locker(dfgBlock-&gt;m_lock);
</span><del>-            result = computeForStubInfo(locker, dfgBlock, dfgMap.get(codeOrigin), uid);
</del><ins>+            result = computeForStubInfo(
+                locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // We use TakesSlowPath in some cases where the stub was unset. That's weird and
</span><span class="lines">@@ -345,7 +403,7 @@
</span><span class="cx">         ASSERT(isValidOffset(offset));
</span><span class="cx">     
</span><span class="cx">         bool didAppend = result.appendVariant(
</span><del>-            PutByIdVariant::transition(structure, transition, chain.release(), offset));
</del><ins>+            PutByIdVariant::transition(structure, transition, chain.get(), offset));
</ins><span class="cx">         if (!didAppend)
</span><span class="cx">             return PutByIdStatus(TakesSlowPath);
</span><span class="cx">     }
</span><span class="lines">@@ -353,6 +411,22 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool PutByIdStatus::makesCalls() const
+{
+    if (m_state == MakesCalls)
+        return true;
+    
+    if (m_state != Simple)
+        return false;
+    
+    for (unsigned i = m_variants.size(); i--;) {
+        if (m_variants[i].makesCalls())
+            return true;
+    }
+    
+    return false;
+}
+
</ins><span class="cx"> void PutByIdStatus::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     switch (m_state) {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdStatush"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #ifndef PutByIdStatus_h
</span><span class="cx"> #define PutByIdStatus_h
</span><span class="cx"> 
</span><ins>+#include &quot;CallLinkStatus.h&quot;
</ins><span class="cx"> #include &quot;ExitingJITType.h&quot;
</span><span class="cx"> #include &quot;PutByIdVariant.h&quot;
</span><span class="cx"> #include &quot;StructureStubInfo.h&quot;
</span><span class="lines">@@ -80,7 +81,7 @@
</span><span class="cx">     bool operator!() const { return m_state == NoInformation; }
</span><span class="cx">     bool isSimple() const { return m_state == Simple; }
</span><span class="cx">     bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
</span><del>-    bool makesCalls() const { return m_state == MakesCalls; }
</del><ins>+    bool makesCalls() const;
</ins><span class="cx">     
</span><span class="cx">     size_t numVariants() const { return m_variants.size(); }
</span><span class="cx">     const Vector&lt;PutByIdVariant, 1&gt;&amp; variants() const { return m_variants; }
</span><span class="lines">@@ -94,7 +95,9 @@
</span><span class="cx">     static bool hasExitSite(const ConcurrentJITLocker&amp;, CodeBlock*, unsigned bytecodeIndex, ExitingJITType = ExitFromAnything);
</span><span class="cx"> #endif
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-    static PutByIdStatus computeForStubInfo(const ConcurrentJITLocker&amp;, CodeBlock*, StructureStubInfo*, StringImpl* uid);
</del><ins>+    static PutByIdStatus computeForStubInfo(
+        const ConcurrentJITLocker&amp;, CodeBlock*, StructureStubInfo*, StringImpl* uid,
+        CallLinkStatus::ExitSiteData);
</ins><span class="cx"> #endif
</span><span class="cx">     static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid);
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -26,10 +26,74 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;PutByIdVariant.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;CallLinkStatus.h&quot;
+#include &quot;JSCInlines.h&quot;
</ins><span class="cx"> #include &lt;wtf/ListDump.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+PutByIdVariant::PutByIdVariant(const PutByIdVariant&amp; other)
+    : PutByIdVariant()
+{
+    *this = other;
+}
+
+PutByIdVariant&amp; PutByIdVariant::operator=(const PutByIdVariant&amp; other)
+{
+    m_kind = other.m_kind;
+    m_oldStructure = other.m_oldStructure;
+    m_newStructure = other.m_newStructure;
+    m_constantChecks = other.m_constantChecks;
+    m_alternateBase = other.m_alternateBase;
+    m_specificValue = other.m_specificValue;
+    m_offset = other.m_offset;
+    if (other.m_callLinkStatus)
+        m_callLinkStatus = std::make_unique&lt;CallLinkStatus&gt;(*other.m_callLinkStatus);
+    else
+        m_callLinkStatus = nullptr;
+    return *this;
+}
+
+PutByIdVariant PutByIdVariant::replace(const StructureSet&amp; structure, PropertyOffset offset)
+{
+    PutByIdVariant result;
+    result.m_kind = Replace;
+    result.m_oldStructure = structure;
+    result.m_offset = offset;
+    return result;
+}
+
+PutByIdVariant PutByIdVariant::transition(
+    const StructureSet&amp; oldStructure, Structure* newStructure,
+    const IntendedStructureChain* structureChain, PropertyOffset offset)
+{
+    PutByIdVariant result;
+    result.m_kind = Transition;
+    result.m_oldStructure = oldStructure;
+    result.m_newStructure = newStructure;
+    if (structureChain)
+        structureChain-&gt;gatherChecks(result.m_constantChecks);
+    result.m_offset = offset;
+    return result;
+}
+
+PutByIdVariant PutByIdVariant::setter(
+    const StructureSet&amp; structure, PropertyOffset offset, JSValue specificValue,
+    IntendedStructureChain* chain, std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus)
+{
+    PutByIdVariant result;
+    result.m_kind = Setter;
+    result.m_oldStructure = structure;
+    if (chain) {
+        chain-&gt;gatherChecks(result.m_constantChecks);
+        result.m_alternateBase = chain-&gt;terminalPrototype();
+    }
+    result.m_offset = offset;
+    result.m_specificValue = specificValue;
+    result.m_callLinkStatus = std::move(callLinkStatus);
+    return result;
+}
+
</ins><span class="cx"> Structure* PutByIdVariant::oldStructureForTransition() const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(kind() == Transition);
</span><span class="lines">@@ -44,20 +108,32 @@
</span><span class="cx"> 
</span><span class="cx"> bool PutByIdVariant::writesStructures() const
</span><span class="cx"> {
</span><del>-    return kind() == Transition;
</del><ins>+    switch (kind()) {
+    case Transition:
+    case Setter:
+        return true;
+    default:
+        return false;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool PutByIdVariant::reallocatesStorage() const
</span><span class="cx"> {
</span><del>-    if (kind() != Transition)
</del><ins>+    switch (kind()) {
+    case Transition:
+        return oldStructureForTransition()-&gt;outOfLineCapacity() != newStructure()-&gt;outOfLineCapacity();
+    case Setter:
+        return true;
+    default:
</ins><span class="cx">         return false;
</span><del>-    
-    if (oldStructureForTransition()-&gt;outOfLineCapacity() == newStructure()-&gt;outOfLineCapacity())
-        return false;
-    
-    return true;
</del><ins>+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool PutByIdVariant::makesCalls() const
+{
+    return kind() == Setter;
+}
+
</ins><span class="cx"> bool PutByIdVariant::attemptToMerge(const PutByIdVariant&amp; other)
</span><span class="cx"> {
</span><span class="cx">     if (m_offset != other.m_offset)
</span><span class="lines">@@ -137,15 +213,28 @@
</span><span class="cx">         
</span><span class="cx">     case Replace:
</span><span class="cx">         out.print(
</span><del>-            &quot;&lt;Replace: &quot;, inContext(structure(), context), &quot;, &quot;, offset(), &quot;&gt;&quot;);
</del><ins>+            &quot;&lt;Replace: &quot;, inContext(structure(), context), &quot;, offset = &quot;, offset(), &quot;&gt;&quot;);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case Transition:
</span><span class="cx">         out.print(
</span><span class="cx">             &quot;&lt;Transition: &quot;, inContext(oldStructure(), context), &quot; -&gt; &quot;,
</span><span class="cx">             pointerDumpInContext(newStructure(), context), &quot;, [&quot;,
</span><del>-            listDumpInContext(constantChecks(), context), &quot;], &quot;, offset(), &quot;&gt;&quot;);
</del><ins>+            listDumpInContext(constantChecks(), context), &quot;], offset = &quot;, offset(), &quot;&gt;&quot;);
</ins><span class="cx">         return;
</span><ins>+        
+    case Setter:
+        out.print(
+            &quot;&lt;Setter: &quot;, inContext(structure(), context), &quot;, [&quot;,
+            listDumpInContext(constantChecks(), context), &quot;]&quot;);
+        if (m_alternateBase)
+            out.print(&quot;, alternateBase = &quot;, inContext(JSValue(m_alternateBase), context));
+        if (m_specificValue)
+            out.print(&quot;, specificValue = &quot;, inContext(m_specificValue, context));
+        out.print(&quot;, offset = &quot;, m_offset);
+        out.print(&quot;, call = &quot;, *m_callLinkStatus);
+        out.print(&quot;&gt;&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -32,44 +32,39 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+class CallLinkStatus;
+
</ins><span class="cx"> class PutByIdVariant {
</span><span class="cx"> public:
</span><span class="cx">     enum Kind {
</span><span class="cx">         NotSet,
</span><span class="cx">         Replace,
</span><del>-        Transition
</del><ins>+        Transition,
+        Setter
</ins><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     PutByIdVariant()
</span><span class="cx">         : m_kind(NotSet)
</span><span class="cx">         , m_newStructure(nullptr)
</span><ins>+        , m_alternateBase(nullptr)
</ins><span class="cx">         , m_offset(invalidOffset)
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    static PutByIdVariant replace(const StructureSet&amp; structure, PropertyOffset offset)
-    {
-        PutByIdVariant result;
-        result.m_kind = Replace;
-        result.m_oldStructure = structure;
-        result.m_offset = offset;
-        return result;
-    }
</del><ins>+    PutByIdVariant(const PutByIdVariant&amp;);
+    PutByIdVariant&amp; operator=(const PutByIdVariant&amp;);
+
+    static PutByIdVariant replace(
+        const StructureSet&amp; structure, PropertyOffset offset);
</ins><span class="cx">     
</span><span class="cx">     static PutByIdVariant transition(
</span><span class="cx">         const StructureSet&amp; oldStructure, Structure* newStructure,
</span><del>-        PassRefPtr&lt;IntendedStructureChain&gt; structureChain, PropertyOffset offset)
-    {
-        PutByIdVariant result;
-        result.m_kind = Transition;
-        result.m_oldStructure = oldStructure;
-        result.m_newStructure = newStructure;
-        if (structureChain)
-            structureChain-&gt;gatherChecks(result.m_constantChecks);
-        result.m_offset = offset;
-        return result;
-    }
</del><ins>+        const IntendedStructureChain* structureChain, PropertyOffset offset);
</ins><span class="cx">     
</span><ins>+    static PutByIdVariant setter(
+        const StructureSet&amp; structure, PropertyOffset offset, JSValue specificValue,
+        IntendedStructureChain* chain, std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus);
+    
</ins><span class="cx">     Kind kind() const { return m_kind; }
</span><span class="cx">     
</span><span class="cx">     bool isSet() const { return kind() != NotSet; }
</span><span class="lines">@@ -77,19 +72,19 @@
</span><span class="cx">     
</span><span class="cx">     const StructureSet&amp; structure() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Replace);
</del><ins>+        ASSERT(kind() == Replace || kind() == Setter);
</ins><span class="cx">         return m_oldStructure;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     const StructureSet&amp; oldStructure() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Transition || kind() == Replace);
</del><ins>+        ASSERT(kind() == Transition || kind() == Replace || kind() == Setter);
</ins><span class="cx">         return m_oldStructure;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     StructureSet&amp; oldStructure()
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Transition || kind() == Replace);
</del><ins>+        ASSERT(kind() == Transition || kind() == Replace || kind() == Setter);
</ins><span class="cx">         return m_oldStructure;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -103,6 +98,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool writesStructures() const;
</span><span class="cx">     bool reallocatesStorage() const;
</span><ins>+    bool makesCalls() const;
</ins><span class="cx">     
</span><span class="cx">     const ConstantStructureCheckVector&amp; constantChecks() const
</span><span class="cx">     {
</span><span class="lines">@@ -115,6 +111,24 @@
</span><span class="cx">         return m_offset;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    JSObject* alternateBase() const
+    {
+        ASSERT(kind() == Setter);
+        return m_alternateBase;
+    }
+    
+    JSValue specificValue() const
+    {
+        ASSERT(kind() == Setter);
+        return m_specificValue;
+    }
+    
+    CallLinkStatus* callLinkStatus() const
+    {
+        ASSERT(kind() == Setter);
+        return m_callLinkStatus.get();
+    }
+
</ins><span class="cx">     bool attemptToMerge(const PutByIdVariant&amp; other);
</span><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="lines">@@ -127,7 +141,10 @@
</span><span class="cx">     StructureSet m_oldStructure;
</span><span class="cx">     Structure* m_newStructure;
</span><span class="cx">     ConstantStructureCheckVector m_constantChecks;
</span><ins>+    JSObject* m_alternateBase;
+    JSValue m_specificValue;
</ins><span class="cx">     PropertyOffset m_offset;
</span><ins>+    std::unique_ptr&lt;CallLinkStatus&gt; m_callLinkStatus;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -171,6 +171,10 @@
</span><span class="cx">     // Handle calls. This resolves issues surrounding inlining and intrinsics.
</span><span class="cx">     void handleCall(
</span><span class="cx">         int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,
</span><ins>+        Node* callTarget, int argCount, int registerOffset, CallLinkStatus,
+        SpeculatedType prediction);
+    void handleCall(
+        int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,
</ins><span class="cx">         Node* callTarget, int argCount, int registerOffset, CallLinkStatus);
</span><span class="cx">     void handleCall(int result, NodeType op, CodeSpecializationKind, unsigned instructionSize, int callee, int argCount, int registerOffset);
</span><span class="cx">     void handleCall(Instruction* pc, NodeType op, CodeSpecializationKind);
</span><span class="lines">@@ -640,10 +644,10 @@
</span><span class="cx">         m_numPassedVarArgs++;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* addCall(int result, NodeType op, Node* callee, int argCount, int registerOffset)
</del><ins>+    Node* addCallWithoutSettingResult(
+        NodeType op, Node* callee, int argCount, int registerOffset,
+        SpeculatedType prediction)
</ins><span class="cx">     {
</span><del>-        SpeculatedType prediction = getPrediction();
-        
</del><span class="cx">         addVarArgChild(callee);
</span><span class="cx">         size_t parameterSlots = JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + argCount;
</span><span class="cx">         if (parameterSlots &gt; m_parameterSlots)
</span><span class="lines">@@ -653,8 +657,18 @@
</span><span class="cx">         for (int i = 0 + dummyThisArgument; i &lt; argCount; ++i)
</span><span class="cx">             addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
</span><span class="cx"> 
</span><del>-        Node* call = addToGraph(Node::VarArg, op, OpInfo(0), OpInfo(prediction));
-        set(VirtualRegister(result), call);
</del><ins>+        return addToGraph(Node::VarArg, op, OpInfo(0), OpInfo(prediction));
+    }
+    
+    Node* addCall(
+        int result, NodeType op, Node* callee, int argCount, int registerOffset,
+        SpeculatedType prediction)
+    {
+        Node* call = addCallWithoutSettingResult(
+            op, callee, argCount, registerOffset, prediction);
+        VirtualRegister resultReg(result);
+        if (resultReg.isValid())
+            set(VirtualRegister(result), call);
</ins><span class="cx">         return call;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -992,6 +1006,16 @@
</span><span class="cx">     Node* callTarget, int argumentCountIncludingThis, int registerOffset,
</span><span class="cx">     CallLinkStatus callLinkStatus)
</span><span class="cx"> {
</span><ins>+    handleCall(
+        result, op, kind, instructionSize, callTarget, argumentCountIncludingThis,
+        registerOffset, callLinkStatus, getPrediction());
+}
+
+void ByteCodeParser::handleCall(
+    int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize,
+    Node* callTarget, int argumentCountIncludingThis, int registerOffset,
+    CallLinkStatus callLinkStatus, SpeculatedType prediction)
+{
</ins><span class="cx">     ASSERT(registerOffset &lt;= 0);
</span><span class="cx">     CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
</span><span class="cx">     
</span><span class="lines">@@ -1002,12 +1026,11 @@
</span><span class="cx">         // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically
</span><span class="cx">         // that we cannot optimize them.
</span><span class="cx">         
</span><del>-        addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset);
</del><ins>+        addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset, prediction);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     unsigned nextOffset = m_currentIndex + instructionSize;
</span><del>-    SpeculatedType prediction = getPrediction();
</del><span class="cx"> 
</span><span class="cx">     if (InternalFunction* function = callLinkStatus.internalFunction()) {
</span><span class="cx">         if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, specializationKind)) {
</span><span class="lines">@@ -1019,7 +1042,7 @@
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // Can only handle this using the generic call handler.
</span><del>-        addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset);
</del><ins>+        addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset, prediction);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="lines">@@ -1056,7 +1079,7 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    Node* call = addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset);
</del><ins>+    Node* call = addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset, prediction);
</ins><span class="cx"> 
</span><span class="cx">     if (knownFunction) 
</span><span class="cx">         call-&gt;giveKnownFunction(knownFunction);
</span><span class="lines">@@ -1203,9 +1226,12 @@
</span><span class="cx">     
</span><span class="cx">     size_t argumentPositionStart = m_graph.m_argumentPositions.size();
</span><span class="cx"> 
</span><ins>+    VirtualRegister resultReg(resultOperand);
+    if (resultReg.isValid())
+        resultReg = m_inlineStackTop-&gt;remapOperand(resultReg);
+    
</ins><span class="cx">     InlineStackEntry inlineStackEntry(
</span><del>-        this, codeBlock, codeBlock, m_graph.lastBlock(), callLinkStatus.function(),
-        m_inlineStackTop-&gt;remapOperand(VirtualRegister(resultOperand)),
</del><ins>+        this, codeBlock, codeBlock, m_graph.lastBlock(), callLinkStatus.function(), resultReg,
</ins><span class="cx">         (VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind);
</span><span class="cx">     
</span><span class="cx">     // This is where the actual inlining really happens.
</span><span class="lines">@@ -1757,7 +1783,8 @@
</span><span class="cx">         loadedValue = weakJSConstant(variant.specificValue());
</span><span class="cx">     else {
</span><span class="cx">         loadedValue = handleGetByOffset(
</span><del>-            prediction, base, identifierNumber, variant.offset(),
</del><ins>+            variant.callLinkStatus() ? SpecCellOther : prediction,
+            base, identifierNumber, variant.offset(),
</ins><span class="cx">             variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -1801,7 +1828,7 @@
</span><span class="cx">     
</span><span class="cx">     handleCall(
</span><span class="cx">         destinationOperand, Call, InlineCallFrame::GetterCall, OPCODE_LENGTH(op_get_by_id),
</span><del>-        getter, numberOfParameters - 1, registerOffset, *variant.callLinkStatus());
</del><ins>+        getter, numberOfParameters - 1, registerOffset, *variant.callLinkStatus(), prediction);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ByteCodeParser::emitPutById(
</span><span class="lines">@@ -1852,7 +1879,8 @@
</span><span class="cx">     ASSERT(putByIdStatus.numVariants() == 1);
</span><span class="cx">     const PutByIdVariant&amp; variant = putByIdStatus[0];
</span><span class="cx">     
</span><del>-    if (variant.kind() == PutByIdVariant::Replace) {
</del><ins>+    switch (variant.kind()) {
+    case PutByIdVariant::Replace: {
</ins><span class="cx">         addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structure())), base);
</span><span class="cx">         handlePutByOffset(base, identifierNumber, variant.offset(), value);
</span><span class="cx">         if (m_graph.compilation())
</span><span class="lines">@@ -1860,57 +1888,116 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (variant.kind() != PutByIdVariant::Transition) {
-        emitPutById(base, identifierNumber, value, putByIdStatus, isDirect);
-        return;
-    }
</del><ins>+    case PutByIdVariant::Transition: {
+        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base);
+        emitChecks(variant.constantChecks());
</ins><span class="cx"> 
</span><del>-    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base);
-    emitChecks(variant.constantChecks());
-
-    ASSERT(variant.oldStructureForTransition()-&gt;transitionWatchpointSetHasBeenInvalidated());
</del><ins>+        ASSERT(variant.oldStructureForTransition()-&gt;transitionWatchpointSetHasBeenInvalidated());
</ins><span class="cx">     
</span><del>-    Node* propertyStorage;
-    Transition* transition = m_graph.m_transitions.add(
-        variant.oldStructureForTransition(), variant.newStructure());
</del><ins>+        Node* propertyStorage;
+        Transition* transition = m_graph.m_transitions.add(
+            variant.oldStructureForTransition(), variant.newStructure());
</ins><span class="cx"> 
</span><del>-    if (variant.reallocatesStorage()) {
</del><ins>+        if (variant.reallocatesStorage()) {
</ins><span class="cx"> 
</span><del>-        // If we're growing the property storage then it must be because we're
-        // storing into the out-of-line storage.
-        ASSERT(!isInlineOffset(variant.offset()));
</del><ins>+            // If we're growing the property storage then it must be because we're
+            // storing into the out-of-line storage.
+            ASSERT(!isInlineOffset(variant.offset()));
</ins><span class="cx"> 
</span><del>-        if (!variant.oldStructureForTransition()-&gt;outOfLineCapacity()) {
-            propertyStorage = addToGraph(
-                AllocatePropertyStorage, OpInfo(transition), base);
</del><ins>+            if (!variant.oldStructureForTransition()-&gt;outOfLineCapacity()) {
+                propertyStorage = addToGraph(
+                    AllocatePropertyStorage, OpInfo(transition), base);
+            } else {
+                propertyStorage = addToGraph(
+                    ReallocatePropertyStorage, OpInfo(transition),
+                    base, addToGraph(GetButterfly, base));
+            }
</ins><span class="cx">         } else {
</span><del>-            propertyStorage = addToGraph(
-                ReallocatePropertyStorage, OpInfo(transition),
-                base, addToGraph(GetButterfly, base));
</del><ins>+            if (isInlineOffset(variant.offset()))
+                propertyStorage = base;
+            else
+                propertyStorage = addToGraph(GetButterfly, base);
</ins><span class="cx">         }
</span><del>-    } else {
-        if (isInlineOffset(variant.offset()))
-            propertyStorage = base;
-        else
-            propertyStorage = addToGraph(GetButterfly, base);
-    }
</del><span class="cx"> 
</span><del>-    addToGraph(PutStructure, OpInfo(transition), base);
</del><ins>+        addToGraph(PutStructure, OpInfo(transition), base);
</ins><span class="cx"> 
</span><del>-    addToGraph(
-        PutByOffset,
-        OpInfo(m_graph.m_storageAccessData.size()),
-        propertyStorage,
-        base,
-        value);
</del><ins>+        addToGraph(
+            PutByOffset,
+            OpInfo(m_graph.m_storageAccessData.size()),
+            propertyStorage,
+            base,
+            value);
</ins><span class="cx"> 
</span><del>-    StorageAccessData storageAccessData;
-    storageAccessData.offset = variant.offset();
-    storageAccessData.identifierNumber = identifierNumber;
-    m_graph.m_storageAccessData.append(storageAccessData);
</del><ins>+        StorageAccessData storageAccessData;
+        storageAccessData.offset = variant.offset();
+        storageAccessData.identifierNumber = identifierNumber;
+        m_graph.m_storageAccessData.append(storageAccessData);
</ins><span class="cx"> 
</span><del>-    if (m_graph.compilation())
-        m_graph.compilation()-&gt;noticeInlinedPutById();
</del><ins>+        if (m_graph.compilation())
+            m_graph.compilation()-&gt;noticeInlinedPutById();
+        return;
+    }
+        
+    case PutByIdVariant::Setter: {
+        Node* originalBase = base;
+        
+        addToGraph(
+            CheckStructure, OpInfo(m_graph.addStructureSet(variant.structure())), base);
+        
+        emitChecks(variant.constantChecks());
+        
+        if (variant.alternateBase())
+            base = weakJSConstant(variant.alternateBase());
+        
+        Node* loadedValue;
+        if (variant.specificValue())
+            loadedValue = weakJSConstant(variant.specificValue());
+        else {
+            loadedValue = handleGetByOffset(
+                SpecCellOther, base, identifierNumber, variant.offset(),
+                GetGetterSetterByOffset);
+        }
+        
+        Node* setter = addToGraph(GetSetter, loadedValue);
+        
+        // Make a call. We don't try to get fancy with using the smallest operand number because
+        // the stack layout phase should compress the stack anyway.
+    
+        unsigned numberOfParameters = 0;
+        numberOfParameters++; // The 'this' argument.
+        numberOfParameters++; // The new value.
+        numberOfParameters++; // True return PC.
+    
+        // Start with a register offset that corresponds to the last in-use register.
+        int registerOffset = virtualRegisterForLocal(
+            m_inlineStackTop-&gt;m_profiledBlock-&gt;m_numCalleeRegisters - 1).offset();
+        registerOffset -= numberOfParameters;
+        registerOffset -= JSStack::CallFrameHeaderSize;
+    
+        // Get the alignment right.
+        registerOffset = -WTF::roundUpToMultipleOf(
+            stackAlignmentRegisters(),
+            -registerOffset);
+    
+        ensureLocals(
+            m_inlineStackTop-&gt;remapOperand(
+                VirtualRegister(registerOffset)).toLocal());
+    
+        int nextRegister = registerOffset + JSStack::CallFrameHeaderSize;
+        set(VirtualRegister(nextRegister++), originalBase, ImmediateNakedSet);
+        set(VirtualRegister(nextRegister++), value, ImmediateNakedSet);
+    
+        handleCall(
+            VirtualRegister().offset(), Call, InlineCallFrame::SetterCall,
+            OPCODE_LENGTH(op_put_by_id), setter, numberOfParameters - 1, registerOffset,
+            *variant.callLinkStatus(), SpecOther);
+        return;
+    }
+    
+    default: {
+        emitPutById(base, identifierNumber, value, putByIdStatus, isDirect);
+        return;
+    } }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ByteCodeParser::prepareToParseBlock()
</span><span class="lines">@@ -2692,8 +2779,8 @@
</span><span class="cx">         case op_ret:
</span><span class="cx">             flushForReturn();
</span><span class="cx">             if (inlineCallFrame()) {
</span><del>-                ASSERT(m_inlineStackTop-&gt;m_returnValue.isValid());
-                setDirect(m_inlineStackTop-&gt;m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
</del><ins>+                if (m_inlineStackTop-&gt;m_returnValue.isValid())
+                    setDirect(m_inlineStackTop-&gt;m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
</ins><span class="cx">                 m_inlineStackTop-&gt;m_didReturn = true;
</span><span class="cx">                 if (m_inlineStackTop-&gt;m_unlinkedBlocks.isEmpty()) {
</span><span class="cx">                     // If we're returning from the first block, then we're done parsing.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/jit/Repatch.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -1209,7 +1209,7 @@
</span><span class="cx">         list-&gt;addAccess(PutByIdAccess::setter(
</span><span class="cx">             *vm, codeBlock-&gt;ownerExecutable(),
</span><span class="cx">             slot.isCacheableSetter() ? PutByIdAccess::Setter : PutByIdAccess::CustomSetter,
</span><del>-            structure, prototypeChain, slot.customSetter(), stubRoutine));
</del><ins>+            structure, prototypeChain, count, slot.customSetter(), stubRoutine));
</ins><span class="cx"> 
</span><span class="cx">         RepatchBuffer repatchBuffer(codeBlock);
</span><span class="cx">         repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine-&gt;code().code()));
</span><span class="lines">@@ -1341,7 +1341,7 @@
</span><span class="cx">         list-&gt;addAccess(PutByIdAccess::setter(
</span><span class="cx">             *vm, codeBlock-&gt;ownerExecutable(),
</span><span class="cx">             slot.isCacheableSetter() ? PutByIdAccess::Setter : PutByIdAccess::CustomSetter,
</span><del>-            structure, prototypeChain, slot.customSetter(), stubRoutine));
</del><ins>+            structure, prototypeChain, count, slot.customSetter(), stubRoutine));
</ins><span class="cx"> 
</span><span class="cx">         RepatchBuffer repatchBuffer(codeBlock);
</span><span class="cx">         repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine-&gt;code().code()));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChaincpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -130,6 +130,15 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool IntendedStructureChain::takesSlowPathInDFGForImpureProperty()
+{
+    for (size_t i = 0; i &lt; size(); ++i) {
+        if (at(i)-&gt;takesSlowPathInDFGForImpureProperty())
+            return true;
+    }
+    return false;
+}
+
</ins><span class="cx"> JSObject* IntendedStructureChain::terminalPrototype() const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_vector.isEmpty());
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChainh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h (170671 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h        2014-07-01 22:34:10 UTC (rev 170671)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -52,6 +52,8 @@
</span><span class="cx">     bool mayInterceptStoreTo(VM&amp;, StringImpl* uid);
</span><span class="cx">     bool isNormalized();
</span><span class="cx">     
</span><ins>+    bool takesSlowPathInDFGForImpureProperty();
+    
</ins><span class="cx">     JSValue prototype() const { return m_prototype; }
</span><span class="cx">     
</span><span class="cx">     size_t size() const { return m_vector.size(); }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressexitfromsetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-setter.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-setter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-setter.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+(function() {
+    var o = {_f:42};
+    o.__defineSetter__(&quot;f&quot;, function(value) { this._f = value * 100; });
+    var n = 50000;
+    function foo(o_, v_) {
+        var o = o_.f;
+        var v = v_.f;
+        o.f = v;
+        o.f = v + 1;
+    }
+    noInline(foo);
+    for (var i = 0; i &lt; n; ++i) {
+        foo({f:o}, {f:11});
+    }
+    if (o._f != (11 + 1) * 100)
+        throw &quot;Error: bad o._f: &quot; + o._f;
+    for (var i = 0; i &lt; n; ++i) {
+        foo({f:o}, {f:1000000000});
+    }
+    if (o._f != 100 * (1000000000 + 1))
+        throw &quot;Error: bad o._f (2): &quot; + o._f;
+})();
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolychainsetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-setter.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-setter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-setter.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+function Cons() {
+}
+Cons.prototype.__defineSetter__(&quot;f&quot;, function(value) {
+    counter++;
+    this._f = value;
+});
+Cons.prototype.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+
+function foo(o, v) {
+    o.f = v;
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, value, expectedCount) {
+    var result = foo(o, value);
+    if (result != value)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    test(new Cons(), i, counter + 1);
+    
+    var o = new Cons();
+    o.g = 54;
+    test(o, i, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolychainthensetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-setter.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-setter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-setter.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+function Cons1() {
+}
+Cons1.prototype.f = 42;
+
+function Cons2() {
+}
+Cons2.prototype.__defineSetter__(&quot;f&quot;, function(value) {
+    counter++;
+    this._f = value;
+});
+Cons2.prototype.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+
+function foo(o, value) {
+    o.f = value;
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, value, expectedCount) {
+    var result = foo(o, value);
+    if (result != value)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    test(new Cons1(), i, counter);
+    test(new Cons2(), i, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolysettercombojs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-combo.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-combo.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-combo.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+function Cons1() {
+}
+Cons1.prototype.f = 42;
+
+function Cons2() {
+}
+Cons2.prototype.__defineSetter__(&quot;f&quot;, function(value) {
+    counter++;
+    this._f = value;
+});
+Cons2.prototype.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+
+function foo(o, value) {
+    o.f = value;
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, value, expectedCount) {
+    var result = foo(o, value);
+    if (result != value)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    test(new Cons1(), i, counter);
+    test(new Cons2(), i, counter + 1);
+    
+    var o = {};
+    o.__defineSetter__(&quot;f&quot;, function(value) {
+        this._f = value;
+        counter++;
+    });
+    o.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+    test(o, i, counter + 1);
+
+    test({f: 42}, i, counter);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolysetterthenselfjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-then-self.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-then-self.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-setter-then-self.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+function foo(o, value) {
+    o.f = value;
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, value, expectedCount) {
+    var result = foo(o, value);
+    if (result != value)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {};
+    o.__defineSetter__(&quot;f&quot;, function(value) {
+        counter++;
+        this._f = value;
+    });
+    o.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+    test(o, i, counter + 1);
+
+    test({f: 42}, i, counter);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressweirdsettercountersyntacticjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter-syntactic.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter-syntactic.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter-syntactic.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+function foo(o, value) {
+    o.f = value;
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, value, expectedCount) {
+    var result = foo(o, value);
+    if (result != value)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {
+        get f() {
+            return this._f;
+        },
+        set f(value) {
+            counter++;
+            this._f = value;
+        }
+    };
+    test(o, i, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressweirdsettercounterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter.js (0 => 170672)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-setter-counter.js        2014-07-01 22:40:05 UTC (rev 170672)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+function foo(o, value) {
+    o.f = value;
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, value, expectedCount) {
+    var result = foo(o, value);
+    if (result != value)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {};
+    o.__defineSetter__(&quot;f&quot;, function(value) {
+        counter++;
+        this._f = value;
+    });
+    o.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+    test(o, i, counter + 1);
+}
</ins></span></pre>
</div>
</div>

</body>
</html>