haikuwebkit/LayoutTests/js/object-literal-computed-met...

67 lines
3.8 KiB
Plaintext
Raw Permalink Normal View History

basic tests for object literal computed methods
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS o = { ['f'+'oo']() { return 10; } }; did not throw exception.
PASS o.foo() is 10
PASS typeof o.foo is 'function'
PASS o.foo.length is 0
Add support for setting Function.name from computed properties. https://bugs.webkit.org/show_bug.cgi?id=155437 Reviewed by Filip Pizlo. Source/JavaScriptCore: In JS code, we can have initialization of computed properties with function and class objects e.g. var o = { [x]: function() {}, [y]: class {} } The ES6 spec states that the function and class in the example above (being anonymous) should take on the value of x and y respectively as their names: o[x].name; // should be the "stringified" value of x. o[y].name; // should be the "stringified" value of y. To achieve this, we will now inject an op_set_function_name bytecode at property initialization sites if: 1. the property assigned value is a function or class, and 2. the function and class is anonymous, and 3. if property assigned value is a class, it doesn't have a static method that is statically named "name". The op_set_function_name will result in JSFunction::setFunctionName() being called on the target function / class before it is assigned to the property. JSFunction::setFunctionName() will take care of: 1. computing the name to use from the value of the computed property name e.g. x and y in the example above. If the computed property name is not a symbol, then the function / class name should be the toString() value of that computed property name. If the computed property name is a symbol, then ... a. if the Symbol has a defined description (e.g. Symbol("foo")), then the function / class name should be "[<symbol description>]" e.g. "[foo]". b. if the Symbol has an undefined description (e.g. Symbol()), then the function / class name should be "". Note: Symbol("") is not the same as Symbol(). The former has a defined descriptor "", and hence, yields a function / class name of "[]". The latter yields a function / class name of "". 2. reifying the lazy name property with this function / class name. op_set_function_name is named after the SetFunctionName internal function in the ES6 spec that performs the above operation. It is behaviorally correct to use op_set_function_name at every property initialization site with computed property names. However, we choose to not emit the op_set_function_name bytecode when we already know that it will do nothing i.e. when the target function / class is proven to already have a name or name property. This is done as an optimization to avoid unnecessary calls to JSFunction::setFunctionName(). Note: we could further check if the class has a static method with a computed name that is a constant string "name" and elide op_set_function_name there too. However, we don't bother because this should be rare. JSFunction::setFunctionName() will still do the right thing. * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): (JSC::computeDefsForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitNewFunction): (JSC::BytecodeGenerator::emitSetFunctionNameIfNeeded): (JSC::BytecodeGenerator::emitCall): * bytecompiler/BytecodeGenerator.h: * bytecompiler/NodesCodegen.cpp: (JSC::PropertyListNode::emitBytecode): (JSC::PropertyListNode::emitPutConstantProperty): * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGCapabilities.cpp: (JSC::DFG::capabilityLevel): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGNodeType.h: * dfg/DFGPredictionPropagationPhase.cpp: (JSC::DFG::PredictionPropagationPhase::propagate): * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileNewFunction): (JSC::DFG::SpeculativeJIT::compileSetFunctionName): (JSC::DFG::SpeculativeJIT::compileForwardVarargs): * dfg/DFGSpeculativeJIT.h: (JSC::DFG::SpeculativeJIT::callOperation): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGStoreBarrierInsertionPhase.cpp: * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp): (JSC::FTL::DFG::LowerDFGToB3::compileSetFunctionName): (JSC::FTL::DFG::LowerDFGToB3::compileStringReplace): * jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): * jit/JIT.h: * jit/JITInlines.h: (JSC::JIT::callOperation): * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_to_primitive): (JSC::JIT::emit_op_set_function_name): (JSC::JIT::emit_op_strcat): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emitSlow_op_to_primitive): (JSC::JIT::emit_op_set_function_name): (JSC::JIT::emit_op_strcat): * jit/JITOperations.cpp: * jit/JITOperations.h: * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::handleHostCall): * llint/LLIntSlowPaths.h: * llint/LowLevelInterpreter.asm: * parser/Nodes.cpp: (JSC::FunctionNode::finishParsing): (JSC::PropertyListNode::hasStaticallyNamedProperty): (JSC::VariableEnvironmentNode::VariableEnvironmentNode): * parser/Nodes.h: * runtime/JSFunction.cpp: (JSC::getCalculatedDisplayName): (JSC::JSFunction::setFunctionName): (JSC::JSFunction::reifyLength): (JSC::JSFunction::reifyName): * runtime/JSFunction.h: * tests/es6.yaml: * tests/stress/computed-function-names.js: Added. (toKeyString): (toFuncName): (shouldBe): (return.propKey): LayoutTests: * js/object-literal-computed-methods-expected.txt: - Exercise op_set_function_name at all tiers. * js/script-tests/function-toString-vs-name.js: - Added tests for computed properties. * js/script-tests/object-literal-computed-methods.js: - rebased results. Canonical link: https://commits.webkit.org/173666@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198288 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-16 18:16:32 +00:00
PASS o.foo.name is 'foo'
ES6: Object Literal Methods toString is missing method name https://bugs.webkit.org/show_bug.cgi?id=142992 Patch by Joseph Pecoraro <pecoraro@apple.com> on 2015-03-24 Reviewed by Geoffrey Garen. Source/JavaScriptCore: Always stringify functions in the pattern: "function " + <function name> + <text from opening parenthesis to closing brace>. * runtime/FunctionPrototype.cpp: (JSC::functionProtoFuncToString): Update the path that was not stringifying in this pattern. * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedFunctionExecutable::parametersStartOffset): * parser/Nodes.h: * runtime/Executable.cpp: (JSC::FunctionExecutable::FunctionExecutable): * runtime/Executable.h: (JSC::FunctionExecutable::parametersStartOffset): Pass the already known function parameter opening parenthesis start offset through to the FunctionExecutable. * tests/mozilla/js1_5/Scope/regress-185485.js: (with.g): Add back original space in this test that was removed by r181810 now that we have the space again in stringification. LayoutTests: * js/class-syntax-default-constructor-expected.txt: This test was already failing, it now fails in a different way. * js/object-literal-computed-methods-expected.txt: * js/object-literal-methods-expected.txt: These tests now pass. * fast/dom/TreeWalker/acceptNode-filter-expected.txt: * js/destructuring-assignment-expected.txt: * js/dfg-redundant-load-of-captured-variable-proven-constant-expected.txt: * js/dfg-resolve-global-specific-dictionary-expected.txt: * js/dom/JSON-parse-expected.txt: * js/dom/JSON-stringify-expected.txt: * js/dom/dfg-strcat-over-objects-then-exit-on-it-expected.txt: * js/dom/function-prototype-expected.txt: * js/dom/toString-and-valueOf-override-expected.txt: * js/kde/lval-exceptions-expected.txt: * storage/domstorage/localstorage/string-conversion-expected.txt: * storage/domstorage/sessionstorage/string-conversion-expected.txt: * js/dom/script-tests/dfg-strcat-over-objects-then-exit-on-it.js: * js/script-tests/dfg-redundant-load-of-captured-variable-proven-constant.js: * js/script-tests/dfg-resolve-global-specific-dictionary.js: * js/dom/function-prototype.html: Update tests to add expected whitespace for stringifying a function with no name. Canonical link: https://commits.webkit.org/161029@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181901 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-03-24 20:07:26 +00:00
PASS o.foo.toString() is 'function () { return 10; }'
PASS Object.getOwnPropertyDescriptor(o, 'foo').value is o.foo
PASS Object.getOwnPropertyDescriptor(o, 'foo').enumerable is true
PASS Object.getOwnPropertyDescriptor(o, 'foo').configurable is true
PASS Object.getOwnPropertyDescriptor(o, 'foo').writable is true
PASS methodName = 'add'; o = { [methodName](x, y) { return x + y; } }; did not throw exception.
PASS o.add(42, -10) is 32
PASS typeof o.add is 'function'
PASS o.add.length is 2
Add support for setting Function.name from computed properties. https://bugs.webkit.org/show_bug.cgi?id=155437 Reviewed by Filip Pizlo. Source/JavaScriptCore: In JS code, we can have initialization of computed properties with function and class objects e.g. var o = { [x]: function() {}, [y]: class {} } The ES6 spec states that the function and class in the example above (being anonymous) should take on the value of x and y respectively as their names: o[x].name; // should be the "stringified" value of x. o[y].name; // should be the "stringified" value of y. To achieve this, we will now inject an op_set_function_name bytecode at property initialization sites if: 1. the property assigned value is a function or class, and 2. the function and class is anonymous, and 3. if property assigned value is a class, it doesn't have a static method that is statically named "name". The op_set_function_name will result in JSFunction::setFunctionName() being called on the target function / class before it is assigned to the property. JSFunction::setFunctionName() will take care of: 1. computing the name to use from the value of the computed property name e.g. x and y in the example above. If the computed property name is not a symbol, then the function / class name should be the toString() value of that computed property name. If the computed property name is a symbol, then ... a. if the Symbol has a defined description (e.g. Symbol("foo")), then the function / class name should be "[<symbol description>]" e.g. "[foo]". b. if the Symbol has an undefined description (e.g. Symbol()), then the function / class name should be "". Note: Symbol("") is not the same as Symbol(). The former has a defined descriptor "", and hence, yields a function / class name of "[]". The latter yields a function / class name of "". 2. reifying the lazy name property with this function / class name. op_set_function_name is named after the SetFunctionName internal function in the ES6 spec that performs the above operation. It is behaviorally correct to use op_set_function_name at every property initialization site with computed property names. However, we choose to not emit the op_set_function_name bytecode when we already know that it will do nothing i.e. when the target function / class is proven to already have a name or name property. This is done as an optimization to avoid unnecessary calls to JSFunction::setFunctionName(). Note: we could further check if the class has a static method with a computed name that is a constant string "name" and elide op_set_function_name there too. However, we don't bother because this should be rare. JSFunction::setFunctionName() will still do the right thing. * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): (JSC::computeDefsForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitNewFunction): (JSC::BytecodeGenerator::emitSetFunctionNameIfNeeded): (JSC::BytecodeGenerator::emitCall): * bytecompiler/BytecodeGenerator.h: * bytecompiler/NodesCodegen.cpp: (JSC::PropertyListNode::emitBytecode): (JSC::PropertyListNode::emitPutConstantProperty): * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGCapabilities.cpp: (JSC::DFG::capabilityLevel): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGNodeType.h: * dfg/DFGPredictionPropagationPhase.cpp: (JSC::DFG::PredictionPropagationPhase::propagate): * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileNewFunction): (JSC::DFG::SpeculativeJIT::compileSetFunctionName): (JSC::DFG::SpeculativeJIT::compileForwardVarargs): * dfg/DFGSpeculativeJIT.h: (JSC::DFG::SpeculativeJIT::callOperation): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGStoreBarrierInsertionPhase.cpp: * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp): (JSC::FTL::DFG::LowerDFGToB3::compileSetFunctionName): (JSC::FTL::DFG::LowerDFGToB3::compileStringReplace): * jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): * jit/JIT.h: * jit/JITInlines.h: (JSC::JIT::callOperation): * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_to_primitive): (JSC::JIT::emit_op_set_function_name): (JSC::JIT::emit_op_strcat): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emitSlow_op_to_primitive): (JSC::JIT::emit_op_set_function_name): (JSC::JIT::emit_op_strcat): * jit/JITOperations.cpp: * jit/JITOperations.h: * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::handleHostCall): * llint/LLIntSlowPaths.h: * llint/LowLevelInterpreter.asm: * parser/Nodes.cpp: (JSC::FunctionNode::finishParsing): (JSC::PropertyListNode::hasStaticallyNamedProperty): (JSC::VariableEnvironmentNode::VariableEnvironmentNode): * parser/Nodes.h: * runtime/JSFunction.cpp: (JSC::getCalculatedDisplayName): (JSC::JSFunction::setFunctionName): (JSC::JSFunction::reifyLength): (JSC::JSFunction::reifyName): * runtime/JSFunction.h: * tests/es6.yaml: * tests/stress/computed-function-names.js: Added. (toKeyString): (toFuncName): (shouldBe): (return.propKey): LayoutTests: * js/object-literal-computed-methods-expected.txt: - Exercise op_set_function_name at all tiers. * js/script-tests/function-toString-vs-name.js: - Added tests for computed properties. * js/script-tests/object-literal-computed-methods.js: - rebased results. Canonical link: https://commits.webkit.org/173666@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198288 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-03-16 18:16:32 +00:00
PASS o.add.name is 'add'
ES6: Object Literal Methods toString is missing method name https://bugs.webkit.org/show_bug.cgi?id=142992 Patch by Joseph Pecoraro <pecoraro@apple.com> on 2015-03-24 Reviewed by Geoffrey Garen. Source/JavaScriptCore: Always stringify functions in the pattern: "function " + <function name> + <text from opening parenthesis to closing brace>. * runtime/FunctionPrototype.cpp: (JSC::functionProtoFuncToString): Update the path that was not stringifying in this pattern. * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedFunctionExecutable::parametersStartOffset): * parser/Nodes.h: * runtime/Executable.cpp: (JSC::FunctionExecutable::FunctionExecutable): * runtime/Executable.h: (JSC::FunctionExecutable::parametersStartOffset): Pass the already known function parameter opening parenthesis start offset through to the FunctionExecutable. * tests/mozilla/js1_5/Scope/regress-185485.js: (with.g): Add back original space in this test that was removed by r181810 now that we have the space again in stringification. LayoutTests: * js/class-syntax-default-constructor-expected.txt: This test was already failing, it now fails in a different way. * js/object-literal-computed-methods-expected.txt: * js/object-literal-methods-expected.txt: These tests now pass. * fast/dom/TreeWalker/acceptNode-filter-expected.txt: * js/destructuring-assignment-expected.txt: * js/dfg-redundant-load-of-captured-variable-proven-constant-expected.txt: * js/dfg-resolve-global-specific-dictionary-expected.txt: * js/dom/JSON-parse-expected.txt: * js/dom/JSON-stringify-expected.txt: * js/dom/dfg-strcat-over-objects-then-exit-on-it-expected.txt: * js/dom/function-prototype-expected.txt: * js/dom/toString-and-valueOf-override-expected.txt: * js/kde/lval-exceptions-expected.txt: * storage/domstorage/localstorage/string-conversion-expected.txt: * storage/domstorage/sessionstorage/string-conversion-expected.txt: * js/dom/script-tests/dfg-strcat-over-objects-then-exit-on-it.js: * js/script-tests/dfg-redundant-load-of-captured-variable-proven-constant.js: * js/script-tests/dfg-resolve-global-specific-dictionary.js: * js/dom/function-prototype.html: Update tests to add expected whitespace for stringifying a function with no name. Canonical link: https://commits.webkit.org/161029@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181901 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-03-24 20:07:26 +00:00
PASS o.add.toString() is 'function (x, y) { return x + y; }'
PASS o = { [ (function() { return 'method'; })() ](x, y) { return x + y; } }; did not throw exception.
PASS o.method(142, -10) is 132
PASS o = { [10*10]() { return 100; } }; did not throw exception.
PASS o[100]() is 100
PASS o['100']() is 100
PASS o = { [100 + 0.100]() { return 100.100; } }; did not throw exception.
PASS o[100.1]() is 100.1
PASS o['100.1']() is 100.1
PASS o = { ['a' + 'dd']([x, y]) { return x + y; } }; did not throw exception.
PASS o.add([142, -100]) is 42
PASS o = { [Array]([x, y]) { return x + y; } }; did not throw exception.
PASS o[Array.toString()]([142, -100]) is 42
PASS o = { foo() { return 10; }, }; did not throw exception.
PASS o = { foo ( ) { return 10; } }; did not throw exception.
PASS o = {[true](){return true;}}; did not throw exception.
PASS o = {[NaN](){return NaN;}}; did not throw exception.
PASS o = {[eval](){return eval;}}; did not throw exception.
PASS o = { a:1, [foo]() { return 10; }, [bar]() { return 20; }, b: 2 }; did not throw exception.
PASS o = { a:1, [foo]() { return 10; }, [bar]() { return 20; }, b }; did not throw exception.
PASS o = { a:1, [foo]() { return 10; }, b: b, [bar]() { return 20; }, c: 2 }; did not throw exception.
PASS o = { a:1, [foo]() { return 10; }, b, [bar]() { return 20; }, c }; did not throw exception.
PASS o = {[foo]:{[bar](){ return 100; }}}; did not throw exception.
PASS o.foo.bar() is 100
PASS o = { [foo]() { return 10; }, [foo]() { return 20; } }; did not throw exception.
PASS o.foo() is 20
PASS o = { ['get'](x, y) { return x + y; } }; did not throw exception.
PASS o.get('hello', 'world') is 'helloworld'
PASS o = { ['set'](x, y) { return x + y; } }; did not throw exception.
PASS o.set('hello', 'world') is 'helloworld'
PASS ({ [](,,,){} }) threw exception SyntaxError: Unexpected token ']'.
PASS ({ [1+](){} }) threw exception SyntaxError: Unexpected token ']'.
PASS ({ [1,](){} }) threw exception SyntaxError: Unexpected token ','. Expected ']' to end a computed property name..
PASS ({ [1,'name'](){} }) threw exception SyntaxError: Unexpected token ','. Expected ']' to end a computed property name..
PASS ({ [[1](){} }) threw exception SyntaxError: Unexpected token '{'. Expected ']' to end a computed property name..
PASS ({ [foo](,,,){} }) threw exception SyntaxError: Unexpected token ','. Expected a parameter pattern or a ')' in parameter list..
PASS ({ [foo](a{}, bar(){} }) threw exception SyntaxError: Unexpected token '{'. Expected a ')' or a ',' after a parameter declaration..
PASS ({ [foo](a, b), bar(){} }) threw exception SyntaxError: Unexpected token ','. Expected an opening '{' at the start of a method body..
PASS ({ [foo](a, b) { if }, bar(){} }) threw exception SyntaxError: Unexpected token '}'. Expected '(' to start an 'if' condition..
PASS ({__proto__: function(){}}) instanceof Function is true
PASS ({['__proto__'](){}}) instanceof Function is false
PASS ({['__proto__'](){}}).__proto__ instanceof Function is true
PASS successfullyParsed is true
TEST COMPLETE