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

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

<h3>Log Message</h3>
<pre>[JSC] Inlining Getter/Setter should care availability of ad-hocly constructed frame
https://bugs.webkit.org/show_bug.cgi?id=197405

Reviewed by Saam Barati.

JSTests:

* stress/getter-setter-inlining-should-emit-movhint.js: Added.
(foo):
(test):
(i.o.get f):
(i.o.set f):

Source/JavaScriptCore:

When inlining getter and setter calls, we setup a stack frame which does not appear in the bytecode.
Because Inlining can switch on executable, we could have a graph like this.

BB#0
    ...
    30: GetSetter
    31: MovHint(loc10)
    32: SetLocal(loc10)
    33: MovHint(loc9)
    34: SetLocal(loc9)
    ...
    37: GetExecutable(@30)
    ...
    41: Switch(@37)

BB#2
    42: GetLocal(loc12, bc#7 of caller)
    ...
    --> callee: loc9 and loc10 are arguments of callee.
      ...
      <HERE, exit to callee, loc9 and loc10 are required in the bytecode>

When we prune OSR availability at the beginning of BB#2 (bc#7 in the caller), we prune loc9 and loc10's liveness because the caller does not actually have loc9 and loc10.
However, when we begin executing the callee, we need OSR exit to be aware of where it can recover the arguments to the setter, loc9 and loc10.

This patch inserts MovHint at the beginning of callee for a getter / setter stack frame to make arguments (loc9 and loc10 in the above example) recoverable from OSR exit.
We also move arity fixup DFG nodes from the caller to the callee, since moved arguments are not live in the caller too.

Interestingly, this fix also reveals the existing issue in LiveCatchVariablePreservationPhase. We emitted Flush for |this| of InlineCallFrame blindly if we saw InlineCallFrame
inside a block which is covered by catch handler. But this is wrong because inlined function can finish its execution within the block, and |this| is completely unrelated to
the catch handler if the catch handler is in the outer callee. We already collect all the live locals at the catch handler. And this locals must include arguments too if the
catch handler is in inlined function. So, we should not emit Flush for each |this| of seen InlineCallFrame. This emitted Flush may connect unrelated locals in the catch handler
to the locals that is only defined and used in the inlined function, and it leads to the results like DFG says the local is live while the bytecode says the local is dead.
This results in reading and using garbage in OSR entry because DFG OSR entry needs to fill live DFG values from the stack.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::inlineCall):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::handlePutById):
* dfg/DFGLiveCatchVariablePreservationPhase.cpp:
(JSC::DFG::LiveCatchVariablePreservationPhase::handleBlockForTryCatch):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGLiveCatchVariablePreservationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressgettersetterinliningshouldemitmovhintjs">trunk/JSTests/stress/getter-setter-inlining-should-emit-movhint.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (244863 => 244864)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2019-05-02 02:20:51 UTC (rev 244863)
+++ trunk/JSTests/ChangeLog     2019-05-02 02:40:44 UTC (rev 244864)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2019-05-01  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Inlining Getter/Setter should care availability of ad-hocly constructed frame
+        https://bugs.webkit.org/show_bug.cgi?id=197405
+
+        Reviewed by Saam Barati.
+
+        * stress/getter-setter-inlining-should-emit-movhint.js: Added.
+        (foo):
+        (test):
+        (i.o.get f):
+        (i.o.set f):
+
</ins><span class="cx"> 2019-05-01  Michael Saboff  <msaboff@apple.com>
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: !m_needExceptionCheck with --validateExceptionChecks=1; ProxyObject.getOwnPropertySlotCommon/JSFunction.callerGetter
</span></span></pre></div>
<a id="trunkJSTestsstressgettersetterinliningshouldemitmovhintjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/getter-setter-inlining-should-emit-movhint.js (0 => 244864)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/getter-setter-inlining-should-emit-movhint.js                               (rev 0)
+++ trunk/JSTests/stress/getter-setter-inlining-should-emit-movhint.js  2019-05-02 02:40:44 UTC (rev 244864)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+//@ runDefault("--useRandomizingFuzzerAgent=1", "--usePolymorphicCallInliningForNonStubStatus=1", "--seedOfRandomizingFuzzerAgent=2896922505", "--useLLInt=0", "--useConcurrentJIT=0")
+function foo(o) {
+    o.f = 0;
+    return o.f;
+}
+noInline(foo);
+
+let counter = 0;
+
+function test(o, value) {
+    var result = foo(o);
+    if (result < value)
+        throw new Error(result);
+    if (counter < value)
+        throw new Error(counter);
+    Array.of(arguments);
+}
+
+for (var i = 0; i < 100000; ++i) {
+    var o = {
+        get f() {
+            return o
+        },
+        set f(v) {
+            counter++;
+            this.z = 0;
+        }
+    };
+    test(o, i, i);
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (244863 => 244864)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2019-05-02 02:20:51 UTC (rev 244863)
+++ trunk/Source/JavaScriptCore/ChangeLog       2019-05-02 02:40:44 UTC (rev 244864)
</span><span class="lines">@@ -1,3 +1,52 @@
</span><ins>+2019-05-01  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Inlining Getter/Setter should care availability of ad-hocly constructed frame
+        https://bugs.webkit.org/show_bug.cgi?id=197405
+
+        Reviewed by Saam Barati.
+
+        When inlining getter and setter calls, we setup a stack frame which does not appear in the bytecode.
+        Because Inlining can switch on executable, we could have a graph like this.
+
+        BB#0
+            ...
+            30: GetSetter
+            31: MovHint(loc10)
+            32: SetLocal(loc10)
+            33: MovHint(loc9)
+            34: SetLocal(loc9)
+            ...
+            37: GetExecutable(@30)
+            ...
+            41: Switch(@37)
+
+        BB#2
+            42: GetLocal(loc12, bc#7 of caller)
+            ...
+            --> callee: loc9 and loc10 are arguments of callee.
+              ...
+              <HERE, exit to callee, loc9 and loc10 are required in the bytecode>
+
+        When we prune OSR availability at the beginning of BB#2 (bc#7 in the caller), we prune loc9 and loc10's liveness because the caller does not actually have loc9 and loc10.
+        However, when we begin executing the callee, we need OSR exit to be aware of where it can recover the arguments to the setter, loc9 and loc10.
+
+        This patch inserts MovHint at the beginning of callee for a getter / setter stack frame to make arguments (loc9 and loc10 in the above example) recoverable from OSR exit.
+        We also move arity fixup DFG nodes from the caller to the callee, since moved arguments are not live in the caller too.
+
+        Interestingly, this fix also reveals the existing issue in LiveCatchVariablePreservationPhase. We emitted Flush for |this| of InlineCallFrame blindly if we saw InlineCallFrame
+        inside a block which is covered by catch handler. But this is wrong because inlined function can finish its execution within the block, and |this| is completely unrelated to
+        the catch handler if the catch handler is in the outer callee. We already collect all the live locals at the catch handler. And this locals must include arguments too if the
+        catch handler is in inlined function. So, we should not emit Flush for each |this| of seen InlineCallFrame. This emitted Flush may connect unrelated locals in the catch handler
+        to the locals that is only defined and used in the inlined function, and it leads to the results like DFG says the local is live while the bytecode says the local is dead.
+        This results in reading and using garbage in OSR entry because DFG OSR entry needs to fill live DFG values from the stack.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::inlineCall):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::handlePutById):
+        * dfg/DFGLiveCatchVariablePreservationPhase.cpp:
+        (JSC::DFG::LiveCatchVariablePreservationPhase::handleBlockForTryCatch):
+
</ins><span class="cx"> 2019-05-01  Michael Saboff  <msaboff@apple.com>
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: !m_needExceptionCheck with --validateExceptionChecks=1; ProxyObject.getOwnPropertySlotCommon/JSFunction.callerGetter
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (244863 => 244864)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp    2019-05-02 02:20:51 UTC (rev 244863)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp       2019-05-02 02:40:44 UTC (rev 244864)
</span><span class="lines">@@ -1608,22 +1608,69 @@
</span><span class="cx">         calleeVariable->mergeShouldNeverUnbox(true);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    InlineStackEntry* callerStackTop = m_inlineStackTop;
+    InlineStackEntry inlineStackEntry(this, codeBlock, codeBlock, callee.function(), result,
+        (VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind, continuationBlock);
+
+    // This is where the actual inlining really happens.
+    unsigned oldIndex = m_currentIndex;
+    m_currentIndex = 0;
+
+    switch (kind) {
+    case InlineCallFrame::GetterCall:
+    case InlineCallFrame::SetterCall: {
+        // When inlining getter and setter calls, we setup a stack frame which does not appear in the bytecode.
+        // Because Inlining can switch on executable, we could have a graph like this.
+        //
+        // BB#0
+        //     ...
+        //     30: GetSetter
+        //     31: MovHint(loc10)
+        //     32: SetLocal(loc10)
+        //     33: MovHint(loc9)
+        //     34: SetLocal(loc9)
+        //     ...
+        //     37: GetExecutable(@30)
+        //     ...
+        //     41: Switch(@37)
+        //
+        // BB#2
+        //     42: GetLocal(loc12, bc#7 of caller)
+        //     ...
+        //     --> callee: loc9 and loc10 are arguments of callee.
+        //       ...
+        //       <HERE, exit to callee, loc9 and loc10 are required in the bytecode>
+        //
+        // When we prune OSR availability at the beginning of BB#2 (bc#7 in the caller), we prune loc9 and loc10's liveness because the caller does not actually have loc9 and loc10.
+        // However, when we begin executing the callee, we need OSR exit to be aware of where it can recover the arguments to the setter, loc9 and loc10. The MovHints in the inlined
+        // callee make it so that if we exit at <HERE>, we can recover loc9 and loc10.
+        for (int index = 0; index < argumentCountIncludingThis; ++index) {
+            VirtualRegister argumentToGet = callerStackTop->remapOperand(virtualRegisterForArgument(index, registerOffset));
+            addToGraph(MovHint, OpInfo(argumentToGet.offset()), getDirect(argumentToGet));
+        }
+        break;
+    }
+    default:
+        break;
+    }
+
</ins><span class="cx">     if (arityFixupCount) {
</span><span class="cx">         // Note: we do arity fixup in two phases:
</span><span class="cx">         // 1. We get all the values we need and MovHint them to the expected locals.
</span><del>-        // 2. We SetLocal them inside the callee's CodeOrigin. This way, if we exit, the callee's
</del><ins>+        // 2. We SetLocal them after that. This way, if we exit, the callee's
</ins><span class="cx">         //    frame is already set up. If any SetLocal exits, we have a valid exit state.
</span><span class="cx">         //    This is required because if we didn't do this in two phases, we may exit in
</span><del>-        //    the middle of arity fixup from the caller's CodeOrigin. This is unsound because if
-        //    we did the SetLocals in the caller's frame, the memcpy may clobber needed parts
-        //    of the frame right before exiting. For example, consider if we need to pad two args:
</del><ins>+        //    the middle of arity fixup from the callee's CodeOrigin. This is unsound because exited
+        //    code does not have arity fixup so that remaining necessary fixups are not executed.
+        //    For example, consider if we need to pad two args:
</ins><span class="cx">         //    [arg3][arg2][arg1][arg0]
</span><span class="cx">         //    [fix ][fix ][arg3][arg2][arg1][arg0]
</span><span class="cx">         //    We memcpy starting from arg0 in the direction of arg3. If we were to exit at a type check
</span><del>-        //    for arg3's SetLocal in the caller's CodeOrigin, we'd exit with a frame like so:
</del><ins>+        //    for arg3's SetLocal in the callee's CodeOrigin, we'd exit with a frame like so:
</ins><span class="cx">         //    [arg3][arg2][arg1][arg2][arg1][arg0]
</span><del>-        //    And the caller would then just end up thinking its argument are:
-        //    [arg3][arg2][arg1][arg2]
</del><ins>+        //    Since we do not perform arity fixup in the callee, this is the frame used by the callee.
+        //    And the callee would then just end up thinking its argument are:
+        //    [fix ][fix ][arg3][arg2][arg1][arg0]
</ins><span class="cx">         //    which is incorrect.
</span><span class="cx"> 
</span><span class="cx">         Node* undefined = addToGraph(JSConstant, OpInfo(m_constantUndefined));
</span><span class="lines">@@ -1642,29 +1689,23 @@
</span><span class="cx">         // In such cases, we do not need to move frames.
</span><span class="cx">         if (registerOffsetAfterFixup != registerOffset) {
</span><span class="cx">             for (int index = 0; index < argumentCountIncludingThis; ++index) {
</span><del>-                Node* value = get(virtualRegisterForArgument(index, registerOffset));
-                VirtualRegister argumentToSet = m_inlineStackTop->remapOperand(virtualRegisterForArgument(index, registerOffsetAfterFixup));
</del><ins>+                VirtualRegister argumentToGet = callerStackTop->remapOperand(virtualRegisterForArgument(index, registerOffset));
+                Node* value = getDirect(argumentToGet);
+                VirtualRegister argumentToSet = m_inlineStackTop->remapOperand(virtualRegisterForArgument(index));
</ins><span class="cx">                 addToGraph(MovHint, OpInfo(argumentToSet.offset()), value);
</span><span class="cx">                 m_setLocalQueue.append(DelayedSetLocal { currentCodeOrigin(), argumentToSet, value, ImmediateNakedSet });
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         for (int index = 0; index < arityFixupCount; ++index) {
</span><del>-            VirtualRegister argumentToSet = m_inlineStackTop->remapOperand(virtualRegisterForArgument(argumentCountIncludingThis + index, registerOffsetAfterFixup));
</del><ins>+            VirtualRegister argumentToSet = m_inlineStackTop->remapOperand(virtualRegisterForArgument(argumentCountIncludingThis + index));
</ins><span class="cx">             addToGraph(MovHint, OpInfo(argumentToSet.offset()), undefined);
</span><span class="cx">             m_setLocalQueue.append(DelayedSetLocal { currentCodeOrigin(), argumentToSet, undefined, ImmediateNakedSet });
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // At this point, it's OK to OSR exit because we finished setting up
</span><del>-        // our callee's frame. We emit an ExitOK below from the callee's CodeOrigin.
</del><ins>+        // our callee's frame. We emit an ExitOK below.
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    InlineStackEntry inlineStackEntry(this, codeBlock, codeBlock, callee.function(), result,
-        (VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind, continuationBlock);
-
-    // This is where the actual inlining really happens.
-    unsigned oldIndex = m_currentIndex;
-    m_currentIndex = 0;
-
</del><span class="cx">     // At this point, it's again OK to OSR exit.
</span><span class="cx">     m_exitOK = true;
</span><span class="cx">     addToGraph(ExitOK);
</span><span class="lines">@@ -4371,8 +4412,7 @@
</span><span class="cx">     //    the dreaded arguments object on the getter, the right things happen. Well, sort of -
</span><span class="cx">     //    since we only really care about 'this' in this case. But we're not going to take that
</span><span class="cx">     //    shortcut.
</span><del>-    int nextRegister = registerOffset + CallFrame::headerSizeInRegisters;
-    set(VirtualRegister(nextRegister++), base, ImmediateNakedSet);
</del><ins>+    set(virtualRegisterForArgument(0, registerOffset), base, ImmediateNakedSet);
</ins><span class="cx"> 
</span><span class="cx">     // We've set some locals, but they are not user-visible. It's still OK to exit from here.
</span><span class="cx">     m_exitOK = true;
</span><span class="lines">@@ -4555,9 +4595,8 @@
</span><span class="cx">             m_inlineStackTop->remapOperand(
</span><span class="cx">                 VirtualRegister(registerOffset)).toLocal());
</span><span class="cx">     
</span><del>-        int nextRegister = registerOffset + CallFrame::headerSizeInRegisters;
-        set(VirtualRegister(nextRegister++), base, ImmediateNakedSet);
-        set(VirtualRegister(nextRegister++), value, ImmediateNakedSet);
</del><ins>+        set(virtualRegisterForArgument(0, registerOffset), base, ImmediateNakedSet);
+        set(virtualRegisterForArgument(1, registerOffset), value, ImmediateNakedSet);
</ins><span class="cx"> 
</span><span class="cx">         // We've set some locals, but they are not user-visible. It's still OK to exit from here.
</span><span class="cx">         m_exitOK = true;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGLiveCatchVariablePreservationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp (244863 => 244864)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp        2019-05-02 02:20:51 UTC (rev 244863)
+++ trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp   2019-05-02 02:40:44 UTC (rev 244864)
</span><span class="lines">@@ -157,14 +157,11 @@
</span><span class="cx">         };
</span><span class="cx"> 
</span><span class="cx">         Operands<VariableAccessData*> currentBlockAccessData(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr);
</span><del>-        HashSet<InlineCallFrame*> seenInlineCallFrames;
</del><span class="cx"> 
</span><span class="cx">         auto flushEverything = [&] (NodeOrigin origin, unsigned index) {
</span><span class="cx">             RELEASE_ASSERT(currentExceptionHandler);
</span><del>-            auto flush = [&] (VirtualRegister operand, bool alwaysInsert) {
-                if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()]) 
-                    || operand.isArgument()
-                    || alwaysInsert) {
</del><ins>+            auto flush = [&] (VirtualRegister operand) {
+                if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()]) || operand.isArgument()) {
</ins><span class="cx"> 
</span><span class="cx">                     ASSERT(isValidFlushLocation(block, index, operand));
</span><span class="cx"> 
</span><span class="lines">@@ -180,12 +177,8 @@
</span><span class="cx">             };
</span><span class="cx"> 
</span><span class="cx">             for (unsigned local = 0; local < block->variablesAtTail.numberOfLocals(); local++)
</span><del>-                flush(virtualRegisterForLocal(local), false);
-            for (InlineCallFrame* inlineCallFrame : seenInlineCallFrames)
-                flush(VirtualRegister(inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset()), true);
-            flush(VirtualRegister(CallFrame::thisArgumentOffset()), true);
-
-            seenInlineCallFrames.clear();
</del><ins>+                flush(virtualRegisterForLocal(local));
+            flush(VirtualRegister(CallFrame::thisArgumentOffset()));
</ins><span class="cx">         };
</span><span class="cx"> 
</span><span class="cx">         for (unsigned nodeIndex = 0; nodeIndex < block->size(); nodeIndex++) {
</span><span class="lines">@@ -199,16 +192,9 @@
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             if (currentExceptionHandler && (node->op() == SetLocal || node->op() == SetArgumentDefinitely || node->op() == SetArgumentMaybe)) {
</span><del>-                InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame();
-                if (inlineCallFrame)
-                    seenInlineCallFrames.add(inlineCallFrame);
</del><span class="cx">                 VirtualRegister operand = node->local();
</span><ins>+                if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()]) || operand.isArgument()) {
</ins><span class="cx"> 
</span><del>-                int stackOffset = inlineCallFrame ? inlineCallFrame->stackOffset : 0;
-                if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()])
-                    || operand.isArgument()
-                    || (operand.offset() == stackOffset + CallFrame::thisArgumentOffset())) {
-
</del><span class="cx">                     ASSERT(isValidFlushLocation(block, nodeIndex, operand));
</span><span class="cx"> 
</span><span class="cx">                     VariableAccessData* variableAccessData = currentBlockAccessData.operand(operand);
</span></span></pre>
</div>
</div>

</body>
</html>