<!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>[185083] 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/185083">185083</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-06-01 16:22:22 -0700 (Mon, 01 Jun 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add the ability to tell between Catch and Finally blocks.
https://bugs.webkit.org/show_bug.cgi?id=145524 

Reviewed by Michael Saboff.

... and also SynthesizedFinally blocks too.  A SynthesizedFinally block
is a finally block that is synthesized by the bytecode generator but
does not actually correspond to any exception handling construct at the
JS source code level.  An example of this is the &quot;for ... of&quot; statement
where it needs to do some &quot;final&quot; clean up before passing on the
exception.

Manually tested by inspecting the bytecode dump of functions with
try-catch-finally blocks as well as for of statements which have
synthesized finally blocks.  The bytecode dumps contains the exception
handlers table which has these blocks labelled with their newly added
types.  No automatic test because this type info is not visible to JS
code.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/HandlerInfo.h:
(JSC::HandlerInfoBase::type):
(JSC::HandlerInfoBase::setType):
(JSC::HandlerInfoBase::typeName):
(JSC::HandlerInfoBase::isCatchHandler):
(JSC::UnlinkedHandlerInfo::UnlinkedHandlerInfo):
(JSC::HandlerInfo::initialize):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::pushTry):
(JSC::BytecodeGenerator::popTryAndEmitCatch):
(JSC::BytecodeGenerator::emitEnumeration):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitThrow):
* 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="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (185082 => 185083)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-06-01 22:46:37 UTC (rev 185082)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-06-01 23:22:22 UTC (rev 185083)
</span><span class="lines">@@ -1,3 +1,43 @@
</span><ins>+2015-06-01  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Add the ability to tell between Catch and Finally blocks.
+        https://bugs.webkit.org/show_bug.cgi?id=145524 
+
+        Reviewed by Michael Saboff.
+
+        ... and also SynthesizedFinally blocks too.  A SynthesizedFinally block
+        is a finally block that is synthesized by the bytecode generator but
+        does not actually correspond to any exception handling construct at the
+        JS source code level.  An example of this is the &quot;for ... of&quot; statement
+        where it needs to do some &quot;final&quot; clean up before passing on the
+        exception.
+
+        Manually tested by inspecting the bytecode dump of functions with
+        try-catch-finally blocks as well as for of statements which have
+        synthesized finally blocks.  The bytecode dumps contains the exception
+        handlers table which has these blocks labelled with their newly added
+        types.  No automatic test because this type info is not visible to JS
+        code.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/HandlerInfo.h:
+        (JSC::HandlerInfoBase::type):
+        (JSC::HandlerInfoBase::setType):
+        (JSC::HandlerInfoBase::typeName):
+        (JSC::HandlerInfoBase::isCatchHandler):
+        (JSC::UnlinkedHandlerInfo::UnlinkedHandlerInfo):
+        (JSC::HandlerInfo::initialize):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::pushTry):
+        (JSC::BytecodeGenerator::popTryAndEmitCatch):
+        (JSC::BytecodeGenerator::emitEnumeration):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitThrow):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::TryNode::emitBytecode):
+
</ins><span class="cx"> 2015-05-29  Geoffrey Garen  &lt;ggaren@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION: These sorting idioms used by Peacekeeper and Browsermark are ~20X slower
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (185082 => 185083)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-06-01 22:46:37 UTC (rev 185082)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-06-01 23:22:22 UTC (rev 185083)
</span><span class="lines">@@ -655,8 +655,8 @@
</span><span class="cx">         unsigned i = 0;
</span><span class="cx">         do {
</span><span class="cx">             HandlerInfo&amp; handler = m_rareData-&gt;m_exceptionHandlers[i];
</span><del>-            out.printf(&quot;\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] }\n&quot;,
-                i + 1, handler.start, handler.end, handler.target, handler.scopeDepth);
</del><ins>+            out.printf(&quot;\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] } %s\n&quot;,
+                i + 1, handler.start, handler.end, handler.target, handler.scopeDepth, handler.typeName());
</ins><span class="cx">             ++i;
</span><span class="cx">         } while (i &lt; m_rareData-&gt;m_exceptionHandlers.size());
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeHandlerInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h (185082 => 185083)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h        2015-06-01 22:46:37 UTC (rev 185082)
+++ trunk/Source/JavaScriptCore/bytecode/HandlerInfo.h        2015-06-01 23:22:22 UTC (rev 185083)
</span><span class="lines">@@ -30,20 +30,50 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+enum class HandlerType {
+    Illegal = 0,
+    Catch = 1,
+    Finally = 2,
+    SynthesizedFinally = 3
+};
+
</ins><span class="cx"> struct HandlerInfoBase {
</span><ins>+    HandlerType type() const { return static_cast&lt;HandlerType&gt;(typeBits); }
+    void setType(HandlerType type) { typeBits = static_cast&lt;uint32_t&gt;(type); }
+    
+    const char* typeName()
+    {
+        switch (type()) {
+        case HandlerType::Catch:
+            return &quot;catch&quot;;
+        case HandlerType::Finally:
+            return &quot;finally&quot;;
+        case HandlerType::SynthesizedFinally:
+            return &quot;synthesized finally&quot;;
+        default:
+            ASSERT_NOT_REACHED();
+        }
+        return nullptr;
+    }
+    
+    bool isCatchHandler() const { return type() == HandlerType::Catch; }
+    
</ins><span class="cx">     uint32_t start;
</span><span class="cx">     uint32_t end;
</span><span class="cx">     uint32_t target;
</span><del>-    uint32_t scopeDepth;
</del><ins>+    uint32_t scopeDepth : 30;
+    uint32_t typeBits : 2; // HandlerType
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct UnlinkedHandlerInfo : public HandlerInfoBase {
</span><del>-    UnlinkedHandlerInfo(uint32_t start, uint32_t end, uint32_t target, uint32_t scopeDepth)
</del><ins>+    UnlinkedHandlerInfo(uint32_t start, uint32_t end, uint32_t target, uint32_t scopeDepth, HandlerType handlerType)
</ins><span class="cx">     {
</span><span class="cx">         this-&gt;start = start;
</span><span class="cx">         this-&gt;end = end;
</span><span class="cx">         this-&gt;target = target;
</span><span class="cx">         this-&gt;scopeDepth = scopeDepth;
</span><ins>+        setType(handlerType);
+        ASSERT(type() == handlerType);
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -54,6 +84,7 @@
</span><span class="cx">         end = unlinkedInfo.end;
</span><span class="cx">         target = unlinkedInfo.target;
</span><span class="cx">         scopeDepth = unlinkedInfo.scopeDepth + nonLocalScopeDepth;
</span><ins>+        typeBits = unlinkedInfo.typeBits;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (185082 => 185083)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-06-01 22:46:37 UTC (rev 185082)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-06-01 23:22:22 UTC (rev 185083)
</span><span class="lines">@@ -129,8 +129,10 @@
</span><span class="cx">             continue;
</span><span class="cx">         
</span><span class="cx">         ASSERT(range.tryData-&gt;targetScopeDepth != UINT_MAX);
</span><ins>+        ASSERT(range.tryData-&gt;handlerType != HandlerType::Illegal);
</ins><span class="cx">         UnlinkedHandlerInfo info(static_cast&lt;uint32_t&gt;(start), static_cast&lt;uint32_t&gt;(end),
</span><del>-            static_cast&lt;uint32_t&gt;(range.tryData-&gt;target-&gt;bind()), range.tryData-&gt;targetScopeDepth);
</del><ins>+            static_cast&lt;uint32_t&gt;(range.tryData-&gt;target-&gt;bind()), range.tryData-&gt;targetScopeDepth,
+            range.tryData-&gt;handlerType);
</ins><span class="cx">         m_codeBlock-&gt;addExceptionHandler(info);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -2513,6 +2515,7 @@
</span><span class="cx">     TryData tryData;
</span><span class="cx">     tryData.target = newLabel();
</span><span class="cx">     tryData.targetScopeDepth = UINT_MAX;
</span><ins>+    tryData.handlerType = HandlerType::Illegal;
</ins><span class="cx">     m_tryData.append(tryData);
</span><span class="cx">     TryData* result = &amp;m_tryData.last();
</span><span class="cx">     
</span><span class="lines">@@ -2525,7 +2528,7 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* targetRegister, Label* end)
</del><ins>+RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* targetRegister, Label* end, HandlerType handlerType)
</ins><span class="cx"> {
</span><span class="cx">     m_usesExceptions = true;
</span><span class="cx">     
</span><span class="lines">@@ -2540,6 +2543,7 @@
</span><span class="cx">     
</span><span class="cx">     emitLabel(tryRange.tryData-&gt;target.get());
</span><span class="cx">     tryRange.tryData-&gt;targetScopeDepth = m_localScopeDepth;
</span><ins>+    tryRange.tryData-&gt;handlerType = handlerType;
</ins><span class="cx"> 
</span><span class="cx">     emitOpcode(op_catch);
</span><span class="cx">     instructions().append(targetRegister-&gt;index());
</span><span class="lines">@@ -2756,7 +2760,7 @@
</span><span class="cx">         // IteratorClose sequence for throw-ed control flow.
</span><span class="cx">         {
</span><span class="cx">             RefPtr&lt;Label&gt; catchHere = emitLabel(newLabel().get());
</span><del>-            RefPtr&lt;RegisterID&gt; exceptionRegister = popTryAndEmitCatch(tryData, newTemporary(), catchHere.get());
</del><ins>+            RefPtr&lt;RegisterID&gt; exceptionRegister = popTryAndEmitCatch(tryData, newTemporary(), catchHere.get(), HandlerType::SynthesizedFinally);
</ins><span class="cx">             RefPtr&lt;Label&gt; catchDone = newLabel();
</span><span class="cx"> 
</span><span class="cx">             RefPtr&lt;RegisterID&gt; returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
</span><span class="lines">@@ -2774,7 +2778,7 @@
</span><span class="cx">             emitThrow(exceptionRegister.get());
</span><span class="cx"> 
</span><span class="cx">             // Absorb exception.
</span><del>-            popTryAndEmitCatch(returnCallTryData, newTemporary(), catchDone.get());
</del><ins>+            popTryAndEmitCatch(returnCallTryData, newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally);
</ins><span class="cx">             emitThrow(exceptionRegister.get());
</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 (185082 => 185083)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-06-01 22:46:37 UTC (rev 185082)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-06-01 23:22:22 UTC (rev 185083)
</span><span class="lines">@@ -175,6 +175,7 @@
</span><span class="cx">     struct TryData {
</span><span class="cx">         RefPtr&lt;Label&gt; target;
</span><span class="cx">         unsigned targetScopeDepth;
</span><ins>+        HandlerType handlerType;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct TryContext {
</span><span class="lines">@@ -552,7 +553,7 @@
</span><span class="cx">         // Start a try block. 'start' must have been emitted.
</span><span class="cx">         TryData* pushTry(Label* start);
</span><span class="cx">         // End a try block. 'end' must have been emitted.
</span><del>-        RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end);
</del><ins>+        RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end, HandlerType);
</ins><span class="cx"> 
</span><span class="cx">         void emitThrow(RegisterID* exc)
</span><span class="cx">         { 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (185082 => 185083)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-06-01 22:46:37 UTC (rev 185082)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-06-01 23:22:22 UTC (rev 185083)
</span><span class="lines">@@ -2881,7 +2881,7 @@
</span><span class="cx"> 
</span><span class="cx">         // Uncaught exception path: the catch block.
</span><span class="cx">         RefPtr&lt;Label&gt; here = generator.emitLabel(generator.newLabel().get());
</span><del>-        RefPtr&lt;RegisterID&gt; exceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), here.get());
</del><ins>+        RefPtr&lt;RegisterID&gt; exceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), here.get(), HandlerType::Catch);
</ins><span class="cx">         
</span><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="lines">@@ -2912,7 +2912,7 @@
</span><span class="cx">         generator.emitJump(finallyEndLabel.get());
</span><span class="cx"> 
</span><span class="cx">         // Uncaught exception path: invoke the finally block, then re-throw the exception.
</span><del>-        RefPtr&lt;RegisterID&gt; tempExceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), preFinallyLabel.get());
</del><ins>+        RefPtr&lt;RegisterID&gt; tempExceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), preFinallyLabel.get(), HandlerType::Finally);
</ins><span class="cx">         generator.emitProfileControlFlow(finallyStartOffset);
</span><span class="cx">         generator.emitNode(dst, m_finallyBlock);
</span><span class="cx">         generator.emitThrow(tempExceptionRegister.get());
</span></span></pre>
</div>
</div>

</body>
</html>