<!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>[192845] 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/192845">192845</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2015-11-30 16:55:32 -0800 (Mon, 30 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>FTL OSR Exits that are exception handlers should not have two different entrances. Instead, we should have two discrete OSR exits that do different things.
https://bugs.webkit.org/show_bug.cgi?id=151404

Reviewed by Filip Pizlo.

* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLExceptionHandlerManager.cpp:
(JSC::FTL::ExceptionHandlerManager::addNewExit):
(JSC::FTL::ExceptionHandlerManager::addNewCallOperationExit):
(JSC::FTL::ExceptionHandlerManager::callOperationExceptionTarget):
(JSC::FTL::ExceptionHandlerManager::lazySlowPathExceptionTarget):
(JSC::FTL::ExceptionHandlerManager::callOperationOSRExit):
(JSC::FTL::ExceptionHandlerManager::getByIdOSRExit): Deleted.
(JSC::FTL::ExceptionHandlerManager::subOSRExit): Deleted.
* ftl/FTLExceptionHandlerManager.h:
* ftl/FTLExitThunkGenerator.cpp:
(JSC::FTL::ExitThunkGenerator::emitThunk):
* ftl/FTLOSRExit.cpp:
(JSC::FTL::OSRExitDescriptor::OSRExitDescriptor):
(JSC::FTL::OSRExitDescriptor::isExceptionHandler):
(JSC::FTL::OSRExit::OSRExit):
(JSC::FTL::OSRExit::spillRegistersToSpillSlot):
(JSC::FTL::OSRExit::recoverRegistersFromSpillSlot):
(JSC::FTL::OSRExit::willArriveAtExitFromIndirectExceptionCheck):
(JSC::FTL::OSRExit::willArriveAtOSRExitFromGenericUnwind):
(JSC::FTL::OSRExit::willArriveAtOSRExitFromCallOperation):
(JSC::FTL::OSRExit::needsRegisterRecoveryOnGenericUnwindOSRExitPath):
(JSC::FTL::OSRExitDescriptor::willArriveAtExitFromIndirectExceptionCheck): Deleted.
(JSC::FTL::OSRExitDescriptor::mightArriveAtOSRExitFromGenericUnwind): Deleted.
(JSC::FTL::OSRExitDescriptor::mightArriveAtOSRExitFromCallOperation): Deleted.
(JSC::FTL::OSRExitDescriptor::needsRegisterRecoveryOnGenericUnwindOSRExitPath): Deleted.
* ftl/FTLOSRExit.h:
* ftl/FTLOSRExitCompilationInfo.h:
(JSC::FTL::OSRExitCompilationInfo::OSRExitCompilationInfo):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileFTLOSRExit):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExceptionHandlerManagercpp">trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExceptionHandlerManagerh">trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLExitThunkGeneratorcpp">trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -1,3 +1,43 @@
</span><ins>+2015-11-30  Saam barati  &lt;sbarati@apple.com&gt;
+
+        FTL OSR Exits that are exception handlers should not have two different entrances. Instead, we should have two discrete OSR exits that do different things.
+        https://bugs.webkit.org/show_bug.cgi?id=151404
+
+        Reviewed by Filip Pizlo.
+
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::mmAllocateDataSection):
+        * ftl/FTLExceptionHandlerManager.cpp:
+        (JSC::FTL::ExceptionHandlerManager::addNewExit):
+        (JSC::FTL::ExceptionHandlerManager::addNewCallOperationExit):
+        (JSC::FTL::ExceptionHandlerManager::callOperationExceptionTarget):
+        (JSC::FTL::ExceptionHandlerManager::lazySlowPathExceptionTarget):
+        (JSC::FTL::ExceptionHandlerManager::callOperationOSRExit):
+        (JSC::FTL::ExceptionHandlerManager::getByIdOSRExit): Deleted.
+        (JSC::FTL::ExceptionHandlerManager::subOSRExit): Deleted.
+        * ftl/FTLExceptionHandlerManager.h:
+        * ftl/FTLExitThunkGenerator.cpp:
+        (JSC::FTL::ExitThunkGenerator::emitThunk):
+        * ftl/FTLOSRExit.cpp:
+        (JSC::FTL::OSRExitDescriptor::OSRExitDescriptor):
+        (JSC::FTL::OSRExitDescriptor::isExceptionHandler):
+        (JSC::FTL::OSRExit::OSRExit):
+        (JSC::FTL::OSRExit::spillRegistersToSpillSlot):
+        (JSC::FTL::OSRExit::recoverRegistersFromSpillSlot):
+        (JSC::FTL::OSRExit::willArriveAtExitFromIndirectExceptionCheck):
+        (JSC::FTL::OSRExit::willArriveAtOSRExitFromGenericUnwind):
+        (JSC::FTL::OSRExit::willArriveAtOSRExitFromCallOperation):
+        (JSC::FTL::OSRExit::needsRegisterRecoveryOnGenericUnwindOSRExitPath):
+        (JSC::FTL::OSRExitDescriptor::willArriveAtExitFromIndirectExceptionCheck): Deleted.
+        (JSC::FTL::OSRExitDescriptor::mightArriveAtOSRExitFromGenericUnwind): Deleted.
+        (JSC::FTL::OSRExitDescriptor::mightArriveAtOSRExitFromCallOperation): Deleted.
+        (JSC::FTL::OSRExitDescriptor::needsRegisterRecoveryOnGenericUnwindOSRExitPath): Deleted.
+        * ftl/FTLOSRExit.h:
+        * ftl/FTLOSRExitCompilationInfo.h:
+        (JSC::FTL::OSRExitCompilationInfo::OSRExitCompilationInfo):
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileFTLOSRExit):
+
</ins><span class="cx"> 2015-11-30  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Refactor the op_add, op_sub, and op_mul snippets to use the SnippetOperand class.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -643,13 +643,40 @@
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             OSRExit&amp; exit = state.jitCode-&gt;osrExit.last();
</span><del>-            if (exitDescriptor.willArriveAtExitFromIndirectExceptionCheck()) {
</del><ins>+            if (exit.willArriveAtExitFromIndirectExceptionCheck()) {
</ins><span class="cx">                 StackMaps::Record&amp; record = iter-&gt;value[j].record;
</span><span class="cx">                 RELEASE_ASSERT(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader.isSet());
</span><span class="cx">                 CallSiteIndex callSiteIndex = state.jitCode-&gt;common.addUniqueCallSiteIndex(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader);
</span><span class="cx">                 exit.m_exceptionHandlerCallSiteIndex = callSiteIndex;
</span><del>-                exceptionHandlerManager.addNewExit(iter-&gt;value[j].index, state.jitCode-&gt;osrExit.size() - 1);
</del><span class="cx"> 
</span><ins>+                OSRExit* callOperationExit = nullptr;
+                if (exitDescriptor.m_exceptionType == ExceptionType::SubGenerator) {
+                    exceptionHandlerManager.addNewCallOperationExit(iter-&gt;value[j].index, state.jitCode-&gt;osrExit.size() - 1);
+                    callOperationExit = &amp;exit;
+                } else
+                    exceptionHandlerManager.addNewExit(iter-&gt;value[j].index, state.jitCode-&gt;osrExit.size() - 1);
+                
+                if (exitDescriptor.m_exceptionType == ExceptionType::GetById || exitDescriptor.m_exceptionType == ExceptionType::PutById) {
+                    // We create two different OSRExits for GetById and PutById.
+                    // One exit that will be arrived at from the genericUnwind exception handler path,
+                    // and the other that will be arrived at from the callOperation exception handler path.
+                    // This code here generates the second callOperation variant.
+                    uint32_t stackmapRecordIndex = iter-&gt;value[j].index;
+                    OSRExit exit(exitDescriptor, stackmapRecordIndex);
+                    if (exitDescriptor.m_exceptionType == ExceptionType::GetById)
+                        exit.m_exceptionType = ExceptionType::GetByIdCallOperation;
+                    else
+                        exit.m_exceptionType = ExceptionType::PutByIdCallOperation;
+                    CallSiteIndex callSiteIndex = state.jitCode-&gt;common.addUniqueCallSiteIndex(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader);
+                    exit.m_exceptionHandlerCallSiteIndex = callSiteIndex;
+
+                    state.jitCode-&gt;osrExit.append(exit);
+                    state.finalizer-&gt;osrExit.append(OSRExitCompilationInfo());
+
+                    exceptionHandlerManager.addNewCallOperationExit(iter-&gt;value[j].index, state.jitCode-&gt;osrExit.size() - 1);
+                    callOperationExit = &amp;state.jitCode-&gt;osrExit.last();
+                }
+
</ins><span class="cx">                 // Subs and GetByIds have an interesting register preservation story,
</span><span class="cx">                 // see comment below at GetById to read about it.
</span><span class="cx">                 //
</span><span class="lines">@@ -666,13 +693,13 @@
</span><span class="cx">                     GPRReg result = record.locations[0].directGPR();
</span><span class="cx">                     GPRReg base = record.locations[1].directGPR();
</span><span class="cx">                     if (base == result)
</span><del>-                        exit.registersToPreserveForCallThatMightThrow.set(base);
</del><ins>+                        callOperationExit-&gt;registersToPreserveForCallThatMightThrow.set(base);
</ins><span class="cx">                 } else if (exitDescriptor.m_exceptionType == ExceptionType::SubGenerator) {
</span><span class="cx">                     GPRReg result = record.locations[0].directGPR();
</span><span class="cx">                     GPRReg left = record.locations[1].directGPR();
</span><span class="cx">                     GPRReg right = record.locations[2].directGPR();
</span><span class="cx">                     if (result == left || result == right)
</span><del>-                        exit.registersToPreserveForCallThatMightThrow.set(result);
</del><ins>+                        callOperationExit-&gt;registersToPreserveForCallThatMightThrow.set(result);
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -703,7 +730,7 @@
</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><span class="cx"> 
</span><del>-            if (exit.m_descriptor.mightArriveAtOSRExitFromGenericUnwind()) {
</del><ins>+            if (exit.willArriveAtOSRExitFromGenericUnwind()) {
</ins><span class="cx">                 HandlerInfo newHandler = exit.m_descriptor.m_baselineExceptionHandler;
</span><span class="cx">                 newHandler.start = exit.m_exceptionHandlerCallSiteIndex.bits();
</span><span class="cx">                 newHandler.end = exit.m_exceptionHandlerCallSiteIndex.bits() + 1;
</span><span class="lines">@@ -781,7 +808,7 @@
</span><span class="cx">                     // register that we would like to do value recovery on. We combat this situation from ever
</span><span class="cx">                     // taking place by ensuring we spill the original base value and then recover it from
</span><span class="cx">                     // the spill slot as the first step in OSR exit.
</span><del>-                    if (OSRExit* exit = exceptionHandlerManager.getByIdOSRExit(iter-&gt;value[i].index))
</del><ins>+                    if (OSRExit* exit = exceptionHandlerManager.callOperationOSRExit(iter-&gt;value[i].index))
</ins><span class="cx">                         exit-&gt;spillRegistersToSpillSlot(slowPathJIT, jsCallThatMightThrowSpillOffset);
</span><span class="cx">                 }
</span><span class="cx">                 MacroAssembler::Call call = callOperation(
</span><span class="lines">@@ -900,7 +927,7 @@
</span><span class="cx">                 if (result == left || result == right) {
</span><span class="cx">                     // This situation has a really interesting register preservation story.
</span><span class="cx">                     // See comment above for GetByIds.
</span><del>-                    if (OSRExit* exit = exceptionHandlerManager.subOSRExit(iter-&gt;value[i].index))
</del><ins>+                    if (OSRExit* exit = exceptionHandlerManager.callOperationOSRExit(iter-&gt;value[i].index))
</ins><span class="cx">                         exit-&gt;spillRegistersToSpillSlot(slowPathJIT, jsCallThatMightThrowSpillOffset);
</span><span class="cx">                 }
</span><span class="cx"> 
</span><span class="lines">@@ -1099,7 +1126,7 @@
</span><span class="cx">         OSRExit&amp; exit = jitCode-&gt;osrExit[exitIndex];
</span><span class="cx">         Vector&lt;const void*&gt; codeAddresses;
</span><span class="cx"> 
</span><del>-        if (exit.m_descriptor.willArriveAtExitFromIndirectExceptionCheck()) // This jump doesn't happen directly from a patchpoint/stackmap we compile. It happens indirectly through an exception check somewhere.
</del><ins>+        if (exit.willArriveAtExitFromIndirectExceptionCheck()) // This jump doesn't happen directly from a patchpoint/stackmap we compile. It happens indirectly through an exception check somewhere.
</ins><span class="cx">             continue;
</span><span class="cx">         
</span><span class="cx">         StackMaps::Record&amp; record = jitCode-&gt;stackmaps.records[exit.m_stackmapRecordIndex];
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExceptionHandlerManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -41,9 +41,16 @@
</span><span class="cx"> {
</span><span class="cx">     m_map.add(stackmapRecordIndex, osrExitIndex);
</span><span class="cx">     OSRExit&amp; exit = m_state.jitCode-&gt;osrExit[osrExitIndex];
</span><del>-    RELEASE_ASSERT(exit.m_descriptor.willArriveAtExitFromIndirectExceptionCheck());
</del><ins>+    RELEASE_ASSERT(exit.willArriveAtExitFromIndirectExceptionCheck());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ExceptionHandlerManager::addNewCallOperationExit(uint32_t stackmapRecordIndex, size_t osrExitIndex)
+{
+    m_callOperationMap.add(stackmapRecordIndex, osrExitIndex);
+    OSRExit&amp; exit = m_state.jitCode-&gt;osrExit[osrExitIndex];
+    RELEASE_ASSERT(exit.willArriveAtExitFromIndirectExceptionCheck());
+}
+
</ins><span class="cx"> CodeLocationLabel ExceptionHandlerManager::callOperationExceptionTarget(uint32_t stackmapRecordIndex)
</span><span class="cx"> {
</span><span class="cx"> #if FTL_USES_B3
</span><span class="lines">@@ -51,15 +58,15 @@
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     return CodeLocationLabel();
</span><span class="cx"> #else // FTL_USES_B3
</span><del>-    auto findResult = m_map.find(stackmapRecordIndex);
-    if (findResult == m_map.end())
</del><ins>+    auto findResult = m_callOperationMap.find(stackmapRecordIndex);
+    if (findResult == m_callOperationMap.end())
</ins><span class="cx">         return CodeLocationLabel();
</span><span class="cx"> 
</span><span class="cx">     size_t osrExitIndex = findResult-&gt;value;
</span><del>-    RELEASE_ASSERT(m_state.jitCode-&gt;osrExit[osrExitIndex].m_descriptor.mightArriveAtOSRExitFromCallOperation());
</del><ins>+    RELEASE_ASSERT(m_state.jitCode-&gt;osrExit[osrExitIndex].willArriveAtOSRExitFromCallOperation());
</ins><span class="cx">     OSRExitCompilationInfo&amp; info = m_state.finalizer-&gt;osrExit[osrExitIndex];
</span><del>-    RELEASE_ASSERT(info.m_callOperationExceptionOSRExitEntrance.isSet());
-    return m_state.finalizer-&gt;exitThunksLinkBuffer-&gt;locationOf(info.m_callOperationExceptionOSRExitEntrance);
</del><ins>+    RELEASE_ASSERT(info.m_thunkLabel.isSet());
+    return m_state.finalizer-&gt;exitThunksLinkBuffer-&gt;locationOf(info.m_thunkLabel);
</ins><span class="cx"> #endif // FTL_USES_B3
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -82,28 +89,19 @@
</span><span class="cx"> #endif // FTL_USES_B3
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-OSRExit* ExceptionHandlerManager::getByIdOSRExit(uint32_t stackmapRecordIndex)
</del><ins>+OSRExit* ExceptionHandlerManager::callOperationOSRExit(uint32_t stackmapRecordIndex)
</ins><span class="cx"> {
</span><del>-    auto findResult = m_map.find(stackmapRecordIndex);
-    if (findResult == m_map.end())
</del><ins>+    auto findResult = m_callOperationMap.find(stackmapRecordIndex);
+    if (findResult == m_callOperationMap.end())
</ins><span class="cx">         return nullptr;
</span><span class="cx">     size_t osrExitIndex = findResult-&gt;value;
</span><span class="cx">     OSRExit* exit = &amp;m_state.jitCode-&gt;osrExit[osrExitIndex];
</span><del>-    RELEASE_ASSERT(exit-&gt;m_descriptor.m_exceptionType == ExceptionType::GetById);
</del><ins>+    // We may have more than one exit for the same stackmap record index (i.e, for GetByIds and PutByIds).
+    // Therefore we need to make sure this exit really is a callOperation OSR exit.
+    RELEASE_ASSERT(exit-&gt;willArriveAtOSRExitFromCallOperation());
</ins><span class="cx">     return exit; 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-OSRExit* ExceptionHandlerManager::subOSRExit(uint32_t stackmapRecordIndex)
-{
-    auto findResult = m_map.find(stackmapRecordIndex);
-    if (findResult == m_map.end())
-        return nullptr;
-    size_t osrExitIndex = findResult-&gt;value;
-    OSRExit* exit = &amp;m_state.jitCode-&gt;osrExit[osrExitIndex];
-    RELEASE_ASSERT(exit-&gt;m_descriptor.m_exceptionType == ExceptionType::SubGenerator);
-    return exit; 
-}
-
</del><span class="cx"> OSRExit* ExceptionHandlerManager::getCallOSRExitCommon(uint32_t stackmapRecordIndex)
</span><span class="cx"> {
</span><span class="cx">     auto findResult = m_map.find(stackmapRecordIndex);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExceptionHandlerManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -54,14 +54,14 @@
</span><span class="cx">     ExceptionHandlerManager(State&amp; state);
</span><span class="cx"> 
</span><span class="cx">     void addNewExit(uint32_t stackmapRecordIndex, size_t osrExitIndex);
</span><ins>+    void addNewCallOperationExit(uint32_t stackmapRecordIndex, size_t osrExitIndex);
</ins><span class="cx"> 
</span><span class="cx">     // These functions only make sense to be called after we've generated the OSR
</span><span class="cx">     // exit thunks and allocated the OSR exit thunks' link buffer.
</span><span class="cx">     CodeLocationLabel callOperationExceptionTarget(uint32_t stackmapRecordIndex);
</span><span class="cx">     CodeLocationLabel lazySlowPathExceptionTarget(uint32_t stackmapRecordIndex);
</span><span class="cx"> 
</span><del>-    OSRExit* getByIdOSRExit(uint32_t stackmapRecordIndex);
-    OSRExit* subOSRExit(uint32_t stackmapRecordIndex);
</del><ins>+    OSRExit* callOperationOSRExit(uint32_t stackmapRecordIndex);
</ins><span class="cx">     OSRExit* getCallOSRExit(uint32_t stackmapRecordIndex, const JSCall&amp;);
</span><span class="cx">     OSRExit* getCallOSRExit(uint32_t stackmapRecordIndex, const JSTailCall&amp;);
</span><span class="cx">     OSRExit* getCallOSRExit(uint32_t stackmapRecordIndex, const JSCallVarargs&amp;);
</span><span class="lines">@@ -78,6 +78,7 @@
</span><span class="cx">     State&amp; m_state;
</span><span class="cx">     typedef HashMap&lt;uint32_t, size_t, WTF::IntHash&lt;uint32_t&gt;, WTF::UnsignedWithZeroKeyHashTraits&lt;uint32_t&gt;&gt; RecordIndexToOSRExitIndexMap;
</span><span class="cx">     RecordIndexToOSRExitIndexMap m_map;
</span><ins>+    RecordIndexToOSRExitIndexMap m_callOperationMap;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLExitThunkGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -53,27 +53,18 @@
</span><span class="cx">     
</span><span class="cx">     info.m_thunkLabel = label();
</span><span class="cx"> 
</span><del>-    Jump jumpToPushIndexFromGenericUnwind;
-    if (exit.m_descriptor.mightArriveAtOSRExitFromGenericUnwind()) {
</del><ins>+    ASSERT(!(exit.willArriveAtOSRExitFromGenericUnwind() &amp;&amp; exit.willArriveAtOSRExitFromCallOperation()));
+    if (exit.willArriveAtOSRExitFromGenericUnwind()) {
</ins><span class="cx">         restoreCalleeSavesFromVMCalleeSavesBuffer();
</span><span class="cx">         loadPtr(vm()-&gt;addressOfCallFrameForCatch(), framePointerRegister);
</span><span class="cx">         addPtr(TrustedImm32(- static_cast&lt;int64_t&gt;(m_state.jitCode-&gt;stackmaps.stackSizeForLocals())), 
</span><span class="cx">             framePointerRegister, stackPointerRegister);
</span><span class="cx"> 
</span><del>-        if (exit.m_descriptor.needsRegisterRecoveryOnGenericUnwindOSRExitPath())
</del><ins>+        if (exit.needsRegisterRecoveryOnGenericUnwindOSRExitPath())
</ins><span class="cx">             exit.recoverRegistersFromSpillSlot(*this, osrExitFromGenericUnwindStackSpillSlot);
</span><del>-
-        jumpToPushIndexFromGenericUnwind = jump();
-    }
-
-    if (exit.m_descriptor.mightArriveAtOSRExitFromCallOperation()) {
-        info.m_callOperationExceptionOSRExitEntrance = label();
</del><ins>+    } else if (exit.willArriveAtOSRExitFromCallOperation())
</ins><span class="cx">         exit.recoverRegistersFromSpillSlot(*this, osrExitFromGenericUnwindStackSpillSlot);
</span><del>-    }
</del><span class="cx">     
</span><del>-    if (exit.m_descriptor.mightArriveAtOSRExitFromGenericUnwind())
-        jumpToPushIndexFromGenericUnwind.link(this);
-
</del><span class="cx">     pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32(index));
</span><span class="cx">     info.m_thunkJump = patchableJump();
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -56,62 +56,6 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool OSRExitDescriptor::willArriveAtExitFromIndirectExceptionCheck() const
-{
-    switch (m_exceptionType) {
-    case ExceptionType::JSCall:
-    case ExceptionType::GetById:
-    case ExceptionType::PutById:
-    case ExceptionType::LazySlowPath:
-    case ExceptionType::SubGenerator:
-        return true;
-    default:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-}
-
-bool OSRExitDescriptor::mightArriveAtOSRExitFromGenericUnwind() const
-{
-    switch (m_exceptionType) {
-    case ExceptionType::JSCall:
-    case ExceptionType::GetById:
-    case ExceptionType::PutById:
-        return true;
-    default:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-}
-
-bool OSRExitDescriptor::mightArriveAtOSRExitFromCallOperation() const
-{
-    switch (m_exceptionType) {
-    case ExceptionType::GetById:
-    case ExceptionType::PutById:
-    case ExceptionType::SubGenerator:
-        return true;
-    default:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-}
-
-bool OSRExitDescriptor::needsRegisterRecoveryOnGenericUnwindOSRExitPath() const
-{
-    // Calls/PutByIds/GetByIds all have a generic unwind osr exit paths.
-    // But, GetById and PutById ICs will do register recovery themselves
-    // because they're responsible for spilling necessary registers, so
-    // they also must recover registers themselves.
-    // Calls don't work this way. We compile Calls as patchpoints in LLVM.
-    // A call patchpoint might pass us volatile registers for locations
-    // we will do value recovery on. Therefore, before we make the call,
-    // we must spill these registers. Otherwise, the call will clobber them.
-    // Therefore, the corresponding OSR exit for the call will need to
-    // recover the spilled registers.
-    return m_exceptionType == ExceptionType::JSCall;
-}
-
</del><span class="cx"> bool OSRExitDescriptor::isExceptionHandler() const
</span><span class="cx"> {
</span><span class="cx">     return m_exceptionType != ExceptionType::None;
</span><span class="lines">@@ -131,6 +75,7 @@
</span><span class="cx">     : OSRExitBase(descriptor.m_kind, descriptor.m_codeOrigin, descriptor.m_codeOriginForExitProfile)
</span><span class="cx">     , m_descriptor(descriptor)
</span><span class="cx">     , m_stackmapRecordIndex(stackmapRecordIndex)
</span><ins>+    , m_exceptionType(descriptor.m_exceptionType)
</ins><span class="cx"> {
</span><span class="cx">     m_isExceptionHandler = descriptor.isExceptionHandler();
</span><span class="cx"> }
</span><span class="lines">@@ -186,7 +131,7 @@
</span><span class="cx"> 
</span><span class="cx"> void OSRExit::spillRegistersToSpillSlot(CCallHelpers&amp; jit, int32_t stackSpillSlot)
</span><span class="cx"> {
</span><del>-    RELEASE_ASSERT(m_descriptor.mightArriveAtOSRExitFromGenericUnwind() || m_descriptor.mightArriveAtOSRExitFromCallOperation());
</del><ins>+    RELEASE_ASSERT(willArriveAtOSRExitFromGenericUnwind() || willArriveAtOSRExitFromCallOperation());
</ins><span class="cx">     unsigned count = 0;
</span><span class="cx">     for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
</span><span class="cx">         if (registersToPreserveForCallThatMightThrow.get(reg)) {
</span><span class="lines">@@ -204,7 +149,7 @@
</span><span class="cx"> 
</span><span class="cx"> void OSRExit::recoverRegistersFromSpillSlot(CCallHelpers&amp; jit, int32_t stackSpillSlot)
</span><span class="cx"> {
</span><del>-    RELEASE_ASSERT(m_descriptor.mightArriveAtOSRExitFromGenericUnwind() || m_descriptor.mightArriveAtOSRExitFromCallOperation());
</del><ins>+    RELEASE_ASSERT(willArriveAtOSRExitFromGenericUnwind() || willArriveAtOSRExitFromCallOperation());
</ins><span class="cx">     unsigned count = 0;
</span><span class="cx">     for (GPRReg reg = MacroAssembler::firstRegister(); reg &lt;= MacroAssembler::lastRegister(); reg = MacroAssembler::nextRegister(reg)) {
</span><span class="cx">         if (registersToPreserveForCallThatMightThrow.get(reg)) {
</span><span class="lines">@@ -220,6 +165,64 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool OSRExit::willArriveAtExitFromIndirectExceptionCheck() const
+{
+    switch (m_exceptionType) {
+    case ExceptionType::JSCall:
+    case ExceptionType::GetById:
+    case ExceptionType::PutById:
+    case ExceptionType::LazySlowPath:
+    case ExceptionType::SubGenerator:
+    case ExceptionType::GetByIdCallOperation:
+    case ExceptionType::PutByIdCallOperation:
+        return true;
+    default:
+        return false;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool OSRExit::willArriveAtOSRExitFromGenericUnwind() const
+{
+    switch (m_exceptionType) {
+    case ExceptionType::JSCall:
+    case ExceptionType::GetById:
+    case ExceptionType::PutById:
+        return true;
+    default:
+        return false;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool OSRExit::willArriveAtOSRExitFromCallOperation() const
+{
+    switch (m_exceptionType) {
+    case ExceptionType::GetByIdCallOperation:
+    case ExceptionType::PutByIdCallOperation:
+    case ExceptionType::SubGenerator:
+        return true;
+    default:
+        return false;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool OSRExit::needsRegisterRecoveryOnGenericUnwindOSRExitPath() const
+{
+    // Calls/PutByIds/GetByIds all have a generic unwind osr exit paths.
+    // But, GetById and PutById ICs will do register recovery themselves
+    // because they're responsible for spilling necessary registers, so
+    // they also must recover registers themselves.
+    // Calls don't work this way. We compile Calls as patchpoints in LLVM.
+    // A call patchpoint might pass us volatile registers for locations
+    // we will do value recovery on. Therefore, before we make the call,
+    // we must spill these registers. Otherwise, the call will clobber them.
+    // Therefore, the corresponding OSR exit for the call will need to
+    // recover the spilled registers.
+    return m_exceptionType == ExceptionType::JSCall;
+}
+
</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 (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -136,14 +136,16 @@
</span><span class="cx"> //   intrinsics (or meta-data, or something) to inform the backend that it's safe to
</span><span class="cx"> //   make the predicate passed to 'exitIf()' more truthy.
</span><span class="cx"> 
</span><del>-enum class ExceptionType {
</del><ins>+enum class ExceptionType : uint8_t {
</ins><span class="cx">     None,
</span><span class="cx">     CCallException,
</span><span class="cx">     JSCall,
</span><span class="cx">     GetById,
</span><ins>+    GetByIdCallOperation,
</ins><span class="cx">     PutById,
</span><ins>+    PutByIdCallOperation,
</ins><span class="cx">     LazySlowPath,
</span><del>-    SubGenerator
</del><ins>+    SubGenerator,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct OSRExitDescriptor {
</span><span class="lines">@@ -152,10 +154,6 @@
</span><span class="cx">         CodeOrigin, CodeOrigin originForProfile,
</span><span class="cx">         unsigned numberOfArguments, unsigned numberOfLocals);
</span><span class="cx"> 
</span><del>-    bool willArriveAtExitFromIndirectExceptionCheck() const;
-    bool mightArriveAtOSRExitFromGenericUnwind() const;
-    bool mightArriveAtOSRExitFromCallOperation() const;
-    bool needsRegisterRecoveryOnGenericUnwindOSRExitPath() const;
</del><span class="cx">     bool isExceptionHandler() const;
</span><span class="cx"> 
</span><span class="cx">     ExitKind m_kind;
</span><span class="lines">@@ -191,6 +189,7 @@
</span><span class="cx">     unsigned m_patchableCodeOffset;
</span><span class="cx">     // Offset within Stackmap::records
</span><span class="cx">     uint32_t m_stackmapRecordIndex;
</span><ins>+    ExceptionType m_exceptionType;
</ins><span class="cx"> 
</span><span class="cx">     RegisterSet registersToPreserveForCallThatMightThrow;
</span><span class="cx"> 
</span><span class="lines">@@ -203,6 +202,11 @@
</span><span class="cx">     void gatherRegistersToSpillForCallIfException(StackMaps&amp;, StackMaps::Record&amp;);
</span><span class="cx">     void spillRegistersToSpillSlot(CCallHelpers&amp;, int32_t stackSpillSlot);
</span><span class="cx">     void recoverRegistersFromSpillSlot(CCallHelpers&amp; jit, int32_t stackSpillSlot);
</span><ins>+
+    bool willArriveAtOSRExitFromGenericUnwind() const;
+    bool willArriveAtExitFromIndirectExceptionCheck() const;
+    bool willArriveAtOSRExitFromCallOperation() const;
+    bool needsRegisterRecoveryOnGenericUnwindOSRExitPath() const;
</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 (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompilationInfo.h        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -39,7 +39,6 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     MacroAssembler::Label m_thunkLabel;
</span><del>-    MacroAssembler::Label m_callOperationExceptionOSRExitEntrance;
</del><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 (192844 => 192845)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp        2015-12-01 00:33:47 UTC (rev 192844)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp        2015-12-01 00:55:32 UTC (rev 192845)
</span><span class="lines">@@ -547,7 +547,7 @@
</span><span class="cx">         dataLog(&quot;    Exit stackmap ID: &quot;, exit.m_descriptor.m_stackmapID, &quot;\n&quot;);
</span><span class="cx">         dataLog(&quot;    Current call site index: &quot;, exec-&gt;callSiteIndex().bits(), &quot;\n&quot;);
</span><span class="cx">         dataLog(&quot;    Exit is exception handler: &quot;, exit.m_isExceptionHandler,
</span><del>-            &quot; might arrive at exit from genericUnwind(): &quot;, exit.m_descriptor.mightArriveAtOSRExitFromGenericUnwind(), 
</del><ins>+            &quot; will arrive at exit from genericUnwind(): &quot;, exit.willArriveAtOSRExitFromGenericUnwind(), 
</ins><span class="cx">             &quot; will arrive at exit from lazy slow path: &quot;, exit.m_descriptor.m_exceptionType == ExceptionType::LazySlowPath, &quot;\n&quot;);
</span><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></pre>
</div>
</div>

</body>
</html>