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

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

<h3>Log Message</h3>
<pre>We should be able to inline getter/setter calls inside an inline cache even when the SpillRegistersMode is NeedsToSpill
https://bugs.webkit.org/show_bug.cgi?id=149601

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Before, if we had a PolymorphicAccess with and a StructureStubInfo
with a NeedToSpill spillMode, we wouldn't generate getter/setter
calls. This patch changes it such that we will generate the
getter/setter call and do the necessary register spilling/filling
around the getter/setter call to preserve any &quot;usedRegisters&quot;.

This has an interesting story with how it relates to exception handling 
inside the DFG. Because the GetById variants are considered a throwing call 
site, we must make sure that we properly restore the registers spilled to the stack 
in case of an exception being thrown inside the getter/setter call. We do 
this by having the inline cache register itself as a new exception handling 
call site. When the inline cache &quot;catches&quot; the exception (i.e, genericUnwind 
will jump to this code), it will restore the registers it spilled that are 
live inside the original catch handler, and then jump to the original catch 
handler. We make sure to only generate this makeshift catch handler when we 
actually need to do any cleanup. If we determine that we don't need to restore 
any registers, we don't bother generating this makeshift catch handler.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::handlerForIndex):
(JSC::CodeBlock::newExceptionHandlingCallSiteIndex):
(JSC::CodeBlock::removeExceptionHandlerForCallSite):
(JSC::CodeBlock::lineNumberForBytecodeOffset):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::appendExceptionHandler):
* bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationState::AccessGenerationState):
(JSC::AccessGenerationState::restoreScratch):
(JSC::AccessGenerationState::succeed):
(JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
(JSC::AccessGenerationState::preserveLiveRegistersToStackForCall):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
(JSC::AccessGenerationState::liveRegistersForCall):
(JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
(JSC::AccessGenerationState::callSiteIndexForExceptionHandling):
(JSC::AccessGenerationState::originalExceptionHandler):
(JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation):
(JSC::AccessGenerationState::needsToRestoreRegistersIfException):
(JSC::AccessGenerationState::originalCallSiteIndex):
(JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
(JSC::AccessCase::AccessCase):
(JSC::AccessCase::generate):
(JSC::PolymorphicAccess::regenerateWithCases):
(JSC::PolymorphicAccess::regenerate):
(JSC::PolymorphicAccess::aboutToDie):
* bytecode/PolymorphicAccess.h:
(JSC::AccessCase::doesCalls):
(JSC::AccessCase::isGetter):
(JSC::AccessCase::callLinkInfo):
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::deref):
(JSC::StructureStubInfo::aboutToDie):
(JSC::StructureStubInfo::addAccessCase):
* bytecode/StructureStubInfo.h:
* bytecode/ValueRecovery.h:
(JSC::ValueRecovery::isInJSValueRegs):
(JSC::ValueRecovery::fpr):
* dfg/DFGCommonData.cpp:
(JSC::DFG::CommonData::addCodeOrigin):
(JSC::DFG::CommonData::addCodeOriginUnconditionally):
(JSC::DFG::CommonData::lastCallSite):
(JSC::DFG::CommonData::removeCallSiteIndex):
(JSC::DFG::CommonData::shrinkToFit):
* dfg/DFGCommonData.h:
* dfg/DFGJITCode.cpp:
(JSC::DFG::JITCode::reconstruct):
(JSC::DFG::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
(JSC::DFG::JITCode::checkIfOptimizationThresholdReached):
* dfg/DFGJITCode.h:
(JSC::DFG::JITCode::osrEntryBlock):
(JSC::DFG::JITCode::setOSREntryBlock):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::appendExceptionHandlingOSRExit):
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::OSRExit):
* dfg/DFGOSRExit.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileIn):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLJITCode.cpp:
(JSC::FTL::JITCode::validateReferences):
(JSC::FTL::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
* ftl/FTLJITCode.h:
(JSC::FTL::JITCode::handles):
(JSC::FTL::JITCode::dataSections):
* jit/GCAwareJITStubRoutine.cpp:
(JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine):
(JSC::GCAwareJITStubRoutine::~GCAwareJITStubRoutine):
(JSC::GCAwareJITStubRoutine::observeZeroRefCount):
(JSC::MarkingGCAwareJITStubRoutineWithOneObject::markRequiredObjectsInternal):
(JSC::GCAwareJITStubRoutineWithExceptionHandler::GCAwareJITStubRoutineWithExceptionHandler):
(JSC::GCAwareJITStubRoutineWithExceptionHandler::aboutToDie):
(JSC::GCAwareJITStubRoutineWithExceptionHandler::~GCAwareJITStubRoutineWithExceptionHandler):
(JSC::createJITStubRoutine):
* jit/GCAwareJITStubRoutine.h:
* jit/JITCode.cpp:
(JSC::NativeJITCode::addressForCall):
(JSC::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
* jit/JITCode.h:
* jit/JITInlineCacheGenerator.cpp:
(JSC::JITByIdGenerator::JITByIdGenerator):
(JSC::JITGetByIdGenerator::JITGetByIdGenerator):
(JSC::JITPutByIdGenerator::JITPutByIdGenerator):
* jit/JITInlineCacheGenerator.h:
(JSC::JITByIdGenerator::reportSlowPathCall):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitGetByValWithCachedId):
(JSC::JIT::emitPutByValWithCachedId):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_put_by_id):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitGetByValWithCachedId):
(JSC::JIT::emitPutByValWithCachedId):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_put_by_id):
* jit/JITStubRoutine.h:
(JSC::JITStubRoutine::createSelfManagedRoutine):
(JSC::JITStubRoutine::aboutToDie):
* jit/RegisterSet.cpp:
(JSC::RegisterSet::webAssemblyCalleeSaveRegisters):
(JSC::RegisterSet::registersToNotSaveForCall):
(JSC::RegisterSet::allGPRs):
* jit/RegisterSet.h:
(JSC::RegisterSet::set):
(JSC::RegisterSet::clear):
* jit/ScratchRegisterAllocator.cpp:
(JSC::ScratchRegisterAllocator::allocateScratchGPR):
(JSC::ScratchRegisterAllocator::allocateScratchFPR):
(JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing):
(JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping):
(JSC::ScratchRegisterAllocator::usedRegistersForCall):
(JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall):
(JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall):
(JSC::ScratchRegisterAllocator::preserveRegistersToStackForCall):
(JSC::ScratchRegisterAllocator::restoreRegistersFromStackForCall):
* jit/ScratchRegisterAllocator.h:
(JSC::ScratchRegisterAllocator::numberOfReusedRegisters):
(JSC::ScratchRegisterAllocator::usedRegisters):
* jsc.cpp:
(WTF::CustomGetter::CustomGetter):
(WTF::CustomGetter::createStructure):
(WTF::CustomGetter::create):
(WTF::CustomGetter::getOwnPropertySlot):
(WTF::CustomGetter::customGetter):
(WTF::Element::handleOwner):
(GlobalObject::finishCreation):
(functionCreateImpureGetter):
(functionCreateCustomGetterObject):
(functionSetImpureGetterDelegate):
* tests/stress/try-catch-custom-getter-as-get-by-id.js: Added.
(assert):
(bar):
(foo):
* tests/stress/try-catch-getter-as-get-by-id-register-restoration.js: Added.
(assert):
(o1.get f):
(bar):
(foo):
* tests/stress/try-catch-getter-as-get-by-id.js: Added.
(assert):
(o1.get f):
(bar):
(foo):
* tests/stress/try-catch-setter-as-put-by-id.js: Added.
(assert):
(o1.set f):
(bar):
(foo):
* tests/stress/try-catch-stub-routine-replaced.js: Added.
(assert):
(arr):
(hello):
(foo):
(objChain.get f):
(fakeOut.get f):
(o.get f):

LayoutTests:

