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

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

<h3>Log Message</h3>
<pre>Rename finallyActionRegister to completionTypeRegister and only store int JSValues in it.
https://bugs.webkit.org/show_bug.cgi?id=165979

Reviewed by Saam Barati.

This patch makes it so that we only store int JSValues in the finallyActionRegister
thereby making type prediction on this register more successful for JITs.  In so
doing, we are able to get some additional benefits:

1. Renamed the following:
   FinallyRegistersScope =&gt; CompletionRecordScope
   finallyActionRegister =&gt; completionTypeRegister
   finallyReturnValueRegister =&gt; completionValueRegister

   These new names are more in line with the ES spec, which describes these
   values as the completion record and its type and value properties.
   https://tc39.github.io/ecma262/#sec-completion-record-specification-type

2. We now think of the Break and Continue jumpIDs as encodings of CompletionType
   (in our implementation of completion type).  As a result, we only need one of
   each of the emitter methods for getting, setting, and compare-and-jump on the
   completion type.  The code using these methods also reads much clearer now.

3. Finally blocks' op_catch should now always pop the caught Exception object into
   the completionValueRegister instead of the completionTypeRegister (formerly
   finallyActionRegister).

Also removed the restoreScopeRegister() call in the IteratorClose catch block
because that is an implementation specific synthesized catch block, and we
can guarantee that it never needs to resolve any symbols from the scope.  Hence,
there is no need to restore the scope register.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::emitJumpViaFinallyIfNeeded):
(JSC::BytecodeGenerator::emitReturnViaFinallyIfNeeded):
(JSC::BytecodeGenerator::emitFinallyCompletion):
(JSC::BytecodeGenerator::allocateCompletionRecordRegisters):
(JSC::BytecodeGenerator::releaseCompletionRecordRegisters):
(JSC::BytecodeGenerator::emitJumpIfCompletionType):
(JSC::BytecodeGenerator::allocateFinallyRegisters): Deleted.
(JSC::BytecodeGenerator::releaseFinallyRegisters): Deleted.
(JSC::BytecodeGenerator::emitCompareFinallyActionAndJumpIf): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::bytecodeOffsetToJumpID):
(JSC::FinallyJump::FinallyJump):
(JSC::FinallyContext::registerJump):
(JSC::BytecodeGenerator::CompletionRecordScope::CompletionRecordScope):
(JSC::BytecodeGenerator::CompletionRecordScope::~CompletionRecordScope):
(JSC::BytecodeGenerator::completionTypeRegister):
(JSC::BytecodeGenerator::completionValueRegister):
(JSC::BytecodeGenerator::emitSetCompletionType):
(JSC::BytecodeGenerator::emitSetCompletionValue):
(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::TryNode::emitBytecode):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209973 => 209974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-18 17:26:26 UTC (rev 209973)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-18 19:04:20 UTC (rev 209974)
</span><span class="lines">@@ -1,3 +1,76 @@
</span><ins>+2016-12-18  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Rename finallyActionRegister to completionTypeRegister and only store int JSValues in it.
+        https://bugs.webkit.org/show_bug.cgi?id=165979
+
+        Reviewed by Saam Barati.
+
+        This patch makes it so that we only store int JSValues in the finallyActionRegister
+        thereby making type prediction on this register more successful for JITs.  In so
+        doing, we are able to get some additional benefits:
+
+        1. Renamed the following:
+           FinallyRegistersScope =&gt; CompletionRecordScope
+           finallyActionRegister =&gt; completionTypeRegister
+           finallyReturnValueRegister =&gt; completionValueRegister
+
+           These new names are more in line with the ES spec, which describes these
+           values as the completion record and its type and value properties.
+           https://tc39.github.io/ecma262/#sec-completion-record-specification-type
+
+        2. We now think of the Break and Continue jumpIDs as encodings of CompletionType
+           (in our implementation of completion type).  As a result, we only need one of
+           each of the emitter methods for getting, setting, and compare-and-jump on the
+           completion type.  The code using these methods also reads much clearer now.  
+
+        3. Finally blocks' op_catch should now always pop the caught Exception object into
+           the completionValueRegister instead of the completionTypeRegister (formerly
+           finallyActionRegister). 
+
+        Also removed the restoreScopeRegister() call in the IteratorClose catch block
+        because that is an implementation specific synthesized catch block, and we
+        can guarantee that it never needs to resolve any symbols from the scope.  Hence,
+        there is no need to restore the scope register.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitEnumeration):
+        (JSC::BytecodeGenerator::emitJumpViaFinallyIfNeeded):
+        (JSC::BytecodeGenerator::emitReturnViaFinallyIfNeeded):
+        (JSC::BytecodeGenerator::emitFinallyCompletion):
+        (JSC::BytecodeGenerator::allocateCompletionRecordRegisters):
+        (JSC::BytecodeGenerator::releaseCompletionRecordRegisters):
+        (JSC::BytecodeGenerator::emitJumpIfCompletionType):
+        (JSC::BytecodeGenerator::allocateFinallyRegisters): Deleted.
+        (JSC::BytecodeGenerator::releaseFinallyRegisters): Deleted.
+        (JSC::BytecodeGenerator::emitCompareFinallyActionAndJumpIf): Deleted.
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::bytecodeOffsetToJumpID):
+        (JSC::FinallyJump::FinallyJump):
+        (JSC::FinallyContext::registerJump):
+        (JSC::BytecodeGenerator::CompletionRecordScope::CompletionRecordScope):
+        (JSC::BytecodeGenerator::CompletionRecordScope::~CompletionRecordScope):
+        (JSC::BytecodeGenerator::completionTypeRegister):
+        (JSC::BytecodeGenerator::completionValueRegister):
+        (JSC::BytecodeGenerator::emitSetCompletionType):
+        (JSC::BytecodeGenerator::emitSetCompletionValue):
+        (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::TryNode::emitBytecode):
+
</ins><span class="cx"> 2016-12-17  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WebAssembly: WasmB3IRGenerator uses WarmAny as a ValueRep but expects the incoming value to be a register
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (209973 => 209974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-12-18 17:26:26 UTC (rev 209973)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-12-18 19:04:20 UTC (rev 209974)
</span><span class="lines">@@ -4126,7 +4126,7 @@
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function&lt;void(BytecodeGenerator&amp;, RegisterID*)&gt;&amp; callBack, ForOfNode* forLoopNode, RegisterID* forLoopSymbolTable)
</span><span class="cx"> {
</span><del>-    FinallyRegistersScope finallyRegistersScope(*this);
</del><ins>+    CompletionRecordScope completionRecordScope(*this);
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;RegisterID&gt; subject = newTemporary();
</span><span class="cx">     emitNode(subject.get(), subjectNode);
</span><span class="lines">@@ -4169,11 +4169,19 @@
</span><span class="cx">             emitLabel(finallyViaThrowLabel.get());
</span><span class="cx">             popTry(tryData, finallyViaThrowLabel.get());
</span><span class="cx"> 
</span><ins>+            RefPtr&lt;Label&gt; finallyBodyLabel = newLabel();
+            RefPtr&lt;RegisterID&gt; finallyExceptionRegister = newTemporary();
</ins><span class="cx">             RegisterID* unused = newTemporary();
</span><del>-            emitCatch(finallyActionRegister(), unused);
-            // Setting the finallyActionRegister to the caught exception here implies CompletionType::Throw.
</del><span class="cx"> 
</span><ins>+            emitCatch(completionValueRegister(), unused);
+            emitSetCompletionType(CompletionType::Throw);
+            emitMove(finallyExceptionRegister.get(), completionValueRegister());
+            emitJump(finallyBodyLabel.get());
+
</ins><span class="cx">             emitLabel(finallyLabel.get());
</span><ins>+            emitMoveEmptyValue(finallyExceptionRegister.get());
+
+            emitLabel(finallyBodyLabel.get());
</ins><span class="cx">             restoreScopeRegister();
</span><span class="cx"> 
</span><span class="cx">             RefPtr&lt;Label&gt; finallyDone = newLabel();
</span><span class="lines">@@ -4181,9 +4189,6 @@
</span><span class="cx">             RefPtr&lt;RegisterID&gt; returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
</span><span class="cx">             emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), finallyDone.get());
</span><span class="cx"> 
</span><del>-            RefPtr&lt;RegisterID&gt; originalFinallyActionRegister = newTemporary();
-            emitMove(originalFinallyActionRegister.get(), finallyActionRegister());
-
</del><span class="cx">             RefPtr&lt;Label&gt; returnCallTryStart = newLabel();
</span><span class="cx">             emitLabel(returnCallTryStart.get());
</span><span class="cx">             TryData* returnCallTryData = pushTry(returnCallTryStart.get(), catchLabel.get(), HandlerType::SynthesizedCatch);
</span><span class="lines">@@ -4209,14 +4214,16 @@
</span><span class="cx">                 RefPtr&lt;RegisterID&gt; exceptionRegister = newTemporary();
</span><span class="cx">                 RegisterID* unused = newTemporary();
</span><span class="cx">                 emitCatch(exceptionRegister.get(), unused);
</span><del>-                restoreScopeRegister();
</del><ins>+                // Since this is a synthesized catch block and we're guaranteed to never need
+                // to resolve any symbols from the scope, we can skip restoring the scope
+                // register here.
</ins><span class="cx"> 
</span><span class="cx">                 RefPtr&lt;Label&gt; throwLabel = newLabel();
</span><del>-                emitJumpIfCompletionTypeIsThrow(originalFinallyActionRegister.get(), throwLabel.get());
-                emitMove(originalFinallyActionRegister.get(), exceptionRegister.get());
</del><ins>+                emitJumpIfTrue(emitIsEmpty(newTemporary(), finallyExceptionRegister.get()), throwLabel.get());
+                emitMove(exceptionRegister.get(), finallyExceptionRegister.get());
</ins><span class="cx"> 
</span><span class="cx">                 emitLabel(throwLabel.get());
</span><del>-                emitThrow(originalFinallyActionRegister.get());
</del><ins>+                emitThrow(exceptionRegister.get());
</ins><span class="cx"> 
</span><span class="cx">                 emitLabel(endCatchLabel.get());
</span><span class="cx">             }
</span><span class="lines">@@ -4819,11 +4826,11 @@
</span><span class="cx">     if (!outermostFinallyContext)
</span><span class="cx">         return false; // No finallys to thread through.
</span><span class="cx"> 
</span><del>-    int jumpID = bytecodeOffsetToJumpID(instructions().size());
</del><ins>+    auto jumpID = bytecodeOffsetToJumpID(instructions().size());
</ins><span class="cx">     int lexicalScopeIndex = labelScopeDepthToLexicalScopeIndex(targetLabelScopeDepth);
</span><span class="cx">     outermostFinallyContext-&gt;registerJump(jumpID, lexicalScopeIndex, jumpTarget);
</span><span class="cx"> 
</span><del>-    emitSetFinallyActionToJumpID(jumpID);
</del><ins>+    emitSetCompletionType(jumpID);
</ins><span class="cx">     emitJump(innermostFinallyContext-&gt;finallyLabel());
</span><span class="cx">     return true; // We'll be jumping to a finally block.
</span><span class="cx"> }
</span><span class="lines">@@ -4849,8 +4856,8 @@
</span><span class="cx">     if (!innermostFinallyContext)
</span><span class="cx">         return false; // No finallys to thread through.
</span><span class="cx"> 
</span><del>-    emitSetFinallyActionToReturnCompletion();
-    emitSetFinallyReturnValueRegister(returnRegister);
</del><ins>+    emitSetCompletionType(CompletionType::Return);
+    emitSetCompletionValue(returnRegister);
</ins><span class="cx">     emitJump(innermostFinallyContext-&gt;finallyLabel());
</span><span class="cx">     return true; // We'll be jumping to a finally block.
</span><span class="cx"> }
</span><span class="lines">@@ -4857,9 +4864,7 @@
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::emitFinallyCompletion(FinallyContext&amp; context, Label* normalCompletionLabel)
</span><span class="cx"> {
</span><del>-    // 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);
</del><ins>+    emitJumpIfCompletionType(op_stricteq, CompletionType::Normal, normalCompletionLabel);
</ins><span class="cx"> 
</span><span class="cx">     if (context.numberOfBreaksOrContinues() || context.handlesReturns()) {
</span><span class="cx">         FinallyContext* outerContext = context.outerContext();
</span><span class="lines">@@ -4869,10 +4874,10 @@
</span><span class="cx">             for (size_t i = 0; i &lt; numberOfJumps; i++) {
</span><span class="cx">                 RefPtr&lt;Label&gt; nextLabel = newLabel();
</span><span class="cx">                 auto&amp; jump = context.jumps(i);
</span><del>-                emitJumpIfFinallyActionIsNotJump(jump.jumpID, nextLabel.get());
</del><ins>+                emitJumpIfCompletionType(op_nstricteq, jump.jumpID, nextLabel.get());
</ins><span class="cx"> 
</span><span class="cx">                 restoreScopeRegister(jump.targetLexicalScopeIndex);
</span><del>-                emitSetFinallyActionToNormalCompletion();
</del><ins>+                emitSetCompletionType(CompletionType::Normal);
</ins><span class="cx">                 emitJump(jump.targetLabel.get());
</span><span class="cx"> 
</span><span class="cx">                 emitLabel(nextLabel.get());
</span><span class="lines">@@ -4880,7 +4885,7 @@
</span><span class="cx"> 
</span><span class="cx">             bool hasBreaksOrContinuesNotCoveredByJumps = context.numberOfBreaksOrContinues() &gt; numberOfJumps;
</span><span class="cx">             if (hasBreaksOrContinuesNotCoveredByJumps || context.handlesReturns())
</span><del>-                emitJumpIfFinallyActionIsNotThrowCompletion(outerContext-&gt;finallyLabel());
</del><ins>+                emitJumpIfCompletionType(op_nstricteq, CompletionType::Throw, outerContext-&gt;finallyLabel());
</ins><span class="cx"> 
</span><span class="cx">         } else {
</span><span class="cx">             // We are the outermost finally.
</span><span class="lines">@@ -4890,10 +4895,10 @@
</span><span class="cx">             for (size_t i = 0; i &lt; numberOfJumps; i++) {
</span><span class="cx">                 RefPtr&lt;Label&gt; nextLabel = newLabel();
</span><span class="cx">                 auto&amp; jump = context.jumps(i);
</span><del>-                emitJumpIfFinallyActionIsNotJump(jump.jumpID, nextLabel.get());
</del><ins>+                emitJumpIfCompletionType(op_nstricteq, jump.jumpID, nextLabel.get());
</ins><span class="cx"> 
</span><span class="cx">                 restoreScopeRegister(jump.targetLexicalScopeIndex);
</span><del>-                emitSetFinallyActionToNormalCompletion();
</del><ins>+                emitSetCompletionType(CompletionType::Normal);
</ins><span class="cx">                 emitJump(jump.targetLabel.get());
</span><span class="cx"> 
</span><span class="cx">                 emitLabel(nextLabel.get());
</span><span class="lines">@@ -4901,46 +4906,46 @@
</span><span class="cx"> 
</span><span class="cx">             if (context.handlesReturns()) {
</span><span class="cx">                 RefPtr&lt;Label&gt; notReturnLabel = newLabel();
</span><del>-                emitJumpIfFinallyActionIsNotReturnCompletion(notReturnLabel.get());
</del><ins>+                emitJumpIfCompletionType(op_nstricteq, CompletionType::Return, notReturnLabel.get());
</ins><span class="cx"> 
</span><span class="cx">                 emitWillLeaveCallFrameDebugHook();
</span><del>-                emitReturn(finallyReturnValueRegister(), ReturnFrom::Finally);
</del><ins>+                emitReturn(completionValueRegister(), ReturnFrom::Finally);
</ins><span class="cx">                 
</span><span class="cx">                 emitLabel(notReturnLabel.get());
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    emitThrow(finallyActionRegister());
</del><ins>+    emitThrow(completionValueRegister());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool BytecodeGenerator::allocateFinallyRegisters()
</del><ins>+bool BytecodeGenerator::allocateCompletionRecordRegisters()
</ins><span class="cx"> {
</span><del>-    if (m_finallyActionRegister)
</del><ins>+    if (m_completionTypeRegister)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    ASSERT(!m_finallyReturnValueRegister);
-    m_finallyActionRegister = newTemporary();
-    m_finallyReturnValueRegister = newTemporary();
</del><ins>+    ASSERT(!m_completionValueRegister);
+    m_completionTypeRegister = newTemporary();
+    m_completionValueRegister = newTemporary();
</ins><span class="cx"> 
</span><del>-    emitSetFinallyActionToNormalCompletion();
-    emitMoveEmptyValue(m_finallyReturnValueRegister.get());
</del><ins>+    emitSetCompletionType(CompletionType::Normal);
+    emitMoveEmptyValue(m_completionValueRegister.get());
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void BytecodeGenerator::releaseFinallyRegisters()
</del><ins>+void BytecodeGenerator::releaseCompletionRecordRegisters()
</ins><span class="cx"> {
</span><del>-    ASSERT(m_finallyActionRegister &amp;&amp; m_finallyReturnValueRegister);
-    m_finallyActionRegister = nullptr;
-    m_finallyReturnValueRegister = nullptr;
</del><ins>+    ASSERT(m_completionTypeRegister &amp;&amp; m_completionValueRegister);
+    m_completionTypeRegister = nullptr;
+    m_completionValueRegister = nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void BytecodeGenerator::emitCompareFinallyActionAndJumpIf(OpcodeID compareOpcode, int value, Label* jumpTarget)
</del><ins>+void BytecodeGenerator::emitJumpIfCompletionType(OpcodeID compareOpcode, CompletionType type, Label* jumpTarget)
</ins><span class="cx"> {
</span><span class="cx">     RefPtr&lt;RegisterID&gt; tempRegister = newTemporary();
</span><del>-    RegisterID* valueConstant = addConstantValue(JSValue(value));
</del><ins>+    RegisterID* valueConstant = addConstantValue(JSValue(static_cast&lt;int&gt;(type)));
</ins><span class="cx">     OperandTypes operandTypes = OperandTypes(ResultType::numberTypeIsInt32(), ResultType::unknownType());
</span><span class="cx"> 
</span><del>-    auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, finallyActionRegister(), operandTypes);
</del><ins>+    auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, completionTypeRegister(), operandTypes);
</ins><span class="cx">     emitJumpIfTrue(equivalenceResult, jumpTarget);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (209973 => 209974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-12-18 17:26:26 UTC (rev 209973)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-12-18 19:04:20 UTC (rev 209974)
</span><span class="lines">@@ -80,15 +80,41 @@
</span><span class="cx">         unsigned m_padding;
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    // https://tc39.github.io/ecma262/#sec-completion-record-specification-type
+    //
+    // For the Break and Continue cases, instead of using the Break and Continue enum values
+    // below, we use the unique jumpID of the break and continue statement as the encoding
+    // for the CompletionType value. emitFinallyCompletion() uses this jumpID value later
+    // to determine the appropriate jump target to jump to after executing the relevant finally
+    // blocks. The jumpID is computed as:
+    //     jumpID = bytecodeOffset (of the break/continue node) + CompletionType::NumberOfTypes.
+    // Hence, there won't be any collision between jumpIDs and CompletionType enums.
+    enum class CompletionType : int {
+        Normal,
+        Break,
+        Continue,
+        Return,
+        Throw,
+        
+        NumberOfTypes
+    };
+
+    inline CompletionType bytecodeOffsetToJumpID(unsigned offset)
+    {
+        int jumpIDAsInt = offset + static_cast&lt;int&gt;(CompletionType::NumberOfTypes);
+        ASSERT(jumpIDAsInt &gt;= static_cast&lt;int&gt;(CompletionType::NumberOfTypes));
+        return static_cast&lt;CompletionType&gt;(jumpIDAsInt);
+    }
+
</ins><span class="cx">     struct FinallyJump {
</span><del>-        FinallyJump(int jumpID, int targetLexicalScopeIndex, Label* targetLabel)
</del><ins>+        FinallyJump(CompletionType jumpID, int targetLexicalScopeIndex, Label* targetLabel)
</ins><span class="cx">             : jumpID(jumpID)
</span><span class="cx">             , targetLexicalScopeIndex(targetLexicalScopeIndex)
</span><span class="cx">             , targetLabel(targetLabel)
</span><span class="cx">         { }
</span><span class="cx"> 
</span><del>-        int jumpID { 0 };
-        int targetLexicalScopeIndex { 0 };
</del><ins>+        CompletionType jumpID;
+        int targetLexicalScopeIndex;
</ins><span class="cx">         RefPtr&lt;Label&gt; targetLabel;
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="lines">@@ -116,7 +142,7 @@
</span><span class="cx">         bool handlesReturns() const { return m_handlesReturns; }
</span><span class="cx">         void setHandlesReturns() { m_handlesReturns = true; }
</span><span class="cx"> 
</span><del>-        void registerJump(int jumpID, int lexicalScopeIndex, Label* targetLabel)
</del><ins>+        void registerJump(CompletionType jumpID, int lexicalScopeIndex, Label* targetLabel)
</ins><span class="cx">         {
</span><span class="cx">             if (!m_jumps)
</span><span class="cx">                 m_jumps = std::make_unique&lt;Vector&lt;FinallyJump&gt;&gt;();
</span><span class="lines">@@ -775,18 +801,18 @@
</span><span class="cx">         void emitDebugHook(ExpressionNode*);
</span><span class="cx">         void emitWillLeaveCallFrameDebugHook();
</span><span class="cx"> 
</span><del>-        class FinallyRegistersScope {
</del><ins>+        class CompletionRecordScope {
</ins><span class="cx">         public:
</span><del>-            FinallyRegistersScope(BytecodeGenerator&amp; generator, bool needFinallyRegisters = true)
</del><ins>+            CompletionRecordScope(BytecodeGenerator&amp; generator, bool needCompletionRecordRegisters = true)
</ins><span class="cx">                 : m_generator(generator)
</span><span class="cx">             {
</span><del>-                if (needFinallyRegisters &amp;&amp; m_generator.allocateFinallyRegisters())
</del><ins>+                if (needCompletionRecordRegisters &amp;&amp; m_generator.allocateCompletionRecordRegisters())
</ins><span class="cx">                     m_needToReleaseOnDestruction = true;
</span><span class="cx">             }
</span><del>-            ~FinallyRegistersScope()
</del><ins>+            ~CompletionRecordScope()
</ins><span class="cx">             {
</span><span class="cx">                 if (m_needToReleaseOnDestruction)
</span><del>-                    m_generator.releaseFinallyRegisters();
</del><ins>+                    m_generator.releaseCompletionRecordRegisters();
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">         private:
</span><span class="lines">@@ -794,79 +820,36 @@
</span><span class="cx">             bool m_needToReleaseOnDestruction { false };
</span><span class="cx">         };
</span><span class="cx"> 
</span><del>-        RegisterID* finallyActionRegister() const
</del><ins>+        RegisterID* completionTypeRegister() const
</ins><span class="cx">         {
</span><del>-            ASSERT(m_finallyActionRegister);
-            return m_finallyActionRegister.get();
</del><ins>+            ASSERT(m_completionTypeRegister);
+            return m_completionTypeRegister.get();
</ins><span class="cx">         }
</span><del>-        RegisterID* finallyReturnValueRegister() const
</del><ins>+        RegisterID* completionValueRegister() const
</ins><span class="cx">         {
</span><del>-            ASSERT(m_finallyReturnValueRegister);
-            return m_finallyReturnValueRegister.get();
</del><ins>+            ASSERT(m_completionValueRegister);
+            return m_completionValueRegister.get();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        void emitSetFinallyActionToNormalCompletion()
</del><ins>+        void emitSetCompletionType(CompletionType type)
</ins><span class="cx">         {
</span><del>-            emitMoveEmptyValue(m_finallyActionRegister.get());
</del><ins>+            emitLoad(completionTypeRegister(), JSValue(static_cast&lt;int&gt;(type)));
</ins><span class="cx">         }
</span><del>-        void emitSetFinallyActionToReturnCompletion()
</del><ins>+        void emitSetCompletionValue(RegisterID* reg)
</ins><span class="cx">         {
</span><del>-            emitLoad(finallyActionRegister(), JSValue(static_cast&lt;int&gt;(CompletionType::Return)));
</del><ins>+            emitMove(completionValueRegister(), reg);
</ins><span class="cx">         }
</span><del>-        void emitSetFinallyActionToJumpID(int jumpID)
-        {
-            emitLoad(finallyActionRegister(), JSValue(jumpID));
-        }
-        void emitSetFinallyReturnValueRegister(RegisterID* reg)
-        {
-            emitMove(finallyReturnValueRegister(), reg);
-        }
</del><span class="cx"> 
</span><del>-        void emitJumpIfFinallyActionIsNormalCompletion(Label* jumpTarget)
-        {
-            emitJumpIfTrue(emitIsEmpty(newTemporary(), finallyActionRegister()), jumpTarget);
-        }
</del><ins>+        void emitJumpIfCompletionType(OpcodeID compareOpcode, CompletionType, Label* jumpTarget);
</ins><span class="cx"> 
</span><del>-        void emitJumpIfFinallyActionIsNotJump(int jumpID, Label* jumpTarget)
-        {
-            emitCompareFinallyActionAndJumpIf(op_nstricteq, jumpID, jumpTarget);
-        }
-
-        void emitJumpIfFinallyActionIsReturnCompletion(Label* jumpTarget)
-        {
-            emitCompareFinallyActionAndJumpIf(op_stricteq, static_cast&lt;int&gt;(CompletionType::Return), jumpTarget);
-        }
-        void emitJumpIfFinallyActionIsNotReturnCompletion(Label* jumpTarget)
-        {
-            emitCompareFinallyActionAndJumpIf(op_nstricteq, static_cast&lt;int&gt;(CompletionType::Return), jumpTarget);
-        }
-
-        void emitJumpIfFinallyActionIsNotThrowCompletion(Label* jumpTarget)
-        {
-            emitJumpIfTrue(emitIsNumber(newTemporary(), finallyActionRegister()), jumpTarget);
-        }
-        void emitJumpIfCompletionTypeIsThrow(RegisterID* reg, Label* jumpTarget)
-        {
-            emitJumpIfFalse(emitIsNumber(newTemporary(), reg), jumpTarget);
-        }
-
</del><span class="cx">         bool emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label* jumpTarget);
</span><span class="cx">         bool emitReturnViaFinallyIfNeeded(RegisterID* returnRegister);
</span><span class="cx">         void emitFinallyCompletion(FinallyContext&amp;, Label* normalCompletionLabel);
</span><span class="cx"> 
</span><span class="cx">     private:
</span><del>-        void emitCompareFinallyActionAndJumpIf(OpcodeID compareOpcode, int value, Label* jumpTarget);
</del><ins>+        bool allocateCompletionRecordRegisters();
+        void releaseCompletionRecordRegisters();
</ins><span class="cx"> 
</span><del>-        int bytecodeOffsetToJumpID(unsigned offset)
-        {
-            int jumpID = offset + static_cast&lt;int&gt;(CompletionType::NumberOfTypes);
-            ASSERT(jumpID &gt;= static_cast&lt;int&gt;(CompletionType::NumberOfTypes));
-            return jumpID;
-        }
-
-        bool allocateFinallyRegisters();
-        void releaseFinallyRegisters();
-
</del><span class="cx">     public:
</span><span class="cx">         FinallyContext* pushFinallyControlFlowScope(Label* finallyLabel);
</span><span class="cx">         FinallyContext popFinallyControlFlowScope();
</span><span class="lines">@@ -1100,33 +1083,9 @@
</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.
</del><ins>+        RefPtr&lt;RegisterID&gt; m_completionTypeRegister;
+        RefPtr&lt;RegisterID&gt; m_completionValueRegister;
</ins><span class="cx"> 
</span><del>-        enum class CompletionType : int {
-            Normal,
-            Break,
-            Continue,
-            Return,
-            Throw,
-
-            NumberOfTypes
-        };
-
-        RefPtr&lt;RegisterID&gt; m_finallyActionRegister;
-        RefPtr&lt;RegisterID&gt; m_finallyReturnValueRegister;
-
</del><span class="cx">         FinallyContext* m_currentFinallyContext { nullptr };
</span><span class="cx"> 
</span><span class="cx">         SegmentedVector&lt;RegisterID*, 16&gt; m_localRegistersForCalleeSaveRegisters;
</span><span class="lines">@@ -1143,7 +1102,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. 
</del><ins>+        // FIXME: Restore overflow checking with UnsafeVectorOverflow once SegmentVector supports it.
</ins><span class="cx">         // https://bugs.webkit.org/show_bug.cgi?id=165980
</span><span class="cx">         SegmentedVector&lt;ControlFlowScope, 16&gt; m_controlFlowScopeStack;
</span><span class="cx">         Vector&lt;SwitchInfo&gt; m_switchContextStack;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (209973 => 209974)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2016-12-18 17:26:26 UTC (rev 209973)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2016-12-18 19:04:20 UTC (rev 209974)
</span><span class="lines">@@ -3287,7 +3287,7 @@
</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><ins>+    BytecodeGenerator::CompletionRecordScope completionRecordScope(generator, m_finallyBlock);
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;Label&gt; catchLabel;
</span><span class="cx">     RefPtr&lt;Label&gt; catchEndLabel;
</span><span class="lines">@@ -3316,7 +3316,6 @@
</span><span class="cx"> 
</span><span class="cx">     generator.emitNode(dst, m_tryBlock);
</span><span class="cx"> 
</span><del>-    // The finallyActionRegister is an empty value by default, which implies CompletionType::Normal.
</del><span class="cx">     if (m_finallyBlock)
</span><span class="cx">         generator.emitJump(finallyLabel.get());
</span><span class="cx">     else
</span><span class="lines">@@ -3351,7 +3350,7 @@
</span><span class="cx">         generator.emitPopCatchScope(m_lexicalVariables);
</span><span class="cx"> 
</span><span class="cx">         if (m_finallyBlock) {
</span><del>-            generator.emitSetFinallyActionToNormalCompletion();
</del><ins>+            generator.emitSetCompletionType(CompletionType::Normal);
</ins><span class="cx">             generator.emitJump(finallyLabel.get());
</span><span class="cx">             generator.popTry(tryData, finallyViaThrowLabel.get());
</span><span class="cx">         }
</span><span class="lines">@@ -3366,8 +3365,8 @@
</span><span class="cx">         // Entry to the finally block for CompletionType::Throw.
</span><span class="cx">         generator.emitLabel(finallyViaThrowLabel.get());
</span><span class="cx">         RegisterID* unused = generator.newTemporary();
</span><del>-        generator.emitCatch(generator.finallyActionRegister(), unused);
-        // Setting the finallyActionRegister to the caught exception here implies CompletionType::Throw.
</del><ins>+        generator.emitCatch(generator.completionValueRegister(), unused);
+        generator.emitSetCompletionType(CompletionType::Throw);
</ins><span class="cx"> 
</span><span class="cx">         // Entry to the finally block for CompletionTypes other than Throw.
</span><span class="cx">         generator.emitLabel(finallyLabel.get());
</span></span></pre>
</div>
</div>

</body>
</html>