<!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>[169143] branches/ftlopt</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/169143">169143</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-05-20 17:44:20 -0700 (Tue, 20 May 2014)</dd>
</dl>

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

Reviewed by Michael Saboff.

Source/JavaScriptCore: 
        
- GetByIdStatus now knows about getters and can report intelligent things about them.
  As is usually the case with how we do these things, GetByIdStatus knows more about
  getters than the DFG can actually handle: it'll report details about polymorphic
  getter calls even though the DFG won't be able to handle those. This is fine; the DFG
  will see those statuses and bail to a generic slow path.
        
- The DFG::ByteCodeParser now knows how to set up and do handleCall() for a getter call.
  This can, and usually does, result in inlining of getters!
        
- CodeOrigin and OSR exit know about inlined getter calls. When you OSR out of an
  inlined getter, we set the return PC to a getter return thunk that fixes up the stack.
  We use the usual offset-true-return-PC trick, where OSR exit places the true return PC
  of the getter's caller as a phony argument that only the thunk knows how to find.
        
- Removed a bunch of dead monomorphic chain support from StructureStubInfo.
        
- A large chunk of this change is dragging GetGetterSetterByOffset, GetGetter, and
  GetSetter through the DFG and FTL. GetGetterSetterByOffset is like GetByOffset except
  that we know that we're returning a GetterSetter cell. GetGetter and GetSetter extract
  the getter, or setter, from the GetterSetter.
        
This is a ~2.5x speed-up on the getter microbenchmarks that we already had. So far none
of the &quot;real&quot; benchmarks exercise getters enough for this to matter. But I noticed that
some of the variants of the Richards benchmark in other languages - for example
Wolczko's Java translation of a C++ translation of Deutsch's Smalltalk version - use
getters and setters extensively. So, I created a getter/setter JavaScript version of
Richards and put it in regress/script-tests/getter-richards.js. That sees about a 2.4x
speed-up from this patch, which is very reassuring.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printGetByIdCacheStatus):
(JSC::CodeBlock::findStubInfo):
* bytecode/CodeBlock.h:
* bytecode/CodeOrigin.cpp:
(WTF::printInternal):
* bytecode/CodeOrigin.h:
(JSC::InlineCallFrame::specializationKindFor):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFor):
(JSC::GetByIdStatus::computeForStubInfo):
(JSC::GetByIdStatus::makesCalls):
(JSC::GetByIdStatus::computeForChain): Deleted.
* bytecode/GetByIdStatus.h:
(JSC::GetByIdStatus::makesCalls): Deleted.
* bytecode/GetByIdVariant.cpp:
(JSC::GetByIdVariant::~GetByIdVariant):
(JSC::GetByIdVariant::GetByIdVariant):
(JSC::GetByIdVariant::operator=):
(JSC::GetByIdVariant::dumpInContext):
* bytecode/GetByIdVariant.h:
(JSC::GetByIdVariant::GetByIdVariant):
(JSC::GetByIdVariant::callLinkStatus):
* bytecode/PolymorphicGetByIdList.cpp:
(JSC::GetByIdAccess::fromStructureStubInfo):
(JSC::PolymorphicGetByIdList::from):
* bytecode/SpeculatedType.h:
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::deref):
(JSC::StructureStubInfo::visitWeakReferences):
* bytecode/StructureStubInfo.h:
(JSC::isGetByIdAccess):
(JSC::StructureStubInfo::initGetByIdChain): Deleted.
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination):
(JSC::DFG::CSEPhase::getInternalFieldLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
(JSC::DFG::CSEPhase::getTypedArrayByteOffsetLoadElimination): Deleted.
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::linkFunction):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasStorageAccessData):
* dfg/DFGNodeType.h:
* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::reifyInlinedCallFrames):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLAbstractHeapRepository.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetGetter):
(JSC::FTL::LowerDFGToLLVM::compileGetSetter):
* jit/AccessorCallJITStubRoutine.h:
* jit/JIT.cpp:
(JSC::JIT::assertStackPointerOffset):
(JSC::JIT::privateCompile):
* jit/JIT.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_id):
* jit/ThunkGenerators.cpp:
(JSC::arityFixupGenerator):
(JSC::baselineGetterReturnThunkGenerator):
(JSC::baselineSetterReturnThunkGenerator):
(JSC::arityFixup): Deleted.
* jit/ThunkGenerators.h:
* runtime/CommonSlowPaths.cpp:
(JSC::setupArityCheckData):
* tests/stress/exit-from-getter.js: Added.
* tests/stress/poly-chain-getter.js: Added.
(Cons):
(foo):
(test):
* tests/stress/poly-chain-then-getter.js: Added.
(Cons1):
(Cons2):
(foo):
(test):
* tests/stress/poly-getter-combo.js: Added.
(Cons1):
(Cons2):
(foo):
(test):
(.test):
* tests/stress/poly-getter-then-chain.js: Added.
(Cons1):
(Cons2):
(foo):
(test):
* tests/stress/poly-getter-then-self.js: Added.
(foo):
(test):
(.test):
* tests/stress/poly-self-getter.js: Added.
(foo):
(test):
(getter):
* tests/stress/poly-self-then-getter.js: Added.
(foo):
(test):
* tests/stress/weird-getter-counter.js: Added.
(foo):
(test):

Source/WTF: 

* wtf/Bag.h:
(WTF::Bag::iterator::operator!=):

LayoutTests: 

