Diff
Modified: trunk/LayoutTests/ChangeLog (198041 => 198042)
--- trunk/LayoutTests/ChangeLog 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/LayoutTests/ChangeLog 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,3 +1,23 @@
+2016-03-11 Mark Lam <[email protected]>
+
+ Implement Function.name and Function#toString for ES6 class.
+ https://bugs.webkit.org/show_bug.cgi?id=155336
+
+ Reviewed by Geoffrey Garen.
+
+ * js/class-syntax-name-expected.txt:
+ * js/script-tests/class-syntax-name.js:
+ (shouldBe):
+ (shouldBeTrue):
+ - Rebased expected result.
+
+ * js/function-toString-vs-name.html:
+ * js/script-tests/function-toString-vs-name.js:
+ - Added new tests for class.
+
+ * platform/mac/inspector/model/remote-object-expected.txt:
+ - Rebased expected result.
+
2016-03-11 Ryan Haddad <[email protected]>
Marking imported/blink/fast/multicol/dynamic/multicol-with-abspos-svg-with-foreignobject-with-multicol-crash.html as flaky
Modified: trunk/LayoutTests/js/class-syntax-name-expected.txt (198041 => 198042)
--- trunk/LayoutTests/js/class-syntax-name-expected.txt 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/LayoutTests/js/class-syntax-name-expected.txt 2016-03-11 21:08:08 UTC (rev 198042)
@@ -12,24 +12,24 @@
PASS 'use strict'; class { constructor() {} }:::SyntaxError: Class statements must have a name.
PASS class A { constructor() {} }
PASS 'use strict'; class A { constructor() {} }
-PASS class A { constructor() {} }; A.toString():::'function A() {}'
-PASS 'use strict'; class A { constructor() {} }; A.toString():::'function A() {}'
+PASS class A { constructor() {} }; A.toString():::'class A { constructor() {} }'
+PASS 'use strict'; class A { constructor() {} }; A.toString():::'class A { constructor() {} }'
PASS class A { constructor() {} }; (new A) instanceof A
PASS 'use strict'; class A { constructor() {} }; (new A) instanceof A
-PASS class A { constructor() { this.base = A; } }; (new A).base.toString():::'function A() { this.base = A; }'
-PASS 'use strict'; class A { constructor() { this.base = A; } }; (new A).base.toString():::'function A() { this.base = A; }'
+PASS class A { constructor() { this.base = A; } }; (new A).base.toString():::'class A { constructor() { this.base = A; } }'
+PASS 'use strict'; class A { constructor() { this.base = A; } }; (new A).base.toString():::'class A { constructor() { this.base = A; } }'
PASS class A { constructor() {} }; class B extends A {};
PASS 'use strict'; class A { constructor() {} }; class B extends A {};
-PASS class A { constructor() {} }; class B extends A { constructor() {} }; B.toString():::'function B() {}'
-PASS 'use strict'; class A { constructor() {} }; class B extends A { constructor() {} }; B.toString():::'function B() {}'
+PASS class A { constructor() {} }; class B extends A { constructor() {} }; B.toString():::'class B extends A { constructor() {} }'
+PASS 'use strict'; class A { constructor() {} }; class B extends A { constructor() {} }; B.toString():::'class B extends A { constructor() {} }'
PASS class A { constructor() {} }; class B extends A {}; (new B) instanceof A
PASS 'use strict'; class A { constructor() {} }; class B extends A {}; (new B) instanceof A
PASS class A { constructor() {} }; class B extends A {}; (new B) instanceof B
PASS 'use strict'; class A { constructor() {} }; class B extends A {}; (new B) instanceof B
-PASS class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString():::'function A() {}'
-PASS 'use strict'; class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString():::'function A() {}'
-PASS class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString():::'function B() { super(); this.base = A; this.derived = B; }'
-PASS 'use strict'; class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString():::'function B() { super(); this.base = A; this.derived = B; }'
+PASS class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString():::'class A { constructor() {} }'
+PASS 'use strict'; class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString():::'class A { constructor() {} }'
+PASS class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString():::'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'
+PASS 'use strict'; class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString():::'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'
Class _expression_
PASS A:::ReferenceError: Can't find variable: A
@@ -52,8 +52,8 @@
PASS 'use strict'; typeof (new (class A {})):::"object"
PASS (new (class A { constructor() { this.base = A; } })).base
PASS 'use strict'; (new (class A { constructor() { this.base = A; } })).base
-PASS (new (class A { constructor() { this.base = A; } })).base.toString():::"function A() { this.base = A; }"
-PASS 'use strict'; (new (class A { constructor() { this.base = A; } })).base.toString():::"function A() { this.base = A; }"
+PASS (new (class A { constructor() { this.base = A; } })).base.toString():::"class A { constructor() { this.base = A; } }"
+PASS 'use strict'; (new (class A { constructor() { this.base = A; } })).base.toString():::"class A { constructor() { this.base = A; } }"
PASS class A {}; (class B extends A {})
PASS 'use strict'; class A {}; (class B extends A {})
PASS class A {}; (class B extends A {}); B:::ReferenceError: Can't find variable: B
@@ -64,36 +64,36 @@
PASS 'use strict'; class A {}; new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })
PASS class A {}; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })) instanceof A
PASS 'use strict'; class A {}; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })) instanceof A
-PASS class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString():::'function A() {}'
-PASS 'use strict'; class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString():::'function A() {}'
-PASS class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString():::'function B() { super(); this.base = A; this.derived = B; }'
-PASS 'use strict'; class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString():::'function B() { super(); this.base = A; this.derived = B; }'
+PASS class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString():::'class A { constructor() {} }'
+PASS 'use strict'; class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString():::'class A { constructor() {} }'
+PASS class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString():::'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'
+PASS 'use strict'; class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString():::'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'
Class _expression_ assignment to variable
PASS A:::ReferenceError: Can't find variable: A
PASS 'use strict'; A:::ReferenceError: Can't find variable: A
PASS var VarA = class {}
PASS 'use strict'; var VarA = class {}
-PASS var VarA = class { constructor() {} }; VarA.toString():::'function () {}'
-PASS 'use strict'; var VarA = class { constructor() {} }; VarA.toString():::'function () {}'
+PASS var VarA = class { constructor() {} }; VarA.toString():::'class { constructor() {} }'
+PASS 'use strict'; var VarA = class { constructor() {} }; VarA.toString():::'class { constructor() {} }'
PASS VarA:::ReferenceError: Can't find variable: VarA
PASS 'use strict'; VarA:::ReferenceError: Can't find variable: VarA
PASS var VarA = class A { constructor() {} }
PASS 'use strict'; var VarA = class A { constructor() {} }
-PASS var VarA = class A { constructor() {} }; VarA.toString():::'function A() {}'
-PASS 'use strict'; var VarA = class A { constructor() {} }; VarA.toString():::'function A() {}'
+PASS var VarA = class A { constructor() {} }; VarA.toString():::'class A { constructor() {} }'
+PASS 'use strict'; var VarA = class A { constructor() {} }; VarA.toString():::'class A { constructor() {} }'
PASS var VarA = class A { constructor() {} }; A.toString():::ReferenceError: Can't find variable: A
PASS 'use strict'; var VarA = class A { constructor() {} }; A.toString():::ReferenceError: Can't find variable: A
PASS var VarA = class A { constructor() {} }; (new VarA) instanceof VarA
PASS 'use strict'; var VarA = class A { constructor() {} }; (new VarA) instanceof VarA
-PASS var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString():::'function A() { this.base = A; }'
-PASS 'use strict'; var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString():::'function A() { this.base = A; }'
+PASS var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString():::'class A { constructor() { this.base = A; } }'
+PASS 'use strict'; var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString():::'class A { constructor() { this.base = A; } }'
PASS var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} };
PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} };
PASS var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; B:::ReferenceError: Can't find variable: B
PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; B:::ReferenceError: Can't find variable: B
-PASS var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString():::'function B() {}'
-PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString():::'function B() {}'
+PASS var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString():::'class B extends VarA { constructor() {} }'
+PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString():::'class B extends VarA { constructor() {} }'
PASS var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarA
PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarA
PASS var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarB
@@ -118,7 +118,7 @@
PASS 'use strict'; class A {}; var result = A; result
PASS eval('var Foo = 10'); Foo:::10
PASS 'use strict'; eval('var Foo = 10'); Foo:::ReferenceError: Can't find variable: Foo
-PASS eval('class Bar { constructor() {} }; Bar.toString()');:::'function Bar() {}'
+PASS eval('class Bar { constructor() {} }; Bar.toString()');:::'class Bar { constructor() {} }'
PASS 'use strict'; eval('class Bar { constructor() {} }'); Bar.toString():::ReferenceError: Can't find variable: Bar
PASS successfullyParsed
Modified: trunk/LayoutTests/js/function-toString-vs-name.html (198041 => 198042)
--- trunk/LayoutTests/js/function-toString-vs-name.html 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/LayoutTests/js/function-toString-vs-name.html 2016-03-11 21:08:08 UTC (rev 198042)
@@ -5,6 +5,46 @@
</head>
<body>
<script src=""
+
+<script>
+failures = "";
+
+section = "global class statements with identical class bodies from different scripts";
+</script>
+<!-- Case 1: A global class statement: -->
+ <script>class globalClass1 { constructor(x) { return x; } stuff() { return 5; } }</script>
+
+<!-- Case 2: Same class body as Case 1 but indented. -->
+ <script>class globalClass2 { constructor(x) { return x; } stuff() { return 5; } }</script>
+
+<!-- Case 3: Same class body indented on the same line. -->
+<script>class globalClass3 { constructor(x) { return x; } stuff() { return 5; } }</script>
+
+<script>
+section = "global class expressions with identical class bodies from different scripts";
+</script>
+<!-- Case 1: A global class _expression_: -->
+ <script>var globalClassExpr1 = class { constructor(x) { return x; } stuff() { return 5; } }</script>
+
+<!-- Case 2: Same class body as Case 1 but indented. -->
+ <script>var globalClassExpr2 = class { constructor(x) { return x; } stuff() { return 5; } }</script>
+
+<!-- Case 3: Same class body indented on the same line. -->
+<script>var globalClassExpr3 = class { constructor(x) { return x; } stuff() { return 5; } }</script>
+
+<script>
+test(globalClass1, "globalClass1", "class globalClass1 { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalClass2, "globalClass2", "class globalClass2 { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalClass3, "globalClass3", "class globalClass3 { constructor(x) { return x; } stuff() { return 5; } }");
+
+test(globalClassExpr1, "globalClassExpr1", "class { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalClassExpr2, "globalClassExpr2", "class { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalClassExpr3, "globalClassExpr3", "class { constructor(x) { return x; } stuff() { return 5; } }");
+
+if (failureCount)
+ throw Error("Found " + failureCount + " failures:\n" + failures);
+</script>
+
<script src=""
</body>
</html>
Modified: trunk/LayoutTests/js/script-tests/class-syntax-name.js (198041 => 198042)
--- trunk/LayoutTests/js/script-tests/class-syntax-name.js 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/LayoutTests/js/script-tests/class-syntax-name.js 2016-03-11 21:08:08 UTC (rev 198042)
@@ -68,15 +68,15 @@
runTestShouldThrow("class {}");
runTestShouldThrow("class { constructor() {} }");
runTestShouldNotThrow("class A { constructor() {} }");
-runTestShouldBe("class A { constructor() {} }; A.toString()", "'function A() {}'");
+runTestShouldBe("class A { constructor() {} }; A.toString()", "'class A { constructor() {} }'");
runTestShouldBeTrue("class A { constructor() {} }; (new A) instanceof A");
-runTestShouldBe("class A { constructor() { this.base = A; } }; (new A).base.toString()", "'function A() { this.base = A; }'");
+runTestShouldBe("class A { constructor() { this.base = A; } }; (new A).base.toString()", "'class A { constructor() { this.base = A; } }'");
runTestShouldNotThrow("class A { constructor() {} }; class B extends A {};");
-runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() {} }; B.toString()", "'function B() {}'");
+runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() {} }; B.toString()", "'class B extends A { constructor() {} }'");
runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof A");
runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof B");
-runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString()", "'function A() {}'");
-runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString()", "'function B() { super(); this.base = A; this.derived = B; }'");
+runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString()", "'class A { constructor() {} }'");
+runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString()", "'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'");
// Class _expression_. Class name not added to scope. Class name is available inside class scope.
debug(''); debug('Class _expression_');
@@ -90,29 +90,29 @@
runTestShouldNotThrow("new (class A {})");
runTestShouldBe("typeof (new (class A {}))", '"object"');
runTestShouldNotThrow("(new (class A { constructor() { this.base = A; } })).base");
-runTestShouldBe("(new (class A { constructor() { this.base = A; } })).base.toString()", '"function A() { this.base = A; }"');
+runTestShouldBe("(new (class A { constructor() { this.base = A; } })).base.toString()", '"class A { constructor() { this.base = A; } }"');
runTestShouldNotThrow("class A {}; (class B extends A {})");
runTestShouldThrow("class A {}; (class B extends A {}); B");
runTestShouldNotThrow("class A {}; new (class B extends A {})");
runTestShouldNotThrow("class A {}; new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })");
runTestShouldBeTrue("class A {}; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })) instanceof A");
-runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString()", "'function A() {}'");
-runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString()", "'function B() { super(); this.base = A; this.derived = B; }'");
+runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString()", "'class A { constructor() {} }'");
+runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString()", "'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'");
// Assignment of a class _expression_ to a variable. Variable name available in scope, class name is not. Class name is available inside class scope.
debug(''); debug('Class _expression_ assignment to variable');
runTestShouldThrow("A");
runTestShouldNotThrow("var VarA = class {}");
-runTestShouldBe("var VarA = class { constructor() {} }; VarA.toString()", "'function () {}'");
+runTestShouldBe("var VarA = class { constructor() {} }; VarA.toString()", "'class { constructor() {} }'");
runTestShouldThrow("VarA");
runTestShouldNotThrow("var VarA = class A { constructor() {} }");
-runTestShouldBe("var VarA = class A { constructor() {} }; VarA.toString()", "'function A() {}'");
+runTestShouldBe("var VarA = class A { constructor() {} }; VarA.toString()", "'class A { constructor() {} }'");
runTestShouldThrow("var VarA = class A { constructor() {} }; A.toString()");
runTestShouldBeTrue("var VarA = class A { constructor() {} }; (new VarA) instanceof VarA");
-runTestShouldBe("var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString()", "'function A() { this.base = A; }'");
+runTestShouldBe("var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString()", "'class A { constructor() { this.base = A; } }'");
runTestShouldNotThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} };");
runTestShouldThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; B");
-runTestShouldBe("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString()", "'function B() {}'");
+runTestShouldBe("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString()", "'class B extends VarA { constructor() {} }'");
runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarA");
runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarB");
runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() { super(); this.base = VarA; this.derived = B; this.derivedVar = VarB; } }; (new VarB).base === VarA");
@@ -128,5 +128,5 @@
runTestShouldNotThrow("class A {}; var result = A; result");
shouldBe("eval('var Foo = 10'); Foo", "10");
shouldThrow("'use strict'; eval('var Foo = 10'); Foo");
-shouldBe("eval('class Bar { constructor() {} }; Bar.toString()');", "'function Bar() {}'");
+shouldBe("eval('class Bar { constructor() {} }; Bar.toString()');", "'class Bar { constructor() {} }'");
shouldThrow("'use strict'; eval('class Bar { constructor() {} }'); Bar.toString()");
Modified: trunk/LayoutTests/js/script-tests/function-toString-vs-name.js (198041 => 198042)
--- trunk/LayoutTests/js/script-tests/function-toString-vs-name.js 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/LayoutTests/js/script-tests/function-toString-vs-name.js 2016-03-11 21:08:08 UTC (rev 198042)
@@ -218,6 +218,306 @@
}
}
+section = "class from statement";
+(function () {
+ class foo {}
+ class bar {}
+ class bax { static name() {} }
+ let baz = bar;
+ class goo extends foo {}
+
+ test(foo, "foo", "class foo {}");
+ test(bar, "bar", "class bar {}");
+ shouldBe("typeof bax.name of ", "bax", typeof bax.name, "function");
+ shouldBe("toString of ", "bax", bax.toString(), "class bax { static name() {} }");
+ test(baz, "bar", "class bar {}");
+ test(goo, "goo", "class goo extends foo {}");
+
+ section = "bound class from statement";
+ {
+ let bound1 = foo.bind({});
+ test(bound1, "bound foo", "function foo() { [native code] }");
+ let bound2 = bar.bind({});
+ test(bound2, "bound bar", "function bar() { [native code] }");
+ let bound3 = bax.bind({});
+ test(bound3, "bound ", "function() { [native code] }"); // bax.name is not a string.
+ let bound4 = baz.bind({});
+ test(bound4, "bound bar", "function bar() { [native code] }");
+ let bound5 = goo.bind({});
+ test(bound5, "bound goo", "function goo() { [native code] }");
+ }
+})();
+
+section = "class with constructor from statement";
+(function () {
+ class foo { constructor(x) {} }
+ class bar { constructor() {} }
+ class bax { static name() {} constructor() {} }
+ let baz = bar;
+ class goo extends foo { constructor() { super(5); } }
+
+ test(foo, "foo", "class foo { constructor(x) {} }");
+ test(bar, "bar", "class bar { constructor() {} }");
+ shouldBe("typeof bax.name of ", "bax", typeof bax.name, "function");
+ shouldBe("toString of ", "bax", bax.toString(), "class bax { static name() {} constructor() {} }");
+ test(baz, "bar", "class bar { constructor() {} }");
+ test(goo, "goo", "class goo extends foo { constructor() { super(5); } }");
+
+ section = "bound class with constructor from statement";
+ {
+ let bound1 = foo.bind({});
+ test(bound1, "bound foo", "function foo() { [native code] }");
+ let bound2 = bar.bind({});
+ test(bound2, "bound bar", "function bar() { [native code] }");
+ let bound3 = bax.bind({});
+ test(bound3, "bound ", "function() { [native code] }"); // bax.name is not a string.
+ let bound4 = baz.bind({});
+ test(bound4, "bound bar", "function bar() { [native code] }");
+ let bound5 = goo.bind({});
+ test(bound5, "bound goo", "function goo() { [native code] }");
+ }
+})();
+
+section = "class from _expression_";
+(function () {
+ let foo = class namedFoo {}
+ let bar = class {}
+ let bax = class { static name() {} }
+ let baz = bar;
+ let goo = class extends foo {}
+
+ test(foo, "namedFoo", "class namedFoo {}");
+ test(bar, "bar", "class {}");
+ shouldBe("typeof bax.name of ", "bax", typeof bax.name, "function");
+ shouldBe("toString of ", "bax", bax.toString(), "class { static name() {} }");
+ test(baz, "bar", "class {}");
+ test(goo, "goo", "class extends foo {}");
+
+ section = "bound class from _expression_";
+ {
+ let bound1 = foo.bind({});
+ test(bound1, "bound namedFoo", "function namedFoo() { [native code] }");
+ let bound2 = bar.bind({});
+ test(bound2, "bound bar", "function bar() { [native code] }");
+ let bound3 = bax.bind({});
+ test(bound3, "bound ", "function() { [native code] }"); // bax.name is not a string.
+ let bound4 = baz.bind({});
+ test(bound4, "bound bar", "function bar() { [native code] }");
+ let bound5 = goo.bind({});
+ test(bound5, "bound goo", "function goo() { [native code] }");
+ }
+})();
+
+section = "class with constructor from _expression_";
+(function () {
+ let foo = class namedFoo { constructor(x) {} }
+ let bar = class { constructor() {} }
+ let bax = class { static name() {} constructor() {} }
+ let baz = bar;
+ let goo = class extends foo { constructor() { super(x) } }
+
+ test(foo, "namedFoo", "class namedFoo { constructor(x) {} }");
+ test(bar, "bar", "class { constructor() {} }");
+ shouldBe("typeof bax.name of ", "bax", typeof bax.name, "function");
+ shouldBe("toString of ", "bax", bax.toString(), "class { static name() {} constructor() {} }");
+ test(baz, "bar", "class { constructor() {} }");
+ test(goo, "goo", "class extends foo { constructor() { super(x) } }");
+
+ section = "bound class with constructor from _expression_";
+ {
+ let bound1 = foo.bind({});
+ test(bound1, "bound namedFoo", "function namedFoo() { [native code] }");
+ let bound2 = bar.bind({});
+ test(bound2, "bound bar", "function bar() { [native code] }");
+ let bound3 = bax.bind({});
+ test(bound3, "bound ", "function() { [native code] }"); // bax.name is not a string.
+ let bound4 = baz.bind({});
+ test(bound4, "bound bar", "function bar() { [native code] }");
+ let bound5 = goo.bind({});
+ test(bound5, "bound goo", "function goo() { [native code] }");
+ }
+})();
+
+section = "class in object property";
+(function () {
+ class gooBase {}
+ let o = {
+ foo: class {},
+ bar: class {},
+ bax: class { static name() {} },
+ goo: class extends gooBase {},
+ };
+ o.bay = o.bar;
+ o.baz = class {};
+
+ test(o.foo, "foo", "class {}");
+ test(o.bar, "bar", "class {}");
+ shouldBe("typeof o.bax.name of ", "o.bax", typeof o.bax.name, "function");
+ shouldBe("toString of ", "o.bax", o.bax.toString(), "class { static name() {} }");
+ test(o.bay, "bar", "class {}");
+ test(o.baz, "", "class {}");
+ test(o.goo, "goo", "class extends gooBase {}");
+
+ section = "bound class in object property";
+ {
+ let bound1 = o.foo.bind({});
+ test(bound1, "bound foo", "function foo() { [native code] }");
+ let bound2 = o.bar.bind({});
+ test(bound2, "bound bar", "function bar() { [native code] }");
+ let bound3 = o.bax.bind({});
+ test(bound3, "bound ", "function() { [native code] }"); // bax.name is not a string.
+ let bound4 = o.bay.bind({});
+ test(bound4, "bound bar", "function bar() { [native code] }");
+ let bound5 = o.baz.bind({});
+ test(bound5, "bound ", "function() { [native code] }");
+ let bound6 = o.goo.bind({});
+ test(bound6, "bound goo", "function goo() { [native code] }");
+ }
+})();
+
+section = "class with constructor in object property";
+(function () {
+ class gooBase { constructor(x) {} }
+ let o = {
+ foo: class { constructor(x) {} },
+ bar: class { constructor() {} },
+ bax: class { static name() {} constructor() {} },
+ goo: class extends gooBase { constructor() { super(5); } },
+ };
+ o.bay = o.bar;
+ o.baz = class { constructor() {} };
+
+ test(o.foo, "foo", "class { constructor(x) {} }");
+ test(o.bar, "bar", "class { constructor() {} }");
+ shouldBe("typeof o.bax.name of ", "o.bax", typeof o.bax.name, "function");
+ shouldBe("toString of ", "o.bax", o.bax.toString(), "class { static name() {} constructor() {} }");
+ test(o.bay, "bar", "class { constructor() {} }");
+ test(o.baz, "", "class { constructor() {} }");
+ test(o.goo, "goo", "class extends gooBase { constructor() { super(5); } }");
+
+ section = "bound class with constructor in object property";
+ {
+ let bound1 = o.foo.bind({});
+ test(bound1, "bound foo", "function foo() { [native code] }");
+ let bound2 = o.bar.bind({});
+ test(bound2, "bound bar", "function bar() { [native code] }");
+ let bound3 = o.bax.bind({});
+ test(bound3, "bound ", "function() { [native code] }"); // bax.name is not a string.
+ let bound4 = o.bay.bind({});
+ test(bound4, "bound bar", "function bar() { [native code] }");
+ let bound5 = o.baz.bind({});
+ test(bound5, "bound ", "function() { [native code] }");
+ let bound6 = o.goo.bind({});
+ test(bound6, "bound goo", "function goo() { [native code] }");
+ }
+})();
+
+section = "global class statement";
+// Checking if there are CodeCache badness that can result from global class statements
+// with identical bodies.
+class globalCS1 { constructor(x) { return x; } stuff() { return 5; } }
+// Identical class body as CS1.
+class globalCS2 { constructor(x) { return x; } stuff() { return 5; } }
+// Identical constructor as CS2 & CS1, but different otherwise.
+class globalCS3 { constructor(x) { return x; } stuff3() { return 15; } }
+
+test(globalCS1, "globalCS1", "class globalCS1 { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalCS2, "globalCS2", "class globalCS2 { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalCS3, "globalCS3", "class globalCS3 { constructor(x) { return x; } stuff3() { return 15; } }");
+
+section = "global class _expression_";
+// Checking if there are CodeCache badness that can result from global class expressions
+// with identical bodies.
+var globalCE1 = class { constructor(x) { return x; } stuff() { return 5; } }
+// Identical class body as CSE1.
+var globalCE2 = class { constructor(x) { return x; } stuff() { return 5; } }
+// Identical constructor as CSE2 & CSE1, but different otherwise.
+var globalCE3 = class { constructor(x) { return x; } stuff3() { return 15; } }
+
+test(globalCE1, "globalCE1", "class { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalCE2, "globalCE2", "class { constructor(x) { return x; } stuff() { return 5; } }");
+test(globalCE3, "globalCE3", "class { constructor(x) { return x; } stuff3() { return 15; } }");
+
+section = "class statements in eval";
+// Checking if there are CodeCache badness that can result from class statements in
+// identical eval statements.
+(function () {
+ let body1 = "class foo { constructor(x) { return x; } stuff() { return 5; } }";
+ // Identical class body as body1.
+ let body2 = "class foo { constructor(x) { return x; } stuff() { return 5; } }";
+ // Identical constructor as body1 & body2, but different otherwise.
+ let body3 = "class foo3 { constructor(x) { return x; } stuff3() { return 15; } }";
+
+ let bar1 = eval(body1);
+ let bar2 = eval(body2);
+ let bar3 = eval(body3);
+ let bar4 = eval(body1);
+
+ test(bar1, "foo", "class foo { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar2, "foo", "class foo { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar3, "foo3", "class foo3 { constructor(x) { return x; } stuff3() { return 15; } }");
+ test(bar4, "foo", "class foo { constructor(x) { return x; } stuff() { return 5; } }");
+})();
+
+section = "class expressions in eval";
+// Checking if there are CodeCache badness that can result from class expressions in
+// identical eval statements.
+(function () {
+ let body1 = "var foo = class { constructor(x) { return x; } stuff() { return 5; } }; foo";
+ // Identical class body as body1.
+ let body2 = "var foo = class { constructor(x) { return x; } stuff() { return 5; } }; foo";
+ // Identical constructor as body1 & body2, but different otherwise.
+ let body3 = "var foo3 = class { constructor(x) { return x; } stuff3() { return 15; } }; foo3";
+
+ let bar1 = eval(body1);
+ let bar2 = eval(body2);
+ let bar3 = eval(body3);
+ let bar4 = eval(body1);
+
+ test(bar1, "foo", "class { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar2, "foo", "class { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar3, "foo3", "class { constructor(x) { return x; } stuff3() { return 15; } }");
+ test(bar4, "foo", "class { constructor(x) { return x; } stuff() { return 5; } }");
+})();
+
+section = "class statements in dynamically created Functions";
+// Checking if there are CodeCache badness that can result from dynamically created
+// Function objects with class statements in identical bodies.
+(function () {
+ let body1 = "class foo { constructor(x) { return x; } stuff() { return 5; } } return foo;";
+ // Identical class body as body1.
+ let body2 = "class foo { constructor(x) { return x; } stuff() { return 5; } } return foo;";
+ // Identical constructor as body1 & body2, but different otherwise.
+ let body3 = "class foo3 { constructor(x) { return x; } stuff3() { return 15; } } return foo3;";
+
+ let bar1 = new Function(body1);
+ let bar2 = new Function(body2);
+ let bar3 = new Function(body3);
+
+ test(bar1(), "foo", "class foo { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar2(), "foo", "class foo { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar3(), "foo3", "class foo3 { constructor(x) { return x; } stuff3() { return 15; } }");
+})();
+
+section = "class expressions in dynamically created Functions";
+// Checking if there are CodeCache badness that can result from dynamically created
+// Function objects with class expressions in identical bodies.
+(function () {
+ let body1 = "var foo = class { constructor(x) { return x; } stuff() { return 5; } }; return foo;";
+ // Identical class body as body1.
+ let body2 = "var foo = class { constructor(x) { return x; } stuff() { return 5; } }; return foo;";
+ // Identical constructor as body1 & body2, but different otherwise.
+ let body3 = "var foo3 = class { constructor(x) { return x; } stuff3() { return 15; } }; return foo3;";
+
+ let bar1 = new Function(body1);
+ let bar2 = new Function(body2);
+ let bar3 = new Function(body3);
+
+ test(bar1(), "foo", "class { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar2(), "foo", "class { constructor(x) { return x; } stuff() { return 5; } }");
+ test(bar3(), "foo3", "class { constructor(x) { return x; } stuff3() { return 15; } }");
+})();
+
// FIXME: Uncomment these when we've added support for Function.name of computed properties.
// section = "Object computed string property";
// {
Modified: trunk/LayoutTests/platform/mac/inspector/model/remote-object-expected.txt (198041 => 198042)
--- trunk/LayoutTests/platform/mac/inspector/model/remote-object-expected.txt 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/LayoutTests/platform/mac/inspector/model/remote-object-expected.txt 2016-03-11 21:08:08 UTC (rev 198042)
@@ -4748,7 +4748,7 @@
"_objectId": "<filtered>",
"_description": "Person"
},
- "_functionDescription": "function Person(name){}"
+ "_functionDescription": "class Person { constructor(name){} get fullName(){} methodName(p1, p2){} }"
}
-----------------------------------------------------
@@ -4771,7 +4771,7 @@
"_objectId": "<filtered>",
"_description": "B"
},
- "_functionDescription": "function B() { super(...arguments); }"
+ "_functionDescription": "class B extends Alpha { methodB(){} }"
}
-----------------------------------------------------
Modified: trunk/Source/_javascript_Core/ChangeLog (198041 => 198042)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,3 +1,137 @@
+2016-03-11 Mark Lam <[email protected]>
+
+ Implement Function.name and Function#toString for ES6 class.
+ https://bugs.webkit.org/show_bug.cgi?id=155336
+
+ Reviewed by Geoffrey Garen.
+
+ The only thing that the ES6 spec says about toString with regards to class
+ objects is:
+
+ "The string representation must have the syntax of a FunctionDeclaration,
+ FunctionExpression, GeneratorDeclaration, GeneratorExpression, ClassDeclaration,
+ ClassExpression, ArrowFunction, MethodDefinition, or GeneratorMethod depending
+ upon the actual characteristics of the object."
+
+ Previously, invoking toString() on a class object will return the function
+ source string of the class' constructor function. This does not conform to the
+ spec in that the toString string for a class does not have the syntax of a
+ ClassDeclaration or ClassExpression.
+
+ This is now fixed by doing the following:
+
+ 1. Added "m_classSource" to FunctionExecutable (and correspondingly to
+ UnlinkedFunctionExecutable, FunctionMetadataNode, and ClassExprNode).
+ m_classSource is the SourceCode for the code range "class ... { ... }".
+
+ Since the class constructor function is the in memory representation of the
+ class object, only class constructor functions will have its m_classSource
+ set. m_classSource will be "null" (by default) for all other functions.
+ This is how we know if a FunctionExecutable is for a class.
+
+ Note: FunctionExecutable does not have its own m_classSource. It always gets
+ it from its UnlinkedFunctionExecutable. This is ok to do because our CodeCache
+ currently does not cache UnlinkedFunctionExecutables for class constructors.
+
+ 2. The ClassExprNode now tracks the SourceCode range for the class _expression_.
+ This is used to set m_classSource in the UnlinkedFunctionExecutable at
+ bytecode generation time, and the FunctionExecutable later at bytecode
+ linking time.
+
+ 3. Function.prototype.toString() now checks if the function is for a class.
+ If so, it returns the string for the class source instead of just the
+ function source for the class constructor.
+
+ Note: the class source is static from the time the class was parsed. This
+ can introduces some weirdness at runtime. Consider the following:
+
+ var v1 = class {}
+ v1.toString(); // yields "class {}".
+
+ class c2 extends v1 {}
+
+ c2.__proto__ === v1; // yields true i.e. c2 extends v1.
+ c2.toString(); // yields "class c2 extends v1 {}" which is fine.
+
+ v1 = {}; // point v1 to something else now.
+
+ c2.__proto__ === v1; // now yields false i.e. c2 no longer extends v1.
+ // c2 actually extends the class that v1 used to
+ // point to, but ...
+ c2.toString(); // still yields "class c2 extends v1 {}" which is no longer true.
+
+ It is unclear how we can best implement toString() to avoid this issue.
+ The above behavior is how Chrome (Version 51.0.2671.0 canary (64-bit))
+ currently implements toString() of a class, and we do the same in this patch.
+ In Firefox (45.0), toString() of a class will yield the function source of it
+ constructor function, which is not better.
+
+ In this patch, we also added ES6 compliance for Function.name on class objects:
+
+ 4. The ClassExprNode now has a m_ecmaName string for tracking the inferred
+ name of a class according to the ES6 spec. The ASTBuilder now mirrors its
+ handling of FuncExprNodes to ClassExprNodes in setting the nodes' m_ecmaName
+ where relevant.
+
+ The m_ecmaName is later used to set the m_ecmaName of the FunctionExecutable
+ of the class constructor, which in turn is used to populate the initial value
+ of the Function.name property.
+
+ 5. Also renamed some variable names (/m_metadata/metadata/) to be consistent with
+ webkit naming convention.
+
+ * bytecode/UnlinkedFunctionExecutable.cpp:
+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+ * bytecode/UnlinkedFunctionExecutable.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
+ (JSC::BytecodeGenerator::emitNewDefaultConstructor):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ClassExprNode::emitBytecode):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createAssignResolve):
+ (JSC::ASTBuilder::createYield):
+ (JSC::ASTBuilder::createClassExpr):
+ (JSC::ASTBuilder::createFunctionExpr):
+ (JSC::ASTBuilder::createProperty):
+ (JSC::ASTBuilder::makeAssignNode):
+ * parser/NodeConstructors.h:
+ (JSC::FunctionParameters::FunctionParameters):
+ (JSC::BaseFuncExprNode::BaseFuncExprNode):
+ (JSC::FuncExprNode::FuncExprNode):
+ (JSC::FuncDeclNode::FuncDeclNode):
+ (JSC::ArrowFuncExprNode::ArrowFuncExprNode):
+ (JSC::ClassDeclNode::ClassDeclNode):
+ (JSC::ClassExprNode::ClassExprNode):
+ * parser/Nodes.h:
+ (JSC::ExpressionNode::isDestructuringNode):
+ (JSC::ExpressionNode::isFuncExprNode):
+ (JSC::ExpressionNode::isArrowFuncExprNode):
+ (JSC::ExpressionNode::isClassExprNode):
+ (JSC::ExpressionNode::isCommaNode):
+ (JSC::ExpressionNode::isSimpleArray):
+ (JSC::ExpressionNode::isAdd):
+ * parser/Parser.cpp:
+ (JSC::stringForFunctionMode):
+ (JSC::Parser<LexerType>::parseFunctionInfo):
+ (JSC::Parser<LexerType>::parseClass):
+ * parser/ParserFunctionInfo.h:
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createEmptyLetExpression):
+ (JSC::SyntaxChecker::createYield):
+ (JSC::SyntaxChecker::createClassExpr):
+ (JSC::SyntaxChecker::createFunctionExpr):
+ (JSC::SyntaxChecker::createFunctionMetadata):
+ (JSC::SyntaxChecker::createArrowFunctionExpr):
+ * runtime/Executable.cpp:
+ (JSC::FunctionExecutable::FunctionExecutable):
+ (JSC::FunctionExecutable::finishCreation):
+ * runtime/Executable.h:
+ * runtime/FunctionPrototype.cpp:
+ (JSC::functionProtoFuncToString):
+ * tests/es6.yaml:
+
2016-03-11 Commit Queue <[email protected]>
Unreviewed, rolling out r197994.
@@ -579,7 +713,6 @@
(noAssign): Deleted.
(catch): Deleted.
->>>>>>> .r197960
2016-03-08 Skachkov Oleksandr <[email protected]>
How we load new.target in arrow functions is broken
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp (198041 => 198042)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013, 2015 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012-2013, 2015-2016 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -105,6 +105,7 @@
, m_ecmaName(node->ecmaName())
, m_inferredName(node->inferredName())
, m_sourceOverride(WTFMove(sourceOverride))
+ , m_classSource(node->classSource())
{
ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h (198041 => 198042)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2015 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -76,9 +76,14 @@
const Identifier& name() const { return m_name; }
const Identifier& ecmaName() const { return m_ecmaName; }
+ void setEcmaName(const Identifier& name) { m_ecmaName = name; }
const Identifier& inferredName() const { return m_inferredName; }
unsigned parameterCount() const { return m_parameterCount; };
SourceParseMode parseMode() const { return static_cast<SourceParseMode>(m_sourceParseMode); };
+
+ const SourceCode& classSource() const { return m_classSource; };
+ void setClassSource(const SourceCode& source) { m_classSource = source; };
+
bool isInStrictContext() const { return m_isInStrictContext; }
FunctionMode functionMode() const { return static_cast<FunctionMode>(m_functionMode); }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
@@ -163,6 +168,7 @@
Identifier m_ecmaName;
Identifier m_inferredName;
RefPtr<SourceProvider> m_sourceOverride;
+ SourceCode m_classSource;
VariableEnvironment m_parentScopeTDZVariables;
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (198041 => 198042)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2009, 2012-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <[email protected]>
* Copyright (C) 2012 Igalia, S.L.
*
@@ -2810,10 +2810,13 @@
return dst;
}
-RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name)
+RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name,
+ const Identifier& ecmaName, const SourceCode& classSource)
{
UnlinkedFunctionExecutable* executable = m_vm->builtinExecutables()->createDefaultConstructor(constructorKind, name);
executable->setInvalidTypeProfilingOffsets();
+ executable->setEcmaName(ecmaName);
+ executable->setClassSource(classSource);
unsigned index = m_codeBlock->addFunctionExpr(executable);
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (198041 => 198042)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2009, 2012-2016 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <[email protected]>
* Copyright (C) 2012 Igalia, S.L.
*
@@ -518,7 +518,7 @@
RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*);
RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
- RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name);
+ RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource);
RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (198041 => 198042)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2002 Harri Porten ([email protected])
* Copyright (C) 2001 Peter Kelly ([email protected])
-* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2015 Apple Inc. All rights reserved.
+* Copyright (C) 2003-2009, 2012-2013, 2015-2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich ([email protected])
* Copyright (C) 2007 Maks Orlovich
* Copyright (C) 2007 Eric Seidel <[email protected]>
@@ -3220,11 +3220,16 @@
RefPtr<RegisterID> constructor;
// FIXME: Make the prototype non-configurable & non-writable.
- if (m_constructorExpression)
+ if (m_constructorExpression) {
+ ASSERT(m_constructorExpression->isFuncExprNode());
+ FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(m_constructorExpression)->metadata();
+ metadata->setEcmaName(ecmaName());
+ metadata->setClassSource(m_classSource);
constructor = generator.emitNode(dst, m_constructorExpression);
- else {
+ } else {
constructor = generator.emitNewDefaultConstructor(generator.finalDestination(dst),
- m_classHeritage ? ConstructorKind::Derived : ConstructorKind::Base, m_name);
+ m_classHeritage ? ConstructorKind::Derived : ConstructorKind::Base,
+ m_name, ecmaName(), m_classSource);
}
const auto& propertyNames = generator.propertyNames();
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (198041 => 198042)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -346,7 +346,8 @@
auto metadata = static_cast<FuncExprNode*>(rhs)->metadata();
metadata->setEcmaName(ident);
metadata->setInferredName(ident);
- }
+ } else if (rhs->isClassExprNode())
+ static_cast<ClassExprNode*>(rhs)->setEcmaName(ident);
AssignResolveNode* node = new (m_parserArena) AssignResolveNode(location, ident, rhs, assignmentContext);
setExceptionLocation(node, start, divot, end);
return node;
@@ -364,10 +365,11 @@
return node;
}
- ClassExprNode* createClassExpr(const JSTokenLocation& location, const Identifier& name, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
+ ClassExprNode* createClassExpr(const JSTokenLocation& location, const ParserClassInfo<ASTBuilder>& classInfo, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
{
- return new (m_parserArena) ClassExprNode(location, name, classEnvironment, constructor, parentClass, instanceMethods, staticMethods);
+ SourceCode source = m_sourceCode->subExpression(classInfo.startOffset, classInfo.endOffset, classInfo.startLine, classInfo.startColumn);
+ return new (m_parserArena) ClassExprNode(location, *classInfo.className, source, classEnvironment, constructor, parentClass, instanceMethods, staticMethods);
}
ExpressionNode* createFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
@@ -442,7 +444,8 @@
auto metadata = static_cast<FuncExprNode*>(node)->metadata();
metadata->setEcmaName(*propertyName);
metadata->setInferredName(*propertyName);
- }
+ } else if (node->isClassExprNode())
+ static_cast<ClassExprNode*>(node)->setEcmaName(*propertyName);
return new (m_parserArena) PropertyNode(*propertyName, node, type, putType, superBinding);
}
PropertyNode* createProperty(VM* vm, ParserArena& parserArena, double propertyName, ExpressionNode* node, PropertyNode::Type type, PropertyNode::PutType putType, bool)
@@ -1301,7 +1304,8 @@
auto metadata = static_cast<FuncExprNode*>(expr)->metadata();
metadata->setEcmaName(resolve->identifier());
metadata->setInferredName(resolve->identifier());
- }
+ } else if (expr->isClassExprNode())
+ static_cast<ClassExprNode*>(expr)->setEcmaName(resolve->identifier());
AssignResolveNode* node = new (m_parserArena) AssignResolveNode(location, resolve->identifier(), expr, AssignmentContext::AssignmentExpression);
setExceptionLocation(node, start, divot, end);
return node;
Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (198041 => 198042)
--- trunk/Source/_javascript_Core/parser/NodeConstructors.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2013, 2015 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -890,27 +890,27 @@
}
- inline BaseFuncExprNode::BaseFuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+ inline BaseFuncExprNode::BaseFuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* metadata, const SourceCode& source)
: ExpressionNode(location)
- , m_metadata(m_metadata)
+ , m_metadata(metadata)
{
m_metadata->finishParsing(source, ident, FunctionExpression);
}
- inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
- : BaseFuncExprNode(location, ident, m_metadata, source)
+ inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* metadata, const SourceCode& source)
+ : BaseFuncExprNode(location, ident, metadata, source)
{
}
- inline FuncDeclNode::FuncDeclNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+ inline FuncDeclNode::FuncDeclNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* metadata, const SourceCode& source)
: StatementNode(location)
- , m_metadata(m_metadata)
+ , m_metadata(metadata)
{
m_metadata->finishParsing(source, ident, FunctionDeclaration);
}
- inline ArrowFuncExprNode::ArrowFuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
- : BaseFuncExprNode(location, ident, m_metadata, source)
+ inline ArrowFuncExprNode::ArrowFuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* metadata, const SourceCode& source)
+ : BaseFuncExprNode(location, ident, metadata, source)
{
}
@@ -927,10 +927,12 @@
{
}
- inline ClassExprNode::ClassExprNode(const JSTokenLocation& location, const Identifier& name, VariableEnvironment& classEnvironment, ExpressionNode* constructorExpression, ExpressionNode* classHeritage, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
+ inline ClassExprNode::ClassExprNode(const JSTokenLocation& location, const Identifier& name, const SourceCode& classSource, VariableEnvironment& classEnvironment, ExpressionNode* constructorExpression, ExpressionNode* classHeritage, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
: ExpressionNode(location)
, VariableEnvironmentNode(classEnvironment)
+ , m_classSource(classSource)
, m_name(name)
+ , m_ecmaName(&name)
, m_constructorExpression(constructorExpression)
, m_classHeritage(classHeritage)
, m_instanceMethods(instanceMethods)
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (198041 => 198042)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2000 Harri Porten ([email protected])
* Copyright (C) 2001 Peter Kelly ([email protected])
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2009, 2013, 2015-2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich ([email protected])
* Copyright (C) 2007 Maks Orlovich
* Copyright (C) 2007 Eric Seidel <[email protected]>
@@ -166,6 +166,7 @@
virtual bool isDestructuringNode() const { return false; }
virtual bool isFuncExprNode() const { return false; }
virtual bool isArrowFuncExprNode() const { return false; }
+ virtual bool isClassExprNode() const { return false; }
virtual bool isCommaNode() const { return false; }
virtual bool isSimpleArray() const { return false; }
virtual bool isAdd() const { return false; }
@@ -1844,7 +1845,7 @@
void overrideName(const Identifier& ident) { m_ident = ident; }
const Identifier& ident() { return m_ident; }
- void setEcmaName(const Identifier& ecmaName) { ASSERT(!ecmaName.isNull()); m_ecmaName = ecmaName; }
+ void setEcmaName(const Identifier& ecmaName) { m_ecmaName = ecmaName; }
const Identifier& ecmaName() { return m_ident.isEmpty() ? m_ecmaName : m_ident; }
void setInferredName(const Identifier& inferredName) { ASSERT(!inferredName.isNull()); m_inferredName = inferredName; }
const Identifier& inferredName() { return m_inferredName.isEmpty() ? m_ident : m_inferredName; }
@@ -1862,6 +1863,8 @@
void setEndPosition(JSTextPosition);
const SourceCode& source() const { return m_source; }
+ const SourceCode& classSource() const { return m_classSource; }
+ void setClassSource(const SourceCode& source) { m_classSource = source; }
int startStartOffset() const { return m_startStartOffset; }
bool isInStrictContext() const { return m_isInStrictContext; }
@@ -1888,6 +1891,7 @@
int m_functionNameStart;
int m_parametersStart;
SourceCode m_source;
+ SourceCode m_classSource;
int m_startStartOffset;
unsigned m_parameterCount;
int m_lastLine;
@@ -1974,15 +1978,22 @@
public:
using ParserArenaDeletable::operator new;
- ClassExprNode(const JSTokenLocation&, const Identifier&, VariableEnvironment& classEnvironment, ExpressionNode* constructorExpresssion,
+ ClassExprNode(const JSTokenLocation&, const Identifier&, const SourceCode& classSource,
+ VariableEnvironment& classEnvironment, ExpressionNode* constructorExpresssion,
ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods);
const Identifier& name() { return m_name; }
+ const Identifier& ecmaName() { return m_ecmaName ? *m_ecmaName : m_name; }
+ void setEcmaName(const Identifier& name) { m_ecmaName = m_name.isNull() ? &name : &m_name; }
private:
RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ bool isClassExprNode() const override { return true; }
+
+ SourceCode m_classSource;
const Identifier& m_name;
+ const Identifier* m_ecmaName;
ExpressionNode* m_constructorExpression;
ExpressionNode* m_classHeritage;
PropertyListNode* m_instanceMethods;
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (198041 => 198042)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2001 Harri Porten ([email protected])
* Copyright (C) 2001 Peter Kelly ([email protected])
- * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006-2010, 2013, 2016 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -2193,6 +2193,9 @@
{
ASSERT(match(CLASSTOKEN));
JSTokenLocation location(tokenLocation());
+ info.startLine = location.line;
+ info.startColumn = tokenColumn();
+ info.startOffset = location.startOffset;
next();
AutoPopScopeRef classScope(this, pushScope());
@@ -2203,7 +2206,6 @@
const Identifier* className = nullptr;
if (match(IDENT)) {
className = m_token.m_data.ident;
- info.className = className;
next();
failIfTrue(classScope->declareLexicalVariable(className, true) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
} else if (requirements == FunctionNeedsName) {
@@ -2214,6 +2216,7 @@
} else
className = &m_vm->propertyNames->nullIdentifier;
ASSERT(className);
+ info.className = className;
TreeExpression parentClass = 0;
if (consume(EXTENDS)) {
@@ -2343,9 +2346,10 @@
}
}
+ info.endOffset = tokenLocation().endOffset - 1;
consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
- auto classExpression = context.createClassExpr(location, *className, classScope->finalizeLexicalEnvironment(), constructor, parentClass, instanceMethods, staticMethods);
+ auto classExpression = context.createClassExpr(location, info, classScope->finalizeLexicalEnvironment(), constructor, parentClass, instanceMethods, staticMethods);
popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
return classExpression;
}
Modified: trunk/Source/_javascript_Core/parser/ParserFunctionInfo.h (198041 => 198042)
--- trunk/Source/_javascript_Core/parser/ParserFunctionInfo.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/parser/ParserFunctionInfo.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -43,7 +43,11 @@
template <class TreeBuilder>
struct ParserClassInfo {
- const Identifier* className = 0;
+ const Identifier* className { nullptr };
+ unsigned startOffset { 0 };
+ unsigned endOffset { 0 };
+ int startLine { 0 };
+ unsigned startColumn { 0 };
};
}
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (198041 => 198042)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -182,7 +182,7 @@
ExpressionType createEmptyLetExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
ExpressionType createYield(const JSTokenLocation&) { return YieldExpr; }
ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool, int, int, int) { return YieldExpr; }
- ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
+ ClassExpression createClassExpr(const JSTokenLocation&, const ParserClassInfo<SyntaxChecker>&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool, InnerArrowFunctionCodeFeatures = NoInnerArrowFunctionFeatures) { return FunctionBodyResult; }
ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
Modified: trunk/Source/_javascript_Core/runtime/Executable.h (198041 => 198042)
--- trunk/Source/_javascript_Core/runtime/Executable.h 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/runtime/Executable.h 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2010, 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2013-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -662,6 +662,7 @@
FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
+ bool isClass() const { return !classSource().isNull(); }
bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
bool isGetter() const { return parseMode() == SourceParseMode::GetterMode; }
bool isSetter() const { return parseMode() == SourceParseMode::SetterMode; }
@@ -672,6 +673,7 @@
const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
+ const SourceCode& classSource() const { return m_unlinkedExecutable->classSource(); }
static void visitChildren(JSCell*, SlotVisitor&);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (198041 => 198042)
--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2016-03-11 21:08:08 UTC (rev 198042)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2001 Harri Porten ([email protected])
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2009, 2015-2016 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -89,7 +89,11 @@
return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(), "() {\n [native code]\n}"));
FunctionExecutable* executable = function->jsExecutable();
-
+ if (executable->isClass()) {
+ StringView classSource = executable->classSource().view();
+ return JSValue::encode(jsString(exec, classSource.toStringWithoutCopying()));
+ }
+
String functionHeader = executable->isArrowFunction() ? "" : "function ";
StringView source = executable->source().provider()->getRange(
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (198041 => 198042)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-11 20:59:27 UTC (rev 198041)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-11 21:08:08 UTC (rev 198042)
@@ -801,7 +801,7 @@
- path: es6/function_name_property_isnt_writable_is_configurable.js
cmd: runES6 :normal
- path: es6/function_name_property_object_methods_class.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/function_name_property_object_methods_function.js
cmd: runES6 :normal
- path: es6/function_name_property_shorthand_methods_no_lexical_binding.js
@@ -809,7 +809,7 @@
- path: es6/function_name_property_symbol-keyed_methods.js
cmd: runES6 :fail
- path: es6/function_name_property_variables_class.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/function_name_property_variables_function.js
cmd: runES6 :normal
- path: es6/generators_%GeneratorPrototype%.constructor.js