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/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 39833fd..3611d7b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,156 @@
+2016-03-16 Mark Lam <mark.lam@apple.com>
+
+ Add support for setting Function.name from computed properties.
+ https://bugs.webkit.org/show_bug.cgi?id=155437
+
+ Reviewed by Filip Pizlo.
+
+ 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):
+
2016-03-16 Yusuke Suzuki <utatane.tea@gmail.com>
[ES6] Reflect.set with receiver
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json
index 8b4d65f..ee49a43 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.json
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json
@@ -94,6 +94,7 @@
{ "name" : "op_new_generator_func", "length" : 4 },
{ "name" : "op_new_generator_func_exp", "length" : 4 },
{ "name" : "op_new_arrow_func_exp", "length" : 4 },
+ { "name" : "op_set_function_name", "length" : 3 },
{ "name" : "op_call", "length" : 9 },
{ "name" : "op_tail_call", "length" : 9 },
{ "name" : "op_call_eval", "length" : 9 },
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index 38f3115..5380b43 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -85,6 +85,7 @@
case op_jngreater:
case op_jngreatereq:
case op_jless:
+ case op_set_function_name:
case op_copy_rest: {
ASSERT(opcodeLengths[opcodeID] > 2);
functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
@@ -322,6 +323,7 @@
case op_profile_type:
case op_profile_control_flow:
case op_put_to_arguments:
+ case op_set_function_name:
case op_watchdog:
#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 63a79b9..ff37843 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1371,6 +1371,13 @@
out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
break;
}
+ case op_set_function_name: {
+ int funcReg = (++it)->u.operand;
+ int nameReg = (++it)->u.operand;
+ printLocationAndOp(out, exec, location, it, "set_function_name");
+ out.printf("%s, %s", registerName(funcReg).data(), registerName(nameReg).data());
+ break;
+ }
case op_call: {
printCallOp(out, exec, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos);
break;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 0867bac..8544e2a 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -2820,6 +2820,28 @@
return dst;
}
+void BytecodeGenerator::emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, RegisterID* name)
+{
+ if (valueNode->isFuncExprNode()) {
+ FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(valueNode)->metadata();
+ if (!metadata->ecmaName().isNull())
+ return;
+ } else if (valueNode->isClassExprNode()) {
+ ClassExprNode* classExprNode = static_cast<ClassExprNode*>(valueNode);
+ if (!classExprNode->ecmaName().isNull())
+ return;
+ if (classExprNode->hasStaticProperty(m_vm->propertyNames->name))
+ return;
+ } else
+ return;
+
+ // FIXME: We should use an op_call to an internal function here instead.
+ // https://bugs.webkit.org/show_bug.cgi?id=155547
+ emitOpcode(op_set_function_name);
+ instructions().append(value->index());
+ instructions().append(name->index());
+}
+
RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
{
return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd);
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 3dc888e..c16c676 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -522,6 +522,8 @@
RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
+ void emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, RegisterID* name);
+
RegisterID* emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant);
RegisterID* emitMoveEmptyValue(RegisterID* dst);
RegisterID* emitMove(RegisterID* dst, RegisterID* src);
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());
}
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index e7d8bce..de49856 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -2653,6 +2653,11 @@
break;
}
+ case SetFunctionName: {
+ clobberWorld(node->origin.semantic, clobberLimit);
+ break;
+ }
+
case StoreBarrier: {
filter(node->child1(), SpecCell);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index b6be85e..ae43c80 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -4636,6 +4636,13 @@
}
}
+ case op_set_function_name: {
+ Node* func = get(VirtualRegister(currentInstruction[1].u.operand));
+ Node* name = get(VirtualRegister(currentInstruction[2].u.operand));
+ addToGraph(SetFunctionName, func, name);
+ NEXT_OPCODE(op_set_function_name);
+ }
+
case op_typeof: {
set(VirtualRegister(currentInstruction[1].u.operand),
addToGraph(TypeOf, get(VirtualRegister(currentInstruction[2].u.operand))));
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 8b0bd30a..abe4c4b 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -219,6 +219,7 @@
case op_new_generator_func:
case op_new_generator_func_exp:
case op_new_arrow_func_exp:
+ case op_set_function_name:
case op_create_lexical_environment:
case op_get_parent_scope:
case op_catch:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index ea97f5c..89aa4bc 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -444,6 +444,7 @@
case ToPrimitive:
case In:
case ValueAdd:
+ case SetFunctionName:
read(World);
write(Heap);
return;
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 0cab9df..cbd0bfa 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -263,6 +263,7 @@
case ToIndexString:
case MaterializeNewObject:
case MaterializeCreateActivation:
+ case SetFunctionName:
case StrCat:
case StringReplace:
return true;
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 06807b0..0b4be57 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1439,6 +1439,14 @@
break;
}
+ case SetFunctionName: {
+ // The first child is guaranteed to be a cell because op_set_function_name is only used
+ // on a newly instantiated function object (the first child).
+ fixEdge<KnownCellUse>(node->child1());
+ fixEdge<UntypedUse>(node->child2());
+ break;
+ }
+
case CopyRest: {
fixEdge<KnownCellUse>(node->child1());
fixEdge<KnownInt32Use>(node->child2());
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index fb8dcec..2e788d4 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -308,6 +308,7 @@
macro(In, NodeResultBoolean | NodeMustGenerate) \
macro(ProfileType, NodeMustGenerate) \
macro(ProfileControlFlow, NodeMustGenerate) \
+ macro(SetFunctionName, NodeMustGenerate) \
\
macro(CreateActivation, NodeResultJS) \
\
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 573cf38..aa52f15 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -752,6 +752,7 @@
case ThrowReferenceError:
case ForceOSRExit:
case SetArgument:
+ case SetFunctionName:
case CheckStructure:
case CheckCell:
case CheckNotEmpty:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 4593084..f8fe612 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -262,6 +262,7 @@
case LogicalNot:
case ToPrimitive:
case ToString:
+ case SetFunctionName:
case StrCat:
case CallStringConstructor:
case NewStringObject:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 1e33349..c57c56da 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -5597,6 +5597,20 @@
cellResult(resultGPR, node);
}
+void SpeculativeJIT::compileSetFunctionName(Node* node)
+{
+ SpeculateCellOperand func(this, node->child1());
+ GPRReg funcGPR = func.gpr();
+ JSValueOperand nameValue(this, node->child2());
+ JSValueRegs nameValueRegs = nameValue.jsValueRegs();
+
+ flushRegisters();
+ callOperation(operationSetFunctionName, funcGPR, nameValueRegs);
+ m_jit.exceptionCheck();
+
+ noResult(node);
+}
+
void SpeculativeJIT::compileForwardVarargs(Node* node)
{
LoadVarargsData* data = node->loadVarargsData();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 2ea8874..45813a4 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1548,6 +1548,11 @@
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCall(operation);
}
+ JITCompiler::Call callOperation(V_JITOperation_ECJ operation, GPRReg arg1, JSValueRegs arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR());
+ return appendCall(operation);
+ }
JITCompiler::Call callOperation(V_JITOperation_ECJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
@@ -1927,6 +1932,11 @@
m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1Payload, arg1Tag, arg2Payload, TrustedImm32(JSValue::CellTag), TrustedImmPtr(uid));
return appendCall(operation);
}
+ JITCompiler::Call callOperation(V_JITOperation_ECJ operation, GPRReg arg1, JSValueRegs arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR());
+ return appendCall(operation);
+ }
JITCompiler::Call callOperation(V_JITOperation_ECJJ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, arg3Payload, arg3Tag);
@@ -2379,6 +2389,7 @@
void compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
template <typename ClassType> void compileNewFunctionCommon(GPRReg, Structure*, GPRReg, GPRReg, GPRReg, MacroAssembler::JumpList&, size_t, FunctionExecutable*, ptrdiff_t, ptrdiff_t, ptrdiff_t);
void compileNewFunction(Node*);
+ void compileSetFunctionName(Node*);
void compileForwardVarargs(Node*);
void compileCreateActivation(Node*);
void compileCreateDirectArguments(Node*);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index bb98d5c..edb3986 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4610,6 +4610,10 @@
compileNewFunction(node);
break;
+ case SetFunctionName:
+ compileSetFunctionName(node);
+ break;
+
case In:
compileIn(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 0185604..74dde07 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4594,6 +4594,10 @@
compileNewFunction(node);
break;
+ case SetFunctionName:
+ compileSetFunctionName(node);
+ break;
+
case In:
compileIn(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
index 9559c5a..74d3907 100644
--- a/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
@@ -283,6 +283,11 @@
break;
}
+ case SetFunctionName: {
+ considerBarrier(m_node->child1(), m_node->child2());
+ break;
+ }
+
default:
break;
}
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index d4d9e56..71a2fb2 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -227,6 +227,7 @@
case StringReplace:
case GetRegExpObjectLastIndex:
case SetRegExpObjectLastIndex:
+ case SetFunctionName:
// These are OK.
break;
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index 58eb90d..654bd6f 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -926,6 +926,9 @@
case NewRegexp:
compileNewRegexp();
break;
+ case SetFunctionName:
+ compileSetFunctionName();
+ break;
case StringReplace:
compileStringReplace();
break;
@@ -6548,6 +6551,12 @@
setJSValue(result);
}
+ void compileSetFunctionName()
+ {
+ vmCall(m_out.voidType, m_out.operation(operationSetFunctionName), m_callFrame,
+ lowCell(m_node->child1()), lowJSValue(m_node->child2()));
+ }
+
void compileStringReplace()
{
if (m_node->child1().useKind() == StringUse
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 1c68ded..121245d 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -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.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -298,6 +298,7 @@
DEFINE_OP(op_rshift)
DEFINE_OP(op_unsigned)
DEFINE_OP(op_urshift)
+ DEFINE_OP(op_set_function_name)
DEFINE_OP(op_strcat)
DEFINE_OP(op_stricteq)
DEFINE_OP(op_sub)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index fd70e5f..ac5c872 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -570,6 +570,7 @@
void emit_op_put_setter_by_val(Instruction*);
void emit_op_ret(Instruction*);
void emit_op_rshift(Instruction*);
+ void emit_op_set_function_name(Instruction*);
void emit_op_strcat(Instruction*);
void emit_op_stricteq(Instruction*);
void emit_op_sub(Instruction*);
@@ -791,8 +792,10 @@
MacroAssembler::Call callOperation(F_JITOperation_EFJZZ, RegisterID, RegisterID, int32_t, RegisterID);
MacroAssembler::Call callOperation(V_JITOperation_ESsiJJI, StructureStubInfo*, RegisterID, RegisterID, UniquedStringImpl*);
MacroAssembler::Call callOperation(V_JITOperation_ECIZJJ, RegisterID, UniquedStringImpl*, int32_t, RegisterID, RegisterID);
+ MacroAssembler::Call callOperation(V_JITOperation_ECJ, RegisterID, RegisterID);
#else
MacroAssembler::Call callOperation(V_JITOperation_ESsiJJI, StructureStubInfo*, RegisterID, RegisterID, RegisterID, RegisterID, UniquedStringImpl*);
+ MacroAssembler::Call callOperation(V_JITOperation_ECJ, RegisterID, RegisterID, RegisterID);
#endif
MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID);
MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, ArrayProfile*);
diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h
index 77adc02..7462848 100644
--- a/Source/JavaScriptCore/jit/JITInlines.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2012, 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -558,6 +558,12 @@
return appendCallWithExceptionCheck(operation);
}
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_ECJ operation, RegisterID arg1, RegisterID arg2)
+{
+ setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheck(operation);
+}
+
ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_ECJZC operation, RegisterID regOp1, RegisterID regOp2, int32_t op3, RegisterID regOp4)
{
setupArgumentsWithExecState(regOp1, regOp2, TrustedImm32(op3), regOp4);
@@ -692,6 +698,12 @@
return appendCallWithExceptionCheck(operation);
}
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_ECJ operation, RegisterID arg1, RegisterID arg2Tag, RegisterID arg2Payload)
+{
+ setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
+ return appendCallWithExceptionCheck(operation);
+}
+
ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_ECJZC operation, RegisterID arg1, RegisterID arg2Tag, RegisterID arg2Payload, int32_t arg3, RegisterID arg4)
{
setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, TrustedImm32(arg3), arg4);
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index c083371..0f682cd 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -296,6 +296,13 @@
}
+void JIT::emit_op_set_function_name(Instruction* currentInstruction)
+{
+ emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
+ emitGetVirtualRegister(currentInstruction[2].u.operand, regT1);
+ callOperation(operationSetFunctionName, regT0, regT1);
+}
+
void JIT::emit_op_strcat(Instruction* currentInstruction)
{
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_strcat);
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index e67d80d..ab3d380 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -395,6 +395,15 @@
slowPathCall.call();
}
+void JIT::emit_op_set_function_name(Instruction* currentInstruction)
+{
+ int func = currentInstruction[1].u.operand;
+ int name = currentInstruction[2].u.operand;
+ emitLoadPayload(func, regT1);
+ emitLoad(name, regT3, regT2);
+ callOperation(operationSetFunctionName, regT1, regT3, regT2);
+}
+
void JIT::emit_op_strcat(Instruction* currentInstruction)
{
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_strcat);
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 2d7b93b..f400c2e 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -1017,6 +1017,13 @@
return operationNewFunctionCommon<JSGeneratorFunction>(exec, scope, functionExecutable, true);
}
+void JIT_OPERATION operationSetFunctionName(ExecState* exec, JSCell* funcCell, EncodedJSValue encodedName)
+{
+ JSFunction* func = jsCast<JSFunction*>(funcCell);
+ JSValue name = JSValue::decode(encodedName);
+ func->setFunctionName(exec, name);
+}
+
JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure)
{
VM* vm = &exec->vm();
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 1c4c1a6..61522e0 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -225,6 +225,7 @@
typedef void JIT_OPERATION (*V_JITOperation_ECIZJJ)(ExecState*, JSCell*, UniquedStringImpl*, int32_t, EncodedJSValue, EncodedJSValue);
typedef void JIT_OPERATION (*V_JITOperation_ECJZC)(ExecState*, JSCell*, EncodedJSValue, int32_t, JSCell*);
typedef void JIT_OPERATION (*V_JITOperation_ECCIcf)(ExecState*, JSCell*, JSCell*, InlineCallFrame*);
+typedef void JIT_OPERATION (*V_JITOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
typedef void JIT_OPERATION (*V_JITOperation_ECJJ)(ExecState*, JSCell*, EncodedJSValue, EncodedJSValue);
typedef void JIT_OPERATION (*V_JITOperation_ECPSPS)(ExecState*, JSCell*, void*, size_t, void*, size_t);
typedef void JIT_OPERATION (*V_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
@@ -333,6 +334,7 @@
EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+void JIT_OPERATION operationSetFunctionName(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
UnusedPtr JIT_OPERATION operationHandleWatchdogTimer(ExecState*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index 846bdba..7097f31 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-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
@@ -1083,6 +1083,15 @@
LLINT_RETURN(JSFunction::create(vm, executable, scope));
}
+LLINT_SLOW_PATH_DECL(slow_path_set_function_name)
+{
+ LLINT_BEGIN();
+ JSFunction* func = jsCast<JSFunction*>(LLINT_OP(1).Register::unboxedCell());
+ JSValue name = LLINT_OP_C(2).Register::jsValue();
+ func->setFunctionName(exec, name);
+ LLINT_END();
+}
+
static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, JSValue callee, CodeSpecializationKind kind)
{
UNUSED_PARAM(pc);
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
index 0d5c8da..5942e59 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2014, 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
@@ -102,6 +102,7 @@
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func_exp);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_arrow_func_exp);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_set_function_name);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_size_frame_for_varargs);
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 50584ee..5da377b 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+# Copyright (C) 2011-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
@@ -1471,6 +1471,11 @@
callSlowPath(_llint_slow_path_new_arrow_func_exp)
dispatch(4)
+_llint_op_set_function_name:
+ traceExecution()
+ callSlowPath(_llint_slow_path_set_function_name)
+ dispatch(3)
+
_llint_op_call:
traceExecution()
arrayProfileForCall()
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
index ab6788b..0a20f52 100644
--- a/Source/JavaScriptCore/parser/Nodes.cpp
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
-* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
+* Copyright (C) 2003-2009, 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
@@ -196,6 +196,18 @@
m_functionMode = functionMode;
}
+bool PropertyListNode::hasStaticallyNamedProperty(const Identifier& propName)
+{
+ PropertyListNode* list = this;
+ while (list) {
+ const Identifier* currentNodeName = list->m_node->name();
+ if (currentNodeName && *currentNodeName == propName)
+ return true;
+ list = list->m_next;
+ }
+ return false;
+}
+
VariableEnvironmentNode::VariableEnvironmentNode(VariableEnvironment& lexicalVariables)
{
m_lexicalVariables.swap(lexicalVariables);
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 58f8334..8dc42c3 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -648,6 +648,8 @@
PropertyListNode(const JSTokenLocation&, PropertyNode*);
PropertyListNode(const JSTokenLocation&, PropertyNode*, PropertyListNode*);
+ bool hasStaticallyNamedProperty(const Identifier& propName);
+
private:
RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&);
@@ -1984,6 +1986,8 @@
const Identifier& ecmaName() { return m_ecmaName ? *m_ecmaName : m_name; }
void setEcmaName(const Identifier& name) { m_ecmaName = m_name.isNull() ? &name : &m_name; }
+ bool hasStaticProperty(const Identifier& propName) { return m_staticMethods ? m_staticMethods->hasStaticallyNamedProperty(propName) : false; }
+
private:
RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 1a4e70c..28ee4ae 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -571,6 +571,34 @@
return emptyString();
}
+void JSFunction::setFunctionName(ExecState* exec, JSValue value)
+{
+ // The "name" property may have been already been defined as part of a property list in an
+ // object literal (and therefore reified).
+ if (hasReifiedName())
+ return;
+
+ ASSERT(!isHostFunction());
+ ASSERT(jsExecutable()->ecmaName().isNull());
+ String name;
+ if (value.isSymbol()) {
+ SymbolImpl* uid = asSymbol(value)->privateName().uid();
+ if (uid->isNullSymbol())
+ name = emptyString();
+ else
+ name = makeString("[", String(asSymbol(value)->privateName().uid()), ']');
+ } else {
+ VM& vm = exec->vm();
+ JSString* jsStr = value.toString(exec);
+ if (vm.exception())
+ return;
+ name = jsStr->value(exec);
+ if (vm.exception())
+ return;
+ }
+ reifyName(exec, name);
+}
+
void JSFunction::reifyLength(ExecState* exec)
{
VM& vm = exec->vm();
@@ -588,6 +616,12 @@
void JSFunction::reifyName(ExecState* exec)
{
+ String name = jsExecutable()->ecmaName().string();
+ reifyName(exec, name);
+}
+
+void JSFunction::reifyName(ExecState* exec, String name)
+{
VM& vm = exec->vm();
FunctionRareData* rareData = this->rareData(vm);
@@ -596,8 +630,6 @@
unsigned initialAttributes = DontEnum | ReadOnly;
const Identifier& propID = exec->propertyNames().name;
- String name = jsExecutable()->ecmaName().string();
-
if (jsExecutable()->isGetter())
name = makeString("get ", name);
else if (jsExecutable()->isSetter())
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index ebe48ca..30070d0 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -150,6 +150,8 @@
JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
bool isClassConstructorFunction() const;
+ void setFunctionName(ExecState*, JSValue name);
+
protected:
JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
@@ -191,6 +193,7 @@
bool hasReifiedName() const;
void reifyLength(ExecState*);
void reifyName(ExecState*);
+ void reifyName(ExecState*, String name);
void reifyLazyPropertyIfNeeded(ExecState*, PropertyName propertyName);
friend class LLIntOffsetsExtractor;
diff --git a/Source/JavaScriptCore/tests/es6.yaml b/Source/JavaScriptCore/tests/es6.yaml
index 5087fd5..5e5c3f9 100644
--- a/Source/JavaScriptCore/tests/es6.yaml
+++ b/Source/JavaScriptCore/tests/es6.yaml
@@ -807,7 +807,7 @@
- path: es6/function_name_property_shorthand_methods_no_lexical_binding.js
cmd: runES6 :fail
- path: es6/function_name_property_symbol-keyed_methods.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/function_name_property_variables_class.js
cmd: runES6 :normal
- path: es6/function_name_property_variables_function.js
diff --git a/Source/JavaScriptCore/tests/stress/computed-function-names.js b/Source/JavaScriptCore/tests/stress/computed-function-names.js
new file mode 100644
index 0000000..960553e
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/computed-function-names.js
@@ -0,0 +1,68 @@
+let nullSymbol = Symbol();
+
+let propKeys = [
+ "foo", "", undefined, null, true, false, 0, 10, 1234.567,
+ Symbol("foo"), Symbol(""), nullSymbol,
+];
+
+function toKeyString(x) {
+ if (typeof x === "string")
+ return '"' + x + '"';
+ if (typeof x === "symbol")
+ return x.toString();
+ return "" + x;
+}
+
+function toFuncName(x) {
+ if (typeof x === "symbol") {
+ if (x !== nullSymbol) {
+ let str = x.toString();
+ let key = str.slice(7, str.length - 1);
+ return "[" + key + "]";
+ }
+ return "";
+ }
+ return "" + x;
+}
+
+function shouldBe(title, actual, expected) {
+ if (actual !== expected)
+ throw Error(title + ": actual:" + actual + " expected:" + expected);
+}
+
+function makeObj(propKey, classMethodName) {
+ return {
+ [propKey]: class { static [classMethodName](){} },
+ };
+}
+noInline(makeObj);
+
+for (var i = 0; i < 1000; i++) {
+ for (var k = 0; k < propKeys.length; k++) {
+ let key = propKeys[k];
+ let o = makeObj(key, "prop");
+ shouldBe("typeof o[" + toKeyString(key) + "].name", typeof o[key].name, "string");
+ shouldBe("o[" + toKeyString(key) + "].name", o[key].name, toFuncName(key));
+ }
+
+ for (var k = 0; k < propKeys.length; k++) {
+ let key = propKeys[k];
+ let o = makeObj(key, "name");
+ shouldBe("typeof o[" + toKeyString(key) + "].name", typeof o[key], "function");
+ }
+
+ for (var k = 0; k < propKeys.length; k++) {
+ let key = propKeys[k];
+ let prop = { toString() { return "prop" } };
+ let o = makeObj(key, prop);
+ shouldBe("typeof o[" + toKeyString(key) + "].name", typeof o[key].name, "string");
+ shouldBe("o[" + toKeyString(key) + "].name", o[key].name, toFuncName(key));
+ }
+
+ for (var k = 0; k < propKeys.length; k++) {
+ let key = propKeys[k];
+ let prop = { toString() { return "name" } };
+ let o = makeObj(key, prop);
+ shouldBe("typeof o[" + toKeyString(key) + "].name", typeof o[key], "function");
+ }
+}