* js/regress/getter-no-activation-expected.txt: Added.
* js/regress/getter-no-activation.html: Added.
* js/regress/script-tests/getter-no-activation.js: Added.
* js/regress/getter-richards-expected.txt: Added.
* js/regress/getter-richards.html: Added.
* js/regress/script-tests/getter-richards.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsChangeLog">branches/ftlopt/LayoutTests/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreChangeLog">branches/ftlopt/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeCodeBlockcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeCodeBlockh">branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeCodeOrigincpp">branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeCodeOriginh">branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdStatush">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePolymorphicGetByIdListcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeSpeculatedTypeh">branches/ftlopt/Source/JavaScriptCore/bytecode/SpeculatedType.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeStructureStubInfocpp">branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeStructureStubInfoh">branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractHeaph">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGCSEPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGClobberizeh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGFixupPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGJITCompilercpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGNodeh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGNodeTypeh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGOSRExitCompilerCommoncpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGSafeToExecuteh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLAbstractHeapRepositorycpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh">branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLCapabilitiescpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLLinkcpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLLink.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitAccessorCallJITStubRoutineh">branches/ftlopt/Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitJITcpp">branches/ftlopt/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitJITh">branches/ftlopt/Source/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitJITPropertyAccesscpp">branches/ftlopt/Source/JavaScriptCore/jit/JITPropertyAccess.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitThunkGeneratorscpp">branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorejitThunkGeneratorsh">branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeCommonSlowPathscpp">branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp</a></li>
<li><a href="#branchesftloptSourceWTFChangeLog">branches/ftlopt/Source/WTF/ChangeLog</a></li>
<li><a href="#branchesftloptSourceWTFwtfBagh">branches/ftlopt/Source/WTF/wtf/Bag.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsjsregressgetternoactivationexpectedtxt">branches/ftlopt/LayoutTests/js/regress/getter-no-activation-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgetternoactivationhtml">branches/ftlopt/LayoutTests/js/regress/getter-no-activation.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgetterrichardsexpectedtxt">branches/ftlopt/LayoutTests/js/regress/getter-richards-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgetterrichardshtml">branches/ftlopt/LayoutTests/js/regress/getter-richards.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsgetternoactivationjs">branches/ftlopt/LayoutTests/js/regress/script-tests/getter-no-activation.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsgetterrichardsjs">branches/ftlopt/LayoutTests/js/regress/script-tests/getter-richards.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressexitfromgetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-getter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolychaingetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-getter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolychainthengetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolygettercombojs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-combo.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolygetterthenchainjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolygetterthenselfjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-self.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolyselfgetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-getter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstresspolyselfthengetterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-then-getter.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressweirdgettercounterjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-getter-counter.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/LayoutTests/ChangeLog (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/ChangeLog        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/LayoutTests/ChangeLog        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-05-19  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to
+        https://bugs.webkit.org/show_bug.cgi?id=133105
+
+        Reviewed by Michael Saboff.
+
+        * js/regress/getter-no-activation-expected.txt: Added.
+        * js/regress/getter-no-activation.html: Added.
+        * js/regress/script-tests/getter-no-activation.js: Added.
+        * js/regress/getter-richards-expected.txt: Added.
+        * js/regress/getter-richards.html: Added.
+        * js/regress/script-tests/getter-richards.js: Added.
+
</ins><span class="cx"> 2014-05-08  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         jsSubstring() should be lazy
</span></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgetternoactivationexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/getter-no-activation-expected.txt (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/getter-no-activation-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/getter-no-activation-expected.txt        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/getter-no-activation
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgetternoactivationhtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/getter-no-activation.html (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/getter-no-activation.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/getter-no-activation.html        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/getter-no-activation.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgetterrichardsexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/getter-richards-expected.txt (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/getter-richards-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/getter-richards-expected.txt        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/getter-richards
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgetterrichardshtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/getter-richards.html (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/getter-richards.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/getter-richards.html        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/getter-richards.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsgetternoactivationjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/getter-no-activation.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/getter-no-activation.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/getter-no-activation.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+(function() {
+    var o = {_f:42};
+    o.__defineGetter__(&quot;f&quot;, function() { return this._f; });
+    (function() {
+        var result = 0;
+        var n = 2000000;
+        for (var i = 0; i &lt; n; ++i)
+            result += o.f;
+        if (result != n * 42)
+            throw &quot;Error: bad result: &quot; + result;
+    })();
+})();
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsgetterrichardsjsfromrev169121branchesftloptPerformanceTestsSunSpidertestsv8v6v8richardsjs"></a>
<div class="copfile"><h4>Copied: branches/ftlopt/LayoutTests/js/regress/script-tests/getter-richards.js (from rev 169121, branches/ftlopt/PerformanceTests/SunSpider/tests/v8-v6/v8-richards.js) (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/getter-richards.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/getter-richards.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,593 @@
</span><ins>+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2014 Apple Inc.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * 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.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; 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 THE COPYRIGHT
+// OWNER 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.
+
+
+// This is a JavaScript implementation of the Richards
+// benchmark from:
+//
+//    http://www.cl.cam.ac.uk/~mr10/Bench.html
+//
+// The benchmark was originally implemented in BCPL by
+// Martin Richards. It was then ported to JavaScript by the
+// V8 project authors, and then subsequently it was modified
+// to use getters and setters by WebKit authors.
+
+
+/**
+ * The Richards benchmark simulates the task dispatcher of an
+ * operating system.
+ **/
+function runRichards() {
+  var scheduler = new Scheduler();
+  scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
+
+  var queue = new Packet(null, ID_WORKER, KIND_WORK);
+  queue = new Packet(queue,  ID_WORKER, KIND_WORK);
+  scheduler.addWorkerTask(ID_WORKER, 1000, queue);
+
+  queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
+  scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
+
+  queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
+  scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
+
+  scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
+
+  scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
+
+  scheduler.schedule();
+
+  if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
+      scheduler.holdCount != EXPECTED_HOLD_COUNT) {
+    var msg =
+        &quot;Error during execution: queueCount = &quot; + scheduler.queueCount +
+        &quot;, holdCount = &quot; + scheduler.holdCount + &quot;.&quot;;
+    throw new Error(msg);
+  }
+}
+
+var COUNT = 1000;
+
+/**
+ * These two constants specify how many times a packet is queued and
+ * how many times a task is put on hold in a correct run of richards.
+ * They don't have any meaning a such but are characteristic of a
+ * correct run so if the actual queue or hold count is different from
+ * the expected there must be a bug in the implementation.
+ **/
+var EXPECTED_QUEUE_COUNT = 2322;
+var EXPECTED_HOLD_COUNT = 928;
+
+
+/**
+ * A scheduler can be used to schedule a set of tasks based on their relative
+ * priorities.  Scheduling is done by maintaining a list of task control blocks
+ * which holds tasks and the data queue they are processing.
+ * @constructor
+ */
+function Scheduler() {
+  this._queueCount = 0;
+  this._holdCount = 0;
+  this._blocks = new Array(NUMBER_OF_IDS);
+  this._list = null;
+  this._currentTcb = null;
+  this._currentId = null;
+}
+
+var ID_IDLE       = 0;
+var ID_WORKER     = 1;
+var ID_HANDLER_A  = 2;
+var ID_HANDLER_B  = 3;
+var ID_DEVICE_A   = 4;
+var ID_DEVICE_B   = 5;
+var NUMBER_OF_IDS = 6;
+
+var KIND_DEVICE   = 0;
+var KIND_WORK     = 1;
+
+Scheduler.prototype.__defineGetter__(&quot;queueCount&quot;, function() { return this._queueCount; });
+Scheduler.prototype.__defineSetter__(&quot;queueCount&quot;, function(value) { this._queueCount = value; });
+Scheduler.prototype.__defineGetter__(&quot;holdCount&quot;, function() { return this._holdCount; });
+Scheduler.prototype.__defineSetter__(&quot;holdCount&quot;, function(value) { this._holdCount = value; });
+Scheduler.prototype.__defineGetter__(&quot;blocks&quot;, function() { return this._blocks; });
+Scheduler.prototype.__defineSetter__(&quot;blocks&quot;, function(value) { this._blocks = value; });
+Scheduler.prototype.__defineGetter__(&quot;list&quot;, function() { return this._list; });
+Scheduler.prototype.__defineSetter__(&quot;list&quot;, function(value) { this._list = value; });
+Scheduler.prototype.__defineGetter__(&quot;currentTcb&quot;, function() { return this._currentTcb; });
+Scheduler.prototype.__defineSetter__(&quot;currentTcb&quot;, function(value) { this._currentTcb = value; });
+Scheduler.prototype.__defineGetter__(&quot;currentId&quot;, function() { return this._currentId; });
+Scheduler.prototype.__defineSetter__(&quot;currentId&quot;, function(value) { this._currentId = value; });
+
+/**
+ * Add an idle task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {int} count the number of times to schedule the task
+ */
+Scheduler.prototype.addIdleTask = function (id, priority, queue, count) {
+  this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
+};
+
+/**
+ * Add a work task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addWorkerTask = function (id, priority, queue) {
+  this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
+};
+
+/**
+ * Add a handler task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addHandlerTask = function (id, priority, queue) {
+  this.addTask(id, priority, queue, new HandlerTask(this));
+};
+
+/**
+ * Add a handler task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addDeviceTask = function (id, priority, queue) {
+  this.addTask(id, priority, queue, new DeviceTask(this))
+};
+
+/**
+ * Add the specified task and mark it as running.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {Task} task the task to add
+ */
+Scheduler.prototype.addRunningTask = function (id, priority, queue, task) {
+  this.addTask(id, priority, queue, task);
+  this.currentTcb.setRunning();
+};
+
+/**
+ * Add the specified task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {Task} task the task to add
+ */
+Scheduler.prototype.addTask = function (id, priority, queue, task) {
+  this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);
+  this.list = this.currentTcb;
+  this.blocks[id] = this.currentTcb;
+};
+
+/**
+ * Execute the tasks managed by this scheduler.
+ */
+Scheduler.prototype.schedule = function () {
+  this.currentTcb = this.list;
+  while (this.currentTcb != null) {
+    if (this.currentTcb.isHeldOrSuspended()) {
+      this.currentTcb = this.currentTcb.link;
+    } else {
+      this.currentId = this.currentTcb.id;
+      this.currentTcb = this.currentTcb.run();
+    }
+  }
+};
+
+/**
+ * Release a task that is currently blocked and return the next block to run.
+ * @param {int} id the id of the task to suspend
+ */
+Scheduler.prototype.release = function (id) {
+  var tcb = this.blocks[id];
+  if (tcb == null) return tcb;
+  tcb.markAsNotHeld();
+  if (tcb.priority &gt; this.currentTcb.priority) {
+    return tcb;
+  } else {
+    return this.currentTcb;
+  }
+};
+
+/**
+ * Block the currently executing task and return the next task control block
+ * to run.  The blocked task will not be made runnable until it is explicitly
+ * released, even if new work is added to it.
+ */
+Scheduler.prototype.holdCurrent = function () {
+  this.holdCount++;
+  this.currentTcb.markAsHeld();
+  return this.currentTcb.link;
+};
+
+/**
+ * Suspend the currently executing task and return the next task control block
+ * to run.  If new work is added to the suspended task it will be made runnable.
+ */
+Scheduler.prototype.suspendCurrent = function () {
+  this.currentTcb.markAsSuspended();
+  return this.currentTcb;
+};
+
+/**
+ * Add the specified packet to the end of the worklist used by the task
+ * associated with the packet and make the task runnable if it is currently
+ * suspended.
+ * @param {Packet} packet the packet to add
+ */
+Scheduler.prototype.queue = function (packet) {
+  var t = this.blocks[packet.id];
+  if (t == null) return t;
+  this.queueCount++;
+  packet.link = null;
+  packet.id = this.currentId;
+  return t.checkPriorityAdd(this.currentTcb, packet);
+};
+
+/**
+ * A task control block manages a task and the queue of work packages associated
+ * with it.
+ * @param {TaskControlBlock} link the preceding block in the linked block list
+ * @param {int} id the id of this block
+ * @param {int} priority the priority of this block
+ * @param {Packet} queue the queue of packages to be processed by the task
+ * @param {Task} task the task
+ * @constructor
+ */
+function TaskControlBlock(link, id, priority, queue, task) {
+  this._link = link;
+  this._id = id;
+  this._priority = priority;
+  this._queue = queue;
+  this._task = task;
+  if (queue == null) {
+    this.state = STATE_SUSPENDED;
+  } else {
+    this.state = STATE_SUSPENDED_RUNNABLE;
+  }
+}
+
+/**
+ * The task is running and is currently scheduled.
+ */
+var STATE_RUNNING = 0;
+
+/**
+ * The task has packets left to process.
+ */
+var STATE_RUNNABLE = 1;
+
+/**
+ * The task is not currently running.  The task is not blocked as such and may
+* be started by the scheduler.
+ */
+var STATE_SUSPENDED = 2;
+
+/**
+ * The task is blocked and cannot be run until it is explicitly released.
+ */
+var STATE_HELD = 4;
+
+var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
+var STATE_NOT_HELD = ~STATE_HELD;
+
+TaskControlBlock.prototype.__defineGetter__(&quot;link&quot;, function() { return this._link; });
+TaskControlBlock.prototype.__defineGetter__(&quot;id&quot;, function() { return this._id; });
+TaskControlBlock.prototype.__defineGetter__(&quot;priority&quot;, function() { return this._priority; });
+TaskControlBlock.prototype.__defineGetter__(&quot;queue&quot;, function() { return this._queue; });
+TaskControlBlock.prototype.__defineSetter__(&quot;queue&quot;, function(value) { this._queue = value; });
+TaskControlBlock.prototype.__defineGetter__(&quot;task&quot;, function() { return this._task; });
+TaskControlBlock.prototype.__defineGetter__(&quot;state&quot;, function() { return this._state; });
+TaskControlBlock.prototype.__defineSetter__(&quot;state&quot;, function(value) { this._state = value; });
+
+TaskControlBlock.prototype.setRunning = function () {
+  this.state = STATE_RUNNING;
+};
+
+TaskControlBlock.prototype.markAsNotHeld = function () {
+  this.state = this.state &amp; STATE_NOT_HELD;
+};
+
+TaskControlBlock.prototype.markAsHeld = function () {
+  this.state = this.state | STATE_HELD;
+};
+
+TaskControlBlock.prototype.isHeldOrSuspended = function () {
+  return (this.state &amp; STATE_HELD) != 0 || (this.state == STATE_SUSPENDED);
+};
+
+TaskControlBlock.prototype.markAsSuspended = function () {
+  this.state = this.state | STATE_SUSPENDED;
+};
+
+TaskControlBlock.prototype.markAsRunnable = function () {
+  this.state = this.state | STATE_RUNNABLE;
+};
+
+/**
+ * Runs this task, if it is ready to be run, and returns the next task to run.
+ */
+TaskControlBlock.prototype.run = function () {
+  var packet;
+  if (this.state == STATE_SUSPENDED_RUNNABLE) {
+    packet = this.queue;
+    this.queue = packet.link;
+    if (this.queue == null) {
+      this.state = STATE_RUNNING;
+    } else {
+      this.state = STATE_RUNNABLE;
+    }
+  } else {
+    packet = null;
+  }
+  return this.task.run(packet);
+};
+
+/**
+ * Adds a packet to the worklist of this block's task, marks this as runnable if
+ * necessary, and returns the next runnable object to run (the one
+ * with the highest priority).
+ */
+TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
+  if (this.queue == null) {
+    this.queue = packet;
+    this.markAsRunnable();
+    if (this.priority &gt; task.priority) return this;
+  } else {
+    this.queue = packet.addTo(this.queue);
+  }
+  return task;
+};
+
+TaskControlBlock.prototype.toString = function () {
+  return &quot;tcb { &quot; + this.task + &quot;@&quot; + this.state + &quot; }&quot;;
+};
+
+/**
+ * An idle task doesn't do any work itself but cycles control between the two
+ * device tasks.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @param {int} v1 a seed value that controls how the device tasks are scheduled
+ * @param {int} count the number of times this task should be scheduled
+ * @constructor
+ */
+function IdleTask(scheduler, v1, count) {
+  this._scheduler = scheduler;
+  this._v1 = v1;
+  this._count = count;
+}
+
+IdleTask.prototype.__defineGetter__(&quot;scheduler&quot;, function() { return this._scheduler; });
+IdleTask.prototype.__defineGetter__(&quot;v1&quot;, function() { return this._v1; });
+IdleTask.prototype.__defineSetter__(&quot;v1&quot;, function(value) { this._v1 = value; });
+IdleTask.prototype.__defineGetter__(&quot;count&quot;, function() { return this._count; });
+IdleTask.prototype.__defineSetter__(&quot;count&quot;, function(value) { this._count = value; });
+
+IdleTask.prototype.run = function (packet) {
+  this.count--;
+  if (this.count == 0) return this.scheduler.holdCurrent();
+  if ((this.v1 &amp; 1) == 0) {
+    this.v1 = this.v1 &gt;&gt; 1;
+    return this.scheduler.release(ID_DEVICE_A);
+  } else {
+    this.v1 = (this.v1 &gt;&gt; 1) ^ 0xD008;
+    return this.scheduler.release(ID_DEVICE_B);
+  }
+};
+
+IdleTask.prototype.toString = function () {
+  return &quot;IdleTask&quot;
+};
+
+/**
+ * A task that suspends itself after each time it has been run to simulate
+ * waiting for data from an external device.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @constructor
+ */
+function DeviceTask(scheduler) {
+  this._scheduler = scheduler;
+  this._v1 = null;
+}
+
+DeviceTask.prototype.__defineGetter__(&quot;scheduler&quot;, function() { return this._scheduler; });
+DeviceTask.prototype.__defineGetter__(&quot;v1&quot;, function() { return this._v1; });
+DeviceTask.prototype.__defineSetter__(&quot;v1&quot;, function(value) { this._v1 = value; });
+
+DeviceTask.prototype.run = function (packet) {
+  if (packet == null) {
+    if (this.v1 == null) return this.scheduler.suspendCurrent();
+    var v = this.v1;
+    this.v1 = null;
+    return this.scheduler.queue(v);
+  } else {
+    this.v1 = packet;
+    return this.scheduler.holdCurrent();
+  }
+};
+
+DeviceTask.prototype.toString = function () {
+  return &quot;DeviceTask&quot;;
+};
+
+/**
+ * A task that manipulates work packets.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @param {int} v1 a seed used to specify how work packets are manipulated
+ * @param {int} v2 another seed used to specify how work packets are manipulated
+ * @constructor
+ */
+function WorkerTask(scheduler, v1, v2) {
+  this._scheduler = scheduler;
+  this._v1 = v1;
+  this._v2 = v2;
+}
+
+WorkerTask.prototype.__defineGetter__(&quot;scheduler&quot;, function() { return this._scheduler; });
+WorkerTask.prototype.__defineGetter__(&quot;v1&quot;, function() { return this._v1; });
+WorkerTask.prototype.__defineSetter__(&quot;v1&quot;, function(value) { this._v1 = value; });
+WorkerTask.prototype.__defineGetter__(&quot;v2&quot;, function() { return this._v2; });
+WorkerTask.prototype.__defineSetter__(&quot;v2&quot;, function(value) { this._v2 = value; });
+
+WorkerTask.prototype.run = function (packet) {
+  if (packet == null) {
+    return this.scheduler.suspendCurrent();
+  } else {
+    if (this.v1 == ID_HANDLER_A) {
+      this.v1 = ID_HANDLER_B;
+    } else {
+      this.v1 = ID_HANDLER_A;
+    }
+    packet.id = this.v1;
+    packet.a1 = 0;
+    for (var i = 0; i &lt; DATA_SIZE; i++) {
+      this.v2++;
+      if (this.v2 &gt; 26) this.v2 = 1;
+      packet.a2[i] = this.v2;
+    }
+    return this.scheduler.queue(packet);
+  }
+};
+
+WorkerTask.prototype.toString = function () {
+  return &quot;WorkerTask&quot;;
+};
+
+/**
+ * A task that manipulates work packets and then suspends itself.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @constructor
+ */
+function HandlerTask(scheduler) {
+  this._scheduler = scheduler;
+  this._v1 = null;
+  this._v2 = null;
+}
+
+HandlerTask.prototype.__defineGetter__(&quot;scheduler&quot;, function() { return this._scheduler; });
+HandlerTask.prototype.__defineGetter__(&quot;v1&quot;, function() { return this._v1; });
+HandlerTask.prototype.__defineSetter__(&quot;v1&quot;, function(value) { this._v1 = value; });
+HandlerTask.prototype.__defineGetter__(&quot;v2&quot;, function() { return this._v2; });
+HandlerTask.prototype.__defineSetter__(&quot;v2&quot;, function(value) { this._v2 = value; });
+
+HandlerTask.prototype.run = function (packet) {
+  if (packet != null) {
+    if (packet.kind == KIND_WORK) {
+      this.v1 = packet.addTo(this.v1);
+    } else {
+      this.v2 = packet.addTo(this.v2);
+    }
+  }
+  if (this.v1 != null) {
+    var count = this.v1.a1;
+    var v;
+    if (count &lt; DATA_SIZE) {
+      if (this.v2 != null) {
+        v = this.v2;
+        this.v2 = this.v2.link;
+        v.a1 = this.v1.a2[count];
+        this.v1.a1 = count + 1;
+        return this.scheduler.queue(v);
+      }
+    } else {
+      v = this.v1;
+      this.v1 = this.v1.link;
+      return this.scheduler.queue(v);
+    }
+  }
+  return this.scheduler.suspendCurrent();
+};
+
+HandlerTask.prototype.toString = function () {
+  return &quot;HandlerTask&quot;;
+};
+
+/* --- *
+ * P a c k e t
+ * --- */
+
+var DATA_SIZE = 4;
+
+/**
+ * A simple package of data that is manipulated by the tasks.  The exact layout
+ * of the payload data carried by a packet is not importaint, and neither is the
+ * nature of the work performed on packets by the tasks.
+ *
+ * Besides carrying data, packets form linked lists and are hence used both as
+ * data and worklists.
+ * @param {Packet} link the tail of the linked list of packets
+ * @param {int} id an ID for this packet
+ * @param {int} kind the type of this packet
+ * @constructor
+ */
+function Packet(link, id, kind) {
+  this._link = link;
+  this._id = id;
+  this._kind = kind;
+  this._a1 = 0;
+  this._a2 = new Array(DATA_SIZE);
+}
+
+Packet.prototype.__defineGetter__(&quot;link&quot;, function() { return this._link; });
+Packet.prototype.__defineSetter__(&quot;link&quot;, function(value) { this._link = value; });
+Packet.prototype.__defineGetter__(&quot;id&quot;, function() { return this._id; });
+Packet.prototype.__defineSetter__(&quot;id&quot;, function(value) { this._id = value; });
+Packet.prototype.__defineGetter__(&quot;kind&quot;, function() { return this._kind; });
+Packet.prototype.__defineGetter__(&quot;a1&quot;, function() { return this._a1; });
+Packet.prototype.__defineSetter__(&quot;a1&quot;, function(value) { this._a1 = value; });
+Packet.prototype.__defineGetter__(&quot;a2&quot;, function() { return this._a2; });
+
+/**
+ * Add this packet to the end of a worklist, and return the worklist.
+ * @param {Packet} queue the worklist to add this packet to
+ */
+Packet.prototype.addTo = function (queue) {
+  this.link = null;
+  if (queue == null) return this;
+  var peek, next = queue;
+  while ((peek = next.link) != null)
+    next = peek;
+  next.link = this;
+  return queue;
+};
+
+Packet.prototype.toString = function () {
+  return &quot;Packet&quot;;
+};
+
+for (var i = 0; i &lt; 350; ++i)
+  runRichards();
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1,3 +1,168 @@
</span><ins>+2014-05-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to
+        https://bugs.webkit.org/show_bug.cgi?id=133105
+
+        Reviewed by Michael Saboff.
+        
+        - GetByIdStatus now knows about getters and can report intelligent things about them.
+          As is usually the case with how we do these things, GetByIdStatus knows more about
+          getters than the DFG can actually handle: it'll report details about polymorphic
+          getter calls even though the DFG won't be able to handle those. This is fine; the DFG
+          will see those statuses and bail to a generic slow path.
+        
+        - The DFG::ByteCodeParser now knows how to set up and do handleCall() for a getter call.
+          This can, and usually does, result in inlining of getters!
+        
+        - CodeOrigin and OSR exit know about inlined getter calls. When you OSR out of an
+          inlined getter, we set the return PC to a getter return thunk that fixes up the stack.
+          We use the usual offset-true-return-PC trick, where OSR exit places the true return PC
+          of the getter's caller as a phony argument that only the thunk knows how to find.
+        
+        - Removed a bunch of dead monomorphic chain support from StructureStubInfo.
+        
+        - A large chunk of this change is dragging GetGetterSetterByOffset, GetGetter, and
+          GetSetter through the DFG and FTL. GetGetterSetterByOffset is like GetByOffset except
+          that we know that we're returning a GetterSetter cell. GetGetter and GetSetter extract
+          the getter, or setter, from the GetterSetter.
+        
+        This is a ~2.5x speed-up on the getter microbenchmarks that we already had. So far none
+        of the &quot;real&quot; benchmarks exercise getters enough for this to matter. But I noticed that
+        some of the variants of the Richards benchmark in other languages - for example
+        Wolczko's Java translation of a C++ translation of Deutsch's Smalltalk version - use
+        getters and setters extensively. So, I created a getter/setter JavaScript version of
+        Richards and put it in regress/script-tests/getter-richards.js. That sees about a 2.4x
+        speed-up from this patch, which is very reassuring.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::printGetByIdCacheStatus):
+        (JSC::CodeBlock::findStubInfo):
+        * bytecode/CodeBlock.h:
+        * bytecode/CodeOrigin.cpp:
+        (WTF::printInternal):
+        * bytecode/CodeOrigin.h:
+        (JSC::InlineCallFrame::specializationKindFor):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFor):
+        (JSC::GetByIdStatus::computeForStubInfo):
+        (JSC::GetByIdStatus::makesCalls):
+        (JSC::GetByIdStatus::computeForChain): Deleted.
+        * bytecode/GetByIdStatus.h:
+        (JSC::GetByIdStatus::makesCalls): Deleted.
+        * bytecode/GetByIdVariant.cpp:
+        (JSC::GetByIdVariant::~GetByIdVariant):
+        (JSC::GetByIdVariant::GetByIdVariant):
+        (JSC::GetByIdVariant::operator=):
+        (JSC::GetByIdVariant::dumpInContext):
+        * bytecode/GetByIdVariant.h:
+        (JSC::GetByIdVariant::GetByIdVariant):
+        (JSC::GetByIdVariant::callLinkStatus):
+        * bytecode/PolymorphicGetByIdList.cpp:
+        (JSC::GetByIdAccess::fromStructureStubInfo):
+        (JSC::PolymorphicGetByIdList::from):
+        * bytecode/SpeculatedType.h:
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::deref):
+        (JSC::StructureStubInfo::visitWeakReferences):
+        * bytecode/StructureStubInfo.h:
+        (JSC::isGetByIdAccess):
+        (JSC::StructureStubInfo::initGetByIdChain): Deleted.
+        * dfg/DFGAbstractHeap.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addCall):
+        (JSC::DFG::ByteCodeParser::handleCall):
+        (JSC::DFG::ByteCodeParser::handleInlining):
+        (JSC::DFG::ByteCodeParser::handleGetByOffset):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+        (JSC::DFG::ByteCodeParser::parse):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination):
+        (JSC::DFG::CSEPhase::getInternalFieldLoadElimination):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        (JSC::DFG::CSEPhase::getTypedArrayByteOffsetLoadElimination): Deleted.
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::linkFunction):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasStorageAccessData):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOSRExitCompilerCommon.cpp:
+        (JSC::DFG::reifyInlinedCallFrames):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLAbstractHeapRepository.cpp:
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLink.cpp:
+        (JSC::FTL::link):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileGetGetter):
+        (JSC::FTL::LowerDFGToLLVM::compileGetSetter):
+        * jit/AccessorCallJITStubRoutine.h:
+        * jit/JIT.cpp:
+        (JSC::JIT::assertStackPointerOffset):
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_id):
+        * jit/ThunkGenerators.cpp:
+        (JSC::arityFixupGenerator):
+        (JSC::baselineGetterReturnThunkGenerator):
+        (JSC::baselineSetterReturnThunkGenerator):
+        (JSC::arityFixup): Deleted.
+        * jit/ThunkGenerators.h:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::setupArityCheckData):
+        * tests/stress/exit-from-getter.js: Added.
+        * tests/stress/poly-chain-getter.js: Added.
+        (Cons):
+        (foo):
+        (test):
+        * tests/stress/poly-chain-then-getter.js: Added.
+        (Cons1):
+        (Cons2):
+        (foo):
+        (test):
+        * tests/stress/poly-getter-combo.js: Added.
+        (Cons1):
+        (Cons2):
+        (foo):
+        (test):
+        (.test):
+        * tests/stress/poly-getter-then-chain.js: Added.
+        (Cons1):
+        (Cons2):
+        (foo):
+        (test):
+        * tests/stress/poly-getter-then-self.js: Added.
+        (foo):
+        (test):
+        (.test):
+        * tests/stress/poly-self-getter.js: Added.
+        (foo):
+        (test):
+        (getter):
+        * tests/stress/poly-self-then-getter.js: Added.
+        (foo):
+        (test):
+        * tests/stress/weird-getter-counter.js: Added.
+        (foo):
+        (test):
+
</ins><span class="cx"> 2014-05-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ftlopt] Factor out how CallLinkStatus uses exit site data
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -352,11 +352,6 @@
</span><span class="cx">                 out.printf(&quot;self&quot;);
</span><span class="cx">                 baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
</span><span class="cx">                 break;
</span><del>-            case access_get_by_id_chain:
-                out.printf(&quot;chain&quot;);
-                baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get();
-                chain = stubInfo.u.getByIdChain.chain.get();
-                break;
</del><span class="cx">             case access_get_by_id_list:
</span><span class="cx">                 out.printf(&quot;list&quot;);
</span><span class="cx">                 list = stubInfo.u.getByIdList.list;
</span><span class="lines">@@ -2344,6 +2339,15 @@
</span><span class="cx">     return m_stubInfos.add();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+StructureStubInfo* CodeBlock::findStubInfo(CodeOrigin codeOrigin)
+{
+    for (StructureStubInfo* stubInfo : m_stubInfos) {
+        if (stubInfo-&gt;codeOrigin == codeOrigin)
+            return stubInfo;
+    }
+    return nullptr;
+}
+
</ins><span class="cx"> CallLinkInfo* CodeBlock::addCallLinkInfo()
</span><span class="cx"> {
</span><span class="cx">     ConcurrentJITLocker locker(m_lock);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -201,6 +201,10 @@
</span><span class="cx">     StructureStubInfo* addStubInfo();
</span><span class="cx">     Bag&lt;StructureStubInfo&gt;::iterator stubInfoBegin() { return m_stubInfos.begin(); }
</span><span class="cx">     Bag&lt;StructureStubInfo&gt;::iterator stubInfoEnd() { return m_stubInfos.end(); }
</span><ins>+    
+    // O(n) operation. Use getStubInfoMap() unless you really only intend to get one
+    // stub info.
+    StructureStubInfo* findStubInfo(CodeOrigin);
</ins><span class="cx"> 
</span><span class="cx">     void resetStub(StructureStubInfo&amp;);
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeCodeOrigincpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -206,6 +206,12 @@
</span><span class="cx">     case JSC::InlineCallFrame::Construct:
</span><span class="cx">         out.print(&quot;Construct&quot;);
</span><span class="cx">         return;
</span><ins>+    case JSC::InlineCallFrame::GetterCall:
+        out.print(&quot;GetterCall&quot;);
+        return;
+    case JSC::InlineCallFrame::SetterCall:
+        out.print(&quot;SetterCall&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeCodeOriginh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/CodeOrigin.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -121,6 +121,11 @@
</span><span class="cx">     enum Kind {
</span><span class="cx">         Call,
</span><span class="cx">         Construct,
</span><ins>+        
+        // For these, the stackOffset incorporates the argument count plus the true return PC
+        // slot.
+        GetterCall,
+        SetterCall
</ins><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     static Kind kindFor(CodeSpecializationKind kind)
</span><span class="lines">@@ -139,6 +144,8 @@
</span><span class="cx">     {
</span><span class="cx">         switch (kind) {
</span><span class="cx">         case Call:
</span><ins>+        case GetterCall:
+        case SetterCall:
</ins><span class="cx">             return CodeForCall;
</span><span class="cx">         case Construct:
</span><span class="cx">             return CodeForConstruct;
</span><span class="lines">@@ -153,7 +160,7 @@
</span><span class="cx">     CodeOrigin caller;
</span><span class="cx">     BitVector capturedVars; // Indexed by the machine call frame's variable numbering.
</span><span class="cx">     signed stackOffset : 30;
</span><del>-    Kind kind : 1;
</del><ins>+    Kind kind : 2;
</ins><span class="cx">     bool isClosureCall : 1; // If false then we know that callee/scope are constants and the DFG won't treat them as variables, i.e. they have to be recovered manually.
</span><span class="cx">     VirtualRegister argumentsRegister; // This is only set if the code uses arguments. The unmodified arguments register follows the unmodifiedArgumentsRegister() convention (see CodeBlock.h).
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;GetByIdStatus.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;AccessorCallJITStubRoutine.h&quot;
</ins><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;JSScope.h&quot;
</span><span class="lines">@@ -89,57 +90,6 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool GetByIdStatus::computeForChain(CodeBlock* profiledBlock, StringImpl* uid, PassRefPtr&lt;IntendedStructureChain&gt; passedChain)
-{
-#if ENABLE(JIT)
-    RefPtr&lt;IntendedStructureChain&gt; chain = passedChain;
-    
-    // Validate the chain. If the chain is invalid, then currently the best thing
-    // we can do is to assume that TakesSlow is true. In the future, it might be
-    // worth exploring reifying the structure chain from the structure we've got
-    // instead of using the one from the cache, since that will do the right things
-    // if the structure chain has changed. But that may be harder, because we may
-    // then end up having a different type of access altogether. And it currently
-    // does not appear to be worth it to do so -- effectively, the heuristic we
-    // have now is that if the structure chain has changed between when it was
-    // cached on in the baseline JIT and when the DFG tried to inline the access,
-    // then we fall back on a polymorphic access.
-    if (!chain-&gt;isStillValid())
-        return false;
-
-    if (chain-&gt;head()-&gt;takesSlowPathInDFGForImpureProperty())
-        return false;
-    size_t chainSize = chain-&gt;size();
-    for (size_t i = 0; i &lt; chainSize; i++) {
-        if (chain-&gt;at(i)-&gt;takesSlowPathInDFGForImpureProperty())
-            return false;
-    }
-
-    JSObject* currentObject = chain-&gt;terminalPrototype();
-    Structure* currentStructure = chain-&gt;last();
-    
-    ASSERT_UNUSED(currentObject, currentObject);
-    
-    unsigned attributesIgnored;
-    JSCell* specificValue;
-    
-    PropertyOffset offset = currentStructure-&gt;getConcurrently(
-        *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
-    if (currentStructure-&gt;isDictionary())
-        specificValue = 0;
-    if (!isValidOffset(offset))
-        return false;
-    
-    return appendVariant(GetByIdVariant(StructureSet(chain-&gt;head()), offset, specificValue, chain));
-#else // ENABLE(JIT)
-    UNUSED_PARAM(profiledBlock);
-    UNUSED_PARAM(uid);
-    UNUSED_PARAM(passedChain);
-    UNREACHABLE_FOR_PLATFORM();
-    return false;
-#endif // ENABLE(JIT)
-}
-
</del><span class="cx"> GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap&amp; map, unsigned bytecodeIndex, StringImpl* uid)
</span><span class="cx"> {
</span><span class="cx">     ConcurrentJITLocker locker(profiledBlock-&gt;m_lock);
</span><span class="lines">@@ -148,12 +98,13 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     result = computeForStubInfo(
</span><del>-        locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid);
</del><ins>+        locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid,
+        CallLinkStatus::computeExitSiteData(locker, profiledBlock, bytecodeIndex));
</ins><span class="cx">     
</span><span class="cx">     if (!result.takesSlowPath()
</span><span class="cx">         &amp;&amp; (hasExitSite(locker, profiledBlock, bytecodeIndex)
</span><span class="cx">             || profiledBlock-&gt;likelyToTakeSlowCase(bytecodeIndex)))
</span><del>-        return GetByIdStatus(TakesSlowPath, true);
</del><ins>+        return GetByIdStatus(result.makesCalls() ? MakesCalls : TakesSlowPath, true);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(map);
</span><span class="cx"> #endif
</span><span class="lines">@@ -166,24 +117,26 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> GetByIdStatus GetByIdStatus::computeForStubInfo(
</span><del>-    const ConcurrentJITLocker&amp;, CodeBlock* profiledBlock, StructureStubInfo* stubInfo,
-    StringImpl* uid)
</del><ins>+    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 GetByIdStatus(NoInformation);
</span><span class="cx">     
</span><del>-    if (stubInfo-&gt;resetByGC)
-        return GetByIdStatus(TakesSlowPath, true);
-
</del><span class="cx">     PolymorphicGetByIdList* list = 0;
</span><ins>+    State slowPathState = TakesSlowPath;
</ins><span class="cx">     if (stubInfo-&gt;accessType == access_get_by_id_list) {
</span><span class="cx">         list = stubInfo-&gt;u.getByIdList.list;
</span><ins>+        
</ins><span class="cx">         for (unsigned i = 0; i &lt; list-&gt;size(); ++i) {
</span><span class="cx">             if (list-&gt;at(i).doesCalls())
</span><del>-                return GetByIdStatus(MakesCalls, true);
</del><ins>+                slowPathState = MakesCalls;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    if (stubInfo-&gt;resetByGC)
+        return GetByIdStatus(slowPathState, true);
+    
</ins><span class="cx">     // Finally figure out if we can derive an access strategy.
</span><span class="cx">     GetByIdStatus result;
</span><span class="cx">     result.m_state = Simple;
</span><span class="lines">@@ -195,14 +148,14 @@
</span><span class="cx">     case access_get_by_id_self: {
</span><span class="cx">         Structure* structure = stubInfo-&gt;u.getByIdSelf.baseObjectStructure.get();
</span><span class="cx">         if (structure-&gt;takesSlowPathInDFGForImpureProperty())
</span><del>-            return GetByIdStatus(TakesSlowPath, true);
</del><ins>+            return GetByIdStatus(slowPathState, true);
</ins><span class="cx">         unsigned attributesIgnored;
</span><span class="cx">         JSCell* specificValue;
</span><span class="cx">         GetByIdVariant variant;
</span><span class="cx">         variant.m_offset = structure-&gt;getConcurrently(
</span><span class="cx">             *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
</span><span class="cx">         if (!isValidOffset(variant.m_offset))
</span><del>-            return GetByIdStatus(TakesSlowPath, true);
</del><ins>+            return GetByIdStatus(slowPathState, true);
</ins><span class="cx">         
</span><span class="cx">         if (structure-&gt;isDictionary())
</span><span class="cx">             specificValue = 0;
</span><span class="lines">@@ -215,8 +168,6 @@
</span><span class="cx">         
</span><span class="cx">     case access_get_by_id_list: {
</span><span class="cx">         for (unsigned listIndex = 0; listIndex &lt; list-&gt;size(); ++listIndex) {
</span><del>-            ASSERT(!list-&gt;at(listIndex).doesCalls());
-            
</del><span class="cx">             Structure* structure = list-&gt;at(listIndex).structure();
</span><span class="cx">             
</span><span class="cx">             // FIXME: We should assert that we never see a structure that
</span><span class="lines">@@ -226,72 +177,112 @@
</span><span class="cx">             // https://bugs.webkit.org/show_bug.cgi?id=131810
</span><span class="cx">             
</span><span class="cx">             if (structure-&gt;takesSlowPathInDFGForImpureProperty())
</span><del>-                return GetByIdStatus(TakesSlowPath, true);
</del><ins>+                return GetByIdStatus(slowPathState, true);
</ins><span class="cx">             
</span><ins>+            unsigned attributesIgnored;
+            JSCell* specificValue;
+            PropertyOffset myOffset;
+            RefPtr&lt;IntendedStructureChain&gt; chain;
+
</ins><span class="cx">             if (list-&gt;at(listIndex).chain()) {
</span><del>-                RefPtr&lt;IntendedStructureChain&gt; chain = adoptRef(new IntendedStructureChain(
</del><ins>+                chain = adoptRef(new IntendedStructureChain(
</ins><span class="cx">                     profiledBlock, structure, list-&gt;at(listIndex).chain(),
</span><span class="cx">                     list-&gt;at(listIndex).chainCount()));
</span><del>-                if (!result.computeForChain(profiledBlock, uid, chain))
-                    return GetByIdStatus(TakesSlowPath, true);
-                continue;
</del><ins>+                
+                if (!chain-&gt;isStillValid())
+                    return GetByIdStatus(slowPathState, true);
+                
+                if (chain-&gt;head()-&gt;takesSlowPathInDFGForImpureProperty())
+                    return GetByIdStatus(slowPathState, true);
+                
+                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);
+                }
+                
+                JSObject* currentObject = chain-&gt;terminalPrototype();
+                Structure* currentStructure = chain-&gt;last();
+                
+                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;
</ins><span class="cx">             }
</span><span class="cx">             
</span><del>-            unsigned attributesIgnored;
-            JSCell* specificValue;
-            PropertyOffset myOffset = structure-&gt;getConcurrently(
-                *profiledBlock-&gt;vm(), uid, attributesIgnored, specificValue);
-            if (structure-&gt;isDictionary())
-                specificValue = 0;
-            
</del><span class="cx">             if (!isValidOffset(myOffset))
</span><del>-                return GetByIdStatus(TakesSlowPath, true);
</del><ins>+                return GetByIdStatus(slowPathState, true);
</ins><span class="cx"> 
</span><del>-            bool found = false;
-            for (unsigned variantIndex = 0; variantIndex &lt; result.m_variants.size(); ++variantIndex) {
-                GetByIdVariant&amp; variant = result.m_variants[variantIndex];
-                if (variant.m_chain)
-                    continue;
</del><ins>+            if (!chain &amp;&amp; !list-&gt;at(listIndex).doesCalls()) {
+                // For non-chain, non-getter accesses, we try to do some coalescing.
+                bool found = false;
+                for (unsigned variantIndex = 0; variantIndex &lt; result.m_variants.size(); ++variantIndex) {
+                    GetByIdVariant&amp; variant = result.m_variants[variantIndex];
+                    if (variant.m_chain)
+                        continue;
</ins><span class="cx">                 
</span><del>-                if (variant.m_offset != myOffset)
-                    continue;
-
-                found = true;
-                if (variant.m_structureSet.contains(structure))
-                    break;
</del><ins>+                    if (variant.m_offset != myOffset)
+                        continue;
</ins><span class="cx">                 
</span><del>-                if (variant.m_specificValue != JSValue(specificValue))
-                    variant.m_specificValue = JSValue();
</del><ins>+                    if (variant.callLinkStatus())
+                        continue;
</ins><span class="cx">                 
</span><del>-                variant.m_structureSet.add(structure);
</del><ins>+                    found = true;
+                    if (variant.m_structureSet.contains(structure))
+                        break;
+                
+                    if (variant.m_specificValue != JSValue(specificValue))
+                        variant.m_specificValue = JSValue();
+                
+                    variant.m_structureSet.add(structure);
+                    break;
+                }
+            
+                if (found)
+                    continue;
+            }
+            
+            std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus;
+            switch (list-&gt;at(listIndex).type()) {
+            case GetByIdAccess::SimpleInline:
+            case GetByIdAccess::SimpleStub: {
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><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
+                return GetByIdStatus(slowPathState, true);
+            }
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+            }
</ins><span class="cx">             
</span><del>-            if (found)
-                continue;
-            
-            if (!result.appendVariant(GetByIdVariant(StructureSet(structure), myOffset, specificValue)))
-                return GetByIdStatus(TakesSlowPath, true);
</del><ins>+            GetByIdVariant variant(
+                StructureSet(structure), myOffset, specificValue, chain,
+                std::move(callLinkStatus));
+            if (!result.appendVariant(variant))
+                return GetByIdStatus(slowPathState, true);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    case access_get_by_id_chain: {
-        if (!stubInfo-&gt;u.getByIdChain.isDirect)
-            return GetByIdStatus(MakesCalls, true);
-        RefPtr&lt;IntendedStructureChain&gt; chain = adoptRef(new IntendedStructureChain(
-            profiledBlock,
-            stubInfo-&gt;u.getByIdChain.baseObjectStructure.get(),
-            stubInfo-&gt;u.getByIdChain.chain.get(),
-            stubInfo-&gt;u.getByIdChain.count));
-        if (result.computeForChain(profiledBlock, uid, chain))
-            return result;
-        return GetByIdStatus(TakesSlowPath, true);
-    }
-        
</del><span class="cx">     default:
</span><del>-        return GetByIdStatus(TakesSlowPath, true);
</del><ins>+        return GetByIdStatus(slowPathState, true);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="lines">@@ -305,10 +296,18 @@
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     if (dfgBlock) {
</span><ins>+        CallLinkStatus::ExitSiteData exitSiteData;
+        {
+            ConcurrentJITLocker locker(profiledBlock-&gt;m_lock);
+            exitSiteData = CallLinkStatus::computeExitSiteData(
+                locker, profiledBlock, codeOrigin.bytecodeIndex, ExitFromFTL);
+        }
+        
</ins><span class="cx">         GetByIdStatus 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">         if (result.takesSlowPath())
</span><span class="lines">@@ -361,6 +360,24 @@
</span><span class="cx">         Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool GetByIdStatus::makesCalls() const
+{
+    switch (m_state) {
+    case NoInformation:
+    case TakesSlowPath:
+        return false;
+    case Simple:
+        for (unsigned i = m_variants.size(); i--;) {
+            if (m_variants[i].callLinkStatus())
+                return true;
+        }
+        return false;
+    case MakesCalls:
+        return true;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> void GetByIdStatus::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     out.print(&quot;(&quot;);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatush"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #ifndef GetByIdStatus_h
</span><span class="cx"> #define GetByIdStatus_h
</span><span class="cx"> 
</span><ins>+#include &quot;CallLinkStatus.h&quot;
</ins><span class="cx"> #include &quot;CodeOrigin.h&quot;
</span><span class="cx"> #include &quot;ConcurrentJITLock.h&quot;
</span><span class="cx"> #include &quot;ExitingJITType.h&quot;
</span><span class="lines">@@ -83,7 +84,7 @@
</span><span class="cx">     const GetByIdVariant&amp; operator[](size_t index) const { return at(index); }
</span><span class="cx"> 
</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">     bool wasSeenInJIT() const { return m_wasSeenInJIT; }
</span><span class="cx">     
</span><span class="lines">@@ -94,9 +95,10 @@
</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 GetByIdStatus computeForStubInfo(const ConcurrentJITLocker&amp;, CodeBlock*, StructureStubInfo*, StringImpl* uid);
</del><ins>+    static GetByIdStatus computeForStubInfo(
+        const ConcurrentJITLocker&amp;, CodeBlock* profiledBlock, StructureStubInfo*,
+        StringImpl* uid, CallLinkStatus::ExitSiteData);
</ins><span class="cx"> #endif
</span><del>-    bool computeForChain(CodeBlock*, StringImpl* uid, PassRefPtr&lt;IntendedStructureChain&gt;);
</del><span class="cx">     static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid);
</span><span class="cx">     
</span><span class="cx">     bool appendVariant(const GetByIdVariant&amp;);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -26,10 +26,31 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;GetByIdVariant.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;CallLinkStatus.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+GetByIdVariant::~GetByIdVariant() { }
+
+GetByIdVariant::GetByIdVariant(const GetByIdVariant&amp; other)
+{
+    *this = other;
+}
+
+GetByIdVariant&amp; GetByIdVariant::operator=(const GetByIdVariant&amp; other)
+{
+    m_structureSet = other.m_structureSet;
+    m_chain = other.m_chain;
+    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;
+}
+
</ins><span class="cx"> void GetByIdVariant::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     dumpInContext(out, 0);
</span><span class="lines">@@ -45,7 +66,10 @@
</span><span class="cx">     out.print(
</span><span class="cx">         &quot;&lt;&quot;, inContext(structureSet(), context), &quot;, &quot;,
</span><span class="cx">         pointerDumpInContext(chain(), context), &quot;, &quot;,
</span><del>-        inContext(specificValue(), context), &quot;, &quot;, offset(), &quot;&gt;&quot;);
</del><ins>+        inContext(specificValue(), context), &quot;, &quot;, offset());
+    if (m_callLinkStatus)
+        out.print(&quot;call: &quot;, *m_callLinkStatus);
+    out.print(&quot;&gt;&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #ifndef GetByIdVariant_h
</span><span class="cx"> #define GetByIdVariant_h
</span><span class="cx"> 
</span><ins>+#include &quot;CallLinkStatus.h&quot;
</ins><span class="cx"> #include &quot;IntendedStructureChain.h&quot;
</span><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><span class="cx"> #include &quot;PropertyOffset.h&quot;
</span><span class="lines">@@ -33,6 +34,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+class CallLinkStatus;
</ins><span class="cx"> class GetByIdStatus;
</span><span class="cx"> struct DumpContext;
</span><span class="cx"> 
</span><span class="lines">@@ -41,11 +43,13 @@
</span><span class="cx">     GetByIdVariant(
</span><span class="cx">         const StructureSet&amp; structureSet = StructureSet(),
</span><span class="cx">         PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(),
</span><del>-        PassRefPtr&lt;IntendedStructureChain&gt; chain = nullptr)
</del><ins>+        PassRefPtr&lt;IntendedStructureChain&gt; chain = nullptr,
+        std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus = nullptr)
</ins><span class="cx">         : m_structureSet(structureSet)
</span><span class="cx">         , m_chain(chain)
</span><span class="cx">         , m_specificValue(specificValue)
</span><span class="cx">         , m_offset(offset)
</span><ins>+        , m_callLinkStatus(std::move(callLinkStatus))
</ins><span class="cx">     {
</span><span class="cx">         if (!structureSet.size()) {
</span><span class="cx">             ASSERT(offset == invalidOffset);
</span><span class="lines">@@ -54,12 +58,18 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    ~GetByIdVariant();
+    
+    GetByIdVariant(const GetByIdVariant&amp;);
+    GetByIdVariant&amp; operator=(const GetByIdVariant&amp;);
+    
</ins><span class="cx">     bool isSet() const { return !!m_structureSet.size(); }
</span><span class="cx">     bool operator!() const { return !isSet(); }
</span><span class="cx">     const StructureSet&amp; structureSet() const { return m_structureSet; }
</span><span class="cx">     IntendedStructureChain* chain() const { return const_cast&lt;IntendedStructureChain*&gt;(m_chain.get()); }
</span><span class="cx">     JSValue specificValue() const { return m_specificValue; }
</span><span class="cx">     PropertyOffset offset() const { return m_offset; }
</span><ins>+    CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); }
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     void dumpInContext(PrintStream&amp;, DumpContext*) const;
</span><span class="lines">@@ -71,6 +81,7 @@
</span><span class="cx">     RefPtr&lt;IntendedStructureChain&gt; m_chain;
</span><span class="cx">     JSValue m_specificValue;
</span><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="branchesftloptSourceJavaScriptCorebytecodePolymorphicGetByIdListcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -58,28 +58,12 @@
</span><span class="cx">     
</span><span class="cx">     GetByIdAccess result;
</span><span class="cx">     
</span><del>-    switch (stubInfo.accessType) {
-    case access_get_by_id_self:
-        result.m_type = SimpleInline;
-        result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure);
-        result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath);
-        break;
-        
-    case access_get_by_id_chain:
-        result.m_structure.copyFrom(stubInfo.u.getByIdChain.baseObjectStructure);
-        result.m_chain.copyFrom(stubInfo.u.getByIdChain.chain);
-        result.m_chainCount = stubInfo.u.getByIdChain.count;
-        result.m_stubRoutine = stubInfo.stubRoutine;
-        if (stubInfo.u.getByIdChain.isDirect)
-            result.m_type = SimpleStub;
-        else
-            result.m_type = Getter;
-        break;
-        
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-    }
</del><ins>+    RELEASE_ASSERT(stubInfo.accessType == access_get_by_id_self);
</ins><span class="cx">     
</span><ins>+    result.m_type = SimpleInline;
+    result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure);
+    result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath);
+    
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -109,7 +93,6 @@
</span><span class="cx">     
</span><span class="cx">     ASSERT(
</span><span class="cx">         stubInfo.accessType == access_get_by_id_self
</span><del>-        || stubInfo.accessType == access_get_by_id_chain
</del><span class="cx">         || stubInfo.accessType == access_unset);
</span><span class="cx">     
</span><span class="cx">     PolymorphicGetByIdList* result = new PolymorphicGetByIdList(stubInfo);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeSpeculatedTypeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/SpeculatedType.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/SpeculatedType.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/SpeculatedType.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx"> static const SpeculatedType SpecStringIdent        = 0x00010000; // It's definitely a JSString, and it's an identifier.
</span><span class="cx"> static const SpeculatedType SpecStringVar          = 0x00020000; // It's definitely a JSString, and it's not an identifier.
</span><span class="cx"> static const SpeculatedType SpecString             = 0x00030000; // It's definitely a JSString.
</span><del>-static const SpeculatedType SpecCellOther          = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
</del><ins>+static const SpeculatedType SpecCellOther          = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078
</ins><span class="cx"> static const SpeculatedType SpecCell               = 0x0007ffff; // It's definitely a JSCell.
</span><span class="cx"> static const SpeculatedType SpecInt32              = 0x00200000; // It's definitely an Int32.
</span><span class="cx"> static const SpeculatedType SpecInt52              = 0x00400000; // It's definitely an Int52 and we intend it to unbox it.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeStructureStubInfocpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -49,7 +49,6 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     case access_get_by_id_self:
</span><del>-    case access_get_by_id_chain:
</del><span class="cx">     case access_put_by_id_transition_normal:
</span><span class="cx">     case access_put_by_id_transition_direct:
</span><span class="cx">     case access_put_by_id_replace:
</span><span class="lines">@@ -68,11 +67,6 @@
</span><span class="cx">         if (!Heap::isMarked(u.getByIdSelf.baseObjectStructure.get()))
</span><span class="cx">             return false;
</span><span class="cx">         break;
</span><del>-    case access_get_by_id_chain:
-        if (!Heap::isMarked(u.getByIdChain.baseObjectStructure.get())
-            || !Heap::isMarked(u.getByIdChain.chain.get()))
-            return false;
-        break;
</del><span class="cx">     case access_get_by_id_list: {
</span><span class="cx">         if (!u.getByIdList.list-&gt;visitWeak(repatchBuffer))
</span><span class="cx">             return false;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeStructureStubInfoh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/StructureStubInfo.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -47,7 +47,6 @@
</span><span class="cx"> 
</span><span class="cx"> enum AccessType {
</span><span class="cx">     access_get_by_id_self,
</span><del>-    access_get_by_id_chain,
</del><span class="cx">     access_get_by_id_list,
</span><span class="cx">     access_put_by_id_transition_normal,
</span><span class="cx">     access_put_by_id_transition_direct,
</span><span class="lines">@@ -61,7 +60,6 @@
</span><span class="cx"> {
</span><span class="cx">     switch (accessType) {
</span><span class="cx">     case access_get_by_id_self:
</span><del>-    case access_get_by_id_chain:
</del><span class="cx">     case access_get_by_id_list:
</span><span class="cx">         return true;
</span><span class="cx">     default:
</span><span class="lines">@@ -107,16 +105,6 @@
</span><span class="cx">         u.getByIdSelf.baseObjectStructure.set(vm, owner, baseObjectStructure);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void initGetByIdChain(VM&amp; vm, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect)
-    {
-        accessType = access_get_by_id_chain;
-
-        u.getByIdChain.baseObjectStructure.set(vm, owner, baseObjectStructure);
-        u.getByIdChain.chain.set(vm, owner, chain);
-        u.getByIdChain.count = count;
-        u.getByIdChain.isDirect = isDirect;
-    }
-
</del><span class="cx">     void initGetByIdList(PolymorphicGetByIdList* list)
</span><span class="cx">     {
</span><span class="cx">         accessType = access_get_by_id_list;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractHeaph"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -50,6 +50,8 @@
</span><span class="cx">     macro(Butterfly_arrayBuffer) \
</span><span class="cx">     macro(Butterfly_publicLength) \
</span><span class="cx">     macro(Butterfly_vectorLength) \
</span><ins>+    macro(GetterSetter_getter) \
+    macro(GetterSetter_setter) \
</ins><span class="cx">     macro(JSArrayBufferView_length) \
</span><span class="cx">     macro(JSArrayBufferView_mode) \
</span><span class="cx">     macro(JSArrayBufferView_vector) \
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1415,6 +1415,8 @@
</span><span class="cx">         break;
</span><span class="cx">         
</span><span class="cx">     case GetCallee:
</span><ins>+    case GetGetter:
+    case GetSetter:
</ins><span class="cx">         forNode(node).setType(SpecFunction);
</span><span class="cx">         break;
</span><span class="cx">         
</span><span class="lines">@@ -1640,6 +1642,11 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case GetGetterSetterByOffset: {
+        forNode(node).set(m_graph, m_graph.m_vm.getterSetterStructure.get());
+        break;
+    }
+        
</ins><span class="cx">     case MultiGetByOffset: {
</span><span class="cx">         AbstractValue&amp; value = forNode(node-&gt;child1());
</span><span class="cx">         ASSERT(!(value.m_type &amp; ~SpecCell)); // Edge filtering should have already ensured this.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -171,21 +171,21 @@
</span><span class="cx">     bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis);
</span><span class="cx">     
</span><span class="cx">     // Handle calls. This resolves issues surrounding inlining and intrinsics.
</span><ins>+    void handleCall(
+        int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,
+        Node* callTarget, int argCount, int registerOffset, CallLinkStatus);
</ins><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="cx">     void emitFunctionChecks(const CallLinkStatus&amp;, Node* callTarget, int registerOffset, CodeSpecializationKind);
</span><span class="cx">     void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind);
</span><span class="cx">     // Handle inlining. Return true if it succeeded, false if we need to plant a call.
</span><del>-    bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&amp;, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
</del><ins>+    bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&amp;, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind);
</ins><span class="cx">     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
</span><span class="cx">     bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction);
</span><span class="cx">     bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType);
</span><span class="cx">     bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
</span><span class="cx">     Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value);
</span><del>-    Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset);
-    void handleGetByOffset(
-        int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber,
-        PropertyOffset);
</del><ins>+    Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, NodeType op = GetByOffset);
</ins><span class="cx">     void handleGetById(
</span><span class="cx">         int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber,
</span><span class="cx">         const GetByIdStatus&amp;);
</span><span class="lines">@@ -811,11 +811,11 @@
</span><span class="cx">         m_numPassedVarArgs++;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* addCall(int result, NodeType op, int callee, int argCount, int registerOffset)
</del><ins>+    Node* addCall(int result, NodeType op, Node* callee, int argCount, int registerOffset)
</ins><span class="cx">     {
</span><span class="cx">         SpeculatedType prediction = getPrediction();
</span><span class="cx">         
</span><del>-        addVarArgChild(get(VirtualRegister(callee)));
</del><ins>+        addVarArgChild(callee);
</ins><span class="cx">         size_t parameterSlots = JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + argCount;
</span><span class="cx">         if (parameterSlots &gt; m_parameterSlots)
</span><span class="cx">             m_parameterSlots = parameterSlots;
</span><span class="lines">@@ -1120,7 +1120,7 @@
</span><span class="cx">             VirtualRegister returnValueVR,
</span><span class="cx">             VirtualRegister inlineCallFrameStart,
</span><span class="cx">             int argumentCountIncludingThis,
</span><del>-            CodeSpecializationKind);
</del><ins>+            InlineCallFrame::Kind);
</ins><span class="cx">         
</span><span class="cx">         ~InlineStackEntry()
</span><span class="cx">         {
</span><span class="lines">@@ -1203,26 +1203,35 @@
</span><span class="cx">     int result, NodeType op, CodeSpecializationKind kind, unsigned instructionSize,
</span><span class="cx">     int callee, int argumentCountIncludingThis, int registerOffset)
</span><span class="cx"> {
</span><ins>+    Node* callTarget = get(VirtualRegister(callee));
+    
+    CallLinkStatus callLinkStatus = CallLinkStatus::computeFor(
+        m_inlineStackTop-&gt;m_profiledBlock, currentCodeOrigin(),
+        m_inlineStackTop-&gt;m_callLinkInfos, m_callContextMap);
+    
+    handleCall(
+        result, op, InlineCallFrame::kindFor(kind), instructionSize, callTarget,
+        argumentCountIncludingThis, registerOffset, callLinkStatus);
+}
+    
+void ByteCodeParser::handleCall(
+    int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize,
+    Node* callTarget, int argumentCountIncludingThis, int registerOffset,
+    CallLinkStatus callLinkStatus)
+{
</ins><span class="cx">     ASSERT(registerOffset &lt;= 0);
</span><ins>+    CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
</ins><span class="cx">     
</span><del>-    Node* callTarget = get(VirtualRegister(callee));
-    
-    CallLinkStatus callLinkStatus;
-
</del><span class="cx">     if (m_graph.isConstant(callTarget)) {
</span><span class="cx">         callLinkStatus = CallLinkStatus(
</span><span class="cx">             m_graph.valueOfJSConstant(callTarget)).setIsProved(true);
</span><del>-    } else {
-        callLinkStatus = CallLinkStatus::computeFor(
-            m_inlineStackTop-&gt;m_profiledBlock, currentCodeOrigin(),
-            m_inlineStackTop-&gt;m_callLinkInfos, m_callContextMap);
</del><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (!callLinkStatus.canOptimize()) {
</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, callee, argumentCountIncludingThis, registerOffset);
</del><ins>+        addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -1230,28 +1239,28 @@
</span><span class="cx">     SpeculatedType prediction = getPrediction();
</span><span class="cx"> 
</span><span class="cx">     if (InternalFunction* function = callLinkStatus.internalFunction()) {
</span><del>-        if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, kind)) {
</del><ins>+        if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, specializationKind)) {
</ins><span class="cx">             // This phantoming has to be *after* the code for the intrinsic, to signify that
</span><span class="cx">             // the inputs must be kept alive whatever exits the intrinsic may do.
</span><span class="cx">             addToGraph(Phantom, callTarget);
</span><del>-            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind);
</del><ins>+            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
</ins><span class="cx">             return;
</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, callee, argumentCountIncludingThis, registerOffset);
</del><ins>+        addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    Intrinsic intrinsic = callLinkStatus.intrinsicFor(kind);
</del><ins>+    Intrinsic intrinsic = callLinkStatus.intrinsicFor(specializationKind);
</ins><span class="cx">     if (intrinsic != NoIntrinsic) {
</span><del>-        emitFunctionChecks(callLinkStatus, callTarget, registerOffset, kind);
</del><ins>+        emitFunctionChecks(callLinkStatus, callTarget, registerOffset, specializationKind);
</ins><span class="cx">             
</span><span class="cx">         if (handleIntrinsic(result, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) {
</span><span class="cx">             // This phantoming has to be *after* the code for the intrinsic, to signify that
</span><span class="cx">             // the inputs must be kept alive whatever exits the intrinsic may do.
</span><span class="cx">             addToGraph(Phantom, callTarget);
</span><del>-            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind);
</del><ins>+            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
</ins><span class="cx">             if (m_graph.compilation())
</span><span class="cx">                 m_graph.compilation()-&gt;noticeInlinedCall();
</span><span class="cx">             return;
</span><span class="lines">@@ -1262,7 +1271,7 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    addCall(result, op, callee, argumentCountIncludingThis, registerOffset);
</del><ins>+    addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ByteCodeParser::emitFunctionChecks(const CallLinkStatus&amp; callLinkStatus, Node* callTarget, int registerOffset, CodeSpecializationKind kind)
</span><span class="lines">@@ -1297,10 +1306,12 @@
</span><span class="cx">         addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset)));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&amp; callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind)
</del><ins>+bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&amp; callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind)
</ins><span class="cx"> {
</span><span class="cx">     static const bool verbose = false;
</span><span class="cx">     
</span><ins>+    CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
+    
</ins><span class="cx">     if (verbose)
</span><span class="cx">         dataLog(&quot;Considering inlining &quot;, callLinkStatus, &quot; into &quot;, currentCodeOrigin(), &quot;\n&quot;);
</span><span class="cx">     
</span><span class="lines">@@ -1333,14 +1344,14 @@
</span><span class="cx">     // if we had a static proof of what was being called; this might happen for example if you call a
</span><span class="cx">     // global function, where watchpointing gives us static information. Overall, it's a rare case
</span><span class="cx">     // because we expect that any hot callees would have already been compiled.
</span><del>-    CodeBlock* codeBlock = executable-&gt;baselineCodeBlockFor(kind);
</del><ins>+    CodeBlock* codeBlock = executable-&gt;baselineCodeBlockFor(specializationKind);
</ins><span class="cx">     if (!codeBlock) {
</span><span class="cx">         if (verbose)
</span><span class="cx">             dataLog(&quot;    Failing because no code block available.\n&quot;);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel(
</span><del>-        codeBlock, kind, callLinkStatus.isClosureCall());
</del><ins>+        codeBlock, specializationKind, callLinkStatus.isClosureCall());
</ins><span class="cx">     if (!canInline(capabilityLevel)) {
</span><span class="cx">         if (verbose)
</span><span class="cx">             dataLog(&quot;    Failing because the function is not inlineable.\n&quot;);
</span><span class="lines">@@ -1392,7 +1403,7 @@
</span><span class="cx">     // Now we know without a doubt that we are committed to inlining. So begin the process
</span><span class="cx">     // by checking the callee (if necessary) and making sure that arguments and the callee
</span><span class="cx">     // are flushed.
</span><del>-    emitFunctionChecks(callLinkStatus, callTargetNode, registerOffset, kind);
</del><ins>+    emitFunctionChecks(callLinkStatus, callTargetNode, registerOffset, specializationKind);
</ins><span class="cx">     
</span><span class="cx">     // FIXME: Don't flush constants!
</span><span class="cx">     
</span><span class="lines">@@ -1850,14 +1861,14 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset)
</del><ins>+Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset, NodeType op)
</ins><span class="cx"> {
</span><span class="cx">     Node* propertyStorage;
</span><span class="cx">     if (isInlineOffset(offset))
</span><span class="cx">         propertyStorage = base;
</span><span class="cx">     else
</span><span class="cx">         propertyStorage = addToGraph(GetButterfly, base);
</span><del>-    Node* getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base);
</del><ins>+    Node* getByOffset = addToGraph(op, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base);
</ins><span class="cx"> 
</span><span class="cx">     StorageAccessData storageAccessData;
</span><span class="cx">     storageAccessData.offset = offset;
</span><span class="lines">@@ -1867,13 +1878,6 @@
</span><span class="cx">     return getByOffset;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ByteCodeParser::handleGetByOffset(
-    int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber,
-    PropertyOffset offset)
-{
-    set(VirtualRegister(destinationOperand), handleGetByOffset(prediction, base, identifierNumber, offset));
-}
-
</del><span class="cx"> Node* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, PropertyOffset offset, Node* value)
</span><span class="cx"> {
</span><span class="cx">     Node* propertyStorage;
</span><span class="lines">@@ -1910,18 +1914,19 @@
</span><span class="cx">     int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber,
</span><span class="cx">     const GetByIdStatus&amp; getByIdStatus)
</span><span class="cx"> {
</span><ins>+    NodeType getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById;
+    
</ins><span class="cx">     if (!getByIdStatus.isSimple() || !Options::enableAccessInlining()) {
</span><span class="cx">         set(VirtualRegister(destinationOperand),
</span><del>-            addToGraph(
-                getByIdStatus.makesCalls() ? GetByIdFlush : GetById,
-                OpInfo(identifierNumber), OpInfo(prediction), base));
</del><ins>+            addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base));
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (getByIdStatus.numVariants() &gt; 1) {
</span><del>-        if (!isFTL(m_graph.m_plan.mode) || !Options::enablePolymorphicAccessInlining()) {
</del><ins>+        if (getByIdStatus.makesCalls() || !isFTL(m_graph.m_plan.mode)
+            || !Options::enablePolymorphicAccessInlining()) {
</ins><span class="cx">             set(VirtualRegister(destinationOperand),
</span><del>-                addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base));
</del><ins>+                addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -1954,7 +1959,7 @@
</span><span class="cx">     if (m_graph.compilation())
</span><span class="cx">         m_graph.compilation()-&gt;noticeInlinedGetById();
</span><span class="cx">     
</span><del>-    Node* originalBaseForBaselineJIT = base;
</del><ins>+    Node* originalBase = base;
</ins><span class="cx">                 
</span><span class="cx">     addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base);
</span><span class="cx">     
</span><span class="lines">@@ -1969,18 +1974,59 @@
</span><span class="cx">     // on something other than the base following the CheckStructure on base, or if the
</span><span class="cx">     // access was compiled to a WeakJSConstant specific value, in which case we might not
</span><span class="cx">     // have any explicit use of the base at all.
</span><del>-    if (variant.specificValue() || originalBaseForBaselineJIT != base)
-        addToGraph(Phantom, originalBaseForBaselineJIT);
</del><ins>+    if (variant.specificValue() || originalBase != base)
+        addToGraph(Phantom, originalBase);
</ins><span class="cx">     
</span><del>-    if (variant.specificValue()) {
-        ASSERT(variant.specificValue().isCell());
-        
-        set(VirtualRegister(destinationOperand), cellConstant(variant.specificValue().asCell()));
</del><ins>+    Node* loadedValue;
+    if (variant.specificValue())
+        loadedValue = cellConstant(variant.specificValue().asCell());
+    else {
+        loadedValue = handleGetByOffset(
+            prediction, base, identifierNumber, variant.offset(),
+            variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset);
+    }
+    
+    if (!variant.callLinkStatus()) {
+        set(VirtualRegister(destinationOperand), loadedValue);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    handleGetByOffset(
-        destinationOperand, prediction, base, identifierNumber, variant.offset());
</del><ins>+    Node* getter = addToGraph(GetGetter, 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++; // 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());
+    
+    // Issue SetLocals. This has two effects:
+    // 1) That's how handleCall() sees the arguments.
+    // 2) If we inline then this ensures that the arguments are flushed so that if you use
+    //    the dreaded arguments object on the getter, the right things happen. Well, sort of -
+    //    since we only really care about 'this' in this case. But we're not going to take that
+    //    shortcut.
+    int nextRegister = registerOffset + JSStack::CallFrameHeaderSize;
+    set(VirtualRegister(nextRegister++), originalBase, ImmediateNakedSet);
+    
+    handleCall(
+        destinationOperand, Call, InlineCallFrame::GetterCall, OPCODE_LENGTH(op_get_by_id),
+        getter, numberOfParameters - 1, registerOffset, *variant.callLinkStatus());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ByteCodeParser::emitPutById(
</span><span class="lines">@@ -3376,7 +3422,7 @@
</span><span class="cx">     VirtualRegister returnValueVR,
</span><span class="cx">     VirtualRegister inlineCallFrameStart,
</span><span class="cx">     int argumentCountIncludingThis,
</span><del>-    CodeSpecializationKind kind)
</del><ins>+    InlineCallFrame::Kind kind)
</ins><span class="cx">     : m_byteCodeParser(byteCodeParser)
</span><span class="cx">     , m_codeBlock(codeBlock)
</span><span class="cx">     , m_profiledBlock(profiledBlock)
</span><span class="lines">@@ -3435,7 +3481,7 @@
</span><span class="cx">             m_inlineCallFrame-&gt;isClosureCall = true;
</span><span class="cx">         m_inlineCallFrame-&gt;caller = byteCodeParser-&gt;currentCodeOrigin();
</span><span class="cx">         m_inlineCallFrame-&gt;arguments.resize(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet.
</span><del>-        m_inlineCallFrame-&gt;kind = InlineCallFrame::kindFor(kind);
</del><ins>+        m_inlineCallFrame-&gt;kind = kind;
</ins><span class="cx">         
</span><span class="cx">         if (m_inlineCallFrame-&gt;caller.inlineCallFrame)
</span><span class="cx">             m_inlineCallFrame-&gt;capturedVars = m_inlineCallFrame-&gt;caller.inlineCallFrame-&gt;capturedVars;
</span><span class="lines">@@ -3674,7 +3720,7 @@
</span><span class="cx">     
</span><span class="cx">     InlineStackEntry inlineStackEntry(
</span><span class="cx">         this, m_codeBlock, m_profiledBlock, 0, 0, VirtualRegister(), VirtualRegister(),
</span><del>-        m_codeBlock-&gt;numParameters(), CodeForCall);
</del><ins>+        m_codeBlock-&gt;numParameters(), InlineCallFrame::Call);
</ins><span class="cx">     
</span><span class="cx">     parseCodeBlock();
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGCSEPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -690,6 +690,40 @@
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    Node* getGetterSetterByOffsetLoadElimination(unsigned identifierNumber, Node* base)
+    {
+        for (unsigned i = m_indexInBlock; i--;) {
+            Node* node = m_currentBlock-&gt;at(i);
+            if (node == base)
+                break;
+
+            switch (node-&gt;op()) {
+            case GetGetterSetterByOffset:
+                if (node-&gt;child2() == base
+                    &amp;&amp; m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber == identifierNumber)
+                    return node;
+                break;
+                    
+            case PutByValDirect:
+            case PutByVal:
+            case PutByValAlias:
+                if (m_graph.byValIsPure(node)) {
+                    // If PutByVal speculates that it's accessing an array with an
+                    // integer index, then it's impossible for it to cause a structure
+                    // change.
+                    break;
+                }
+                return 0;
+                
+            default:
+                if (m_graph.clobbersWorld(node))
+                    return 0;
+                break;
+            }
+        }
+        return 0;
+    }
+    
</ins><span class="cx">     Node* putByOffsetStoreElimination(unsigned identifierNumber, Node* child1)
</span><span class="cx">     {
</span><span class="cx">         for (unsigned i = m_indexInBlock; i--;) {
</span><span class="lines">@@ -845,25 +879,18 @@
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* getTypedArrayByteOffsetLoadElimination(Node* child1)
</del><ins>+    Node* getInternalFieldLoadElimination(NodeType op, Node* child1)
</ins><span class="cx">     {
</span><span class="cx">         for (unsigned i = m_indexInBlock; i--;) {
</span><span class="cx">             Node* node = m_currentBlock-&gt;at(i);
</span><span class="cx">             if (node == child1) 
</span><span class="cx">                 break;
</span><span class="cx"> 
</span><del>-            switch (node-&gt;op()) {
-            case GetTypedArrayByteOffset: {
-                if (node-&gt;child1() == child1)
-                    return node;
-                break;
-            }
</del><ins>+            if (node-&gt;op() == op &amp;&amp; node-&gt;child1() == child1)
+                return node;
</ins><span class="cx"> 
</span><del>-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
-                break;
-            }
</del><ins>+            if (m_graph.clobbersWorld(node))
+                return 0;
</ins><span class="cx">         }
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="lines">@@ -1401,10 +1428,12 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case GetTypedArrayByteOffset: {
</del><ins>+        case GetTypedArrayByteOffset:
+        case GetGetter:
+        case GetSetter: {
</ins><span class="cx">             if (cseMode == StoreElimination)
</span><span class="cx">                 break;
</span><del>-            setReplacement(getTypedArrayByteOffsetLoadElimination(node-&gt;child1().node()));
</del><ins>+            setReplacement(getInternalFieldLoadElimination(node-&gt;op(), node-&gt;child1().node()));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1420,6 +1449,12 @@
</span><span class="cx">             setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber, node-&gt;child2().node()));
</span><span class="cx">             break;
</span><span class="cx">             
</span><ins>+        case GetGetterSetterByOffset:
+            if (cseMode == StoreElimination)
+                break;
+            setReplacement(getGetterSetterByOffsetLoadElimination(m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber, node-&gt;child2().node()));
+            break;
+            
</ins><span class="cx">         case MultiGetByOffset:
</span><span class="cx">             if (cseMode == StoreElimination)
</span><span class="cx">                 break;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -213,6 +213,14 @@
</span><span class="cx">         write(World);
</span><span class="cx">         return;
</span><span class="cx">         
</span><ins>+    case GetGetter:
+        read(GetterSetter_getter);
+        return;
+        
+    case GetSetter:
+        read(GetterSetter_setter);
+        return;
+        
</ins><span class="cx">     case GetCallee:
</span><span class="cx">         read(AbstractHeap(Variables, JSStack::Callee));
</span><span class="cx">         return;
</span><span class="lines">@@ -481,6 +489,7 @@
</span><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetByOffset:
</span><ins>+    case GetGetterSetterByOffset:
</ins><span class="cx">         read(AbstractHeap(NamedProperties, graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber));
</span><span class="cx">         return;
</span><span class="cx">         
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -885,7 +885,9 @@
</span><span class="cx">         case GetClosureRegisters:
</span><span class="cx">         case SkipTopScope:
</span><span class="cx">         case SkipScope:
</span><del>-        case GetScope: {
</del><ins>+        case GetScope:
+        case GetGetter:
+        case GetSetter: {
</ins><span class="cx">             fixEdge&lt;KnownCellUse&gt;(node-&gt;child1());
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="lines">@@ -945,7 +947,8 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case GetByOffset: {
</del><ins>+        case GetByOffset:
+        case GetGetterSetterByOffset: {
</ins><span class="cx">             if (!node-&gt;child1()-&gt;hasStorageResult())
</span><span class="cx">                 fixEdge&lt;KnownCellUse&gt;(node-&gt;child1());
</span><span class="cx">             fixEdge&lt;KnownCellUse&gt;(node-&gt;child2());
</span><span class="lines">@@ -1034,6 +1037,8 @@
</span><span class="cx">             Node* globalObjectNode = m_insertionSet.insertNode(
</span><span class="cx">                 m_indexInBlock, SpecNone, WeakJSConstant, node-&gt;origin, 
</span><span class="cx">                 OpInfo(m_graph.globalObjectFor(node-&gt;origin.semantic)));
</span><ins>+            // FIXME: This probably shouldn't have an unconditional barrier.
+            // https://bugs.webkit.org/show_bug.cgi?id=133104
</ins><span class="cx">             Node* barrierNode = m_graph.addNode(
</span><span class="cx">                 SpecNone, StoreBarrier, m_currentNode-&gt;origin, 
</span><span class="cx">                 Edge(globalObjectNode, KnownCellUse));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGJITCompilercpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -417,7 +417,7 @@
</span><span class="cx">     m_jitCode-&gt;shrinkToFit();
</span><span class="cx">     codeBlock()-&gt;shrinkToFit(CodeBlock::LateShrink);
</span><span class="cx">     
</span><del>-    linkBuffer-&gt;link(m_callArityFixup, FunctionPtr((m_vm-&gt;getCTIStub(arityFixup)).code().executableAddress()));
</del><ins>+    linkBuffer-&gt;link(m_callArityFixup, FunctionPtr((m_vm-&gt;getCTIStub(arityFixupGenerator)).code().executableAddress()));
</ins><span class="cx">     
</span><span class="cx">     disassemble(*linkBuffer);
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1146,7 +1146,7 @@
</span><span class="cx">     
</span><span class="cx">     bool hasStorageAccessData()
</span><span class="cx">     {
</span><del>-        return op() == GetByOffset || op() == PutByOffset;
</del><ins>+        return op() == GetByOffset || op() == GetGetterSetterByOffset || op() == PutByOffset;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     unsigned storageAccessDataIndex()
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGNodeType.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGNodeType.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGNodeType.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -176,7 +176,10 @@
</span><span class="cx">     macro(GetIndexedPropertyStorage, NodeResultStorage) \
</span><span class="cx">     macro(ConstantStoragePointer, NodeResultStorage) \
</span><span class="cx">     macro(TypedArrayWatchpoint, NodeMustGenerate) \
</span><ins>+    macro(GetGetter, NodeResultJS) \
+    macro(GetSetter, NodeResultJS) \
</ins><span class="cx">     macro(GetByOffset, NodeResultJS) \
</span><ins>+    macro(GetGetterSetterByOffset, NodeResultJS) \
</ins><span class="cx">     macro(MultiGetByOffset, NodeResultJS) \
</span><span class="cx">     macro(PutByOffset, NodeMustGenerate) \
</span><span class="cx">     macro(MultiPutByOffset, NodeMustGenerate) \
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGOSRExitCompilerCommoncpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -108,12 +108,44 @@
</span><span class="cx">         InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
</span><span class="cx">         CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin);
</span><span class="cx">         CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame-&gt;caller);
</span><ins>+        void* jumpTarget;
+        void* trueReturnPC = nullptr;
+        
</ins><span class="cx">         unsigned callBytecodeIndex = inlineCallFrame-&gt;caller.bytecodeIndex;
</span><del>-        CallLinkInfo* callLinkInfo =
-            baselineCodeBlockForCaller-&gt;getCallLinkInfoForBytecodeIndex(callBytecodeIndex);
-        RELEASE_ASSERT(callLinkInfo);
</del><span class="cx">         
</span><del>-        void* jumpTarget = callLinkInfo-&gt;callReturnLocation.executableAddress();
</del><ins>+        switch (inlineCallFrame-&gt;kind) {
+        case InlineCallFrame::Call:
+        case InlineCallFrame::Construct: {
+            CallLinkInfo* callLinkInfo =
+                baselineCodeBlockForCaller-&gt;getCallLinkInfoForBytecodeIndex(callBytecodeIndex);
+            RELEASE_ASSERT(callLinkInfo);
+            
+            jumpTarget = callLinkInfo-&gt;callReturnLocation.executableAddress();
+            break;
+        }
+            
+        case InlineCallFrame::GetterCall:
+        case InlineCallFrame::SetterCall: {
+            StructureStubInfo* stubInfo =
+                baselineCodeBlockForCaller-&gt;findStubInfo(CodeOrigin(callBytecodeIndex));
+            RELEASE_ASSERT(stubInfo);
+            
+            switch (inlineCallFrame-&gt;kind) {
+            case InlineCallFrame::GetterCall:
+                jumpTarget = jit.vm()-&gt;getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress();
+                break;
+            case InlineCallFrame::SetterCall:
+                jumpTarget = jit.vm()-&gt;getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress();
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+            
+            trueReturnPC = stubInfo-&gt;callReturnLocation.labelAtOffset(
+                stubInfo-&gt;patch.deltaCallToDone).executableAddress();
+            break;
+        } }
</ins><span class="cx"> 
</span><span class="cx">         GPRReg callerFrameGPR;
</span><span class="cx">         if (inlineCallFrame-&gt;caller.inlineCallFrame) {
</span><span class="lines">@@ -122,12 +154,15 @@
</span><span class="cx">         } else
</span><span class="cx">             callerFrameGPR = GPRInfo::callFrameRegister;
</span><span class="cx">         
</span><ins>+        jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame-&gt;returnPCOffset()));
+        if (trueReturnPC)
+            jit.storePtr(AssemblyHelpers::TrustedImmPtr(trueReturnPC), AssemblyHelpers::addressFor(inlineCallFrame-&gt;stackOffset + virtualRegisterForArgument(inlineCallFrame-&gt;arguments.size()).offset()));
+                         
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">         jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame-&gt;stackOffset + JSStack::CodeBlock)));
</span><span class="cx">         if (!inlineCallFrame-&gt;isClosureCall)
</span><span class="cx">             jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame-&gt;calleeConstant()-&gt;scope()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame-&gt;stackOffset + JSStack::ScopeChain)));
</span><span class="cx">         jit.store64(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame-&gt;callerFrameOffset()));
</span><del>-        jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame-&gt;returnPCOffset()));
</del><span class="cx">         uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin.bytecodeIndex);
</span><span class="cx">         jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame-&gt;stackOffset + JSStack::ArgumentCount)));
</span><span class="cx">         jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame-&gt;arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame-&gt;stackOffset + JSStack::ArgumentCount)));
</span><span class="lines">@@ -143,7 +178,6 @@
</span><span class="cx">         if (!inlineCallFrame-&gt;isClosureCall)
</span><span class="cx">             jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame-&gt;calleeConstant()-&gt;scope()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame-&gt;stackOffset + JSStack::ScopeChain)));
</span><span class="cx">         jit.storePtr(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame-&gt;callerFrameOffset()));
</span><del>-        jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame-&gt;returnPCOffset()));
</del><span class="cx">         Instruction* instruction = baselineCodeBlock-&gt;instructions().begin() + codeOrigin.bytecodeIndex;
</span><span class="cx">         uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction);
</span><span class="cx">         jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame-&gt;stackOffset + JSStack::ArgumentCount)));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -188,7 +188,21 @@
</span><span class="cx">             changed |= setPrediction(node-&gt;getHeapPrediction());
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+            
+        case GetGetterSetterByOffset: {
+            changed |= setPrediction(SpecCellOther);
+            break;
+        }
</ins><span class="cx"> 
</span><ins>+        case GetGetter:
+        case GetSetter:
+        case GetCallee:
+        case NewFunctionNoCheck:
+        case NewFunctionExpression: {
+            changed |= setPrediction(SpecFunction);
+            break;
+        }
+
</ins><span class="cx">         case StringCharCodeAt: {
</span><span class="cx">             changed |= setPrediction(SpecInt32);
</span><span class="cx">             break;
</span><span class="lines">@@ -423,11 +437,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case GetCallee: {
-            changed |= setPrediction(SpecFunction);
-            break;
-        }
-            
</del><span class="cx">         case CreateThis:
</span><span class="cx">         case NewObject: {
</span><span class="cx">             changed |= setPrediction(SpecFinalObject);
</span><span class="lines">@@ -490,12 +499,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case NewFunctionNoCheck:
-        case NewFunctionExpression: {
-            changed |= setPrediction(SpecFunction);
-            break;
-        }
-            
</del><span class="cx">         case PutByValAlias:
</span><span class="cx">         case GetArrayLength:
</span><span class="cx">         case GetTypedArrayByteOffset:
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -253,6 +253,8 @@
</span><span class="cx">     case ValueRep:
</span><span class="cx">     case DoubleRep:
</span><span class="cx">     case Int52Rep:
</span><ins>+    case GetGetter:
+    case GetSetter:
</ins><span class="cx">         return true;
</span><span class="cx">         
</span><span class="cx">     case GetByVal:
</span><span class="lines">@@ -285,6 +287,7 @@
</span><span class="cx">             StructureSet(node-&gt;structureTransitionData().previousStructure));
</span><span class="cx">         
</span><span class="cx">     case GetByOffset:
</span><ins>+    case GetGetterSetterByOffset:
</ins><span class="cx">     case PutByOffset:
</span><span class="cx">         return state.forNode(node-&gt;child1()).m_currentKnownStructure.isValidOffset(
</span><span class="cx">             graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].offset);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;DFGOperations.h&quot;
</span><span class="cx"> #include &quot;DFGSlowPathGenerator.h&quot;
</span><span class="cx"> #include &quot;Debugger.h&quot;
</span><ins>+#include &quot;GetterSetter.h&quot;
</ins><span class="cx"> #include &quot;JSActivation.h&quot;
</span><span class="cx"> #include &quot;ObjectPrototype.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="lines">@@ -3792,6 +3793,47 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case GetGetterSetterByOffset: {
+        StorageOperand storage(this, node-&gt;child1());
+        GPRTemporary resultPayload(this);
+        
+        GPRReg storageGPR = storage.gpr();
+        GPRReg resultPayloadGPR = resultPayload.gpr();
+        
+        StorageAccessData&amp; storageAccessData = m_jit.graph().m_storageAccessData[node-&gt;storageAccessDataIndex()];
+        
+        m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
+        
+        cellResult(resultPayloadGPR, node);
+        break;
+    }
+        
+    case GetGetter: {
+        SpeculateCellOperand op1(this, node-&gt;child1());
+        GPRTemporary result(this, Reuse, op1);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR);
+        
+        cellResult(resultGPR, node);
+        break;
+    }
+        
+    case GetSetter: {
+        SpeculateCellOperand op1(this, node-&gt;child1());
+        GPRTemporary result(this, Reuse, op1);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR);
+        
+        cellResult(resultGPR, node);
+        break;
+    }
+        
</ins><span class="cx">     case PutByOffset: {
</span><span class="cx">         StorageOperand storage(this, node-&gt;child1());
</span><span class="cx">         JSValueOperand value(this, node-&gt;child3());
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;DFGOperations.h&quot;
</span><span class="cx"> #include &quot;DFGSlowPathGenerator.h&quot;
</span><span class="cx"> #include &quot;Debugger.h&quot;
</span><ins>+#include &quot;GetterSetter.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;ObjectPrototype.h&quot;
</span><span class="cx"> #include &quot;SpillRegistersMode.h&quot;
</span><span class="lines">@@ -3853,7 +3854,8 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    case GetByOffset: {
</del><ins>+    case GetByOffset:
+    case GetGetterSetterByOffset: {
</ins><span class="cx">         StorageOperand storage(this, node-&gt;child1());
</span><span class="cx">         GPRTemporary result(this, Reuse, storage);
</span><span class="cx">         
</span><span class="lines">@@ -3868,6 +3870,32 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case GetGetter: {
+        SpeculateCellOperand op1(this, node-&gt;child1());
+        GPRTemporary result(this, Reuse, op1);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR);
+        
+        cellResult(resultGPR, node);
+        break;
+    }
+        
+    case GetSetter: {
+        SpeculateCellOperand op1(this, node-&gt;child1());
+        GPRTemporary result(this, Reuse, op1);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR);
+        
+        cellResult(resultGPR, node);
+        break;
+    }
+        
</ins><span class="cx">     case PutByOffset: {
</span><span class="cx">         StorageOperand storage(this, node-&gt;child1());
</span><span class="cx">         JSValueOperand value(this, node-&gt;child3());
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLAbstractHeapRepositorycpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(FTL_JIT)
</span><span class="cx"> 
</span><ins>+#include &quot;GetterSetter.h&quot;
</ins><span class="cx"> #include &quot;JSScope.h&quot;
</span><span class="cx"> #include &quot;JSVariableObject.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -46,6 +46,8 @@
</span><span class="cx">     macro(Butterfly_publicLength, Butterfly::offsetOfPublicLength()) \
</span><span class="cx">     macro(Butterfly_vectorLength, Butterfly::offsetOfVectorLength()) \
</span><span class="cx">     macro(CallFrame_callerFrame, CallFrame::callerFrameOffset()) \
</span><ins>+    macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \
+    macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \
</ins><span class="cx">     macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \
</span><span class="cx">     macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \
</span><span class="cx">     macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -72,6 +72,9 @@
</span><span class="cx">     case NewArray:
</span><span class="cx">     case NewArrayBuffer:
</span><span class="cx">     case GetByOffset:
</span><ins>+    case GetGetterSetterByOffset:
+    case GetGetter:
+    case GetSetter:
</ins><span class="cx">     case PutByOffset:
</span><span class="cx">     case GetGlobalVar:
</span><span class="cx">     case PutGlobalVar:
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLLinkcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLLink.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLLink.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLLink.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -178,7 +178,7 @@
</span><span class="cx"> 
</span><span class="cx">         linkBuffer = adoptPtr(new LinkBuffer(vm, &amp;jit, codeBlock, JITCompilationMustSucceed));
</span><span class="cx">         linkBuffer-&gt;link(callArityCheck, codeBlock-&gt;m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
</span><del>-        linkBuffer-&gt;link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixup)).code().executableAddress()));
</del><ins>+        linkBuffer-&gt;link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress()));
</ins><span class="cx">         linkBuffer-&gt;link(mainPathJumps, CodeLocationLabel(bitwise_cast&lt;void*&gt;(state.generatedFunction)));
</span><span class="cx"> 
</span><span class="cx">         state.jitCode-&gt;initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast&lt;void*&gt;(state.generatedFunction)));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -493,8 +493,15 @@
</span><span class="cx">             compileStringCharCodeAt();
</span><span class="cx">             break;
</span><span class="cx">         case GetByOffset:
</span><ins>+        case GetGetterSetterByOffset:
</ins><span class="cx">             compileGetByOffset();
</span><span class="cx">             break;
</span><ins>+        case GetGetter:
+            compileGetGetter();
+            break;
+        case GetSetter:
+            compileGetSetter();
+            break;
</ins><span class="cx">         case MultiGetByOffset:
</span><span class="cx">             compileMultiGetByOffset();
</span><span class="cx">             break;
</span><span class="lines">@@ -3141,6 +3148,16 @@
</span><span class="cx">             lowStorage(m_node-&gt;child1()), data.identifierNumber, data.offset));
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void compileGetGetter()
+    {
+        setJSValue(m_out.loadPtr(lowCell(m_node-&gt;child1()), m_heaps.GetterSetter_getter));
+    }
+    
+    void compileGetSetter()
+    {
+        setJSValue(m_out.loadPtr(lowCell(m_node-&gt;child1()), m_heaps.GetterSetter_setter));
+    }
+    
</ins><span class="cx">     void compileMultiGetByOffset()
</span><span class="cx">     {
</span><span class="cx">         LValue base = lowCell(m_node-&gt;child1());
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitAccessorCallJITStubRoutineh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -46,7 +46,6 @@
</span><span class="cx">     
</span><span class="cx">     virtual bool visitWeak(RepatchBuffer&amp;) override;
</span><span class="cx">     
</span><del>-private:
</del><span class="cx">     std::unique_ptr&lt;CallLinkInfo&gt; m_callLinkInfo;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/JIT.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/JIT.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/jit/JIT.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -108,6 +108,17 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+void JIT::assertStackPointerOffset()
+{
+    if (ASSERT_DISABLED)
+        return;
+    
+    addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, regT0);
+    Jump ok = branchPtr(Equal, regT0, stackPointerRegister);
+    breakpoint();
+    ok.link(this);
+}
+
</ins><span class="cx"> #define NEXT_OPCODE(name) \
</span><span class="cx">     m_bytecodeOffset += OPCODE_LENGTH(name); \
</span><span class="cx">     break;
</span><span class="lines">@@ -570,7 +581,7 @@
</span><span class="cx"> #endif
</span><span class="cx">         move(TrustedImmPtr(m_vm-&gt;arityCheckFailReturnThunks-&gt;returnPCsFor(*m_vm, m_codeBlock-&gt;numParameters())), thunkReg);
</span><span class="cx">         loadPtr(BaseIndex(thunkReg, regT0, timesPtr()), thunkReg);
</span><del>-        emitNakedCall(m_vm-&gt;getCTIStub(arityFixup).code());
</del><ins>+        emitNakedCall(m_vm-&gt;getCTIStub(arityFixupGenerator).code());
</ins><span class="cx"> 
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">         m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/JIT.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/JIT.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/jit/JIT.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -446,6 +446,8 @@
</span><span class="cx"> 
</span><span class="cx">         void emit_compareAndJump(OpcodeID, int op1, int op2, unsigned target, RelationalCondition);
</span><span class="cx">         void emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><ins>+        
+        void assertStackPointerOffset();
</ins><span class="cx"> 
</span><span class="cx">         void emit_op_touch_entry(Instruction*);
</span><span class="cx">         void emit_op_add(Instruction*);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitJITPropertyAccesscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/JITPropertyAccess.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -528,6 +528,7 @@
</span><span class="cx"> 
</span><span class="cx">     emitValueProfilingSite();
</span><span class="cx">     emitPutVirtualRegister(resultVReg);
</span><ins>+    assertStackPointerOffset();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitThunkGeneratorscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -430,7 +430,7 @@
</span><span class="cx">     return nativeForGenerator(vm, CodeForConstruct);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MacroAssemblerCodeRef arityFixup(VM* vm)
</del><ins>+MacroAssemblerCodeRef arityFixupGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx">     JSInterfaceJIT jit(vm);
</span><span class="cx"> 
</span><span class="lines">@@ -533,6 +533,83 @@
</span><span class="cx">     return FINALIZE_CODE(patchBuffer, (&quot;fixup arity&quot;));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef baselineGetterReturnThunkGenerator(VM* vm)
+{
+    JSInterfaceJIT jit(vm);
+    
+#if USE(JSVALUE64)
+    jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0);
+#else
+    jit.setupResults(GPRInfo::regT0, GPRInfo::regT1);
+#endif
+    
+    unsigned numberOfParameters = 0;
+    numberOfParameters++; // The 'this' argument.
+    numberOfParameters++; // The true return PC.
+    
+    unsigned numberOfRegsForCall =
+        JSStack::CallFrameHeaderSize + numberOfParameters;
+    
+    unsigned numberOfBytesForCall =
+        numberOfRegsForCall * sizeof(Register) - sizeof(CallerFrameAndPC);
+    
+    unsigned alignedNumberOfBytesForCall =
+        WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall);
+            
+    // The real return address is stored above the arguments. We passed one argument, which is
+    // 'this'. So argument at index 1 is the return address.
+    jit.loadPtr(
+        AssemblyHelpers::Address(
+            AssemblyHelpers::stackPointerRegister,
+            (virtualRegisterForArgument(1).offset() - JSStack::CallerFrameAndPCSize) * sizeof(Register)),
+        GPRInfo::regT2);
+    
+    jit.addPtr(
+        AssemblyHelpers::TrustedImm32(alignedNumberOfBytesForCall),
+        AssemblyHelpers::stackPointerRegister);
+    
+    jit.jump(GPRInfo::regT2);
+
+    LinkBuffer patchBuffer(*vm, &amp;jit, GLOBAL_THUNK_ID);
+    return FINALIZE_CODE(patchBuffer, (&quot;baseline getter return thunk&quot;));
+}
+
+MacroAssemblerCodeRef baselineSetterReturnThunkGenerator(VM* vm)
+{
+    JSInterfaceJIT jit(vm);
+    
+    unsigned numberOfParameters = 0;
+    numberOfParameters++; // The 'this' argument.
+    numberOfParameters++; // The value to set.
+    numberOfParameters++; // The true return PC.
+    
+    unsigned numberOfRegsForCall =
+        JSStack::CallFrameHeaderSize + numberOfParameters;
+    
+    unsigned numberOfBytesForCall =
+        numberOfRegsForCall * sizeof(Register) - sizeof(CallerFrameAndPC);
+    
+    unsigned alignedNumberOfBytesForCall =
+        WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall);
+            
+    // The real return address is stored above the arguments. We passed two arguments, so
+    // the argument at index 2 is the return address.
+    jit.loadPtr(
+        AssemblyHelpers::Address(
+            AssemblyHelpers::stackPointerRegister,
+            (virtualRegisterForArgument(2).offset() - JSStack::CallerFrameAndPCSize) * sizeof(Register)),
+        GPRInfo::regT2);
+    
+    jit.addPtr(
+        AssemblyHelpers::TrustedImm32(alignedNumberOfBytesForCall),
+        AssemblyHelpers::stackPointerRegister);
+    
+    jit.jump(GPRInfo::regT2);
+
+    LinkBuffer patchBuffer(*vm, &amp;jit, GLOBAL_THUNK_ID);
+    return FINALIZE_CODE(patchBuffer, (&quot;baseline setter return thunk&quot;));
+}
+
</ins><span class="cx"> static void stringCharLoad(SpecializedThunkJIT&amp; jit, VM* vm)
</span><span class="cx"> {
</span><span class="cx">     // load string
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorejitThunkGeneratorsh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/jit/ThunkGenerators.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -113,8 +113,11 @@
</span><span class="cx"> MacroAssemblerCodeRef nativeCallGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef nativeConstructGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef nativeTailCallGenerator(VM*);
</span><del>-MacroAssemblerCodeRef arityFixup(VM*);
</del><ins>+MacroAssemblerCodeRef arityFixupGenerator(VM*);
</ins><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef baselineGetterReturnThunkGenerator(VM* vm);
+MacroAssemblerCodeRef baselineSetterReturnThunkGenerator(VM* vm);
+
</ins><span class="cx"> MacroAssemblerCodeRef charCodeAtThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef charAtThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef fromCharCodeThunkGenerator(VM*);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeCommonSlowPathscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -170,7 +170,7 @@
</span><span class="cx">     result-&gt;paddedStackSpace = slotsToAdd;
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx">     if (vm.canUseJIT()) {
</span><del>-        result-&gt;thunkToCall = vm.getCTIStub(arityFixup).code().executableAddress();
</del><ins>+        result-&gt;thunkToCall = vm.getCTIStub(arityFixupGenerator).code().executableAddress();
</ins><span class="cx">         result-&gt;returnPC = vm.arityCheckFailReturnThunks-&gt;returnPCFor(vm, slotsToAdd * stackAlignmentRegisters()).executableAddress();
</span><span class="cx">     } else
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressexitfromgetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-getter.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-getter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/exit-from-getter.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+(function() {
+    var o = {_f:42};
+    o.__defineGetter__(&quot;f&quot;, function() { return this._f * 100; });
+    var result = 0;
+    var n = 50000;
+    function foo(o) {
+        return o.f + 11;
+    }
+    noInline(foo);
+    for (var i = 0; i &lt; n; ++i) {
+        result += foo(o);
+    }
+    if (result != n * (42 * 100 + 11))
+        throw &quot;Error: bad result: &quot; + result;
+    o._f = 1000000000;
+    result = 0;
+    for (var i = 0; i &lt; n; ++i) {
+        result += foo(o);
+    }
+    if (result != n * (1000000000 * 100 + 11))
+        throw &quot;Error: bad result (2): &quot; + result;
+})();
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolychaingetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-getter.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-getter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-getter.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+function Cons() {
+}
+Cons.prototype.__defineGetter__(&quot;f&quot;, function() {
+    counter++;
+    return 84;
+});
+
+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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(), 84, counter + 1);
+    
+    var o = new Cons();
+    o.g = 54;
+    test(o, 84, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolychainthengetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+function Cons1() {
+}
+Cons1.prototype.f = 42;
+
+function Cons2() {
+}
+Cons2.prototype.__defineGetter__(&quot;f&quot;, function() {
+    counter++;
+    return 84;
+});
+
+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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(), 42, counter);
+    test(new Cons2(), 84, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolygettercombojs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-combo.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-combo.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-combo.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+function Cons1() {
+}
+Cons1.prototype.f = 42;
+
+function Cons2() {
+}
+Cons2.prototype.__defineGetter__(&quot;f&quot;, function() {
+    counter++;
+    return 84;
+});
+
+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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(), 42, counter);
+    test(new Cons2(), 84, counter + 1);
+    
+    var o = {};
+    o.__defineGetter__(&quot;f&quot;, function() {
+        counter++;
+        return 84;
+    });
+    test(o, 84, counter + 1);
+
+    test({f: 42}, 42, counter);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolygetterthenchainjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+function Cons1() {
+}
+Cons1.prototype.f = 42;
+
+function Cons2() {
+}
+Cons2.prototype.__defineGetter__(&quot;f&quot;, function() {
+    counter++;
+    return 84;
+});
+
+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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 Cons2(), 84, counter + 1);
+    test(new Cons1(), 42, counter);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolygetterthenselfjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-self.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-self.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-getter-then-self.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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.__defineGetter__(&quot;f&quot;, function() {
+        counter++;
+        return 84;
+    });
+    test(o, 84, counter + 1);
+
+    test({f: 42}, 42, counter);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolyselfgetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-getter.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-getter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-getter.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        throw new Error(&quot;Bad result: &quot; + result);
+    if (counter != expectedCount)
+        throw new Error(&quot;Bad counter value: &quot; + counter);
+}
+
+function getter() {
+    counter++;
+    return 84;
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {};
+    o.__defineGetter__(&quot;f&quot;, getter);
+    test(o, 84, counter + 1);
+
+    var o = {};
+    o.__defineGetter__(&quot;f&quot;, getter);
+    o.g = 54;
+    test(o, 84, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstresspolyselfthengetterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-then-getter.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-then-getter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/poly-self-then-getter.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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({f: 42}, 42, counter);
+
+    var o = {};
+    o.__defineGetter__(&quot;f&quot;, function() {
+        counter++;
+        return 84;
+    });
+    test(o, 84, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressweirdgettercounterjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-getter-counter.js (0 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-getter-counter.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/weird-getter-counter.js        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var counter = 0;
+
+function test(o, expected, expectedCount) {
+    var result = foo(o);
+    if (result != expected)
+        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.__defineGetter__(&quot;f&quot;, function() {
+        counter++;
+        return 84;
+    });
+    test(o, 84, counter + 1);
+}
</ins></span></pre></div>
<a id="branchesftloptSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/WTF/ChangeLog (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/WTF/ChangeLog        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/WTF/ChangeLog        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2014-05-19  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to
+        https://bugs.webkit.org/show_bug.cgi?id=133105
+
+        Reviewed by Michael Saboff.
+
+        * wtf/Bag.h:
+        (WTF::Bag::iterator::operator!=):
+
</ins><span class="cx"> 2014-05-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         UNREACHABLE_FOR_PLATFORM() is meant to be a release crash.
</span></span></pre></div>
<a id="branchesftloptSourceWTFwtfBagh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/WTF/wtf/Bag.h (169142 => 169143)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/WTF/wtf/Bag.h        2014-05-21 00:13:30 UTC (rev 169142)
+++ branches/ftlopt/Source/WTF/wtf/Bag.h        2014-05-21 00:44:20 UTC (rev 169143)
</span><span class="lines">@@ -83,6 +83,11 @@
</span><span class="cx">         {
</span><span class="cx">             return m_node == other.m_node;
</span><span class="cx">         }
</span><ins>+        
+        bool operator!=(const iterator&amp; other) const
+        {
+            return !(*this == other);
+        }
</ins><span class="cx">     private:
</span><span class="cx">         template&lt;typename U&gt; friend class WTF::Bag;
</span><span class="cx">         Node* m_node;
</span></span></pre>
</div>
</div>

</body>
</html>