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.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@198288 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 679651a..b717ee7 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -511,6 +511,7 @@
                 // Computed accessors.
                 if (node->m_type & PropertyNode::Computed) {
                     RefPtr<RegisterID> propertyName = generator.emitNode(node->m_expression);
+                    generator.emitSetFunctionNameIfNeeded(node->m_assign, value.get(), propertyName.get());
                     if (node->m_type & PropertyNode::Getter)
                         generator.emitPutGetterByVal(dst, propertyName.get(), attribute, value.get());
                     else
@@ -601,6 +602,7 @@
         return;
     }
     RefPtr<RegisterID> propertyName = generator.emitNode(node.m_expression);
+    generator.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyName.get());
     generator.emitDirectPutByVal(newObj, propertyName.get(), value.get());
 }