2015-03-06 22:31:28 +00:00
|
|
|
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'
|
2015-03-24 20:07:26 +00:00
|
|
|
PASS o.foo.toString() is 'function () { return 10; }'
|
2015-03-06 22:31:28 +00:00
|
|
|
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'
|
2015-03-24 20:07:26 +00:00
|
|
|
PASS o.add.toString() is 'function (x, y) { return x + y; }'
|
2015-03-06 22:31:28 +00:00
|
|
|
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 ']'.
|
2015-03-22 03:14:47 +00:00
|
|
|
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..
|
2015-03-06 22:31:28 +00:00
|
|
|
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..
|
2016-05-04 21:05:16 +00:00
|
|
|
PASS ({ [foo](a, b) { if }, bar(){} }) threw exception SyntaxError: Unexpected token '}'. Expected '(' to start an 'if' condition..
|
2015-03-06 22:31:28 +00:00
|
|
|
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
|
|
|
|
|