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

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

<h3>Log Message</h3>
<pre>Implement try/catch in the FTL
https://bugs.webkit.org/show_bug.cgi?id=149409

Reviewed by Filip Pizlo.

This patch implements try/catch in the FTL in a similar
way to how it's implemented in the DFG. The main idea is
this: anytime an exception is thrown in a try block, 
we OSR exit into the baseline JIT's corresponding catch
block. We compile OSR exits in a few forms:
1) Explicit exception checks that check VM's exception
pointer. This is modeled explicitly in LLVM IR.
2) OSR exits that are arrived at from genericUnwind 
caused by an exception being thrown in a JS call (including
getters and setters).
3) Exception from lazy slow paths.
4) Exception from when an IC misses and makes a slow path C Call.

All stackmaps associated with the above types of exits all 
take arguments that correspond to variables that are 
bytecode-live in the catch block.

1) Item 1 is the simplest implementation. When inside
a try block, exception checks will emit a branch to
an OSR exit stackmap intrinsic. This stackmap intrinsic
takes as arguments the live catch variables.

2) All forms of calls and GetByIds and PutByIds are implemented
as patchpoints in LLVM. As a patchpoint, they have a stackmap ID.
We use the same stackmap ID for the OSR exit. The OSR exit arguments
are appended to the end of the normal arguments for the patchpoint. These
types of OSR exits are only reached indirectly via genericUnwind.
Therefore, the LLVM IR we generate never has a direct branch to them.
These are the OSR exits we store in the CodeBlock's exception handling
table. The exception handlers' code locations point to the beginning
of the corresponding OSR exit. There is an interesting story here
about how we preserve registers. LLVM patchpoints assume late clobber,
i.e, they assume we use the patchpoint arguments before we clobber them.
Therefore, it's sound for LLVM to pass us arguments in volatile registers.
We must take care to store the arguments in volatile registers to the
stack before making a call. We ensure we have stack space for these
by using LLVM's alloca instruction. Then, when making a call inside
a try block, we spill the needed registers, and if that call throws,
we make sure the OSR exit fills the corresponding registers.

3) Exceptions from lazy slow paths are similar to (2) except they
don't go through generic unwind. These OSR Exits are arrived at from explicit
exception checks in the generated lazy slow path. Therefore, the callframe
is intact when arriving at the OSR exit. We make sure such lazy slow
paths exception check are linked to the OSR exit's code location.

