<!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>[204842] 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/204842">204842</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2016-08-23 11:14:30 -0700 (Tue, 23 Aug 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>[ES6] Modules' `export default function/class` should be declaration
https://bugs.webkit.org/show_bug.cgi?id=160499
Reviewed by Saam Barati.
JSTests:
Add several module tests. And flip the failed tests flags in test262.
* modules/export-default-function-name-in-assignment-expression.js: Added.
(export.default):
* modules/export-default-function-name-in-class-declaration.js: Added.
* modules/export-default-function-name-in-function-declaration.js: Added.
(export.default):
* modules/export-default-function-name-in-generator-declaration.js: Added.
(export.default):
* stress/method-name.js: Added.
(testSyntax):
(testSyntaxError):
(testSyntaxError.Hello.prototype.hello.hello):
(testSyntaxError.Hello):
(SyntaxError.Unexpected.identifier.string_appeared_here.Expected.an.opening.string_appeared_here.before.a.method.testSyntaxError.let.obj.hello.hello):
(testSyntaxError.Hello.prototype.get hello):
(testSyntaxError.Hello.prototype.set hello):
* test262.yaml:
Source/JavaScriptCore:
Previously, we parsed the following cases as FunctionExpression and ClassExpression.
```
export default function () { }
export default class { }
```
But, as per ES6 spec, the above `function ...` and `class ...` parts should be parsed
as function declaration and class declaration. This has big difference; the instantiation
of the function declarations are done in the function prologue.
In this patch, we correctly parse the above cases as declaration. To handle no-named
declarations, we add a new flag, DeclarationDefaultContext. This indicates [Default]
flag in the ES6 spec's BNF.
Furthermore, this patch also fixes the following name related bugs.
1. The bug related to "export default"'s function name. If the name is not provided (like the above case), the name of the function becomes
"default", not "*default*". This is special handling in ES6 spec. We handle this in JSFunction's reifyName.
2. `class Hello { hello hello() { } }` is accepted. We introduced FunctionRequirements::Unnamed and fix this bug.
* parser/ModuleScopeData.h:
(JSC::ModuleScopeData::exportBinding):
Exported names are already guranteed uniqueness by m_exportedNames. Not necessary to use set here. Use vector instead.
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionInfo):
If we pass FunctionRequirements::NoRequirements, we need to initialize functionInfo.name / classInfo.className
with the default fallback name. For example, in the above `export default` case, we initialize it with `*default*`.
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClassDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseExportDeclaration):
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parseClassExpression):
(JSC::Parser<LexerType>::parseFunctionExpression):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseArrowFunctionExpression):
* parser/Parser.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::reifyName):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTeststest262yaml">trunk/JSTests/test262.yaml</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorJSInjectedScriptHostcpp">trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserModuleScopeDatah">trunk/Source/JavaScriptCore/parser/ModuleScopeData.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="#trunkSourceJavaScriptCoreruntimeFunctionPrototypecpp">trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSFunctioncpp">trunk/Source/JavaScriptCore/runtime/JSFunction.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSFunctionh">trunk/Source/JavaScriptCore/runtime/JSFunction.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeLazyClassStructurecpp">trunk/Source/JavaScriptCore/runtime/LazyClassStructure.cpp</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsmodulesexportdefaultfunctionnameinassignmentexpressionjs">trunk/JSTests/modules/export-default-function-name-in-assignment-expression.js</a></li>
<li><a href="#trunkJSTestsmodulesexportdefaultfunctionnameinclassdeclarationjs">trunk/JSTests/modules/export-default-function-name-in-class-declaration.js</a></li>
<li><a href="#trunkJSTestsmodulesexportdefaultfunctionnameinfunctiondeclarationjs">trunk/JSTests/modules/export-default-function-name-in-function-declaration.js</a></li>
<li><a href="#trunkJSTestsmodulesexportdefaultfunctionnameingeneratordeclarationjs">trunk/JSTests/modules/export-default-function-name-in-generator-declaration.js</a></li>
<li><a href="#trunkJSTestsstressmethodnamejs">trunk/JSTests/stress/method-name.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/JSTests/ChangeLog        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -1,5 +1,31 @@
</span><span class="cx"> 2016-08-22 Yusuke Suzuki <utatane.tea@gmail.com>
</span><span class="cx">
</span><ins>+ [ES6] Modules' `export default function/class` should be declaration
+ https://bugs.webkit.org/show_bug.cgi?id=160499
+
+ Reviewed by Saam Barati.
+
+ Add several module tests. And flip the failed tests flags in test262.
+
+ * modules/export-default-function-name-in-assignment-expression.js: Added.
+ (export.default):
+ * modules/export-default-function-name-in-class-declaration.js: Added.
+ * modules/export-default-function-name-in-function-declaration.js: Added.
+ (export.default):
+ * modules/export-default-function-name-in-generator-declaration.js: Added.
+ (export.default):
+ * stress/method-name.js: Added.
+ (testSyntax):
+ (testSyntaxError):
+ (testSyntaxError.Hello.prototype.hello.hello):
+ (testSyntaxError.Hello):
+ (SyntaxError.Unexpected.identifier.string_appeared_here.Expected.an.opening.string_appeared_here.before.a.method.testSyntaxError.let.obj.hello.hello):
+ (testSyntaxError.Hello.prototype.get hello):
+ (testSyntaxError.Hello.prototype.set hello):
+ * test262.yaml:
+
+2016-08-22 Yusuke Suzuki <utatane.tea@gmail.com>
+
</ins><span class="cx"> [ES6] Module should not allow HTML comments
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=161041
</span><span class="cx">
</span></span></pre></div>
<a id="trunkJSTestsmodulesexportdefaultfunctionnameinassignmentexpressionjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/export-default-function-name-in-assignment-expression.js (0 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/export-default-function-name-in-assignment-expression.js         (rev 0)
+++ trunk/JSTests/modules/export-default-function-name-in-assignment-expression.js        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+import func from "./export-default-function-name-in-assignment-expression.js"
+import { shouldBe } from "./resources/assert.js";
+
+export default (function () { });
+
+// https://tc39.github.io/ecma262/#sec-exports-runtime-semantics-evaluation
+shouldBe(func.name, 'default');
+shouldBe(func.toString(), `function () { }`);
</ins></span></pre></div>
<a id="trunkJSTestsmodulesexportdefaultfunctionnameinclassdeclarationjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/export-default-function-name-in-class-declaration.js (0 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/export-default-function-name-in-class-declaration.js         (rev 0)
+++ trunk/JSTests/modules/export-default-function-name-in-class-declaration.js        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+import cls from "./export-default-function-name-in-class-declaration.js"
+import { shouldBe } from "./resources/assert.js";
+
+export default class { }
+
+// https://tc39.github.io/ecma262/#sec-exports-runtime-semantics-evaluation
+shouldBe(cls.name, 'default');
+shouldBe(cls.toString(), `class { }`);
</ins></span></pre></div>
<a id="trunkJSTestsmodulesexportdefaultfunctionnameinfunctiondeclarationjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/export-default-function-name-in-function-declaration.js (0 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/export-default-function-name-in-function-declaration.js         (rev 0)
+++ trunk/JSTests/modules/export-default-function-name-in-function-declaration.js        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+import func from "./export-default-function-name-in-function-declaration.js"
+import { shouldBe } from "./resources/assert.js";
+
+export default function () { }
+
+// https://tc39.github.io/ecma262/#sec-exports-runtime-semantics-evaluation
+shouldBe(func.name, 'default');
+shouldBe(func.toString(), `function () { }`);
</ins></span></pre></div>
<a id="trunkJSTestsmodulesexportdefaultfunctionnameingeneratordeclarationjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/export-default-function-name-in-generator-declaration.js (0 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/export-default-function-name-in-generator-declaration.js         (rev 0)
+++ trunk/JSTests/modules/export-default-function-name-in-generator-declaration.js        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+import func from "./export-default-function-name-in-generator-declaration.js"
+import { shouldBe } from "./resources/assert.js";
+
+export default function * () { }
+
+// https://tc39.github.io/ecma262/#sec-exports-runtime-semantics-evaluation
+shouldBe(func.name, 'default');
+// shouldBe(func.toString(), `function * () { }`);
</ins></span></pre></div>
<a id="trunkJSTestsstressmethodnamejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/method-name.js (0 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/method-name.js         (rev 0)
+++ trunk/JSTests/stress/method-name.js        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+function testSyntax(script) {
+ try {
+ eval(script);
+ } catch (error) {
+ if (error instanceof SyntaxError)
+ throw new Error("Bad error: " + String(error));
+ }
+}
+
+function testSyntaxError(script, message) {
+ var error = null;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+ if (!error)
+ throw new Error("Expected syntax error not thrown");
+
+ if (String(error) !== message)
+ throw new Error("Bad error: " + String(error));
+}
+
+testSyntaxError(`
+class Hello {
+ hello hello() { }
+}
+`, `SyntaxError: Unexpected identifier 'hello'. Expected an opening '(' before a method's parameter list.`);
+
+testSyntaxError(`
+let obj = {
+ hello hello() { }
+}
+`, `SyntaxError: Unexpected identifier 'hello'. Expected a ':' following the property name 'hello'.`);
+
+testSyntaxError(`
+class Hello {
+ get hello hello() { }
+}
+`, `SyntaxError: Unexpected identifier 'hello'. Expected a parameter list for getter definition.`);
+
+testSyntaxError(`
+class Hello {
+ set hello hello(v) { }
+}
+`, `SyntaxError: Unexpected identifier 'hello'. Expected a parameter list for setter definition.`);
</ins></span></pre></div>
<a id="trunkJSTeststest262yaml"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/test262.yaml (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/test262.yaml        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/JSTests/test262.yaml        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -70868,7 +70868,7 @@
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-cls-anon-semi.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-cls-anon.js
</span><del>- cmd: runTest262 :fail, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-cls-name-meth.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-cls-named-semi.js
</span><span class="lines">@@ -70876,7 +70876,7 @@
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-cls-named.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-cls-anon.js
</span><del>- cmd: runTest262 :fail, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-cls-name-meth.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-cls-named.js
</span><span class="lines">@@ -70886,11 +70886,11 @@
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-err-get-value.js
</span><span class="cx"> cmd: runTest262 :normal, "ReferenceError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-fn-anon.js
</span><del>- cmd: runTest262 :fail, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-fn-named.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-gen-anon.js
</span><del>- cmd: runTest262 :fail, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-gen-named.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/eval-export-dflt-expr-in.js
</span><span class="lines">@@ -71072,11 +71072,11 @@
</span><span class="cx"> - path: test262/test/language/module-code/instn-named-bndng-dflt-expr.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/instn-named-bndng-dflt-fun-anon.js
</span><del>- cmd: runTest262 :fail, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/instn-named-bndng-dflt-fun-named.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/instn-named-bndng-dflt-gen-anon.js
</span><del>- cmd: runTest262 :fail, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/instn-named-bndng-dflt-gen-named.js
</span><span class="cx"> cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/instn-named-bndng-dflt-named.js
</span><span class="lines">@@ -71504,9 +71504,9 @@
</span><span class="cx"> - path: test262/test/language/module-code/parse-err-hoist-lex-gen.js
</span><span class="cx"> cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/parse-err-invoke-anon-fun-decl.js
</span><del>- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/parse-err-invoke-anon-gen-decl.js
</span><del>- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</del><ins>+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</ins><span class="cx"> - path: test262/test/language/module-code/parse-err-reference.js
</span><span class="cx"> cmd: runTest262 :normal, "ReferenceError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
</span><span class="cx"> - path: test262/test/language/module-code/parse-err-semi-dflt-expr.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2016-08-22 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [ES6] Modules' `export default function/class` should be declaration
+ https://bugs.webkit.org/show_bug.cgi?id=160499
+
+ Reviewed by Saam Barati.
+
+ Previously, we parsed the following cases as FunctionExpression and ClassExpression.
+
+ ```
+ export default function () { }
+ export default class { }
+ ```
+
+ But, as per ES6 spec, the above `function ...` and `class ...` parts should be parsed
+ as function declaration and class declaration. This has big difference; the instantiation
+ of the function declarations are done in the function prologue.
+
+ In this patch, we correctly parse the above cases as declaration. To handle no-named
+ declarations, we add a new flag, DeclarationDefaultContext. This indicates [Default]
+ flag in the ES6 spec's BNF.
+
+ Furthermore, this patch also fixes the following name related bugs.
+
+ 1. The bug related to "export default"'s function name. If the name is not provided (like the above case), the name of the function becomes
+ "default", not "*default*". This is special handling in ES6 spec. We handle this in JSFunction's reifyName.
+
+ 2. `class Hello { hello hello() { } }` is accepted. We introduced FunctionRequirements::Unnamed and fix this bug.
+
+ * parser/ModuleScopeData.h:
+ (JSC::ModuleScopeData::exportBinding):
+ Exported names are already guranteed uniqueness by m_exportedNames. Not necessary to use set here. Use vector instead.
+
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseFunctionInfo):
+ If we pass FunctionRequirements::NoRequirements, we need to initialize functionInfo.name / classInfo.className
+ with the default fallback name. For example, in the above `export default` case, we initialize it with `*default*`.
+
+ (JSC::Parser<LexerType>::parseFunctionDeclaration):
+ (JSC::Parser<LexerType>::parseClassDeclaration):
+ (JSC::Parser<LexerType>::parseClass):
+ (JSC::Parser<LexerType>::parseExportDeclaration):
+ (JSC::Parser<LexerType>::parsePropertyMethod):
+ (JSC::Parser<LexerType>::parseGetterSetter):
+ (JSC::Parser<LexerType>::parseClassExpression):
+ (JSC::Parser<LexerType>::parseFunctionExpression):
+ (JSC::Parser<LexerType>::parsePrimaryExpression):
+ (JSC::Parser<LexerType>::parseArrowFunctionExpression):
+ * parser/Parser.h:
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::reifyName):
+
</ins><span class="cx"> 2016-08-23 Saam Barati <sbarati@apple.com>
</span><span class="cx">
</span><span class="cx"> JIT::updateTopCallframe() in the baseline JIT should use PC instead of PC+1
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorJSInjectedScriptHostcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -228,7 +228,7 @@
</span><span class="cx"> JSObject* result = constructEmptyObject(exec);
</span><span class="cx"> result->putDirect(vm, Identifier::fromString(exec, "location"), location);
</span><span class="cx">
</span><del>- String name = function->name();
</del><ins>+ String name = function->name(vm);
</ins><span class="cx"> if (!name.isEmpty())
</span><span class="cx"> result->putDirect(vm, Identifier::fromString(exec, "name"), jsString(exec, name));
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserModuleScopeDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ModuleScopeData.h (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ModuleScopeData.h        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/parser/ModuleScopeData.h        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> WTF_MAKE_NONCOPYABLE(ModuleScopeData);
</span><span class="cx"> WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><del>- typedef HashMap<RefPtr<UniquedStringImpl>, IdentifierSet, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> IdentifierAliasMap;
</del><ins>+ typedef HashMap<RefPtr<UniquedStringImpl>, Vector<RefPtr<UniquedStringImpl>>, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> IdentifierAliasMap;
</ins><span class="cx">
</span><span class="cx"> static Ref<ModuleScopeData> create() { return adoptRef(*new ModuleScopeData); }
</span><span class="cx">
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx">
</span><span class="cx"> void exportBinding(const Identifier& localName, const Identifier& exportedName)
</span><span class="cx"> {
</span><del>- m_exportedBindings.add(localName.impl(), IdentifierSet()).iterator->value.add(exportedName.impl());
</del><ins>+ m_exportedBindings.add(localName.impl(), Vector<RefPtr<UniquedStringImpl>>()).iterator->value.append(exportedName.impl());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void exportBinding(const Identifier& localName)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -1930,7 +1930,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><del>-template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionDefinitionType functionDefinitionType)
</del><ins>+template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionNameRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionDefinitionType functionDefinitionType)
</ins><span class="cx"> {
</span><span class="cx"> RELEASE_ASSERT(isFunctionParseMode(mode));
</span><span class="cx">
</span><span class="lines">@@ -2072,18 +2072,22 @@
</span><span class="cx"> if (functionDefinitionType == FunctionDefinitionType::Expression && mode == SourceParseMode::NormalFunctionMode)
</span><span class="cx"> upperScopeIsGenerator = false;
</span><span class="cx">
</span><del>- if (matchSpecIdentifier(upperScopeIsGenerator)) {
- functionInfo.name = m_token.m_data.ident;
- m_parserState.lastFunctionName = functionInfo.name;
- next();
- if (!nameIsInContainingScope)
- failIfTrueIfStrict(functionScope->declareCallee(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
- } else if (requirements == FunctionNeedsName) {
- if (match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode)
- semanticFail("Function statements must have a name");
- semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
- failDueToUnexpectedToken();
- return false;
</del><ins>+ if (requirements != FunctionNameRequirements::Unnamed) {
+ ASSERT_WITH_MESSAGE(!(requirements == FunctionNameRequirements::None && !functionInfo.name), "When specifying FunctionNameRequirements::None, we need to initialize functionInfo.name with the default value in the caller side.");
+ if (matchSpecIdentifier(upperScopeIsGenerator)) {
+ functionInfo.name = m_token.m_data.ident;
+ m_parserState.lastFunctionName = functionInfo.name;
+ next();
+ if (!nameIsInContainingScope)
+ failIfTrueIfStrict(functionScope->declareCallee(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
+ } else if (requirements == FunctionNameRequirements::Named) {
+ if (match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode)
+ semanticFail("Function statements must have a name");
+ semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
+ failDueToUnexpectedToken();
+ return false;
+ }
+ ASSERT(functionInfo.name);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> startLocation = tokenLocation();
</span><span class="lines">@@ -2163,7 +2167,8 @@
</span><span class="cx"> restoreParserState(oldState);
</span><span class="cx"> failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
</span><span class="cx"> context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
</span><del>- if (functionScope->strictMode() && functionInfo.name) {
</del><ins>+ if (functionScope->strictMode() && requirements != FunctionNameRequirements::Unnamed) {
+ ASSERT(functionInfo.name);
</ins><span class="cx"> RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode);
</span><span class="cx"> semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
</span><span class="cx"> semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
</span><span class="lines">@@ -2221,19 +2226,46 @@
</span><span class="cx"> static FunctionMetadataNode* getMetadata(ParserFunctionInfo<ASTBuilder>& info) { return info.body; }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><del>-template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType)
</del><ins>+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(match(FUNCTION));
</span><span class="cx"> JSTokenLocation location(tokenLocation());
</span><span class="cx"> unsigned functionKeywordStart = tokenStart();
</span><span class="cx"> next();
</span><del>- ParserFunctionInfo<TreeBuilder> functionInfo;
</del><span class="cx"> SourceParseMode parseMode = SourceParseMode::NormalFunctionMode;
</span><span class="cx"> if (consume(TIMES))
</span><span class="cx"> parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNeedsName, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
- failIfFalse(functionInfo.name, "Function statements must have a name");
</del><span class="cx">
</span><ins>+ ParserFunctionInfo<TreeBuilder> functionInfo;
+ FunctionNameRequirements requirements = FunctionNameRequirements::Named;
+ if (declarationDefaultContext == DeclarationDefaultContext::ExportDefault) {
+ // Under the "export default" context, function declaration does not require the function name.
+ //
+ // ExportDeclaration:
+ // ...
+ // export default HoistableDeclaration[~Yield, +Default]
+ // ...
+ //
+ // HoistableDeclaration[Yield, Default]:
+ // FunctionDeclaration[?Yield, ?Default]
+ // GeneratorDeclaration[?Yield, ?Default]
+ //
+ // FunctionDeclaration[Yield, Default]:
+ // ...
+ // [+Default] function ( FormalParameters[~Yield] ) { FunctionBody[~Yield] }
+ //
+ // GeneratorDeclaration[Yield, Default]:
+ // ...
+ // [+Default] function * ( FormalParameters[+Yield] ) { GeneratorBody }
+ //
+ // In this case, we use "*default*" as this function declaration's name.
+ requirements = FunctionNameRequirements::None;
+ functionInfo.name = &m_vm->propertyNames->builtinNames().starDefaultPrivateName();
+ }
+
+ failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
+ ASSERT(functionInfo.name);
+
</ins><span class="cx"> std::pair<DeclarationResultMask, ScopeRef> functionDeclaration = declareFunction(functionInfo.name);
</span><span class="cx"> DeclarationResultMask declarationResult = functionDeclaration.first;
</span><span class="cx"> failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
</span><span class="lines">@@ -2240,6 +2272,7 @@
</span><span class="cx"> if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
</span><span class="cx"> internalFailWithMessage(false, "Cannot declare a function that shadows a let/const/class/function variable '", functionInfo.name->impl(), "' in strict mode");
</span><span class="cx"> if (exportType == ExportType::Exported) {
</span><ins>+ ASSERT_WITH_MESSAGE(declarationDefaultContext != DeclarationDefaultContext::ExportDefault, "Export default case will export the name and binding in the caller.");
</ins><span class="cx"> semanticFailIfFalse(exportName(*functionInfo.name), "Cannot export a duplicate function name: '", functionInfo.name->impl(), "'");
</span><span class="cx"> m_moduleScopeData->exportBinding(*functionInfo.name);
</span><span class="cx"> }
</span><span class="lines">@@ -2251,7 +2284,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><del>-template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context, ExportType exportType)
</del><ins>+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(match(CLASSTOKEN));
</span><span class="cx"> JSTokenLocation location(tokenLocation());
</span><span class="lines">@@ -2259,13 +2292,33 @@
</span><span class="cx"> unsigned classStartLine = tokenLine();
</span><span class="cx">
</span><span class="cx"> ParserClassInfo<TreeBuilder> info;
</span><del>- TreeClassExpression classExpr = parseClass(context, FunctionNeedsName, info);
</del><ins>+ FunctionNameRequirements requirements = FunctionNameRequirements::Named;
+ if (declarationDefaultContext == DeclarationDefaultContext::ExportDefault) {
+ // Under the "export default" context, class declaration does not require the class name.
+ //
+ // ExportDeclaration:
+ // ...
+ // export default ClassDeclaration[~Yield, +Default]
+ // ...
+ //
+ // ClassDeclaration[Yield, Default]:
+ // ...
+ // [+Default] class ClassTail[?Yield]
+ //
+ // In this case, we use "*default*" as this class declaration's name.
+ requirements = FunctionNameRequirements::None;
+ info.className = &m_vm->propertyNames->builtinNames().starDefaultPrivateName();
+ }
+
+ TreeClassExpression classExpr = parseClass(context, requirements, info);
</ins><span class="cx"> failIfFalse(classExpr, "Failed to parse class");
</span><ins>+ ASSERT(info.className);
</ins><span class="cx">
</span><span class="cx"> DeclarationResultMask declarationResult = declareVariable(info.className, DeclarationType::LetDeclaration);
</span><span class="cx"> if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
</span><span class="cx"> internalFailWithMessage(false, "Cannot declare a class twice: '", info.className->impl(), "'");
</span><span class="cx"> if (exportType == ExportType::Exported) {
</span><ins>+ ASSERT_WITH_MESSAGE(declarationDefaultContext != DeclarationDefaultContext::ExportDefault, "Export default case will export the name and binding in the caller.");
</ins><span class="cx"> semanticFailIfFalse(exportName(*info.className), "Cannot export a duplicate class name: '", info.className->impl(), "'");
</span><span class="cx"> m_moduleScopeData->exportBinding(*info.className);
</span><span class="cx"> }
</span><span class="lines">@@ -2277,7 +2330,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><del>-template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(TreeBuilder& context, FunctionRequirements requirements, ParserClassInfo<TreeBuilder>& info)
</del><ins>+template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(TreeBuilder& context, FunctionNameRequirements requirements, ParserClassInfo<TreeBuilder>& info)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(match(CLASSTOKEN));
</span><span class="cx"> JSTokenLocation location(tokenLocation());
</span><span class="lines">@@ -2291,20 +2344,19 @@
</span><span class="cx"> classScope->preventVarDeclarations();
</span><span class="cx"> classScope->setStrictMode();
</span><span class="cx">
</span><del>- const Identifier* className = nullptr;
</del><ins>+ ASSERT_WITH_MESSAGE(requirements != FunctionNameRequirements::Unnamed, "Currently, there is no caller that uses FunctionNameRequirements::Unnamed for class syntax.");
+ ASSERT_WITH_MESSAGE(!(requirements == FunctionNameRequirements::None && !info.className), "When specifying FunctionNameRequirements::None, we need to initialize info.className with the default value in the caller side.");
</ins><span class="cx"> if (match(IDENT)) {
</span><del>- className = m_token.m_data.ident;
</del><ins>+ info.className = m_token.m_data.ident;
</ins><span class="cx"> next();
</span><del>- failIfTrue(classScope->declareLexicalVariable(className, true) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
- } else if (requirements == FunctionNeedsName) {
</del><ins>+ failIfTrue(classScope->declareLexicalVariable(info.className, true) & DeclarationResult::InvalidStrictMode, "'", info.className->impl(), "' is not a valid class name");
+ } else if (requirements == FunctionNameRequirements::Named) {
</ins><span class="cx"> if (match(OPENBRACE))
</span><span class="cx"> semanticFail("Class statements must have a name");
</span><span class="cx"> semanticFailureDueToKeyword("class name");
</span><span class="cx"> failDueToUnexpectedToken();
</span><del>- } else
- className = &m_vm->propertyNames->nullIdentifier;
- ASSERT(className);
- info.className = className;
</del><ins>+ }
+ ASSERT(info.className);
</ins><span class="cx">
</span><span class="cx"> TreeExpression parentClass = 0;
</span><span class="cx"> if (consume(EXTENDS)) {
</span><span class="lines">@@ -2401,8 +2453,8 @@
</span><span class="cx"> semanticFailIfTrue(*ident == m_vm->propertyNames->prototype, "Cannot declare a generator named 'prototype'");
</span><span class="cx"> semanticFailIfTrue(*ident == m_vm->propertyNames->constructor, "Cannot declare a generator named 'constructor'");
</span><span class="cx"> }
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
- methodInfo.name = isConstructor ? className : ident;
</del><ins>+ methodInfo.name = isConstructor ? info.className : ident;
+ failIfFalse((parseFunctionInfo(context, FunctionNameRequirements::Unnamed, parseMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
</ins><span class="cx">
</span><span class="cx"> TreeExpression method = context.createMethodDefinition(methodLocation, methodInfo);
</span><span class="cx"> if (isConstructor) {
</span><span class="lines">@@ -2856,10 +2908,10 @@
</span><span class="cx"> TreeStatement result = 0;
</span><span class="cx"> bool isFunctionOrClassDeclaration = false;
</span><span class="cx"> const Identifier* localName = nullptr;
</span><del>- SavePoint savePoint = createSavePoint();
</del><span class="cx">
</span><span class="cx"> bool startsWithFunction = match(FUNCTION);
</span><span class="cx"> if (startsWithFunction || match(CLASSTOKEN)) {
</span><ins>+ SavePoint savePoint = createSavePoint();
</ins><span class="cx"> isFunctionOrClassDeclaration = true;
</span><span class="cx"> next();
</span><span class="cx">
</span><span class="lines">@@ -2871,14 +2923,18 @@
</span><span class="cx"> restoreSavePoint(savePoint);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (localName) {
- if (match(FUNCTION)) {
</del><ins>+ if (!localName)
+ localName = &m_vm->propertyNames->builtinNames().starDefaultPrivateName();
+
+ if (isFunctionOrClassDeclaration) {
+ if (startsWithFunction) {
+ ASSERT(match(FUNCTION));
</ins><span class="cx"> DepthManager statementDepth(&m_statementDepth);
</span><span class="cx"> m_statementDepth = 1;
</span><del>- result = parseFunctionDeclaration(context);
</del><ins>+ result = parseFunctionDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::ExportDefault);
</ins><span class="cx"> } else {
</span><span class="cx"> ASSERT(match(CLASSTOKEN));
</span><del>- result = parseClassDeclaration(context);
</del><ins>+ result = parseClassDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::ExportDefault);
</ins><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> // export default expr;
</span><span class="lines">@@ -2901,9 +2957,7 @@
</span><span class="cx">
</span><span class="cx"> TreeExpression assignment = context.createAssignResolve(location, m_vm->propertyNames->builtinNames().starDefaultPrivateName(), expression, start, start, tokenEndPosition(), AssignmentContext::ConstDeclarationStatement);
</span><span class="cx"> result = context.createExprStatement(location, assignment, start, tokenEndPosition());
</span><del>- if (!isFunctionOrClassDeclaration)
- failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
- localName = &m_vm->propertyNames->builtinNames().starDefaultPrivateName();
</del><ins>+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
</ins><span class="cx"> }
</span><span class="cx"> failIfFalse(result, "Cannot parse the declaration");
</span><span class="cx">
</span><span class="lines">@@ -3429,9 +3483,9 @@
</span><span class="cx"> JSTokenLocation methodLocation(tokenLocation());
</span><span class="cx"> unsigned methodStart = tokenStart();
</span><span class="cx"> ParserFunctionInfo<TreeBuilder> methodInfo;
</span><ins>+ methodInfo.name = methodName;
</ins><span class="cx"> SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorWrapperFunctionMode : SourceParseMode::MethodMode;
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
- methodInfo.name = methodName;
</del><ins>+ failIfFalse((parseFunctionInfo(context, FunctionNameRequirements::Unnamed, parseMode, false, ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
</ins><span class="cx"> return context.createMethodDefinition(methodLocation, methodInfo);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3466,10 +3520,10 @@
</span><span class="cx"> ParserFunctionInfo<TreeBuilder> info;
</span><span class="cx"> if (type & PropertyNode::Getter) {
</span><span class="cx"> failIfFalse(match(OPENPAREN), "Expected a parameter list for getter definition");
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::GetterMode, false, constructorKind, SuperBinding::Needed, getterOrSetterStartOffset, info, FunctionDefinitionType::Method)), "Cannot parse getter definition");
</del><ins>+ failIfFalse((parseFunctionInfo(context, FunctionNameRequirements::Unnamed, SourceParseMode::GetterMode, false, constructorKind, SuperBinding::Needed, getterOrSetterStartOffset, info, FunctionDefinitionType::Method)), "Cannot parse getter definition");
</ins><span class="cx"> } else {
</span><span class="cx"> failIfFalse(match(OPENPAREN), "Expected a parameter list for setter definition");
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::SetterMode, false, constructorKind, SuperBinding::Needed, getterOrSetterStartOffset, info, FunctionDefinitionType::Method)), "Cannot parse setter definition");
</del><ins>+ failIfFalse((parseFunctionInfo(context, FunctionNameRequirements::Unnamed, SourceParseMode::SetterMode, false, constructorKind, SuperBinding::Needed, getterOrSetterStartOffset, info, FunctionDefinitionType::Method)), "Cannot parse setter definition");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (stringPropertyName)
</span><span class="lines">@@ -3671,6 +3725,15 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template <typename LexerType>
</span><ins>+template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClassExpression(TreeBuilder& context)
+{
+ ASSERT(match(CLASSTOKEN));
+ ParserClassInfo<TreeBuilder> info;
+ info.className = &m_vm->propertyNames->nullIdentifier;
+ return parseClass(context, FunctionNameRequirements::None, info);
+}
+
+template <typename LexerType>
</ins><span class="cx"> template <class TreeBuilder> TreeExpression Parser<LexerType>::parseFunctionExpression(TreeBuilder& context)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(match(FUNCTION));
</span><span class="lines">@@ -3682,7 +3745,7 @@
</span><span class="cx"> SourceParseMode parseMode = SourceParseMode::NormalFunctionMode;
</span><span class="cx"> if (consume(TIMES))
</span><span class="cx"> parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Expression)), "Cannot parse function expression");
</del><ins>+ failIfFalse((parseFunctionInfo(context, FunctionNameRequirements::None, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Expression)), "Cannot parse function expression");
</ins><span class="cx"> return context.createFunctionExpr(location, functionInfo);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3751,10 +3814,8 @@
</span><span class="cx"> switch (m_token.m_type) {
</span><span class="cx"> case FUNCTION:
</span><span class="cx"> return parseFunctionExpression(context);
</span><del>- case CLASSTOKEN: {
- ParserClassInfo<TreeBuilder> info;
- return parseClass(context, FunctionNoRequirements, info);
- }
</del><ins>+ case CLASSTOKEN:
+ return parseClassExpression(context);
</ins><span class="cx"> case OPENBRACE:
</span><span class="cx"> if (strictMode())
</span><span class="cx"> return parseStrictObjectLiteral(context);
</span><span class="lines">@@ -4078,7 +4139,7 @@
</span><span class="cx"> location = tokenLocation();
</span><span class="cx"> ParserFunctionInfo<TreeBuilder> info;
</span><span class="cx"> info.name = &m_vm->propertyNames->nullIdentifier;
</span><del>- failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::ArrowFunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, FunctionDefinitionType::Expression)), "Cannot parse arrow function expression");
</del><ins>+ failIfFalse((parseFunctionInfo(context, FunctionNameRequirements::Unnamed, SourceParseMode::ArrowFunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, FunctionDefinitionType::Expression)), "Cannot parse arrow function expression");
</ins><span class="cx">
</span><span class="cx"> return context.createArrowFunctionExpr(location, info);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.h (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.h        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/parser/Parser.h        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx">
</span><span class="cx"> enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
</span><span class="cx"> enum FunctionBodyType { ArrowFunctionBodyExpression, ArrowFunctionBodyBlock, StandardFunctionBodyBlock };
</span><del>-enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
</del><ins>+enum class FunctionNameRequirements { None, Named, Unnamed };
</ins><span class="cx">
</span><span class="cx"> enum class DestructuringKind {
</span><span class="cx"> DestructureToVariables,
</span><span class="lines">@@ -101,6 +101,10 @@
</span><span class="cx">
</span><span class="cx"> typedef uint8_t DeclarationResultMask;
</span><span class="cx">
</span><ins>+enum class DeclarationDefaultContext {
+ Standard,
+ ExportDefault,
+};
</ins><span class="cx">
</span><span class="cx"> template <typename T> inline bool isEvalNode() { return false; }
</span><span class="cx"> template <> inline bool isEvalNode<EvalNode>() { return true; }
</span><span class="lines">@@ -1355,8 +1359,8 @@
</span><span class="cx"> template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
</span><span class="cx"> template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
</span><span class="cx"> enum class ExportType { Exported, NotExported };
</span><del>- template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
- template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
</del><ins>+ template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard);
+ template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard);
</ins><span class="cx"> template <class TreeBuilder> TreeStatement parseVariableDeclaration(TreeBuilder&, DeclarationType, ExportType = ExportType::NotExported);
</span><span class="cx"> template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
</span><span class="lines">@@ -1388,6 +1392,7 @@
</span><span class="cx"> template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
</span><ins>+ template <class TreeBuilder> ALWAYS_INLINE TreeClassExpression parseClassExpression(TreeBuilder&);
</ins><span class="cx"> template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseFunctionExpression(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
</span><span class="cx"> template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArgument(TreeBuilder&, ArgumentType&);
</span><span class="lines">@@ -1416,7 +1421,7 @@
</span><span class="cx"> template <class TreeBuilder> TreeStatement parseExportDeclaration(TreeBuilder&);
</span><span class="cx">
</span><span class="cx"> enum class FunctionDefinitionType { Expression, Declaration, Method };
</span><del>- template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType);
</del><ins>+ template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionNameRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType);
</ins><span class="cx">
</span><span class="cx"> ALWAYS_INLINE bool isArrowFunctionParameters();
</span><span class="cx">
</span><span class="lines">@@ -1423,7 +1428,7 @@
</span><span class="cx"> template <class TreeBuilder, class FunctionInfoType> NEVER_INLINE typename TreeBuilder::FormalParameterList parseFunctionParameters(TreeBuilder&, SourceParseMode, FunctionInfoType&);
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::FormalParameterList createGeneratorParameters(TreeBuilder&);
</span><span class="cx">
</span><del>- template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
</del><ins>+ template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionNameRequirements, ParserClassInfo<TreeBuilder>&);
</ins><span class="cx">
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode, bool& elementIsTail);
</span><span class="cx"> template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&, typename LexerType::RawStringsBuildMode);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeFunctionPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -82,11 +82,12 @@
</span><span class="cx">
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
</span><span class="cx"> {
</span><ins>+ VM& vm = exec->vm();
</ins><span class="cx"> JSValue thisValue = exec->thisValue();
</span><span class="cx"> if (thisValue.inherits(JSFunction::info())) {
</span><span class="cx"> JSFunction* function = jsCast<JSFunction*>(thisValue);
</span><span class="cx"> if (function->isHostOrBuiltinFunction())
</span><del>- return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(), "() {\n [native code]\n}"));
</del><ins>+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(vm), "() {\n [native code]\n}"));
</ins><span class="cx">
</span><span class="cx"> FunctionExecutable* executable = function->jsExecutable();
</span><span class="cx"> if (executable->isClass()) {
</span><span class="lines">@@ -99,7 +100,7 @@
</span><span class="cx"> StringView source = executable->source().provider()->getRange(
</span><span class="cx"> executable->parametersStartOffset(),
</span><span class="cx"> executable->parametersStartOffset() + executable->source().length());
</span><del>- return JSValue::encode(jsMakeNontrivialString(exec, functionHeader, function->name(), source));
</del><ins>+ return JSValue::encode(jsMakeNontrivialString(exec, functionHeader, function->name(vm), source));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (thisValue.inherits(InternalFunction::info())) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSFunctioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSFunction.cpp (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSFunction.cpp        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/runtime/JSFunction.cpp        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -166,13 +166,16 @@
</span><span class="cx"> return m_rareData.get();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-String JSFunction::name()
</del><ins>+String JSFunction::name(VM& vm)
</ins><span class="cx"> {
</span><span class="cx"> if (isHostFunction()) {
</span><span class="cx"> NativeExecutable* executable = jsCast<NativeExecutable*>(this->executable());
</span><span class="cx"> return executable->name();
</span><span class="cx"> }
</span><del>- return jsExecutable()->name().string();
</del><ins>+ const Identifier identifier = jsExecutable()->name();
+ if (identifier == vm.propertyNames->builtinNames().starDefaultPrivateName())
+ return emptyString();
+ return identifier.string();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> String JSFunction::displayName(VM& vm)
</span><span class="lines">@@ -192,7 +195,7 @@
</span><span class="cx"> if (!explicitName.isEmpty())
</span><span class="cx"> return explicitName;
</span><span class="cx">
</span><del>- const String actualName = name();
</del><ins>+ const String actualName = name(vm);
</ins><span class="cx"> if (!actualName.isEmpty() || isHostOrBuiltinFunction())
</span><span class="cx"> return actualName;
</span><span class="cx">
</span><span class="lines">@@ -616,7 +619,15 @@
</span><span class="cx">
</span><span class="cx"> void JSFunction::reifyName(ExecState* exec)
</span><span class="cx"> {
</span><del>- String name = jsExecutable()->ecmaName().string();
</del><ins>+ const Identifier& ecmaName = jsExecutable()->ecmaName();
+ String name;
+ // https://tc39.github.io/ecma262/#sec-exports-runtime-semantics-evaluation
+ // When the ident is "*default*", we need to set "default" for the ecma name.
+ // This "*default*" name is never shown to users.
+ if (ecmaName == exec->propertyNames().builtinNames().starDefaultPrivateName())
+ name = exec->propertyNames().defaultKeyword.string();
+ else
+ name = ecmaName.string();
</ins><span class="cx"> reifyName(exec, name);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSFunctionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSFunction.h (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSFunction.h        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/runtime/JSFunction.h        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx"> JS_EXPORT_PRIVATE static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*);
</span><span class="cx"> static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*, const String& name);
</span><span class="cx">
</span><del>- JS_EXPORT_PRIVATE String name();
</del><ins>+ JS_EXPORT_PRIVATE String name(VM&);
</ins><span class="cx"> JS_EXPORT_PRIVATE String displayName(VM&);
</span><span class="cx"> const String calculatedDisplayName(VM&);
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeLazyClassStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/LazyClassStructure.cpp (204841 => 204842)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/LazyClassStructure.cpp        2016-08-23 18:09:21 UTC (rev 204841)
+++ trunk/Source/JavaScriptCore/runtime/LazyClassStructure.cpp        2016-08-23 18:14:30 UTC (rev 204842)
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx"> if (InternalFunction* internalFunction = jsDynamicCast<InternalFunction*>(constructor))
</span><span class="cx"> name = internalFunction->name();
</span><span class="cx"> else if (JSFunction* function = jsDynamicCast<JSFunction*>(constructor))
</span><del>- name = function->name();
</del><ins>+ name = function->name(vm);
</ins><span class="cx"> else
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>