<!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>[188926] 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/188926">188926</a></dd>
<dt>Author</dt> <dd>saambarati1@gmail.com</dd>
<dt>Date</dt> <dd>2015-08-25 11:40:14 -0700 (Tue, 25 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Callee can be incorrectly overridden when it's captured
https://bugs.webkit.org/show_bug.cgi?id=148400

Reviewed by Filip Pizlo.

We now resort to always creating the function name scope
when the function name is in scope. Because the bytecode
generator now has a notion of local lexical scoping,
this incurs no runtime penalty for function expression names
that aren't heap allocated. If they are heap allocated,
this means we may now have one more scope on the runtime
scope stack than before. This modification simplifies the
callee initialization code and uses the lexical scoping constructs
to implement this. This implementation also ensures
that everything Just Works for function's with default
parameter values. Before this patch, IIFE functions
with default parameter values and a captured function
name would crash JSC.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::pushLexicalScopeInternal):
(JSC::BytecodeGenerator::popLexicalScopeInternal):
(JSC::BytecodeGenerator::variable):
(JSC::BytecodeGenerator::resolveType):
(JSC::BytecodeGenerator::emitThrowTypeError):
(JSC::BytecodeGenerator::emitPushFunctionNameScope):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
* bytecompiler/BytecodeGenerator.h:
(JSC::Variable::isReadOnly):
(JSC::Variable::isSpecial):
(JSC::Variable::isConst):
(JSC::Variable::setIsReadOnly):
* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::BindingNode::bindValue):
* tests/stress/IIFE-es6-default-parameters.js: Added.
(assert):
(.):
* tests/stress/IIFE-function-name-captured.js: Added.
(assert):
(.):</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>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressIIFEes6defaultparametersjs">trunk/Source/JavaScriptCore/tests/stress/IIFE-es6-default-parameters.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressIIFEfunctionnamecapturedjs">trunk/Source/JavaScriptCore/tests/stress/IIFE-function-name-captured.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (188925 => 188926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-08-25 18:38:14 UTC (rev 188925)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-08-25 18:40:14 UTC (rev 188926)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2015-08-25  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Callee can be incorrectly overridden when it's captured
+        https://bugs.webkit.org/show_bug.cgi?id=148400
+
+        Reviewed by Filip Pizlo.
+
+        We now resort to always creating the function name scope
+        when the function name is in scope. Because the bytecode
+        generator now has a notion of local lexical scoping,
+        this incurs no runtime penalty for function expression names
+        that aren't heap allocated. If they are heap allocated,
+        this means we may now have one more scope on the runtime
+        scope stack than before. This modification simplifies the
+        callee initialization code and uses the lexical scoping constructs
+        to implement this. This implementation also ensures
+        that everything Just Works for function's with default
+        parameter values. Before this patch, IIFE functions
+        with default parameter values and a captured function
+        name would crash JSC.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::pushLexicalScopeInternal):
+        (JSC::BytecodeGenerator::popLexicalScopeInternal):
+        (JSC::BytecodeGenerator::variable):
+        (JSC::BytecodeGenerator::resolveType):
+        (JSC::BytecodeGenerator::emitThrowTypeError):
+        (JSC::BytecodeGenerator::emitPushFunctionNameScope):
+        (JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::Variable::isReadOnly):
+        (JSC::Variable::isSpecial):
+        (JSC::Variable::isConst):
+        (JSC::Variable::setIsReadOnly):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PostfixNode::emitResolve):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::ReadModifyResolveNode::emitBytecode):
+        (JSC::AssignResolveNode::emitBytecode):
+        (JSC::BindingNode::bindValue):
+        * tests/stress/IIFE-es6-default-parameters.js: Added.
+        (assert):
+        (.):
+        * tests/stress/IIFE-function-name-captured.js: Added.
+        (assert):
+        (.):
+
</ins><span class="cx"> 2015-08-24  Brian Burg  &lt;bburg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: add protocol test for existing error handling performed by the backend
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (188925 => 188926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-08-25 18:38:14 UTC (rev 188925)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-08-25 18:40:14 UTC (rev 188926)
</span><span class="lines">@@ -232,9 +232,11 @@
</span><span class="cx">     
</span><span class="cx">     m_calleeRegister.setIndex(JSStack::Callee);
</span><span class="cx">     
</span><del>-    if (functionNameIsInScope(functionNode-&gt;ident(), functionNode-&gt;functionMode())
-        &amp;&amp; functionNameScopeIsDynamic(codeBlock-&gt;usesEval(), codeBlock-&gt;isStrictMode())) {
-        emitPushFunctionNameScope(functionNode-&gt;ident(), &amp;m_calleeRegister);
</del><ins>+    if (functionNameIsInScope(functionNode-&gt;ident(), functionNode-&gt;functionMode())) {
+        bool isDynamicScope = functionNameScopeIsDynamic(codeBlock-&gt;usesEval(), codeBlock-&gt;isStrictMode());
+        bool isFunctionNameCaptured = captures(functionNode-&gt;ident().impl());
+        bool markAsCaptured = isDynamicScope || isFunctionNameCaptured;
+        emitPushFunctionNameScope(functionNode-&gt;ident(), &amp;m_calleeRegister, markAsCaptured);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (shouldCaptureSomeOfTheThings) {
</span><span class="lines">@@ -396,15 +398,12 @@
</span><span class="cx">     // - &quot;arguments&quot;: unless it's used as a function or parameter, this should refer to the
</span><span class="cx">     //   arguments object.
</span><span class="cx">     //
</span><del>-    // - callee: unless it's used as a var, function, or parameter, this should refer to the
-    //   callee (i.e. our function).
-    //
</del><span class="cx">     // - functions: these always override everything else.
</span><span class="cx">     //
</span><span class="cx">     // The most logical way to do all of this is to initialize none of the variables until now,
</span><span class="cx">     // and then initialize them in BytecodeGenerator::generate() in such an order that the rules
</span><del>-    // for how these things override each other end up holding. We would initialize the callee
-    // first, then &quot;arguments&quot;, then all arguments, then the functions.
</del><ins>+    // for how these things override each other end up holding. We would initialize &quot;arguments&quot; first, 
+    // then all arguments, then the functions.
</ins><span class="cx">     //
</span><span class="cx">     // But some arguments are already initialized by default, since if they aren't captured and we
</span><span class="cx">     // don't have &quot;arguments&quot; then we just point the symbol table at the stack slot of those
</span><span class="lines">@@ -412,35 +411,6 @@
</span><span class="cx">     // binding (i.e. don't involve destructuring) above when figuring out how to lay them out,
</span><span class="cx">     // because that's just the simplest thing. This means that when we initialize them, we have to
</span><span class="cx">     // watch out for the things that override arguments (namely, functions).
</span><del>-    //
-    // We also initialize callee here as well, just because it's so weird. We know whether we want
-    // to do this because we can just check if it's in the symbol table.
-    if (functionNameIsInScope(functionNode-&gt;ident(), functionNode-&gt;functionMode())
-        &amp;&amp; !functionNameScopeIsDynamic(codeBlock-&gt;usesEval(), codeBlock-&gt;isStrictMode())
-        &amp;&amp; functionSymbolTable-&gt;get(functionNode-&gt;ident().impl()).isNull()) {
-        if (captures(functionNode-&gt;ident().impl())) {
-            ScopeOffset offset;
-            {
-                ConcurrentJITLocker locker(functionSymbolTable-&gt;m_lock);
-                offset = functionSymbolTable-&gt;takeNextScopeOffset(locker);
-                functionSymbolTable-&gt;add(
-                    locker, functionNode-&gt;ident().impl(),
-                    SymbolTableEntry(VarOffset(offset), ReadOnly));
-            }
-            
-            emitOpcode(op_put_to_scope);
-            instructions().append(m_lexicalEnvironmentRegister-&gt;index());
-            instructions().append(addConstant(functionNode-&gt;ident()));
-            instructions().append(m_calleeRegister.index());
-            instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand());
-            instructions().append(symbolTableConstantIndex);
-            instructions().append(offset.offset());
-        } else {
-            functionSymbolTable-&gt;add(
-                functionNode-&gt;ident().impl(),
-                SymbolTableEntry(VarOffset(m_calleeRegister.virtualRegister()), ReadOnly));
-        }
-    }
</del><span class="cx">     
</span><span class="cx">     // This is our final act of weirdness. &quot;arguments&quot; is overridden by everything except the
</span><span class="cx">     // callee. We add it to the symbol table if it's not already there and it's not an argument.
</span><span class="lines">@@ -1441,8 +1411,12 @@
</span><span class="cx">                 hasCapturedVariables = true;
</span><span class="cx">             } else {
</span><span class="cx">                 ASSERT(varKind == VarKind::Stack);
</span><del>-                RegisterID* local = newBlockScopeVariable();
-                local-&gt;ref();
</del><ins>+                RegisterID* local;
+                if (scopeRegisterType == ScopeRegisterType::Block) {
+                    local = newBlockScopeVariable();
+                    local-&gt;ref();
+                } else
+                    local = addVar();
</ins><span class="cx">                 varOffset = VarOffset(local-&gt;virtualRegister());
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -1512,6 +1486,8 @@
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::popLexicalScopeInternal(VariableEnvironment&amp; environment, TDZRequirement tdzRequirement)
</span><span class="cx"> {
</span><ins>+    // NOTE: This function only makes sense for scopes that aren't ScopeRegisterType::Var (only function name scope right now is ScopeRegisterType::Var).
+    // This doesn't make sense for ScopeRegisterType::Var because we deref RegisterIDs here.
</ins><span class="cx">     if (!environment.size())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -1654,12 +1630,20 @@
</span><span class="cx">         SymbolTableEntry symbolTableEntry = symbolTable-&gt;get(property.impl());
</span><span class="cx">         if (symbolTableEntry.isNull())
</span><span class="cx">             continue;
</span><del>-        if (symbolTable-&gt;scopeType() == SymbolTable::ScopeType::FunctionNameScope &amp;&amp; m_usesNonStrictEval) {
-            // We don't know if an eval has introduced a &quot;var&quot; named the same thing as the function name scope variable name.
-            // We resort to dynamic lookup to answer this question.
-            return Variable(property);
</del><ins>+        bool resultIsCallee = false;
+        if (symbolTable-&gt;scopeType() == SymbolTable::ScopeType::FunctionNameScope) {
+            if (m_usesNonStrictEval) {
+                // We don't know if an eval has introduced a &quot;var&quot; named the same thing as the function name scope variable name.
+                // We resort to dynamic lookup to answer this question.
+                Variable result = Variable(property);
+                return result;
+            }
+            resultIsCallee = true;
</ins><span class="cx">         }
</span><del>-        return variableForLocalEntry(property, symbolTableEntry, stackEntry.m_symbolTableConstantIndex, symbolTable-&gt;scopeType() == SymbolTable::ScopeType::LexicalScope);
</del><ins>+        Variable result = variableForLocalEntry(property, symbolTableEntry, stackEntry.m_symbolTableConstantIndex, symbolTable-&gt;scopeType() == SymbolTable::ScopeType::LexicalScope);
+        if (resultIsCallee)
+            result.setIsReadOnly();
+        return result;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return Variable(property);
</span><span class="lines">@@ -1740,8 +1724,9 @@
</span><span class="cx">         if (m_symbolTableStack[i].m_isWithScope)
</span><span class="cx">             return Dynamic;
</span><span class="cx">         if (m_usesNonStrictEval &amp;&amp; m_symbolTableStack[i].m_symbolTable-&gt;scopeType() == SymbolTable::ScopeType::FunctionNameScope) {
</span><del>-            // What we really want here is something like LocalClosureVarWithVarInjectionsCheck but it's probably
-            // not worth inventing just for the function name scope.
</del><ins>+            // We never want to assign to a FunctionNameScope. Returning Dynamic here achieves this goal.
+            // If we aren't in non-strict eval mode, then NodesCodeGen needs to take care not to emit
+            // a put_to_scope with the destination being the function name scope variable.
</ins><span class="cx">             return Dynamic;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -3101,7 +3086,7 @@
</span><span class="cx">     instructions().append(false);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void BytecodeGenerator::emitPushFunctionNameScope(const Identifier&amp; property, RegisterID* callee)
</del><ins>+void BytecodeGenerator::emitPushFunctionNameScope(const Identifier&amp; property, RegisterID* callee, bool isCaptured)
</ins><span class="cx"> {
</span><span class="cx">     // There is some nuance here:
</span><span class="cx">     // If we're in strict mode code, the function name scope variable acts exactly like a &quot;const&quot; variable.
</span><span class="lines">@@ -3114,7 +3099,8 @@
</span><span class="cx">     // to lexical environments.
</span><span class="cx">     VariableEnvironment nameScopeEnvironment;
</span><span class="cx">     auto addResult = nameScopeEnvironment.add(property);
</span><del>-    addResult.iterator-&gt;value.setIsCaptured();
</del><ins>+    if (isCaptured)
+        addResult.iterator-&gt;value.setIsCaptured();
</ins><span class="cx">     addResult.iterator-&gt;value.setIsConst(); // The function name scope name acts like a const variable.
</span><span class="cx">     unsigned numVars = m_codeBlock-&gt;m_numVars;
</span><span class="cx">     pushLexicalScopeInternal(nameScopeEnvironment, true, nullptr, TDZRequirement::NotUnderTDZ, ScopeType::FunctionNameScope, ScopeRegisterType::Var);
</span><span class="lines">@@ -3287,6 +3273,8 @@
</span><span class="cx"> 
</span><span class="cx"> bool BytecodeGenerator::emitReadOnlyExceptionIfNeeded(const Variable&amp; variable)
</span><span class="cx"> {
</span><ins>+    // If we're in strict mode, we always throw.
+    // If we're not in strict mode, we throw for &quot;const&quot; variables but not the function callee.
</ins><span class="cx">     if (isStrictMode() || variable.isConst()) {
</span><span class="cx">         emitOpcode(op_throw_static_error);
</span><span class="cx">         instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, StrictModeReadonlyPropertyWriteError)))-&gt;index());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (188925 => 188926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-08-25 18:38:14 UTC (rev 188925)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-08-25 18:40:14 UTC (rev 188926)
</span><span class="lines">@@ -234,6 +234,7 @@
</span><span class="cx">         bool isReadOnly() const { return m_attributes &amp; ReadOnly; }
</span><span class="cx">         bool isSpecial() const { return m_kind != NormalVariable; }
</span><span class="cx">         bool isConst() const { return isReadOnly() &amp;&amp; m_isLexicallyScoped; }
</span><ins>+        void setIsReadOnly() { m_attributes |= ReadOnly; }
</ins><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         Identifier m_ident;
</span><span class="lines">@@ -589,7 +590,6 @@
</span><span class="cx">         void emitThrowReferenceError(const String&amp; message);
</span><span class="cx">         void emitThrowTypeError(const String&amp; message);
</span><span class="cx"> 
</span><del>-        void emitPushFunctionNameScope(const Identifier&amp; property, RegisterID* value);
</del><span class="cx">         void emitPushCatchScope(const Identifier&amp; property, RegisterID* exceptionValue, VariableEnvironment&amp;);
</span><span class="cx">         void emitPopCatchScope(VariableEnvironment&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -637,6 +637,8 @@
</span><span class="cx">         void popLexicalScopeInternal(VariableEnvironment&amp;, TDZRequirement);
</span><span class="cx">         void emitPopScope(RegisterID* dst, RegisterID* scope);
</span><span class="cx">         RegisterID* emitGetParentScope(RegisterID* dst, RegisterID* scope);
</span><ins>+        void emitPushFunctionNameScope(const Identifier&amp; property, RegisterID* value, bool isCaptured);
+
</ins><span class="cx">     public:
</span><span class="cx">         void pushLexicalScope(VariableEnvironmentNode*, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult = nullptr);
</span><span class="cx">         void popLexicalScope(VariableEnvironmentNode*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (188925 => 188926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-08-25 18:38:14 UTC (rev 188925)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-08-25 18:40:14 UTC (rev 188926)
</span><span class="lines">@@ -1052,8 +1052,10 @@
</span><span class="cx">             return value.get();
</span><span class="cx">     }
</span><span class="cx">     RefPtr&lt;RegisterID&gt; oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
</span><del>-    generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
-    generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
</del><ins>+    if (!var.isReadOnly()) {
+        generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
+        generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
+    }
</ins><span class="cx"> 
</span><span class="cx">     return oldValue.get();
</span><span class="cx"> }
</span><span class="lines">@@ -1250,8 +1252,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     emitIncOrDec(generator, value.get(), m_operator);
</span><del>-    generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
-    generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
</del><ins>+    if (!var.isReadOnly()) {
+        generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
+        generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
+    }
</ins><span class="cx">     return generator.moveToDestinationIfNeeded(dst, value.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1771,8 +1775,11 @@
</span><span class="cx">             return value.get();
</span><span class="cx">     }
</span><span class="cx">     RefPtr&lt;RegisterID&gt; result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right-&gt;resultDescriptor()), this);
</span><del>-    RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound);
-    generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
</del><ins>+    RegisterID* returnResult = result.get();
+    if (!var.isReadOnly()) {
+        returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound);
+        generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
+    }
</ins><span class="cx">     return returnResult;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1781,12 +1788,13 @@
</span><span class="cx"> RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator&amp; generator, RegisterID* dst)
</span><span class="cx"> {
</span><span class="cx">     Variable var = generator.variable(m_ident);
</span><ins>+    bool isReadOnly = var.isReadOnly() &amp;&amp; m_assignmentContext != AssignmentContext::ConstDeclarationStatement;
</ins><span class="cx">     if (RegisterID* local = var.local()) {
</span><span class="cx">         RegisterID* result = nullptr;
</span><span class="cx">         if (m_assignmentContext == AssignmentContext::AssignmentExpression)
</span><span class="cx">             generator.emitTDZCheckIfNecessary(var, local, nullptr);
</span><span class="cx"> 
</span><del>-        if (var.isReadOnly() &amp;&amp; m_assignmentContext != AssignmentContext::ConstDeclarationStatement) {
</del><ins>+        if (isReadOnly) {
</ins><span class="cx">             result = generator.emitNode(dst, m_right); // Execute side effects first.
</span><span class="cx">             generator.emitReadOnlyExceptionIfNeeded(var);
</span><span class="cx">             generator.emitProfileType(result, var, divotStart(), divotEnd());
</span><span class="lines">@@ -1817,15 +1825,18 @@
</span><span class="cx">     if (dst == generator.ignoredResult())
</span><span class="cx">         dst = 0;
</span><span class="cx">     RefPtr&lt;RegisterID&gt; result = generator.emitNode(dst, m_right);
</span><del>-    if (var.isReadOnly() &amp;&amp; m_assignmentContext != AssignmentContext::ConstDeclarationStatement) {
</del><ins>+    if (isReadOnly) {
</ins><span class="cx">         RegisterID* result = generator.emitNode(dst, m_right); // Execute side effects first.
</span><span class="cx">         bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
</span><span class="cx">         if (threwException)
</span><span class="cx">             return result;
</span><span class="cx">     }
</span><span class="cx">     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>-    RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
-    generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
</del><ins>+    RegisterID* returnResult = result.get();
+    if (!isReadOnly) {
+        returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+        generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (m_assignmentContext == AssignmentContext::DeclarationStatement || m_assignmentContext == AssignmentContext::ConstDeclarationStatement)
</span><span class="cx">         generator.liftTDZCheckIfPossible(var);
</span><span class="lines">@@ -3282,13 +3293,13 @@
</span><span class="cx"> void BindingNode::bindValue(BytecodeGenerator&amp; generator, RegisterID* value) const
</span><span class="cx"> {
</span><span class="cx">     Variable var = generator.variable(m_boundProperty);
</span><ins>+    bool isReadOnly = var.isReadOnly() &amp;&amp; m_bindingContext != AssignmentContext::ConstDeclarationStatement;
</ins><span class="cx">     if (RegisterID* local = var.local()) {
</span><span class="cx">         if (m_bindingContext == AssignmentContext::AssignmentExpression)
</span><span class="cx">             generator.emitTDZCheckIfNecessary(var, local, nullptr);
</span><del>-        if (var.isReadOnly() &amp;&amp; m_bindingContext != AssignmentContext::ConstDeclarationStatement) {
-            bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
-            if (threwException)
-                return;
</del><ins>+        if (isReadOnly) {
+            generator.emitReadOnlyExceptionIfNeeded(var);
+            return;
</ins><span class="cx">         }
</span><span class="cx">         generator.emitMove(local, value);
</span><span class="cx">         generator.emitProfileType(local, var, divotStart(), divotEnd());
</span><span class="lines">@@ -3302,10 +3313,9 @@
</span><span class="cx">     generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
</span><span class="cx">     if (m_bindingContext == AssignmentContext::AssignmentExpression)
</span><span class="cx">         generator.emitTDZCheckIfNecessary(var, nullptr, scope);
</span><del>-    if (var.isReadOnly() &amp;&amp; m_bindingContext != AssignmentContext::ConstDeclarationStatement) {
-        bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
-        if (threwException)
-            return;
</del><ins>+    if (isReadOnly) {
+        generator.emitReadOnlyExceptionIfNeeded(var);
+        return;
</ins><span class="cx">     }
</span><span class="cx">     generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
</span><span class="cx">     generator.emitProfileType(value, var, divotStart(), divotEnd());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressIIFEes6defaultparametersjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/IIFE-es6-default-parameters.js (0 => 188926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/IIFE-es6-default-parameters.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/IIFE-es6-default-parameters.js        2015-08-25 18:40:14 UTC (rev 188926)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+
+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion&quot;);
+}
+
+for (var i = 0; i &lt; 1000; i++) {
+
+    ;(function foo(x = 20) {
+        assert(typeof foo === &quot;function&quot;);
+    })();
+
+    ;(function foo(x = 20) {
+        function bar() { return foo; }
+        assert(typeof foo === &quot;function&quot;);
+    })();
+
+    ;(function foo(x = foo) {
+        var foo = 20;
+        assert(foo === 20);
+        assert(typeof x === &quot;function&quot;);
+    })();
+
+    ;(function foo(capFoo = function() { return foo; }) {
+        var foo = 20;
+        assert(foo === 20);
+        assert(typeof capFoo() === &quot;function&quot;);
+    })();
+
+    ;(function foo(x = eval(&quot;foo&quot;)) {
+        var foo = 20;
+        assert(foo === 20);
+        assert(typeof x === &quot;function&quot;);
+    })();
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressIIFEfunctionnamecapturedjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/IIFE-function-name-captured.js (0 => 188926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/IIFE-function-name-captured.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/IIFE-function-name-captured.js        2015-08-25 18:40:14 UTC (rev 188926)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion&quot;);
+}
+
+for (var i = 0; i &lt; 1000; i++) {
+    ;(function foo() {
+        foo = 20;
+        assert(foo !== 20);
+        assert(typeof foo === &quot;function&quot;);
+    })();
+
+    ;(function foo() {
+        var bar = function() { return foo; }
+        foo = 20;
+        assert(foo !== 20);
+        assert(bar() !== 20);
+        assert(typeof foo === &quot;function&quot;);
+        assert(typeof bar() === &quot;function&quot;);
+    })();
+
+    ;(function foo() {
+        eval(&quot;foo = 20;&quot;);
+        assert(foo !== 20);
+        assert(typeof foo === &quot;function&quot;);
+    })();
+
+    ;(function foo() {
+        eval(&quot;var foo = 20;&quot;);
+        assert(foo === 20);
+    })();
+
+    ;(function foo() {
+        &quot;use strict&quot;;
+        assert(foo !== 20);
+        assert(typeof foo === &quot;function&quot;);
+    })();
+}
</ins></span></pre>
</div>
</div>

</body>
</html>