haikuwebkit/LayoutTests/js/function-toString-vs-name.html

51 lines
2.1 KiB
HTML
Raw Permalink Normal View History

Implement Function.name support for getters/setters and inferring name of function properties. https://bugs.webkit.org/show_bug.cgi?id=154865 Reviewed by Geoffrey Garen. Source/JavaScriptCore: 1. toString() no longer uses the value of Function.name as the name of the function in the returned string, because ... i. Function.name is supposed to be configurable. Hence, it can be made writable and can be set to any JSValue, or deleted. ii. Function.prototype.toString() is supposed to produce a string that can be eval'ed. Hence, for JS functions, the function name in the produced string must be a legal function name (and not some arbitrary value set in Function.name). For example, while a number is a legal value for Function.name, it is not legal as the function name in the toString() string. Instead, we'll always use the original name from the JS source that the function was parsed from. 2. JSFunction::name() now always return the original name, not the value of the Function.name property. As a result, it also no longer needs an ExecState* arg. If the original name is an empty string, JSFunction::name() will use the inferred name. 3. For JS functions, the original name can be attained from their FunctionExecutable object. For host/native functions (which do not have a FunctionExecutable), we get the "original" name from its NativeExecutable. 4. The m_hostFunctionStubMap now keys its NativeExecutable pointers using the original name, in addition to the native function and constructor pointers. This is needed because we want a different NativeExecutable for functions with a different name (to satisfy (3) above). 5. Changed JSBoundFunction to store the name of its bound function in its NativeExecutable. This will later be used to generate the toString() string. It's Function.name value is eagerly initialized at construction time. 6. Function.name for getters/setters are now prefixed with "get"/"set". This was done both for the JSBoundSlotBaseFunctions and JS definable get/set functions. 7. Added InternalFunction::m_originalName so that we can use it to generate the toString() string. We're storing it as a JSString instead of a WTF::String only because we want InternalFunction to be continue to be trivially destructible. * inspector/JSInjectedScriptHost.cpp: (Inspector::JSInjectedScriptHost::functionDetails): * jit/JITThunks.cpp: (JSC::JITThunks::finalize): (JSC::JITThunks::hostFunctionStub): * jit/JITThunks.h: * runtime/Executable.h: * runtime/FunctionPrototype.cpp: (JSC::functionProtoFuncToString): * runtime/InternalFunction.cpp: (JSC::InternalFunction::finishCreation): (JSC::InternalFunction::visitChildren): (JSC::InternalFunction::name): (JSC::InternalFunction::displayName): * runtime/InternalFunction.h: * runtime/JSBoundFunction.cpp: (JSC::JSBoundFunction::create): (JSC::JSBoundFunction::visitChildren): (JSC::JSBoundFunction::toStringName): Deleted. * runtime/JSBoundFunction.h: (JSC::JSBoundFunction::boundThis): (JSC::JSBoundFunction::boundArgs): (JSC::JSBoundFunction::createStructure): * runtime/JSBoundSlotBaseFunction.cpp: (JSC::boundSlotBaseFunctionCall): (JSC::JSBoundSlotBaseFunction::create): * runtime/JSFunction.cpp: (JSC::JSFunction::initializeRareData): (JSC::JSFunction::name): (JSC::JSFunction::displayName): (JSC::JSFunction::calculatedDisplayName): (JSC::JSFunction::reifyName): * runtime/JSFunction.h: * tests/es6.yaml: LayoutTests: * js/function-toString-vs-name-expected.txt: Added. * js/function-toString-vs-name.html: Added. * js/script-tests/function-toString-vs-name.js: Added. Canonical link: https://commits.webkit.org/173305@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197815 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-09 00:01:09 +00:00
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
</head>
<body>
<script src="script-tests/function-toString-vs-name.js"></script>
Implement Function.name and Function#toString for ES6 class. https://bugs.webkit.org/show_bug.cgi?id=155336 Reviewed by Geoffrey Garen. Source/JavaScriptCore: 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. Canonical link: https://commits.webkit.org/173492@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198042 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-11 21:08:08 +00:00
<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>
Implement Function.name support for getters/setters and inferring name of function properties. https://bugs.webkit.org/show_bug.cgi?id=154865 Reviewed by Geoffrey Garen. Source/JavaScriptCore: 1. toString() no longer uses the value of Function.name as the name of the function in the returned string, because ... i. Function.name is supposed to be configurable. Hence, it can be made writable and can be set to any JSValue, or deleted. ii. Function.prototype.toString() is supposed to produce a string that can be eval'ed. Hence, for JS functions, the function name in the produced string must be a legal function name (and not some arbitrary value set in Function.name). For example, while a number is a legal value for Function.name, it is not legal as the function name in the toString() string. Instead, we'll always use the original name from the JS source that the function was parsed from. 2. JSFunction::name() now always return the original name, not the value of the Function.name property. As a result, it also no longer needs an ExecState* arg. If the original name is an empty string, JSFunction::name() will use the inferred name. 3. For JS functions, the original name can be attained from their FunctionExecutable object. For host/native functions (which do not have a FunctionExecutable), we get the "original" name from its NativeExecutable. 4. The m_hostFunctionStubMap now keys its NativeExecutable pointers using the original name, in addition to the native function and constructor pointers. This is needed because we want a different NativeExecutable for functions with a different name (to satisfy (3) above). 5. Changed JSBoundFunction to store the name of its bound function in its NativeExecutable. This will later be used to generate the toString() string. It's Function.name value is eagerly initialized at construction time. 6. Function.name for getters/setters are now prefixed with "get"/"set". This was done both for the JSBoundSlotBaseFunctions and JS definable get/set functions. 7. Added InternalFunction::m_originalName so that we can use it to generate the toString() string. We're storing it as a JSString instead of a WTF::String only because we want InternalFunction to be continue to be trivially destructible. * inspector/JSInjectedScriptHost.cpp: (Inspector::JSInjectedScriptHost::functionDetails): * jit/JITThunks.cpp: (JSC::JITThunks::finalize): (JSC::JITThunks::hostFunctionStub): * jit/JITThunks.h: * runtime/Executable.h: * runtime/FunctionPrototype.cpp: (JSC::functionProtoFuncToString): * runtime/InternalFunction.cpp: (JSC::InternalFunction::finishCreation): (JSC::InternalFunction::visitChildren): (JSC::InternalFunction::name): (JSC::InternalFunction::displayName): * runtime/InternalFunction.h: * runtime/JSBoundFunction.cpp: (JSC::JSBoundFunction::create): (JSC::JSBoundFunction::visitChildren): (JSC::JSBoundFunction::toStringName): Deleted. * runtime/JSBoundFunction.h: (JSC::JSBoundFunction::boundThis): (JSC::JSBoundFunction::boundArgs): (JSC::JSBoundFunction::createStructure): * runtime/JSBoundSlotBaseFunction.cpp: (JSC::boundSlotBaseFunctionCall): (JSC::JSBoundSlotBaseFunction::create): * runtime/JSFunction.cpp: (JSC::JSFunction::initializeRareData): (JSC::JSFunction::name): (JSC::JSFunction::displayName): (JSC::JSFunction::calculatedDisplayName): (JSC::JSFunction::reifyName): * runtime/JSFunction.h: * tests/es6.yaml: LayoutTests: * js/function-toString-vs-name-expected.txt: Added. * js/function-toString-vs-name.html: Added. * js/script-tests/function-toString-vs-name.js: Added. Canonical link: https://commits.webkit.org/173305@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197815 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-09 00:01:09 +00:00
<script src="../resources/js-test-post.js"></script>
</body>
</html>