Title: [198042] trunk
Revision
198042
Author
[email protected]
Date
2016-03-11 13:08:08 -0800 (Fri, 11 Mar 2016)

Log Message

Implement Function.name and Function#toString for ES6 class.
https://bugs.webkit.org/show_bug.cgi?id=155336

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

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:

LayoutTests:

* 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.

Modified Paths

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to