* js/regress/custom-setter-getter-as-put-get-by-id-expected.txt: Added.
* js/regress/custom-setter-getter-as-put-get-by-id.html: Added.
* js/regress/script-tests/custom-setter-getter-as-put-get-by-id.js: Added.
(assert):
(test):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp">trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePolymorphicAccessh">trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeStructureStubInfocpp">trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeStructureStubInfoh">trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeValueRecoveryh">trunk/Source/JavaScriptCore/bytecode/ValueRecovery.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonDatacpp">trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonDatah">trunk/Source/JavaScriptCore/dfg/DFGCommonData.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCodecpp">trunk/Source/JavaScriptCore/dfg/DFGJITCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCodeh">trunk/Source/JavaScriptCore/dfg/DFGJITCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCompilercpp">trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOSRExitcpp">trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOSRExith">trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJITCodecpp">trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJITCodeh">trunk/Source/JavaScriptCore/ftl/FTLJITCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitGCAwareJITStubRoutinecpp">trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitGCAwareJITStubRoutineh">trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCodecpp">trunk/Source/JavaScriptCore/jit/JITCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCodeh">trunk/Source/JavaScriptCore/jit/JITCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITInlineCacheGeneratorcpp">trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITInlineCacheGeneratorh">trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccesscpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccess32_64cpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITStubRoutineh">trunk/Source/JavaScriptCore/jit/JITStubRoutine.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegisterSetcpp">trunk/Source/JavaScriptCore/jit/RegisterSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegisterSeth">trunk/Source/JavaScriptCore/jit/RegisterSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitScratchRegisterAllocatorcpp">trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitScratchRegisterAllocatorh">trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregresscustomsettergetterasputgetbyidexpectedtxt">trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregresscustomsettergetterasputgetbyidhtml">trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestscustomsettergetterasputgetbyidjs">trunk/LayoutTests/js/regress/script-tests/custom-setter-getter-as-put-get-by-id.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrycatchcustomgetterasgetbyidjs">trunk/Source/JavaScriptCore/tests/stress/try-catch-custom-getter-as-get-by-id.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrycatchgetterasgetbyidregisterrestorationjs">trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id-register-restoration.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrycatchgetterasgetbyidjs">trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrycatchsetterasputbyidjs">trunk/Source/JavaScriptCore/tests/stress/try-catch-setter-as-put-by-id.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrycatchstubroutinereplacedjs">trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/LayoutTests/ChangeLog        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2015-10-08  Saam barati  &lt;sbarati@apple.com&gt;
+
+        We should be able to inline getter/setter calls inside an inline cache even when the SpillRegistersMode is NeedsToSpill
+        https://bugs.webkit.org/show_bug.cgi?id=149601
+
+        Reviewed by Filip Pizlo.
+
+        * js/regress/custom-setter-getter-as-put-get-by-id-expected.txt: Added.
+        * js/regress/custom-setter-getter-as-put-get-by-id.html: Added.
+        * js/regress/script-tests/custom-setter-getter-as-put-get-by-id.js: Added.
+        (assert):
+        (test):
+
</ins><span class="cx"> 2015-10-08  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         fast/events/scroll-after-click-on-tab-index.html is flaky
</span></span></pre></div>
<a id="trunkLayoutTestsjsregresscustomsettergetterasputgetbyidexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id-expected.txt (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id-expected.txt        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/custom-setter-getter-as-put-get-by-id
+
+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="trunkLayoutTestsjsregresscustomsettergetterasputgetbyidhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id.html (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/custom-setter-getter-as-put-get-by-id.html        2015-10-08 19:37:28 UTC (rev 190735)
</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/custom-setter-getter-as-put-get-by-id.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="trunkLayoutTestsjsregressscripttestscustomsettergetterasputgetbyidjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/custom-setter-getter-as-put-get-by-id.js (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/custom-setter-getter-as-put-get-by-id.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/custom-setter-getter-as-put-get-by-id.js        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;bad assertion&quot;);
+}
+noInline(assert);
+
+// RegExp.input is a handy custom getter/setter.
+var o1 = RegExp;
+function test(o) {
+    o.input = &quot;bar&quot;;
+    return o.input;
+}
+noInline(test);
+
+var o2 = {
+    input: &quot;hello&quot;
+}
+
+var o3 = {
+    x: 20,
+    input: &quot;hello&quot;
+}
+
+// First compile as GetById node.
+for (let i = 0; i &lt; 1000; i++) {
+    assert(test(i % 2 ? o2 : o3) === &quot;bar&quot;);
+}
+
+// Cause the inline cache to generate customSetter/customGetter code on a GetBydId.
+for (let i = 0; i &lt; 100; i++) {
+    assert(test(o1) === &quot;bar&quot;);
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -1,3 +1,196 @@
</span><ins>+2015-10-08  Saam barati  &lt;sbarati@apple.com&gt;
+
+        We should be able to inline getter/setter calls inside an inline cache even when the SpillRegistersMode is NeedsToSpill
+        https://bugs.webkit.org/show_bug.cgi?id=149601
+
+        Reviewed by Filip Pizlo.
+
+        Before, if we had a PolymorphicAccess with and a StructureStubInfo
+        with a NeedToSpill spillMode, we wouldn't generate getter/setter
+        calls. This patch changes it such that we will generate the
+        getter/setter call and do the necessary register spilling/filling
+        around the getter/setter call to preserve any &quot;usedRegisters&quot;.
+
+        This has an interesting story with how it relates to exception handling 
+        inside the DFG. Because the GetById variants are considered a throwing call 
+        site, we must make sure that we properly restore the registers spilled to the stack 
+        in case of an exception being thrown inside the getter/setter call. We do 
+        this by having the inline cache register itself as a new exception handling 
+        call site. When the inline cache &quot;catches&quot; the exception (i.e, genericUnwind 
+        will jump to this code), it will restore the registers it spilled that are 
+        live inside the original catch handler, and then jump to the original catch 
+        handler. We make sure to only generate this makeshift catch handler when we 
+        actually need to do any cleanup. If we determine that we don't need to restore 
+        any registers, we don't bother generating this makeshift catch handler.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::~CodeBlock):
+        (JSC::CodeBlock::handlerForIndex):
+        (JSC::CodeBlock::newExceptionHandlingCallSiteIndex):
+        (JSC::CodeBlock::removeExceptionHandlerForCallSite):
+        (JSC::CodeBlock::lineNumberForBytecodeOffset):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::appendExceptionHandler):
+        * bytecode/PolymorphicAccess.cpp:
+        (JSC::AccessGenerationState::AccessGenerationState):
+        (JSC::AccessGenerationState::restoreScratch):
+        (JSC::AccessGenerationState::succeed):
+        (JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
+        (JSC::AccessGenerationState::preserveLiveRegistersToStackForCall):
+        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
+        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
+        (JSC::AccessGenerationState::liveRegistersForCall):
+        (JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
+        (JSC::AccessGenerationState::callSiteIndexForExceptionHandling):
+        (JSC::AccessGenerationState::originalExceptionHandler):
+        (JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation):
+        (JSC::AccessGenerationState::needsToRestoreRegistersIfException):
+        (JSC::AccessGenerationState::originalCallSiteIndex):
+        (JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
+        (JSC::AccessCase::AccessCase):
+        (JSC::AccessCase::generate):
+        (JSC::PolymorphicAccess::regenerateWithCases):
+        (JSC::PolymorphicAccess::regenerate):
+        (JSC::PolymorphicAccess::aboutToDie):
+        * bytecode/PolymorphicAccess.h:
+        (JSC::AccessCase::doesCalls):
+        (JSC::AccessCase::isGetter):
+        (JSC::AccessCase::callLinkInfo):
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::deref):
+        (JSC::StructureStubInfo::aboutToDie):
+        (JSC::StructureStubInfo::addAccessCase):
+        * bytecode/StructureStubInfo.h:
+        * bytecode/ValueRecovery.h:
+        (JSC::ValueRecovery::isInJSValueRegs):
+        (JSC::ValueRecovery::fpr):
+        * dfg/DFGCommonData.cpp:
+        (JSC::DFG::CommonData::addCodeOrigin):
+        (JSC::DFG::CommonData::addCodeOriginUnconditionally):
+        (JSC::DFG::CommonData::lastCallSite):
+        (JSC::DFG::CommonData::removeCallSiteIndex):
+        (JSC::DFG::CommonData::shrinkToFit):
+        * dfg/DFGCommonData.h:
+        * dfg/DFGJITCode.cpp:
+        (JSC::DFG::JITCode::reconstruct):
+        (JSC::DFG::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
+        (JSC::DFG::JITCode::checkIfOptimizationThresholdReached):
+        * dfg/DFGJITCode.h:
+        (JSC::DFG::JITCode::osrEntryBlock):
+        (JSC::DFG::JITCode::setOSREntryBlock):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::appendExceptionHandlingOSRExit):
+        * dfg/DFGOSRExit.cpp:
+        (JSC::DFG::OSRExit::OSRExit):
+        * dfg/DFGOSRExit.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileIn):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::cachedPutById):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::cachedPutById):
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::mmAllocateDataSection):
+        * ftl/FTLJITCode.cpp:
+        (JSC::FTL::JITCode::validateReferences):
+        (JSC::FTL::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
+        * ftl/FTLJITCode.h:
+        (JSC::FTL::JITCode::handles):
+        (JSC::FTL::JITCode::dataSections):
+        * jit/GCAwareJITStubRoutine.cpp:
+        (JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine):
+        (JSC::GCAwareJITStubRoutine::~GCAwareJITStubRoutine):
+        (JSC::GCAwareJITStubRoutine::observeZeroRefCount):
+        (JSC::MarkingGCAwareJITStubRoutineWithOneObject::markRequiredObjectsInternal):
+        (JSC::GCAwareJITStubRoutineWithExceptionHandler::GCAwareJITStubRoutineWithExceptionHandler):
+        (JSC::GCAwareJITStubRoutineWithExceptionHandler::aboutToDie):
+        (JSC::GCAwareJITStubRoutineWithExceptionHandler::~GCAwareJITStubRoutineWithExceptionHandler):
+        (JSC::createJITStubRoutine):
+        * jit/GCAwareJITStubRoutine.h:
+        * jit/JITCode.cpp:
+        (JSC::NativeJITCode::addressForCall):
+        (JSC::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
+        * jit/JITCode.h:
+        * jit/JITInlineCacheGenerator.cpp:
+        (JSC::JITByIdGenerator::JITByIdGenerator):
+        (JSC::JITGetByIdGenerator::JITGetByIdGenerator):
+        (JSC::JITPutByIdGenerator::JITPutByIdGenerator):
+        * jit/JITInlineCacheGenerator.h:
+        (JSC::JITByIdGenerator::reportSlowPathCall):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitGetByValWithCachedId):
+        (JSC::JIT::emitPutByValWithCachedId):
+        (JSC::JIT::emit_op_get_by_id):
+        (JSC::JIT::emit_op_put_by_id):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emitGetByValWithCachedId):
+        (JSC::JIT::emitPutByValWithCachedId):
+        (JSC::JIT::emit_op_get_by_id):
+        (JSC::JIT::emit_op_put_by_id):
+        * jit/JITStubRoutine.h:
+        (JSC::JITStubRoutine::createSelfManagedRoutine):
+        (JSC::JITStubRoutine::aboutToDie):
+        * jit/RegisterSet.cpp:
+        (JSC::RegisterSet::webAssemblyCalleeSaveRegisters):
+        (JSC::RegisterSet::registersToNotSaveForCall):
+        (JSC::RegisterSet::allGPRs):
+        * jit/RegisterSet.h:
+        (JSC::RegisterSet::set):
+        (JSC::RegisterSet::clear):
+        * jit/ScratchRegisterAllocator.cpp:
+        (JSC::ScratchRegisterAllocator::allocateScratchGPR):
+        (JSC::ScratchRegisterAllocator::allocateScratchFPR):
+        (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing):
+        (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping):
+        (JSC::ScratchRegisterAllocator::usedRegistersForCall):
+        (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall):
+        (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall):
+        (JSC::ScratchRegisterAllocator::preserveRegistersToStackForCall):
+        (JSC::ScratchRegisterAllocator::restoreRegistersFromStackForCall):
+        * jit/ScratchRegisterAllocator.h:
+        (JSC::ScratchRegisterAllocator::numberOfReusedRegisters):
+        (JSC::ScratchRegisterAllocator::usedRegisters):
+        * jsc.cpp:
+        (WTF::CustomGetter::CustomGetter):
+        (WTF::CustomGetter::createStructure):
+        (WTF::CustomGetter::create):
+        (WTF::CustomGetter::getOwnPropertySlot):
+        (WTF::CustomGetter::customGetter):
+        (WTF::Element::handleOwner):
+        (GlobalObject::finishCreation):
+        (functionCreateImpureGetter):
+        (functionCreateCustomGetterObject):
+        (functionSetImpureGetterDelegate):
+        * tests/stress/try-catch-custom-getter-as-get-by-id.js: Added.
+        (assert):
+        (bar):
+        (foo):
+        * tests/stress/try-catch-getter-as-get-by-id-register-restoration.js: Added.
+        (assert):
+        (o1.get f):
+        (bar):
+        (foo):
+        * tests/stress/try-catch-getter-as-get-by-id.js: Added.
+        (assert):
+        (o1.get f):
+        (bar):
+        (foo):
+        * tests/stress/try-catch-setter-as-put-by-id.js: Added.
+        (assert):
+        (o1.set f):
+        (bar):
+        (foo):
+        * tests/stress/try-catch-stub-routine-replaced.js: Added.
+        (assert):
+        (arr):
+        (hello):
+        (foo):
+        (objChain.get f):
+        (fakeOut.get f):
+        (o.get f):
+
</ins><span class="cx"> 2015-10-08  Commit Queue  &lt;commit-queue@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r190716.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -2263,8 +2263,11 @@
</span><span class="cx">     // destructors.
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-    for (Bag&lt;StructureStubInfo&gt;::iterator iter = m_stubInfos.begin(); !!iter; ++iter)
-        (*iter)-&gt;deref();
</del><ins>+    for (Bag&lt;StructureStubInfo&gt;::iterator iter = m_stubInfos.begin(); !!iter; ++iter) {
+        StructureStubInfo* stub = *iter;
+        stub-&gt;aboutToDie();
+        stub-&gt;deref();
+    }
</ins><span class="cx"> #endif // ENABLE(JIT)
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2982,6 +2985,38 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CallSiteIndex CodeBlock::newExceptionHandlingCallSiteIndex(CallSiteIndex originalCallSite)
+{
+#if ENABLE(DFG_JIT)
+    RELEASE_ASSERT(jitType() == JITCode::DFGJIT); // FIXME: When implementing FTL try/catch we should include that JITType here as well: https://bugs.webkit.org/show_bug.cgi?id=149409
+    RELEASE_ASSERT(canGetCodeOrigin(originalCallSite));
+    ASSERT(!!handlerForIndex(originalCallSite.bits()));
+    CodeOrigin originalOrigin = codeOrigin(originalCallSite);
+    return m_jitCode-&gt;dfgCommon()-&gt;addCodeOriginUnconditionally(originalOrigin);
+#else
+    // We never create new on-the-fly exception handling
+    // call sites outside the DFG/FTL inline caches.
+    RELEASE_ASSERT_NOT_REACHED();
+    return CallSiteIndex(0);
+#endif
+}
+
+void CodeBlock::removeExceptionHandlerForCallSite(CallSiteIndex callSiteIndex)
+{
+    RELEASE_ASSERT(m_rareData);
+    Vector&lt;HandlerInfo&gt;&amp; exceptionHandlers = m_rareData-&gt;m_exceptionHandlers;
+    unsigned index = callSiteIndex.bits();
+    for (size_t i = 0; i &lt; exceptionHandlers.size(); ++i) {
+        HandlerInfo&amp; handler = exceptionHandlers[i];
+        if (handler.start &lt;= index &amp;&amp; handler.end &gt; index) {
+            exceptionHandlers.remove(i);
+            return;
+        }
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> unsigned CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(bytecodeOffset &lt; instructions().size());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -217,6 +217,7 @@
</span><span class="cx">     };
</span><span class="cx">     HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler);
</span><span class="cx">     HandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler);
</span><ins>+    void removeExceptionHandlerForCallSite(CallSiteIndex);
</ins><span class="cx">     unsigned lineNumberForBytecodeOffset(unsigned bytecodeOffset);
</span><span class="cx">     unsigned columnNumberForBytecodeOffset(unsigned bytecodeOffset);
</span><span class="cx">     void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int&amp; divot,
</span><span class="lines">@@ -916,6 +917,8 @@
</span><span class="cx">         m_rareData-&gt;m_exceptionHandlers.append(handler);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    CallSiteIndex newExceptionHandlingCallSiteIndex(CallSiteIndex originalCallSite);
+
</ins><span class="cx"> protected:
</span><span class="cx">     void finalizeLLIntInlineCaches();
</span><span class="cx">     void finalizeBaselineJITInlineCaches();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> #include &quot;JITOperations.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;LinkBuffer.h&quot;
</span><ins>+#include &quot;MaxFrameExtentForSlowPathCall.h&quot;
</ins><span class="cx"> #include &quot;ScratchRegisterAllocator.h&quot;
</span><span class="cx"> #include &quot;StructureStubClearingWatchpoint.h&quot;
</span><span class="cx"> #include &quot;StructureStubInfo.h&quot;
</span><span class="lines">@@ -47,9 +48,15 @@
</span><span class="cx"> static const bool verbose = false;
</span><span class="cx"> 
</span><span class="cx"> struct AccessGenerationState {
</span><ins>+    AccessGenerationState() 
+        : m_calculatedRegistersForCallAndExceptionHandling(false)
+        , m_needsToRestoreRegistersIfException(false)
+        , m_calculatedCallSiteIndex(false)
+    {
+    }
</ins><span class="cx">     CCallHelpers* jit { nullptr };
</span><span class="cx">     ScratchRegisterAllocator* allocator;
</span><del>-    size_t numberOfPaddingBytes { 0 };
</del><ins>+    unsigned numberOfBytesUsedToPreserveReusedRegisters { 0 };
</ins><span class="cx">     PolymorphicAccess* access { nullptr };
</span><span class="cx">     StructureStubInfo* stubInfo { nullptr };
</span><span class="cx">     CCallHelpers::JumpList success;
</span><span class="lines">@@ -71,7 +78,7 @@
</span><span class="cx"> 
</span><span class="cx">     void restoreScratch()
</span><span class="cx">     {
</span><del>-        allocator-&gt;restoreReusedRegistersByPopping(*jit, numberOfPaddingBytes);
</del><ins>+        allocator-&gt;restoreReusedRegistersByPopping(*jit, numberOfBytesUsedToPreserveReusedRegisters);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void succeed()
</span><span class="lines">@@ -79,6 +86,127 @@
</span><span class="cx">         restoreScratch();
</span><span class="cx">         success.append(jit-&gt;jump());
</span><span class="cx">     }
</span><ins>+
+    void calculateLiveRegistersForCallAndExceptionHandling()
+    {
+        if (!m_calculatedRegistersForCallAndExceptionHandling) {
+            m_calculatedRegistersForCallAndExceptionHandling = true;
+
+            m_liveRegistersToPreserveAtExceptionHandlingCallSite = jit-&gt;codeBlock()-&gt;jitCode()-&gt;liveRegistersToPreserveAtExceptionHandlingCallSite(jit-&gt;codeBlock(), stubInfo-&gt;callSiteIndex);
+            m_needsToRestoreRegistersIfException = m_liveRegistersToPreserveAtExceptionHandlingCallSite.numberOfSetRegisters() &gt; 0;
+            if (m_needsToRestoreRegistersIfException)
+                RELEASE_ASSERT(JITCode::isOptimizingJIT(jit-&gt;codeBlock()-&gt;jitType()));
+
+            m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator-&gt;usedRegisters());
+            m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForCall());
+        }
+    }
+
+    void preserveLiveRegistersToStackForCall()
+    {
+        unsigned extraStackPadding = 0;
+        unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegistersForCall(), extraStackPadding);
+        if (m_numberOfStackBytesUsedForRegisterPreservation != std::numeric_limits&lt;unsigned&gt;::max())
+            RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == m_numberOfStackBytesUsedForRegisterPreservation);
+        m_numberOfStackBytesUsedForRegisterPreservation = numberOfStackBytesUsedForRegisterPreservation;
+    }
+
+    void restoreLiveRegistersFromStackForCall(bool isGetter)
+    {
+        RegisterSet dontRestore;
+        if (isGetter) {
+            // This is the result value. We don't want to overwrite the result with what we stored to the stack.
+            // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
+            dontRestore.set(valueRegs); 
+        }
+        restoreLiveRegistersFromStackForCall(dontRestore);
+    }
+
+    void restoreLiveRegistersFromStackForCallWithThrownException()
+    {
+        // Even if we're a getter, we don't want to ignore the result value like we normally do 
+        // because the getter threw, and therefore, didn't return a value that means anything. 
+        // Instead, we want to restore that register to what it was upon entering the getter 
+        // inline cache. The subtlety here is if the base and the result are the same register, 
+        // and the getter threw, we want OSR exit to see the original base value, not the result 
+        // of the getter call.
+        RegisterSet dontRestore = liveRegistersForCall();
+        // As an optimization here, we only need to restore what is live for exception handling.
+        // We can construct the dontRestore set to accomplish this goal by having it contain only
+        // what is live for call but not live for exception handling. By ignoring things that are 
+        // only live at the call but not the exception handler, we will only restore things live 
+        // at the exception handler.
+        dontRestore.exclude(liveRegistersToPreserveAtExceptionHandlingCallSite());
+        restoreLiveRegistersFromStackForCall(dontRestore);
+    }
+
+    void restoreLiveRegistersFromStackForCall(const RegisterSet&amp; dontRestore)
+    {
+        unsigned extraStackPadding = 0;
+        ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, liveRegistersForCall(), dontRestore, m_numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
+    }
+
+    const RegisterSet&amp; liveRegistersForCall()
+    {
+        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
+        return m_liveRegistersForCall;
+    }
+
+    CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal()
+    {
+        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
+
+        if (!m_calculatedCallSiteIndex) {
+            m_calculatedCallSiteIndex = true;
+
+            if (m_needsToRestoreRegistersIfException)
+                m_callSiteIndex = jit-&gt;codeBlock()-&gt;newExceptionHandlingCallSiteIndex(stubInfo-&gt;callSiteIndex);
+            else
+                m_callSiteIndex = originalCallSiteIndex();
+        }
+
+        return m_callSiteIndex;
+    }
+
+    CallSiteIndex callSiteIndexForExceptionHandling()
+    {
+        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
+        RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
+        RELEASE_ASSERT(m_calculatedCallSiteIndex);
+        return m_callSiteIndex;
+    }
+
+    const HandlerInfo&amp; originalExceptionHandler() const
+    { 
+        RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
+        HandlerInfo* exceptionHandler = jit-&gt;codeBlock()-&gt;handlerForIndex(stubInfo-&gt;callSiteIndex.bits());
+        RELEASE_ASSERT(exceptionHandler);
+        return *exceptionHandler;
+    }
+
+    unsigned numberOfStackBytesUsedForRegisterPreservation() const 
+    {
+        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
+        return m_numberOfStackBytesUsedForRegisterPreservation; 
+    }
+
+    bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
+    CallSiteIndex originalCallSiteIndex() const { return stubInfo-&gt;callSiteIndex; }
+
+private:
+    const RegisterSet&amp; liveRegistersToPreserveAtExceptionHandlingCallSite()
+    {
+        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
+        return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
+    }
+    
+    RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
+    RegisterSet m_liveRegistersForCall;
+    CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits&lt;unsigned&gt;::max()) };
+    unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits&lt;unsigned&gt;::max() };
+    bool m_calculatedRegistersForCallAndExceptionHandling : 1;
+    bool m_needsToRestoreRegistersIfException : 1;
+    bool m_calculatedCallSiteIndex : 1;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> AccessCase::AccessCase()
</span><span class="lines">@@ -497,208 +625,250 @@
</span><span class="cx"> #endif
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // Stuff for custom getters.
</del><ins>+        if (m_type == Load) {
+            state.succeed();
+            return;
+        }
+
+        // Stuff for custom getters/setters.
</ins><span class="cx">         CCallHelpers::Call operationCall;
</span><del>-        CCallHelpers::Call handlerCall;
</del><ins>+        CCallHelpers::Call lookupExceptionHandlerCall;
</ins><span class="cx"> 
</span><del>-        // Stuff for JS getters.
</del><ins>+        // Stuff for JS getters/setters.
</ins><span class="cx">         CCallHelpers::DataLabelPtr addressOfLinkFunctionCheck;
</span><span class="cx">         CCallHelpers::Call fastPathCall;
</span><span class="cx">         CCallHelpers::Call slowPathCall;
</span><span class="cx"> 
</span><span class="cx">         CCallHelpers::Jump success;
</span><span class="cx">         CCallHelpers::Jump fail;
</span><del>-        if (m_type != Load &amp;&amp; m_type != Miss) {
-            // Need to make sure that whenever this call is made in the future, we remember the
-            // place that we made it from.
-            jit.store32(
-                CCallHelpers::TrustedImm32(stubInfo.callSiteIndex.bits()),
-                CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(JSStack::ArgumentCount)));
</del><span class="cx"> 
</span><del>-            if (m_type == Getter || m_type == Setter) {
-                // Create a JS call using a JS call inline cache. Assume that:
-                //
-                // - SP is aligned and represents the extent of the calling compiler's stack usage.
-                //
-                // - FP is set correctly (i.e. it points to the caller's call frame header).
-                //
-                // - SP - FP is an aligned difference.
-                //
-                // - Any byte between FP (exclusive) and SP (inclusive) could be live in the calling
-                //   code.
-                //
-                // Therefore, we temporarily grow the stack for the purpose of the call and then
-                // shrink it after.
</del><ins>+        // This also does the necessary calculations of whether or not we're an
+        // exception handling call site.
+        state.calculateLiveRegistersForCallAndExceptionHandling();
+        state.preserveLiveRegistersToStackForCall();
</ins><span class="cx"> 
</span><del>-                RELEASE_ASSERT(!m_rareData-&gt;callLinkInfo);
-                m_rareData-&gt;callLinkInfo = std::make_unique&lt;CallLinkInfo&gt;();
-                
-                // FIXME: If we generated a polymorphic call stub that jumped back to the getter
-                // stub, which then jumped back to the main code, then we'd have a reachability
-                // situation that the GC doesn't know about. The GC would ensure that the polymorphic
-                // call stub stayed alive, and it would ensure that the main code stayed alive, but
-                // it wouldn't know that the getter stub was alive. Ideally JIT stub routines would
-                // be GC objects, and then we'd be able to say that the polymorphic call stub has a
-                // reference to the getter stub.
-                // https://bugs.webkit.org/show_bug.cgi?id=148914
-                m_rareData-&gt;callLinkInfo-&gt;disallowStubs();
-                
-                m_rareData-&gt;callLinkInfo-&gt;setUpCall(
-                    CallLinkInfo::Call, stubInfo.codeOrigin, loadedValueGPR);
</del><ins>+        // Need to make sure that whenever this call is made in the future, we remember the
+        // place that we made it from.
+        jit.store32(
+            CCallHelpers::TrustedImm32(state.callSiteIndexForExceptionHandlingOrOriginal().bits()),
+            CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(JSStack::ArgumentCount)));
</ins><span class="cx"> 
</span><del>-                CCallHelpers::JumpList done;
</del><ins>+        if (m_type == Getter || m_type == Setter) {
+            // Create a JS call using a JS call inline cache. Assume that:
+            //
+            // - SP is aligned and represents the extent of the calling compiler's stack usage.
+            //
+            // - FP is set correctly (i.e. it points to the caller's call frame header).
+            //
+            // - SP - FP is an aligned difference.
+            //
+            // - Any byte between FP (exclusive) and SP (inclusive) could be live in the calling
+            //   code.
+            //
+            // Therefore, we temporarily grow the stack for the purpose of the call and then
+            // shrink it after.
</ins><span class="cx"> 
</span><del>-                // There is a &quot;this&quot; argument.
-                unsigned numberOfParameters = 1;
-                // ... and a value argument if we're calling a setter.
-                if (m_type == Setter)
-                    numberOfParameters++;
</del><ins>+            RELEASE_ASSERT(!m_rareData-&gt;callLinkInfo);
+            m_rareData-&gt;callLinkInfo = std::make_unique&lt;CallLinkInfo&gt;();
+            
+            // FIXME: If we generated a polymorphic call stub that jumped back to the getter
+            // stub, which then jumped back to the main code, then we'd have a reachability
+            // situation that the GC doesn't know about. The GC would ensure that the polymorphic
+            // call stub stayed alive, and it would ensure that the main code stayed alive, but
+            // it wouldn't know that the getter stub was alive. Ideally JIT stub routines would
+            // be GC objects, and then we'd be able to say that the polymorphic call stub has a
+            // reference to the getter stub.
+            // https://bugs.webkit.org/show_bug.cgi?id=148914
+            m_rareData-&gt;callLinkInfo-&gt;disallowStubs();
+            
+            m_rareData-&gt;callLinkInfo-&gt;setUpCall(
+                CallLinkInfo::Call, stubInfo.codeOrigin, loadedValueGPR);
</ins><span class="cx"> 
</span><del>-                // Get the accessor; if there ain't one then the result is jsUndefined().
-                if (m_type == Setter) {
-                    jit.loadPtr(
-                        CCallHelpers::Address(loadedValueGPR, GetterSetter::offsetOfSetter()),
-                        loadedValueGPR);
-                } else {
-                    jit.loadPtr(
-                        CCallHelpers::Address(loadedValueGPR, GetterSetter::offsetOfGetter()),
-                        loadedValueGPR);
-                }
</del><ins>+            CCallHelpers::JumpList done;
</ins><span class="cx"> 
</span><del>-                CCallHelpers::Jump returnUndefined = jit.branchTestPtr(
-                    CCallHelpers::Zero, loadedValueGPR);
</del><ins>+            // There is a &quot;this&quot; argument.
+            unsigned numberOfParameters = 1;
+            // ... and a value argument if we're calling a setter.
+            if (m_type == Setter)
+                numberOfParameters++;
</ins><span class="cx"> 
</span><del>-                unsigned numberOfRegsForCall = JSStack::CallFrameHeaderSize + numberOfParameters;
</del><ins>+            // Get the accessor; if there ain't one then the result is jsUndefined().
+            if (m_type == Setter) {
+                jit.loadPtr(
+                    CCallHelpers::Address(loadedValueGPR, GetterSetter::offsetOfSetter()),
+                    loadedValueGPR);
+            } else {
+                jit.loadPtr(
+                    CCallHelpers::Address(loadedValueGPR, GetterSetter::offsetOfGetter()),
+                    loadedValueGPR);
+            }
</ins><span class="cx"> 
</span><del>-                unsigned numberOfBytesForCall =
-                    numberOfRegsForCall * sizeof(Register) + sizeof(CallerFrameAndPC);
</del><ins>+            CCallHelpers::Jump returnUndefined = jit.branchTestPtr(
+                CCallHelpers::Zero, loadedValueGPR);
</ins><span class="cx"> 
</span><del>-                unsigned alignedNumberOfBytesForCall =
-                    WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall);
</del><ins>+            unsigned numberOfRegsForCall = JSStack::CallFrameHeaderSize + numberOfParameters;
</ins><span class="cx"> 
</span><del>-                jit.subPtr(
-                    CCallHelpers::TrustedImm32(alignedNumberOfBytesForCall),
-                    CCallHelpers::stackPointerRegister);
</del><ins>+            unsigned numberOfBytesForCall =
+                numberOfRegsForCall * sizeof(Register) + sizeof(CallerFrameAndPC);
</ins><span class="cx"> 
</span><del>-                CCallHelpers::Address calleeFrame = CCallHelpers::Address(
-                    CCallHelpers::stackPointerRegister,
-                    -static_cast&lt;ptrdiff_t&gt;(sizeof(CallerFrameAndPC)));
</del><ins>+            unsigned alignedNumberOfBytesForCall =
+                WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall);
</ins><span class="cx"> 
</span><del>-                jit.store32(
-                    CCallHelpers::TrustedImm32(numberOfParameters),
-                    calleeFrame.withOffset(JSStack::ArgumentCount * sizeof(Register) + PayloadOffset));
</del><ins>+            jit.subPtr(
+                CCallHelpers::TrustedImm32(alignedNumberOfBytesForCall),
+                CCallHelpers::stackPointerRegister);
</ins><span class="cx"> 
</span><del>-                jit.storeCell(
-                    loadedValueGPR, calleeFrame.withOffset(JSStack::Callee * sizeof(Register)));
</del><ins>+            CCallHelpers::Address calleeFrame = CCallHelpers::Address(
+                CCallHelpers::stackPointerRegister,
+                -static_cast&lt;ptrdiff_t&gt;(sizeof(CallerFrameAndPC)));
</ins><span class="cx"> 
</span><del>-                jit.storeCell(
-                    baseForGetGPR,
-                    calleeFrame.withOffset(virtualRegisterForArgument(0).offset() * sizeof(Register)));
</del><ins>+            jit.store32(
+                CCallHelpers::TrustedImm32(numberOfParameters),
+                calleeFrame.withOffset(JSStack::ArgumentCount * sizeof(Register) + PayloadOffset));
</ins><span class="cx"> 
</span><del>-                if (m_type == Setter) {
-                    jit.storeValue(
-                        valueRegs,
-                        calleeFrame.withOffset(
-                            virtualRegisterForArgument(1).offset() * sizeof(Register)));
-                }
</del><ins>+            jit.storeCell(
+                loadedValueGPR, calleeFrame.withOffset(JSStack::Callee * sizeof(Register)));
</ins><span class="cx"> 
</span><del>-                CCallHelpers::Jump slowCase = jit.branchPtrWithPatch(
-                    CCallHelpers::NotEqual, loadedValueGPR, addressOfLinkFunctionCheck,
-                    CCallHelpers::TrustedImmPtr(0));
</del><ins>+            jit.storeCell(
+                baseForGetGPR,
+                calleeFrame.withOffset(virtualRegisterForArgument(0).offset() * sizeof(Register)));
</ins><span class="cx"> 
</span><del>-                fastPathCall = jit.nearCall();
</del><ins>+            if (m_type == Setter) {
+                jit.storeValue(
+                    valueRegs,
+                    calleeFrame.withOffset(
+                        virtualRegisterForArgument(1).offset() * sizeof(Register)));
+            }
</ins><span class="cx"> 
</span><del>-                jit.addPtr(
-                    CCallHelpers::TrustedImm32(alignedNumberOfBytesForCall),
-                    CCallHelpers::stackPointerRegister);
-                if (m_type == Getter)
-                    jit.setupResults(valueRegs);
</del><ins>+            CCallHelpers::Jump slowCase = jit.branchPtrWithPatch(
+                CCallHelpers::NotEqual, loadedValueGPR, addressOfLinkFunctionCheck,
+                CCallHelpers::TrustedImmPtr(0));
</ins><span class="cx"> 
</span><del>-                done.append(jit.jump());
-                slowCase.link(&amp;jit);
</del><ins>+            fastPathCall = jit.nearCall();
+            if (m_type == Getter)
+                jit.setupResults(valueRegs);
+            done.append(jit.jump());
</ins><span class="cx"> 
</span><del>-                jit.move(loadedValueGPR, GPRInfo::regT0);
</del><ins>+            slowCase.link(&amp;jit);
+            jit.move(loadedValueGPR, GPRInfo::regT0);
</ins><span class="cx"> #if USE(JSVALUE32_64)
</span><del>-                // We *always* know that the getter/setter, if non-null, is a cell.
-                jit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::regT1);
</del><ins>+            // We *always* know that the getter/setter, if non-null, is a cell.
+            jit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::regT1);
</ins><span class="cx"> #endif
</span><del>-                jit.move(CCallHelpers::TrustedImmPtr(m_rareData-&gt;callLinkInfo.get()), GPRInfo::regT2);
-                slowPathCall = jit.nearCall();
</del><ins>+            jit.move(CCallHelpers::TrustedImmPtr(m_rareData-&gt;callLinkInfo.get()), GPRInfo::regT2);
+            slowPathCall = jit.nearCall();
+            if (m_type == Getter)
+                jit.setupResults(valueRegs);
+            done.append(jit.jump());
</ins><span class="cx"> 
</span><del>-                jit.addPtr(
-                    CCallHelpers::TrustedImm32(alignedNumberOfBytesForCall),
-                    CCallHelpers::stackPointerRegister);
-                if (m_type == Getter)
-                    jit.setupResults(valueRegs);
</del><ins>+            returnUndefined.link(&amp;jit);
+            if (m_type == Getter)
+                jit.moveTrustedValue(jsUndefined(), valueRegs);
</ins><span class="cx"> 
</span><del>-                done.append(jit.jump());
-                returnUndefined.link(&amp;jit);
</del><ins>+            done.link(&amp;jit);
</ins><span class="cx"> 
</span><del>-                if (m_type == Getter)
-                    jit.moveTrustedValue(jsUndefined(), valueRegs);
</del><ins>+            jit.addPtr(CCallHelpers::TrustedImm32((jit.codeBlock()-&gt;stackPointerOffset() * sizeof(Register)) - state.numberOfBytesUsedToPreserveReusedRegisters - state.numberOfStackBytesUsedForRegisterPreservation()),
+                GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
+            state.restoreLiveRegistersFromStackForCall(isGetter());
</ins><span class="cx"> 
</span><del>-                done.link(&amp;jit);
</del><ins>+            state.callbacks.append(
+                [=, &amp;vm] (LinkBuffer&amp; linkBuffer) {
+                    m_rareData-&gt;callLinkInfo-&gt;setCallLocations(
+                        linkBuffer.locationOfNearCall(slowPathCall),
+                        linkBuffer.locationOf(addressOfLinkFunctionCheck),
+                        linkBuffer.locationOfNearCall(fastPathCall));
</ins><span class="cx"> 
</span><del>-                jit.addPtr(
-                    CCallHelpers::TrustedImm32(
-                        jit.codeBlock()-&gt;stackPointerOffset() * sizeof(Register)),
-                    GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
</del><ins>+                    linkBuffer.link(
+                        slowPathCall,
+                        CodeLocationLabel(vm.getCTIStub(linkCallThunkGenerator).code()));
+                });
+        } else {
+            unsigned stackOffset = 0;
+            // Need to make room for the C call so our spillage isn't overwritten.
+            if (state.numberOfStackBytesUsedForRegisterPreservation()) {
+                if (maxFrameExtentForSlowPathCall)
+                    stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), maxFrameExtentForSlowPathCall);
+            }
+            if (stackOffset) {
+                jit.subPtr(
+                    CCallHelpers::TrustedImm32(stackOffset),
+                    CCallHelpers::stackPointerRegister);
+            }
</ins><span class="cx"> 
</span><del>-                state.callbacks.append(
-                    [=, &amp;vm] (LinkBuffer&amp; linkBuffer) {
-                        m_rareData-&gt;callLinkInfo-&gt;setCallLocations(
-                            linkBuffer.locationOfNearCall(slowPathCall),
-                            linkBuffer.locationOf(addressOfLinkFunctionCheck),
-                            linkBuffer.locationOfNearCall(fastPathCall));
-
-                        linkBuffer.link(
-                            slowPathCall,
-                            CodeLocationLabel(vm.getCTIStub(linkCallThunkGenerator).code()));
-                    });
-            } else {
-                // getter: EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName);
-                // setter: void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
</del><ins>+            // getter: EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName);
+            // setter: void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
</ins><span class="cx"> #if USE(JSVALUE64)
</span><del>-                if (m_type == CustomGetter) {
-                    jit.setupArgumentsWithExecState(
-                        baseForAccessGPR, baseForGetGPR,
-                        CCallHelpers::TrustedImmPtr(ident.impl()));
-                } else
-                    jit.setupArgumentsWithExecState(baseForAccessGPR, baseForGetGPR, valueRegs.gpr());
</del><ins>+            if (m_type == CustomGetter) {
+                jit.setupArgumentsWithExecState(
+                    baseForAccessGPR, baseForGetGPR,
+                    CCallHelpers::TrustedImmPtr(ident.impl()));
+            } else
+                jit.setupArgumentsWithExecState(baseForAccessGPR, baseForGetGPR, valueRegs.gpr());
</ins><span class="cx"> #else
</span><del>-                if (m_type == CustomGetter) {
-                    jit.setupArgumentsWithExecState(
-                        baseForAccessGPR, baseForGetGPR,
-                        CCallHelpers::TrustedImm32(JSValue::CellTag),
-                        CCallHelpers::TrustedImmPtr(ident.impl()));
-                } else {
-                    jit.setupArgumentsWithExecState(
-                        baseForAccessGPR, baseForGetGPR,
-                        CCallHelpers::TrustedImm32(JSValue::CellTag),
-                        valueRegs.payloadGPR(), valueRegs.tagGPR());
-                }
</del><ins>+            if (m_type == CustomGetter) {
+                jit.setupArgumentsWithExecState(
+                    baseForAccessGPR, baseForGetGPR,
+                    CCallHelpers::TrustedImm32(JSValue::CellTag),
+                    CCallHelpers::TrustedImmPtr(ident.impl()));
+            } else {
+                jit.setupArgumentsWithExecState(
+                    baseForAccessGPR, baseForGetGPR,
+                    CCallHelpers::TrustedImm32(JSValue::CellTag),
+                    valueRegs.payloadGPR(), valueRegs.tagGPR());
+            }
</ins><span class="cx"> #endif
</span><del>-                jit.storePtr(GPRInfo::callFrameRegister, &amp;vm.topCallFrame);
</del><ins>+            jit.storePtr(GPRInfo::callFrameRegister, &amp;vm.topCallFrame);
</ins><span class="cx"> 
</span><del>-                operationCall = jit.call();
-                if (m_type == CustomGetter)
-                    jit.setupResults(valueRegs);
-                CCallHelpers::Jump noException =
-                    jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
</del><ins>+            operationCall = jit.call();
+            if (m_type == CustomGetter)
+                jit.setupResults(valueRegs);
</ins><span class="cx"> 
</span><del>-                jit.copyCalleeSavesToVMCalleeSavesBuffer();
-                jit.setupArguments(CCallHelpers::TrustedImmPtr(&amp;vm), GPRInfo::callFrameRegister);
-                handlerCall = jit.call();
-                jit.jumpToExceptionHandler();
-            
-                noException.link(&amp;jit);
</del><ins>+            if (stackOffset) {
+                jit.addPtr(
+                    CCallHelpers::TrustedImm32(stackOffset),
+                    CCallHelpers::stackPointerRegister);
+            }
</ins><span class="cx"> 
</span><ins>+            CCallHelpers::Jump noException =
+                jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
+
+            bool didSetLookupExceptionHandler = false;
+            state.restoreLiveRegistersFromStackForCallWithThrownException();
+            state.restoreScratch();
+            jit.copyCalleeSavesToVMCalleeSavesBuffer();
+            if (state.needsToRestoreRegistersIfException()) {
+                // To the JIT that produces the original exception handling
+                // call site, they will expect the OSR exit to be arrived
+                // at from genericUnwind. Therefore we must model what genericUnwind
+                // does here. I.e, set callFrameForCatch and copy callee saves.
+
+                jit.storePtr(GPRInfo::callFrameRegister, vm.addressOfCallFrameForCatch());
+                CCallHelpers::Jump jumpToOSRExitExceptionHandler = jit.jump();
+
+                // We don't need to insert a new exception handler in the table
+                // because we're doing a manual exception check here. i.e, we'll
+                // never arrive here from genericUnwind().
+                HandlerInfo originalHandler = state.originalExceptionHandler();
</ins><span class="cx">                 state.callbacks.append(
</span><span class="cx">                     [=] (LinkBuffer&amp; linkBuffer) {
</span><del>-                        linkBuffer.link(operationCall, FunctionPtr(m_rareData-&gt;customAccessor.opaque));
-                        linkBuffer.link(handlerCall, lookupExceptionHandler);
</del><ins>+                        linkBuffer.link(jumpToOSRExitExceptionHandler, originalHandler.nativeCode);
</ins><span class="cx">                     });
</span><ins>+            } else {
+                jit.setupArguments(CCallHelpers::TrustedImmPtr(&amp;vm), GPRInfo::callFrameRegister);
+                lookupExceptionHandlerCall = jit.call();
+                didSetLookupExceptionHandler = true;
+                jit.jumpToExceptionHandler();
</ins><span class="cx">             }
</span><ins>+        
+            noException.link(&amp;jit);
+            state.restoreLiveRegistersFromStackForCall(isGetter());
+
+            state.callbacks.append(
+                [=] (LinkBuffer&amp; linkBuffer) {
+                    linkBuffer.link(operationCall, FunctionPtr(m_rareData-&gt;customAccessor.opaque));
+                    if (didSetLookupExceptionHandler)
+                        linkBuffer.link(lookupExceptionHandlerCall, lookupExceptionHandler);
+                });
</ins><span class="cx">         }
</span><span class="cx">         state.succeed();
</span><span class="cx">         return;
</span><span class="lines">@@ -761,7 +931,7 @@
</span><span class="cx">         else
</span><span class="cx">             scratchGPR3 = InvalidGPRReg;
</span><span class="cx"> 
</span><del>-        size_t numberOfPaddingBytes = allocator.preserveReusedRegistersByPushing(jit);
</del><ins>+        size_t numberOfBytesUsedToPreserveReusedRegisters = allocator.preserveReusedRegistersByPushing(jit);
</ins><span class="cx"> 
</span><span class="cx">         ASSERT(structure()-&gt;transitionWatchpointSetHasBeenInvalidated());
</span><span class="cx"> 
</span><span class="lines">@@ -883,12 +1053,12 @@
</span><span class="cx">                 });
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        allocator.restoreReusedRegistersByPopping(jit, numberOfPaddingBytes);
</del><ins>+        allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters);
</ins><span class="cx">         state.succeed();
</span><span class="cx"> 
</span><span class="cx">         if (newStructure()-&gt;outOfLineCapacity() != structure()-&gt;outOfLineCapacity()) {
</span><span class="cx">             slowPath.link(&amp;jit);
</span><del>-            allocator.restoreReusedRegistersByPopping(jit, numberOfPaddingBytes);
</del><ins>+            allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters);
</ins><span class="cx">             allocator.preserveUsedRegistersToScratchBufferForCall(jit, scratchBuffer, scratchGPR);
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">             jit.setupArgumentsWithExecState(
</span><span class="lines">@@ -971,9 +1141,6 @@
</span><span class="cx">         if (found)
</span><span class="cx">             continue;
</span><span class="cx">         
</span><del>-        if (myCase-&gt;doesCalls() &amp;&amp; stubInfo.patch.spillMode == NeedToSpill)
-            return MacroAssemblerCodePtr();
-
</del><span class="cx">         casesToAdd.append(WTF::move(myCase));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1091,11 +1258,15 @@
</span><span class="cx">     CCallHelpers jit(&amp;vm, codeBlock);
</span><span class="cx">     state.jit = &amp;jit;
</span><span class="cx"> 
</span><del>-    state.numberOfPaddingBytes = allocator.preserveReusedRegistersByPushing(jit);
</del><ins>+    state.numberOfBytesUsedToPreserveReusedRegisters = allocator.preserveReusedRegistersByPushing(jit);
</ins><span class="cx"> 
</span><span class="cx">     bool allGuardedByStructureCheck = true;
</span><del>-    for (auto&amp; entry : cases)
</del><ins>+    bool hasJSGetterSetterCall = false;
+    for (auto&amp; entry : cases) {
</ins><span class="cx">         allGuardedByStructureCheck &amp;= entry-&gt;guardedByStructureCheck();
</span><ins>+        if (entry-&gt;type() == AccessCase::Getter || entry-&gt;type() == AccessCase::Setter)
+            hasJSGetterSetterCall = true;
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (cases.isEmpty()) {
</span><span class="cx">         // This is super unlikely, but we make it legal anyway.
</span><span class="lines">@@ -1147,6 +1318,38 @@
</span><span class="cx">         failure = state.failAndRepatch;
</span><span class="cx">     failure.append(jit.jump());
</span><span class="cx"> 
</span><ins>+    if (state.needsToRestoreRegistersIfException() &amp;&amp; hasJSGetterSetterCall) {
+        // Emit the exception handler.
+        // Note that this code is only reachable when doing genericUnwind from a pure JS getter/setter .
+        // Note also that this is not reachable from custom getter/setter. Custom getter/setters will have 
+        // their own exception handling logic that doesn't go through genericUnwind.
+        MacroAssembler::Label makeshiftCatchHandler = jit.label();
+
+        int stackPointerOffset = codeBlock-&gt;stackPointerOffset() * sizeof(EncodedJSValue);
+        stackPointerOffset -= state.numberOfBytesUsedToPreserveReusedRegisters;
+        stackPointerOffset -= state.numberOfStackBytesUsedForRegisterPreservation();
+
+        jit.loadPtr(vm.addressOfCallFrameForCatch(), GPRInfo::callFrameRegister);
+        jit.addPtr(CCallHelpers::TrustedImm32(stackPointerOffset), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
+
+        state.restoreLiveRegistersFromStackForCallWithThrownException();
+        state.restoreScratch();
+        CCallHelpers::Jump jumpToOSRExitExceptionHandler = jit.jump();
+
+        HandlerInfo oldHandler = state.originalExceptionHandler();
+        CallSiteIndex newExceptionHandlingCallSite = state.callSiteIndexForExceptionHandling();
+        state.callbacks.append(
+            [=] (LinkBuffer&amp; linkBuffer) {
+                linkBuffer.link(jumpToOSRExitExceptionHandler, oldHandler.nativeCode);
+
+                HandlerInfo handlerToRegister = oldHandler;
+                handlerToRegister.nativeCode = linkBuffer.locationOf(makeshiftCatchHandler);
+                handlerToRegister.start = newExceptionHandlingCallSite.bits();
+                handlerToRegister.end = newExceptionHandlingCallSite.bits() + 1;
+                codeBlock-&gt;appendExceptionHandler(handlerToRegister);
+            });
+    }
+
</ins><span class="cx">     LinkBuffer linkBuffer(vm, jit, codeBlock, JITCompilationCanFail);
</span><span class="cx">     if (linkBuffer.didFailToAllocate()) {
</span><span class="cx">         if (verbose)
</span><span class="lines">@@ -1168,7 +1371,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (verbose)
</span><span class="cx">         dataLog(*codeBlock, &quot; &quot;, stubInfo.codeOrigin, &quot;: Generating polymorphic access stub for &quot;, listDump(cases), &quot;\n&quot;);
</span><del>-    
</del><ins>+
</ins><span class="cx">     MacroAssemblerCodeRef code = FINALIZE_CODE_FOR(
</span><span class="cx">         codeBlock, linkBuffer,
</span><span class="cx">         (&quot;%s&quot;, toCString(&quot;Access stub for &quot;, *codeBlock, &quot; &quot;, stubInfo.codeOrigin, &quot; with return point &quot;, successLabel, &quot;: &quot;, listDump(cases)).data()));
</span><span class="lines">@@ -1177,7 +1380,15 @@
</span><span class="cx">     for (auto&amp; entry : cases)
</span><span class="cx">         doesCalls |= entry-&gt;doesCalls();
</span><span class="cx">     
</span><del>-    m_stubRoutine = createJITStubRoutine(code, vm, codeBlock, doesCalls);
</del><ins>+    CodeBlock* codeBlockThatOwnsExceptionHandlers = nullptr;
+    CallSiteIndex callSiteIndexForExceptionHandling = state.originalCallSiteIndex();
+    if (state.needsToRestoreRegistersIfException()) {
+        codeBlockThatOwnsExceptionHandlers = codeBlock;
+        ASSERT(JITCode::isOptimizingJIT(codeBlockThatOwnsExceptionHandlers-&gt;jitType()));
+        callSiteIndexForExceptionHandling = state.callSiteIndexForExceptionHandling();
+    }
+
+    m_stubRoutine = createJITStubRoutine(code, vm, codeBlock, doesCalls, nullptr, codeBlockThatOwnsExceptionHandlers, callSiteIndexForExceptionHandling);
</ins><span class="cx">     m_watchpoints = WTF::move(state.watchpoints);
</span><span class="cx">     if (!state.weakReferences.isEmpty())
</span><span class="cx">         m_weakReferences = std::make_unique&lt;Vector&lt;WriteBarrier&lt;JSCell&gt;&gt;&gt;(WTF::move(state.weakReferences));
</span><span class="lines">@@ -1186,6 +1397,11 @@
</span><span class="cx">     return code.code();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PolymorphicAccess::aboutToDie()
+{
+    m_stubRoutine-&gt;aboutToDie();
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -199,6 +199,17 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isGetter() const
+    {
+        switch (type()) {
+        case Getter:
+        case CustomGetter:
+            return true;
+        default:
+            return false;
+        }
+    }
+
</ins><span class="cx">     CallLinkInfo* callLinkInfo() const
</span><span class="cx">     {
</span><span class="cx">         if (!m_rareData)
</span><span class="lines">@@ -289,6 +300,8 @@
</span><span class="cx">     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
</span><span class="cx">     bool visitWeak(VM&amp;) const;
</span><span class="cx"> 
</span><ins>+    void aboutToDie();
+
</ins><span class="cx">     void dump(PrintStream&amp; out) const;
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeStructureStubInfocpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -89,6 +89,21 @@
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void StructureStubInfo::aboutToDie()
+{
+    switch (cacheType) {
+    case CacheType::Stub:
+        u.stub-&gt;aboutToDie();
+        return;
+    case CacheType::Unset:
+    case CacheType::GetByIdSelf:
+    case CacheType::PutByIdReplace:
+        return;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> MacroAssemblerCodePtr StructureStubInfo::addAccessCase(
</span><span class="cx">     CodeBlock* codeBlock, const Identifier&amp; ident, std::unique_ptr&lt;AccessCase&gt; accessCase)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeStructureStubInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -35,7 +35,6 @@
</span><span class="cx"> #include &quot;Options.h&quot;
</span><span class="cx"> #include &quot;PolymorphicAccess.h&quot;
</span><span class="cx"> #include &quot;RegisterSet.h&quot;
</span><del>-#include &quot;SpillRegistersMode.h&quot;
</del><span class="cx"> #include &quot;Structure.h&quot;
</span><span class="cx"> #include &quot;StructureStubClearingWatchpoint.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -75,6 +74,7 @@
</span><span class="cx">     void reset(CodeBlock*);
</span><span class="cx"> 
</span><span class="cx">     void deref();
</span><ins>+    void aboutToDie();
</ins><span class="cx"> 
</span><span class="cx">     // Check if the stub has weak references that are dead. If it does, then it resets itself,
</span><span class="cx">     // either entirely or just enough to ensure that those dead pointers don't get used anymore.
</span><span class="lines">@@ -131,7 +131,6 @@
</span><span class="cx">     } u;
</span><span class="cx"> 
</span><span class="cx">     struct {
</span><del>-        unsigned spillMode : 8;
</del><span class="cx">         int8_t baseGPR;
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx">         int8_t valueTagGPR;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeValueRecoveryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/ValueRecovery.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ValueRecovery.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/bytecode/ValueRecovery.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -326,7 +326,7 @@
</span><span class="cx">     {
</span><span class="cx">         return isInGPR();
</span><span class="cx">     }
</span><del>-#endif
</del><ins>+#endif // USE(JSVALUE32_64)
</ins><span class="cx">     
</span><span class="cx">     MacroAssembler::FPRegisterID fpr() const
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -57,12 +57,29 @@
</span><span class="cx">     return CallSiteIndex(index);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CallSiteIndex CommonData::addCodeOriginUnconditionally(CodeOrigin codeOrigin)
+{
+    if (callSiteIndexFreeList.size())
+        return CallSiteIndex(callSiteIndexFreeList.takeAny());
+
+    codeOrigins.append(codeOrigin);
+    unsigned index = codeOrigins.size() - 1;
+    ASSERT(codeOrigins[index] == codeOrigin);
+    return CallSiteIndex(index);
+}
+
</ins><span class="cx"> CallSiteIndex CommonData::lastCallSite() const
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(codeOrigins.size());
</span><span class="cx">     return CallSiteIndex(codeOrigins.size() - 1);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CommonData::removeCallSiteIndex(CallSiteIndex callSite)
+{
+    RELEASE_ASSERT(callSite.bits() &lt; codeOrigins.size());
+    callSiteIndexFreeList.add(callSite.bits());
+}
+
</ins><span class="cx"> void CommonData::shrinkToFit()
</span><span class="cx"> {
</span><span class="cx">     codeOrigins.shrinkToFit();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommonData.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommonData.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommonData.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -80,7 +80,9 @@
</span><span class="cx">     
</span><span class="cx">     void notifyCompilingStructureTransition(Plan&amp;, CodeBlock*, Node*);
</span><span class="cx">     CallSiteIndex addCodeOrigin(CodeOrigin);
</span><ins>+    CallSiteIndex addCodeOriginUnconditionally(CodeOrigin);
</ins><span class="cx">     CallSiteIndex lastCallSite() const;
</span><ins>+    void removeCallSiteIndex(CallSiteIndex);
</ins><span class="cx">     
</span><span class="cx">     void shrinkToFit();
</span><span class="cx">     
</span><span class="lines">@@ -116,6 +118,10 @@
</span><span class="cx">     
</span><span class="cx">     unsigned frameRegisterCount;
</span><span class="cx">     unsigned requiredRegisterCountForExit;
</span><ins>+
+private:
+    HashSet&lt;unsigned, WTF::IntHash&lt;unsigned&gt;, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; callSiteIndexFreeList;
+
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCode.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCode.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCode.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -87,6 +87,38 @@
</span><span class="cx">         result[i] = recoveries[i].recover(exec);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RegisterSet JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock* codeBlock, CallSiteIndex callSiteIndex)
+{
+    for (OSRExit&amp; exit : osrExit) {
+        if (exit.m_isExceptionHandler &amp;&amp; exit.m_exceptionHandlerCallSiteIndex.bits() == callSiteIndex.bits()) {
+            Operands&lt;ValueRecovery&gt; valueRecoveries;
+            reconstruct(codeBlock, exit.m_codeOrigin, exit.m_streamIndex, valueRecoveries);
+            RegisterSet liveAtOSRExit;
+            for (size_t index = 0; index &lt; valueRecoveries.size(); ++index) {
+                const ValueRecovery&amp; recovery = valueRecoveries[index];
+                if (recovery.isInRegisters()) {
+                    if (recovery.isInGPR())
+                        liveAtOSRExit.set(recovery.gpr());
+                    else if (recovery.isInFPR())
+                        liveAtOSRExit.set(recovery.fpr());
+#if USE(JSVALUE32_64)
+                    else if (recovery.isInJSValueRegs()) {
+                        liveAtOSRExit.set(recovery.payloadGPR());
+                        liveAtOSRExit.set(recovery.tagGPR());
+                    }
+#endif
+                    else
+                        RELEASE_ASSERT_NOT_REACHED();
+                }
+            }
+
+            return liveAtOSRExit;
+        }
+    }
+
+    return RegisterSet();
+}
+
</ins><span class="cx"> #if ENABLE(FTL_JIT)
</span><span class="cx"> bool JITCode::checkIfOptimizationThresholdReached(CodeBlock* codeBlock)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCode.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCode.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCode.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -116,6 +116,7 @@
</span><span class="cx">     
</span><span class="cx">     void shrinkToFit();
</span><span class="cx"> 
</span><ins>+    RegisterSet liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex) override;
</ins><span class="cx"> #if ENABLE(FTL_JIT)
</span><span class="cx">     CodeBlock* osrEntryBlock() { return m_osrEntryBlock.get(); }
</span><span class="cx">     void setOSREntryBlock(VM&amp; vm, const JSCell* owner, CodeBlock* osrEntryBlock) { m_osrEntryBlock.set(vm, owner, osrEntryBlock); }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -555,6 +555,7 @@
</span><span class="cx">     exit.m_willArriveAtOSRExitFromGenericUnwind = jumpsToFail.empty(); // If jumps are empty, we're going to jump here from genericUnwind from a child call frame.
</span><span class="cx">     exit.m_isExceptionHandler = true;
</span><span class="cx">     exit.m_codeOrigin = opCatchOrigin;
</span><ins>+    exit.m_exceptionHandlerCallSiteIndex = callSite;
</ins><span class="cx">     OSRExitCompilationInfo&amp; exitInfo = appendExitInfo(jumpsToFail);
</span><span class="cx">     jitCode()-&gt;appendOSRExit(exit);
</span><span class="cx">     m_exceptionHandlerOSRExitCallSites.append(ExceptionHandlingOSRExitInfo { exitInfo, *exceptionHandler, callSite });
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx">     , m_patchableCodeOffset(0)
</span><span class="cx">     , m_recoveryIndex(recoveryIndex)
</span><span class="cx">     , m_streamIndex(streamIndex)
</span><ins>+    , m_exceptionHandlerCallSiteIndex(std::numeric_limits&lt;unsigned&gt;::max())
</ins><span class="cx">     , m_willArriveAtOSRExitFromGenericUnwind(false)
</span><span class="cx">     , m_isExceptionHandler(false)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExith"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -100,6 +100,7 @@
</span><span class="cx">     void correctJump(LinkBuffer&amp;);
</span><span class="cx"> 
</span><span class="cx">     unsigned m_streamIndex;
</span><ins>+    CallSiteIndex m_exceptionHandlerCallSiteIndex;
</ins><span class="cx"> 
</span><span class="cx">     bool m_willArriveAtOSRExitFromGenericUnwind : 1;
</span><span class="cx">     bool m_isExceptionHandler : 1;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -960,7 +960,6 @@
</span><span class="cx">             stubInfo-&gt;patch.valueTagGPR = static_cast&lt;int8_t&gt;(InvalidGPRReg);
</span><span class="cx"> #endif
</span><span class="cx">             stubInfo-&gt;patch.usedRegisters = usedRegisters();
</span><del>-            stubInfo-&gt;patch.spillMode = NeedToSpill;
</del><span class="cx"> 
</span><span class="cx">             m_jit.addIn(InRecord(jump, done, slowPath.get(), stubInfo));
</span><span class="cx">             addSlowPathGenerator(WTF::move(slowPath));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -183,11 +183,18 @@
</span><span class="cx">         basePayloadGPR = resultPayloadGPR;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    RegisterSet usedRegisters = this-&gt;usedRegisters();
+    if (spillMode == DontSpill) {
+        // We've already flushed registers to the stack, we don't need to spill these.
+        usedRegisters.set(JSValueRegs(baseTagGPROrNone, basePayloadGPR), false);
+        usedRegisters.set(JSValueRegs(resultTagGPR, resultPayloadGPR), false);
+    }
+    
</ins><span class="cx">     CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream-&gt;size());
</span><span class="cx">     JITGetByIdGenerator gen(
</span><del>-        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters(),
</del><ins>+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
</ins><span class="cx">         JSValueRegs(baseTagGPROrNone, basePayloadGPR),
</span><del>-        JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode);
</del><ins>+        JSValueRegs(resultTagGPR, resultPayloadGPR));
</ins><span class="cx">     
</span><span class="cx">     gen.generateFastPath(m_jit);
</span><span class="cx">     
</span><span class="lines">@@ -216,11 +223,17 @@
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
</span><span class="cx"> {
</span><ins>+    RegisterSet usedRegisters = this-&gt;usedRegisters();
+    if (spillMode == DontSpill) {
+        // We've already flushed registers to the stack, we don't need to spill these.
+        usedRegisters.set(basePayloadGPR, false);
+        usedRegisters.set(JSValueRegs(valueTagGPR, valuePayloadGPR), false);
+    }
</ins><span class="cx">     CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream-&gt;size());
</span><span class="cx">     JITPutByIdGenerator gen(
</span><del>-        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters(),
</del><ins>+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
</ins><span class="cx">         JSValueRegs::payloadOnly(basePayloadGPR), JSValueRegs(valueTagGPR, valuePayloadGPR),
</span><del>-        scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind);
</del><ins>+        scratchGPR, m_jit.ecmaModeFor(codeOrigin), putKind);
</ins><span class="cx">     
</span><span class="cx">     gen.generateFastPath(m_jit);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -155,10 +155,15 @@
</span><span class="cx"> void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
</span><span class="cx"> {
</span><span class="cx">     CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream-&gt;size());
</span><del>-
</del><ins>+    RegisterSet usedRegisters = this-&gt;usedRegisters();
+    if (spillMode == DontSpill) {
+        // We've already flushed registers to the stack, we don't need to spill these.
+        usedRegisters.set(baseGPR, false);
+        usedRegisters.set(resultGPR, false);
+    }
</ins><span class="cx">     JITGetByIdGenerator gen(
</span><del>-        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters(), JSValueRegs(baseGPR),
-        JSValueRegs(resultGPR), spillMode);
</del><ins>+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, JSValueRegs(baseGPR),
+        JSValueRegs(resultGPR));
</ins><span class="cx">     gen.generateFastPath(m_jit);
</span><span class="cx">     
</span><span class="cx">     JITCompiler::JumpList slowCases;
</span><span class="lines">@@ -177,10 +182,16 @@
</span><span class="cx"> void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
</span><span class="cx"> {
</span><span class="cx">     CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream-&gt;size());
</span><ins>+    RegisterSet usedRegisters = this-&gt;usedRegisters();
+    if (spillMode == DontSpill) {
+        // We've already flushed registers to the stack, we don't need to spill these.
+        usedRegisters.set(baseGPR, false);
+        usedRegisters.set(valueGPR, false);
+    }
</ins><span class="cx"> 
</span><span class="cx">     JITPutByIdGenerator gen(
</span><del>-        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters(), JSValueRegs(baseGPR),
-        JSValueRegs(valueGPR), scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind);
</del><ins>+        m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, JSValueRegs(baseGPR),
+        JSValueRegs(valueGPR), scratchGPR, m_jit.ecmaModeFor(codeOrigin), putKind);
</ins><span class="cx"> 
</span><span class="cx">     gen.generateFastPath(m_jit);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -467,7 +467,7 @@
</span><span class="cx">                 
</span><span class="cx">                 JITGetByIdGenerator gen(
</span><span class="cx">                     codeBlock, codeOrigin, getById.callSiteIndex(), usedRegisters, JSValueRegs(base),
</span><del>-                    JSValueRegs(result), NeedToSpill);
</del><ins>+                    JSValueRegs(result));
</ins><span class="cx">                 
</span><span class="cx">                 MacroAssembler::Label begin = slowPathJIT.label();
</span><span class="cx"> 
</span><span class="lines">@@ -505,8 +505,7 @@
</span><span class="cx">                 
</span><span class="cx">                 JITPutByIdGenerator gen(
</span><span class="cx">                     codeBlock, codeOrigin, putById.callSiteIndex(), usedRegisters, JSValueRegs(base),
</span><del>-                    JSValueRegs(value), GPRInfo::patchpointScratchRegister, NeedToSpill,
-                    putById.ecmaMode(), putById.putKind());
</del><ins>+                    JSValueRegs(value), GPRInfo::patchpointScratchRegister, putById.ecmaMode(), putById.putKind());
</ins><span class="cx">                 
</span><span class="cx">                 MacroAssembler::Label begin = slowPathJIT.label();
</span><span class="cx">                 
</span><span class="lines">@@ -545,7 +544,6 @@
</span><span class="cx">                 stubInfo-&gt;patch.baseGPR = static_cast&lt;int8_t&gt;(obj);
</span><span class="cx">                 stubInfo-&gt;patch.valueGPR = static_cast&lt;int8_t&gt;(result);
</span><span class="cx">                 stubInfo-&gt;patch.usedRegisters = usedRegisters;
</span><del>-                stubInfo-&gt;patch.spillMode = NeedToSpill;
</del><span class="cx"> 
</span><span class="cx">                 MacroAssembler::Label begin = slowPathJIT.label();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJITCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -144,6 +144,13 @@
</span><span class="cx">         exit.validateReferences(trackedReferences);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RegisterSet JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex)
+{
+    // FIXME: implement this when FTL implements try/catch.
+    // https://bugs.webkit.org/show_bug.cgi?id=149409
+    return RegisterSet();
+}
+
</ins><span class="cx"> } } // namespace JSC::FTL
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(FTL_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJITCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJITCode.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJITCode.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/ftl/FTLJITCode.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -72,6 +72,8 @@
</span><span class="cx">     void initializeAddressForCall(CodePtr);
</span><span class="cx">     
</span><span class="cx">     void validateReferences(const TrackedReferences&amp;) override;
</span><ins>+
+    RegisterSet liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex) override;
</ins><span class="cx">     
</span><span class="cx">     const Vector&lt;RefPtr&lt;ExecutableMemoryHandle&gt;&gt;&amp; handles() const { return m_handles; }
</span><span class="cx">     const Vector&lt;RefPtr&lt;DataSection&gt;&gt;&amp; dataSections() const { return m_dataSections; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGCAwareJITStubRoutinecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -28,6 +28,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> 
</span><ins>+#include &quot;CodeBlock.h&quot;
+#include &quot;DFGCommonData.h&quot;
</ins><span class="cx"> #include &quot;Heap.h&quot;
</span><span class="cx"> #include &quot;VM.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="lines">@@ -44,7 +46,7 @@
</span><span class="cx"> {
</span><span class="cx">     vm.heap.m_jitStubRoutines.add(this);
</span><span class="cx"> }
</span><del>-    
</del><ins>+
</ins><span class="cx"> GCAwareJITStubRoutine::~GCAwareJITStubRoutine() { }
</span><span class="cx"> 
</span><span class="cx"> void GCAwareJITStubRoutine::observeZeroRefCount()
</span><span class="lines">@@ -94,16 +96,50 @@
</span><span class="cx">     visitor.append(&amp;m_object);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+GCAwareJITStubRoutineWithExceptionHandler::GCAwareJITStubRoutineWithExceptionHandler(
+    const MacroAssemblerCodeRef&amp; code, VM&amp; vm, 
+    CodeBlock* codeBlockForExceptionHandlers, CallSiteIndex exceptionHandlerCallSiteIndex)
+    : GCAwareJITStubRoutine(code, vm)
+    , m_codeBlockWithExceptionHandler(codeBlockForExceptionHandlers)
+    , m_exceptionHandlerCallSiteIndex(exceptionHandlerCallSiteIndex)
+{
+    RELEASE_ASSERT(m_codeBlockWithExceptionHandler);
+}
+
+void GCAwareJITStubRoutineWithExceptionHandler::aboutToDie()
+{
+    m_codeBlockWithExceptionHandler = nullptr;
+}
+
+GCAwareJITStubRoutineWithExceptionHandler::~GCAwareJITStubRoutineWithExceptionHandler()
+{
+    if (m_codeBlockWithExceptionHandler) {
+        m_codeBlockWithExceptionHandler-&gt;jitCode()-&gt;dfgCommon()-&gt;removeCallSiteIndex(m_exceptionHandlerCallSiteIndex);
+        m_codeBlockWithExceptionHandler-&gt;removeExceptionHandlerForCallSite(m_exceptionHandlerCallSiteIndex);
+    }
+}
+    
+
</ins><span class="cx"> PassRefPtr&lt;JITStubRoutine&gt; createJITStubRoutine(
</span><span class="cx">     const MacroAssemblerCodeRef&amp; code,
</span><span class="cx">     VM&amp; vm,
</span><span class="cx">     const JSCell* owner,
</span><span class="cx">     bool makesCalls,
</span><del>-    JSCell* object)
</del><ins>+    JSCell* object,
+    CodeBlock* codeBlockForExceptionHandlers,
+    CallSiteIndex exceptionHandlerCallSiteIndex)
</ins><span class="cx"> {
</span><span class="cx">     if (!makesCalls)
</span><span class="cx">         return adoptRef(new JITStubRoutine(code));
</span><span class="cx">     
</span><ins>+    if (codeBlockForExceptionHandlers) {
+        RELEASE_ASSERT(!object); // We're not a marking stub routine.
+        RELEASE_ASSERT(JITCode::isOptimizingJIT(codeBlockForExceptionHandlers-&gt;jitType()));
+        return static_pointer_cast&lt;JITStubRoutine&gt;(
+            adoptRef(new GCAwareJITStubRoutineWithExceptionHandler(code, vm, codeBlockForExceptionHandlers, exceptionHandlerCallSiteIndex)));
+    }
+
</ins><span class="cx">     if (!object) {
</span><span class="cx">         return static_pointer_cast&lt;JITStubRoutine&gt;(
</span><span class="cx">             adoptRef(new GCAwareJITStubRoutine(code, vm)));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGCAwareJITStubRoutineh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -89,6 +89,22 @@
</span><span class="cx">     WriteBarrier&lt;JSCell&gt; m_object;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+
+// The stub has exception handlers in it. So it clears itself from exception
+// handling table when it dies. It also frees space in CodeOrigin table
+// for new exception handlers to use the same CallSiteIndex.
+class GCAwareJITStubRoutineWithExceptionHandler : public GCAwareJITStubRoutine {
+public:
+    GCAwareJITStubRoutineWithExceptionHandler(const MacroAssemblerCodeRef&amp;, VM&amp;, CodeBlock*, CallSiteIndex);
+    ~GCAwareJITStubRoutineWithExceptionHandler() override;
+
+    void aboutToDie() override;
+
+private:
+    CodeBlock* m_codeBlockWithExceptionHandler;
+    CallSiteIndex m_exceptionHandlerCallSiteIndex;
+};
+
</ins><span class="cx"> // Helper for easily creating a GC-aware JIT stub routine. For the varargs,
</span><span class="cx"> // pass zero or more JSCell*'s. This will either create a JITStubRoutine, a
</span><span class="cx"> // GCAwareJITStubRoutine, or an ObjectMarkingGCAwareJITStubRoutine as
</span><span class="lines">@@ -110,7 +126,8 @@
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;JITStubRoutine&gt; createJITStubRoutine(
</span><span class="cx">     const MacroAssemblerCodeRef&amp;, VM&amp;, const JSCell* owner, bool makesCalls,
</span><del>-    JSCell* = nullptr);
</del><ins>+    JSCell* = nullptr, 
+    CodeBlock* codeBlockForExceptionHandlers = nullptr, CallSiteIndex exceptionHandlingCallSiteIndex = CallSiteIndex(std::numeric_limits&lt;unsigned&gt;::max()));
</ins><span class="cx"> 
</span><span class="cx"> // Helper for the creation of simple stub routines that need no help from the GC. Note
</span><span class="cx"> // that codeBlock gets &quot;executed&quot; more than once.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCode.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCode.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITCode.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -218,6 +218,11 @@
</span><span class="cx">     return m_ref.code();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RegisterSet JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex)
+{
+    return RegisterSet();
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCode.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCode.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITCode.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include &quot;JITStubs.h&quot;
</span><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><span class="cx"> #include &quot;MacroAssemblerCodeRef.h&quot;
</span><ins>+#include &quot;RegisterSet.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -193,6 +194,8 @@
</span><span class="cx">     
</span><span class="cx">     virtual bool contains(void*) = 0;
</span><span class="cx"> 
</span><ins>+    virtual RegisterSet liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex);
+
</ins><span class="cx"> private:
</span><span class="cx">     JITType m_jitType;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITInlineCacheGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -51,20 +51,13 @@
</span><span class="cx"> 
</span><span class="cx"> JITByIdGenerator::JITByIdGenerator(
</span><span class="cx">     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType,
</span><del>-    const RegisterSet&amp; usedRegisters, JSValueRegs base, JSValueRegs value,
-    SpillRegistersMode spillMode)
</del><ins>+    const RegisterSet&amp; usedRegisters, JSValueRegs base, JSValueRegs value)
</ins><span class="cx">     : JITInlineCacheGenerator(codeBlock, codeOrigin, callSite, accessType)
</span><span class="cx">     , m_base(base)
</span><span class="cx">     , m_value(value)
</span><span class="cx"> {
</span><del>-    m_stubInfo-&gt;patch.spillMode = spillMode;
</del><span class="cx">     m_stubInfo-&gt;patch.usedRegisters = usedRegisters;
</span><span class="cx">     
</span><del>-    // This is a convenience - in cases where the only registers you're using are base/value,
-    // it allows you to pass RegisterSet() as the usedRegisters argument.
-    m_stubInfo-&gt;patch.usedRegisters.set(base);
-    m_stubInfo-&gt;patch.usedRegisters.set(value);
-    
</del><span class="cx">     m_stubInfo-&gt;patch.baseGPR = static_cast&lt;int8_t&gt;(base.payloadGPR());
</span><span class="cx">     m_stubInfo-&gt;patch.valueGPR = static_cast&lt;int8_t&gt;(value.payloadGPR());
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="lines">@@ -110,9 +103,9 @@
</span><span class="cx"> 
</span><span class="cx"> JITGetByIdGenerator::JITGetByIdGenerator(
</span><span class="cx">     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet&amp; usedRegisters,
</span><del>-    JSValueRegs base, JSValueRegs value, SpillRegistersMode spillMode)
</del><ins>+    JSValueRegs base, JSValueRegs value)
</ins><span class="cx">     : JITByIdGenerator(
</span><del>-        codeBlock, codeOrigin, callSite, AccessType::Get, usedRegisters, base, value, spillMode)
</del><ins>+        codeBlock, codeOrigin, callSite, AccessType::Get, usedRegisters, base, value)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(base.payloadGPR() != value.tagGPR());
</span><span class="cx"> }
</span><span class="lines">@@ -136,10 +129,10 @@
</span><span class="cx"> 
</span><span class="cx"> JITPutByIdGenerator::JITPutByIdGenerator(
</span><span class="cx">     CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet&amp; usedRegisters,
</span><del>-    JSValueRegs base, JSValueRegs value, GPRReg scratch, SpillRegistersMode spillMode,
</del><ins>+    JSValueRegs base, JSValueRegs value, GPRReg scratch, 
</ins><span class="cx">     ECMAMode ecmaMode, PutKind putKind)
</span><span class="cx">     : JITByIdGenerator(
</span><del>-        codeBlock, codeOrigin, callSite, AccessType::Put, usedRegisters, base, value, spillMode)
</del><ins>+        codeBlock, codeOrigin, callSite, AccessType::Put, usedRegisters, base, value)
</ins><span class="cx">     , m_ecmaMode(ecmaMode)
</span><span class="cx">     , m_putKind(putKind)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITInlineCacheGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITByIdGenerator(
</span><span class="cx">         CodeBlock*, CodeOrigin, CallSiteIndex, AccessType, const RegisterSet&amp;, JSValueRegs base,
</span><del>-        JSValueRegs value, SpillRegistersMode spillMode);
</del><ins>+        JSValueRegs value);
</ins><span class="cx">     
</span><span class="cx"> public:
</span><span class="cx">     void reportSlowPathCall(MacroAssembler::Label slowPathBegin, MacroAssembler::Call call)
</span><span class="lines">@@ -96,7 +96,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITGetByIdGenerator(
</span><span class="cx">         CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet&amp; usedRegisters, JSValueRegs base,
</span><del>-        JSValueRegs value, SpillRegistersMode spillMode);
</del><ins>+        JSValueRegs value);
</ins><span class="cx">     
</span><span class="cx">     void generateFastPath(MacroAssembler&amp;);
</span><span class="cx"> };
</span><span class="lines">@@ -107,7 +107,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITPutByIdGenerator(
</span><span class="cx">         CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet&amp; usedRegisters, JSValueRegs base,
</span><del>-        JSValueRegs, GPRReg scratch, SpillRegistersMode spillMode, ECMAMode, PutKind);
</del><ins>+        JSValueRegs, GPRReg scratch, ECMAMode, PutKind);
</ins><span class="cx">     
</span><span class="cx">     void generateFastPath(MacroAssembler&amp;);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -214,7 +214,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITGetByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs(regT0), JSValueRegs(regT0), DontSpill);
</del><ins>+        JSValueRegs(regT0), JSValueRegs(regT0));
</ins><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx"> 
</span><span class="cx">     fastDoneCase = jump();
</span><span class="lines">@@ -422,7 +422,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITPutByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs(regT0), JSValueRegs(regT1), regT2, DontSpill, m_codeBlock-&gt;ecmaMode(), putKind);
</del><ins>+        JSValueRegs(regT0), JSValueRegs(regT1), regT2, m_codeBlock-&gt;ecmaMode(), putKind);
</ins><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx">     doneCases.append(jump());
</span><span class="cx"> 
</span><span class="lines">@@ -547,7 +547,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITGetByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs(regT0), JSValueRegs(regT0), DontSpill);
</del><ins>+        JSValueRegs(regT0), JSValueRegs(regT0));
</ins><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx">     addSlowCase(gen.slowPathJump());
</span><span class="cx">     m_getByIds.append(gen);
</span><span class="lines">@@ -593,7 +593,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITPutByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs(regT0), JSValueRegs(regT1), regT2, DontSpill, m_codeBlock-&gt;ecmaMode(),
</del><ins>+        JSValueRegs(regT0), JSValueRegs(regT1), regT2, m_codeBlock-&gt;ecmaMode(),
</ins><span class="cx">         direct ? Direct : NotDirect);
</span><span class="cx">     
</span><span class="cx">     gen.generateFastPath(*this);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccess32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -283,7 +283,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITGetByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), DontSpill);
</del><ins>+        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0));
</ins><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx"> 
</span><span class="cx">     fastDoneCase = jump();
</span><span class="lines">@@ -495,7 +495,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITPutByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2), regT1, DontSpill, m_codeBlock-&gt;ecmaMode(), putKind);
</del><ins>+        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2), regT1, m_codeBlock-&gt;ecmaMode(), putKind);
</ins><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx">     doneCases.append(jump());
</span><span class="cx"> 
</span><span class="lines">@@ -588,7 +588,7 @@
</span><span class="cx"> 
</span><span class="cx">     JITGetByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
</span><del>-        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), DontSpill);
</del><ins>+        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0));
</ins><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx">     addSlowCase(gen.slowPathJump());
</span><span class="cx">     m_getByIds.append(gen);
</span><span class="lines">@@ -634,7 +634,7 @@
</span><span class="cx">     JITPutByIdGenerator gen(
</span><span class="cx">         m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
</span><span class="cx">         JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2),
</span><del>-        regT1, DontSpill, m_codeBlock-&gt;ecmaMode(), direct ? Direct : NotDirect);
</del><ins>+        regT1, m_codeBlock-&gt;ecmaMode(), direct ? Direct : NotDirect);
</ins><span class="cx">     
</span><span class="cx">     gen.generateFastPath(*this);
</span><span class="cx">     addSlowCase(gen.slowPathJump());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITStubRoutineh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITStubRoutine.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITStubRoutine.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/JITStubRoutine.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -66,6 +66,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     virtual ~JITStubRoutine();
</span><ins>+    virtual void aboutToDie() { }
</ins><span class="cx">     
</span><span class="cx">     // MacroAssemblerCodeRef is copyable, but at the cost of reference
</span><span class="cx">     // counting churn. Returning a reference is a good way of reducing
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -307,6 +307,11 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+RegisterSet RegisterSet::registersToNotSaveForCall()
+{
+    return RegisterSet(RegisterSet::vmCalleeSaveRegisters(), RegisterSet::stackRegisters(), RegisterSet::reservedHardwareRegisters());
+}
+
</ins><span class="cx"> RegisterSet RegisterSet::allGPRs()
</span><span class="cx"> {
</span><span class="cx">     RegisterSet result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -61,6 +61,8 @@
</span><span class="cx">     static RegisterSet allGPRs();
</span><span class="cx">     static RegisterSet allFPRs();
</span><span class="cx">     static RegisterSet allRegisters();
</span><ins>+
+    static RegisterSet registersToNotSaveForCall();
</ins><span class="cx">     
</span><span class="cx">     void set(Reg reg, bool value = true)
</span><span class="cx">     {
</span><span class="lines">@@ -68,11 +70,11 @@
</span><span class="cx">         m_vector.set(reg.index(), value);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void set(JSValueRegs regs)
</del><ins>+    void set(JSValueRegs regs, bool value = true)
</ins><span class="cx">     {
</span><span class="cx">         if (regs.tagGPR() != InvalidGPRReg)
</span><del>-            set(regs.tagGPR());
-        set(regs.payloadGPR());
</del><ins>+            set(regs.tagGPR(), value);
+        set(regs.payloadGPR(), value);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void clear(Reg reg)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitScratchRegisterAllocatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -102,64 +102,55 @@
</span><span class="cx"> GPRReg ScratchRegisterAllocator::allocateScratchGPR() { return allocateScratch&lt;GPRInfo&gt;(); }
</span><span class="cx"> FPRReg ScratchRegisterAllocator::allocateScratchFPR() { return allocateScratch&lt;FPRInfo&gt;(); }
</span><span class="cx"> 
</span><del>-size_t ScratchRegisterAllocator::preserveReusedRegistersByPushing(MacroAssembler&amp; jit)
</del><ins>+unsigned ScratchRegisterAllocator::preserveReusedRegistersByPushing(MacroAssembler&amp; jit)
</ins><span class="cx"> {
</span><span class="cx">     if (!didReuseRegisters())
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    size_t numberOfBytesPushed = 0;
-
</del><ins>+    RegisterSet registersToSpill;
</ins><span class="cx">     for (unsigned i = 0; i &lt; FPRInfo::numberOfRegisters; ++i) {
</span><span class="cx">         FPRReg reg = FPRInfo::toRegister(i);
</span><del>-        if (m_scratchRegisters.getFPRByIndex(i) &amp;&amp; m_usedRegisters.get(reg)) {
-            jit.pushToSave(reg);
-            numberOfBytesPushed += sizeof(double);
-        }
</del><ins>+        if (m_scratchRegisters.getFPRByIndex(i) &amp;&amp; m_usedRegisters.get(reg))
+            registersToSpill.set(reg);
</ins><span class="cx">     }
</span><span class="cx">     for (unsigned i = 0; i &lt; GPRInfo::numberOfRegisters; ++i) {
</span><span class="cx">         GPRReg reg = GPRInfo::toRegister(i);
</span><del>-        if (m_scratchRegisters.getGPRByIndex(i) &amp;&amp; m_usedRegisters.get(reg)) {
-            jit.pushToSave(reg);
-            numberOfBytesPushed += sizeof(uintptr_t);
-        }
</del><ins>+        if (m_scratchRegisters.getGPRByIndex(i) &amp;&amp; m_usedRegisters.get(reg))
+            registersToSpill.set(reg);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    size_t totalStackAdjustmentBytes = numberOfBytesPushed + maxFrameExtentForSlowPathCall;
-    totalStackAdjustmentBytes = WTF::roundUpToMultipleOf(stackAlignmentBytes(), totalStackAdjustmentBytes);
</del><ins>+    unsigned extraStackBytesAtTopOfStack = maxFrameExtentForSlowPathCall;
+    unsigned stackAdjustmentSize = ScratchRegisterAllocator::preserveRegistersToStackForCall(jit, registersToSpill, extraStackBytesAtTopOfStack);
</ins><span class="cx"> 
</span><del>-    // FIXME: We shouldn't have to do this.
-    // https://bugs.webkit.org/show_bug.cgi?id=149030
-    size_t numberOfPaddingBytes = totalStackAdjustmentBytes - numberOfBytesPushed;
-    jit.subPtr(MacroAssembler::TrustedImm32(numberOfPaddingBytes), MacroAssembler::stackPointerRegister);
-
-    return numberOfPaddingBytes;
</del><ins>+    return stackAdjustmentSize;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ScratchRegisterAllocator::restoreReusedRegistersByPopping(MacroAssembler&amp; jit, size_t numberOfPaddingBytes)
</del><ins>+void ScratchRegisterAllocator::restoreReusedRegistersByPopping(MacroAssembler&amp; jit, unsigned numberOfBytesUsedToPreserveReusedRegisters)
</ins><span class="cx"> {
</span><span class="cx">     if (!didReuseRegisters())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    jit.addPtr(MacroAssembler::TrustedImm32(numberOfPaddingBytes), MacroAssembler::stackPointerRegister);
-
</del><ins>+    RegisterSet registersToFill;
</ins><span class="cx">     for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
</span><span class="cx">         GPRReg reg = GPRInfo::toRegister(i);
</span><span class="cx">         if (m_scratchRegisters.getGPRByIndex(i) &amp;&amp; m_usedRegisters.get(reg))
</span><del>-            jit.popToRestore(reg);
</del><ins>+            registersToFill.set(reg);
</ins><span class="cx">     }
</span><span class="cx">     for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
</span><span class="cx">         FPRReg reg = FPRInfo::toRegister(i);
</span><span class="cx">         if (m_scratchRegisters.getFPRByIndex(i) &amp;&amp; m_usedRegisters.get(reg))
</span><del>-            jit.popToRestore(reg);
</del><ins>+            registersToFill.set(reg);
</ins><span class="cx">     }
</span><ins>+
+    unsigned extraStackBytesAtTopOfStack = maxFrameExtentForSlowPathCall;
+    RegisterSet dontRestore; // Empty set. We want to restore everything.
+    ScratchRegisterAllocator::restoreRegistersFromStackForCall(jit, registersToFill, dontRestore, numberOfBytesUsedToPreserveReusedRegisters, extraStackBytesAtTopOfStack);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RegisterSet ScratchRegisterAllocator::usedRegistersForCall() const
</span><span class="cx"> {
</span><span class="cx">     RegisterSet result = m_usedRegisters;
</span><del>-    result.exclude(RegisterSet::calleeSaveRegisters());
-    result.exclude(RegisterSet::stackRegisters());
-    result.exclude(RegisterSet::reservedHardwareRegisters());
</del><ins>+    result.exclude(RegisterSet::registersToNotSaveForCall());
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -176,8 +167,10 @@
</span><span class="cx">     
</span><span class="cx">     unsigned count = 0;
</span><span class="cx">     for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
</span><del>-        if (usedRegisters.get(reg))
-            jit.storePtr(reg, static_cast&lt;EncodedJSValue*&gt;(scratchBuffer-&gt;dataBuffer()) + (count++));
</del><ins>+        if (usedRegisters.get(reg)) {
+            jit.storePtr(reg, static_cast&lt;EncodedJSValue*&gt;(scratchBuffer-&gt;dataBuffer()) + count);
+            count++;
+        }
</ins><span class="cx">         if (GPRInfo::toIndex(reg) != GPRInfo::InvalidIndex
</span><span class="cx">             &amp;&amp; scratchGPR == InvalidGPRReg
</span><span class="cx">             &amp;&amp; !m_lockedRegisters.get(reg) &amp;&amp; !m_scratchRegisters.get(reg))
</span><span class="lines">@@ -186,7 +179,8 @@
</span><span class="cx">     RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
</span><span class="cx">     for (FPRReg reg = MacroAssembler::firstFPRegister(); reg &lt;= MacroAssembler::lastFPRegister(); reg = MacroAssembler::nextFPRegister(reg)) {
</span><span class="cx">         if (usedRegisters.get(reg)) {
</span><del>-            jit.move(MacroAssembler::TrustedImmPtr(static_cast&lt;EncodedJSValue*&gt;(scratchBuffer-&gt;dataBuffer()) + (count++)), scratchGPR);
</del><ins>+            jit.move(MacroAssembler::TrustedImmPtr(static_cast&lt;EncodedJSValue*&gt;(scratchBuffer-&gt;dataBuffer()) + count), scratchGPR);
+            count++;
</ins><span class="cx">             jit.storeDouble(reg, scratchGPR);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -232,6 +226,74 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+unsigned ScratchRegisterAllocator::preserveRegistersToStackForCall(MacroAssembler&amp; jit, const RegisterSet&amp; usedRegisters, unsigned extraBytesAtTopOfStack)
+{
+    RELEASE_ASSERT(extraBytesAtTopOfStack % sizeof(void*) == 0);
+    if (!usedRegisters.numberOfSetRegisters())
+        return 0;
+    
+    unsigned stackOffset = (usedRegisters.numberOfSetRegisters()) * sizeof(EncodedJSValue);
+    stackOffset += extraBytesAtTopOfStack;
+    stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), stackOffset);
+    jit.subPtr(
+        MacroAssembler::TrustedImm32(stackOffset),
+        MacroAssembler::stackPointerRegister);
+
+    unsigned count = 0;
+    for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
+        if (usedRegisters.get(reg)) {
+            jit.storePtr(reg, MacroAssembler::Address(MacroAssembler::stackPointerRegister, extraBytesAtTopOfStack + (count * sizeof(EncodedJSValue))));
+            count++;
+        }
+    }
+    for (FPRReg reg = MacroAssembler::firstFPRegister(); reg &lt;= MacroAssembler::lastFPRegister(); reg = MacroAssembler::nextFPRegister(reg)) {
+        if (usedRegisters.get(reg)) {
+            jit.storeDouble(reg, MacroAssembler::Address(MacroAssembler::stackPointerRegister, extraBytesAtTopOfStack + (count * sizeof(EncodedJSValue))));
+            count++;
+        }
+    }
+
+    RELEASE_ASSERT(count == usedRegisters.numberOfSetRegisters());
+
+    return stackOffset;
+}
+
+void ScratchRegisterAllocator::restoreRegistersFromStackForCall(MacroAssembler&amp; jit, const RegisterSet&amp; usedRegisters, const RegisterSet&amp; ignore, unsigned numberOfStackBytesUsedForRegisterPreservation, unsigned extraBytesAtTopOfStack)
+{
+    RELEASE_ASSERT(extraBytesAtTopOfStack % sizeof(void*) == 0);
+    if (!usedRegisters.numberOfSetRegisters()) {
+        RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == 0);
+        return;
+    }
+
+    unsigned count = 0;
+    for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
+        if (usedRegisters.get(reg)) {
+            if (!ignore.get(reg))
+                jit.loadPtr(MacroAssembler::Address(MacroAssembler::stackPointerRegister, extraBytesAtTopOfStack + (sizeof(EncodedJSValue) * count)), reg);
+            count++;
+        }
+    }
+    for (FPRReg reg = MacroAssembler::firstFPRegister(); reg &lt;= MacroAssembler::lastFPRegister(); reg = MacroAssembler::nextFPRegister(reg)) {
+        if (usedRegisters.get(reg)) {
+            if (!ignore.get(reg))
+                jit.loadDouble(MacroAssembler::Address(MacroAssembler::stackPointerRegister, extraBytesAtTopOfStack + (sizeof(EncodedJSValue) * count)), reg);
+            count++;
+        }
+    }
+
+    unsigned stackOffset = (usedRegisters.numberOfSetRegisters()) * sizeof(EncodedJSValue);
+    stackOffset += extraBytesAtTopOfStack;
+    stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), stackOffset);
+
+    RELEASE_ASSERT(count == usedRegisters.numberOfSetRegisters());
+    RELEASE_ASSERT(stackOffset == numberOfStackBytesUsedForRegisterPreservation);
+
+    jit.addPtr(
+        MacroAssembler::TrustedImm32(stackOffset),
+        MacroAssembler::stackPointerRegister);
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitScratchRegisterAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -63,22 +63,26 @@
</span><span class="cx">     {
</span><span class="cx">         return m_numberOfReusedRegisters;
</span><span class="cx">     }
</span><ins>+
+    RegisterSet usedRegisters() const { return m_usedRegisters; }
</ins><span class="cx">     
</span><span class="cx">     // preserveReusedRegistersByPushing() returns the number of padding bytes used to keep the stack
</span><span class="cx">     // pointer properly aligned and to reserve room for calling a C helper. This number of padding
</span><span class="cx">     // bytes must be provided to restoreReusedRegistersByPopping() in order to reverse the work done
</span><span class="cx">     // by preserveReusedRegistersByPushing().
</span><del>-    size_t preserveReusedRegistersByPushing(MacroAssembler&amp; jit);
-    void restoreReusedRegistersByPopping(MacroAssembler&amp; jit, size_t numberOfPaddingBytes);
</del><ins>+    unsigned preserveReusedRegistersByPushing(MacroAssembler&amp; jit);
+    void restoreReusedRegistersByPopping(MacroAssembler&amp; jit, unsigned numberOfBytesUsedToPreserveReusedRegisters);
</ins><span class="cx">     
</span><span class="cx">     RegisterSet usedRegistersForCall() const;
</span><span class="cx">     
</span><span class="cx">     unsigned desiredScratchBufferSizeForCall() const;
</span><span class="cx">     
</span><span class="cx">     void preserveUsedRegistersToScratchBufferForCall(MacroAssembler&amp; jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg);
</span><del>-    
</del><span class="cx">     void restoreUsedRegistersFromScratchBufferForCall(MacroAssembler&amp; jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg);
</span><del>-    
</del><ins>+
+    static unsigned preserveRegistersToStackForCall(MacroAssembler&amp; jit, const RegisterSet&amp; usedRegisters, unsigned extraPaddingInBytes);
+    static void restoreRegistersFromStackForCall(MacroAssembler&amp; jit, const RegisterSet&amp; usedRegisters, const RegisterSet&amp; ignore, unsigned numberOfStackBytesUsedForRegisterPreservation, unsigned extraPaddingInBytes);
+
</ins><span class="cx"> private:
</span><span class="cx">     RegisterSet m_usedRegisters;
</span><span class="cx">     TempRegisterSet m_lockedRegisters;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (190734 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2015-10-08 18:46:20 UTC (rev 190734)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -314,6 +314,52 @@
</span><span class="cx">     WriteBarrier&lt;JSObject&gt; m_delegate;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class CustomGetter : public JSNonFinalObject {
+public:
+    CustomGetter(VM&amp; vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+
+    DECLARE_INFO;
+    typedef JSNonFinalObject Base;
+    static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot;
+
+    static Structure* createStructure(VM&amp; vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+    static CustomGetter* create(VM&amp; vm, Structure* structure)
+    {
+        CustomGetter* getter = new (NotNull, allocateCell&lt;CustomGetter&gt;(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure);
+        getter-&gt;finishCreation(vm);
+        return getter;
+    }
+
+    static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot&amp; slot)
+    {
+        CustomGetter* thisObject = jsCast&lt;CustomGetter*&gt;(object);
+        if (propertyName == PropertyName(Identifier::fromString(exec, &quot;customGetter&quot;))) {
+            slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject-&gt;customGetter);
+            return true;
+        }
+        return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+    }
+
+private:
+    static EncodedJSValue customGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
+    {
+        CustomGetter* thisObject = jsDynamicCast&lt;CustomGetter*&gt;(JSValue::decode(thisValue));
+        if (!thisObject)
+            return throwVMTypeError(exec);
+        bool shouldThrow = thisObject-&gt;get(exec, PropertyName(Identifier::fromString(exec, &quot;shouldThrow&quot;))).toBoolean(exec);
+        if (shouldThrow)
+            return throwVMTypeError(exec);
+        return JSValue::encode(jsNumber(100));
+    }
+};
+
</ins><span class="cx"> class RuntimeArray : public JSArray {
</span><span class="cx"> public:
</span><span class="cx">     typedef JSArray Base;
</span><span class="lines">@@ -422,6 +468,7 @@
</span><span class="cx"> const ClassInfo Masquerader::s_info = { &quot;Masquerader&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
</span><span class="cx"> const ClassInfo Root::s_info = { &quot;Root&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
</span><span class="cx"> const ClassInfo ImpureGetter::s_info = { &quot;ImpureGetter&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
</span><ins>+const ClassInfo CustomGetter::s_info = { &quot;CustomGetter&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
</ins><span class="cx"> const ClassInfo RuntimeArray::s_info = { &quot;RuntimeArray&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
</span><span class="cx"> 
</span><span class="cx"> ElementHandleOwner* Element::handleOwner()
</span><span class="lines">@@ -446,6 +493,7 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
</ins><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
</span><span class="cx"> 
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
</span><span class="lines">@@ -663,6 +711,7 @@
</span><span class="cx">         addFunction(vm, &quot;createRuntimeArray&quot;, functionCreateRuntimeArray, 0);
</span><span class="cx"> 
</span><span class="cx">         addFunction(vm, &quot;createImpureGetter&quot;, functionCreateImpureGetter, 1);
</span><ins>+        addFunction(vm, &quot;createCustomGetterObject&quot;, functionCreateCustomGetterObject, 0);
</ins><span class="cx">         addFunction(vm, &quot;setImpureGetterDelegate&quot;, functionSetImpureGetterDelegate, 2);
</span><span class="cx"> 
</span><span class="cx">         addFunction(vm, &quot;dumpTypesForAllVariables&quot;, functionDumpTypesForAllVariables , 0);
</span><span class="lines">@@ -1092,6 +1141,14 @@
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
+{
+    JSLockHolder lock(exec);
+    Structure* structure = CustomGetter::createStructure(exec-&gt;vm(), exec-&gt;lexicalGlobalObject(), jsNull());
+    CustomGetter* result = CustomGetter::create(exec-&gt;vm(), structure);
+    return JSValue::encode(result);
+}
+
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     JSLockHolder lock(exec);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrycatchcustomgetterasgetbyidjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/try-catch-custom-getter-as-get-by-id.js (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/try-catch-custom-getter-as-get-by-id.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/try-catch-custom-getter-as-get-by-id.js        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+function assert(b) {
+    if (!b) throw new Error(&quot;b&quot;);
+}
+noInline(assert);
+
+let i;
+var o1 = createCustomGetterObject();
+o1.shouldThrow = false;
+
+var o2 = {
+    customGetter: 40
+}
+
+var o3 = { 
+    x: 100,
+    customGetter: 50 
+}
+
+i = -1000;
+bar(i);
+foo(i);
+function bar(i) {
+    if (i === -1000)
+        return o1;
+
+    if (i % 2)
+        return o3;
+    else
+        return o2;
+}
+noInline(bar);
+
+function foo(i) {
+    var o = bar(i);
+    var v;
+    try {
+        v = o.customGetter;
+    } catch(e) {
+        assert(o === o1);
+    }
+}
+noInline(foo);
+
+foo(i);
+for (i = 0; i &lt; 1000; i++)
+    foo(i);
+
+i = -1000;
+for (let j = 0; j &lt; 1000; j++) {
+    if (j &gt; 10)
+        o1.shouldThrow = true;
+    foo(i);
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrycatchgetterasgetbyidregisterrestorationjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id-register-restoration.js (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id-register-restoration.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id-register-restoration.js        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+function assert(b) {
+    if (!b) throw new Error(&quot;bad value&quot;);
+}
+noInline(assert);
+
+let i;
+var o1 = { 
+    get f() {
+        if (i === -1000)
+            throw new Error(&quot;hello&quot;);
+        return 20;
+    },
+    x: &quot;x&quot;
+};
+
+var o2 = {
+    f: 40
+}
+
+var o3 = {
+    x: 100,
+    f: &quot;f&quot;
+}
+
+function bar(i) {
+    if (i === -1000)
+        return o1;
+
+    if (i % 2)
+        return o3;
+    else
+        return o2;
+}
+noInline(bar);
+
+function foo(i) {
+    var o = bar(i);
+    let v;
+    let v2;
+    let v3;
+    try {
+        v2 = o.x;
+        v = o.f;
+    } catch(e) {
+        assert(v2 === &quot;x&quot;);
+        assert(o === o1);
+    }
+}
+noInline(foo);
+
+foo(i);
+for (i = 0; i &lt; 1000; i++)
+    foo(i);
+
+i = -1000;
+for (let j = 0; j &lt; 1000; j++)
+    foo(i);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrycatchgetterasgetbyidjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id.js (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/try-catch-getter-as-get-by-id.js        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+function assert(b) {
+    if (!b) throw new Error(&quot;b&quot;);
+}
+noInline(assert);
+
+
+let i;
+var o1 = { 
+    get f() {
+        if (i === -1000)
+            throw new Error(&quot;hello&quot;);
+        return 20;
+    }
+};
+
+var o2 = {
+    f: 40
+}
+
+var o3 = { 
+    x: 100,
+    f: 50 
+}
+
+function bar(i) {
+    if (i === -1000)
+        return o1;
+
+    if (i % 2)
+        return o3;
+    else
+        return o2;
+}
+noInline(bar);
+
+function foo(i) {
+    var o = bar(i);
+    var v;
+    try {
+        v = o.f
+    } catch(e) {
+        assert(o === o1);
+    }
+}
+noInline(foo);
+
+foo(i);
+for (i = 0; i &lt; 1000; i++)
+    foo(i);
+
+i = -1000;
+for (let j = 0; j &lt; 1000; j++)
+    foo(i);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrycatchsetterasputbyidjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/try-catch-setter-as-put-by-id.js (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/try-catch-setter-as-put-by-id.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/try-catch-setter-as-put-by-id.js        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+function assert(b) {
+    if (!b) 
+        throw new Error(&quot;bad assertion&quot;);
+}
+noInline(assert);
+
+
+let i;
+var o1 = { 
+    set f(v) {
+        if (i === -1000)
+            throw new Error(&quot;hello&quot;);
+        this._v = v;
+    }
+};
+
+var o2 = {
+    f: 40
+}
+
+var o3 = { 
+    x: 100,
+    f: 50 
+}
+
+function bar(i) {
+    if (i === -1000)
+        return o1;
+
+    if (i % 2)
+        return o3;
+    else
+        return o2;
+}
+noInline(bar);
+
+function foo(i) {
+    let o = bar(i);
+    let v = o.x;
+    try {
+        o.f = v;
+    } catch(e) {
+        assert(o === o1);
+    }
+}
+noInline(foo);
+
+foo(i);
+for (i = 0; i &lt; 1000; i++)
+    foo(i);
+
+i = -1000;
+for (let j = 0; j &lt; 1000; j++)
+    foo(i);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrycatchstubroutinereplacedjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js (0 => 190735)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js        2015-10-08 19:37:28 UTC (rev 190735)
</span><span class="lines">@@ -0,0 +1,79 @@
</span><ins>+// The main purpose of this test is to ensure that
+// we will re-use no longer in use CallSiteIndices for
+// inline cache stubs. See relevant code in destructor
+// which calls:
+// DFG::CommonData::removeCallSiteIndex(.)
+// CodeBlock::removeExceptionHandlerForCallSite(.)
+// Which add old call site indices to a free list.
+
+function assert(b) {
+    if (!b)
+        throw new Error(&quot;bad value&quot;);
+}
+noInline(assert);
+
+var arr = []
+function allocate() {
+    for (var i = 0; i &lt; 10000; i++)
+        arr.push({});
+}
+
+function hello() { return 20; }
+noInline(hello);
+
+function foo(o) {
+    let baz = hello();
+    let v;
+    try {
+        v = o.f;
+        v = o.f;
+        v = o.f;
+    } catch(e) {
+        assert(baz === 20);
+        assert(v === 2); // Really flagCount.
+    }
+    return v;
+}
+noInline(foo);
+
+var objChain = {f: 40};
+var fakeOut = {x: 30, f: 100};
+for (let i = 0; i &lt; 1000; i++)
+    foo(i % 2 ? objChain : fakeOut);
+
+var i;
+var flag = &quot;flag&quot;;
+var flagCount = 0;
+objChain = { 
+    get f() {
+        if (flagCount === 2)
+            throw new Error(&quot;I'm testing you.&quot;);
+        if (i === flag)
+            flagCount++;
+        return flagCount;
+    }
+};
+for (i = 0; i &lt; 100; i++) {
+    allocate();
+    if (i === 99)
+        i = flag;
+    foo(objChain);
+}
+
+fakeOut = {x: 30, get f() { return 100}};
+for (i = 0; i &lt; 100; i++) {
+    allocate();
+    if (i === 99)
+        i = flag;
+    foo(fakeOut);
+}
+
+var o = { 
+    get f() {
+        return flagCount;
+    },
+    x: 100
+};
+
+for (i = 0; i &lt; 100; i++)
+    foo(o);
</ins></span></pre>
</div>
</div>

</body>
</html>