<!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>[210010] 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/210010">210010</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2016-12-19 18:03:02 -0800 (Mon, 19 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Rolling out <a href="http://trac.webkit.org/projects/webkit/changeset/209974">r209974</a> and <a href="http://trac.webkit.org/projects/webkit/changeset/209952">r209952</a>. They break some websites in mysterious ways. Step 2: Rollout <a href="http://trac.webkit.org/projects/webkit/changeset/209952">r209952</a>.
https://bugs.webkit.org/show_bug.cgi?id=166049
Not reviewed.
JSTests:
* stress/deeply-nested-finallys.js: Removed.
* stress/test-finally.js: Removed.
Source/JavaScriptCore:
* bytecode/HandlerInfo.h:
(JSC::HandlerInfoBase::typeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitReturn):
(JSC::BytecodeGenerator::pushFinallyControlFlowScope):
(JSC::BytecodeGenerator::pushIteratorCloseControlFlowScope):
(JSC::BytecodeGenerator::popFinallyControlFlowScope):
(JSC::BytecodeGenerator::popIteratorCloseControlFlowScope):
(JSC::BytecodeGenerator::emitComplexPopScopes):
(JSC::BytecodeGenerator::emitPopScopes):
(JSC::BytecodeGenerator::pushTry):
(JSC::BytecodeGenerator::popTryAndEmitCatch):
(JSC::BytecodeGenerator::labelScopeDepth):
(JSC::BytecodeGenerator::pushLocalControlFlowScope):
(JSC::BytecodeGenerator::popLocalControlFlowScope):
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::emitYield):
(JSC::BytecodeGenerator::emitDelegateYield):
(JSC::BytecodeGenerator::popTry): Deleted.
(JSC::BytecodeGenerator::emitCatch): Deleted.
(JSC::BytecodeGenerator::restoreScopeRegister): Deleted.
(JSC::BytecodeGenerator::labelScopeDepthToLexicalScopeIndex): Deleted.
(JSC::BytecodeGenerator::emitIsNumber): Deleted.
(JSC::BytecodeGenerator::emitJumpViaFinallyIfNeeded): Deleted.
(JSC::BytecodeGenerator::emitReturnViaFinallyIfNeeded): Deleted.
(JSC::BytecodeGenerator::emitFinallyCompletion): Deleted.
(JSC::BytecodeGenerator::allocateFinallyRegisters): Deleted.
(JSC::BytecodeGenerator::releaseFinallyRegisters): Deleted.
(JSC::BytecodeGenerator::emitCompareFinallyActionAndJumpIf): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::isInFinallyBlock):
(JSC::FinallyJump::FinallyJump): Deleted.
(JSC::FinallyContext::FinallyContext): Deleted.
(JSC::FinallyContext::outerContext): Deleted.
(JSC::FinallyContext::finallyLabel): Deleted.
(JSC::FinallyContext::depth): Deleted.
(JSC::FinallyContext::numberOfBreaksOrContinues): Deleted.
(JSC::FinallyContext::incNumberOfBreaksOrContinues): Deleted.
(JSC::FinallyContext::handlesReturns): Deleted.
(JSC::FinallyContext::setHandlesReturns): Deleted.
(JSC::FinallyContext::registerJump): Deleted.
(JSC::FinallyContext::numberOfJumps): Deleted.
(JSC::FinallyContext::jumps): Deleted.
(JSC::ControlFlowScope::ControlFlowScope): Deleted.
(JSC::ControlFlowScope::isLabelScope): Deleted.
(JSC::ControlFlowScope::isFinallyScope): Deleted.
(JSC::BytecodeGenerator::currentLexicalScopeIndex): Deleted.
(JSC::BytecodeGenerator::FinallyRegistersScope::FinallyRegistersScope): Deleted.
(JSC::BytecodeGenerator::FinallyRegistersScope::~FinallyRegistersScope): Deleted.
(JSC::BytecodeGenerator::finallyActionRegister): Deleted.
(JSC::BytecodeGenerator::finallyReturnValueRegister): Deleted.
(JSC::BytecodeGenerator::emitSetFinallyActionToNormalCompletion): Deleted.
(JSC::BytecodeGenerator::emitSetFinallyActionToReturnCompletion): Deleted.
(JSC::BytecodeGenerator::emitSetFinallyActionToJumpID): Deleted.
(JSC::BytecodeGenerator::emitSetFinallyReturnValueRegister): Deleted.
(JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNormalCompletion): Deleted.
(JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotJump): Deleted.
(JSC::BytecodeGenerator::emitJumpIfFinallyActionIsReturnCompletion): Deleted.
(JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotReturnCompletion): Deleted.
(JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotThrowCompletion): Deleted.
(JSC::BytecodeGenerator::emitJumpIfCompletionTypeIsThrow): Deleted.
(JSC::BytecodeGenerator::bytecodeOffsetToJumpID): Deleted.
* bytecompiler/NodesCodegen.cpp:
(JSC::ContinueNode::emitBytecode):
(JSC::BreakNode::emitBytecode):
(JSC::ReturnNode::emitBytecode):
(JSC::TryNode::emitBytecode):
Source/WTF:
* wtf/SegmentedVector.h:
(WTF::SegmentedVector::last):
(WTF::SegmentedVector::first): Deleted.
(WTF::SegmentedVector::takeLast): Deleted.</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="#trunkSourceJavaScriptCorebytecodeHandlerInfoh">trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfSegmentedVectorh">trunk/Source/WTF/wtf/SegmentedVector.h</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressdeeplynestedfinallysjs">trunk/JSTests/stress/deeply-nested-finallys.js</a></li>
<li><a href="#trunkJSTestsstresstestfinallyjs">trunk/JSTests/stress/test-finally.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/JSTests/ChangeLog        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-12-19 Mark Lam <mark.lam@apple.com>
+
+ Rolling out r209974 and r209952. They break some websites in mysterious ways. Step 2: Rollout r209952.
+ https://bugs.webkit.org/show_bug.cgi?id=166049
+
+ Not reviewed.
+
+ * stress/deeply-nested-finallys.js: Removed.
+ * stress/test-finally.js: Removed.
+
</ins><span class="cx"> 2016-12-19 Saam Barati <sbarati@apple.com>
</span><span class="cx">
</span><span class="cx"> WebAssembly: Make running Wasm tests take less time by reducing some tests' iteration count and by splitting some tests into different files
</span></span></pre></div>
<a id="trunkJSTestsstressdeeplynestedfinallysjs"></a>
<div class="delfile"><h4>Deleted: trunk/JSTests/stress/deeply-nested-finallys.js (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/deeply-nested-finallys.js        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/JSTests/stress/deeply-nested-finallys.js        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -1,78 +0,0 @@
</span><del>-// This test should finish almost instantly.
-
-function exp() {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- try {
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally { return 1; }
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally {return 1;}
- } finally { return 1; }
-}
-
-exp();
</del></span></pre></div>
<a id="trunkJSTestsstresstestfinallyjs"></a>
<div class="delfile"><h4>Deleted: trunk/JSTests/stress/test-finally.js (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/test-finally.js        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/JSTests/stress/test-finally.js        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -1,1018 +0,0 @@
</span><del>-// This test just creates functions which exercise various permutations of control flow
-// thru finally blocks. The test passes if it does not throw any exceptions or crash on
-// bytecode validation.
-
-if (this.window)
- print = console.log;
-
-var steps;
-var returned;
-var thrown;
-var testLineNumber;
-
-let NothingReturned = "NothingReturned";
-let NothingThrown = "NothingThrown";
-
-function assertResults(expectedSteps, expectedReturned, expectedThrown) {
- let stepsMismatch = (steps != expectedSteps);
- let returnedMismatch = (returned != expectedReturned);
- let thrownMismatch = (thrown != expectedThrown && !("" + thrown).startsWith("" + expectedThrown));
-
- if (stepsMismatch || returnedMismatch || thrownMismatch) {
- print("FAILED Test @ line " + testLineNumber + ":");
- print(" Actual: steps: " + steps + ", returned: " + returned + ", thrown: '" + thrown + "'");
- print(" Expected: steps: " + expectedSteps + ", returned: " + expectedReturned + ", thrown: '" + expectedThrown + "'");
- }
- if (stepsMismatch)
- throw "FAILED Test @ line " + testLineNumber + ": steps do not match: expected ='" + expectedSteps + "' actual='" + steps + "'";
- if (returnedMismatch)
- throw "FAILED Test @ line " + testLineNumber + ": returned value does not match: expected ='" + expectedReturned + "' actual='" + returned + "'";
- if (thrownMismatch)
- throw "FAILED Test @ line " + testLineNumber + ": thrown value does does not match: expected ='" + expectedThrown + "' actual='" + thrown + "'";
-}
-
-function resetResults() {
- steps = [];
- returned = NothingReturned;
- thrown = NothingThrown;
-}
-
-function append(step) {
- let next = steps.length;
- steps[next] = step;
-}
-
-function test(func, expectedSteps, expectedReturned, expectedThrown) {
- testLineNumber = new Error().stack.match(/global code@.+\.js:([0-9]+)/)[1];
- resetResults();
-
- try {
- returned = func();
- } catch (e) {
- thrown = e;
- }
-
- assertResults(expectedSteps, expectedReturned, expectedThrown);
-}
-
-// Test CompletionType::Normal on an empty try blocks.
-test(() => {
- try {
- append("t2");
- for (var i = 0; i < 2; i++) {
- try {
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,f1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Normal.
-test(() => {
- try {
- append("t2");
- for (var i = 0; i < 2; i++) {
- try {
- append("t1");
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Break.
-test(() => {
- try {
- append("t2");
- for (var i = 0; i < 2; i++) {
- try {
- append("t1");
- break;
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Continue.
-test(() => {
- try {
- append("t2");
- for (var i = 0; i < 2; i++) {
- try {
- append("t1");
- continue;
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Return.
-test(() => {
- try {
- append("t2");
- for (var i = 0; i < 2; i++) {
- try {
- append("t1");
- return;
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Throw.
-test(() => {
- try {
- append("t2");
- for (var i = 0; i < 2; i++) {
- try {
- append("t1");
- throw { };
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,c1,f1,t1,c1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Normal in a for-of loop.
-test(() => {
- let arr = [1, 2];
- try {
- append("t2");
- for (let x of arr) {
- try {
- append("t1");
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Break in a for-of loop.
-test(() => {
- let arr = [1, 2];
- try {
- append("t2");
- for (let x of arr) {
- try {
- append("t1");
- break;
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Continue in a for-of loop.
-test(() => {
- let arr = [1, 2];
- try {
- append("t2");
- for (let x of arr) {
- try {
- append("t1");
- continue;
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Return in a for-of loop.
-test(() => {
- let arr = [1, 2];
- try {
- append("t2");
- for (let x of arr) {
- try {
- append("t1");
- return;
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,f1,f2", undefined, NothingThrown);
-
-// Test CompletionType::Throw in a for-of loop.
-test(() => {
- let arr = [1, 2];
- try {
- append("t2");
- for (let x of arr) {
- try {
- append("t1");
- throw { };
- } catch(a) {
- append("c1");
- } finally {
- append("f1");
- }
- }
- } catch(b) {
- append("c2");
- } finally {
- append("f2");
- }
-
-}, "t2,t1,c1,f1,t1,c1,f1,f2", undefined, NothingThrown);
-
-
-// No abrupt completions.
-test(() => {
- append("a");
- try {
- append("b");
- } finally {
- append("c");
- }
- append("d");
- return 400;
-
-}, "a,b,c,d", 400, NothingThrown);
-
-
-// Return after a. Should not execute any finally blocks, and return a's result.
-test(() => {
- append("a");
- return 100;
- try {
- append("b");
- return 200;
- try {
- append("c");
- return 300;
- } finally {
- append("d");
- }
- append("e");
- return 500;
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a", 100, NothingThrown);
-
-// Return after b. Should execute finally block f only, and return b's result.
-test(() => {
- append("a");
- try {
- append("b");
- return 200;
- try {
- append("c");
- return 300;
- } finally {
- append("d");
- }
- append("e");
- return 500;
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,f", 200, NothingThrown);
-
-// Return after c. Should execute finally blocks d and f, and return c's result.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- return 300;
- } finally {
- append("d");
- }
- append("e");
- return 500;
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,c,d,f", 300, NothingThrown);
-
-// Return after c and d. Should execute finally blocks d and f, and return last return value from d.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- return 300;
- } finally {
- append("d");
- return 400;
- }
- append("e");
- return 500;
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,c,d,f", 400, NothingThrown);
-
-// Return after c, d, and f. Should execute finally blocks d and f, and return last return value from f.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- return 300;
- } finally {
- append("d");
- return 400;
- }
- append("e");
- return 500;
- } finally {
- append("f");
- return 600;
- }
- append("g");
- return 700;
-
-}, "a,b,c,d,f", 600, NothingThrown);
-
-// Return after g.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- } finally {
- append("d");
- }
- append("e");
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,c,d,e,f,g", 700, NothingThrown);
-
-// Throw after a.
-test(() => {
- append("a");
- throw 100;
- try {
- append("b");
- throw 200;
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- }
- append("e");
- throw 500;
- } finally {
- append("f");
- }
- append("g");
- throw 700;
-
-}, "a", NothingReturned, 100);
-
-// Throw after b.
-test(() => {
- append("a");
- try {
- append("b");
- throw 200;
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- }
- append("e");
- throw 500;
- } finally {
- append("f");
- }
- append("g");
- throw 700;
-
-}, "a,b,f", NothingReturned, 200);
-
-// Throw after c.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- }
- append("e");
- throw 500;
- } finally {
- append("f");
- }
- append("g");
- throw 700;
-
-}, "a,b,c,d,f", NothingReturned, 300);
-
-// Throw after c and d.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- throw 400;
- }
- append("e");
- throw 500;
- } finally {
- append("f");
- }
- append("g");
- throw 700;
-
-}, "a,b,c,d,f", NothingReturned, 400);
-
-// Throw after c, d, and f.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- throw 400;
- }
- append("e");
- throw 500;
- } finally {
- append("f");
- throw 600;
- }
- append("g");
- return 700;
-
-}, "a,b,c,d,f", NothingReturned, 600);
-
-// Throw after g.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- } finally {
- append("d");
- }
- append("e");
- } finally {
- append("f");
- }
- append("g");
- throw 700;
-
-}, "a,b,c,d,e,f,g", NothingReturned, 700);
-
-// Throw after b with catch at z.
-test(() => {
- append("a");
- try {
- append("b");
- throw 200;
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- }
- append("e");
- throw 500;
- } catch (e) {
- append("z");
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,z,f,g", 700, NothingThrown);
-
-// Throw after b with catch at z and rethrow at z.
-test(() => {
- append("a");
- try {
- append("b");
- throw 200;
- try {
- append("c");
- throw 300;
- } finally {
- append("d");
- }
- append("e");
- throw 500;
- } catch (e) {
- append("z");
- throw 5000;
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,z,f", NothingReturned, 5000);
-
-// Throw after c with catch at y and z.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } catch (e) {
- append("y");
- } finally {
- append("d");
- }
- append("e");
- } catch (e) {
- append("z");
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,c,y,d,e,f,g", 700, NothingThrown);
-
-// Throw after c with catch at y and z, and rethrow at y.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } catch (e) {
- append("y");
- throw 3000;
- } finally {
- append("d");
- }
- append("e");
- } catch (e) {
- append("z");
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,c,y,d,z,f,g", 700, NothingThrown);
-
-// Throw after c with catch at y and z, and rethrow at y and z.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } catch (e) {
- append("y");
- throw 3000;
- } finally {
- append("d");
- }
- append("e");
- } catch (e) {
- append("z");
- throw 5000;
- } finally {
- append("f");
- }
- append("g");
- return 700;
-
-}, "a,b,c,y,d,z,f", NothingReturned, 5000);
-
-// Throw after c with catch at y and z, and rethrow at y, z, and f.
-test(() => {
- append("a");
- try {
- append("b");
- try {
- append("c");
- throw 300;
- } catch (e) {
- append("y");
- throw 3000;
- } finally {
- append("d");
- }
- append("e");
- } catch (e) {
- append("z");
- throw 5000;
- } finally {
- append("f");
- throw 600;
- }
- append("g");
- return 700;
-
-}, "a,b,c,y,d,z,f", NothingReturned, 600);
-
-// No throw or return in for-of loop.
-test(() => {
- class TestIterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- return { }
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new TestIterator();
- }
-
- for (var element of arr) {
- append(element);
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,n,2,n,x", 200, NothingThrown);
-
-// Break in for-of loop.
-test(() => {
- class TestIterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- return { }
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new TestIterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- break;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r,x", 200, NothingThrown);
-
-// Break in for-of loop with throw in Iterator.return().
-test(() => {
- class Iterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- throw 300;
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new Iterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- break;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", NothingReturned, 300);
-
-// Break in for-of loop with Iterator.return() returning a non object.
-test(() => {
- class Iterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new Iterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- break;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", NothingReturned, 'TypeError');
-
-// Return in for-of loop.
-test(() => {
- class TestIterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- return { }
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new TestIterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- return 100;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", 100, NothingThrown);
-
-// Return in for-of loop with throw in Iterator.return().
-test(() => {
- class Iterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- throw 300;
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new Iterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- return 100;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", NothingReturned, 300);
-
-// Return in for-of loop with Iterator.return() returning a non object.
-test(() => {
- class Iterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new Iterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- return 100;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", NothingReturned, 'TypeError');
-
-
-// Throw in for-of loop.
-test(() => {
- class Iterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new Iterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- throw 100;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", NothingReturned, 100);
-
-// Throw in for-of loop with throw in Iterator.return().
-test(() => {
- class Iterator {
- constructor() {
- append("c");
- this.i = 0;
- }
- next() {
- append("n");
- let done = (this.i == 3);
- return { done, value: this.i++ };
- }
- return() {
- append("r");
- throw 300;
- }
- }
-
- var arr = [];
- arr[Symbol.iterator] = function() {
- return new Iterator();
- }
-
- for (var element of arr) {
- append(element);
- if (element == 1)
- throw 100;
- }
- append("x");
- return 200;
-
-}, "c,n,0,n,1,r", NothingReturned, 100);
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -1,5 +1,82 @@
</span><span class="cx"> 2016-12-19 Mark Lam <mark.lam@apple.com>
</span><span class="cx">
</span><ins>+ Rolling out r209974 and r209952. They break some websites in mysterious ways. Step 2: Rollout r209952.
+ https://bugs.webkit.org/show_bug.cgi?id=166049
+
+ Not reviewed.
+
+ * bytecode/HandlerInfo.h:
+ (JSC::HandlerInfoBase::typeName):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::generate):
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ (JSC::BytecodeGenerator::emitReturn):
+ (JSC::BytecodeGenerator::pushFinallyControlFlowScope):
+ (JSC::BytecodeGenerator::pushIteratorCloseControlFlowScope):
+ (JSC::BytecodeGenerator::popFinallyControlFlowScope):
+ (JSC::BytecodeGenerator::popIteratorCloseControlFlowScope):
+ (JSC::BytecodeGenerator::emitComplexPopScopes):
+ (JSC::BytecodeGenerator::emitPopScopes):
+ (JSC::BytecodeGenerator::pushTry):
+ (JSC::BytecodeGenerator::popTryAndEmitCatch):
+ (JSC::BytecodeGenerator::labelScopeDepth):
+ (JSC::BytecodeGenerator::pushLocalControlFlowScope):
+ (JSC::BytecodeGenerator::popLocalControlFlowScope):
+ (JSC::BytecodeGenerator::emitEnumeration):
+ (JSC::BytecodeGenerator::emitYield):
+ (JSC::BytecodeGenerator::emitDelegateYield):
+ (JSC::BytecodeGenerator::popTry): Deleted.
+ (JSC::BytecodeGenerator::emitCatch): Deleted.
+ (JSC::BytecodeGenerator::restoreScopeRegister): Deleted.
+ (JSC::BytecodeGenerator::labelScopeDepthToLexicalScopeIndex): Deleted.
+ (JSC::BytecodeGenerator::emitIsNumber): Deleted.
+ (JSC::BytecodeGenerator::emitJumpViaFinallyIfNeeded): Deleted.
+ (JSC::BytecodeGenerator::emitReturnViaFinallyIfNeeded): Deleted.
+ (JSC::BytecodeGenerator::emitFinallyCompletion): Deleted.
+ (JSC::BytecodeGenerator::allocateFinallyRegisters): Deleted.
+ (JSC::BytecodeGenerator::releaseFinallyRegisters): Deleted.
+ (JSC::BytecodeGenerator::emitCompareFinallyActionAndJumpIf): Deleted.
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::BytecodeGenerator::isInFinallyBlock):
+ (JSC::FinallyJump::FinallyJump): Deleted.
+ (JSC::FinallyContext::FinallyContext): Deleted.
+ (JSC::FinallyContext::outerContext): Deleted.
+ (JSC::FinallyContext::finallyLabel): Deleted.
+ (JSC::FinallyContext::depth): Deleted.
+ (JSC::FinallyContext::numberOfBreaksOrContinues): Deleted.
+ (JSC::FinallyContext::incNumberOfBreaksOrContinues): Deleted.
+ (JSC::FinallyContext::handlesReturns): Deleted.
+ (JSC::FinallyContext::setHandlesReturns): Deleted.
+ (JSC::FinallyContext::registerJump): Deleted.
+ (JSC::FinallyContext::numberOfJumps): Deleted.
+ (JSC::FinallyContext::jumps): Deleted.
+ (JSC::ControlFlowScope::ControlFlowScope): Deleted.
+ (JSC::ControlFlowScope::isLabelScope): Deleted.
+ (JSC::ControlFlowScope::isFinallyScope): Deleted.
+ (JSC::BytecodeGenerator::currentLexicalScopeIndex): Deleted.
+ (JSC::BytecodeGenerator::FinallyRegistersScope::FinallyRegistersScope): Deleted.
+ (JSC::BytecodeGenerator::FinallyRegistersScope::~FinallyRegistersScope): Deleted.
+ (JSC::BytecodeGenerator::finallyActionRegister): Deleted.
+ (JSC::BytecodeGenerator::finallyReturnValueRegister): Deleted.
+ (JSC::BytecodeGenerator::emitSetFinallyActionToNormalCompletion): Deleted.
+ (JSC::BytecodeGenerator::emitSetFinallyActionToReturnCompletion): Deleted.
+ (JSC::BytecodeGenerator::emitSetFinallyActionToJumpID): Deleted.
+ (JSC::BytecodeGenerator::emitSetFinallyReturnValueRegister): Deleted.
+ (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNormalCompletion): Deleted.
+ (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotJump): Deleted.
+ (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsReturnCompletion): Deleted.
+ (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotReturnCompletion): Deleted.
+ (JSC::BytecodeGenerator::emitJumpIfFinallyActionIsNotThrowCompletion): Deleted.
+ (JSC::BytecodeGenerator::emitJumpIfCompletionTypeIsThrow): Deleted.
+ (JSC::BytecodeGenerator::bytecodeOffsetToJumpID): Deleted.
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ContinueNode::emitBytecode):
+ (JSC::BreakNode::emitBytecode):
+ (JSC::ReturnNode::emitBytecode):
+ (JSC::TryNode::emitBytecode):
+
+2016-12-19 Mark Lam <mark.lam@apple.com>
+
</ins><span class="cx"> Rolling out r209974 and r209952. They break some websites in mysterious ways. Step 1: Rollout r209974.
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=166049
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeHandlerInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -31,9 +31,9 @@
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><span class="cx"> enum class HandlerType {
</span><del>- Catch = 0,
- Finally = 1,
- SynthesizedCatch = 2,
</del><ins>+ Illegal = 0,
+ Catch = 1,
+ Finally = 2,
</ins><span class="cx"> SynthesizedFinally = 3
</span><span class="cx"> };
</span><span class="cx">
</span><span class="lines">@@ -53,8 +53,6 @@
</span><span class="cx"> return "catch";
</span><span class="cx"> case HandlerType::Finally:
</span><span class="cx"> return "finally";
</span><del>- case HandlerType::SynthesizedCatch:
- return "synthesized catch";
</del><span class="cx"> case HandlerType::SynthesizedFinally:
</span><span class="cx"> return "synthesized finally";
</span><span class="cx"> default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -156,6 +156,7 @@
</span><span class="cx"> if (end <= start)
</span><span class="cx"> continue;
</span><span class="cx">
</span><ins>+ ASSERT(range.tryData->handlerType != HandlerType::Illegal);
</ins><span class="cx"> UnlinkedHandlerInfo info(static_cast<uint32_t>(start), static_cast<uint32_t>(end),
</span><span class="cx"> static_cast<uint32_t>(range.tryData->target->bind()), range.tryData->handlerType);
</span><span class="cx"> m_codeBlock->addExceptionHandler(info);
</span><span class="lines">@@ -679,25 +680,21 @@
</span><span class="cx"> // because a function's default parameter ExpressionNodes will use temporary registers.
</span><span class="cx"> pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ);
</span><span class="cx">
</span><del>- RefPtr<Label> catchLabel = newLabel();
</del><span class="cx"> TryData* tryFormalParametersData = nullptr;
</span><del>- bool needTryCatch = isAsyncFunctionWrapperParseMode(parseMode) && !isSimpleParameterList;
- if (needTryCatch) {
</del><ins>+ if (isAsyncFunctionWrapperParseMode(parseMode) && !isSimpleParameterList) {
</ins><span class="cx"> RefPtr<Label> tryFormalParametersStart = emitLabel(newLabel().get());
</span><del>- tryFormalParametersData = pushTry(tryFormalParametersStart.get(), catchLabel.get(), HandlerType::SynthesizedCatch);
</del><ins>+ tryFormalParametersData = pushTry(tryFormalParametersStart.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, isSimpleParameterList, functionNode, functionSymbolTable, symbolTableConstantIndex, captures, shouldCreateArgumentsVariableInParameterScope);
</span><span class="cx">
</span><del>- if (needTryCatch) {
</del><ins>+ if (isAsyncFunctionWrapperParseMode(parseMode) && !isSimpleParameterList) {
</ins><span class="cx"> RefPtr<Label> didNotThrow = newLabel();
</span><span class="cx"> emitJump(didNotThrow.get());
</span><del>- emitLabel(catchLabel.get());
- popTry(tryFormalParametersData, catchLabel.get());
-
</del><ins>+ RefPtr<RegisterID> exception = newTemporary();
</ins><span class="cx"> RefPtr<RegisterID> thrownValue = newTemporary();
</span><del>- RegisterID* unused = newTemporary();
- emitCatch(unused, thrownValue.get());
</del><ins>+ RefPtr<Label> catchHere = emitLabel(newLabel().get());
+ popTryAndEmitCatch(tryFormalParametersData, exception.get(), thrownValue.get(), catchHere.get(), HandlerType::Catch);
</ins><span class="cx">
</span><span class="cx"> // return promiseCapability.@reject(thrownValue)
</span><span class="cx"> RefPtr<RegisterID> reject = emitGetById(newTemporary(), promiseCapabilityRegister(), m_vm->propertyNames->builtinNames().rejectPrivateName());
</span><span class="lines">@@ -3496,16 +3493,16 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-RegisterID* BytecodeGenerator::emitReturn(RegisterID* src, ReturnFrom from)
</del><ins>+RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
</ins><span class="cx"> {
</span><span class="cx"> if (isConstructor()) {
</span><span class="cx"> bool mightBeDerived = constructorKind() == ConstructorKind::Extends;
</span><span class="cx"> bool srcIsThis = src->index() == m_thisRegister.index();
</span><span class="cx">
</span><del>- if (mightBeDerived && (srcIsThis || from == ReturnFrom::Finally))
</del><ins>+ if (mightBeDerived && srcIsThis)
</ins><span class="cx"> emitTDZCheck(src);
</span><span class="cx">
</span><del>- if (!srcIsThis || from == ReturnFrom::Finally) {
</del><ins>+ if (!srcIsThis) {
</ins><span class="cx"> RefPtr<Label> isObjectLabel = newLabel();
</span><span class="cx"> emitJumpIfTrue(emitIsObject(newTemporary(), src), isObjectLabel.get());
</span><span class="cx">
</span><span class="lines">@@ -3683,31 +3680,82 @@
</span><span class="cx"> emitDebugHook(WillLeaveCallFrame, m_scopeNode->lastLine(), m_scopeNode->startOffset(), m_scopeNode->lineStartOffset());
</span><span class="cx"> }
</span><span class="cx">
</span><del>-FinallyContext* BytecodeGenerator::pushFinallyControlFlowScope(Label* finallyLabel)
</del><ins>+void BytecodeGenerator::pushFinallyControlFlowScope(StatementNode* finallyBlock)
</ins><span class="cx"> {
</span><span class="cx"> // Reclaim free label scopes.
</span><span class="cx"> while (m_labelScopes.size() && !m_labelScopes.last().refCount())
</span><span class="cx"> m_labelScopes.removeLast();
</span><span class="cx">
</span><del>- ControlFlowScope scope(ControlFlowScope::Finally, currentLexicalScopeIndex(), FinallyContext(m_currentFinallyContext, finallyLabel, m_finallyDepth));
- m_controlFlowScopeStack.append(WTFMove(scope));
</del><ins>+ ControlFlowScope scope;
+ scope.isFinallyBlock = true;
+ FinallyContext context = {
+ finallyBlock,
+ nullptr,
+ nullptr,
+ static_cast<unsigned>(m_controlFlowScopeStack.size()),
+ static_cast<unsigned>(m_switchContextStack.size()),
+ static_cast<unsigned>(m_forInContextStack.size()),
+ static_cast<unsigned>(m_tryContextStack.size()),
+ static_cast<unsigned>(m_labelScopes.size()),
+ static_cast<unsigned>(m_lexicalScopeStack.size()),
+ m_finallyDepth,
+ m_localScopeDepth
+ };
+ scope.finallyContext = context;
+ m_controlFlowScopeStack.append(scope);
+ m_finallyDepth++;
+}
</ins><span class="cx">
</span><ins>+void BytecodeGenerator::pushIteratorCloseControlFlowScope(RegisterID* iterator, ThrowableExpressionData* node)
+{
+ // Reclaim free label scopes.
+ while (m_labelScopes.size() && !m_labelScopes.last().refCount())
+ m_labelScopes.removeLast();
+
+ ControlFlowScope scope;
+ scope.isFinallyBlock = true;
+ FinallyContext context = {
+ nullptr,
+ iterator,
+ node,
+ static_cast<unsigned>(m_controlFlowScopeStack.size()),
+ static_cast<unsigned>(m_switchContextStack.size()),
+ static_cast<unsigned>(m_forInContextStack.size()),
+ static_cast<unsigned>(m_tryContextStack.size()),
+ static_cast<unsigned>(m_labelScopes.size()),
+ static_cast<unsigned>(m_lexicalScopeStack.size()),
+ m_finallyDepth,
+ m_localScopeDepth
+ };
+ scope.finallyContext = context;
+ m_controlFlowScopeStack.append(scope);
</ins><span class="cx"> m_finallyDepth++;
</span><del>- m_currentFinallyContext = &m_controlFlowScopeStack.last().finallyContext;
- return m_currentFinallyContext;
</del><span class="cx"> }
</span><span class="cx">
</span><del>-FinallyContext BytecodeGenerator::popFinallyControlFlowScope()
</del><ins>+void BytecodeGenerator::popFinallyControlFlowScope()
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(m_controlFlowScopeStack.size());
</span><del>- ASSERT(m_controlFlowScopeStack.last().isFinallyScope());
</del><ins>+ ASSERT(m_controlFlowScopeStack.last().isFinallyBlock);
+ ASSERT(m_controlFlowScopeStack.last().finallyContext.finallyBlock);
+ ASSERT(!m_controlFlowScopeStack.last().finallyContext.iterator);
+ ASSERT(!m_controlFlowScopeStack.last().finallyContext.enumerationNode);
</ins><span class="cx"> ASSERT(m_finallyDepth > 0);
</span><del>- ASSERT(m_currentFinallyContext);
- m_currentFinallyContext = m_currentFinallyContext->outerContext();
</del><ins>+ m_controlFlowScopeStack.removeLast();
</ins><span class="cx"> m_finallyDepth--;
</span><del>- return m_controlFlowScopeStack.takeLast().finallyContext;
</del><span class="cx"> }
</span><span class="cx">
</span><ins>+void BytecodeGenerator::popIteratorCloseControlFlowScope()
+{
+ ASSERT(m_controlFlowScopeStack.size());
+ ASSERT(m_controlFlowScopeStack.last().isFinallyBlock);
+ ASSERT(!m_controlFlowScopeStack.last().finallyContext.finallyBlock);
+ ASSERT(m_controlFlowScopeStack.last().finallyContext.iterator);
+ ASSERT(m_controlFlowScopeStack.last().finallyContext.enumerationNode);
+ ASSERT(m_finallyDepth > 0);
+ m_controlFlowScopeStack.removeLast();
+ m_finallyDepth--;
+}
+
</ins><span class="cx"> LabelScopePtr BytecodeGenerator::breakTarget(const Identifier& name)
</span><span class="cx"> {
</span><span class="cx"> // Reclaim free label scopes.
</span><span class="lines">@@ -3805,12 +3853,162 @@
</span><span class="cx"> m_topMostScope = addVar();
</span><span class="cx"> emitMove(m_topMostScope, scopeRegister());
</span><span class="cx"> }
</span><ins>+
+void BytecodeGenerator::emitComplexPopScopes(RegisterID* scope, ControlFlowScope* topScope, ControlFlowScope* bottomScope)
+{
+ while (topScope > bottomScope) {
+ // First we count the number of dynamic scopes we need to remove to get
+ // to a finally block.
+ int numberOfNormalScopes = 0;
+ while (topScope > bottomScope) {
+ if (topScope->isFinallyBlock)
+ break;
+ ++numberOfNormalScopes;
+ --topScope;
+ }
</ins><span class="cx">
</span><del>-TryData* BytecodeGenerator::pushTry(Label* start, Label* handlerLabel, HandlerType handlerType)
</del><ins>+ if (numberOfNormalScopes) {
+ // We need to remove a number of dynamic scopes to get to the next
+ // finally block
+ RefPtr<RegisterID> parentScope = newTemporary();
+ while (numberOfNormalScopes--) {
+ parentScope = emitGetParentScope(parentScope.get(), scope);
+ emitMove(scope, parentScope.get());
+ }
+
+ // If topScope == bottomScope then there isn't a finally block left to emit.
+ if (topScope == bottomScope)
+ return;
+ }
+
+ Vector<ControlFlowScope> savedControlFlowScopeStack;
+ Vector<SwitchInfo> savedSwitchContextStack;
+ Vector<RefPtr<ForInContext>> savedForInContextStack;
+ Vector<TryContext> poppedTryContexts;
+ Vector<LexicalScopeStackEntry> savedLexicalScopeStack;
+ LabelScopeStore savedLabelScopes;
+ while (topScope > bottomScope && topScope->isFinallyBlock) {
+ RefPtr<Label> beforeFinally = emitLabel(newLabel().get());
+
+ // Save the current state of the world while instating the state of the world
+ // for the finally block.
+ FinallyContext finallyContext = topScope->finallyContext;
+ bool flipScopes = finallyContext.controlFlowScopeStackSize != m_controlFlowScopeStack.size();
+ bool flipSwitches = finallyContext.switchContextStackSize != m_switchContextStack.size();
+ bool flipForIns = finallyContext.forInContextStackSize != m_forInContextStack.size();
+ bool flipTries = finallyContext.tryContextStackSize != m_tryContextStack.size();
+ bool flipLabelScopes = finallyContext.labelScopesSize != m_labelScopes.size();
+ bool flipLexicalScopeStack = finallyContext.lexicalScopeStackSize != m_lexicalScopeStack.size();
+ int topScopeIndex = -1;
+ int bottomScopeIndex = -1;
+ if (flipScopes) {
+ topScopeIndex = topScope - m_controlFlowScopeStack.begin();
+ bottomScopeIndex = bottomScope - m_controlFlowScopeStack.begin();
+ savedControlFlowScopeStack = m_controlFlowScopeStack;
+ m_controlFlowScopeStack.shrink(finallyContext.controlFlowScopeStackSize);
+ }
+ if (flipSwitches) {
+ savedSwitchContextStack = m_switchContextStack;
+ m_switchContextStack.shrink(finallyContext.switchContextStackSize);
+ }
+ if (flipForIns) {
+ savedForInContextStack = m_forInContextStack;
+ m_forInContextStack.shrink(finallyContext.forInContextStackSize);
+ }
+ if (flipTries) {
+ while (m_tryContextStack.size() != finallyContext.tryContextStackSize) {
+ ASSERT(m_tryContextStack.size() > finallyContext.tryContextStackSize);
+ TryContext context = m_tryContextStack.takeLast();
+ TryRange range;
+ range.start = context.start;
+ range.end = beforeFinally;
+ range.tryData = context.tryData;
+ m_tryRanges.append(range);
+ poppedTryContexts.append(context);
+ }
+ }
+ if (flipLabelScopes) {
+ savedLabelScopes = m_labelScopes;
+ while (m_labelScopes.size() > finallyContext.labelScopesSize)
+ m_labelScopes.removeLast();
+ }
+ if (flipLexicalScopeStack) {
+ savedLexicalScopeStack = m_lexicalScopeStack;
+ m_lexicalScopeStack.shrink(finallyContext.lexicalScopeStackSize);
+ }
+ int savedFinallyDepth = m_finallyDepth;
+ m_finallyDepth = finallyContext.finallyDepth;
+ int savedDynamicScopeDepth = m_localScopeDepth;
+ m_localScopeDepth = finallyContext.dynamicScopeDepth;
+
+ if (finallyContext.finallyBlock) {
+ // Emit the finally block.
+ emitNode(finallyContext.finallyBlock);
+ } else {
+ // Emit the IteratorClose block.
+ ASSERT(finallyContext.iterator);
+ emitIteratorClose(finallyContext.iterator, finallyContext.enumerationNode);
+ }
+
+ RefPtr<Label> afterFinally = emitLabel(newLabel().get());
+
+ // Restore the state of the world.
+ if (flipScopes) {
+ m_controlFlowScopeStack = savedControlFlowScopeStack;
+ topScope = &m_controlFlowScopeStack[topScopeIndex]; // assert it's within bounds
+ bottomScope = m_controlFlowScopeStack.begin() + bottomScopeIndex; // don't assert, since it the index might be -1.
+ }
+ if (flipSwitches)
+ m_switchContextStack = savedSwitchContextStack;
+ if (flipForIns)
+ m_forInContextStack = savedForInContextStack;
+ if (flipTries) {
+ ASSERT(m_tryContextStack.size() == finallyContext.tryContextStackSize);
+ for (unsigned i = poppedTryContexts.size(); i--;) {
+ TryContext context = poppedTryContexts[i];
+ context.start = afterFinally;
+ m_tryContextStack.append(context);
+ }
+ poppedTryContexts.clear();
+ }
+ if (flipLabelScopes)
+ m_labelScopes = savedLabelScopes;
+ if (flipLexicalScopeStack)
+ m_lexicalScopeStack = savedLexicalScopeStack;
+ m_finallyDepth = savedFinallyDepth;
+ m_localScopeDepth = savedDynamicScopeDepth;
+
+ --topScope;
+ }
+ }
+}
+
+void BytecodeGenerator::emitPopScopes(RegisterID* scope, int targetScopeDepth)
</ins><span class="cx"> {
</span><ins>+ ASSERT(labelScopeDepth() - targetScopeDepth >= 0);
+
+ size_t scopeDelta = labelScopeDepth() - targetScopeDepth;
+ ASSERT(scopeDelta <= m_controlFlowScopeStack.size());
+ if (!scopeDelta)
+ return;
+
+ if (!m_finallyDepth) {
+ RefPtr<RegisterID> parentScope = newTemporary();
+ while (scopeDelta--) {
+ parentScope = emitGetParentScope(parentScope.get(), scope);
+ emitMove(scope, parentScope.get());
+ }
+ return;
+ }
+
+ emitComplexPopScopes(scope, &m_controlFlowScopeStack.last(), &m_controlFlowScopeStack.last() - scopeDelta);
+}
+
+TryData* BytecodeGenerator::pushTry(Label* start)
+{
</ins><span class="cx"> TryData tryData;
</span><del>- tryData.target = handlerLabel;
- tryData.handlerType = handlerType;
</del><ins>+ tryData.target = newLabel();
+ tryData.handlerType = HandlerType::Illegal;
</ins><span class="cx"> m_tryData.append(tryData);
</span><span class="cx"> TryData* result = &m_tryData.last();
</span><span class="cx">
</span><span class="lines">@@ -3823,7 +4021,7 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void BytecodeGenerator::popTry(TryData* tryData, Label* end)
</del><ins>+void BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType handlerType)
</ins><span class="cx"> {
</span><span class="cx"> m_usesExceptions = true;
</span><span class="cx">
</span><span class="lines">@@ -3835,52 +4033,28 @@
</span><span class="cx"> tryRange.tryData = m_tryContextStack.last().tryData;
</span><span class="cx"> m_tryRanges.append(tryRange);
</span><span class="cx"> m_tryContextStack.removeLast();
</span><del>-}
</del><ins>+
+ emitLabel(tryRange.tryData->target.get());
+ tryRange.tryData->handlerType = handlerType;
</ins><span class="cx">
</span><del>-void BytecodeGenerator::emitCatch(RegisterID* exceptionRegister, RegisterID* thrownValueRegister)
-{
</del><span class="cx"> emitOpcode(op_catch);
</span><span class="cx"> instructions().append(exceptionRegister->index());
</span><span class="cx"> instructions().append(thrownValueRegister->index());
</span><del>-}
</del><span class="cx">
</span><del>-void BytecodeGenerator::restoreScopeRegister(int lexicalScopeIndex)
-{
- if (lexicalScopeIndex == CurrentLexicalScopeIndex)
- return; // No change needed.
-
- if (lexicalScopeIndex != OutermostLexicalScopeIndex) {
- ASSERT(lexicalScopeIndex < static_cast<int>(m_lexicalScopeStack.size()));
- int endIndex = lexicalScopeIndex + 1;
- for (size_t i = endIndex; i--; ) {
- if (m_lexicalScopeStack[i].m_scope) {
- emitMove(scopeRegister(), m_lexicalScopeStack[i].m_scope);
- return;
- }
</del><ins>+ bool foundLocalScope = false;
+ for (unsigned i = m_lexicalScopeStack.size(); i--; ) {
+ // Note that if we don't find a local scope in the current function/program,
+ // we must grab the outer-most scope of this bytecode generation.
+ if (m_lexicalScopeStack[i].m_scope) {
+ foundLocalScope = true;
+ emitMove(scopeRegister(), m_lexicalScopeStack[i].m_scope);
+ break;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><del>- // Note that if we don't find a local scope in the current function/program,
- // we must grab the outer-most scope of this bytecode generation.
- emitMove(scopeRegister(), m_topMostScope);
</del><ins>+ if (!foundLocalScope)
+ emitMove(scopeRegister(), m_topMostScope);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-void BytecodeGenerator::restoreScopeRegister()
-{
- restoreScopeRegister(currentLexicalScopeIndex());
-}
-
-int BytecodeGenerator::labelScopeDepthToLexicalScopeIndex(int targetLabelScopeDepth)
-{
- ASSERT(labelScopeDepth() - targetLabelScopeDepth >= 0);
- size_t scopeDelta = labelScopeDepth() - targetLabelScopeDepth;
- ASSERT(scopeDelta <= m_controlFlowScopeStack.size());
- if (!scopeDelta)
- return CurrentLexicalScopeIndex;
-
- ControlFlowScope& targetScope = m_controlFlowScopeStack[targetLabelScopeDepth];
- return targetScope.lexicalScopeIndex;
-}
-
</del><span class="cx"> int BytecodeGenerator::localScopeDepth() const
</span><span class="cx"> {
</span><span class="cx"> return m_localScopeDepth;
</span><span class="lines">@@ -3887,10 +4061,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> int BytecodeGenerator::labelScopeDepth() const
</span><del>-{
- int depth = localScopeDepth() + m_finallyDepth;
- ASSERT(depth == static_cast<int>(m_controlFlowScopeStack.size()));
- return depth;
</del><ins>+{
+ return localScopeDepth() + m_finallyDepth;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void BytecodeGenerator::emitThrowStaticError(ErrorType errorType, RegisterID* raw)
</span><span class="lines">@@ -3960,8 +4132,9 @@
</span><span class="cx">
</span><span class="cx"> void BytecodeGenerator::pushLocalControlFlowScope()
</span><span class="cx"> {
</span><del>- ControlFlowScope scope(ControlFlowScope::Label, currentLexicalScopeIndex());
- m_controlFlowScopeStack.append(WTFMove(scope));
</del><ins>+ ControlFlowScope scope;
+ scope.isFinallyBlock = false;
+ m_controlFlowScopeStack.append(scope);
</ins><span class="cx"> m_localScopeDepth++;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3968,7 +4141,7 @@
</span><span class="cx"> void BytecodeGenerator::popLocalControlFlowScope()
</span><span class="cx"> {
</span><span class="cx"> ASSERT(m_controlFlowScopeStack.size());
</span><del>- ASSERT(!m_controlFlowScopeStack.last().isFinallyScope());
</del><ins>+ ASSERT(!m_controlFlowScopeStack.last().isFinallyBlock);
</ins><span class="cx"> m_controlFlowScopeStack.removeLast();
</span><span class="cx"> m_localScopeDepth--;
</span><span class="cx"> }
</span><span class="lines">@@ -4123,11 +4296,9 @@
</span><span class="cx"> }
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack, ForOfNode* forLoopNode, RegisterID* forLoopSymbolTable)
</span><span class="cx"> {
</span><del>- FinallyRegistersScope finallyRegistersScope(*this);
-
</del><span class="cx"> RefPtr<RegisterID> subject = newTemporary();
</span><span class="cx"> emitNode(subject.get(), subjectNode);
</span><span class="cx"> RefPtr<RegisterID> iterator = emitGetById(newTemporary(), subject.get(), propertyNames().iteratorSymbol);
</span><span class="lines">@@ -4138,15 +4309,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<Label> loopDone = newLabel();
</span><del>- RefPtr<Label> tryStartLabel = newLabel();
- RefPtr<Label> finallyViaThrowLabel = newLabel();
- RefPtr<Label> finallyLabel = newLabel();
- RefPtr<Label> catchLabel = newLabel();
- RefPtr<Label> endCatchLabel = newLabel();
-
</del><span class="cx"> // RefPtr<Register> iterator's lifetime must be longer than IteratorCloseContext.
</span><del>- FinallyContext* finallyContext = pushFinallyControlFlowScope(finallyLabel.get());
-
</del><ins>+ pushIteratorCloseControlFlowScope(iterator.get(), node);
</ins><span class="cx"> {
</span><span class="cx"> LabelScopePtr scope = newLabelScope(LabelScope::Loop);
</span><span class="cx"> RefPtr<RegisterID> value = newTemporary();
</span><span class="lines">@@ -4158,68 +4322,40 @@
</span><span class="cx"> emitLabel(loopStart.get());
</span><span class="cx"> emitLoopHint();
</span><span class="cx">
</span><ins>+ RefPtr<Label> tryStartLabel = newLabel();
</ins><span class="cx"> emitLabel(tryStartLabel.get());
</span><del>- TryData* tryData = pushTry(tryStartLabel.get(), finallyViaThrowLabel.get(), HandlerType::SynthesizedFinally);
</del><ins>+ TryData* tryData = pushTry(tryStartLabel.get());
</ins><span class="cx"> callBack(*this, value.get());
</span><span class="cx"> emitJump(scope->continueTarget());
</span><span class="cx">
</span><del>- // IteratorClose sequence for abrupt completions.
</del><ins>+ // IteratorClose sequence for throw-ed control flow.
</ins><span class="cx"> {
</span><del>- // Finally block for the enumeration.
- emitLabel(finallyViaThrowLabel.get());
- popTry(tryData, finallyViaThrowLabel.get());
</del><ins>+ RefPtr<Label> catchHere = emitLabel(newLabel().get());
+ RefPtr<RegisterID> exceptionRegister = newTemporary();
+ RefPtr<RegisterID> thrownValueRegister = newTemporary();
+ popTryAndEmitCatch(tryData, exceptionRegister.get(),
+ thrownValueRegister.get(), catchHere.get(), HandlerType::SynthesizedFinally);
</ins><span class="cx">
</span><del>- RegisterID* unused = newTemporary();
- emitCatch(finallyActionRegister(), unused);
- // Setting the finallyActionRegister to the caught exception here implies CompletionType::Throw.
</del><ins>+ RefPtr<Label> catchDone = newLabel();
</ins><span class="cx">
</span><del>- emitLabel(finallyLabel.get());
- restoreScopeRegister();
-
- RefPtr<Label> finallyDone = newLabel();
-
</del><span class="cx"> RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
</span><del>- emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), finallyDone.get());
</del><ins>+ emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), catchDone.get());
</ins><span class="cx">
</span><del>- RefPtr<RegisterID> originalFinallyActionRegister = newTemporary();
- emitMove(originalFinallyActionRegister.get(), finallyActionRegister());
-
</del><span class="cx"> RefPtr<Label> returnCallTryStart = newLabel();
</span><span class="cx"> emitLabel(returnCallTryStart.get());
</span><del>- TryData* returnCallTryData = pushTry(returnCallTryStart.get(), catchLabel.get(), HandlerType::SynthesizedCatch);
</del><ins>+ TryData* returnCallTryData = pushTry(returnCallTryStart.get());
</ins><span class="cx">
</span><span class="cx"> CallArguments returnArguments(*this, nullptr);
</span><span class="cx"> emitMove(returnArguments.thisRegister(), iterator.get());
</span><span class="cx"> emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
</span><del>- emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), finallyDone.get());
- emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object."));
</del><span class="cx">
</span><del>- emitLabel(finallyDone.get());
- emitFinallyCompletion(*finallyContext, endCatchLabel.get());
</del><ins>+ emitLabel(catchDone.get());
+ emitThrow(exceptionRegister.get());
</ins><span class="cx">
</span><del>- popTry(returnCallTryData, finallyDone.get());
-
- // Catch block for exceptions that may be thrown while calling the return
- // handler in the enumeration finally block. The only reason we need this
- // catch block is because if entered the above finally block due to a thrown
- // exception, then we want to re-throw the original exception on exiting
- // the finally block. Otherwise, we'll let any new exception pass through.
- {
- emitLabel(catchLabel.get());
- RefPtr<RegisterID> exceptionRegister = newTemporary();
- RegisterID* unused = newTemporary();
- emitCatch(exceptionRegister.get(), unused);
- restoreScopeRegister();
-
- RefPtr<Label> throwLabel = newLabel();
- emitJumpIfCompletionTypeIsThrow(originalFinallyActionRegister.get(), throwLabel.get());
- emitMove(originalFinallyActionRegister.get(), exceptionRegister.get());
-
- emitLabel(throwLabel.get());
- emitThrow(originalFinallyActionRegister.get());
-
- emitLabel(endCatchLabel.get());
- }
</del><ins>+ // Absorb exception.
+ popTryAndEmitCatch(returnCallTryData, newTemporary(),
+ newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally);
+ emitThrow(exceptionRegister.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> emitLabel(scope->continueTarget());
</span><span class="lines">@@ -4240,7 +4376,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // IteratorClose sequence for break-ed control flow.
</span><del>- popFinallyControlFlowScope();
</del><ins>+ popIteratorCloseControlFlowScope();
</ins><span class="cx"> emitIteratorClose(iterator.get(), node);
</span><span class="cx"> emitLabel(loopDone.get());
</span><span class="cx"> }
</span><span class="lines">@@ -4361,14 +4497,6 @@
</span><span class="cx"> return dst;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-RegisterID* BytecodeGenerator::emitIsNumber(RegisterID* dst, RegisterID* src)
-{
- emitOpcode(op_is_number);
- instructions().append(dst->index());
- instructions().append(src->index());
- return dst;
-}
-
</del><span class="cx"> RegisterID* BytecodeGenerator::emitIsUndefined(RegisterID* dst, RegisterID* src)
</span><span class="cx"> {
</span><span class="cx"> emitOpcode(op_is_undefined);
</span><span class="lines">@@ -4656,9 +4784,11 @@
</span><span class="cx"> // Return.
</span><span class="cx"> {
</span><span class="cx"> RefPtr<RegisterID> returnRegister = generatorValueRegister();
</span><del>- bool hasFinally = emitReturnViaFinallyIfNeeded(returnRegister.get());
- if (!hasFinally)
- emitReturn(returnRegister.get());
</del><ins>+ if (isInFinallyBlock()) {
+ returnRegister = emitMove(newTemporary(), returnRegister.get());
+ emitPopScopes(scopeRegister(), 0);
+ }
+ emitReturn(returnRegister.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Throw.
</span><span class="lines">@@ -4761,9 +4891,9 @@
</span><span class="cx"> emitGetById(value.get(), value.get(), propertyNames().value);
</span><span class="cx">
</span><span class="cx"> emitLabel(returnSequence.get());
</span><del>- bool hasFinally = emitReturnViaFinallyIfNeeded(value.get());
- if (!hasFinally)
- emitReturn(value.get());
</del><ins>+ if (isInFinallyBlock())
+ emitPopScopes(scopeRegister(), 0);
+ emitReturn(value.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Normal.
</span><span class="lines">@@ -4793,157 +4923,6 @@
</span><span class="cx"> emitPutById(generatorRegister(), propertyNames().builtinNames().generatorStatePrivateName(), completedState);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool BytecodeGenerator::emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label* jumpTarget)
-{
- ASSERT(labelScopeDepth() - targetLabelScopeDepth >= 0);
- size_t scopeDelta = labelScopeDepth() - targetLabelScopeDepth;
- ASSERT(scopeDelta <= m_controlFlowScopeStack.size());
- if (!scopeDelta)
- return false; // No finallys to thread through.
-
- ControlFlowScope* topScope = &m_controlFlowScopeStack.last();
- ControlFlowScope* bottomScope = &m_controlFlowScopeStack.last() - scopeDelta;
-
- FinallyContext* innermostFinallyContext = nullptr;
- FinallyContext* outermostFinallyContext = nullptr;
- while (topScope > bottomScope) {
- if (topScope->isFinallyScope()) {
- FinallyContext* finallyContext = &topScope->finallyContext;
- if (!innermostFinallyContext)
- innermostFinallyContext = finallyContext;
- outermostFinallyContext = finallyContext;
- finallyContext->incNumberOfBreaksOrContinues();
- }
- --topScope;
- }
- if (!outermostFinallyContext)
- return false; // No finallys to thread through.
-
- int jumpID = bytecodeOffsetToJumpID(instructions().size());
- int lexicalScopeIndex = labelScopeDepthToLexicalScopeIndex(targetLabelScopeDepth);
- outermostFinallyContext->registerJump(jumpID, lexicalScopeIndex, jumpTarget);
-
- emitSetFinallyActionToJumpID(jumpID);
- emitJump(innermostFinallyContext->finallyLabel());
- return true; // We'll be jumping to a finally block.
-}
-
-bool BytecodeGenerator::emitReturnViaFinallyIfNeeded(RegisterID* returnRegister)
-{
- if (!m_controlFlowScopeStack.size())
- return false; // No finallys to thread through.
-
- ControlFlowScope* topScope = &m_controlFlowScopeStack.last();
- ControlFlowScope* bottomScope = &m_controlFlowScopeStack.first();
-
- FinallyContext* innermostFinallyContext = nullptr;
- while (topScope >= bottomScope) {
- if (topScope->isFinallyScope()) {
- FinallyContext* finallyContext = &topScope->finallyContext;
- if (!innermostFinallyContext)
- innermostFinallyContext = finallyContext;
- finallyContext->setHandlesReturns();
- }
- --topScope;
- }
- if (!innermostFinallyContext)
- return false; // No finallys to thread through.
-
- emitSetFinallyActionToReturnCompletion();
- emitSetFinallyReturnValueRegister(returnRegister);
- emitJump(innermostFinallyContext->finallyLabel());
- return true; // We'll be jumping to a finally block.
-}
-
-void BytecodeGenerator::emitFinallyCompletion(FinallyContext& context, Label* normalCompletionLabel)
-{
- // FIXME: switch the finallyActionRegister to only store int values for all CompletionTypes. This is more optimal for JIT type speculation.
- // https://bugs.webkit.org/show_bug.cgi?id=165979
- emitJumpIfFinallyActionIsNormalCompletion(normalCompletionLabel);
-
- if (context.numberOfBreaksOrContinues() || context.handlesReturns()) {
- FinallyContext* outerContext = context.outerContext();
- if (outerContext) {
- // We are not the outermost finally.
- size_t numberOfJumps = context.numberOfJumps();
- for (size_t i = 0; i < numberOfJumps; i++) {
- RefPtr<Label> nextLabel = newLabel();
- auto& jump = context.jumps(i);
- emitJumpIfFinallyActionIsNotJump(jump.jumpID, nextLabel.get());
-
- restoreScopeRegister(jump.targetLexicalScopeIndex);
- emitSetFinallyActionToNormalCompletion();
- emitJump(jump.targetLabel.get());
-
- emitLabel(nextLabel.get());
- }
-
- bool hasBreaksOrContinuesNotCoveredByJumps = context.numberOfBreaksOrContinues() > numberOfJumps;
- if (hasBreaksOrContinuesNotCoveredByJumps || context.handlesReturns())
- emitJumpIfFinallyActionIsNotThrowCompletion(outerContext->finallyLabel());
-
- } else {
- // We are the outermost finally.
- size_t numberOfJumps = context.numberOfJumps();
- ASSERT(numberOfJumps == context.numberOfBreaksOrContinues());
-
- for (size_t i = 0; i < numberOfJumps; i++) {
- RefPtr<Label> nextLabel = newLabel();
- auto& jump = context.jumps(i);
- emitJumpIfFinallyActionIsNotJump(jump.jumpID, nextLabel.get());
-
- restoreScopeRegister(jump.targetLexicalScopeIndex);
- emitSetFinallyActionToNormalCompletion();
- emitJump(jump.targetLabel.get());
-
- emitLabel(nextLabel.get());
- }
-
- if (context.handlesReturns()) {
- RefPtr<Label> notReturnLabel = newLabel();
- emitJumpIfFinallyActionIsNotReturnCompletion(notReturnLabel.get());
-
- emitWillLeaveCallFrameDebugHook();
- emitReturn(finallyReturnValueRegister(), ReturnFrom::Finally);
-
- emitLabel(notReturnLabel.get());
- }
- }
- }
- emitThrow(finallyActionRegister());
-}
-
-bool BytecodeGenerator::allocateFinallyRegisters()
-{
- if (m_finallyActionRegister)
- return false;
-
- ASSERT(!m_finallyReturnValueRegister);
- m_finallyActionRegister = newTemporary();
- m_finallyReturnValueRegister = newTemporary();
-
- emitSetFinallyActionToNormalCompletion();
- emitMoveEmptyValue(m_finallyReturnValueRegister.get());
- return true;
-}
-
-void BytecodeGenerator::releaseFinallyRegisters()
-{
- ASSERT(m_finallyActionRegister && m_finallyReturnValueRegister);
- m_finallyActionRegister = nullptr;
- m_finallyReturnValueRegister = nullptr;
-}
-
-void BytecodeGenerator::emitCompareFinallyActionAndJumpIf(OpcodeID compareOpcode, int value, Label* jumpTarget)
-{
- RefPtr<RegisterID> tempRegister = newTemporary();
- RegisterID* valueConstant = addConstantValue(JSValue(value));
- OperandTypes operandTypes = OperandTypes(ResultType::numberTypeIsInt32(), ResultType::unknownType());
-
- auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, finallyActionRegister(), operandTypes);
- emitJumpIfTrue(equivalenceResult, jumpTarget);
-}
-
</del><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -80,78 +80,22 @@
</span><span class="cx"> unsigned m_padding;
</span><span class="cx"> };
</span><span class="cx">
</span><del>- struct FinallyJump {
- FinallyJump(int jumpID, int targetLexicalScopeIndex, Label* targetLabel)
- : jumpID(jumpID)
- , targetLexicalScopeIndex(targetLexicalScopeIndex)
- , targetLabel(targetLabel)
- { }
-
- int jumpID { 0 };
- int targetLexicalScopeIndex { 0 };
- RefPtr<Label> targetLabel;
- };
-
</del><span class="cx"> struct FinallyContext {
</span><del>- FinallyContext() { }
- FinallyContext(FinallyContext* outerContext, Label* finallyLabel, int finallyDepth)
- : m_outerContext(outerContext)
- , m_finallyLabel(finallyLabel)
- , m_finallyDepth(finallyDepth)
- {
- ASSERT(!m_jumps || m_jumps->isEmpty());
- }
-
- FinallyContext* outerContext() const { return m_outerContext; }
- Label* finallyLabel() const { return m_finallyLabel; }
- int depth() const { return m_finallyDepth; }
-
- unsigned numberOfBreaksOrContinues() const { return m_numberOfBreaksOrContinues; }
- void incNumberOfBreaksOrContinues()
- {
- ASSERT(m_numberOfBreaksOrContinues < INT_MAX);
- m_numberOfBreaksOrContinues++;
- }
-
- bool handlesReturns() const { return m_handlesReturns; }
- void setHandlesReturns() { m_handlesReturns = true; }
-
- void registerJump(int jumpID, int lexicalScopeIndex, Label* targetLabel)
- {
- if (!m_jumps)
- m_jumps = std::make_unique<Vector<FinallyJump>>();
- m_jumps->append(FinallyJump(jumpID, lexicalScopeIndex, targetLabel));
- }
-
- size_t numberOfJumps() const { return m_jumps ? m_jumps->size() : 0; }
- FinallyJump& jumps(size_t i) { return (*m_jumps)[i]; }
-
- private:
- FinallyContext* m_outerContext { nullptr };
- Label* m_finallyLabel { nullptr };
- int m_finallyDepth { 0 };
- unsigned m_numberOfBreaksOrContinues { 0 };
- bool m_handlesReturns { false };
- std::unique_ptr<Vector<FinallyJump>> m_jumps;
</del><ins>+ StatementNode* finallyBlock;
+ RegisterID* iterator;
+ ThrowableExpressionData* enumerationNode;
+ unsigned controlFlowScopeStackSize;
+ unsigned switchContextStackSize;
+ unsigned forInContextStackSize;
+ unsigned tryContextStackSize;
+ unsigned labelScopesSize;
+ unsigned lexicalScopeStackSize;
+ int finallyDepth;
+ int dynamicScopeDepth;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> struct ControlFlowScope {
</span><del>- typedef uint8_t Type;
- enum {
- Label,
- Finally
- };
- ControlFlowScope(Type type, int lexicalScopeIndex, FinallyContext&& finallyContext = FinallyContext())
- : type(type)
- , lexicalScopeIndex(lexicalScopeIndex)
- , finallyContext(std::forward<FinallyContext>(finallyContext))
- { }
-
- bool isLabelScope() const { return type == Label; }
- bool isFinallyScope() const { return type == Finally; }
-
- Type type;
- int lexicalScopeIndex;
</del><ins>+ bool isFinallyBlock;
</ins><span class="cx"> FinallyContext finallyContext;
</span><span class="cx"> };
</span><span class="cx">
</span><span class="lines">@@ -661,8 +605,7 @@
</span><span class="cx">
</span><span class="cx"> RegisterID* emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode*);
</span><span class="cx">
</span><del>- enum class ReturnFrom { Normal, Finally };
- RegisterID* emitReturn(RegisterID* src, ReturnFrom = ReturnFrom::Normal);
</del><ins>+ RegisterID* emitReturn(RegisterID* src);
</ins><span class="cx"> RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
</span><span class="cx">
</span><span class="cx"> RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
</span><span class="lines">@@ -683,6 +626,7 @@
</span><span class="cx"> PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target);
</span><span class="cx"> PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target);
</span><span class="cx"> PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target);
</span><ins>+ void emitPopScopes(RegisterID* srcDst, int targetScopeDepth);
</ins><span class="cx">
</span><span class="cx"> void emitEnter();
</span><span class="cx"> void emitWatchdog();
</span><span class="lines">@@ -705,7 +649,6 @@
</span><span class="cx"> RegisterID* emitIsMap(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSMapType); }
</span><span class="cx"> RegisterID* emitIsSet(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSSetType); }
</span><span class="cx"> RegisterID* emitIsObject(RegisterID* dst, RegisterID* src);
</span><del>- RegisterID* emitIsNumber(RegisterID* dst, RegisterID* src);
</del><span class="cx"> RegisterID* emitIsUndefined(RegisterID* dst, RegisterID* src);
</span><span class="cx"> RegisterID* emitIsEmpty(RegisterID* dst, RegisterID* src);
</span><span class="cx"> RegisterID* emitIsDerivedArray(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, DerivedArrayType); }
</span><span class="lines">@@ -720,30 +663,10 @@
</span><span class="cx"> bool emitReadOnlyExceptionIfNeeded(const Variable&);
</span><span class="cx">
</span><span class="cx"> // Start a try block. 'start' must have been emitted.
</span><del>- TryData* pushTry(Label* start, Label* handlerLabel, HandlerType);
</del><ins>+ TryData* pushTry(Label* start);
</ins><span class="cx"> // End a try block. 'end' must have been emitted.
</span><del>- void popTry(TryData*, Label* end);
- void emitCatch(RegisterID* exceptionRegister, RegisterID* thrownValueRegister);
</del><ins>+ void popTryAndEmitCatch(TryData*, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType);
</ins><span class="cx">
</span><del>- private:
- static const int CurrentLexicalScopeIndex = -2;
- static const int OutermostLexicalScopeIndex = -1;
-
- public:
- void restoreScopeRegister();
- void restoreScopeRegister(int lexicalScopeIndex);
-
- int currentLexicalScopeIndex() const
- {
- int size = static_cast<int>(m_lexicalScopeStack.size());
- ASSERT(static_cast<size_t>(size) == m_lexicalScopeStack.size());
- ASSERT(size >= 0);
- int index = size - 1;
- return index;
- }
-
- int labelScopeDepthToLexicalScopeIndex(int labelScopeDepth);
-
</del><span class="cx"> void emitThrow(RegisterID* exc)
</span><span class="cx"> {
</span><span class="cx"> m_usesExceptions = true;
</span><span class="lines">@@ -775,102 +698,13 @@
</span><span class="cx"> void emitDebugHook(ExpressionNode*);
</span><span class="cx"> void emitWillLeaveCallFrameDebugHook();
</span><span class="cx">
</span><del>- class FinallyRegistersScope {
- public:
- FinallyRegistersScope(BytecodeGenerator& generator, bool needFinallyRegisters = true)
- : m_generator(generator)
- {
- if (needFinallyRegisters && m_generator.allocateFinallyRegisters())
- m_needToReleaseOnDestruction = true;
- }
- ~FinallyRegistersScope()
- {
- if (m_needToReleaseOnDestruction)
- m_generator.releaseFinallyRegisters();
- }
</del><ins>+ bool isInFinallyBlock() { return m_finallyDepth > 0; }
</ins><span class="cx">
</span><del>- private:
- BytecodeGenerator& m_generator;
- bool m_needToReleaseOnDestruction { false };
- };
</del><ins>+ void pushFinallyControlFlowScope(StatementNode* finallyBlock);
+ void popFinallyControlFlowScope();
+ void pushIteratorCloseControlFlowScope(RegisterID* iterator, ThrowableExpressionData* enumerationNode);
+ void popIteratorCloseControlFlowScope();
</ins><span class="cx">
</span><del>- RegisterID* finallyActionRegister() const
- {
- ASSERT(m_finallyActionRegister);
- return m_finallyActionRegister.get();
- }
- RegisterID* finallyReturnValueRegister() const
- {
- ASSERT(m_finallyReturnValueRegister);
- return m_finallyReturnValueRegister.get();
- }
-
- void emitSetFinallyActionToNormalCompletion()
- {
- emitMoveEmptyValue(m_finallyActionRegister.get());
- }
- void emitSetFinallyActionToReturnCompletion()
- {
- emitLoad(finallyActionRegister(), JSValue(static_cast<int>(CompletionType::Return)));
- }
- void emitSetFinallyActionToJumpID(int jumpID)
- {
- emitLoad(finallyActionRegister(), JSValue(jumpID));
- }
- void emitSetFinallyReturnValueRegister(RegisterID* reg)
- {
- emitMove(finallyReturnValueRegister(), reg);
- }
-
- void emitJumpIfFinallyActionIsNormalCompletion(Label* jumpTarget)
- {
- emitJumpIfTrue(emitIsEmpty(newTemporary(), finallyActionRegister()), jumpTarget);
- }
-
- void emitJumpIfFinallyActionIsNotJump(int jumpID, Label* jumpTarget)
- {
- emitCompareFinallyActionAndJumpIf(op_nstricteq, jumpID, jumpTarget);
- }
-
- void emitJumpIfFinallyActionIsReturnCompletion(Label* jumpTarget)
- {
- emitCompareFinallyActionAndJumpIf(op_stricteq, static_cast<int>(CompletionType::Return), jumpTarget);
- }
- void emitJumpIfFinallyActionIsNotReturnCompletion(Label* jumpTarget)
- {
- emitCompareFinallyActionAndJumpIf(op_nstricteq, static_cast<int>(CompletionType::Return), jumpTarget);
- }
-
- void emitJumpIfFinallyActionIsNotThrowCompletion(Label* jumpTarget)
- {
- emitJumpIfTrue(emitIsNumber(newTemporary(), finallyActionRegister()), jumpTarget);
- }
- void emitJumpIfCompletionTypeIsThrow(RegisterID* reg, Label* jumpTarget)
- {
- emitJumpIfFalse(emitIsNumber(newTemporary(), reg), jumpTarget);
- }
-
- bool emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label* jumpTarget);
- bool emitReturnViaFinallyIfNeeded(RegisterID* returnRegister);
- void emitFinallyCompletion(FinallyContext&, Label* normalCompletionLabel);
-
- private:
- void emitCompareFinallyActionAndJumpIf(OpcodeID compareOpcode, int value, Label* jumpTarget);
-
- int bytecodeOffsetToJumpID(unsigned offset)
- {
- int jumpID = offset + static_cast<int>(CompletionType::NumberOfTypes);
- ASSERT(jumpID >= static_cast<int>(CompletionType::NumberOfTypes));
- return jumpID;
- }
-
- bool allocateFinallyRegisters();
- void releaseFinallyRegisters();
-
- public:
- FinallyContext* pushFinallyControlFlowScope(Label* finallyLabel);
- FinallyContext popFinallyControlFlowScope();
-
</del><span class="cx"> void pushIndexedForInScope(RegisterID* local, RegisterID* index);
</span><span class="cx"> void popIndexedForInScope(RegisterID* local);
</span><span class="cx"> void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator);
</span><span class="lines">@@ -963,6 +797,7 @@
</span><span class="cx">
</span><span class="cx"> void allocateCalleeSaveSpace();
</span><span class="cx"> void allocateAndEmitScope();
</span><ins>+ void emitComplexPopScopes(RegisterID*, ControlFlowScope* topScope, ControlFlowScope* bottomScope);
</ins><span class="cx">
</span><span class="cx"> typedef HashMap<double, JSValue> NumberMap;
</span><span class="cx"> typedef HashMap<UniquedStringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
</span><span class="lines">@@ -1100,35 +935,6 @@
</span><span class="cx"> RegisterID* m_arrowFunctionContextLexicalEnvironmentRegister { nullptr };
</span><span class="cx"> RegisterID* m_promiseCapabilityRegister { nullptr };
</span><span class="cx">
</span><del>- // The spec at https://tc39.github.io/ecma262/#sec-completion-record-specification-type says
- // that there are 5 types of completions. Conceptually, we'll set m_finallyActionRegister
- // to one of these completion types. However, to optimize our implementation, we'll encode
- // these type info as follows:
- //
- // CompletionType::Normal - m_finallyActionRegister is empty.
- // CompletionType::Break - m_finallyActionRegister is an int JSValue jumpID.
- // CompletionType::Continue - m_finallyActionRegister is an int JSValue jumpID.
- // CompletionType::Return - m_finallyActionRegister is the Return enum as an int JSValue.
- // CompletionType::Throw - m_finallyActionRegister is the Exception object to rethrow.
- //
- // Hence, of the 5 completion types, only the CompletionType::Return enum value is used in
- // our implementation. The rest are just provided for completeness.
-
- enum class CompletionType : int {
- Normal,
- Break,
- Continue,
- Return,
- Throw,
-
- NumberOfTypes
- };
-
- RefPtr<RegisterID> m_finallyActionRegister;
- RefPtr<RegisterID> m_finallyReturnValueRegister;
-
- FinallyContext* m_currentFinallyContext { nullptr };
-
</del><span class="cx"> SegmentedVector<RegisterID*, 16> m_localRegistersForCalleeSaveRegisters;
</span><span class="cx"> SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
</span><span class="cx"> SegmentedVector<RegisterID, 32> m_calleeLocals;
</span><span class="lines">@@ -1143,9 +949,7 @@
</span><span class="cx"> void pushLocalControlFlowScope();
</span><span class="cx"> void popLocalControlFlowScope();
</span><span class="cx">
</span><del>- // FIXME: Restore overflow checking with UnsafeVectorOverflow once SegmentVector supports it.
- // https://bugs.webkit.org/show_bug.cgi?id=165980
- SegmentedVector<ControlFlowScope, 16> m_controlFlowScopeStack;
</del><ins>+ Vector<ControlFlowScope, 0, UnsafeVectorOverflow> m_controlFlowScopeStack;
</ins><span class="cx"> Vector<SwitchInfo> m_switchContextStack;
</span><span class="cx"> Vector<RefPtr<ForInContext>> m_forInContextStack;
</span><span class="cx"> Vector<TryContext> m_tryContextStack;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -2998,12 +2998,8 @@
</span><span class="cx"> LabelScopePtr scope = generator.continueTarget(m_ident);
</span><span class="cx"> ASSERT(scope);
</span><span class="cx">
</span><del>- bool hasFinally = generator.emitJumpViaFinallyIfNeeded(scope->scopeDepth(), scope->continueTarget());
- if (!hasFinally) {
- int lexicalScopeIndex = generator.labelScopeDepthToLexicalScopeIndex(scope->scopeDepth());
- generator.restoreScopeRegister(lexicalScopeIndex);
- generator.emitJump(scope->continueTarget());
- }
</del><ins>+ generator.emitPopScopes(generator.scopeRegister(), scope->scopeDepth());
+ generator.emitJump(scope->continueTarget());
</ins><span class="cx">
</span><span class="cx"> generator.emitProfileControlFlow(endOffset());
</span><span class="cx"> }
</span><span class="lines">@@ -3029,12 +3025,8 @@
</span><span class="cx"> LabelScopePtr scope = generator.breakTarget(m_ident);
</span><span class="cx"> ASSERT(scope);
</span><span class="cx">
</span><del>- bool hasFinally = generator.emitJumpViaFinallyIfNeeded(scope->scopeDepth(), scope->breakTarget());
- if (!hasFinally) {
- int lexicalScopeIndex = generator.labelScopeDepthToLexicalScopeIndex(scope->scopeDepth());
- generator.restoreScopeRegister(lexicalScopeIndex);
- generator.emitJump(scope->breakTarget());
- }
</del><ins>+ generator.emitPopScopes(generator.scopeRegister(), scope->scopeDepth());
+ generator.emitJump(scope->breakTarget());
</ins><span class="cx">
</span><span class="cx"> generator.emitProfileControlFlow(endOffset());
</span><span class="cx"> }
</span><span class="lines">@@ -3051,14 +3043,14 @@
</span><span class="cx"> RefPtr<RegisterID> returnRegister = m_value ? generator.emitNodeInTailPosition(dst, m_value) : generator.emitLoad(dst, jsUndefined());
</span><span class="cx">
</span><span class="cx"> generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, divotStart(), divotEnd());
</span><del>-
- bool hasFinally = generator.emitReturnViaFinallyIfNeeded(returnRegister.get());
- if (!hasFinally) {
- generator.emitWillLeaveCallFrameDebugHook();
- generator.emitReturn(returnRegister.get());
</del><ins>+ if (generator.isInFinallyBlock()) {
+ returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get());
+ generator.emitPopScopes(generator.scopeRegister(), 0);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- generator.emitProfileControlFlow(endOffset());
</del><ins>+ generator.emitWillLeaveCallFrameDebugHook();
+ generator.emitReturn(returnRegister.get());
+ generator.emitProfileControlFlow(endOffset());
</ins><span class="cx"> // Emitting an unreachable return here is needed in case this op_profile_control_flow is the
</span><span class="cx"> // last opcode in a CodeBlock because a CodeBlock's instructions must end with a terminal opcode.
</span><span class="cx"> if (generator.vm()->controlFlowProfiler())
</span><span class="lines">@@ -3287,57 +3279,32 @@
</span><span class="cx"> // optimizer knows they may be jumped to from anywhere.
</span><span class="cx">
</span><span class="cx"> ASSERT(m_catchBlock || m_finallyBlock);
</span><del>- BytecodeGenerator::FinallyRegistersScope finallyRegistersScope(generator, m_finallyBlock);
</del><span class="cx">
</span><del>- RefPtr<Label> catchLabel;
- RefPtr<Label> catchEndLabel;
- RefPtr<Label> finallyViaThrowLabel;
- RefPtr<Label> finallyLabel;
- RefPtr<Label> finallyEndLabel;
-
</del><span class="cx"> RefPtr<Label> tryStartLabel = generator.newLabel();
</span><span class="cx"> generator.emitLabel(tryStartLabel.get());
</span><ins>+
+ if (m_finallyBlock)
+ generator.pushFinallyControlFlowScope(m_finallyBlock);
+ TryData* tryData = generator.pushTry(tryStartLabel.get());
</ins><span class="cx">
</span><del>- if (m_finallyBlock) {
- finallyViaThrowLabel = generator.newLabel();
- finallyLabel = generator.newLabel();
- finallyEndLabel = generator.newLabel();
</del><ins>+ generator.emitNode(dst, m_tryBlock);
</ins><span class="cx">
</span><del>- generator.pushFinallyControlFlowScope(finallyLabel.get());
- }
</del><span class="cx"> if (m_catchBlock) {
</span><del>- catchLabel = generator.newLabel();
- catchEndLabel = generator.newLabel();
- }
-
- Label* tryHandlerLabel = m_catchBlock ? catchLabel.get() : finallyViaThrowLabel.get();
- HandlerType tryHandlerType = m_catchBlock ? HandlerType::Catch : HandlerType::Finally;
- TryData* tryData = generator.pushTry(tryStartLabel.get(), tryHandlerLabel, tryHandlerType);
-
- generator.emitNode(dst, m_tryBlock);
-
- // The finallyActionRegister is an empty value by default, which implies CompletionType::Normal.
- if (m_finallyBlock)
- generator.emitJump(finallyLabel.get());
- else
</del><ins>+ RefPtr<Label> catchEndLabel = generator.newLabel();
+
+ // Normal path: jump over the catch block.
</ins><span class="cx"> generator.emitJump(catchEndLabel.get());
</span><span class="cx">
</span><del>- RefPtr<Label> endTryLabel = generator.emitLabel(generator.newLabel().get());
- generator.popTry(tryData, endTryLabel.get());
-
- if (m_catchBlock) {
</del><span class="cx"> // Uncaught exception path: the catch block.
</span><del>- generator.emitLabel(catchLabel.get());
</del><ins>+ RefPtr<Label> here = generator.emitLabel(generator.newLabel().get());
+ RefPtr<RegisterID> exceptionRegister = generator.newTemporary();
</ins><span class="cx"> RefPtr<RegisterID> thrownValueRegister = generator.newTemporary();
</span><del>- RegisterID* unused = generator.newTemporary();
- generator.emitCatch(unused, thrownValueRegister.get());
- generator.restoreScopeRegister();
-
- TryData* tryData = nullptr;
</del><ins>+ generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), here.get(), HandlerType::Catch);
+
</ins><span class="cx"> if (m_finallyBlock) {
</span><span class="cx"> // If the catch block throws an exception and we have a finally block, then the finally
</span><span class="cx"> // block should "catch" that exception.
</span><del>- tryData = generator.pushTry(catchLabel.get(), finallyViaThrowLabel.get(), HandlerType::Finally);
</del><ins>+ tryData = generator.pushTry(here.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> generator.emitPushCatchScope(m_lexicalVariables);
</span><span class="lines">@@ -3349,38 +3316,37 @@
</span><span class="cx"> generator.emitNodeInTailPosition(dst, m_catchBlock);
</span><span class="cx"> generator.emitLoad(thrownValueRegister.get(), jsUndefined());
</span><span class="cx"> generator.emitPopCatchScope(m_lexicalVariables);
</span><del>-
- if (m_finallyBlock) {
- generator.emitSetFinallyActionToNormalCompletion();
- generator.emitJump(finallyLabel.get());
- generator.popTry(tryData, finallyViaThrowLabel.get());
- }
-
</del><span class="cx"> generator.emitLabel(catchEndLabel.get());
</span><del>- generator.emitProfileControlFlow(m_catchBlock->endOffset() + 1);
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (m_finallyBlock) {
</span><del>- FinallyContext finallyContext = generator.popFinallyControlFlowScope();
</del><ins>+ RefPtr<Label> preFinallyLabel = generator.emitLabel(generator.newLabel().get());
+
+ generator.popFinallyControlFlowScope();
</ins><span class="cx">
</span><del>- // Entry to the finally block for CompletionType::Throw.
- generator.emitLabel(finallyViaThrowLabel.get());
- RegisterID* unused = generator.newTemporary();
- generator.emitCatch(generator.finallyActionRegister(), unused);
- // Setting the finallyActionRegister to the caught exception here implies CompletionType::Throw.
</del><ins>+ RefPtr<Label> finallyEndLabel = generator.newLabel();
</ins><span class="cx">
</span><del>- // Entry to the finally block for CompletionTypes other than Throw.
- generator.emitLabel(finallyLabel.get());
- generator.restoreScopeRegister();
</del><ins>+ int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() + 1 : m_tryBlock->endOffset() + 1;
</ins><span class="cx">
</span><del>- int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() + 1 : m_tryBlock->endOffset() + 1;
</del><ins>+ // Normal path: run the finally code, and jump to the end.
</ins><span class="cx"> generator.emitProfileControlFlow(finallyStartOffset);
</span><span class="cx"> generator.emitNodeInTailPosition(dst, m_finallyBlock);
</span><ins>+ generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1);
+ generator.emitJump(finallyEndLabel.get());
</ins><span class="cx">
</span><del>- generator.emitFinallyCompletion(finallyContext, finallyEndLabel.get());
</del><ins>+ // Uncaught exception path: invoke the finally block, then re-throw the exception.
+ RefPtr<RegisterID> exceptionRegister = generator.newTemporary();
+ RefPtr<RegisterID> thrownValueRegister = generator.newTemporary();
+ generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), preFinallyLabel.get(), HandlerType::Finally);
+ generator.emitProfileControlFlow(finallyStartOffset);
+ generator.emitNodeInTailPosition(dst, m_finallyBlock);
+ generator.emitThrow(exceptionRegister.get());
+
</ins><span class="cx"> generator.emitLabel(finallyEndLabel.get());
</span><span class="cx"> generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1);
</span><del>- }
</del><ins>+ } else
+ generator.emitProfileControlFlow(m_catchBlock->endOffset() + 1);
+
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // ------------------------------ ScopeNode -----------------------------
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/WTF/ChangeLog        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-12-19 Mark Lam <mark.lam@apple.com>
+
+ Rolling out r209974 and r209952. They break some websites in mysterious ways. Step 2: Rollout r209952.
+ https://bugs.webkit.org/show_bug.cgi?id=166049
+
+ Not reviewed.
+
+ * wtf/SegmentedVector.h:
+ (WTF::SegmentedVector::last):
+ (WTF::SegmentedVector::first): Deleted.
+ (WTF::SegmentedVector::takeLast): Deleted.
+
</ins><span class="cx"> 2016-12-16 Mark Lam <mark.lam@apple.com>
</span><span class="cx">
</span><span class="cx"> Add predecessor info to dumps from JSC_dumpBytecodeLivenessResults=true.
</span></span></pre></div>
<a id="trunkSourceWTFwtfSegmentedVectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/SegmentedVector.h (210009 => 210010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/SegmentedVector.h        2016-12-20 02:01:21 UTC (rev 210009)
+++ trunk/Source/WTF/wtf/SegmentedVector.h        2016-12-20 02:03:02 UTC (rev 210010)
</span><span class="lines">@@ -127,17 +127,9 @@
</span><span class="cx"> return at(index);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- T& first() { return at(0); }
- const T& first() const { return at(0); }
- T& last() { return at(size() - 1); }
- const T& last() const { return at(size() - 1); }
-
- T takeLast()
</del><ins>+ T& last()
</ins><span class="cx"> {
</span><del>- ASSERT_WITH_SECURITY_IMPLICATION(!isEmpty());
- T result = WTFMove(last());
- --m_size;
- return result;
</del><ins>+ return at(size() - 1);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename... Args>
</span></span></pre>
</div>
</div>
</body>
</html>