<!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>[163328] 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/163328">163328</a></dd>
<dt>Author</dt> <dd>oliver@apple.com</dd>
<dt>Date</dt> <dd>2014-02-03 14:43:28 -0800 (Mon, 03 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Deconstructed parameters aren't being placed in the correct scope
https://bugs.webkit.org/show_bug.cgi?id=128126

Reviewed by Antti Koivisto.

Source/JavaScriptCore:

Make sure we declare the bound parameter names as variables when
we reparse.  In the BytecodeGenerator we now also directly ensure
that bound parameters are placed in the symbol table of the function
we're currently compiling.  We then delay binding until just before
we start codegen for the body of the function so that we can ensure
the function has completely initialised all scope details.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
* bytecompiler/BytecodeGenerator.h:
* parser/Parser.cpp:
(JSC::Parser&lt;LexerType&gt;::Parser):
(JSC::Parser&lt;LexerType&gt;::createBindingPattern):

LayoutTests:

Added tests for correct behaviour.

* js/deconstructing-parameters-should-be-locals-expected.txt: Added.
* js/deconstructing-parameters-should-be-locals.html: Added.
* js/script-tests/deconstructing-parameters-should-be-locals.js: Added.
(description.value.string_appeared_here.readDeconstructedParameter):
(overwriteDeconstructedParameter):
(readCapturedDeconstructedParameter):
(overwriteCapturedDeconstructedParameter):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<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="#trunkSourceJavaScriptCoreparserParsercpp">trunk/Source/JavaScriptCore/parser/Parser.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsdeconstructingparametersshouldbelocalsexpectedtxt">trunk/LayoutTests/js/deconstructing-parameters-should-be-locals-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsdeconstructingparametersshouldbelocalshtml">trunk/LayoutTests/js/deconstructing-parameters-should-be-locals.html</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsdeconstructingparametersshouldbelocalsjs">trunk/LayoutTests/js/script-tests/deconstructing-parameters-should-be-locals.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (163327 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-03 22:39:38 UTC (rev 163327)
+++ trunk/LayoutTests/ChangeLog        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2014-02-03  Oliver Hunt  &lt;oliver@apple.com&gt;
+
+        Deconstructed parameters aren't being placed in the correct scope
+        https://bugs.webkit.org/show_bug.cgi?id=128126
+
+        Reviewed by Antti Koivisto.
+
+        Added tests for correct behaviour.
+
+        * js/deconstructing-parameters-should-be-locals-expected.txt: Added.
+        * js/deconstructing-parameters-should-be-locals.html: Added.
+        * js/script-tests/deconstructing-parameters-should-be-locals.js: Added.
+        (description.value.string_appeared_here.readDeconstructedParameter):
+        (overwriteDeconstructedParameter):
+        (readCapturedDeconstructedParameter):
+        (overwriteCapturedDeconstructedParameter):
+
</ins><span class="cx"> 2014-01-31  Geoffrey Garen  &lt;ggaren@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Simplified name scope creation for function expressions
</span></span></pre></div>
<a id="trunkLayoutTestsjsdeconstructingparametersshouldbelocalsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/deconstructing-parameters-should-be-locals-expected.txt (0 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/deconstructing-parameters-should-be-locals-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/deconstructing-parameters-should-be-locals-expected.txt        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+This tests to ensure that ddeconstructing parameters behave like regular locals
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS readDeconstructedParameter(['inner']) is 'inner'
+PASS overwriteDeconstructedParameter(['unused']); value; is 'outer'
+PASS readCapturedDeconstructedParameter(['inner']) is 'inner'
+PASS overwriteCapturedDeconstructedParameter(['unused']); is 'innermost'
+PASS value is 'outer'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsdeconstructingparametersshouldbelocalshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/deconstructing-parameters-should-be-locals.html (0 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/deconstructing-parameters-should-be-locals.html                                (rev 0)
+++ trunk/LayoutTests/js/deconstructing-parameters-should-be-locals.html        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/deconstructing-parameters-should-be-locals.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsdeconstructingparametersshouldbelocalsjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/deconstructing-parameters-should-be-locals.js (0 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/deconstructing-parameters-should-be-locals.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/deconstructing-parameters-should-be-locals.js        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+description(&quot;This tests to ensure that ddeconstructing parameters behave like regular locals&quot;)
+
+var value=&quot;outer&quot;
+function readDeconstructedParameter([value]) {
+    return value;
+}
+
+function overwriteDeconstructedParameter([value]) {
+        value = &quot;inner&quot;
+}
+
+function readCapturedDeconstructedParameter([value]) {
+        return (function () {
+            return value;
+        })()
+}
+
+function overwriteCapturedDeconstructedParameter([value]) {
+        (function () {
+            value = &quot;innermost&quot;;
+        })()
+        return value
+}
+
+shouldBe(&quot;readDeconstructedParameter(['inner'])&quot;, &quot;'inner'&quot;)
+overwriteDeconstructedParameter(['inner'])
+
+shouldBe(&quot;overwriteDeconstructedParameter(['unused']); value;&quot;, &quot;'outer'&quot;)
+
+shouldBe(&quot;readCapturedDeconstructedParameter(['inner'])&quot;, &quot;'inner'&quot;)
+overwriteDeconstructedParameter(['inner'])
+
+shouldBe(&quot;overwriteCapturedDeconstructedParameter(['unused']);&quot;, &quot;'innermost'&quot;)
+shouldBe(&quot;value&quot;, &quot;'outer'&quot;)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (163327 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-02-03 22:39:38 UTC (rev 163327)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2014-02-03  Oliver Hunt  &lt;oliver@apple.com&gt;
+
+        Deconstructed parameters aren't being placed in the correct scope
+        https://bugs.webkit.org/show_bug.cgi?id=128126
+
+        Reviewed by Antti Koivisto.
+
+        Make sure we declare the bound parameter names as variables when
+        we reparse.  In the BytecodeGenerator we now also directly ensure
+        that bound parameters are placed in the symbol table of the function
+        we're currently compiling.  We then delay binding until just before
+        we start codegen for the body of the function so that we can ensure
+        the function has completely initialised all scope details.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        * bytecompiler/BytecodeGenerator.h:
+        * parser/Parser.cpp:
+        (JSC::Parser&lt;LexerType&gt;::Parser):
+        (JSC::Parser&lt;LexerType&gt;::createBindingPattern):
+
</ins><span class="cx"> 2014-02-03  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Update JS whitespace definition for changes in Unicode 6.3
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (163327 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2014-02-03 22:39:38 UTC (rev 163327)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -63,6 +63,10 @@
</span><span class="cx">     SamplingRegion samplingRegion(&quot;Bytecode Generation&quot;);
</span><span class="cx">     
</span><span class="cx">     m_codeBlock-&gt;setThisRegister(m_thisRegister.virtualRegister());
</span><ins>+    for (size_t i = 0; i &lt; m_deconstructedParameters.size(); i++) {
+        auto&amp; entry = m_deconstructedParameters[i];
+        entry.second-&gt;bindValue(*this, entry.first.get());
+    }
</ins><span class="cx"> 
</span><span class="cx">     m_scopeNode-&gt;emitBytecode(*this);
</span><span class="cx"> 
</span><span class="lines">@@ -298,10 +302,16 @@
</span><span class="cx"> 
</span><span class="cx">     const DeclarationStacks::FunctionStack&amp; functionStack = functionBody-&gt;functionStack();
</span><span class="cx">     const DeclarationStacks::VarStack&amp; varStack = functionBody-&gt;varStack();
</span><ins>+    IdentifierSet test;
</ins><span class="cx"> 
</span><span class="cx">     // Captured variables and functions go first so that activations don't have
</span><span class="cx">     // to step over the non-captured locals to mark them.
</span><span class="cx">     if (functionBody-&gt;hasCapturedVariables()) {
</span><ins>+        for (size_t i = 0; i &lt; boundParameterProperties.size(); i++) {
+            const Identifier&amp; ident = boundParameterProperties[i];
+            if (functionBody-&gt;captures(ident))
+                addVar(ident, IsVariable, IsWatchable);
+        }
</ins><span class="cx">         for (size_t i = 0; i &lt; functionStack.size(); ++i) {
</span><span class="cx">             FunctionBodyNode* function = functionStack[i];
</span><span class="cx">             const Identifier&amp; ident = function-&gt;ident();
</span><span class="lines">@@ -338,6 +348,11 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock-&gt;m_numVars : m_firstLazyFunction;
</span><ins>+    for (size_t i = 0; i &lt; boundParameterProperties.size(); i++) {
+        const Identifier&amp; ident = boundParameterProperties[i];
+        if (!functionBody-&gt;captures(ident))
+            addVar(ident, IsVariable, IsWatchable);
+    }
</ins><span class="cx">     for (size_t i = 0; i &lt; varStack.size(); ++i) {
</span><span class="cx">         const Identifier&amp; ident = varStack[i].first;
</span><span class="cx">         if (!functionBody-&gt;captures(ident))
</span><span class="lines">@@ -356,7 +371,6 @@
</span><span class="cx">     int nextParameterIndex = CallFrame::thisArgumentOffset();
</span><span class="cx">     m_thisRegister.setIndex(nextParameterIndex++);
</span><span class="cx">     m_codeBlock-&gt;addParameter();
</span><del>-    Vector&lt;std::pair&lt;RegisterID*, const DeconstructionPatternNode*&gt;&gt; deconstructedParameters;
</del><span class="cx">     for (size_t i = 0; i &lt; parameters.size(); ++i, ++nextParameterIndex) {
</span><span class="cx">         int index = nextParameterIndex;
</span><span class="cx">         auto pattern = parameters.at(i);
</span><span class="lines">@@ -364,7 +378,7 @@
</span><span class="cx">             m_codeBlock-&gt;addParameter();
</span><span class="cx">             RegisterID&amp; parameter = registerFor(index);
</span><span class="cx">             parameter.setIndex(index);
</span><del>-            deconstructedParameters.append(std::make_pair(&amp;parameter, pattern));
</del><ins>+            m_deconstructedParameters.append(std::make_pair(&amp;parameter, pattern));
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         auto simpleParameter = static_cast&lt;const BindingNode*&gt;(pattern);
</span><span class="lines">@@ -389,10 +403,6 @@
</span><span class="cx">         instructions().append(kill(&amp;m_thisRegister));
</span><span class="cx">         instructions().append(0);
</span><span class="cx">     }
</span><del>-    for (size_t i = 0; i &lt; deconstructedParameters.size(); i++) {
-        auto&amp; entry = deconstructedParameters[i];
-        entry.second-&gt;bindValue(*this, entry.first);
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> BytecodeGenerator::BytecodeGenerator(VM&amp; vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (163327 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2014-02-03 22:39:38 UTC (rev 163327)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -644,6 +644,7 @@
</span><span class="cx">         Vector&lt;SwitchInfo&gt; m_switchContextStack;
</span><span class="cx">         Vector&lt;ForInContext&gt; m_forInContextStack;
</span><span class="cx">         Vector&lt;TryContext&gt; m_tryContextStack;
</span><ins>+        Vector&lt;std::pair&lt;RefPtr&lt;RegisterID&gt;, const DeconstructionPatternNode*&gt;&gt; m_deconstructedParameters;
</ins><span class="cx">         
</span><span class="cx">         Vector&lt;TryRange&gt; m_tryRanges;
</span><span class="cx">         SegmentedVector&lt;TryData, 8&gt; m_tryData;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (163327 => 163328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2014-02-03 22:39:38 UTC (rev 163327)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2014-02-03 22:43:28 UTC (rev 163328)
</span><span class="lines">@@ -219,12 +219,26 @@
</span><span class="cx">     if (strictness == JSParseStrict)
</span><span class="cx">         scope-&gt;setStrictMode();
</span><span class="cx">     if (parameters) {
</span><ins>+        bool hadBindingParameters = false;
</ins><span class="cx">         for (unsigned i = 0; i &lt; parameters-&gt;size(); i++) {
</span><span class="cx">             auto parameter = parameters-&gt;at(i);
</span><del>-            if (!parameter-&gt;isBindingNode())
</del><ins>+            if (!parameter-&gt;isBindingNode()) {
+                hadBindingParameters = true;
</ins><span class="cx">                 continue;
</span><ins>+            }
</ins><span class="cx">             scope-&gt;declareParameter(&amp;static_cast&lt;BindingNode*&gt;(parameter)-&gt;boundProperty());
</span><span class="cx">         }
</span><ins>+        if (hadBindingParameters) {
+            Vector&lt;Identifier&gt; boundParameterNames;
+            for (unsigned i = 0; i &lt; parameters-&gt;size(); i++) {
+                auto parameter = parameters-&gt;at(i);
+                if (parameter-&gt;isBindingNode())
+                    continue;
+                parameter-&gt;collectBoundIdentifiers(boundParameterNames);
+            }
+            for (auto boundParameterName : boundParameterNames)
+                scope-&gt;declareVariable(&amp;boundParameterName);
+        }
</ins><span class="cx">     }
</span><span class="cx">     if (!name.isNull())
</span><span class="cx">         scope-&gt;declareCallee(&amp;name);
</span><span class="lines">@@ -498,7 +512,8 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         if (kind != DeconstructToExpressions)
</span><del>-            context.addVar(&amp;name, kind == DeconstructToParameters ? 0 : DeclarationStacks::HasInitializer);
</del><ins>+            context.addVar(&amp;name, DeclarationStacks::HasInitializer);
+
</ins><span class="cx">     } else {
</span><span class="cx">         if (kind == DeconstructToVariables) {
</span><span class="cx">             failIfFalseIfStrict(declareVariable(&amp;name), &quot;Cannot declare a variable named '&quot;, name.impl(), &quot;' in strict mode&quot;);
</span></span></pre>
</div>
</div>

</body>
</html>