<!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>[198989] 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/198989">198989</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-04-03 12:45:05 -0700 (Sun, 03 Apr 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Implement Annex B.3.3 function hoisting rules for function code
https://bugs.webkit.org/show_bug.cgi?id=155672

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

The spec states that functions declared inside a function
inside a block scope are subject to the rules of Annex B.3.3:
https://tc39.github.io/ecma262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics

The rule states that functions declared in such blocks should
be local bindings of the block. If declaring the function's name
as a &quot;var&quot; in the function would not lead to a syntax error (i.e,
if we don't have a let/const/class variable with the same name)
and if we don't have a parameter with the same name, then we
implictly also declare the funcion name as a &quot;var&quot;. When evaluating
the block statement we bind the hoisted &quot;var&quot; to be the value
of the local function binding.

There is one more thing we do for web compatibility. We allow
function declarations inside if/else statements that aren't
blocks. For such statements, we transform the code as if the
function were declared inside a block statement. For example:
``` function foo() { if (cond) function baz() { } }```
is transformed into:
``` function foo() { if (cond) { function baz() { } } }```

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
(JSC::BytecodeGenerator::initializeBlockScopedFunctions):
* bytecompiler/BytecodeGenerator.h:
* parser/Nodes.cpp:
(JSC::ScopeNode::ScopeNode):
(JSC::ProgramNode::ProgramNode):
(JSC::ModuleProgramNode::ModuleProgramNode):
(JSC::EvalNode::EvalNode):
(JSC::FunctionNode::FunctionNode):
* parser/Nodes.h:
(JSC::ScopeNode::hasCapturedVariables):
(JSC::ScopeNode::captures):
(JSC::ScopeNode::hasSloppyModeHoistedFunction):
(JSC::ScopeNode::varDeclarations):
(JSC::ProgramNode::startColumn):
(JSC::ProgramNode::endColumn):
(JSC::EvalNode::startColumn):
(JSC::EvalNode::endColumn):
(JSC::ModuleProgramNode::startColumn):
(JSC::ModuleProgramNode::endColumn):
* parser/Parser.cpp:
(JSC::Parser&lt;LexerType&gt;::Parser):
(JSC::Parser&lt;LexerType&gt;::parseInner):
(JSC::Parser&lt;LexerType&gt;::didFinishParsing):
(JSC::Parser&lt;LexerType&gt;::parseStatement):
(JSC::Parser&lt;LexerType&gt;::parseIfStatement):
* parser/Parser.h:
(JSC::Scope::declareVariable):
(JSC::Scope::declareFunction):
(JSC::Scope::addSloppyModeHoistableFunctionCandidate):
(JSC::Scope::appendFunction):
(JSC::Scope::declareParameter):
(JSC::Scope::mergeInnerArrowFunctionFeatures):
(JSC::Scope::getSloppyModeHoistedFunctions):
(JSC::Scope::getCapturedVars):
(JSC::ScopeRef::containingScope):
(JSC::ScopeRef::operator==):
(JSC::ScopeRef::operator!=):
(JSC::Parser::declareFunction):
(JSC::Parser::hasDeclaredVariable):
(JSC::Parser::isFunctionMetadataNode):
(JSC::Parser::DepthManager::DepthManager):
(JSC::Parser&lt;LexerType&gt;::parse):
* parser/VariableEnvironment.h:
(JSC::VariableEnvironmentEntry::isImported):
(JSC::VariableEnvironmentEntry::isImportedNamespace):
(JSC::VariableEnvironmentEntry::isFunction):
(JSC::VariableEnvironmentEntry::isParameter):
(JSC::VariableEnvironmentEntry::isSloppyModeHoistingCandidate):
(JSC::VariableEnvironmentEntry::setIsCaptured):
(JSC::VariableEnvironmentEntry::setIsConst):
(JSC::VariableEnvironmentEntry::setIsImported):
(JSC::VariableEnvironmentEntry::setIsImportedNamespace):
(JSC::VariableEnvironmentEntry::setIsFunction):
(JSC::VariableEnvironmentEntry::setIsParameter):
(JSC::VariableEnvironmentEntry::setIsSloppyModeHoistingCandidate):
(JSC::VariableEnvironmentEntry::clearIsVar):
* runtime/CodeCache.h:
(JSC::SourceCodeValue::SourceCodeValue):
* runtime/JSScope.cpp:
* runtime/JSScope.h:
* tests/es6.yaml:
* tests/stress/sloppy-mode-function-hoisting.js: Added.
(assert):
(test):
(falsey):
(truthy):
(test.):
(test.a):
(test.f):
(test.let.funcs.f):
(test.catch.f):
(test.foo):
(test.bar):
(test.switch.case.0):
(test.else.f):
(test.b):
(test.c):
(test.d):
(test.e):
(test.g):
(test.h):
(test.i):
(test.j):
(test.k):
(test.l):
(test.m):
(test.n):
(test.o):
(test.p):
(test.q):
(test.r):
(test.s):
(test.t):
(test.u):
(test.v):
(test.w):
(test.x):
(test.y):
(test.z):
(foo):
(bar):
(falsey.bar):
(baz):
(falsey.baz):

LayoutTests:

* js/kde/func-decl-expected.txt:
* js/kde/script-tests/func-decl.js:
* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:
(valid):
(onlyValidGlobally):
(onlyInvalidGlobally):
(invalid):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsjsfunctiondeclarationstatementexpectedtxt">trunk/LayoutTests/js/function-declaration-statement-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjskdefuncdeclexpectedtxt">trunk/LayoutTests/js/kde/func-decl-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjskdescripttestsfuncdecljs">trunk/LayoutTests/js/kde/script-tests/func-decl.js</a></li>
<li><a href="#trunkLayoutTestsjsparsersyntaxcheckexpectedtxt">trunk/LayoutTests/js/parser-syntax-check-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsfunctiondeclarationstatementjs">trunk/LayoutTests/js/script-tests/function-declaration-statement.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsparsersyntaxcheckjs">trunk/LayoutTests/js/script-tests/parser-syntax-check.js</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="#trunkSourceJavaScriptCoreparserNodescpp">trunk/Source/JavaScriptCore/parser/Nodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodesh">trunk/Source/JavaScriptCore/parser/Nodes.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParsercpp">trunk/Source/JavaScriptCore/parser/Parser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParserh">trunk/Source/JavaScriptCore/parser/Parser.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserVariableEnvironmenth">trunk/Source/JavaScriptCore/parser/VariableEnvironment.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCodeCacheh">trunk/Source/JavaScriptCore/runtime/CodeCache.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSScopecpp">trunk/Source/JavaScriptCore/runtime/JSScope.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSScopeh">trunk/Source/JavaScriptCore/runtime/JSScope.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6yaml">trunk/Source/JavaScriptCore/tests/es6.yaml</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstresssloppymodefunctionhoistingjs">trunk/Source/JavaScriptCore/tests/stress/sloppy-mode-function-hoisting.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/ChangeLog        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2016-04-03  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Implement Annex B.3.3 function hoisting rules for function code
+        https://bugs.webkit.org/show_bug.cgi?id=155672
+
+        Reviewed by Geoffrey Garen.
+
+        * js/kde/func-decl-expected.txt:
+        * js/kde/script-tests/func-decl.js:
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/parser-syntax-check.js:
+        (valid):
+        (onlyValidGlobally):
+        (onlyInvalidGlobally):
+        (invalid):
+
</ins><span class="cx"> 2016-04-03  David Kilzer  &lt;ddkilzer@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r198859): fast/scrolling/rtl-scrollbars-animation-property.html fails on non-Mac platforms
</span></span></pre></div>
<a id="trunkLayoutTestsjsfunctiondeclarationstatementexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/function-declaration-statement-expected.txt (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/function-declaration-statement-expected.txt        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/js/function-declaration-statement-expected.txt        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -5,14 +5,6 @@
</span><span class="cx"> 
</span><span class="cx"> PASS ifTest() is true
</span><span class="cx"> PASS ifElseTest() is true
</span><del>-PASS doWhileTest() is true
-PASS whileTest() is true
-PASS forTest() is true
-PASS forVarTest() is true
-PASS forInTest() is true
-PASS forInVarTest() is true
-PASS forInVarInitTest() is true
-PASS withTest() is true
</del><span class="cx"> PASS labelTest() is true
</span><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsjskdefuncdeclexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/kde/func-decl-expected.txt (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/kde/func-decl-expected.txt        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/js/kde/func-decl-expected.txt        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -3,8 +3,8 @@
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-PASS Function declaration takes effect at entry
-PASS Decl not yet overwritten
</del><ins>+PASS Function declaration takes effect at declaration block
+PASS Decl already overwritten
</ins><span class="cx"> PASS After assign (0)
</span><span class="cx"> PASS function decls have no execution content
</span><span class="cx"> PASS After assign #2 (0)
</span></span></pre></div>
<a id="trunkLayoutTestsjskdescripttestsfuncdecljs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/kde/script-tests/func-decl.js (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/kde/script-tests/func-decl.js        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/js/kde/script-tests/func-decl.js        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -17,17 +17,14 @@
</span><span class="cx"> 
</span><span class="cx"> function test() {
</span><span class="cx">   try {
</span><del>-    shouldBeOfType(&quot;Function declaration takes effect at entry&quot;, f, &quot;function&quot;);
</del><ins>+    shouldBeOfType(&quot;Function declaration takes effect at declaration block&quot;, f, &quot;undefined&quot;);
</ins><span class="cx">   }
</span><span class="cx">   catch (e) {
</span><span class="cx">     testFailed(&quot;Scoping very broken!&quot;);
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   for (var i = 0; i &lt; 3; ++i) {
</span><del>-    if (i == 0)
-      shouldBeOfType(&quot;Decl not yet overwritten&quot;, f, 'function');
-    else
-      shouldBeOfType(&quot;Decl already overwritten&quot;, f, 'number');
</del><ins>+    shouldBeOfType(&quot;Decl already overwritten&quot;, f, 'function');
</ins><span class="cx"> 
</span><span class="cx">     f = 3;
</span><span class="cx">     shouldBeVal(&quot;After assign (&quot;+i+&quot;)&quot;, f, 3);
</span></span></pre></div>
<a id="trunkLayoutTestsjsparsersyntaxcheckexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/parser-syntax-check-expected.txt (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/parser-syntax-check-expected.txt        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -302,8 +302,8 @@
</span><span class="cx"> PASS Invalid: &quot;function f() { while if (a) ; }&quot;
</span><span class="cx"> PASS Valid:   &quot;if (a) function f() {} else function g() {}&quot;
</span><span class="cx"> PASS Valid:   &quot;function f() { if (a) function f() {} else function g() {} }&quot;
</span><del>-PASS Valid:   &quot;if (a()) while(0) function f() {} else function g() {}&quot; with TypeError
-PASS Valid:   &quot;function f() { if (a()) while(0) function f() {} else function g() {} }&quot;
</del><ins>+PASS Invalid: &quot;if (a()) while(0) function f() {} else function g() {}&quot;
+PASS Invalid: &quot;function f() { if (a()) while(0) function f() {} else function g() {} }&quot;
</ins><span class="cx"> PASS Invalid: &quot;if (a()) function f() { else function g() }&quot;
</span><span class="cx"> PASS Invalid: &quot;function f() { if (a()) function f() { else function g() } }&quot;
</span><span class="cx"> PASS Invalid: &quot;if (a) if (b) ; else function f {}&quot;
</span><span class="lines">@@ -676,16 +676,50 @@
</span><span class="cx"> PASS Invalid: &quot;function f() { 'use strict'; function f1(a) {}; let f1;  }&quot;
</span><span class="cx"> PASS Invalid: &quot;let f1; function f1(a) {};&quot;
</span><span class="cx"> PASS Invalid: &quot;function f() { let f1; function f1(a) {}; }&quot;
</span><del>-PASS Invalid: &quot;let f1; { function f1(a) {}; }&quot;
-PASS Invalid: &quot;function f() { let f1; { function f1(a) {}; } }&quot;
-PASS Invalid: &quot;{ function f1(a) {}; } let f1;&quot;
-PASS Invalid: &quot;function f() { { function f1(a) {}; } let f1; }&quot;
-PASS Valid:   &quot;{ let f1; function f1(a) {}; }&quot;
-PASS Valid:   &quot;function f() { { let f1; function f1(a) {}; } }&quot;
-PASS Valid:   &quot;{  function f1(a) {}; let f1; }&quot;
-PASS Valid:   &quot;function f() { {  function f1(a) {}; let f1; } }&quot;
</del><ins>+PASS Valid:   &quot;function foo() { let f1; { function f1(a) {}; } }&quot;
+PASS Valid:   &quot;function f() { function foo() { let f1; { function f1(a) {}; } } }&quot;
+PASS Valid:   &quot;function foo() { { function f1(a) {}; } let f1; }&quot;
+PASS Valid:   &quot;function f() { function foo() { { function f1(a) {}; } let f1; } }&quot;
+PASS Valid:   &quot;function foo() { { function foo() { }; function foo() { } } }&quot;
+PASS Valid:   &quot;function f() { function foo() { { function foo() { }; function foo() { } } } }&quot;
+PASS Invalid: &quot;function foo() { 'use strict'; { function foo() { }; function foo() { } } }&quot;
+PASS Invalid: &quot;function f() { function foo() { 'use strict'; { function foo() { }; function foo() { } } } }&quot;
+PASS Invalid: &quot;function foo() { let f1; function f1(a) {}; }&quot;
+PASS Invalid: &quot;function f() { function foo() { let f1; function f1(a) {}; } }&quot;
+PASS Invalid: &quot;let f1; function f1(a) {};&quot;
+PASS Invalid: &quot;function f() { let f1; function f1(a) {}; }&quot;
+PASS Valid:   &quot;{ function f1(a) {}; let f1; }&quot;
+PASS Invalid: &quot;function f() { { function f1(a) {}; let f1; } }&quot;
+PASS Valid:   &quot;{ function f1(a) {}; const f1 = 25; }&quot;
+PASS Invalid: &quot;function f() { { function f1(a) {}; const f1 = 25; } }&quot;
+PASS Valid:   &quot;{ function f1(a) {}; class f1{}; }&quot;
+PASS Invalid: &quot;function f() { { function f1(a) {}; class f1{}; } }&quot;
+PASS Invalid: &quot;function foo() { { let bar; function bar() { } } }&quot;
+PASS Invalid: &quot;function f() { function foo() { { let bar; function bar() { } } } }&quot;
+PASS Invalid: &quot;function foo() { { function bar() { }; let bar; } }&quot;
+PASS Invalid: &quot;function f() { function foo() { { function bar() { }; let bar; } } }&quot;
+PASS Invalid: &quot;function foo() { { const bar; function bar() { } } }&quot;
+PASS Invalid: &quot;function f() { function foo() { { const bar; function bar() { } } } }&quot;
+PASS Invalid: &quot;function foo() { { function bar() { }; const bar; } }&quot;
+PASS Invalid: &quot;function f() { function foo() { { function bar() { }; const bar; } } }&quot;
+PASS Invalid: &quot;function foo() { { class bar{}; function bar() { } } }&quot;
+PASS Invalid: &quot;function f() { function foo() { { class bar{}; function bar() { } } } }&quot;
+PASS Invalid: &quot;function foo() { { function bar() { }; class bar{}; } }&quot;
+PASS Invalid: &quot;function f() { function foo() { { function bar() { }; class bar{}; } } }&quot;
</ins><span class="cx"> PASS Valid:   &quot;switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; }&quot;
</span><span class="cx"> PASS Valid:   &quot;function f() { switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; } }&quot;
</span><ins>+PASS Valid:   &quot;switch('foo') { case 1: let foo; function foo() {}; break; case 2: function foo() {}; break; }&quot;
+PASS Invalid: &quot;function f() { switch('foo') { case 1: let foo; function foo() {}; break; case 2: function foo() {}; break; } }&quot;
+PASS Valid:   &quot;switch('foo') { case 1: function foo() {}; let foo; break; case 2: function foo() {}; break; }&quot;
+PASS Invalid: &quot;function f() { switch('foo') { case 1: function foo() {}; let foo; break; case 2: function foo() {}; break; } }&quot;
+PASS Valid:   &quot;switch('foo') { case 1: function foo() {}; const foo = 25; break; case 2: function foo() {}; break; }&quot;
+PASS Invalid: &quot;function f() { switch('foo') { case 1: function foo() {}; const foo = 25; break; case 2: function foo() {}; break; } }&quot;
+PASS Valid:   &quot;switch('foo') { case 1: function foo() {}; class foo {} ; break; case 2: function foo() {}; break; }&quot;
+PASS Invalid: &quot;function f() { switch('foo') { case 1: function foo() {}; class foo {} ; break; case 2: function foo() {}; break; } }&quot;
+PASS Valid:   &quot;switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; case 3: let foo; }&quot;
+PASS Invalid: &quot;function f() { switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; case 3: let foo; } }&quot;
+PASS Valid:   &quot;function foo() { switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; case 3: { let foo; } } }&quot;
+PASS Valid:   &quot;function f() { function foo() { switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; case 3: { let foo; } } } }&quot;
</ins><span class="cx"> PASS Invalid: &quot;'use strict'; switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; }&quot;
</span><span class="cx"> PASS Invalid: &quot;function f() { 'use strict'; switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; } }&quot;
</span><span class="cx"> PASS Invalid: &quot;'use strict'; switch('foo') { case 1: function foo() {}; break; case 2: let foo; break; }&quot;
</span><span class="lines">@@ -700,6 +734,74 @@
</span><span class="cx"> PASS Invalid: &quot;function f() { 'use strict'; if (true) function foo() { };  }&quot;
</span><span class="cx"> PASS Valid:   &quot;if (true) function foo() { }; &quot;
</span><span class="cx"> PASS Valid:   &quot;function f() { if (true) function foo() { };  }&quot;
</span><ins>+PASS Invalid: &quot; let foo; if (true) function foo() { };&quot;
+PASS Valid:   &quot;function f() {  let foo; if (true) function foo() { }; }&quot;
+PASS Valid:   &quot;function baz() { let foo; if (true) function foo() { }; }&quot;
+PASS Valid:   &quot;function f() { function baz() { let foo; if (true) function foo() { }; } }&quot;
+PASS Invalid: &quot;if (true) function foo() { }; let foo;&quot;
+PASS Valid:   &quot;function f() { if (true) function foo() { }; let foo; }&quot;
+PASS Invalid: &quot;{ if (true) function foo() { }; } let foo;&quot;
+PASS Valid:   &quot;function f() { { if (true) function foo() { }; } let foo; }&quot;
+PASS Invalid: &quot;let foo; while (false) function foo() { }; &quot;
+PASS Invalid: &quot;function f() { let foo; while (false) function foo() { };  }&quot;
+PASS Invalid: &quot;let foo;  { while (false) function foo() { }; } &quot;
+PASS Invalid: &quot;function f() { let foo;  { while (false) function foo() { }; }  }&quot;
+PASS Invalid: &quot;while (false) function foo() { }; let foo;&quot;
+PASS Invalid: &quot;function f() { while (false) function foo() { }; let foo; }&quot;
+PASS Invalid: &quot;let foo; while (false) label: function foo() { }; &quot;
+PASS Invalid: &quot;function f() { let foo; while (false) label: function foo() { };  }&quot;
+PASS Invalid: &quot;while (false) label: function foo() { }; let foo;&quot;
+PASS Invalid: &quot;function f() { while (false) label: function foo() { }; let foo; }&quot;
+PASS Invalid: &quot;'use strict'; while (false) function foo() { }; &quot;
+PASS Invalid: &quot;function f() { 'use strict'; while (false) function foo() { };  }&quot;
+PASS Invalid: &quot;'use strict'; if (false) function foo() { }; &quot;
+PASS Invalid: &quot;function f() { 'use strict'; if (false) function foo() { };  }&quot;
+PASS Invalid: &quot;'use strict'; do function foo() { } while (false); &quot;
+PASS Invalid: &quot;function f() { 'use strict'; do function foo() { } while (false);  }&quot;
+PASS Invalid: &quot;while (false) function foo() { }; &quot;
+PASS Invalid: &quot;function f() { while (false) function foo() { };  }&quot;
+PASS Valid:   &quot;if (false) function foo() { }; &quot;
+PASS Valid:   &quot;function f() { if (false) function foo() { };  }&quot;
+PASS Invalid: &quot;do function foo() { } while (false); &quot;
+PASS Invalid: &quot;function f() { do function foo() { } while (false);  }&quot;
+PASS Invalid: &quot;if (cond) label: function foo() { }&quot;
+PASS Invalid: &quot;function f() { if (cond) label: function foo() { } }&quot;
+PASS Invalid: &quot;while (true) { while (true) function bar() { } }&quot;
+PASS Invalid: &quot;function f() { while (true) { while (true) function bar() { } } }&quot;
+PASS Invalid: &quot;with ({}) function bar() { }&quot;
+PASS Invalid: &quot;function f() { with ({}) function bar() { } }&quot;
+PASS Valid:   &quot;function bar() { label: function baz() { } }&quot;
+PASS Valid:   &quot;function f() { function bar() { label: function baz() { } } }&quot;
+PASS Valid:   &quot;function bar() { let: function baz() { } }&quot;
+PASS Valid:   &quot;function f() { function bar() { let: function baz() { } } }&quot;
+PASS Invalid: &quot;function bar() { 'use strict'; let: function baz() { } }&quot;
+PASS Invalid: &quot;function f() { function bar() { 'use strict'; let: function baz() { } } }&quot;
+PASS Valid:   &quot;function bar() { yield: function baz() { } }&quot;
+PASS Valid:   &quot;function f() { function bar() { yield: function baz() { } } }&quot;
+PASS Valid:   &quot;function bar() { label: label2: function baz() { } }&quot;
+PASS Valid:   &quot;function f() { function bar() { label: label2: function baz() { } } }&quot;
+PASS Valid:   &quot;function bar() { label: label2: label3: function baz() { } }&quot;
+PASS Valid:   &quot;function f() { function bar() { label: label2: label3: function baz() { } } }&quot;
+PASS Invalid: &quot;function bar() { label: label2: label weird: function baz() { } }&quot;
+PASS Invalid: &quot;function f() { function bar() { label: label2: label weird: function baz() { } } }&quot;
+PASS Valid:   &quot;function bar() { label: label2: label3: function baz() { } }&quot;
+PASS Valid:   &quot;function f() { function bar() { label: label2: label3: function baz() { } } }&quot;
+PASS Invalid: &quot;function bar() { 'use strict'; label: label2: label 3: function baz() { } }&quot;
+PASS Invalid: &quot;function f() { function bar() { 'use strict'; label: label2: label 3: function baz() { } } }&quot;
+PASS Invalid: &quot;function bar() { if (cond) label: function foo() { } }&quot;
+PASS Invalid: &quot;function f() { function bar() { if (cond) label: function foo() { } } }&quot;
+PASS Invalid: &quot;function bar() { while (cond) label: function foo() { } }&quot;
+PASS Invalid: &quot;function f() { function bar() { while (cond) label: function foo() { } } }&quot;
+PASS Valid:   &quot;label: function foo() { }&quot;
+PASS Valid:   &quot;function f() { label: function foo() { } }&quot;
+PASS Valid:   &quot;let: function foo() { }&quot;
+PASS Valid:   &quot;function f() { let: function foo() { } }&quot;
+PASS Valid:   &quot;yield: function foo() { }&quot;
+PASS Valid:   &quot;function f() { yield: function foo() { } }&quot;
+PASS Valid:   &quot;yield: let: function foo() { }&quot;
+PASS Valid:   &quot;function f() { yield: let: function foo() { } }&quot;
+PASS Invalid: &quot;'use strict'; yield: let: function foo() { }&quot;
+PASS Invalid: &quot;function f() { 'use strict'; yield: let: function foo() { } }&quot;
</ins><span class="cx"> PASS Valid:   &quot;var str = &quot;'use strict'; function f1(a) { function f2(b) { return b; } return f2(a); } return f1(arguments[0]);&quot;; var foo = new Function(str); foo(5);&quot;
</span><span class="cx"> PASS Valid:   &quot;function f() { var str = &quot;'use strict'; function f1(a) { function f2(b) { return b; } return f2(a); } return f1(arguments[0]);&quot;; var foo = new Function(str); foo(5); }&quot;
</span><span class="cx"> PASS Valid:   &quot;var str = &quot;'use strict'; function f1(a) { function f2(b) { function f3(c) { return c; } return f3(b); } return f2(a); } return f1(arguments[0]);&quot;; var foo = new Function(str); foo(5);&quot;
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsfunctiondeclarationstatementjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/function-declaration-statement.js (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/function-declaration-statement.js        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/js/script-tests/function-declaration-statement.js        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -35,117 +35,6 @@
</span><span class="cx"> 
</span><span class="cx"> shouldBeTrue(&quot;ifElseTest()&quot;);
</span><span class="cx"> 
</span><del>-function doWhileTest()
-{
-    var i = 0;
-    do
-        function f()
-        {
-            return true;
-        }
-    while (i++ &lt; 10)
-
-    return f();
-}
-
-shouldBeTrue(&quot;doWhileTest()&quot;);
-
-function whileTest()
-{
-    var i = 0;
-    while (i++ &lt; 10)
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;whileTest()&quot;);
-
-function forTest()
-{
-    var i;
-    for (i = 0; i &lt; 10; ++i)
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;forTest()&quot;);
-
-function forVarTest()
-{
-    for (var i = 0; i &lt; 10; ++i)
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;forVarTest()&quot;);
-
-function forInTest()
-{
-    var a;
-    for (a in { field: false })
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;forInTest()&quot;);
-
-function forInVarTest()
-{
-    var a;
-    for (var a in { field: false })
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;forInVarTest()&quot;);
-
-function forInVarInitTest()
-{
-    var a;
-    for (var a in { field: false })
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;forInVarInitTest()&quot;);
-
-function withTest()
-{
-    with ({ })
-        function f()
-        {
-            return true;
-        }
-
-    return f();
-}
-
-shouldBeTrue(&quot;withTest()&quot;);
-
</del><span class="cx"> function labelTest()
</span><span class="cx"> {
</span><span class="cx">     label:
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsparsersyntaxcheckjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/parser-syntax-check.js (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -43,6 +43,18 @@
</span><span class="cx">     runTest(&quot;function f() { &quot; + _a + &quot; }&quot;, false);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function onlyValidGlobally(_a)
+{
+    runTest(_a, false);
+    runTest(&quot;function f() { &quot; + _a + &quot; }&quot;, true);
+}
+
+function onlyInvalidGlobally(_a)
+{
+    runTest(_a, true);
+    runTest(&quot;function f() { &quot; + _a + &quot; }&quot;, false);
+}
+
</ins><span class="cx"> function invalid(_a)
</span><span class="cx"> {
</span><span class="cx">     // Test both the grammar and the syntax checker
</span><span class="lines">@@ -226,7 +238,7 @@
</span><span class="cx"> invalid(&quot;do if (a) while (false) else debugger&quot;);
</span><span class="cx"> invalid(&quot;while if (a) ;&quot;);
</span><span class="cx"> valid  (&quot;if (a) function f() {} else function g() {}&quot;);
</span><del>-valid  (&quot;if (a()) while(0) function f() {} else function g() {}&quot;);
</del><ins>+invalid(&quot;if (a()) while(0) function f() {} else function g() {}&quot;);
</ins><span class="cx"> invalid(&quot;if (a()) function f() { else function g() }&quot;);
</span><span class="cx"> invalid(&quot;if (a) if (b) ; else function f {}&quot;);
</span><span class="cx"> invalid(&quot;if (a) if (b) ; else function (){}&quot;);
</span><span class="lines">@@ -428,11 +440,28 @@
</span><span class="cx"> invalid(&quot;'use strict'; let f1; function f1(a) {};&quot;)
</span><span class="cx"> invalid(&quot;'use strict'; function f1(a) {}; let f1; &quot;)
</span><span class="cx"> invalid(&quot;let f1; function f1(a) {};&quot;)
</span><del>-invalid(&quot;let f1; { function f1(a) {}; }&quot;)
-invalid(&quot;{ function f1(a) {}; } let f1;&quot;)
-valid(&quot;{ let f1; function f1(a) {}; }&quot;)
-valid(&quot;{  function f1(a) {}; let f1; }&quot;)
</del><ins>+valid(&quot;function foo() { let f1; { function f1(a) {}; } }&quot;)
+valid(&quot;function foo() { { function f1(a) {}; } let f1; }&quot;)
+valid(&quot;function foo() { { function foo() { }; function foo() { } } }&quot;)
+invalid(&quot;function foo() { 'use strict'; { function foo() { }; function foo() { } } }&quot;)
+invalid(&quot;function foo() { let f1; function f1(a) {}; }&quot;)
+invalid(&quot;let f1; function f1(a) {};&quot;)
+onlyValidGlobally(&quot;{ function f1(a) {}; let f1; }&quot;)
+onlyValidGlobally(&quot;{ function f1(a) {}; const f1 = 25; }&quot;)
+onlyValidGlobally(&quot;{ function f1(a) {}; class f1{}; }&quot;)
+invalid(&quot;function foo() { { let bar; function bar() { } } }&quot;)
+invalid(&quot;function foo() { { function bar() { }; let bar; } }&quot;)
+invalid(&quot;function foo() { { const bar; function bar() { } } }&quot;)
+invalid(&quot;function foo() { { function bar() { }; const bar; } }&quot;)
+invalid(&quot;function foo() { { class bar{}; function bar() { } } }&quot;)
+invalid(&quot;function foo() { { function bar() { }; class bar{}; } }&quot;)
</ins><span class="cx"> valid(&quot;switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; }&quot;)
</span><ins>+onlyValidGlobally(&quot;switch('foo') { case 1: let foo; function foo() {}; break; case 2: function foo() {}; break; }&quot;)
+onlyValidGlobally(&quot;switch('foo') { case 1: function foo() {}; let foo; break; case 2: function foo() {}; break; }&quot;)
+onlyValidGlobally(&quot;switch('foo') { case 1: function foo() {}; const foo = 25; break; case 2: function foo() {}; break; }&quot;)
+onlyValidGlobally(&quot;switch('foo') { case 1: function foo() {}; class foo {} ; break; case 2: function foo() {}; break; }&quot;)
+onlyValidGlobally(&quot;switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; case 3: let foo; }&quot;)
+valid(&quot;function foo() { switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; case 3: { let foo; } } }&quot;)
</ins><span class="cx"> invalid(&quot;'use strict'; switch('foo') { case 1: function foo() {}; break; case 2: function foo() {}; break; }&quot;);
</span><span class="cx"> invalid(&quot;'use strict'; switch('foo') { case 1: function foo() {}; break; case 2: let foo; break; }&quot;);
</span><span class="cx"> invalid(&quot;'use strict'; switch('foo') { case 1: let foo; break; case 2: function foo() {}; break; }&quot;);
</span><span class="lines">@@ -440,6 +469,40 @@
</span><span class="cx"> valid(&quot;'use strict'; switch('foo') { case 1: { function foo() { }; break; } case 2: function foo() {}; break; }&quot;);
</span><span class="cx"> invalid(&quot;'use strict'; if (true) function foo() { }; &quot;);
</span><span class="cx"> valid(&quot;if (true) function foo() { }; &quot;);
</span><ins>+onlyInvalidGlobally(&quot; let foo; if (true) function foo() { };&quot;);
+valid(&quot;function baz() { let foo; if (true) function foo() { }; }&quot;);
+onlyInvalidGlobally(&quot;if (true) function foo() { }; let foo;&quot;);
+onlyInvalidGlobally(&quot;{ if (true) function foo() { }; } let foo;&quot;);
+invalid(&quot;let foo; while (false) function foo() { }; &quot;);
+invalid(&quot;let foo;  { while (false) function foo() { }; } &quot;);
+invalid(&quot;while (false) function foo() { }; let foo;&quot;);
+invalid(&quot;let foo; while (false) label: function foo() { }; &quot;);
+invalid(&quot;while (false) label: function foo() { }; let foo;&quot;);
+invalid(&quot;'use strict'; while (false) function foo() { }; &quot;);
+invalid(&quot;'use strict'; if (false) function foo() { }; &quot;);
+invalid(&quot;'use strict'; do function foo() { } while (false); &quot;);
+invalid(&quot;while (false) function foo() { }; &quot;);
+valid(&quot;if (false) function foo() { }; &quot;);
+invalid(&quot;do function foo() { } while (false); &quot;);
+invalid(&quot;if (cond) label: function foo() { }&quot;);
+invalid(&quot;while (true) { while (true) function bar() { } }&quot;);
+invalid(&quot;with ({}) function bar() { }&quot;);
+valid(&quot;function bar() { label: function baz() { } }&quot;);
+valid(&quot;function bar() { let: function baz() { } }&quot;);
+invalid(&quot;function bar() { 'use strict'; let: function baz() { } }&quot;);
+valid(&quot;function bar() { yield: function baz() { } }&quot;);
+valid(&quot;function bar() { label: label2: function baz() { } }&quot;);
+valid(&quot;function bar() { label: label2: label3: function baz() { } }&quot;);
+invalid(&quot;function bar() { label: label2: label weird: function baz() { } }&quot;);
+valid(&quot;function bar() { label: label2: label3: function baz() { } }&quot;);
+invalid(&quot;function bar() { 'use strict'; label: label2: label 3: function baz() { } }&quot;);
+invalid(&quot;function bar() { if (cond) label: function foo() { } }&quot;);
+invalid(&quot;function bar() { while (cond) label: function foo() { } }&quot;);
+valid(&quot;label: function foo() { }&quot;);
+valid(&quot;let: function foo() { }&quot;);
+valid(&quot;yield: function foo() { }&quot;);
+valid(&quot;yield: let: function foo() { }&quot;);
+invalid(&quot;'use strict'; yield: let: function foo() { }&quot;);
</ins><span class="cx"> 
</span><span class="cx"> valid(&quot;var str = \&quot;'use strict'; function f1(a) { function f2(b) { return b; } return f2(a); } return f1(arguments[0]);\&quot;; var foo = new Function(str); foo(5);&quot;)
</span><span class="cx"> valid(&quot;var str = \&quot;'use strict'; function f1(a) { function f2(b) { function f3(c) { return c; } return f3(b); } return f2(a); } return f1(arguments[0]);\&quot;; var foo = new Function(str); foo(5);&quot;)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -1,3 +1,138 @@
</span><ins>+2016-04-03  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Implement Annex B.3.3 function hoisting rules for function code
+        https://bugs.webkit.org/show_bug.cgi?id=155672
+
+        Reviewed by Geoffrey Garen.
+
+        The spec states that functions declared inside a function
+        inside a block scope are subject to the rules of Annex B.3.3:
+        https://tc39.github.io/ecma262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics
+
+        The rule states that functions declared in such blocks should
+        be local bindings of the block. If declaring the function's name
+        as a &quot;var&quot; in the function would not lead to a syntax error (i.e,
+        if we don't have a let/const/class variable with the same name)
+        and if we don't have a parameter with the same name, then we
+        implictly also declare the funcion name as a &quot;var&quot;. When evaluating
+        the block statement we bind the hoisted &quot;var&quot; to be the value
+        of the local function binding.
+
+        There is one more thing we do for web compatibility. We allow
+        function declarations inside if/else statements that aren't
+        blocks. For such statements, we transform the code as if the
+        function were declared inside a block statement. For example:
+        ``` function foo() { if (cond) function baz() { } }```
+        is transformed into:
+        ``` function foo() { if (cond) { function baz() { } } }```
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
+        (JSC::BytecodeGenerator::initializeBlockScopedFunctions):
+        * bytecompiler/BytecodeGenerator.h:
+        * parser/Nodes.cpp:
+        (JSC::ScopeNode::ScopeNode):
+        (JSC::ProgramNode::ProgramNode):
+        (JSC::ModuleProgramNode::ModuleProgramNode):
+        (JSC::EvalNode::EvalNode):
+        (JSC::FunctionNode::FunctionNode):
+        * parser/Nodes.h:
+        (JSC::ScopeNode::hasCapturedVariables):
+        (JSC::ScopeNode::captures):
+        (JSC::ScopeNode::hasSloppyModeHoistedFunction):
+        (JSC::ScopeNode::varDeclarations):
+        (JSC::ProgramNode::startColumn):
+        (JSC::ProgramNode::endColumn):
+        (JSC::EvalNode::startColumn):
+        (JSC::EvalNode::endColumn):
+        (JSC::ModuleProgramNode::startColumn):
+        (JSC::ModuleProgramNode::endColumn):
+        * parser/Parser.cpp:
+        (JSC::Parser&lt;LexerType&gt;::Parser):
+        (JSC::Parser&lt;LexerType&gt;::parseInner):
+        (JSC::Parser&lt;LexerType&gt;::didFinishParsing):
+        (JSC::Parser&lt;LexerType&gt;::parseStatement):
+        (JSC::Parser&lt;LexerType&gt;::parseIfStatement):
+        * parser/Parser.h:
+        (JSC::Scope::declareVariable):
+        (JSC::Scope::declareFunction):
+        (JSC::Scope::addSloppyModeHoistableFunctionCandidate):
+        (JSC::Scope::appendFunction):
+        (JSC::Scope::declareParameter):
+        (JSC::Scope::mergeInnerArrowFunctionFeatures):
+        (JSC::Scope::getSloppyModeHoistedFunctions):
+        (JSC::Scope::getCapturedVars):
+        (JSC::ScopeRef::containingScope):
+        (JSC::ScopeRef::operator==):
+        (JSC::ScopeRef::operator!=):
+        (JSC::Parser::declareFunction):
+        (JSC::Parser::hasDeclaredVariable):
+        (JSC::Parser::isFunctionMetadataNode):
+        (JSC::Parser::DepthManager::DepthManager):
+        (JSC::Parser&lt;LexerType&gt;::parse):
+        * parser/VariableEnvironment.h:
+        (JSC::VariableEnvironmentEntry::isImported):
+        (JSC::VariableEnvironmentEntry::isImportedNamespace):
+        (JSC::VariableEnvironmentEntry::isFunction):
+        (JSC::VariableEnvironmentEntry::isParameter):
+        (JSC::VariableEnvironmentEntry::isSloppyModeHoistingCandidate):
+        (JSC::VariableEnvironmentEntry::setIsCaptured):
+        (JSC::VariableEnvironmentEntry::setIsConst):
+        (JSC::VariableEnvironmentEntry::setIsImported):
+        (JSC::VariableEnvironmentEntry::setIsImportedNamespace):
+        (JSC::VariableEnvironmentEntry::setIsFunction):
+        (JSC::VariableEnvironmentEntry::setIsParameter):
+        (JSC::VariableEnvironmentEntry::setIsSloppyModeHoistingCandidate):
+        (JSC::VariableEnvironmentEntry::clearIsVar):
+        * runtime/CodeCache.h:
+        (JSC::SourceCodeValue::SourceCodeValue):
+        * runtime/JSScope.cpp:
+        * runtime/JSScope.h:
+        * tests/es6.yaml:
+        * tests/stress/sloppy-mode-function-hoisting.js: Added.
+        (assert):
+        (test):
+        (falsey):
+        (truthy):
+        (test.):
+        (test.a):
+        (test.f):
+        (test.let.funcs.f):
+        (test.catch.f):
+        (test.foo):
+        (test.bar):
+        (test.switch.case.0):
+        (test.else.f):
+        (test.b):
+        (test.c):
+        (test.d):
+        (test.e):
+        (test.g):
+        (test.h):
+        (test.i):
+        (test.j):
+        (test.k):
+        (test.l):
+        (test.m):
+        (test.n):
+        (test.o):
+        (test.p):
+        (test.q):
+        (test.r):
+        (test.s):
+        (test.t):
+        (test.u):
+        (test.v):
+        (test.w):
+        (test.x):
+        (test.y):
+        (test.z):
+        (foo):
+        (bar):
+        (falsey.bar):
+        (baz):
+        (falsey.baz):
+
</ins><span class="cx"> 2016-04-03  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, turn ES6 for-in loop test success
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -861,6 +861,8 @@
</span><span class="cx">         pushScopedControlFlowContext();
</span><span class="cx">     m_symbolTableStack.append(SymbolTableStackEntry{ Strong&lt;SymbolTable&gt;(*m_vm, functionSymbolTable), m_lexicalEnvironmentRegister, false, symbolTableConstantIndex });
</span><span class="cx"> 
</span><ins>+    m_varScopeSymbolTableIndex = m_symbolTableStack.size() - 1;
+
</ins><span class="cx">     // This completes step 28 of section 9.2.12.
</span><span class="cx">     for (unsigned i = 0; i &lt; valuesToMoveIntoVars.size(); i++) {
</span><span class="cx">         ASSERT(!isSimpleParameterList);
</span><span class="lines">@@ -1931,6 +1933,18 @@
</span><span class="cx">         emitNewFunctionExpressionCommon(temp.get(), function);
</span><span class="cx">         bool isLexicallyScoped = true;
</span><span class="cx">         emitPutToScope(scope, variableForLocalEntry(name, entry, symbolTableIndex, isLexicallyScoped), temp.get(), DoNotThrowIfNotFound, Initialization);
</span><ins>+
+        if (iter-&gt;value.isSloppyModeHoistingCandidate() &amp;&amp; m_scopeNode-&gt;hasSloppyModeHoistedFunction(name.impl())) {
+            ASSERT(m_varScopeSymbolTableIndex);
+            ASSERT(*m_varScopeSymbolTableIndex &lt; m_symbolTableStack.size());
+            SymbolTableStackEntry&amp; varScope = m_symbolTableStack[*m_varScopeSymbolTableIndex];
+            SymbolTable* varSymbolTable = varScope.m_symbolTable.get();
+            RELEASE_ASSERT(varSymbolTable-&gt;scopeType() == SymbolTable::ScopeType::VarScope);
+            SymbolTableEntry entry = varSymbolTable-&gt;get(name.impl());
+            RELEASE_ASSERT(!entry.isNull());
+            bool isLexicallyScoped = false;
+            emitPutToScope(varScope.m_scope, variableForLocalEntry(name, entry, varScope.m_symbolTableConstantIndex, isLexicallyScoped), temp.get(), DoNotThrowIfNotFound, Initialization);
+        }
</ins><span class="cx">     }
</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 (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -863,6 +863,7 @@
</span><span class="cx">         };
</span><span class="cx">         Vector&lt;SymbolTableStackEntry&gt; m_symbolTableStack;
</span><span class="cx">         Vector&lt;std::pair&lt;VariableEnvironment, TDZCheckOptimization&gt;&gt; m_TDZStack;
</span><ins>+        Optional&lt;size_t&gt; m_varScopeSymbolTableIndex;
</ins><span class="cx">         void pushTDZVariables(VariableEnvironment, TDZCheckOptimization);
</span><span class="cx"> 
</span><span class="cx">         ScopeNode* const m_scopeNode;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Nodes.cpp (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Nodes.cpp        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/parser/Nodes.cpp        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -93,7 +93,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ScopeNode::ScopeNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, const SourceCode&amp; source, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
</del><ins>+ScopeNode::ScopeNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, const SourceCode&amp; source, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, UniquedStringImplPtrSet&amp;&amp; sloppyModeHoistedFunctions, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
</ins><span class="cx">     : StatementNode(endLocation)
</span><span class="cx">     , ParserArenaRoot(parserArena)
</span><span class="cx">     , VariableEnvironmentNode(lexicalVariables, WTFMove(funcStack))
</span><span class="lines">@@ -103,6 +103,7 @@
</span><span class="cx">     , m_features(features)
</span><span class="cx">     , m_innerArrowFunctionCodeFeatures(innerArrowFunctionCodeFeatures)
</span><span class="cx">     , m_source(source)
</span><ins>+    , m_sloppyModeHoistedFunctions(WTFMove(sloppyModeHoistedFunctions))
</ins><span class="cx">     , m_numConstants(numConstants)
</span><span class="cx">     , m_statements(children)
</span><span class="cx"> {
</span><span class="lines">@@ -116,8 +117,8 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ ProgramNode -----------------------------
</span><span class="cx"> 
</span><del>-ProgramNode::ProgramNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, FunctionParameters*, const SourceCode&amp; source, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
-    : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, WTFMove(funcStack), lexicalVariables, features, innerArrowFunctionCodeFeatures, numConstants)
</del><ins>+ProgramNode::ProgramNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, UniquedStringImplPtrSet&amp;&amp; sloppyModeHoistedFunctions, FunctionParameters*, const SourceCode&amp; source, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
+    : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, WTFMove(funcStack), lexicalVariables, WTFMove(sloppyModeHoistedFunctions), features, innerArrowFunctionCodeFeatures, numConstants)
</ins><span class="cx">     , m_startColumn(startColumn)
</span><span class="cx">     , m_endColumn(endColumn)
</span><span class="cx"> {
</span><span class="lines">@@ -125,8 +126,8 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ ModuleProgramNode -----------------------------
</span><span class="cx"> 
</span><del>-ModuleProgramNode::ModuleProgramNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, FunctionParameters*, const SourceCode&amp; source, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
-    : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, WTFMove(funcStack), lexicalVariables, features, innerArrowFunctionCodeFeatures, numConstants)
</del><ins>+ModuleProgramNode::ModuleProgramNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, UniquedStringImplPtrSet&amp;&amp; sloppyModeHoistedFunctions, FunctionParameters*, const SourceCode&amp; source, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
+    : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, WTFMove(funcStack), lexicalVariables, WTFMove(sloppyModeHoistedFunctions), features, innerArrowFunctionCodeFeatures, numConstants)
</ins><span class="cx">     , m_startColumn(startColumn)
</span><span class="cx">     , m_endColumn(endColumn)
</span><span class="cx"> {
</span><span class="lines">@@ -134,8 +135,8 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ EvalNode -----------------------------
</span><span class="cx"> 
</span><del>-EvalNode::EvalNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, FunctionParameters*, const SourceCode&amp; source, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
-    : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, WTFMove(funcStack), lexicalVariables, features, innerArrowFunctionCodeFeatures, numConstants)
</del><ins>+EvalNode::EvalNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, UniquedStringImplPtrSet&amp;&amp; sloppyModeHoistedFunctions, FunctionParameters*, const SourceCode&amp; source, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
+    : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, WTFMove(funcStack), lexicalVariables, WTFMove(sloppyModeHoistedFunctions), features, innerArrowFunctionCodeFeatures, numConstants)
</ins><span class="cx">     , m_endColumn(endColumn)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -180,8 +181,8 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ FunctionNode -----------------------------
</span><span class="cx"> 
</span><del>-FunctionNode::FunctionNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, FunctionParameters* parameters, const SourceCode&amp; sourceCode, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
-    : ScopeNode(parserArena, startLocation, endLocation, sourceCode, children, varEnvironment, WTFMove(funcStack), lexicalVariables, features, innerArrowFunctionCodeFeatures, numConstants)
</del><ins>+FunctionNode::FunctionNode(ParserArena&amp; parserArena, const JSTokenLocation&amp; startLocation, const JSTokenLocation&amp; endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment&amp; varEnvironment, FunctionStack&amp;&amp; funcStack, VariableEnvironment&amp; lexicalVariables, UniquedStringImplPtrSet&amp;&amp; sloppyModeHoistedFunctions, FunctionParameters* parameters, const SourceCode&amp; sourceCode, CodeFeatures features, InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures, int numConstants)
+    : ScopeNode(parserArena, startLocation, endLocation, sourceCode, children, varEnvironment, WTFMove(funcStack), lexicalVariables, WTFMove(sloppyModeHoistedFunctions), features, innerArrowFunctionCodeFeatures, numConstants)
</ins><span class="cx">     , m_parameters(parameters)
</span><span class="cx">     , m_startColumn(startColumn)
</span><span class="cx">     , m_endColumn(endColumn)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Nodes.h (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Nodes.h        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/parser/Nodes.h        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> #include &quot;SymbolTable.h&quot;
</span><span class="cx"> #include &quot;VariableEnvironment.h&quot;
</span><span class="cx"> #include &lt;wtf/MathExtras.h&gt;
</span><ins>+#include &lt;wtf/SmallPtrSet.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -51,6 +52,8 @@
</span><span class="cx">     class ScopeNode;
</span><span class="cx">     class ModuleAnalyzer;
</span><span class="cx"> 
</span><ins>+    typedef SmallPtrSet&lt;UniquedStringImpl*&gt; UniquedStringImplPtrSet;
+
</ins><span class="cx">     enum Operator {
</span><span class="cx">         OpEqual,
</span><span class="cx">         OpPlusEq,
</span><span class="lines">@@ -1563,7 +1566,7 @@
</span><span class="cx">     public:
</span><span class="cx"> 
</span><span class="cx">         ScopeNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, bool inStrictContext);
</span><del>-        ScopeNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, const SourceCode&amp;, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</del><ins>+        ScopeNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, const SourceCode&amp;, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, UniquedStringImplPtrSet&amp;&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</ins><span class="cx"> 
</span><span class="cx">         using ParserArenaRoot::operator new;
</span><span class="cx"> 
</span><span class="lines">@@ -1601,6 +1604,7 @@
</span><span class="cx">         bool hasCapturedVariables() const { return m_varDeclarations.hasCapturedVariables(); }
</span><span class="cx">         bool captures(UniquedStringImpl* uid) { return m_varDeclarations.captures(uid); }
</span><span class="cx">         bool captures(const Identifier&amp; ident) { return captures(ident.impl()); }
</span><ins>+        bool hasSloppyModeHoistedFunction(UniquedStringImpl* uid) const { return m_sloppyModeHoistedFunctions.contains(uid); }
</ins><span class="cx"> 
</span><span class="cx">         VariableEnvironment&amp; varDeclarations() { return m_varDeclarations; }
</span><span class="cx"> 
</span><span class="lines">@@ -1627,13 +1631,14 @@
</span><span class="cx">         InnerArrowFunctionCodeFeatures m_innerArrowFunctionCodeFeatures;
</span><span class="cx">         SourceCode m_source;
</span><span class="cx">         VariableEnvironment m_varDeclarations;
</span><ins>+        UniquedStringImplPtrSet m_sloppyModeHoistedFunctions;
</ins><span class="cx">         int m_numConstants;
</span><span class="cx">         SourceElements* m_statements;
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     class ProgramNode : public ScopeNode {
</span><span class="cx">     public:
</span><del>-        ProgramNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</del><ins>+        ProgramNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, UniquedStringImplPtrSet&amp;&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</ins><span class="cx"> 
</span><span class="cx">         unsigned startColumn() const { return m_startColumn; }
</span><span class="cx">         unsigned endColumn() const { return m_endColumn; }
</span><span class="lines">@@ -1648,7 +1653,7 @@
</span><span class="cx"> 
</span><span class="cx">     class EvalNode : public ScopeNode {
</span><span class="cx">     public:
</span><del>-        EvalNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</del><ins>+        EvalNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, UniquedStringImplPtrSet&amp;&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</ins><span class="cx"> 
</span><span class="cx">         ALWAYS_INLINE unsigned startColumn() const { return 0; }
</span><span class="cx">         unsigned endColumn() const { return m_endColumn; }
</span><span class="lines">@@ -1663,7 +1668,7 @@
</span><span class="cx"> 
</span><span class="cx">     class ModuleProgramNode : public ScopeNode {
</span><span class="cx">     public:
</span><del>-        ModuleProgramNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</del><ins>+        ModuleProgramNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, UniquedStringImplPtrSet&amp;&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</ins><span class="cx"> 
</span><span class="cx">         unsigned startColumn() const { return m_startColumn; }
</span><span class="cx">         unsigned endColumn() const { return m_endColumn; }
</span><span class="lines">@@ -1904,7 +1909,7 @@
</span><span class="cx"> 
</span><span class="cx">     class FunctionNode final : public ScopeNode {
</span><span class="cx">     public:
</span><del>-        FunctionNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</del><ins>+        FunctionNode(ParserArena&amp;, const JSTokenLocation&amp; start, const JSTokenLocation&amp; end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&amp;, FunctionStack&amp;&amp;, VariableEnvironment&amp;, UniquedStringImplPtrSet&amp;&amp;, FunctionParameters*, const SourceCode&amp;, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants);
</ins><span class="cx"> 
</span><span class="cx">         FunctionParameters* parameters() const { return m_parameters; }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -203,6 +203,7 @@
</span><span class="cx">     , m_superBinding(superBinding)
</span><span class="cx">     , m_defaultConstructorKind(defaultConstructorKind)
</span><span class="cx">     , m_thisTDZMode(thisTDZMode)
</span><ins>+    , m_immediateParentAllowsFunctionDeclarationInStatement(false)
</ins><span class="cx"> {
</span><span class="cx">     m_lexer = std::make_unique&lt;LexerType&gt;(vm, builtinMode);
</span><span class="cx">     m_lexer-&gt;setCode(source, &amp;m_parserArena);
</span><span class="lines">@@ -304,9 +305,11 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     IdentifierSet capturedVariables;
</span><ins>+    UniquedStringImplPtrSet sloppyModeHoistedFunctions;
</ins><span class="cx">     bool modifiedParameter = false;
</span><span class="cx">     bool modifiedArguments = false;
</span><del>-    scope-&gt;getCapturedVars(capturedVariables, modifiedParameter, modifiedArguments);
</del><ins>+    scope-&gt;getSloppyModeHoistedFunctions(sloppyModeHoistedFunctions);
+    scope-&gt;getCapturedVars(capturedVariables,  modifiedParameter, modifiedArguments);
</ins><span class="cx"> 
</span><span class="cx">     VariableEnvironment&amp; varDeclarations = scope-&gt;declaredVariables();
</span><span class="cx">     for (auto&amp; entry : capturedVariables)
</span><span class="lines">@@ -341,19 +344,20 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> #endif // NDEBUG
</span><del>-    didFinishParsing(sourceElements, scope-&gt;takeFunctionDeclarations(), varDeclarations, features, context.numConstants());
</del><ins>+    didFinishParsing(sourceElements, scope-&gt;takeFunctionDeclarations(), varDeclarations, WTFMove(sloppyModeHoistedFunctions), features, context.numConstants());
</ins><span class="cx"> 
</span><span class="cx">     return parseError;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename LexerType&gt;
</span><span class="cx"> void Parser&lt;LexerType&gt;::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::FunctionStack&amp;&amp; funcStack, 
</span><del>-    VariableEnvironment&amp; varDeclarations, CodeFeatures features, int numConstants)
</del><ins>+    VariableEnvironment&amp; varDeclarations, UniquedStringImplPtrSet&amp;&amp; sloppyModeHoistedFunctions, CodeFeatures features, int numConstants)
</ins><span class="cx"> {
</span><span class="cx">     m_sourceElements = sourceElements;
</span><span class="cx">     m_funcDeclarations = WTFMove(funcStack);
</span><span class="cx">     m_varDeclarations.swap(varDeclarations);
</span><span class="cx">     m_features = features;
</span><ins>+    m_sloppyModeHoistedFunctions = WTFMove(sloppyModeHoistedFunctions);
</ins><span class="cx">     m_numConstants = numConstants;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -562,8 +566,10 @@
</span><span class="cx">         }
</span><span class="cx">         if (shouldParseVariableDeclaration)
</span><span class="cx">             result = parseVariableDeclaration(context, DeclarationType::LetDeclaration);
</span><del>-        else
-            result = parseExpressionOrLabelStatement(context); // Treat this as an IDENT. This is how ::parseStatement() handles IDENT.
</del><ins>+        else {
+            bool allowFunctionDeclarationAsStatement = true;
+            result = parseExpressionOrLabelStatement(context, allowFunctionDeclarationAsStatement);
+        }
</ins><span class="cx"> 
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -575,6 +581,16 @@
</span><span class="cx">     case FUNCTION:
</span><span class="cx">         result = parseFunctionDeclaration(context);
</span><span class="cx">         break;
</span><ins>+    case IDENT:
+    case YIELD: {
+        // This is a convenient place to notice labeled statements
+        // (even though we also parse them as normal statements)
+        // because we allow the following type of code in sloppy mode:
+        // ``` function foo() { label: function bar() { } } ```
+        bool allowFunctionDeclarationAsStatement = true;
+        result = parseExpressionOrLabelStatement(context, allowFunctionDeclarationAsStatement);
+        break;
+    }
</ins><span class="cx">     default:
</span><span class="cx">         m_statementDepth--; // parseStatement() increments the depth.
</span><span class="cx">         result = parseStatement(context, directive, directiveLiteralLength);
</span><span class="lines">@@ -1603,6 +1619,8 @@
</span><span class="cx">     failIfStackOverflow();
</span><span class="cx">     TreeStatement result = 0;
</span><span class="cx">     bool shouldSetEndOffset = true;
</span><ins>+    bool parentAllowsFunctionDeclarationAsStatement = m_immediateParentAllowsFunctionDeclarationInStatement;
+    m_immediateParentAllowsFunctionDeclarationInStatement = false;
</ins><span class="cx"> 
</span><span class="cx">     switch (m_token.m_type) {
</span><span class="cx">     case OPENBRACE:
</span><span class="lines">@@ -1612,12 +1630,46 @@
</span><span class="cx">     case VAR:
</span><span class="cx">         result = parseVariableDeclaration(context, DeclarationType::VarDeclaration);
</span><span class="cx">         break;
</span><del>-    case FUNCTION:
-        if (!strictMode())
-            result = parseFunctionDeclaration(context);
-        else
</del><ins>+    case FUNCTION: {
+        if (!strictMode()) {
+            failIfFalse(parentAllowsFunctionDeclarationAsStatement, &quot;Function declarations are only allowed inside block statements or at the top level of a program&quot;);
+            if (currentScope()-&gt;isFunction()) {
+                // Any function declaration that isn't in a block is a syntax error unless it's
+                // in an if/else statement. If it's in an if/else statement, we will magically
+                // treat it as if the if/else statement is inside a block statement.
+                // to the very top like a &quot;var&quot;. For example:
+                // function a() {
+                //     if (cond) function foo() { }
+                // }
+                // will be rewritten as:
+                // function a() {
+                //     if (cond) { function foo() { } }
+                // }
+                AutoPopScopeRef blockScope(this, pushScope());
+                blockScope-&gt;setIsLexicalScope();
+                blockScope-&gt;preventVarDeclarations();
+                JSTokenLocation location(tokenLocation());
+                int start = tokenLine();
+
+                TreeStatement function = parseFunctionDeclaration(context);
+                propagateError();
+                failIfFalse(function, &quot;Expected valid function statement after 'function' keyword&quot;);
+                TreeSourceElements sourceElements = context.createSourceElements();
+                context.appendStatement(sourceElements, function);
+                result = context.createBlockStatement(location, sourceElements, start, m_lastTokenEndPosition.line, currentScope()-&gt;finalizeLexicalEnvironment(), currentScope()-&gt;takeFunctionDeclarations());
+                popScope(blockScope, TreeBuilder::NeedsFreeVariableInfo);
+            } else {
+                // We only implement annex B.3.3 if we're in function mode. Otherwise, we fall back
+                // to hoisting behavior.
+                // FIXME: https://bugs.webkit.org/show_bug.cgi?id=155813
+                DepthManager statementDepth(&amp;m_statementDepth);
+                m_statementDepth = 1;
+                result = parseFunctionDeclaration(context);
+            }
+        } else
</ins><span class="cx">             failWithMessage(&quot;Function declarations are only allowed inside blocks or switch statements in strict mode&quot;);
</span><span class="cx">         break;
</span><ins>+    }
</ins><span class="cx">     case SEMICOLON: {
</span><span class="cx">         JSTokenLocation location(tokenLocation());
</span><span class="cx">         next();
</span><span class="lines">@@ -1667,9 +1719,11 @@
</span><span class="cx">         // These tokens imply the end of a set of source elements
</span><span class="cx">         return 0;
</span><span class="cx">     case IDENT:
</span><del>-    case YIELD:
-        result = parseExpressionOrLabelStatement(context);
</del><ins>+    case YIELD: {
+        bool allowFunctionDeclarationAsStatement = false;
+        result = parseExpressionOrLabelStatement(context, allowFunctionDeclarationAsStatement);
</ins><span class="cx">         break;
</span><ins>+    }
</ins><span class="cx">     case STRING:
</span><span class="cx">         directive = m_token.m_data.ident;
</span><span class="cx">         if (directiveLiteralLength)
</span><span class="lines">@@ -2372,7 +2426,7 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename LexerType&gt;
</span><del>-template &lt;class TreeBuilder&gt; TreeStatement Parser&lt;LexerType&gt;::parseExpressionOrLabelStatement(TreeBuilder&amp; context)
</del><ins>+template &lt;class TreeBuilder&gt; TreeStatement Parser&lt;LexerType&gt;::parseExpressionOrLabelStatement(TreeBuilder&amp; context, bool allowFunctionDeclarationAsStatement)
</ins><span class="cx"> {
</span><span class="cx">     
</span><span class="cx">     /* Expression and Label statements are ambiguous at LL(1), so we have a
</span><span class="lines">@@ -2423,6 +2477,7 @@
</span><span class="cx">         for (size_t i = 0; i &lt; labels.size(); i++)
</span><span class="cx">             pushLabel(labels[i].m_ident, isLoop);
</span><span class="cx">     }
</span><ins>+    m_immediateParentAllowsFunctionDeclarationInStatement = allowFunctionDeclarationAsStatement;
</ins><span class="cx">     TreeStatement statement = parseStatement(context, unused);
</span><span class="cx">     if (!m_syntaxAlreadyValidated) {
</span><span class="cx">         for (size_t i = 0; i &lt; labels.size(); i++)
</span><span class="lines">@@ -2475,6 +2530,7 @@
</span><span class="cx">     handleProductionOrFail(CLOSEPAREN, &quot;)&quot;, &quot;end&quot;, &quot;'if' condition&quot;);
</span><span class="cx"> 
</span><span class="cx">     const Identifier* unused = 0;
</span><ins>+    m_immediateParentAllowsFunctionDeclarationInStatement = true;
</ins><span class="cx">     TreeStatement trueBlock = parseStatement(context, unused);
</span><span class="cx">     failIfFalse(trueBlock, &quot;Expected a statement as the body of an if block&quot;);
</span><span class="cx"> 
</span><span class="lines">@@ -2491,6 +2547,7 @@
</span><span class="cx">         next();
</span><span class="cx">         if (!match(IF)) {
</span><span class="cx">             const Identifier* unused = 0;
</span><ins>+            m_immediateParentAllowsFunctionDeclarationInStatement = true;
</ins><span class="cx">             TreeStatement block = parseStatement(context, unused);
</span><span class="cx">             failIfFalse(block, &quot;Expected a statement as the body of an else block&quot;);
</span><span class="cx">             statementStack.append(block);
</span><span class="lines">@@ -2507,6 +2564,7 @@
</span><span class="cx">         int innerEnd = tokenLine();
</span><span class="cx">         handleProductionOrFail(CLOSEPAREN, &quot;)&quot;, &quot;end&quot;, &quot;'if' condition&quot;);
</span><span class="cx">         const Identifier* unused = 0;
</span><ins>+        m_immediateParentAllowsFunctionDeclarationInStatement = true;
</ins><span class="cx">         TreeStatement innerTrueBlock = parseStatement(context, unused);
</span><span class="cx">         failIfFalse(innerTrueBlock, &quot;Expected a statement as the body of an if block&quot;);
</span><span class="cx">         tokenLocationStack.append(tempLocation);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.h (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.h        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/parser/Parser.h        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -40,7 +40,6 @@
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> #include &lt;wtf/RefPtr.h&gt;
</span><del>-#include &lt;wtf/SmallPtrSet.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -52,8 +51,6 @@
</span><span class="cx"> class ProgramNode;
</span><span class="cx"> class SourceCode;
</span><span class="cx"> 
</span><del>-typedef SmallPtrSet&lt;UniquedStringImpl*&gt; UniquedStringImplPtrSet;
-
</del><span class="cx"> // Macros to make the more common TreeBuilder types a little less verbose
</span><span class="cx"> #define TreeStatement typename TreeBuilder::Statement
</span><span class="cx"> #define TreeExpression typename TreeBuilder::Expression
</span><span class="lines">@@ -369,7 +366,7 @@
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    DeclarationResultMask declareFunction(const Identifier* ident, bool declareAsVar)
</del><ins>+    DeclarationResultMask declareFunction(const Identifier* ident, bool declareAsVar, bool isSloppyModeHoistingCandidate)
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(m_allowsVarDeclarations || m_allowsLexicalDeclarations);
</span><span class="cx">         DeclarationResultMask result = DeclarationResult::Valid;
</span><span class="lines">@@ -378,7 +375,8 @@
</span><span class="cx">             result |= DeclarationResult::InvalidStrictMode;
</span><span class="cx">         m_isValidStrictMode = m_isValidStrictMode &amp;&amp; isValidStrictMode;
</span><span class="cx">         auto addResult = declareAsVar ? m_declaredVariables.add(ident-&gt;impl()) : m_lexicalVariables.add(ident-&gt;impl());
</span><del>-        addResult.iterator-&gt;value.setIsFunction();
</del><ins>+        if (isSloppyModeHoistingCandidate)
+            addResult.iterator-&gt;value.setIsSloppyModeHoistingCandidate();
</ins><span class="cx">         if (declareAsVar) {
</span><span class="cx">             addResult.iterator-&gt;value.setIsVar();
</span><span class="cx">             if (m_lexicalVariables.contains(ident-&gt;impl()))
</span><span class="lines">@@ -386,12 +384,23 @@
</span><span class="cx">         } else {
</span><span class="cx">             addResult.iterator-&gt;value.setIsLet();
</span><span class="cx">             ASSERT_WITH_MESSAGE(!m_declaredVariables.size(), &quot;We should only declare a function as a lexically scoped variable in scopes where var declarations aren't allowed. I.e, in strict mode and not at the top-level scope of a function or program.&quot;);
</span><del>-            if (!addResult.isNewEntry) 
-                result |= DeclarationResult::InvalidDuplicateDeclaration;
</del><ins>+            if (!addResult.isNewEntry) {
+                if (!isSloppyModeHoistingCandidate || !addResult.iterator-&gt;value.isFunction())
+                    result |= DeclarationResult::InvalidDuplicateDeclaration;
+            }
</ins><span class="cx">         }
</span><ins>+
+        addResult.iterator-&gt;value.setIsFunction();
+
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void addSloppyModeHoistableFunctionCandidate(const Identifier* ident)
+    {
+        ASSERT(m_allowsVarDeclarations);
+        m_sloppyModeHoistableFunctionCandidates.add(ident-&gt;impl());
+    }
+
</ins><span class="cx">     void appendFunction(FunctionMetadataNode* node)
</span><span class="cx">     { 
</span><span class="cx">         ASSERT(node);
</span><span class="lines">@@ -478,6 +487,7 @@
</span><span class="cx">         bool isArgumentsIdent = isArguments(m_vm, ident);
</span><span class="cx">         auto addResult = m_declaredVariables.add(ident-&gt;impl());
</span><span class="cx">         addResult.iterator-&gt;value.clearIsVar();
</span><ins>+        addResult.iterator-&gt;value.setIsParameter();
</ins><span class="cx">         bool isValidStrictMode = addResult.isNewEntry &amp;&amp; m_vm-&gt;propertyNames-&gt;eval != *ident &amp;&amp; !isArgumentsIdent;
</span><span class="cx">         m_isValidStrictMode = m_isValidStrictMode &amp;&amp; isValidStrictMode;
</span><span class="cx">         m_declaredParameters.add(ident-&gt;impl());
</span><span class="lines">@@ -603,6 +613,25 @@
</span><span class="cx">         m_innerArrowFunctionFeatures = m_innerArrowFunctionFeatures | arrowFunctionCodeFeatures;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void getSloppyModeHoistedFunctions(UniquedStringImplPtrSet&amp; sloppyModeHoistedFunctions)
+    {
+        for (UniquedStringImpl* function : m_sloppyModeHoistableFunctionCandidates) {
+            // ES6 Annex B.3.3. The only time we can't hoist a function is if a syntax error would
+            // be caused by declaring a var with that function's name or if we have a parameter with
+            // that function's name. Note that we would only cause a syntax error if we had a let/const/class
+            // variable with the same name.
+            if (!m_lexicalVariables.contains(function)) {
+                auto iter = m_declaredVariables.find(function);
+                bool isParameter = iter != m_declaredVariables.end() &amp;&amp; iter-&gt;value.isParameter();
+                if (!isParameter) {
+                    auto addResult = m_declaredVariables.add(function);
+                    addResult.iterator-&gt;value.setIsVar();
+                    sloppyModeHoistedFunctions.add(function);
+                }
+            }
+        }
+    }
+
</ins><span class="cx">     void getCapturedVars(IdentifierSet&amp; capturedVariables, bool&amp; modifiedParameter, bool&amp; modifiedArguments)
</span><span class="cx">     {
</span><span class="cx">         if (m_needsFullActivation || m_usesEval) {
</span><span class="lines">@@ -742,6 +771,7 @@
</span><span class="cx">     VariableEnvironment m_declaredVariables;
</span><span class="cx">     VariableEnvironment m_lexicalVariables;
</span><span class="cx">     Vector&lt;UniquedStringImplPtrSet, 6&gt; m_usedVariables;
</span><ins>+    UniquedStringImplPtrSet m_sloppyModeHoistableFunctionCandidates;
</ins><span class="cx">     IdentifierSet m_closedVariableCandidates;
</span><span class="cx">     UniquedStringImplPtrSet m_writtenVariables;
</span><span class="cx">     RefPtr&lt;ModuleScopeData&gt; m_moduleScopeData;
</span><span class="lines">@@ -770,6 +800,17 @@
</span><span class="cx">         return ScopeRef(m_scopeStack, m_index - 1);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool operator==(const ScopeRef&amp; other)
+    {
+        ASSERT(other.m_scopeStack == m_scopeStack);
+        return m_index == other.m_index;
+    }
+
+    bool operator!=(const ScopeRef&amp; other)
+    {
+        return !(*this == other);
+    }
+
</ins><span class="cx"> private:
</span><span class="cx">     ScopeStack* m_scopeStack;
</span><span class="cx">     unsigned m_index;
</span><span class="lines">@@ -1076,18 +1117,40 @@
</span><span class="cx"> 
</span><span class="cx">     std::pair&lt;DeclarationResultMask, ScopeRef&gt; declareFunction(const Identifier* ident)
</span><span class="cx">     {
</span><del>-        if (m_statementDepth == 1 || !strictMode()) {
</del><ins>+        if (m_statementDepth == 1 || (!strictMode() &amp;&amp; !currentScope()-&gt;isFunction())) {
</ins><span class="cx">             // Functions declared at the top-most scope (both in sloppy and strict mode) are declared as vars
</span><span class="cx">             // for backwards compatibility. This allows us to declare functions with the same name more than once.
</span><span class="cx">             // In sloppy mode, we always declare functions as vars.
</span><span class="cx">             bool declareAsVar = true;
</span><ins>+            bool isSloppyModeHoistingCandidate = false;
</ins><span class="cx">             ScopeRef variableScope = currentVariableScope();
</span><del>-            return std::make_pair(variableScope-&gt;declareFunction(ident, declareAsVar), variableScope);
</del><ins>+            return std::make_pair(variableScope-&gt;declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), variableScope);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (!strictMode()) {
+            ASSERT(currentScope()-&gt;isFunction());
+
+            // Functions declared inside a function inside a nested block scope in sloppy mode are subject to this
+            // crazy rule defined inside Annex B.3.3 in the ES6 spec. It basically states that we will create
+            // the function as a local block scoped variable, but when we evaluate the block that the function is
+            // contained in, we will assign the function to a &quot;var&quot; variable only if declaring such a &quot;var&quot; wouldn't
+            // be a syntax error and if there isn't a parameter with the same name. (It would only be a syntax error if
+            // there are is a let/class/const with the same name). Note that this mean we only do the &quot;var&quot; hoisting 
+            // binding if the block evaluates. For example, this means we wont won't perform the binding if it's inside
+            // the untaken branch of an if statement.
+            bool declareAsVar = false;
+            bool isSloppyModeHoistingCandidate = true;
+            ScopeRef lexicalVariableScope = currentLexicalDeclarationScope();
+            ScopeRef varScope = currentVariableScope();
+            varScope-&gt;addSloppyModeHoistableFunctionCandidate(ident);
+            ASSERT(varScope != lexicalVariableScope);
+            return std::make_pair(lexicalVariableScope-&gt;declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), lexicalVariableScope);
+        }
+
</ins><span class="cx">         bool declareAsVar = false;
</span><ins>+        bool isSloppyModeHoistingCandidate = false;
</ins><span class="cx">         ScopeRef lexicalVariableScope = currentLexicalDeclarationScope();
</span><del>-        return std::make_pair(lexicalVariableScope-&gt;declareFunction(ident, declareAsVar), lexicalVariableScope);
</del><ins>+        return std::make_pair(lexicalVariableScope-&gt;declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), lexicalVariableScope);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     NEVER_INLINE bool hasDeclaredVariable(const Identifier&amp; ident)
</span><span class="lines">@@ -1134,7 +1197,7 @@
</span><span class="cx">     Parser();
</span><span class="cx">     String parseInner(const Identifier&amp;, SourceParseMode);
</span><span class="cx"> 
</span><del>-    void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&amp;&amp;, VariableEnvironment&amp;, CodeFeatures, int);
</del><ins>+    void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&amp;&amp;, VariableEnvironment&amp;, UniquedStringImplPtrSet&amp;&amp;, CodeFeatures, int);
</ins><span class="cx"> 
</span><span class="cx">     // Used to determine type of error to report.
</span><span class="cx">     bool isFunctionMetadataNode(ScopeNode*) { return false; }
</span><span class="lines">@@ -1349,7 +1412,7 @@
</span><span class="cx">     template &lt;class TreeBuilder&gt; TreeStatement parseTryStatement(TreeBuilder&amp;);
</span><span class="cx">     template &lt;class TreeBuilder&gt; TreeStatement parseDebuggerStatement(TreeBuilder&amp;);
</span><span class="cx">     template &lt;class TreeBuilder&gt; TreeStatement parseExpressionStatement(TreeBuilder&amp;);
</span><del>-    template &lt;class TreeBuilder&gt; TreeStatement parseExpressionOrLabelStatement(TreeBuilder&amp;);
</del><ins>+    template &lt;class TreeBuilder&gt; TreeStatement parseExpressionOrLabelStatement(TreeBuilder&amp;, bool allowFunctionDeclarationAsStatement);
</ins><span class="cx">     template &lt;class TreeBuilder&gt; TreeStatement parseIfStatement(TreeBuilder&amp;);
</span><span class="cx">     template &lt;class TreeBuilder&gt; TreeStatement parseBlockStatement(TreeBuilder&amp;);
</span><span class="cx">     template &lt;class TreeBuilder&gt; TreeExpression parseExpression(TreeBuilder&amp;);
</span><span class="lines">@@ -1544,10 +1607,12 @@
</span><span class="cx">     ThisTDZMode m_thisTDZMode;
</span><span class="cx">     VariableEnvironment m_varDeclarations;
</span><span class="cx">     DeclarationStacks::FunctionStack m_funcDeclarations;
</span><ins>+    UniquedStringImplPtrSet m_sloppyModeHoistedFunctions;
</ins><span class="cx">     CodeFeatures m_features;
</span><span class="cx">     int m_numConstants;
</span><span class="cx">     ExpressionErrorClassifier* m_expressionErrorClassifier;
</span><span class="cx">     bool m_isEvalContext;
</span><ins>+    bool m_immediateParentAllowsFunctionDeclarationInStatement;
</ins><span class="cx">     
</span><span class="cx">     struct DepthManager {
</span><span class="cx">         DepthManager(int* depth)
</span><span class="lines">@@ -1617,6 +1682,7 @@
</span><span class="cx">                                     m_varDeclarations,
</span><span class="cx">                                     WTFMove(m_funcDeclarations),
</span><span class="cx">                                     currentScope()-&gt;finalizeLexicalEnvironment(),
</span><ins>+                                    WTFMove(m_sloppyModeHoistedFunctions),
</ins><span class="cx">                                     m_parameters,
</span><span class="cx">                                     *m_source,
</span><span class="cx">                                     m_features,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserVariableEnvironmenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/VariableEnvironment.h (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/VariableEnvironment.h        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/parser/VariableEnvironment.h        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -41,6 +41,8 @@
</span><span class="cx">     ALWAYS_INLINE bool isImported() const { return m_bits &amp; IsImported; }
</span><span class="cx">     ALWAYS_INLINE bool isImportedNamespace() const { return m_bits &amp; IsImportedNamespace; }
</span><span class="cx">     ALWAYS_INLINE bool isFunction() const { return m_bits &amp; IsFunction; }
</span><ins>+    ALWAYS_INLINE bool isParameter() const { return m_bits &amp; IsParameter; }
+    ALWAYS_INLINE bool isSloppyModeHoistingCandidate() const { return m_bits &amp; IsSloppyModeHoistingCandidate; }
</ins><span class="cx"> 
</span><span class="cx">     ALWAYS_INLINE void setIsCaptured() { m_bits |= IsCaptured; }
</span><span class="cx">     ALWAYS_INLINE void setIsConst() { m_bits |= IsConst; }
</span><span class="lines">@@ -50,11 +52,13 @@
</span><span class="cx">     ALWAYS_INLINE void setIsImported() { m_bits |= IsImported; }
</span><span class="cx">     ALWAYS_INLINE void setIsImportedNamespace() { m_bits |= IsImportedNamespace; }
</span><span class="cx">     ALWAYS_INLINE void setIsFunction() { m_bits |= IsFunction; }
</span><ins>+    ALWAYS_INLINE void setIsParameter() { m_bits |= IsParameter; }
+    ALWAYS_INLINE void setIsSloppyModeHoistingCandidate() { m_bits |= IsSloppyModeHoistingCandidate; }
</ins><span class="cx"> 
</span><span class="cx">     ALWAYS_INLINE void clearIsVar() { m_bits &amp;= ~IsVar; }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    enum Traits : uint8_t {
</del><ins>+    enum Traits : uint16_t {
</ins><span class="cx">         IsCaptured = 1 &lt;&lt; 0,
</span><span class="cx">         IsConst = 1 &lt;&lt; 1,
</span><span class="cx">         IsVar = 1 &lt;&lt; 2,
</span><span class="lines">@@ -62,9 +66,11 @@
</span><span class="cx">         IsExported = 1 &lt;&lt; 4,
</span><span class="cx">         IsImported = 1 &lt;&lt; 5,
</span><span class="cx">         IsImportedNamespace = 1 &lt;&lt; 6,
</span><del>-        IsFunction = 1 &lt;&lt; 7
</del><ins>+        IsFunction = 1 &lt;&lt; 7,
+        IsParameter = 1 &lt;&lt; 8,
+        IsSloppyModeHoistingCandidate = 1 &lt;&lt; 9
</ins><span class="cx">     };
</span><del>-    uint8_t m_bits { 0 };
</del><ins>+    uint16_t m_bits { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct VariableEnvironmentEntryHashTraits : HashTraits&lt;VariableEnvironmentEntry&gt; {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCodeCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CodeCache.h (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CodeCache.h        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/runtime/CodeCache.h        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -32,7 +32,6 @@
</span><span class="cx"> #include &quot;SourceCode.h&quot;
</span><span class="cx"> #include &quot;SourceCodeKey.h&quot;
</span><span class="cx"> #include &quot;Strong.h&quot;
</span><del>-#include &quot;VariableEnvironment.h&quot;
</del><span class="cx"> #include &lt;wtf/CurrentTime.h&gt;
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><span class="cx"> #include &lt;wtf/RandomNumber.h&gt;
</span><span class="lines">@@ -57,6 +56,7 @@
</span><span class="cx"> class VM;
</span><span class="cx"> class SourceCode;
</span><span class="cx"> class SourceProvider;
</span><ins>+class VariableEnvironment;
</ins><span class="cx"> 
</span><span class="cx"> struct SourceCodeValue {
</span><span class="cx">     SourceCodeValue()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSScopecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSScope.cpp (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSScope.cpp        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/runtime/JSScope.cpp        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include &quot;JSModuleRecord.h&quot;
</span><span class="cx"> #include &quot;JSWithScope.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><ins>+#include &quot;VariableEnvironment.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSScopeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSScope.h (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSScope.h        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/runtime/JSScope.h        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -28,12 +28,12 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;GetPutInfo.h&quot;
</span><span class="cx"> #include &quot;JSObject.h&quot;
</span><del>-#include &quot;VariableEnvironment.h&quot;
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> class ScopeChainIterator;
</span><span class="cx"> class WatchpointSet;
</span><ins>+class VariableEnvironment;
</ins><span class="cx"> 
</span><span class="cx"> class JSScope : public JSNonFinalObject {
</span><span class="cx"> public:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6yaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/es6.yaml (198988 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6.yaml        2016-04-03 19:38:54 UTC (rev 198988)
+++ trunk/Source/JavaScriptCore/tests/es6.yaml        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -881,7 +881,7 @@
</span><span class="cx"> - path: es6/new.target_assignment_is_an_early_error.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/non-strict_function_semantics_hoisted_block-level_function_declaration.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Promise_is_subclassable_Promise.all.js
</span><span class="cx">   cmd: runES6 :fail
</span><span class="cx"> - path: es6/Promise_is_subclassable_Promise.race.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresssloppymodefunctionhoistingjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/sloppy-mode-function-hoisting.js (0 => 198989)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/sloppy-mode-function-hoisting.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/sloppy-mode-function-hoisting.js        2016-04-03 19:45:05 UTC (rev 198989)
</span><span class="lines">@@ -0,0 +1,655 @@
</span><ins>+function assert(b) {
+    if (!b)
+        throw new Error(&quot;Bad assertion.&quot;);
+}
+
+function test(f, ...args) {
+    for (let i = 0; i &lt; 500; i++)
+        f(...args);
+}
+
+function falsey() { return false; }
+noInline(falsey);
+function truthy() { return true; }
+noInline(truthy);
+
+test(function() {
+    var a;
+    assert(a === undefined);
+    {
+        function a() { return 20; }
+    }
+    assert(a() === 20);
+});
+
+test(function(a) {
+    var a;
+    assert(a === undefined);
+    {
+        function a() { return 20; }
+    }
+    assert(a === undefined);
+});
+
+test(function({a}) {
+    var a;
+    assert(a === undefined);
+    {
+        function a() { return 20; }
+    }
+    assert(a === undefined);
+}, {});
+
+test(function() {
+    let a;
+    assert(a === undefined);
+    {
+        function a() { return 20; }
+    }
+    assert(a === undefined);
+});
+
+test(function() {
+    assert(a === undefined);
+    function foo() { return a(); }
+    {
+        function a() { return 20; }
+    }
+    assert(a() === 20);
+    assert(foo() === 20);
+});
+
+test(function(a = 30) {
+    assert(a === 30);
+    function foo() { return a; }
+    assert(foo() === 30);
+    {
+        function a() { return 20; }
+        assert(a() === 20);
+        assert(foo() === 30);
+    }
+    assert(a === 30);
+    assert(foo() === 30);
+});
+
+test(function() {
+    let x = 15;
+    assert(x === 15);
+    assert(a === undefined);
+    {
+        let x = {x: 20};
+        function a() { return x; }
+        assert(a() === x);
+        assert(a().x === 20);
+    }
+    assert(a().x === 20);
+    assert(x === 15);
+});
+
+test(function() {
+    let x = 15;
+    assert(x === 15);
+    assert(a === undefined);
+    let f;
+    {
+        let x = {x: 20};
+        assert(a() === x);
+        assert(a().x === 20);
+
+        function a() { throw new Error; }
+        function a() { return x; }
+        f = a;
+    }
+    assert(a().x === 20);
+    assert(x === 15);
+    assert(f().x === 20);
+});
+
+test(function() {
+    let x = 15;
+    let f;
+    assert(x === 15);
+    assert(a === undefined);
+    assert(f === undefined);
+    {
+        function a() { return f; }
+        f = a;
+    }
+    assert(x === 15);
+    assert(f() === f);
+});
+
+test(function() {
+    function a() { return 20; }
+    let f = a;
+    assert(a() === 20);
+    {
+        function a() { return 25; }
+        assert(a() === 25);
+    }
+    assert(f() === 20);
+    assert(a() === 25);
+});
+
+test(function() {
+    assert(f === undefined);
+    for (let i = 0; i &lt; 10; i++) {
+        function f() { return i; }
+        assert(f() === i);
+    }
+    assert(f() === 9);
+});
+
+test(function() {
+    assert(f === undefined);
+    let nums = [0, 1, 2, 3];
+    for (let i of nums) {
+        function f() { return i; }
+        assert(f() === i);
+    }
+    assert(f() === 3);
+});
+
+test(function() {
+    assert(f === undefined);
+    let obj = {0:0, 1:1, 2:2, 3:3};
+    for (let i in obj) {
+        function f() { return i; }
+        assert(f() === i);
+    }
+    assert(f() === &quot;3&quot;);
+});
+
+test(function() {
+    assert(f === undefined);
+    let nums = [0, 1, 2, 3];
+    let funcs = []
+    for (let i of nums) {
+        function f() { return i; }
+        funcs.push(f);
+        assert(f() === i);
+    }
+    assert(f() === 3);
+    assert(funcs.length === nums.length);
+    for (let i = 0; i &lt; funcs.length; i++) {
+        assert(funcs[i]() === nums[i]);
+    }
+});
+
+test(function() {
+    assert(f === undefined);
+    try {
+        throw new Error(&quot;foo&quot;);
+    } catch(e) {
+        function f() { return 20; }
+    }
+    assert(f() === 20);
+});
+
+test(function() {
+    assert(f === undefined);
+    try {
+        ;
+    } catch(e) {
+        function f() { return 20; }
+    }
+    assert(f === undefined);
+});
+
+test(function() {
+    assert(foo === undefined);
+    if (falsey()) {
+        function foo() { return 20; }
+    }
+    assert(foo === undefined);
+});
+
+test(function() {
+    assert(foo === undefined);
+    if (falsey())
+        function foo() { return 20; }
+    assert(foo === undefined);
+});
+
+test(function() {
+    assert(foo === undefined);
+    if (truthy()) {
+        function foo() { return 20; }
+    }
+    assert(foo() === 20);
+});
+
+test(function() {
+    assert(foo === undefined);
+    while (truthy()) {
+        break;
+
+        function foo() { return 20; }
+    }
+    assert(foo() === 20);
+});
+
+test(function() {
+    function bar() { return foo; }
+    assert(foo === undefined);
+    assert(bar() === undefined);
+    while (truthy()) {
+        break;
+
+        function foo() { return 20; }
+    }
+    assert(foo() === 20);
+    assert(bar()() === 20);
+});
+
+test(function() {
+    function bar() { return foo; }
+    assert(foo === undefined);
+    assert(bar() === undefined);
+    while (falsey()) {
+        function foo() { return 20; }
+    }
+    assert(foo === undefined);
+    assert(bar() === undefined);
+});
+
+test(function() {
+    var a = &quot;a&quot;;
+    assert(a === &quot;a&quot;);
+    {
+        let b = 1;
+        assert(a === &quot;a&quot;);
+        {
+            let c = 2;
+            assert(a === &quot;a&quot;);
+            {
+                let d = 3;
+                function a() { return b + c+ d; }
+                assert(a() === 6);
+            }
+            assert(a() === 6);
+        }
+        assert(a() === 6);
+    }
+    assert(a() === 6);
+});
+
+test(function() {
+    assert(foo === undefined);
+    switch(1) {
+    case 0:
+        function foo() { return 20; }
+        break;
+    }
+    assert(foo() === 20);
+});
+
+test(function() {
+    assert(foo === undefined);
+    switch(1) {
+    case 0:{
+        function foo() { return 20; }
+        break;
+    }
+    }
+    assert(foo === undefined);
+});
+
+test(function() {
+    assert(foo === undefined);
+    switch(0) {
+    case 0:{
+        function foo() { return 20; }
+        break;
+    }
+    }
+    assert(foo() === 20);
+});
+
+test(function() {
+    assert(foo === undefined);
+    switch(0) {
+    case 0:
+        function foo() { return bar; }
+        break;
+    case 1:
+        let bar = 20;
+        break;
+    }
+
+    let threw = false;
+    try {
+        foo();
+    } catch (e) {
+        assert(e instanceof ReferenceError);
+        threw = true;
+    }
+    assert(threw);
+});
+
+test(function() {
+    assert(foo === undefined);
+    switch(0) {
+    case 0:
+        function foo() { return bar; }
+    case 1:
+        let bar = 20;
+        break;
+    }
+
+    assert(foo() === 20);
+});
+
+test(function() {
+    assert(foo === undefined);
+    switch(1) {
+    case 0:
+        function foo() { return bar; }
+    case 1:
+        let bar = 20;
+        assert(foo() === 20);
+        break;
+    }
+
+    assert(foo() === 20);
+});
+
+test(function(a) {
+    assert(a === 25);
+    switch(1) {
+    case 0:
+        function a() { return bar; }
+    case 1:
+        let bar = 20;
+        assert(a() === 20);
+        break;
+    }
+
+    assert(a === 25);
+}, 25);
+
+test(function() {
+    let a = 25;
+    assert(a === 25);
+    switch(1) {
+    case 0:
+        function a() { return bar; }
+    case 1:
+        let bar = 20;
+        assert(a() === 20);
+        break;
+    }
+
+    assert(a === 25);
+});
+
+test(function() {
+    const a = 25;
+    assert(a === 25);
+    switch(1) {
+    case 0:
+        function a() { return bar; }
+    case 1:
+        let bar = 20;
+        assert(a() === 20);
+        break;
+    }
+
+    assert(a === 25);
+});
+
+test(function() {
+    let foo = {};
+    class a { constructor() { return foo; } }
+    assert(new a === foo);
+    switch(1) {
+    case 0:
+        function a() { return bar; }
+    case 1:
+        let bar = 20;
+        assert(a() === 20);
+        break;
+    }
+
+    assert(new a === foo);
+});
+
+test(function() {
+    assert(f === undefined);
+    {
+        if (true)
+            function f() { return 20; }
+        assert(f() === 20);
+    }
+    assert(f() === 20);
+});
+
+test(function() {
+    assert(f === undefined);
+    {
+        if (false)
+            function f() { return 20; }
+        assert(f === undefined);
+    }
+    assert(f === undefined);
+});
+
+test(function() {
+    var x;
+    assert(f === undefined);
+    if (true)
+        if (true)
+            if (true)
+                function f() { return 20; }
+    assert(f() === 20);
+});
+
+test(function() {
+    var x;
+    assert(f === undefined);
+    {
+        if (true)
+            if (false)
+                if (true)
+                    function f() { return 20; }
+    }
+    assert(f === undefined);
+});
+
+test(function() {
+    var x;
+    assert(f === undefined);
+    {
+        while (false)
+            while (false)
+                if (true)
+                    function f() { return 20; }
+    }
+    assert(f === undefined);
+});
+
+test(function() {
+    assert(f === undefined);
+    var f = 20;
+    assert(f === 20);
+    while (false)
+        while (false)
+            if (true)
+                function f() { return 20; }
+    assert(f === 20);
+});
+
+test(function() {
+    assert(f === undefined);
+    var f = 20;
+    assert(f === 20);
+    var i = 2;
+    {
+        while (i-- &gt; 0)
+            while (i-- &gt; 0)
+                if (true)
+                    function f() { return 20; }
+    }
+    assert(f() === 20);
+});
+
+test(function() {
+    assert(f === undefined);
+    var f = 20;
+    assert(f === 20);
+    var i = 2;
+    {
+        while (i-- &gt; 0)
+            while (i-- &gt; 0)
+                if (false)
+                    function f() { return 20; }
+    }
+    assert(f === 20);
+});
+
+test(function() {
+    assert(f === undefined);
+    var f = 20;
+    assert(f === 20);
+    var i = 2;
+    {
+        while (i-- &gt; 0)
+            while (i-- &gt; 0)
+                if (false)
+                    function f() { return 20; }
+                else
+                    function f() { return 30; }
+    }
+    assert(f() === 30);
+});
+
+test(function() {
+    assert(f === undefined);
+    if (true) {
+        label: function f() { return 20; }
+    }
+    assert(f() === 20);
+});
+
+test(function() {
+    assert(f === undefined);
+    if (true) {
+        label: label2: label3: function f() { return 20; }
+    }
+    assert(f() === 20);
+});
+
+test(function() {
+    assert(a === undefined);
+    assert(b === undefined);
+    assert(c === undefined);
+    assert(d === undefined);
+    assert(e === undefined);
+    assert(f === undefined);
+    assert(g === undefined);
+    assert(h === undefined);
+    assert(i === undefined);
+    assert(j === undefined);
+    assert(k === undefined);
+    assert(l === undefined);
+    assert(m === undefined);
+    assert(n === undefined);
+    assert(o === undefined);
+    assert(p === undefined);
+    assert(q === undefined);
+    assert(r === undefined);
+    assert(s === undefined);
+    assert(t === undefined);
+    assert(u === undefined);
+    assert(v === undefined);
+    assert(w === undefined);
+    assert(x === undefined);
+    assert(y === undefined);
+    assert(z === undefined);
+    {
+        function a() { } 
+        function b() { } 
+        function c() { } 
+        function d() { } 
+        function e() { } 
+        function f() { } 
+        function g() { } 
+        function h() { } 
+        function i() { } 
+        function j() { } 
+        function k() { } 
+        function l() { } 
+        function m() { } 
+        function n() { } 
+        function o() { } 
+        function p() { } 
+        function q() { } 
+        function r() { } 
+        function s() { } 
+        function t() { } 
+        function u() { } 
+        function v() { } 
+        function w() { } 
+        function x() { } 
+        function y() { } 
+        function z() { } 
+    }
+    assert(typeof a === &quot;function&quot;);
+    assert(typeof b === &quot;function&quot;);
+    assert(typeof c === &quot;function&quot;);
+    assert(typeof d === &quot;function&quot;);
+    assert(typeof e === &quot;function&quot;);
+    assert(typeof f === &quot;function&quot;);
+    assert(typeof g === &quot;function&quot;);
+    assert(typeof h === &quot;function&quot;);
+    assert(typeof i === &quot;function&quot;);
+    assert(typeof j === &quot;function&quot;);
+    assert(typeof k === &quot;function&quot;);
+    assert(typeof l === &quot;function&quot;);
+    assert(typeof m === &quot;function&quot;);
+    assert(typeof n === &quot;function&quot;);
+    assert(typeof o === &quot;function&quot;);
+    assert(typeof p === &quot;function&quot;);
+    assert(typeof q === &quot;function&quot;);
+    assert(typeof r === &quot;function&quot;);
+    assert(typeof s === &quot;function&quot;);
+    assert(typeof t === &quot;function&quot;);
+    assert(typeof u === &quot;function&quot;);
+    assert(typeof v === &quot;function&quot;);
+    assert(typeof w === &quot;function&quot;);
+    assert(typeof x === &quot;function&quot;);
+    assert(typeof y === &quot;function&quot;);
+    assert(typeof z === &quot;function&quot;);
+});
+
+for (let i = 0; i &lt; 500; i++)
+    assert(foo() === 25);
+function foo() { return 20; }
+
+{
+    function foo() { return 25; }
+    assert(foo() === 25);
+}
+assert(foo() === 25);
+
+for (let i = 0; i &lt; 500; i++)
+    assert(bar() === &quot;bar2&quot;);
+function bar() { return &quot;bar1&quot;; }
+if (falsey()) {
+    {
+        if (falsey()) {
+            function bar() { return &quot;bar2&quot;; }
+        }
+    }
+}
+assert(bar() === &quot;bar2&quot;);
+
+for (let i = 0; i &lt; 500; i++)
+    assert(baz() === &quot;baz2&quot;);
+function baz() { return &quot;baz1&quot;; }
+while (falsey()) {
+    if (falsey()) {
+        function baz() { return &quot;baz2&quot;; }
+    }
+}
+assert(baz() === &quot;baz2&quot;);
</ins></span></pre>
</div>
</div>

</body>
</html>