4) This has a really interesting register preservation story.
We may have a GetById that has an IC miss and therefore goes
through the FTL's callOperation machinery. LLVM may also
ask for the result to be placed in the same register as the
base. Therefore, after the call, when storing to the result,
we overwrite the base. This can't fly with exceptions because
operationGetByIdOptimize may throw an exception and return &quot;undefined&quot;. What
we really want is the original base value for OSR exit value
recovery. In this case, we take special care to flush the base 
value to the stack before the callOperation GetById slow path. 
Like call OSR exits, these types of exits will recover the base 
value from the stack when necessary.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::newExceptionHandlingCallSiteIndex):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::canOptimizeStringObjectAccess):
(JSC::DFG::Graph::willCatchExceptionInMachineFrame):
* dfg/DFGGraph.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::appendExceptionHandlingOSRExit):
(JSC::DFG::JITCompiler::exceptionCheck):
(JSC::DFG::JITCompiler::recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded):
(JSC::DFG::JITCompiler::willCatchExceptionInMachineFrame): Deleted.
* dfg/DFGJITCompiler.h:
* dfg/DFGNodeOrigin.h:
(JSC::DFG::NodeOrigin::withSemantic):
(JSC::DFG::NodeOrigin::withForExitAndExitOK):
(JSC::DFG::NodeOrigin::withExitOK):
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::OSRExit):
* dfg/DFGOSRExit.h:
(JSC::DFG::OSRExit::considerAddingAsFrequentExitSite):
* dfg/DFGOSRExitBase.h:
(JSC::DFG::OSRExitBase::OSRExitBase):
(JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):
* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::reifyInlinedCallFrames):
* dfg/DFGPutStackSinkingPhase.cpp:
* dfg/DFGTierUpCheckInjectionPhase.cpp:
(JSC::DFG::TierUpCheckInjectionPhase::run):
* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLExitArgument.h:
(JSC::FTL::ExitArgument::withFormat):
(JSC::FTL::ExitArgument::representation):
* ftl/FTLExitThunkGenerator.cpp:
(JSC::FTL::ExitThunkGenerator::~ExitThunkGenerator):
(JSC::FTL::ExitThunkGenerator::emitThunk):
(JSC::FTL::ExitThunkGenerator::emitThunks):
* ftl/FTLExitThunkGenerator.h:
(JSC::FTL::ExitThunkGenerator::didThings):
* ftl/FTLExitValue.h:
(JSC::FTL::ExitValue::isArgument):
(JSC::FTL::ExitValue::isRecovery):
(JSC::FTL::ExitValue::isObjectMaterialization):
(JSC::FTL::ExitValue::hasIndexInStackmapLocations):
(JSC::FTL::ExitValue::exitArgument):
(JSC::FTL::ExitValue::rightRecoveryArgument):
(JSC::FTL::ExitValue::adjustStackmapLocationsIndexByOffset):
(JSC::FTL::ExitValue::recoveryFormat):
* ftl/FTLJITCode.cpp:
(JSC::FTL::JITCode::validateReferences):
(JSC::FTL::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
* ftl/FTLJSCall.cpp:
(JSC::FTL::JSCall::JSCall):
(JSC::FTL::JSCall::emit):
* ftl/FTLJSCall.h:
(JSC::FTL::JSCall::stackmapID):
* ftl/FTLJSCallBase.cpp:
(JSC::FTL::JSCallBase::JSCallBase):
(JSC::FTL::JSCallBase::emit):
* ftl/FTLJSCallBase.h:
(JSC::FTL::JSCallBase::setCallSiteIndex):
(JSC::FTL::JSCallBase::callSiteDescriptionOrigin):
(JSC::FTL::JSCallBase::setCorrespondingGenericUnwindOSRExit):
* ftl/FTLJSCallVarargs.cpp:
(JSC::FTL::JSCallVarargs::numSpillSlotsNeeded):
(JSC::FTL::JSCallVarargs::emit):
* ftl/FTLJSCallVarargs.h:
(JSC::FTL::JSCallVarargs::stackmapID):
(JSC::FTL::JSCallVarargs::operator&lt;):
(JSC::FTL::JSCallVarargs::setCallSiteIndex):
(JSC::FTL::JSCallVarargs::callSiteDescriptionOrigin):
(JSC::FTL::JSCallVarargs::setCorrespondingGenericUnwindOSRExit):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::lower):
(JSC::FTL::DFG::LowerDFGToLLVM::compilePutById):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCallOrConstruct):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCallOrConstructVarargs):
(JSC::FTL::DFG::LowerDFGToLLVM::getById):
(JSC::FTL::DFG::LowerDFGToLLVM::lazySlowPath):
(JSC::FTL::DFG::LowerDFGToLLVM::speculate):
(JSC::FTL::DFG::LowerDFGToLLVM::terminate):
(JSC::FTL::DFG::LowerDFGToLLVM::appendTypeCheck):
(JSC::FTL::DFG::LowerDFGToLLVM::callPreflight):
(JSC::FTL::DFG::LowerDFGToLLVM::callCheck):
(JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExitArgumentsForPatchpointIfWillCatchException):
(JSC::FTL::DFG::LowerDFGToLLVM::emitBranchToOSRExitIfWillCatchException):
(JSC::FTL::DFG::LowerDFGToLLVM::lowBlock):
(JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExitDescriptor):
(JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::DFG::LowerDFGToLLVM::exitValueForNode):
* ftl/FTLOSRExit.cpp:
(JSC::FTL::OSRExitDescriptor::OSRExitDescriptor):
(JSC::FTL::OSRExit::OSRExit):
(JSC::FTL::OSRExit::codeLocationForRepatch):
(JSC::FTL::OSRExit::gatherRegistersToSpillForCallIfException):
(JSC::FTL::OSRExit::spillRegistersToSpillSlot):
(JSC::FTL::OSRExit::recoverRegistersFromSpillSlot):
* ftl/FTLOSRExit.h:
(JSC::FTL::OSRExit::considerAddingAsFrequentExitSite):
* ftl/FTLOSRExitCompilationInfo.h:
(JSC::FTL::OSRExitCompilationInfo::OSRExitCompilationInfo):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
(JSC::FTL::compileFTLOSRExit):
* ftl/FTLState.cpp:
(JSC::FTL::State::State):
* ftl/FTLState.h:
* interpreter/Interpreter.cpp:
(JSC::findExceptionHandler):
* jit/RegisterSet.cpp:
(JSC::RegisterSet::specialRegisters):
(JSC::RegisterSet::volatileRegistersForJSCall):
(JSC::RegisterSet::stubUnavailableRegisters):
* jit/RegisterSet.h:
* tests/stress/ftl-try-catch-getter-ic-fail-to-call-operation-throw-error.js: Added.
(assert):
(let.oThrow.get f):
(let.o2.get f):
(foo):
(f):
* tests/stress/ftl-try-catch-getter-throw.js: Added.
(assert):
(random):
(foo):
(f):
(let.o2.get f):
* tests/stress/ftl-try-catch-oom-error-lazy-slow-path.js: Added.
(assert):
(a):
(b):
(c):
(d):
(e):
(f):
(g):
(foo):
(blah):
* tests/stress/ftl-try-catch-patchpoint-with-volatile-registers.js: Added.
(assert):
(o1.get f):
(a):
(b):
(c):
(d):
(e):
(f):
(g):
(o2.get f):
(foo):
* tests/stress/ftl-try-catch-setter-throw.js: Added.
(foo):
(assert):
(f):
(let.o2.set f):
* tests/stress/ftl-try-catch-tail-call-inilned-caller.js: Added.
(value):
(assert):
(validate):
(bar):
(baz):
(jaz):
* tests/stress/ftl-try-catch-varargs-call-throws.js: Added.
(foo):
(f):
* tests/stress/try-catch-stub-routine-replaced.js:
(hello):
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<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="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCompilercpp">trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCompilerh">trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeOriginh">trunk/Source/JavaScriptCore/dfg/DFGNodeOrigin.h</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="#trunkSourceJavaScriptCoredfgDFGOSRExitBaseh">trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOSRExitCompilerCommoncpp">trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGTierUpCheckInjectionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExitArgumenth">trunk/Source/JavaScriptCore/ftl/FTLExitArgument.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExitThunkGeneratorcpp">trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExitThunkGeneratorh">trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExitValueh">trunk/Source/JavaScriptCore/ftl/FTLExitValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJITCodecpp">trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallcpp">trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallh">trunk/Source/JavaScriptCore/ftl/FTLJSCall.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallBasecpp">trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallBaseh">trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallVarargscpp">trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallVarargsh">trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExitcpp">trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExith">trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExitCompilationInfoh">trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExitCompilercpp">trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLStatecpp">trunk/Source/JavaScriptCore/ftl/FTLState.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLStateh">trunk/Source/JavaScriptCore/ftl/FTLState.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</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="#trunkSourceJavaScriptCoretestsstresstrycatchstubroutinereplacedjs">trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchgettericfailtocalloperationthrowerrorjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-ic-fail-to-call-operation-throw-error.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchgetterthrowjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-throw.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchoomerrorlazyslowpathjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-oom-error-lazy-slow-path.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchpatchpointwithvolatileregistersjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-patchpoint-with-volatile-registers.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchsetterthrowjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-setter-throw.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchtailcallinilnedcallerjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-tail-call-inilned-caller.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressftltrycatchvarargscallthrowsjs">trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-varargs-call-throws.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -1,3 +1,237 @@
</span><ins>+2015-11-09  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Implement try/catch in the FTL
+        https://bugs.webkit.org/show_bug.cgi?id=149409
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements try/catch in the FTL in a similar
+        way to how it's implemented in the DFG. The main idea is
+        this: anytime an exception is thrown in a try block, 
+        we OSR exit into the baseline JIT's corresponding catch
+        block. We compile OSR exits in a few forms:
+        1) Explicit exception checks that check VM's exception
+        pointer. This is modeled explicitly in LLVM IR.
+        2) OSR exits that are arrived at from genericUnwind 
+        caused by an exception being thrown in a JS call (including
+        getters and setters).
+        3) Exception from lazy slow paths.
+        4) Exception from when an IC misses and makes a slow path C Call.
+
+        All stackmaps associated with the above types of exits all 
+        take arguments that correspond to variables that are 
+        bytecode-live in the catch block.
+
+        1) Item 1 is the simplest implementation. When inside
+        a try block, exception checks will emit a branch to
+        an OSR exit stackmap intrinsic. This stackmap intrinsic
+        takes as arguments the live catch variables.
+
+        2) All forms of calls and GetByIds and PutByIds are implemented
+        as patchpoints in LLVM. As a patchpoint, they have a stackmap ID.
+        We use the same stackmap ID for the OSR exit. The OSR exit arguments
+        are appended to the end of the normal arguments for the patchpoint. These
+        types of OSR exits are only reached indirectly via genericUnwind.
+        Therefore, the LLVM IR we generate never has a direct branch to them.
+        These are the OSR exits we store in the CodeBlock's exception handling
+        table. The exception handlers' code locations point to the beginning
+        of the corresponding OSR exit. There is an interesting story here
+        about how we preserve registers. LLVM patchpoints assume late clobber,
+        i.e, they assume we use the patchpoint arguments before we clobber them.
+        Therefore, it's sound for LLVM to pass us arguments in volatile registers.
+        We must take care to store the arguments in volatile registers to the
+        stack before making a call. We ensure we have stack space for these
+        by using LLVM's alloca instruction. Then, when making a call inside
+        a try block, we spill the needed registers, and if that call throws,
+        we make sure the OSR exit fills the corresponding registers.
+
+        3) Exceptions from lazy slow paths are similar to (2) except they
+        don't go through generic unwind. These OSR Exits are arrived at from explicit
+        exception checks in the generated lazy slow path. Therefore, the callframe
+        is intact when arriving at the OSR exit. We make sure such lazy slow
+        paths exception check are linked to the OSR exit's code location.
+
+        4) This has a really interesting register preservation story.
+        We may have a GetById that has an IC miss and therefore goes
+        through the FTL's callOperation machinery. LLVM may also
+        ask for the result to be placed in the same register as the
+        base. Therefore, after the call, when storing to the result,
+        we overwrite the base. This can't fly with exceptions because
+        operationGetByIdOptimize may throw an exception and return &quot;undefined&quot;. What
+        we really want is the original base value for OSR exit value
+        recovery. In this case, we take special care to flush the base 
+        value to the stack before the callOperation GetById slow path. 
+        Like call OSR exits, these types of exits will recover the base 
+        value from the stack when necessary.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::newExceptionHandlingCallSiteIndex):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::canOptimizeStringObjectAccess):
+        (JSC::DFG::Graph::willCatchExceptionInMachineFrame):
+        * dfg/DFGGraph.h:
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::appendExceptionHandlingOSRExit):
+        (JSC::DFG::JITCompiler::exceptionCheck):
+        (JSC::DFG::JITCompiler::recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded):
+        (JSC::DFG::JITCompiler::willCatchExceptionInMachineFrame): Deleted.
+        * dfg/DFGJITCompiler.h:
+        * dfg/DFGNodeOrigin.h:
+        (JSC::DFG::NodeOrigin::withSemantic):
+        (JSC::DFG::NodeOrigin::withForExitAndExitOK):
+        (JSC::DFG::NodeOrigin::withExitOK):
+        * dfg/DFGOSRExit.cpp:
+        (JSC::DFG::OSRExit::OSRExit):
+        * dfg/DFGOSRExit.h:
+        (JSC::DFG::OSRExit::considerAddingAsFrequentExitSite):
+        * dfg/DFGOSRExitBase.h:
+        (JSC::DFG::OSRExitBase::OSRExitBase):
+        (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):
+        * dfg/DFGOSRExitCompilerCommon.cpp:
+        (JSC::DFG::reifyInlinedCallFrames):
+        * dfg/DFGPutStackSinkingPhase.cpp:
+        * dfg/DFGTierUpCheckInjectionPhase.cpp:
+        (JSC::DFG::TierUpCheckInjectionPhase::run):
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::mmAllocateDataSection):
+        * ftl/FTLExitArgument.h:
+        (JSC::FTL::ExitArgument::withFormat):
+        (JSC::FTL::ExitArgument::representation):
+        * ftl/FTLExitThunkGenerator.cpp:
+        (JSC::FTL::ExitThunkGenerator::~ExitThunkGenerator):
+        (JSC::FTL::ExitThunkGenerator::emitThunk):
+        (JSC::FTL::ExitThunkGenerator::emitThunks):
+        * ftl/FTLExitThunkGenerator.h:
+        (JSC::FTL::ExitThunkGenerator::didThings):
+        * ftl/FTLExitValue.h:
+        (JSC::FTL::ExitValue::isArgument):
+        (JSC::FTL::ExitValue::isRecovery):
+        (JSC::FTL::ExitValue::isObjectMaterialization):
+        (JSC::FTL::ExitValue::hasIndexInStackmapLocations):
+        (JSC::FTL::ExitValue::exitArgument):
+        (JSC::FTL::ExitValue::rightRecoveryArgument):
+        (JSC::FTL::ExitValue::adjustStackmapLocationsIndexByOffset):
+        (JSC::FTL::ExitValue::recoveryFormat):
+        * ftl/FTLJITCode.cpp:
+        (JSC::FTL::JITCode::validateReferences):
+        (JSC::FTL::JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite):
+        * ftl/FTLJSCall.cpp:
+        (JSC::FTL::JSCall::JSCall):
+        (JSC::FTL::JSCall::emit):
+        * ftl/FTLJSCall.h:
+        (JSC::FTL::JSCall::stackmapID):
+        * ftl/FTLJSCallBase.cpp:
+        (JSC::FTL::JSCallBase::JSCallBase):
+        (JSC::FTL::JSCallBase::emit):
+        * ftl/FTLJSCallBase.h:
+        (JSC::FTL::JSCallBase::setCallSiteIndex):
+        (JSC::FTL::JSCallBase::callSiteDescriptionOrigin):
+        (JSC::FTL::JSCallBase::setCorrespondingGenericUnwindOSRExit):
+        * ftl/FTLJSCallVarargs.cpp:
+        (JSC::FTL::JSCallVarargs::numSpillSlotsNeeded):
+        (JSC::FTL::JSCallVarargs::emit):
+        * ftl/FTLJSCallVarargs.h:
+        (JSC::FTL::JSCallVarargs::stackmapID):
+        (JSC::FTL::JSCallVarargs::operator&lt;):
+        (JSC::FTL::JSCallVarargs::setCallSiteIndex):
+        (JSC::FTL::JSCallVarargs::callSiteDescriptionOrigin):
+        (JSC::FTL::JSCallVarargs::setCorrespondingGenericUnwindOSRExit):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::lower):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compilePutById):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCallOrConstruct):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCallOrConstructVarargs):
+        (JSC::FTL::DFG::LowerDFGToLLVM::getById):
+        (JSC::FTL::DFG::LowerDFGToLLVM::lazySlowPath):
+        (JSC::FTL::DFG::LowerDFGToLLVM::speculate):
+        (JSC::FTL::DFG::LowerDFGToLLVM::terminate):
+        (JSC::FTL::DFG::LowerDFGToLLVM::appendTypeCheck):
+        (JSC::FTL::DFG::LowerDFGToLLVM::callPreflight):
+        (JSC::FTL::DFG::LowerDFGToLLVM::callCheck):
+        (JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExitArgumentsForPatchpointIfWillCatchException):
+        (JSC::FTL::DFG::LowerDFGToLLVM::emitBranchToOSRExitIfWillCatchException):
+        (JSC::FTL::DFG::LowerDFGToLLVM::lowBlock):
+        (JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExitDescriptor):
+        (JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExit):
+        (JSC::FTL::DFG::LowerDFGToLLVM::exitValueForNode):
+        * ftl/FTLOSRExit.cpp:
+        (JSC::FTL::OSRExitDescriptor::OSRExitDescriptor):
+        (JSC::FTL::OSRExit::OSRExit):
+        (JSC::FTL::OSRExit::codeLocationForRepatch):
+        (JSC::FTL::OSRExit::gatherRegistersToSpillForCallIfException):
+        (JSC::FTL::OSRExit::spillRegistersToSpillSlot):
+        (JSC::FTL::OSRExit::recoverRegistersFromSpillSlot):
+        * ftl/FTLOSRExit.h:
+        (JSC::FTL::OSRExit::considerAddingAsFrequentExitSite):
+        * ftl/FTLOSRExitCompilationInfo.h:
+        (JSC::FTL::OSRExitCompilationInfo::OSRExitCompilationInfo):
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileStub):
+        (JSC::FTL::compileFTLOSRExit):
+        * ftl/FTLState.cpp:
+        (JSC::FTL::State::State):
+        * ftl/FTLState.h:
+        * interpreter/Interpreter.cpp:
+        (JSC::findExceptionHandler):
+        * jit/RegisterSet.cpp:
+        (JSC::RegisterSet::specialRegisters):
+        (JSC::RegisterSet::volatileRegistersForJSCall):
+        (JSC::RegisterSet::stubUnavailableRegisters):
+        * jit/RegisterSet.h:
+        * tests/stress/ftl-try-catch-getter-ic-fail-to-call-operation-throw-error.js: Added.
+        (assert):
+        (let.oThrow.get f):
+        (let.o2.get f):
+        (foo):
+        (f):
+        * tests/stress/ftl-try-catch-getter-throw.js: Added.
+        (assert):
+        (random):
+        (foo):
+        (f):
+        (let.o2.get f):
+        * tests/stress/ftl-try-catch-oom-error-lazy-slow-path.js: Added.
+        (assert):
+        (a):
+        (b):
+        (c):
+        (d):
+        (e):
+        (f):
+        (g):
+        (foo):
+        (blah):
+        * tests/stress/ftl-try-catch-patchpoint-with-volatile-registers.js: Added.
+        (assert):
+        (o1.get f):
+        (a):
+        (b):
+        (c):
+        (d):
+        (e):
+        (f):
+        (g):
+        (o2.get f):
+        (foo):
+        * tests/stress/ftl-try-catch-setter-throw.js: Added.
+        (foo):
+        (assert):
+        (f):
+        (let.o2.set f):
+        * tests/stress/ftl-try-catch-tail-call-inilned-caller.js: Added.
+        (value):
+        (assert):
+        (validate):
+        (bar):
+        (baz):
+        (jaz):
+        * tests/stress/ftl-try-catch-varargs-call-throws.js: Added.
+        (foo):
+        (f):
+        * tests/stress/try-catch-stub-routine-replaced.js:
+        (hello):
+        (foo):
+
</ins><span class="cx"> 2015-11-09  Youenn Fablet  &lt;youenn.fablet@crf.canon.fr&gt;
</span><span class="cx"> 
</span><span class="cx">         Built-in generator should check that there are no duplicate in JS built-in internal functions
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -2953,7 +2953,7 @@
</span><span class="cx"> CallSiteIndex CodeBlock::newExceptionHandlingCallSiteIndex(CallSiteIndex originalCallSite)
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><del>-    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
</del><ins>+    RELEASE_ASSERT(JITCode::isOptimizingJIT(jitType()));
</ins><span class="cx">     RELEASE_ASSERT(canGetCodeOrigin(originalCallSite));
</span><span class="cx">     ASSERT(!!handlerForIndex(originalCallSite.bits()));
</span><span class="cx">     CodeOrigin originalOrigin = codeOrigin(originalCallSite);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -1532,6 +1532,31 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Graph::willCatchExceptionInMachineFrame(CodeOrigin codeOrigin, CodeOrigin&amp; opCatchOriginOut, HandlerInfo*&amp; catchHandlerOut)
+{
+    if (!m_hasExceptionHandlers)
+        return false;
+
+    unsigned bytecodeIndexToCheck = codeOrigin.bytecodeIndex;
+    while (1) {
+        InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
+        CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame);
+        if (HandlerInfo* handler = codeBlock-&gt;handlerForBytecodeOffset(bytecodeIndexToCheck)) {
+            opCatchOriginOut = CodeOrigin(handler-&gt;target, inlineCallFrame);
+            catchHandlerOut = handler;
+            return true;
+        }
+
+        if (!inlineCallFrame)
+            return false;
+
+        bytecodeIndexToCheck = inlineCallFrame-&gt;directCaller.bytecodeIndex;
+        codeOrigin = codeOrigin.inlineCallFrame-&gt;directCaller;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -828,6 +828,11 @@
</span><span class="cx">     void ensurePrePostNumbering();
</span><span class="cx">     void ensureNaturalLoops();
</span><span class="cx"> 
</span><ins>+    // This function only makes sense to call after bytecode parsing
+    // because it queries the m_hasExceptionHandlers boolean whose value
+    // is only fully determined after bytcode parsing.
+    bool willCatchExceptionInMachineFrame(CodeOrigin, CodeOrigin&amp; opCatchOriginOut, HandlerInfo*&amp; catchHandlerOut);
+
</ins><span class="cx">     VM&amp; m_vm;
</span><span class="cx">     Plan&amp; m_plan;
</span><span class="cx">     CodeBlock* m_codeBlock;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -561,28 +561,6 @@
</span><span class="cx">     m_exceptionHandlerOSRExitCallSites.append(ExceptionHandlingOSRExitInfo { exitInfo, *exceptionHandler, callSite });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool JITCompiler::willCatchExceptionInMachineFrame(CodeOrigin codeOrigin, CodeOrigin&amp; opCatchOriginOut, HandlerInfo*&amp; catchHandlerOut)
-{
-    unsigned bytecodeIndexToCheck = codeOrigin.bytecodeIndex;
-    while (1) {
-        InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
-        CodeBlock* codeBlock = m_graph.baselineCodeBlockFor(inlineCallFrame);
-        if (HandlerInfo* handler = codeBlock-&gt;handlerForBytecodeOffset(bytecodeIndexToCheck)) {
-            opCatchOriginOut = CodeOrigin(handler-&gt;target, inlineCallFrame);
-            catchHandlerOut = handler;
-            return true;
-        }
-
-        if (!inlineCallFrame)
-            return false;
-
-        bytecodeIndexToCheck = inlineCallFrame-&gt;directCaller.bytecodeIndex;
-        codeOrigin = codeOrigin.inlineCallFrame-&gt;directCaller;
-    }
-
-    RELEASE_ASSERT_NOT_REACHED();
-}
-
</del><span class="cx"> void JITCompiler::exceptionCheck()
</span><span class="cx"> {
</span><span class="cx">     // It's important that we use origin.forExit here. Consider if we hoist string
</span><span class="lines">@@ -607,7 +585,7 @@
</span><span class="cx">     // }
</span><span class="cx">     CodeOrigin opCatchOrigin;
</span><span class="cx">     HandlerInfo* exceptionHandler;
</span><del>-    bool willCatchException = willCatchExceptionInMachineFrame(m_speculative-&gt;m_currentNode-&gt;origin.forExit, opCatchOrigin, exceptionHandler); 
</del><ins>+    bool willCatchException = m_graph.willCatchExceptionInMachineFrame(m_speculative-&gt;m_currentNode-&gt;origin.forExit, opCatchOrigin, exceptionHandler); 
</ins><span class="cx">     if (willCatchException) {
</span><span class="cx">         unsigned streamIndex = m_speculative-&gt;m_outOfLineStreamIndex != UINT_MAX ? m_speculative-&gt;m_outOfLineStreamIndex : m_speculative-&gt;m_stream-&gt;size();
</span><span class="cx">         MacroAssembler::Jump hadException = emitNonPatchableExceptionCheck();
</span><span class="lines">@@ -621,7 +599,7 @@
</span><span class="cx"> {
</span><span class="cx">     CodeOrigin opCatchOrigin;
</span><span class="cx">     HandlerInfo* exceptionHandler;
</span><del>-    bool willCatchException = willCatchExceptionInMachineFrame(callSiteCodeOrigin, opCatchOrigin, exceptionHandler);
</del><ins>+    bool willCatchException = m_graph.willCatchExceptionInMachineFrame(callSiteCodeOrigin, opCatchOrigin, exceptionHandler);
</ins><span class="cx">     CallSiteIndex callSite = addCallSite(callSiteCodeOrigin);
</span><span class="cx">     if (willCatchException)
</span><span class="cx">         appendExceptionHandlingOSRExit(eventStreamIndex, opCatchOrigin, exceptionHandler, callSite);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCompilerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -279,7 +279,6 @@
</span><span class="cx">     void linkOSRExits();
</span><span class="cx">     void disassemble(LinkBuffer&amp;);
</span><span class="cx"> 
</span><del>-    bool willCatchExceptionInMachineFrame(CodeOrigin, CodeOrigin&amp; opCatchOriginOut, HandlerInfo*&amp; catchHandlerOut);
</del><span class="cx">     void appendExceptionHandlingOSRExit(unsigned eventStreamIndex, CodeOrigin, HandlerInfo* exceptionHandler, CallSiteIndex, MacroAssembler::JumpList jumpsToFail = MacroAssembler::JumpList());
</span><span class="cx"> 
</span><span class="cx">     // The dataflow graph currently being generated.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeOriginh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeOrigin.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeOrigin.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeOrigin.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -63,6 +63,18 @@
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    NodeOrigin withForExitAndExitOK(CodeOrigin forExit, bool exitOK) const
+    {
+        if (!isSet())
+            return NodeOrigin();
+        
+        NodeOrigin result = *this;
+        if (forExit.isSet())
+            result.forExit = forExit;
+        result.exitOK = exitOK;
+        return result;
+    }
+
</ins><span class="cx">     NodeOrigin withExitOK(bool value) const
</span><span class="cx">     {
</span><span class="cx">         NodeOrigin result = *this;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -43,9 +43,7 @@
</span><span class="cx">     , m_patchableCodeOffset(0)
</span><span class="cx">     , m_recoveryIndex(recoveryIndex)
</span><span class="cx">     , m_streamIndex(streamIndex)
</span><del>-    , m_exceptionHandlerCallSiteIndex(std::numeric_limits&lt;unsigned&gt;::max())
</del><span class="cx">     , m_willArriveAtOSRExitFromGenericUnwind(false)
</span><del>-    , m_isExceptionHandler(false)
</del><span class="cx"> {
</span><span class="cx">     bool canExit = jit-&gt;m_origin.exitOK;
</span><span class="cx">     if (!canExit &amp;&amp; jit-&gt;m_currentNode) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExith"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -100,11 +100,7 @@
</span><span class="cx">     void correctJump(LinkBuffer&amp;);
</span><span class="cx"> 
</span><span class="cx">     unsigned m_streamIndex;
</span><del>-    CallSiteIndex m_exceptionHandlerCallSiteIndex;
-
</del><span class="cx">     bool m_willArriveAtOSRExitFromGenericUnwind : 1;
</span><del>-    bool m_isExceptionHandler : 1;
-    
</del><span class="cx">     void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
</span><span class="cx">     {
</span><span class="cx">         OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromDFG);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExitBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -45,6 +45,8 @@
</span><span class="cx">         , m_count(0)
</span><span class="cx">         , m_codeOrigin(origin)
</span><span class="cx">         , m_codeOriginForExitProfile(originForProfile)
</span><ins>+        , m_exceptionHandlerCallSiteIndex(std::numeric_limits&lt;unsigned&gt;::max())
+        , m_isExceptionHandler(false)
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(m_codeOrigin.isSet());
</span><span class="cx">         ASSERT(m_codeOriginForExitProfile.isSet());
</span><span class="lines">@@ -55,7 +57,10 @@
</span><span class="cx">     
</span><span class="cx">     CodeOrigin m_codeOrigin;
</span><span class="cx">     CodeOrigin m_codeOriginForExitProfile;
</span><ins>+    CallSiteIndex m_exceptionHandlerCallSiteIndex;
</ins><span class="cx"> 
</span><ins>+    bool m_isExceptionHandler : 1;
+
</ins><span class="cx"> protected:
</span><span class="cx">     void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock, ExitingJITType jitType)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExitCompilerCommoncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -235,10 +235,10 @@
</span><span class="cx">     // Don't need to set the toplevel code origin if we only did inline tail calls
</span><span class="cx">     if (codeOrigin) {
</span><span class="cx"> #if USE(JSVALUE64)
</span><del>-    uint32_t locationBits = CallSiteIndex(codeOrigin-&gt;bytecodeIndex).bits();
</del><ins>+        uint32_t locationBits = CallSiteIndex(codeOrigin-&gt;bytecodeIndex).bits();
</ins><span class="cx"> #else
</span><del>-    Instruction* instruction = jit.baselineCodeBlock()-&gt;instructions().begin() + codeOrigin-&gt;bytecodeIndex;
-    uint32_t locationBits = CallSiteIndex(instruction).bits();
</del><ins>+        Instruction* instruction = jit.baselineCodeBlock()-&gt;instructions().begin() + codeOrigin-&gt;bytecodeIndex;
+        uint32_t locationBits = CallSiteIndex(instruction).bits();
</ins><span class="cx"> #endif
</span><span class="cx">         jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(JSStack::ArgumentCount)));
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -527,7 +527,7 @@
</span><span class="cx">                         dataLog(&quot;Creating Upsilon for &quot;, operand, &quot; at &quot;, pointerDump(block), &quot;-&gt;&quot;, pointerDump(successorBlock), &quot;\n&quot;);
</span><span class="cx">                     FlushFormat format = deferredAtHead[successorBlock].operand(operand);
</span><span class="cx">                     DFG_ASSERT(m_graph, nullptr, isConcrete(format));
</span><del>-                    UseKind useKind = useKindFor(format);
</del><ins>+                    UseKind useKind = uncheckedUseKindFor(format);
</ins><span class="cx">                     
</span><span class="cx">                     // We need to get a value for the stack slot. This phase doesn't really have a
</span><span class="cx">                     // good way of determining if a stack location got clobbered. It just knows if
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGTierUpCheckInjectionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -54,9 +54,6 @@
</span><span class="cx">         if (m_graph.m_profiledBlock-&gt;m_didFailFTLCompilation)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        if (m_graph.m_hasExceptionHandlers)
-            return false;
-        
</del><span class="cx"> #if ENABLE(FTL_JIT)
</span><span class="cx">         FTL::CapabilityLevel level = FTL::canCompile(m_graph);
</span><span class="cx">         if (level == FTL::CannotCompile)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -466,7 +466,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename CallType&gt;
</span><del>-void adjustCallICsForStackmaps(Vector&lt;CallType&gt;&amp; calls, StackMaps::RecordMap&amp; recordMap)
</del><ins>+void adjustCallICsForStackmaps(Vector&lt;CallType&gt;&amp; calls, StackMaps::RecordMap&amp; recordMap, std::function&lt;CallSiteIndex (uint32_t recordIndex, CodeOrigin origin)&gt; generateCallSiteIndexFunction, std::function&lt;OSRExit* (uint32_t recordIndex)&gt; getCorrespondingOSRExit)
</ins><span class="cx"> {
</span><span class="cx">     // Handling JS calls is weird: we need to ensure that we sort them by the PC in LLVM
</span><span class="cx">     // generated code. That implies first pruning the ones that LLVM didn't generate.
</span><span class="lines">@@ -484,6 +484,9 @@
</span><span class="cx">         for (unsigned j = 0; j &lt; iter-&gt;value.size(); ++j) {
</span><span class="cx">             CallType copy = call;
</span><span class="cx">             copy.m_instructionOffset = iter-&gt;value[j].record.instructionOffset;
</span><ins>+            copy.setCallSiteIndex(generateCallSiteIndexFunction(iter-&gt;value[j].index, copy.callSiteDescriptionOrigin()));
+            copy.setCorrespondingGenericUnwindOSRExit(getCorrespondingOSRExit(iter-&gt;value[j].index));
+
</ins><span class="cx">             calls.append(copy);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -498,9 +501,34 @@
</span><span class="cx">     Graph&amp; graph = state.graph;
</span><span class="cx">     VM&amp; vm = graph.m_vm;
</span><span class="cx">     StackMaps&amp; stackmaps = jitCode-&gt;stackmaps;
</span><ins>+
+    // We fill this when generating OSR exits that will be executed via genericUnwind()
+    // or lazy slow path exception checks.
+    // That way, when we assign a CallSiteIndex to the Call/GetById/PutById/LazySlowPath, we assign
+    // it the proper CallSiteIndex that corresponds to the OSRExit exception handler.
+    HashMap&lt;uint32_t, size_t, WTF::IntHash&lt;uint32_t&gt;, WTF::UnsignedWithZeroKeyHashTraits&lt;uint32_t&gt;&gt; recordIndexToGenericUnwindOrLazySlowPathOSRExit;
+    auto generateOrGetAlreadyGeneratedCallSiteIndex = [&amp;] (uint32_t recordIndex, CodeOrigin origin) -&gt; CallSiteIndex {
+        auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(recordIndex);
+        if (findResult == recordIndexToGenericUnwindOrLazySlowPathOSRExit.end())
+            return state.jitCode-&gt;common.addUniqueCallSiteIndex(origin);
+        size_t osrExitIndex = findResult-&gt;value;
+        return state.jitCode-&gt;osrExit[osrExitIndex].m_exceptionHandlerCallSiteIndex;
+    };
+    auto jsCallOSRExitForRecordIndex = [&amp;] (uint32_t recordIndex) -&gt; OSRExit* {
+        auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(recordIndex);
+        if (findResult == recordIndexToGenericUnwindOrLazySlowPathOSRExit.end())
+            return nullptr;
+
+        size_t osrExitIndex = findResult-&gt;value;
+        OSRExit&amp; exit = state.jitCode-&gt;osrExit[osrExitIndex];
+        if (!exit.m_descriptor.m_isExceptionFromJSCall)
+            return nullptr;
+        return &amp;exit;
+    };
</ins><span class="cx">     
</span><span class="cx">     int localsOffset = offsetOfStackRegion(recordMap, state.capturedStackmapID) + graph.m_nextMachineLocal;
</span><span class="cx">     int varargsSpillSlotsOffset = offsetOfStackRegion(recordMap, state.varargsSpillSlotsStackmapID);
</span><ins>+    int jsCallThatMightThrowSpillOffset = offsetOfStackRegion(recordMap, state.exceptionHandlingSpillSlotStackmapID);
</ins><span class="cx">     
</span><span class="cx">     for (unsigned i = graph.m_inlineVariableData.size(); i--;) {
</span><span class="cx">         InlineCallFrame* inlineCallFrame = graph.m_inlineVariableData[i].inlineCallFrame;
</span><span class="lines">@@ -569,14 +597,35 @@
</span><span class="cx">             materialization-&gt;accountForLocalsOffset(localsOffset);
</span><span class="cx"> 
</span><span class="cx">         for (unsigned j = 0; j &lt; iter-&gt;value.size(); j++) {
</span><del>-            uint32_t stackmapRecordIndex = iter-&gt;value[j].index;
-            OSRExit exit(exitDescriptor, stackmapRecordIndex);
-            state.jitCode-&gt;osrExit.append(exit);
-            state.finalizer-&gt;osrExit.append(OSRExitCompilationInfo());
</del><ins>+            {
+                uint32_t stackmapRecordIndex = iter-&gt;value[j].index;
+                OSRExit exit(exitDescriptor, stackmapRecordIndex);
+                state.jitCode-&gt;osrExit.append(exit);
+                state.finalizer-&gt;osrExit.append(OSRExitCompilationInfo());
+            }
+
+            OSRExit&amp; exit = state.jitCode-&gt;osrExit.last();
+            if (exitDescriptor.m_willArriveAtOSRExitFromGenericUnwind || exitDescriptor.m_isExceptionFromLazySlowPath) {
+                StackMaps::Record&amp; record = iter-&gt;value[j].record;
+                RELEASE_ASSERT(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader.isSet());
+                CallSiteIndex callSiteIndex = state.jitCode-&gt;common.addUniqueCallSiteIndex(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader);
+                exit.m_exceptionHandlerCallSiteIndex = callSiteIndex;
+                recordIndexToGenericUnwindOrLazySlowPathOSRExit.add(iter-&gt;value[j].index, state.jitCode-&gt;osrExit.size() - 1);
+
+                if (exitDescriptor.m_isExceptionFromJSCall)
+                    exit.gatherRegistersToSpillForCallIfException(stackmaps, record);
+                if (exitDescriptor.m_isExceptionFromGetById) {
+                    GPRReg result = record.locations[0].directGPR();
+                    GPRReg base = record.locations[1].directGPR();
+                    // This has an interesting story, see comment below describing it.
+                    if (result == base)
+                        exit.registersToPreserveForCallThatMightThrow.set(base);
+                }
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     ExitThunkGenerator exitThunkGenerator(state);
</span><del>-    exitThunkGenerator.emitThunks();
</del><ins>+    exitThunkGenerator.emitThunks(jsCallThatMightThrowSpillOffset);
</ins><span class="cx">     if (exitThunkGenerator.didThings()) {
</span><span class="cx">         RELEASE_ASSERT(state.finalizer-&gt;osrExit.size());
</span><span class="cx">         
</span><span class="lines">@@ -589,16 +638,26 @@
</span><span class="cx">         
</span><span class="cx">         RELEASE_ASSERT(state.finalizer-&gt;osrExit.size() == state.jitCode-&gt;osrExit.size());
</span><span class="cx">         
</span><ins>+        codeBlock-&gt;clearExceptionHandlers();
+
</ins><span class="cx">         for (unsigned i = 0; i &lt; state.jitCode-&gt;osrExit.size(); ++i) {
</span><span class="cx">             OSRExitCompilationInfo&amp; info = state.finalizer-&gt;osrExit[i];
</span><del>-            OSRExit&amp; exit = jitCode-&gt;osrExit[i];
</del><ins>+            OSRExit&amp; exit = state.jitCode-&gt;osrExit[i];
</ins><span class="cx">             
</span><span class="cx">             if (verboseCompilationEnabled())
</span><span class="cx">                 dataLog(&quot;Handling OSR stackmap #&quot;, exit.m_descriptor.m_stackmapID, &quot; for &quot;, exit.m_codeOrigin, &quot;\n&quot;);
</span><span class="cx"> 
</span><span class="cx">             info.m_thunkAddress = linkBuffer-&gt;locationOf(info.m_thunkLabel);
</span><span class="cx">             exit.m_patchableCodeOffset = linkBuffer-&gt;offsetOf(info.m_thunkJump);
</span><del>-            
</del><ins>+
+            if (exit.m_descriptor.m_willArriveAtOSRExitFromGenericUnwind) {
+                HandlerInfo newHandler = exit.m_descriptor.m_baselineExceptionHandler;
+                newHandler.start = exit.m_exceptionHandlerCallSiteIndex.bits();
+                newHandler.end = exit.m_exceptionHandlerCallSiteIndex.bits() + 1;
+                newHandler.nativeCode = info.m_thunkAddress;
+                codeBlock-&gt;appendExceptionHandler(newHandler);
+            }
+
</ins><span class="cx">             if (verboseCompilationEnabled()) {
</span><span class="cx">                 DumpContext context;
</span><span class="cx">                 dataLog(&quot;    Exit values: &quot;, inContext(exit.m_descriptor.m_values, &amp;context), &quot;\n&quot;);
</span><span class="lines">@@ -621,6 +680,21 @@
</span><span class="cx">         CCallHelpers slowPathJIT(&amp;vm, codeBlock);
</span><span class="cx">         
</span><span class="cx">         CCallHelpers::JumpList exceptionTarget;
</span><ins>+
+        Vector&lt;std::pair&lt;CCallHelpers::JumpList, CodeLocationLabel&gt;&gt; exceptionJumpsToLink;
+        auto addNewExceptionJumpIfNecessary = [&amp;] (uint32_t recordIndex) {
+            auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(recordIndex);
+            if (findResult == recordIndexToGenericUnwindOrLazySlowPathOSRExit.end())
+                return false;
+
+            size_t osrExitIndex = findResult-&gt;value;
+            RELEASE_ASSERT(state.jitCode-&gt;osrExit[osrExitIndex].m_descriptor.m_willArriveAtOSRExitFromGenericUnwind);
+            OSRExitCompilationInfo&amp; info = state.finalizer-&gt;osrExit[osrExitIndex];
+            RELEASE_ASSERT(info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance.isSet());
+            exceptionJumpsToLink.append(
+                std::make_pair(CCallHelpers::JumpList(), state.finalizer-&gt;exitThunksLinkBuffer-&gt;locationOf(info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance)));
+            return true;
+        };
</ins><span class="cx">         
</span><span class="cx">         for (unsigned i = state.getByIds.size(); i--;) {
</span><span class="cx">             GetByIdDescriptor&amp; getById = state.getByIds[i];
</span><span class="lines">@@ -644,13 +718,31 @@
</span><span class="cx">                 GPRReg base = record.locations[1].directGPR();
</span><span class="cx">                 
</span><span class="cx">                 JITGetByIdGenerator gen(
</span><del>-                    codeBlock, codeOrigin, state.jitCode-&gt;common.addUniqueCallSiteIndex(codeOrigin), usedRegisters, JSValueRegs(base),
</del><ins>+                    codeBlock, codeOrigin, generateOrGetAlreadyGeneratedCallSiteIndex(iter-&gt;value[i].index, codeOrigin), usedRegisters, JSValueRegs(base),
</ins><span class="cx">                     JSValueRegs(result));
</span><span class="cx">                 
</span><ins>+                bool addedUniqueExceptionJump = addNewExceptionJumpIfNecessary(iter-&gt;value[i].index);
</ins><span class="cx">                 MacroAssembler::Label begin = slowPathJIT.label();
</span><del>-
</del><ins>+                if (result == base) {
+                    // This situation has a really interesting story. We may have a GetById inside
+                    // a try block where LLVM assigns the result and the base to the same register.
+                    // The inline cache may miss and we may end up at this slow path callOperation. 
+                    // Then, suppose the base and the result are both the same register, so the return
+                    // value of the C call gets stored into the original base register. If the operationGetByIdOptimize
+                    // throws, it will return &quot;undefined&quot; and we will be stuck with &quot;undefined&quot; in the base
+                    // register that we would like to do value recovery on. We combat this situation from ever
+                    // taking place by ensuring we spill the original base value and then recover it from
+                    // the spill slot as the first step in OSR exit.
+                    auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(iter-&gt;value[i].index);
+                    if (findResult != recordIndexToGenericUnwindOrLazySlowPathOSRExit.end()) {
+                        size_t osrExitIndex = findResult-&gt;value;
+                        OSRExit&amp; exit = state.jitCode-&gt;osrExit[osrExitIndex];
+                        RELEASE_ASSERT(exit.m_descriptor.m_isExceptionFromGetById);
+                        exit.spillRegistersToSpillSlot(slowPathJIT, jsCallThatMightThrowSpillOffset);
+                    }
+                }
</ins><span class="cx">                 MacroAssembler::Call call = callOperation(
</span><del>-                    state, usedRegisters, slowPathJIT, codeOrigin, &amp;exceptionTarget,
</del><ins>+                    state, usedRegisters, slowPathJIT, codeOrigin, addedUniqueExceptionJump ? &amp;exceptionJumpsToLink.last().first : &amp;exceptionTarget,
</ins><span class="cx">                     operationGetByIdOptimize, result, CCallHelpers::TrustedImmPtr(gen.stubInfo()),
</span><span class="cx">                     base, CCallHelpers::TrustedImmPtr(getById.uid())).call();
</span><span class="cx"> 
</span><span class="lines">@@ -683,13 +775,15 @@
</span><span class="cx">                 GPRReg value = record.locations[1].directGPR();
</span><span class="cx">                 
</span><span class="cx">                 JITPutByIdGenerator gen(
</span><del>-                    codeBlock, codeOrigin, state.jitCode-&gt;common.addUniqueCallSiteIndex(codeOrigin), usedRegisters, JSValueRegs(base),
</del><ins>+                    codeBlock, codeOrigin, generateOrGetAlreadyGeneratedCallSiteIndex(iter-&gt;value[i].index, codeOrigin), usedRegisters, JSValueRegs(base),
</ins><span class="cx">                     JSValueRegs(value), GPRInfo::patchpointScratchRegister, putById.ecmaMode(), putById.putKind());
</span><span class="cx">                 
</span><ins>+                bool addedUniqueExceptionJump = addNewExceptionJumpIfNecessary(iter-&gt;value[i].index);
+
</ins><span class="cx">                 MacroAssembler::Label begin = slowPathJIT.label();
</span><del>-                
</del><ins>+
</ins><span class="cx">                 MacroAssembler::Call call = callOperation(
</span><del>-                    state, usedRegisters, slowPathJIT, codeOrigin, &amp;exceptionTarget,
</del><ins>+                    state, usedRegisters, slowPathJIT, codeOrigin, addedUniqueExceptionJump ? &amp;exceptionJumpsToLink.last().first : &amp;exceptionTarget,
</ins><span class="cx">                     gen.slowPathFunction(), InvalidGPRReg,
</span><span class="cx">                     CCallHelpers::TrustedImmPtr(gen.stubInfo()), value, base,
</span><span class="cx">                     CCallHelpers::TrustedImmPtr(putById.uid())).call();
</span><span class="lines">@@ -789,11 +883,18 @@
</span><span class="cx">                 char* startOfIC =
</span><span class="cx">                     bitwise_cast&lt;char*&gt;(generatedFunction) + record.instructionOffset;
</span><span class="cx">                 CodeLocationLabel patchpoint((MacroAssemblerCodePtr(startOfIC)));
</span><del>-                CodeLocationLabel exceptionTarget =
-                    state.finalizer-&gt;handleExceptionsLinkBuffer-&gt;entrypoint();
</del><ins>+                CodeLocationLabel exceptionTarget;
+                auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(iter-&gt;value[i].index);
+                if (findResult != recordIndexToGenericUnwindOrLazySlowPathOSRExit.end()) {
+                    size_t osrExitIndex = findResult-&gt;value;
+                    OSRExitCompilationInfo&amp; info = state.finalizer-&gt;osrExit[osrExitIndex];
+                    RELEASE_ASSERT(state.jitCode-&gt;osrExit[osrExitIndex].m_descriptor.m_isExceptionFromLazySlowPath);
+                    exceptionTarget = state.finalizer-&gt;exitThunksLinkBuffer-&gt;locationOf(info.m_thunkLabel);
+                } else
+                    exceptionTarget = state.finalizer-&gt;handleExceptionsLinkBuffer-&gt;entrypoint();
</ins><span class="cx"> 
</span><span class="cx">                 std::unique_ptr&lt;LazySlowPath&gt; lazySlowPath = std::make_unique&lt;LazySlowPath&gt;(
</span><del>-                    patchpoint, exceptionTarget, usedRegisters, state.jitCode-&gt;common.addUniqueCallSiteIndex(codeOrigin),
</del><ins>+                    patchpoint, exceptionTarget, usedRegisters, generateOrGetAlreadyGeneratedCallSiteIndex(iter-&gt;value[i].index, codeOrigin),
</ins><span class="cx">                     descriptor.m_linker-&gt;run(locations));
</span><span class="cx"> 
</span><span class="cx">                 CCallHelpers::Label begin = slowPathJIT.label();
</span><span class="lines">@@ -847,15 +948,17 @@
</span><span class="cx">                     state.finalizer-&gt;sideCodeLinkBuffer-&gt;locationOf(std::get&lt;1&gt;(tuple)));
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+        for (auto&amp; pair : exceptionJumpsToLink)
+            state.finalizer-&gt;sideCodeLinkBuffer-&gt;link(pair.first, pair.second);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    adjustCallICsForStackmaps(state.jsCalls, recordMap);
</del><ins>+    adjustCallICsForStackmaps(state.jsCalls, recordMap, generateOrGetAlreadyGeneratedCallSiteIndex, jsCallOSRExitForRecordIndex);
</ins><span class="cx">     
</span><span class="cx">     for (unsigned i = state.jsCalls.size(); i--;) {
</span><span class="cx">         JSCall&amp; call = state.jsCalls[i];
</span><span class="cx"> 
</span><span class="cx">         CCallHelpers fastPathJIT(&amp;vm, codeBlock);
</span><del>-        call.emit(fastPathJIT, state);
</del><ins>+        call.emit(fastPathJIT, state, jsCallThatMightThrowSpillOffset);
</ins><span class="cx"> 
</span><span class="cx">         char* startOfIC = bitwise_cast&lt;char*&gt;(generatedFunction) + call.m_instructionOffset;
</span><span class="cx"> 
</span><span class="lines">@@ -864,13 +967,13 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    adjustCallICsForStackmaps(state.jsCallVarargses, recordMap);
</del><ins>+    adjustCallICsForStackmaps(state.jsCallVarargses, recordMap, generateOrGetAlreadyGeneratedCallSiteIndex, jsCallOSRExitForRecordIndex);
</ins><span class="cx">     
</span><span class="cx">     for (unsigned i = state.jsCallVarargses.size(); i--;) {
</span><span class="cx">         JSCallVarargs&amp; call = state.jsCallVarargses[i];
</span><span class="cx">         
</span><span class="cx">         CCallHelpers fastPathJIT(&amp;vm, codeBlock);
</span><del>-        call.emit(fastPathJIT, state, varargsSpillSlotsOffset);
</del><ins>+        call.emit(fastPathJIT, state, varargsSpillSlotsOffset, jsCallThatMightThrowSpillOffset);
</ins><span class="cx"> 
</span><span class="cx">         char* startOfIC = bitwise_cast&lt;char*&gt;(generatedFunction) + call.m_instructionOffset;
</span><span class="cx">         size_t sizeOfIC = sizeOfICFor(call.node());
</span><span class="lines">@@ -880,7 +983,9 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    adjustCallICsForStackmaps(state.jsTailCalls, recordMap);
</del><ins>+    // FIXME: We shouldn't generate CallSite indices for tail calls.
+    // https://bugs.webkit.org/show_bug.cgi?id=151079
+    adjustCallICsForStackmaps(state.jsTailCalls, recordMap, generateOrGetAlreadyGeneratedCallSiteIndex, jsCallOSRExitForRecordIndex);
</ins><span class="cx"> 
</span><span class="cx">     for (unsigned i = state.jsTailCalls.size(); i--;) {
</span><span class="cx">         JSTailCall&amp; call = state.jsTailCalls[i];
</span><span class="lines">@@ -929,8 +1034,10 @@
</span><span class="cx">     for (unsigned exitIndex = 0; exitIndex &lt; jitCode-&gt;osrExit.size(); ++exitIndex) {
</span><span class="cx">         OSRExitCompilationInfo&amp; info = state.finalizer-&gt;osrExit[exitIndex];
</span><span class="cx">         OSRExit&amp; exit = jitCode-&gt;osrExit[exitIndex];
</span><del>-        
</del><span class="cx">         Vector&lt;const void*&gt; codeAddresses;
</span><ins>+
+        if (exit.m_descriptor.m_willArriveAtOSRExitFromGenericUnwind || exit.m_descriptor.m_isExceptionFromLazySlowPath) // This is reached by a jump from genericUnwind or a jump from a lazy slow path.
+            continue;
</ins><span class="cx">         
</span><span class="cx">         StackMaps::Record&amp; record = jitCode-&gt;stackmaps.records[exit.m_stackmapRecordIndex];
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExitArgumenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExitArgument.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExitArgument.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLExitArgument.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">     {
</span><span class="cx">         return ExitArgument(format, argument());
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     ExitArgumentRepresentation representation() const { return m_representation; }
</span><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExitThunkGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -46,21 +46,41 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ExitThunkGenerator::emitThunk(unsigned index)
</del><ins>+void ExitThunkGenerator::emitThunk(unsigned index, int32_t osrExitFromGenericUnwindStackSpillSlot)
</ins><span class="cx"> {
</span><span class="cx">     OSRExitCompilationInfo&amp; info = m_state.finalizer-&gt;osrExit[index];
</span><ins>+    OSRExit&amp; exit = m_state.jitCode-&gt;osrExit[index];
</ins><span class="cx">     
</span><span class="cx">     info.m_thunkLabel = label();
</span><ins>+
+    if (exit.m_descriptor.m_willArriveAtOSRExitFromGenericUnwind) {
+        restoreCalleeSavesFromVMCalleeSavesBuffer();
+        loadPtr(vm()-&gt;addressOfCallFrameForCatch(), framePointerRegister);
+        addPtr(TrustedImm32(- static_cast&lt;int64_t&gt;(m_state.jitCode-&gt;stackmaps.stackSizeForLocals())), 
+            framePointerRegister, stackPointerRegister);
+
+        if (exit.m_descriptor.m_isExceptionFromJSCall)
+            exit.recoverRegistersFromSpillSlot(*this, osrExitFromGenericUnwindStackSpillSlot);
+
+        Jump skipGetAndPutByIdSlowPathEntrance = jump();
+
+        info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance = label();
+        if (exit.m_descriptor.m_isExceptionFromGetById)
+            exit.recoverRegistersFromSpillSlot(*this, osrExitFromGenericUnwindStackSpillSlot);
+        
+        skipGetAndPutByIdSlowPathEntrance.link(this);
+    }
+
</ins><span class="cx">     pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32(index));
</span><span class="cx">     info.m_thunkJump = patchableJump();
</span><span class="cx">     
</span><span class="cx">     m_didThings = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ExitThunkGenerator::emitThunks()
</del><ins>+void ExitThunkGenerator::emitThunks(int32_t osrExitFromGenericUnwindStackSpillSlot)
</ins><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; i &lt; m_state.finalizer-&gt;osrExit.size(); ++i)
</span><del>-        emitThunk(i);
</del><ins>+        emitThunk(i, osrExitFromGenericUnwindStackSpillSlot);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExitThunkGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -40,8 +40,8 @@
</span><span class="cx">     ExitThunkGenerator(State&amp; state);
</span><span class="cx">     ~ExitThunkGenerator();
</span><span class="cx">     
</span><del>-    void emitThunk(unsigned index);
-    void emitThunks();
</del><ins>+    void emitThunk(unsigned index, int32_t osrExitFromGenericUnwindStackSpillSlot);
+    void emitThunks(int32_t osrExitFromGenericUnwindStackSpillSlot);
</ins><span class="cx">     
</span><span class="cx">     bool didThings() const { return m_didThings; }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExitValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExitValue.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExitValue.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLExitValue.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -157,6 +157,7 @@
</span><span class="cx">     bool isArgument() const { return kind() == ExitValueArgument; }
</span><span class="cx">     bool isRecovery() const { return kind() == ExitValueRecovery; }
</span><span class="cx">     bool isObjectMaterialization() const { return kind() == ExitValueMaterializeNewObject; }
</span><ins>+    bool hasIndexInStackmapLocations() const { return isArgument() || isRecovery(); }
</ins><span class="cx">     
</span><span class="cx">     ExitArgument exitArgument() const
</span><span class="cx">     {
</span><span class="lines">@@ -175,6 +176,18 @@
</span><span class="cx">         ASSERT(isRecovery());
</span><span class="cx">         return u.recovery.rightArgument;
</span><span class="cx">     }
</span><ins>+
+    void adjustStackmapLocationsIndexByOffset(unsigned offset)
+    {
+        ASSERT(hasIndexInStackmapLocations());
+        if (isArgument())
+            u.argument.argument += offset;
+        else {
+            ASSERT(isRecovery());
+            u.recovery.rightArgument += offset;
+            u.recovery.leftArgument += offset;
+        }
+    }
</ins><span class="cx">     
</span><span class="cx">     DataFormat recoveryFormat() const
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJITCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -144,10 +144,14 @@
</span><span class="cx">         exit.m_descriptor.validateReferences(trackedReferences);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterSet JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex)
</del><ins>+RegisterSet JITCode::liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex callSiteIndex)
</ins><span class="cx"> {
</span><del>-    // FIXME: implement this when FTL implements try/catch.
-    // https://bugs.webkit.org/show_bug.cgi?id=149409
</del><ins>+    for (OSRExit&amp; exit : osrExit) {
+        if (exit.m_exceptionHandlerCallSiteIndex.bits() == callSiteIndex.bits()) {
+            RELEASE_ASSERT(exit.m_isExceptionHandler);
+            return stackmaps.records[exit.m_stackmapRecordIndex].usedRegisterSet();
+        }
+    }
</ins><span class="cx">     return RegisterSet();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -50,9 +50,9 @@
</span><span class="cx">     ASSERT(node-&gt;op() == Call || node-&gt;op() == Construct || node-&gt;op() == TailCallInlinedCaller);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSCall::emit(CCallHelpers&amp; jit, State&amp; state)
</del><ins>+void JSCall::emit(CCallHelpers&amp; jit, State&amp; state, int32_t osrExitFromGenericUnwindSpillSlots)
</ins><span class="cx"> {
</span><del>-    JSCallBase::emit(jit, state);
</del><ins>+    JSCallBase::emit(jit, state, osrExitFromGenericUnwindSpillSlots);
</ins><span class="cx"> 
</span><span class="cx">     jit.addPtr(CCallHelpers::TrustedImm32(- static_cast&lt;int64_t&gt;(state.jitCode-&gt;stackmaps.stackSizeForLocals())), CCallHelpers::framePointerRegister, CCallHelpers::stackPointerRegister);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCall.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCall.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCall.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -43,7 +43,7 @@
</span><span class="cx">     JSCall();
</span><span class="cx">     JSCall(unsigned stackmapID, DFG::Node*, CodeOrigin callSiteDescriptionOrigin);
</span><span class="cx"> 
</span><del>-    void emit(CCallHelpers&amp;, State&amp;);
</del><ins>+    void emit(CCallHelpers&amp;, State&amp;, int32_t osrExitFromGenericUnwindSpillSlots);
</ins><span class="cx">     
</span><span class="cx">     unsigned stackmapID() const { return m_stackmapID; }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> JSCallBase::JSCallBase()
</span><span class="cx">     : m_type(CallLinkInfo::None)
</span><span class="cx">     , m_callLinkInfo(nullptr)
</span><ins>+    , m_correspondingGenericUnwindOSRExit(nullptr)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -50,11 +51,15 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSCallBase::emit(CCallHelpers&amp; jit, State&amp; state)
</del><ins>+void JSCallBase::emit(CCallHelpers&amp; jit, State&amp; /*state*/, int32_t osrExitFromGenericUnwindStackSpillSlot)
</ins><span class="cx"> {
</span><del>-    CallSiteIndex callSiteIndex = state.jitCode-&gt;common.addUniqueCallSiteIndex(m_callSiteDescriptionOrigin);
-    jit.store32(CCallHelpers::TrustedImm32(callSiteIndex.bits()), CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(JSStack::ArgumentCount)));
</del><ins>+    RELEASE_ASSERT(!!m_callSiteIndex);
+    
+    if (m_correspondingGenericUnwindOSRExit)
+        m_correspondingGenericUnwindOSRExit-&gt;spillRegistersToSpillSlot(jit, osrExitFromGenericUnwindStackSpillSlot);
</ins><span class="cx"> 
</span><ins>+    jit.store32(CCallHelpers::TrustedImm32(m_callSiteIndex.bits()), CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(JSStack::ArgumentCount)));
+
</ins><span class="cx">     m_callLinkInfo = jit.codeBlock()-&gt;addCallLinkInfo();
</span><span class="cx">     
</span><span class="cx">     if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;CCallHelpers.h&quot;
</span><span class="cx"> #include &quot;CallLinkInfo.h&quot;
</span><span class="cx"> #include &quot;CodeOrigin.h&quot;
</span><ins>+#include &quot;FTLOSRExit.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -49,17 +50,25 @@
</span><span class="cx">     JSCallBase();
</span><span class="cx">     JSCallBase(CallLinkInfo::CallType, CodeOrigin semantic, CodeOrigin callSiteDescription);
</span><span class="cx">     
</span><del>-    void emit(CCallHelpers&amp;, State&amp;);
</del><ins>+    void emit(CCallHelpers&amp;, State&amp;, int32_t osrExitFromGenericUnwindSpillSlots);
</ins><span class="cx">     void link(VM&amp;, LinkBuffer&amp;);
</span><ins>+
+    void setCallSiteIndex(CallSiteIndex callSiteIndex) { m_callSiteIndex = callSiteIndex; }
+    CodeOrigin callSiteDescriptionOrigin() const { return m_callSiteDescriptionOrigin; }
+
+    void setCorrespondingGenericUnwindOSRExit(OSRExit* exit) { m_correspondingGenericUnwindOSRExit = exit; }
</ins><span class="cx">     
</span><span class="cx"> protected:
</span><span class="cx">     CallLinkInfo::CallType m_type;
</span><span class="cx">     CodeOrigin m_semanticeOrigin;
</span><span class="cx">     CodeOrigin m_callSiteDescriptionOrigin; // These two code origins may be different with tail calls under some circumstances of inlining. See relevant comment in LowerDFGToLLVM.
</span><ins>+    CallSiteIndex m_callSiteIndex;
</ins><span class="cx">     CCallHelpers::DataLabelPtr m_targetToCheck;
</span><span class="cx">     CCallHelpers::Call m_fastCall;
</span><span class="cx">     CCallHelpers::Call m_slowCall;
</span><span class="cx">     CallLinkInfo* m_callLinkInfo;
</span><ins>+public:
+    OSRExit* m_correspondingGenericUnwindOSRExit;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallVarargscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -69,7 +69,7 @@
</span><span class="cx">     return 4;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSCallVarargs::emit(CCallHelpers&amp; jit, State&amp; state, int32_t spillSlotsOffset)
</del><ins>+void JSCallVarargs::emit(CCallHelpers&amp; jit, State&amp; state, int32_t spillSlotsOffset, int32_t osrExitFromGenericUnwindSpillSlots)
</ins><span class="cx"> {
</span><span class="cx">     // We are passed three pieces of information:
</span><span class="cx">     // - The callee.
</span><span class="lines">@@ -205,7 +205,8 @@
</span><span class="cx">     // stack frame to already be set up, which it is.
</span><span class="cx">     jit.store64(GPRInfo::regT0, CCallHelpers::calleeFrameSlot(JSStack::Callee));
</span><span class="cx"> 
</span><del>-    m_callBase.emit(jit, state);
</del><ins>+    m_callBase.emit(jit, state, osrExitFromGenericUnwindSpillSlots);
+
</ins><span class="cx">     
</span><span class="cx">     // Undo the damage we've done.
</span><span class="cx">     if (isARM64()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallVarargsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx">     
</span><span class="cx">     static unsigned numSpillSlotsNeeded();
</span><span class="cx">     
</span><del>-    void emit(CCallHelpers&amp;, State&amp;, int32_t spillSlotsOffset);
</del><ins>+    void emit(CCallHelpers&amp;, State&amp;, int32_t spillSlotsOffset, int32_t osrExitFromGenericUnwindSpillSlots);
</ins><span class="cx">     void link(VM&amp;, LinkBuffer&amp;, CodeLocationLabel exceptionHandler);
</span><span class="cx">     
</span><span class="cx">     unsigned stackmapID() const { return m_stackmapID; }
</span><span class="lines">@@ -59,6 +59,10 @@
</span><span class="cx">         return m_instructionOffset &lt; other.m_instructionOffset;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void setCallSiteIndex(CallSiteIndex callSiteIndex) { m_callBase.setCallSiteIndex(callSiteIndex); }
+    CodeOrigin callSiteDescriptionOrigin() const { return m_callBase.callSiteDescriptionOrigin(); }
+    void setCorrespondingGenericUnwindOSRExit(OSRExit* exit) { m_callBase.setCorrespondingGenericUnwindOSRExit(exit); }
+    
</ins><span class="cx"> private:
</span><span class="cx">     unsigned m_stackmapID;
</span><span class="cx">     DFG::Node* m_node;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -170,8 +170,9 @@
</span><span class="cx">             m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID),
</span><span class="cx">             m_out.int32Zero, capturedAlloca);
</span><span class="cx">         
</span><del>-        // If we have any CallVarargs then we nee to have a spill slot for it.
</del><ins>+        // If we have any CallVarargs then we need to have a spill slot for it.
</ins><span class="cx">         bool hasVarargs = false;
</span><ins>+        size_t maxNumberOfCatchSpills = 0;
</ins><span class="cx">         for (BasicBlock* block : preOrder) {
</span><span class="cx">             for (Node* node : *block) {
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="lines">@@ -188,6 +189,43 @@
</span><span class="cx">                 default:
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><ins>+
+                if (m_graph.m_hasExceptionHandlers) {
+                    switch (node-&gt;op()) {
+                    case Call:
+                    case CallVarargs:
+                    case CallForwardVarargs:
+                    case Construct:
+                    case ConstructVarargs:
+                    case ConstructForwardVarargs:
+                    case TailCallInlinedCaller:
+                    case TailCallVarargsInlinedCaller:
+                    case TailCallForwardVarargsInlinedCaller: {
+                        CodeOrigin opCatchOrigin;
+                        HandlerInfo* exceptionHandler;
+                        bool willCatchException = m_graph.willCatchExceptionInMachineFrame(node-&gt;origin.forExit, opCatchOrigin, exceptionHandler);
+                        if (willCatchException)
+                            maxNumberOfCatchSpills = std::max(maxNumberOfCatchSpills, m_graph.localsLiveInBytecode(opCatchOrigin).bitCount());
+                        break;
+                    }
+                    case GetById:
+                    case GetByIdFlush: {
+                        // We may have to flush one thing for GetByIds when the base and result
+                        // are assigned the same register. For a more comprehensive overview, look
+                        // at the comment in FTLCompile.cpp
+                        CodeOrigin opCatchOrigin;
+                        HandlerInfo* exceptionHandler;
+                        bool willCatchException = m_graph.willCatchExceptionInMachineFrame(node-&gt;origin.forExit, opCatchOrigin, exceptionHandler);
+                        if (willCatchException) {
+                            static const size_t numberOfGetByIdSpills = 1;
+                            maxNumberOfCatchSpills = std::max(maxNumberOfCatchSpills, numberOfGetByIdSpills);
+                        }
+                        break;
+                    }
+                    default:
+                        break;
+                    }
+                }
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         if (hasVarargs) {
</span><span class="lines">@@ -198,6 +236,18 @@
</span><span class="cx">                 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.varargsSpillSlotsStackmapID),
</span><span class="cx">                 m_out.int32Zero, varargsSpillSlots);
</span><span class="cx">         }
</span><ins>+
+        if (m_graph.m_hasExceptionHandlers &amp;&amp; maxNumberOfCatchSpills) {
+            RegisterSet volatileRegisters = RegisterSet::volatileRegistersForJSCall();
+            maxNumberOfCatchSpills = std::min(volatileRegisters.numberOfSetRegisters(), maxNumberOfCatchSpills);
+
+            LValue exceptionHandlingVolatileRegistersSpillSlots = m_out.alloca(
+                arrayType(m_out.int64, maxNumberOfCatchSpills));
+            m_ftlState.exceptionHandlingSpillSlotStackmapID = m_stackmapIDs++;
+            m_out.call(
+                m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.exceptionHandlingSpillSlotStackmapID),
+                m_out.int32Zero, exceptionHandlingVolatileRegistersSpillSlots);
+        }
</ins><span class="cx">         
</span><span class="cx">         // We should not create any alloca's after this point, since they will cease to
</span><span class="cx">         // be mem2reg candidates.
</span><span class="lines">@@ -2311,10 +2361,18 @@
</span><span class="cx">         if (verboseCompilationEnabled())
</span><span class="cx">             dataLog(&quot;    Emitting PutById patchpoint with stackmap #&quot;, stackmapID, &quot;\n&quot;);
</span><span class="cx">         
</span><del>-        LValue call = m_out.call(
-            m_out.patchpointVoidIntrinsic(),
-            m_out.constInt64(stackmapID), m_out.constInt32(sizeOfPutById()),
-            constNull(m_out.ref8), m_out.constInt32(2), base, value);
</del><ins>+        ExitArgumentList arguments;
+        arguments.append(base); 
+        arguments.append(value);
+
+        appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments, LLVMAnyRegCallConv, 2); // 2 arguments show up in the stackmap locations: the base and the value.
+
+        arguments.insert(0, m_out.constInt32(2)); 
+        arguments.insert(0, constNull(m_out.ref8)); 
+        arguments.insert(0, m_out.constInt32(sizeOfPutById()));
+        arguments.insert(0, m_out.constInt64(stackmapID));
+
+        LValue call = m_out.call(m_out.patchpointVoidIntrinsic(), arguments);
</ins><span class="cx">         setInstructionCallingConvention(call, LLVMAnyRegCallConv);
</span><span class="cx">         
</span><span class="cx">         m_ftlState.putByIds.append(PutByIdDescriptor(
</span><span class="lines">@@ -4519,12 +4577,9 @@
</span><span class="cx">         unsigned frameSize = JSStack::CallFrameHeaderSize + numArgs;
</span><span class="cx">         unsigned alignedFrameSize = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), frameSize);
</span><span class="cx">         unsigned padding = alignedFrameSize - frameSize;
</span><del>-
-        Vector&lt;LValue&gt; arguments;
-        arguments.append(m_out.constInt64(stackmapID));
-        arguments.append(m_out.constInt32(sizeOfCall()));
-        arguments.append(constNull(m_out.ref8));
-        arguments.append(m_out.constInt32(1 + alignedFrameSize - JSStack::CallerFrameAndPCSize));
</del><ins>+        // Documentation about stackmap and patchpoint intrinsics:
+        // http://llvm.org/docs/StackMaps.html
+        ExitArgumentList arguments;
</ins><span class="cx">         arguments.append(jsCallee); // callee -&gt; %rax
</span><span class="cx">         arguments.append(getUndef(m_out.int64)); // code block
</span><span class="cx">         arguments.append(jsCallee); // callee -&gt; stack
</span><span class="lines">@@ -4533,6 +4588,13 @@
</span><span class="cx">             arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
</span><span class="cx">         for (unsigned i = 0; i &lt; padding; ++i)
</span><span class="cx">             arguments.append(getUndef(m_out.int64));
</span><ins>+
+        appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments, LLVMWebKitJSCallConv, 0); // No call arguments show up in the stackmap locations.
+
+        arguments.insert(0, m_out.constInt32(1 + alignedFrameSize - JSStack::CallerFrameAndPCSize));
+        arguments.insert(0, constNull(m_out.ref8));
+        arguments.insert(0, m_out.constInt32(sizeOfCall()));
+        arguments.insert(0, m_out.constInt64(stackmapID));
</ins><span class="cx">         
</span><span class="cx">         LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
</span><span class="cx">         setInstructionCallingConvention(call, LLVMWebKitJSCallConv);
</span><span class="lines">@@ -4603,16 +4665,19 @@
</span><span class="cx">         
</span><span class="cx">         unsigned stackmapID = m_stackmapIDs++;
</span><span class="cx">         
</span><del>-        Vector&lt;LValue&gt; arguments;
-        arguments.append(m_out.constInt64(stackmapID));
-        arguments.append(m_out.constInt32(sizeOfICFor(m_node)));
-        arguments.append(constNull(m_out.ref8));
-        arguments.append(m_out.constInt32(2 + !!jsArguments));
</del><ins>+        ExitArgumentList arguments;
</ins><span class="cx">         arguments.append(jsCallee);
</span><span class="cx">         if (jsArguments)
</span><span class="cx">             arguments.append(jsArguments);
</span><span class="cx">         ASSERT(thisArg);
</span><span class="cx">         arguments.append(thisArg);
</span><ins>+
+        appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments, LLVMCCallConv, 0); // No call arguments show up in stackmap locations.
+
+        arguments.insert(0, m_out.constInt32(2 + !!jsArguments));
+        arguments.insert(0, constNull(m_out.ref8));
+        arguments.insert(0, m_out.constInt32(sizeOfICFor(m_node)));
+        arguments.insert(0, m_out.constInt64(stackmapID));
</ins><span class="cx">         
</span><span class="cx">         LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
</span><span class="cx">         setInstructionCallingConvention(call, LLVMCCallConv);
</span><span class="lines">@@ -6173,10 +6238,17 @@
</span><span class="cx">         if (Options::verboseCompilation())
</span><span class="cx">             dataLog(&quot;    Emitting GetById patchpoint with stackmap #&quot;, stackmapID, &quot;\n&quot;);
</span><span class="cx">         
</span><del>-        LValue call = m_out.call(
-            m_out.patchpointInt64Intrinsic(),
-            m_out.constInt64(stackmapID), m_out.constInt32(sizeOfGetById()),
-            constNull(m_out.ref8), m_out.constInt32(1), base);
</del><ins>+        ExitArgumentList arguments;
+        arguments.append(base);
+
+        appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments, LLVMAnyRegCallConv, 2, false, true); // 2 arguments show up in the stackmap locations: the result and the base.
+
+        arguments.insert(0, m_out.constInt32(1)); 
+        arguments.insert(0, constNull(m_out.ref8));
+        arguments.insert(0, m_out.constInt32(sizeOfGetById()));
+        arguments.insert(0, m_out.constInt64(stackmapID)); 
+
+        LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
</ins><span class="cx">         setInstructionCallingConvention(call, LLVMAnyRegCallConv);
</span><span class="cx">         
</span><span class="cx">         m_ftlState.getByIds.append(GetByIdDescriptor(stackmapID, m_node-&gt;origin.semantic, uid));
</span><span class="lines">@@ -7517,12 +7589,15 @@
</span><span class="cx">     {
</span><span class="cx">         unsigned stackmapID = m_stackmapIDs++;
</span><span class="cx"> 
</span><del>-        Vector&lt;LValue&gt; arguments;
</del><ins>+        ExitArgumentList arguments;
</ins><span class="cx">         arguments.append(m_out.constInt64(stackmapID));
</span><span class="cx">         arguments.append(m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
</span><span class="cx">         arguments.append(constNull(m_out.ref8));
</span><span class="cx">         arguments.append(m_out.constInt32(userArguments.size()));
</span><span class="cx">         arguments.appendVector(userArguments);
</span><ins>+
+        appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments, LLVMAnyRegCallConv, userArguments.size() + 1, true); // All the arguments plus the result show up in the stackmap locations.
+
</ins><span class="cx">         LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
</span><span class="cx">         setInstructionCallingConvention(call, LLVMAnyRegCallConv);
</span><span class="cx">         
</span><span class="lines">@@ -7537,7 +7612,7 @@
</span><span class="cx">     void speculate(
</span><span class="cx">         ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
</span><span class="cx">     {
</span><del>-        appendOSRExit(kind, lowValue, highValue, failCondition);
</del><ins>+        appendOSRExit(kind, lowValue, highValue, failCondition, m_origin);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void terminate(ExitKind kind)
</span><span class="lines">@@ -7565,7 +7640,7 @@
</span><span class="cx">         if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
</span><span class="cx">             return;
</span><span class="cx">         ASSERT(mayHaveTypeCheck(highValue.useKind()));
</span><del>-        appendOSRExit(BadType, lowValue, highValue.node(), failCondition);
</del><ins>+        appendOSRExit(BadType, lowValue, highValue.node(), failCondition, m_origin);
</ins><span class="cx">         m_interpreter.filter(highValue, typesPassedThrough);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -8722,9 +8797,9 @@
</span><span class="cx"> 
</span><span class="cx">     void callPreflight(CodeOrigin codeOrigin)
</span><span class="cx">     {
</span><ins>+        CallSiteIndex callSiteIndex = m_ftlState.jitCode-&gt;common.addCodeOrigin(codeOrigin);
</ins><span class="cx">         m_out.store32(
</span><del>-            m_out.constInt32(
-                m_ftlState.jitCode-&gt;common.addCodeOrigin(codeOrigin).bits()),
</del><ins>+            m_out.constInt32(callSiteIndex.bits()),
</ins><span class="cx">             tagFor(JSStack::ArgumentCount));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -8755,23 +8830,81 @@
</span><span class="cx">         if (Options::useExceptionFuzz())
</span><span class="cx">             m_out.call(m_out.operation(operationExceptionFuzz), m_callFrame);
</span><span class="cx">         
</span><ins>+        LValue exception = m_out.load64(m_out.absolute(vm().addressOfException()));
+        LValue hadException = m_out.notZero64(exception);
+
+        bool emittedExceptionHandlingCodeForOSRExit = emitBranchToOSRExitIfWillCatchException(hadException);
+        if (emittedExceptionHandlingCodeForOSRExit) // It already took care of exception handling logic.
+            return;
+
</ins><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;Exception check continuation&quot;));
</span><del>-        
-        LValue exception = m_out.load64(m_out.absolute(vm().addressOfException()));
-        
</del><ins>+
</ins><span class="cx">         m_out.branch(
</span><del>-            m_out.notZero64(exception), rarely(m_handleExceptions), usually(continuation));
-        
</del><ins>+            hadException, rarely(m_handleExceptions), usually(continuation));
+
</ins><span class="cx">         m_out.appendTo(continuation);
</span><span class="cx">     }
</span><ins>+
+    void appendOSRExitArgumentsForPatchpointIfWillCatchException(ExitArgumentList&amp; arguments, LCallConv callingConvention, unsigned offsetOfExitArguments, bool isLazySlowPath = false, bool isGetBydId = false)
+    {
+        CodeOrigin opCatchOrigin;
+        HandlerInfo* exceptionHandler;
+        bool willCatchException = m_graph.willCatchExceptionInMachineFrame(m_origin.forExit, opCatchOrigin, exceptionHandler);
+        if (!willCatchException)
+            return;
+
+        appendOSRExitDescriptor(Uncountable, noValue(), nullptr, m_origin.withForExitAndExitOK(opCatchOrigin, true));
+        OSRExitDescriptor&amp; exitDescriptor = m_ftlState.jitCode-&gt;osrExitDescriptors.last();
+        exitDescriptor.m_semanticCodeOriginForCallFrameHeader = codeOriginDescriptionOfCallSite();
+        exitDescriptor.m_isExceptionHandler = true;
+        exitDescriptor.m_willArriveAtOSRExitFromGenericUnwind = !isLazySlowPath;
+        exitDescriptor.m_isExceptionFromLazySlowPath = isLazySlowPath;
+        exitDescriptor.m_isExceptionFromJSCall = callingConvention == LLVMWebKitJSCallConv || callingConvention == LLVMCCallConv;
+        exitDescriptor.m_isExceptionFromGetById = isGetBydId;
+        exitDescriptor.m_baselineExceptionHandler = *exceptionHandler;
+        exitDescriptor.m_stackmapID = m_stackmapIDs - 1;
+
+        ExitArgumentList freshList;
+        buildExitArguments(exitDescriptor, freshList, noValue(), exitDescriptor.m_codeOrigin);
+        arguments.appendVector(freshList);
+
+        if (offsetOfExitArguments) {
+            for (size_t i = 0; i &lt; exitDescriptor.m_values.size(); i++) {
+                if (exitDescriptor.m_values[i].hasIndexInStackmapLocations())
+                    exitDescriptor.m_values[i].adjustStackmapLocationsIndexByOffset(offsetOfExitArguments);
+            }
+        }
+    }
+
+    bool emitBranchToOSRExitIfWillCatchException(LValue hadException)
+    {
+        CodeOrigin opCatchOrigin;
+        HandlerInfo* exceptionHandler;
+        bool willCatchException = m_graph.willCatchExceptionInMachineFrame(m_origin.forExit, opCatchOrigin, exceptionHandler); 
+        if (!willCatchException)
+            return false;
+
+        appendOSRExit(Uncountable, noValue(), nullptr, hadException, m_origin.withForExitAndExitOK(opCatchOrigin, true), true);
+        return true;
+    }
</ins><span class="cx">     
</span><span class="cx">     LBasicBlock lowBlock(BasicBlock* block)
</span><span class="cx">     {
</span><span class="cx">         return m_blocks.get(block);
</span><span class="cx">     }
</span><ins>+
+    void appendOSRExitDescriptor(ExitKind kind, FormattedValue lowValue, Node* highValue, NodeOrigin origin)
+    {
+        m_ftlState.jitCode-&gt;osrExitDescriptors.append(OSRExitDescriptor(
+            kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
+            origin.forExit, origin.semantic,
+            availabilityMap().m_locals.numberOfArguments(),
+            availabilityMap().m_locals.numberOfLocals()));
+    }
</ins><span class="cx">     
</span><span class="cx">     void appendOSRExit(
</span><del>-        ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
</del><ins>+        ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition, 
+        NodeOrigin origin, bool isExceptionHandler = false)
</ins><span class="cx">     {
</span><span class="cx">         if (verboseCompilationEnabled()) {
</span><span class="cx">             dataLog(&quot;    OSR exit #&quot;, m_ftlState.jitCode-&gt;osrExitDescriptors.size(), &quot; with availability: &quot;, availabilityMap(), &quot;\n&quot;);
</span><span class="lines">@@ -8779,9 +8912,9 @@
</span><span class="cx">                 dataLog(&quot;        Available recoveries: &quot;, listDump(m_availableRecoveries), &quot;\n&quot;);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        DFG_ASSERT(m_graph, m_node, m_origin.exitOK);
</del><ins>+        DFG_ASSERT(m_graph, m_node, origin.exitOK);
</ins><span class="cx">         
</span><del>-        if (doOSRExitFuzzing()) {
</del><ins>+        if (doOSRExitFuzzing() &amp;&amp; !isExceptionHandler) {
</ins><span class="cx">             LValue numberOfFuzzChecks = m_out.add(
</span><span class="cx">                 m_out.load32(m_out.absolute(&amp;g_numberOfOSRExitFuzzChecks)),
</span><span class="cx">                 m_out.int32One);
</span><span class="lines">@@ -8803,13 +8936,9 @@
</span><span class="cx">         if (failCondition == m_out.booleanFalse)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        m_ftlState.jitCode-&gt;osrExitDescriptors.append(OSRExitDescriptor(
-            kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
-            m_origin.forExit, m_origin.semantic,
-            availabilityMap().m_locals.numberOfArguments(),
-            availabilityMap().m_locals.numberOfLocals()));
-
</del><ins>+        appendOSRExitDescriptor(kind, lowValue, highValue, origin);
</ins><span class="cx">         OSRExitDescriptor&amp; exitDescriptor = m_ftlState.jitCode-&gt;osrExitDescriptors.last();
</span><ins>+        exitDescriptor.m_isExceptionHandler = isExceptionHandler;
</ins><span class="cx"> 
</span><span class="cx">         if (failCondition == m_out.booleanTrue) {
</span><span class="cx">             emitOSRExitCall(exitDescriptor, lowValue);
</span><span class="lines">@@ -8977,7 +9106,6 @@
</span><span class="cx">             AvailableRecovery recovery = m_availableRecoveries[i];
</span><span class="cx">             if (recovery.node() != node)
</span><span class="cx">                 continue;
</span><del>-            
</del><span class="cx">             ExitValue result = ExitValue::recovery(
</span><span class="cx">                 recovery.opcode(), arguments.size(), arguments.size() + 1,
</span><span class="cx">                 recovery.format());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;FTLExitArgument.h&quot;
</span><span class="cx"> #include &quot;FTLExitArgumentList.h&quot;
</span><span class="cx"> #include &quot;FTLJITCode.h&quot;
</span><ins>+#include &quot;FTLLocation.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace FTL {
</span><span class="lines">@@ -52,6 +53,11 @@
</span><span class="cx">     , m_valueProfile(valueProfile)
</span><span class="cx">     , m_values(numberOfArguments, numberOfLocals)
</span><span class="cx">     , m_isInvalidationPoint(false)
</span><ins>+    , m_isExceptionHandler(false)
+    , m_willArriveAtOSRExitFromGenericUnwind(false)
+    , m_isExceptionFromJSCall(false)
+    , m_isExceptionFromGetById(false)
+    , m_isExceptionFromLazySlowPath(false)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -70,6 +76,7 @@
</span><span class="cx">     , m_descriptor(descriptor)
</span><span class="cx">     , m_stackmapRecordIndex(stackmapRecordIndex)
</span><span class="cx"> {
</span><ins>+    m_isExceptionHandler = descriptor.m_isExceptionHandler;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CodeLocationJump OSRExit::codeLocationForRepatch(CodeBlock* ftlCodeBlock) const
</span><span class="lines">@@ -80,6 +87,76 @@
</span><span class="cx">         m_patchableCodeOffset);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void OSRExit::gatherRegistersToSpillForCallIfException(StackMaps&amp; stackmaps, StackMaps::Record&amp; record)
+{
+    RELEASE_ASSERT(m_descriptor.m_isExceptionFromJSCall);
+
+    RegisterSet volatileRegisters = RegisterSet::volatileRegistersForJSCall();
+
+    auto addNeededRegisters = [&amp;] (const ExitValue&amp; exitValue) {
+        auto handleLocation = [&amp;] (const FTL::Location&amp; location) {
+            if (location.involvesGPR() &amp;&amp; volatileRegisters.get(location.gpr()))
+                this-&gt;registersToPreserveForCallThatMightThrow.set(location.gpr());
+            else if (location.isFPR() &amp;&amp; volatileRegisters.get(location.fpr()))
+                this-&gt;registersToPreserveForCallThatMightThrow.set(location.fpr());
+        };
+
+        switch (exitValue.kind()) {
+        case ExitValueArgument:
+            handleLocation(FTL::Location::forStackmaps(&amp;stackmaps, record.locations[exitValue.exitArgument().argument()]));
+            break;
+        case ExitValueRecovery:
+            handleLocation(FTL::Location::forStackmaps(&amp;stackmaps, record.locations[exitValue.rightRecoveryArgument()]));
+            handleLocation(FTL::Location::forStackmaps(&amp;stackmaps, record.locations[exitValue.leftRecoveryArgument()]));
+            break;
+        default:
+            break;
+        }
+    };
+    for (ExitTimeObjectMaterialization* materialization : m_descriptor.m_materializations) {
+        for (unsigned propertyIndex = materialization-&gt;properties().size(); propertyIndex--;)
+            addNeededRegisters(materialization-&gt;properties()[propertyIndex].value());
+    }
+    for (unsigned index = m_descriptor.m_values.size(); index--;)
+        addNeededRegisters(m_descriptor.m_values[index]);
+}
+
+void OSRExit::spillRegistersToSpillSlot(CCallHelpers&amp; jit, int32_t stackSpillSlot)
+{
+    RELEASE_ASSERT(m_descriptor.m_isExceptionFromJSCall || m_descriptor.m_isExceptionFromGetById);
+    unsigned count = 0;
+    for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
+        if (registersToPreserveForCallThatMightThrow.get(reg)) {
+            jit.store64(reg, CCallHelpers::addressFor(stackSpillSlot + count));
+            count++;
+        }
+    }
+    for (FPRReg reg = MacroAssembler::firstFPRegister(); reg &lt;= MacroAssembler::lastFPRegister(); reg = MacroAssembler::nextFPRegister(reg)) {
+        if (registersToPreserveForCallThatMightThrow.get(reg)) {
+            jit.storeDouble(reg, CCallHelpers::addressFor(stackSpillSlot + count));
+            count++;
+        }
+    }
+}
+
+void OSRExit::recoverRegistersFromSpillSlot(CCallHelpers&amp; jit, int32_t stackSpillSlot)
+{
+    RELEASE_ASSERT(m_descriptor.m_isExceptionFromJSCall || m_descriptor.m_isExceptionFromGetById);
+    unsigned count = 0;
+    for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
+        if (registersToPreserveForCallThatMightThrow.get(reg)) {
+            jit.load64(CCallHelpers::addressFor(stackSpillSlot + count), reg);
+            count++;
+        }
+    }
+    for (FPRReg reg = MacroAssembler::firstFPRegister(); reg &lt;= MacroAssembler::lastFPRegister(); reg = MacroAssembler::nextFPRegister(reg)) {
+        if (registersToPreserveForCallThatMightThrow.get(reg)) {
+            jit.loadDouble(CCallHelpers::addressFor(stackSpillSlot + count), reg);
+            count++;
+        }
+    }
+}
+
</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="trunkSourceJavaScriptCoreftlFTLOSRExith"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -36,8 +36,11 @@
</span><span class="cx"> #include &quot;FTLExitTimeObjectMaterialization.h&quot;
</span><span class="cx"> #include &quot;FTLExitValue.h&quot;
</span><span class="cx"> #include &quot;FTLFormattedValue.h&quot;
</span><ins>+#include &quot;FTLStackMaps.h&quot;
+#include &quot;HandlerInfo.h&quot;
</ins><span class="cx"> #include &quot;MethodOfGettingAValueProfile.h&quot;
</span><span class="cx"> #include &quot;Operands.h&quot;
</span><ins>+#include &quot;Reg.h&quot;
</ins><span class="cx"> #include &quot;ValueProfile.h&quot;
</span><span class="cx"> #include &quot;VirtualRegister.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -142,6 +145,7 @@
</span><span class="cx">     ExitKind m_kind;
</span><span class="cx">     CodeOrigin m_codeOrigin;
</span><span class="cx">     CodeOrigin m_codeOriginForExitProfile;
</span><ins>+    CodeOrigin m_semanticCodeOriginForCallFrameHeader;
</ins><span class="cx">     
</span><span class="cx">     // The first argument to the exit call may be a value we wish to profile.
</span><span class="cx">     // If that's the case, the format will be not Invalid and we'll have a
</span><span class="lines">@@ -155,7 +159,13 @@
</span><span class="cx">     Bag&lt;ExitTimeObjectMaterialization&gt; m_materializations;
</span><span class="cx">     
</span><span class="cx">     uint32_t m_stackmapID;
</span><del>-    bool m_isInvalidationPoint;
</del><ins>+    HandlerInfo m_baselineExceptionHandler;
+    bool m_isInvalidationPoint : 1;
+    bool m_isExceptionHandler : 1;
+    bool m_willArriveAtOSRExitFromGenericUnwind : 1;
+    bool m_isExceptionFromJSCall : 1;
+    bool m_isExceptionFromGetById : 1;
+    bool m_isExceptionFromLazySlowPath : 1;
</ins><span class="cx">     
</span><span class="cx">     void validateReferences(const TrackedReferences&amp;);
</span><span class="cx"> };
</span><span class="lines">@@ -170,11 +180,17 @@
</span><span class="cx">     // Offset within Stackmap::records
</span><span class="cx">     uint32_t m_stackmapRecordIndex;
</span><span class="cx"> 
</span><ins>+    RegisterSet registersToPreserveForCallThatMightThrow;
+
</ins><span class="cx">     CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const;
</span><span class="cx">     void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
</span><span class="cx">     {
</span><span class="cx">         OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL);
</span><span class="cx">     }
</span><ins>+
+    void gatherRegistersToSpillForCallIfException(StackMaps&amp;, StackMaps::Record&amp;);
+    void spillRegistersToSpillSlot(CCallHelpers&amp;, int32_t stackSpillSlot);
+    void recoverRegistersFromSpillSlot(CCallHelpers&amp; jit, int32_t stackSpillSlot);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExitCompilationInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     MacroAssembler::Label m_thunkLabel;
</span><ins>+    MacroAssembler::Label m_getAndPutByIdCallOperationExceptionOSRExitEntrance;
</ins><span class="cx">     MacroAssembler::PatchableJump m_thunkJump;
</span><span class="cx">     CodeLocationLabel m_thunkAddress;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExitCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include &quot;DFGOSRExitPreparation.h&quot;
</span><span class="cx"> #include &quot;FTLExitArgumentForOperand.h&quot;
</span><span class="cx"> #include &quot;FTLJITCode.h&quot;
</span><ins>+#include &quot;FTLLocation.h&quot;
</ins><span class="cx"> #include &quot;FTLOSRExit.h&quot;
</span><span class="cx"> #include &quot;FTLOperations.h&quot;
</span><span class="cx"> #include &quot;FTLState.h&quot;
</span><span class="lines">@@ -178,12 +179,12 @@
</span><span class="cx"> {
</span><span class="cx">     StackMaps::Record* record = &amp;jitCode-&gt;stackmaps.records[exit.m_stackmapRecordIndex];
</span><span class="cx">     RELEASE_ASSERT(record-&gt;patchpointID == exit.m_descriptor.m_stackmapID);
</span><del>-    
</del><ins>+
</ins><span class="cx">     // This code requires framePointerRegister is the same as callFrameRegister
</span><span class="cx">     static_assert(MacroAssembler::framePointerRegister == GPRInfo::callFrameRegister, &quot;MacroAssembler::framePointerRegister and GPRInfo::callFrameRegister must be the same&quot;);
</span><span class="cx"> 
</span><span class="cx">     CCallHelpers jit(vm, codeBlock);
</span><del>-    
</del><ins>+
</ins><span class="cx">     // We need scratch space to save all registers, to build up the JS stack, to deal with unwind
</span><span class="cx">     // fixup, pointers to all of the objects we materialize, and the elements inside those objects
</span><span class="cx">     // that we materialize.
</span><span class="lines">@@ -426,15 +427,26 @@
</span><span class="cx"> 
</span><span class="cx">     RegisterSet allFTLCalleeSaves = RegisterSet::ftlCalleeSaveRegisters();
</span><span class="cx">     RegisterAtOffsetList* baselineCalleeSaves = baselineCodeBlock-&gt;calleeSaveRegisters();
</span><ins>+    RegisterAtOffsetList* vmCalleeSaves = vm-&gt;getAllCalleeSaveRegisterOffsets();
+    RegisterSet vmCalleeSavesToSkip = RegisterSet::stackRegisters();
+    if (exit.m_isExceptionHandler)
+        jit.move(CCallHelpers::TrustedImmPtr(vm-&gt;calleeSaveRegistersBuffer), GPRInfo::regT1);
</ins><span class="cx"> 
</span><span class="cx">     for (Reg reg = Reg::first(); reg &lt;= Reg::last(); reg = reg.next()) {
</span><del>-        if (!allFTLCalleeSaves.get(reg))
</del><ins>+        if (!allFTLCalleeSaves.get(reg)) {
+            if (exit.m_isExceptionHandler)
+                RELEASE_ASSERT(!vmCalleeSaves-&gt;find(reg));
</ins><span class="cx">             continue;
</span><ins>+        }
</ins><span class="cx">         unsigned unwindIndex = codeBlock-&gt;calleeSaveRegisters()-&gt;indexOf(reg);
</span><span class="cx">         RegisterAtOffset* baselineRegisterOffset = baselineCalleeSaves-&gt;find(reg);
</span><ins>+        RegisterAtOffset* vmCalleeSave = nullptr; 
+        if (exit.m_isExceptionHandler)
+            vmCalleeSave = vmCalleeSaves-&gt;find(reg);
</ins><span class="cx"> 
</span><span class="cx">         if (reg.isGPR()) {
</span><span class="cx">             GPRReg regToLoad = baselineRegisterOffset ? GPRInfo::regT0 : reg.gpr();
</span><ins>+            RELEASE_ASSERT(regToLoad != GPRInfo::regT1);
</ins><span class="cx"> 
</span><span class="cx">             if (unwindIndex == UINT_MAX) {
</span><span class="cx">                 // The FTL compilation didn't preserve this register. This means that it also
</span><span class="lines">@@ -452,6 +464,8 @@
</span><span class="cx"> 
</span><span class="cx">             if (baselineRegisterOffset)
</span><span class="cx">                 jit.store64(regToLoad, MacroAssembler::Address(MacroAssembler::framePointerRegister, baselineRegisterOffset-&gt;offset()));
</span><ins>+            if (vmCalleeSave &amp;&amp; !vmCalleeSavesToSkip.get(vmCalleeSave-&gt;reg()))
+                jit.store64(regToLoad, MacroAssembler::Address(GPRInfo::regT1, vmCalleeSave-&gt;offset()));
</ins><span class="cx">         } else {
</span><span class="cx">             FPRReg fpRegToLoad = baselineRegisterOffset ? FPRInfo::fpRegT0 : reg.fpr();
</span><span class="cx"> 
</span><span class="lines">@@ -462,9 +476,19 @@
</span><span class="cx"> 
</span><span class="cx">             if (baselineRegisterOffset)
</span><span class="cx">                 jit.storeDouble(fpRegToLoad, MacroAssembler::Address(MacroAssembler::framePointerRegister, baselineRegisterOffset-&gt;offset()));
</span><ins>+            if (vmCalleeSave &amp;&amp; !vmCalleeSavesToSkip.get(vmCalleeSave-&gt;reg()))
+                jit.storeDouble(fpRegToLoad, MacroAssembler::Address(GPRInfo::regT1, vmCalleeSave-&gt;offset()));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (exit.m_isExceptionHandler) {
+        RegisterAtOffset* vmCalleeSave = vmCalleeSaves-&gt;find(GPRInfo::tagTypeNumberRegister);
+        jit.store64(GPRInfo::tagTypeNumberRegister, MacroAssembler::Address(GPRInfo::regT1, vmCalleeSave-&gt;offset()));
+
+        vmCalleeSave = vmCalleeSaves-&gt;find(GPRInfo::tagMaskRegister);
+        jit.store64(GPRInfo::tagMaskRegister, MacroAssembler::Address(GPRInfo::regT1, vmCalleeSave-&gt;offset()));
+    }
+
</ins><span class="cx">     size_t baselineVirtualRegistersForCalleeSaves = baselineCodeBlock-&gt;calleeSaveSpaceAsVirtualRegisters();
</span><span class="cx"> 
</span><span class="cx">     // Now get state out of the scratch buffer and place it back into the stack. The values are
</span><span class="lines">@@ -481,7 +505,7 @@
</span><span class="cx">     
</span><span class="cx">     handleExitCounts(jit, exit);
</span><span class="cx">     reifyInlinedCallFrames(jit, exit);
</span><del>-    adjustAndJumpToTarget(jit, exit, false);
</del><ins>+    adjustAndJumpToTarget(jit, exit, exit.m_isExceptionHandler);
</ins><span class="cx">     
</span><span class="cx">     LinkBuffer patchBuffer(*vm, jit, codeBlock);
</span><span class="cx">     exit.m_code = FINALIZE_CODE_IF(
</span><span class="lines">@@ -520,6 +544,11 @@
</span><span class="cx">         dataLog(&quot;    Origin: &quot;, exit.m_codeOrigin, &quot;\n&quot;);
</span><span class="cx">         if (exit.m_codeOriginForExitProfile != exit.m_codeOrigin)
</span><span class="cx">             dataLog(&quot;    Origin for exit profile: &quot;, exit.m_codeOriginForExitProfile, &quot;\n&quot;);
</span><ins>+        dataLog(&quot;    Exit stackmap ID: &quot;, exit.m_descriptor.m_stackmapID, &quot;\n&quot;);
+        dataLog(&quot;    Current call site index: &quot;, exec-&gt;callSiteIndex().bits(), &quot;\n&quot;);
+        dataLog(&quot;    Exit is exception handler: &quot;, exit.m_isExceptionHandler,
+            &quot; will arrive at exit from genericUnwind(): &quot;, exit.m_descriptor.m_willArriveAtOSRExitFromGenericUnwind, 
+            &quot; will arrive at exit from lazy slow path: &quot;, exit.m_descriptor.m_isExceptionFromLazySlowPath, &quot;\n&quot;);
</ins><span class="cx">         dataLog(&quot;    Exit values: &quot;, exit.m_descriptor.m_values, &quot;\n&quot;);
</span><span class="cx">         if (!exit.m_descriptor.m_materializations.isEmpty()) {
</span><span class="cx">             dataLog(&quot;    Materializations:\n&quot;);
</span><span class="lines">@@ -531,7 +560,7 @@
</span><span class="cx">     prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin);
</span><span class="cx">     
</span><span class="cx">     compileStub(exitID, jitCode, exit, vm, codeBlock);
</span><del>-    
</del><ins>+
</ins><span class="cx">     MacroAssembler::repatchJump(
</span><span class="cx">         exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code()));
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLState.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLState.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLState.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx">     , handleExceptionStackmapID(UINT_MAX)
</span><span class="cx">     , capturedStackmapID(UINT_MAX)
</span><span class="cx">     , varargsSpillSlotsStackmapID(UINT_MAX)
</span><ins>+    , exceptionHandlingSpillSlotStackmapID(UINT_MAX)
</ins><span class="cx">     , unwindDataSection(0)
</span><span class="cx">     , unwindDataSectionSize(0)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLStateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLState.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLState.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/ftl/FTLState.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -75,6 +75,7 @@
</span><span class="cx">     unsigned handleExceptionStackmapID;
</span><span class="cx">     unsigned capturedStackmapID;
</span><span class="cx">     unsigned varargsSpillSlotsStackmapID;
</span><ins>+    unsigned exceptionHandlingSpillSlotStackmapID;
</ins><span class="cx">     SegmentedVector&lt;GetByIdDescriptor&gt; getByIds;
</span><span class="cx">     SegmentedVector&lt;PutByIdDescriptor&gt; putByIds;
</span><span class="cx">     SegmentedVector&lt;CheckInDescriptor&gt; checkIns;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -595,10 +595,10 @@
</span><span class="cx"> 
</span><span class="cx">     CallFrame* callFrame = visitor-&gt;callFrame();
</span><span class="cx">     unsigned exceptionHandlerIndex;
</span><del>-    if (codeBlock-&gt;jitType() != JITCode::DFGJIT)
</del><ins>+    if (JITCode::isOptimizingJIT(codeBlock-&gt;jitType()))
+        exceptionHandlerIndex = callFrame-&gt;callSiteIndex().bits();
+    else
</ins><span class="cx">         exceptionHandlerIndex = callFrame-&gt;bytecodeOffset();
</span><del>-    else
-        exceptionHandlerIndex = callFrame-&gt;callSiteIndex().bits();
</del><span class="cx"> 
</span><span class="cx">     return codeBlock-&gt;handlerForIndex(exceptionHandlerIndex, requiredHandler);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.cpp (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.cpp        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.cpp        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -66,6 +66,15 @@
</span><span class="cx">         stackRegisters(), reservedHardwareRegisters(), runtimeRegisters());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RegisterSet RegisterSet::volatileRegistersForJSCall()
+{
+    RegisterSet volatileRegisters = allRegisters();
+    volatileRegisters.exclude(RegisterSet::stackRegisters());
+    volatileRegisters.exclude(RegisterSet::reservedHardwareRegisters());
+    volatileRegisters.exclude(RegisterSet::vmCalleeSaveRegisters());
+    return volatileRegisters;
+}
+
</ins><span class="cx"> RegisterSet RegisterSet::stubUnavailableRegisters()
</span><span class="cx"> {
</span><span class="cx">     return RegisterSet(specialRegisters(), vmCalleeSaveRegisters());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.h (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.h        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.h        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx">     static RegisterSet webAssemblyCalleeSaveRegisters(); // Registers saved and used by the WebAssembly JIT.
</span><span class="cx"> #endif
</span><ins>+    static RegisterSet volatileRegistersForJSCall();
</ins><span class="cx">     static RegisterSet stubUnavailableRegisters(); // The union of callee saves and special registers.
</span><span class="cx">     static RegisterSet allGPRs();
</span><span class="cx">     static RegisterSet allFPRs();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchgettericfailtocalloperationthrowerrorjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-ic-fail-to-call-operation-throw-error.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-ic-fail-to-call-operation-throw-error.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-ic-fail-to-call-operation-throw-error.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;bad value&quot;)
+}
+noInline(assert);
+
+let oThrow = {
+    x: 20,
+    y: 40,
+    z: 50,
+    get f() { throw new Error(&quot;Hello World!&quot;); }
+};
+
+let o1 = {
+    x: 20,
+    f: 40
+};
+
+let o2 = {
+    x: 20,
+    y: 50,
+    get f() { return 20; }
+};
+
+function foo(f) {
+    let o = f();
+    try {
+        o = o.f;
+    } catch(e) {
+        assert(o === oThrow); // Make sure this is not undefined when we have an IC miss and an exception at the same time.
+    }
+}
+noInline(foo);
+
+let i;
+let flag = false;
+function f() {
+    if (flag)
+        return oThrow;
+    if (i % 2)
+        return o1;
+    return o2;
+}
+noInline(f);
+for (i = 0; i &lt; 100000; i++) {
+    foo(f);
+}
+flag = true;
+foo(f);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchgetterthrowjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-throw.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-throw.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-getter-throw.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;bad value&quot;)
+}
+noInline(assert);
+
+function random() { 
+    return &quot;blah&quot;;
+}
+noInline(random);
+
+function foo(o, a) {
+    let x = o.g;
+    let y = o.y;
+    let j = random();
+    try {
+        j = o.f;
+    } catch(e) {
+        assert(j === &quot;blah&quot;);
+        return x + y + 1;
+    }
+    return x + y;
+}
+
+noInline(foo);
+var flag = false;
+function f(arg1, arg2, arg3) {
+    if (flag)
+        throw new Error(&quot;blah&quot;)
+    return arg1;
+}
+noInline(f);
+let o1 = {
+    g: 20,
+    y: 40,
+    f: &quot;get f&quot;
+};
+
+let o2 = {
+    g: &quot;g&quot;,
+    y: &quot;y&quot;,
+    get f() { 
+        if (flag) 
+            throw new Error(&quot;blah&quot;); 
+        return &quot;get f&quot;;
+    }
+}
+
+for (let i = 0; i &lt; 100000; i++) {
+    if (i % 2) {
+        assert(foo(o1) === 60);
+    } else {
+        assert(foo(o2) === &quot;gy&quot;);
+    }
+}
+flag = true;
+assert(foo(o2) === &quot;gy1&quot;);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchoomerrorlazyslowpathjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-oom-error-lazy-slow-path.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-oom-error-lazy-slow-path.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-oom-error-lazy-slow-path.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+forceGCSlowPaths(); // Force OOM error in FTL MakeRope to happen in a lazy slow path.
+
+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion&quot;);
+}
+
+function a() { return &quot;a&quot;; }
+noInline(a);
+function b() { return &quot;b&quot;; }
+noInline(b);
+function c() { return &quot;c&quot;; }
+noInline(c);
+function d() { return &quot;d&quot;; }
+noInline(d);
+function e() { return &quot;e&quot;; }
+noInline(e);
+function f() { return &quot;f&quot;; }
+noInline(f);
+function g() { return &quot;g&quot;; }
+noInline(g);
+
+let expString = &quot;a&quot;;
+let exponentialBlowup = false;
+let shouldBreak = false;
+function foo(fun, left, right) {
+    let x = fun();
+    let r = left + right;
+
+    var _a = a();
+    var _b = b();
+    var _c = c();
+    var _d = d();
+    var _e = e();
+    var _f = f();
+    var _g = g();
+    try {
+        expString = expString + expString;
+    } catch(e) {
+        shouldBreak = true;
+
+        assert(_b === &quot;b&quot;);
+        assert(_c === &quot;c&quot;);
+        assert(_d === &quot;d&quot;);
+        assert(_e === &quot;e&quot;);
+        assert(_f === &quot;f&quot;);
+        assert(_g === &quot;g&quot;);
+    }
+    return x + r;
+}
+noInline(foo);
+
+
+
+function blah() { return &quot;blah&quot;; }
+noInline(blah);
+
+for (let i = 0; i &lt; 100000; i++) {
+    assert(foo(blah, &quot;b&quot;, &quot;a&quot;) === &quot;blahba&quot;);
+    if (!exponentialBlowup)
+        expString = &quot;a&quot;;
+}
+
+exponentialBlowup = true;
+while (true) {
+    assert(foo(blah, &quot;a&quot;, &quot;b&quot;) === &quot;blahab&quot;);
+    if (shouldBreak)
+        break;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchpatchpointwithvolatileregistersjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-patchpoint-with-volatile-registers.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-patchpoint-with-volatile-registers.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-patchpoint-with-volatile-registers.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad value.&quot;)
+}
+noInline(assert);
+
+var v1 = 100;
+var v2 = 200;
+var flag = false;
+var o1 = {
+    get f() {
+        if (flag)
+            throw new Error(&quot;gotcha!&quot;);
+        return v1;    
+    }
+}
+
+function a() { return &quot;a&quot;; }
+noInline(a);
+function b() { return &quot;b&quot;; }
+noInline(b);
+function c() { return &quot;c&quot;; }
+noInline(c);
+function d() { return &quot;d&quot;; }
+noInline(d);
+function e() { return &quot;e&quot;; }
+noInline(e);
+function f() { return &quot;f&quot;; }
+noInline(f);
+function g() { return &quot;g&quot;; }
+noInline(g);
+
+var o2 = {
+    get f() {
+        assert(true);
+        assert(true);
+        assert(true);
+        assert(true);
+        assert(true);
+        assert(true);
+        assert(true);
+        return v2;
+    }
+}
+
+function foo(o) {
+    try {
+        var _a = a();
+        var _b = b();
+        var _c = c();
+        var _d = d();
+        var _e = e();
+        var _f = f();
+        var _g = g();
+
+        o = o.f;
+
+    } catch(e) {
+        assert(o === o1);
+        assert(_b === &quot;b&quot;);
+        assert(_c === &quot;c&quot;);
+        assert(_d === &quot;d&quot;);
+        assert(_e === &quot;e&quot;);
+        assert(_f === &quot;f&quot;);
+        assert(_g === &quot;g&quot;);
+    }
+}
+noInline(foo);
+
+for (var i = 0; i &lt; 1000000; i++)
+    foo(i % 2 ? o1 : o2);
+flag = true;
+foo(o1);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchsetterthrowjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-setter-throw.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-setter-throw.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-setter-throw.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+function foo(o, a) {
+    let x = o.g;
+    let y = o.y;
+    try {
+        o.f = 20;
+    } catch(e) {
+        return x + y + 1;
+    }
+    return x + y;
+}
+
+function assert(b) {
+    if (!b)
+        throw new Error(&quot;bad value&quot;)
+}
+noInline(assert);
+
+noInline(foo);
+var flag = false;
+function f(arg1, arg2, arg3) {
+    if (flag)
+        throw new Error(&quot;blah&quot;)
+    return arg1;
+}
+noInline(f);
+let o1 = {
+    g: 20,
+    y: 40,
+    f: null
+};
+
+let o2 = {
+    g: &quot;g&quot;,
+    y: &quot;y&quot;,
+    set f(v) { if (flag) throw new Error(&quot;blah&quot;); }
+}
+
+for (let i = 0; i &lt; 100000; i++) {
+    if (i % 2) {
+        assert(foo(o1) === 60);
+    } else {
+        assert(foo(o2) === &quot;gy&quot;);
+    }
+}
+flag = true;
+assert(foo(o2) === &quot;gy1&quot;);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchtailcallinilnedcallerjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-tail-call-inilned-caller.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-tail-call-inilned-caller.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-tail-call-inilned-caller.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+// This test ensures the TailCallInilnedCaller has the correct
+// stack trace in the FTL inside a try block.
+// This case arises when you have a situation like this:
+// foo makes a call to bar, bar is inlined in foo. bar makes a call
+// to baz and baz is inlined in bar. And then baz makes a tail-call to jaz,
+// and jaz is inlined in baz. We want the callframe for jaz to appear to 
+// have caller be bar. 
+
+
+&quot;use strict&quot;;
+function value() {
+    return &quot;value&quot;;
+}
+noInline(value);
+
+function assert(b) {
+    if (!b)
+        throw new Error(&quot;bad value&quot;);
+}
+noInline(assert);
+
+function validate(stack) {
+    let arr = stack.split(&quot;\n&quot;);
+    assert(arr[0].indexOf(&quot;jaz&quot;) !== -1);
+    assert(arr[1].indexOf(&quot;bar&quot;) !== -1);
+    assert(arr[2].indexOf(&quot;foo&quot;) !== -1);
+}
+
+function foo() {
+    let v = value();
+    try {
+        return bar() + 1;
+    } catch(e) {
+        assert(v === &quot;value&quot;);
+        validate(e.stack);
+    }
+}
+noInline(foo);
+
+function bar() {
+    return baz() + 1;
+}
+
+function baz() { 
+    return jaz();
+}
+
+let flag = false;
+function jaz() { 
+    if (flag)
+        throw new Error(&quot;lol&quot;);
+    return 20; 
+}
+noInline(jaz);
+
+for (var i = 0; i &lt; 50000; i++) {
+    foo();
+}
+flag = true;
+foo();
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressftltrycatchvarargscallthrowsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-varargs-call-throws.js (0 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-varargs-call-throws.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/ftl-try-catch-varargs-call-throws.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+function foo(o, a) {
+    let resetFlag = false;
+    if (flag) {
+        resetFlag = true;
+        flag = false;
+    }
+    let x = o(10);
+    let y = o(20);
+    if (resetFlag)
+        flag = true;
+    try {
+        o.apply(null, a);
+    } catch(e) {
+        if (x !== 10)
+            throw new Error(&quot;Not 10&quot;)
+        return x + y;
+    }
+}
+noInline(foo);
+var flag = false;
+function f(arg1, arg2, arg3) {
+    if (flag)
+        throw new Error(&quot;blah&quot;)
+    return arg1;
+}
+noInline(f);
+
+for (let i = 0; i &lt; 100000; i++) {
+    foo(f, [10, 20, 30]);
+}
+flag = true;
+foo(f, [10, 20, 30]);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrycatchstubroutinereplacedjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js (192202 => 192203)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js        2015-11-10 07:21:23 UTC (rev 192202)
+++ trunk/Source/JavaScriptCore/tests/stress/try-catch-stub-routine-replaced.js        2015-11-10 07:48:54 UTC (rev 192203)
</span><span class="lines">@@ -21,8 +21,15 @@
</span><span class="cx"> function hello() { return 20; }
</span><span class="cx"> noInline(hello);
</span><span class="cx"> 
</span><ins>+let __jaz = {};
+function jazzy() {
+    return __jaz;
+}
+noInline(jazzy);
+
</ins><span class="cx"> function foo(o) {
</span><span class="cx">     let baz = hello();
</span><ins>+    let jaz = jazzy();
</ins><span class="cx">     let v;
</span><span class="cx">     try {
</span><span class="cx">         v = o.f;
</span><span class="lines">@@ -30,6 +37,7 @@
</span><span class="cx">         v = o.f;
</span><span class="cx">     } catch(e) {
</span><span class="cx">         assert(baz === 20);
</span><ins>+        assert(jaz === __jaz);
</ins><span class="cx">         assert(v === 2); // Really flagCount.
</span><span class="cx">     }
</span><span class="cx">     return v;
</span></span></pre>
</div>
</div>

</body>
</html>