summaryrefslogtreecommitdiffstats
path: root/js/src/frontend
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-03-20 10:08:54 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-03-20 10:10:12 +0100
commit893a886ea38853a1a3e97bcf135ea3cb616cd69a (patch)
tree5188f8895ce513381917d37115b50f72fb4e64a9 /js/src/frontend
parent7197b308fb97cd8ab7a972df6a3a17a7a265b594 (diff)
parent6085bfdcecc2529c1037f813e70583c2a776677d (diff)
downloadUXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar.gz
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar.lz
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar.xz
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.zip
Add support for the function `name` property.
This resolves #78. Merged remote-tracking branch 'janek/js_function_name_1'
Diffstat (limited to 'js/src/frontend')
-rw-r--r--js/src/frontend/BytecodeCompiler.cpp27
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp141
-rw-r--r--js/src/frontend/BytecodeEmitter.h16
-rw-r--r--js/src/frontend/FullParseHandler.h7
-rw-r--r--js/src/frontend/ParseNode-inl.h2
-rw-r--r--js/src/frontend/ParseNode.cpp18
-rw-r--r--js/src/frontend/ParseNode.h15
-rw-r--r--js/src/frontend/Parser.cpp45
-rw-r--r--js/src/frontend/SharedContext.h8
-rw-r--r--js/src/frontend/SyntaxParseHandler.h3
10 files changed, 221 insertions, 61 deletions
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index 3fbfdaa1a..76afe80b1 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -336,10 +336,10 @@ BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc)
if (!deoptimizeArgumentsInEnclosingScripts(cx->asJSContext(), environment))
return nullptr;
}
- if (!NameFunctions(cx, pn))
- return nullptr;
if (!emitter->emitScript(pn))
return nullptr;
+ if (!NameFunctions(cx, pn))
+ return nullptr;
parser->handler.freeTree(pn);
break;
@@ -397,15 +397,15 @@ BytecodeCompiler::compileModule()
if (!pn)
return nullptr;
- if (!NameFunctions(cx, pn))
- return nullptr;
-
Maybe<BytecodeEmitter> emitter;
if (!emplaceEmitter(emitter, &modulesc))
return nullptr;
if (!emitter->emitScript(pn->pn_body))
return nullptr;
+ if (!NameFunctions(cx, pn))
+ return nullptr;
+
parser->handler.freeTree(pn);
if (!builder.initModule())
@@ -453,9 +453,6 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
return false;
} while (!fn);
- if (!NameFunctions(cx, fn))
- return false;
-
if (fn->pn_funbox->function()->isInterpreted()) {
MOZ_ASSERT(fun == fn->pn_funbox->function());
@@ -472,6 +469,9 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
MOZ_ASSERT(IsAsmJSModule(fun));
}
+ if (!NameFunctions(cx, fn))
+ return false;
+
if (!maybeCompleteCompressSource())
return false;
@@ -646,9 +646,6 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
if (!pn)
return false;
- if (!NameFunctions(cx, pn))
- return false;
-
RootedScriptSource sourceObject(cx, lazy->sourceObject());
MOZ_ASSERT(sourceObject);
@@ -667,7 +664,13 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
if (!bce.init())
return false;
- return bce.emitFunctionScript(pn->pn_body);
+ if (!bce.emitFunctionScript(pn->pn_body))
+ return false;
+
+ if (!NameFunctions(cx, pn))
+ return false;
+
+ return true;
}
bool
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 1e9d8f224..acf734794 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1053,7 +1053,7 @@ BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox*
if (p) {
MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
MOZ_ASSERT(!funbox->hasDestructuringArgs);
- MOZ_ASSERT(!funbox->function()->hasRest());
+ MOZ_ASSERT(!funbox->hasRest());
p->value() = loc;
continue;
}
@@ -4070,7 +4070,7 @@ BytecodeEmitter::isRunOnceLambda()
FunctionBox* funbox = sc->asFunctionBox();
return !funbox->argumentsHasLocalBinding() &&
!funbox->isGenerator() &&
- !funbox->function()->name();
+ !funbox->function()->explicitName();
}
bool
@@ -4463,7 +4463,7 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, DestructuringFlavor fla
}
bool
-BytecodeEmitter::emitConditionallyExecutedDestructuringLHS(ParseNode* target, DestructuringFlavor flav)
+BytecodeEmitter::emitDestructuringLHSInBranch(ParseNode* target, DestructuringFlavor flav)
{
TDZCheckCache tdzCache(this);
return emitDestructuringLHS(target, flav);
@@ -4491,7 +4491,7 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted)
}
bool
-BytecodeEmitter::emitDefault(ParseNode* defaultExpr)
+BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern)
{
if (!emit1(JSOP_DUP)) // VALUE VALUE
return false;
@@ -4507,13 +4507,77 @@ BytecodeEmitter::emitDefault(ParseNode* defaultExpr)
return false;
if (!emit1(JSOP_POP)) // .
return false;
- if (!emitConditionallyExecutedTree(defaultExpr)) // DEFAULTVALUE
+ if (!emitInitializerInBranch(defaultExpr, pattern)) // DEFAULTVALUE
return false;
if (!emitJumpTargetAndPatch(jump))
return false;
return true;
}
+bool
+BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
+ FunctionPrefixKind prefixKind)
+{
+ if (maybeFun->isKind(PNK_FUNCTION)) {
+ // Function doesn't have 'name' property at this point.
+ // Set function's name at compile time.
+ RootedFunction fun(cx, maybeFun->pn_funbox->function());
+
+ // Single node can be emitted multiple times if it appears in
+ // array destructuring default. If function already has a name,
+ // just return.
+ if (fun->hasCompileTimeName()) {
+#ifdef DEBUG
+ RootedAtom funName(cx, NameToFunctionName(cx, name, prefixKind));
+ if (!funName)
+ return false;
+ MOZ_ASSERT(funName == maybeFun->pn_funbox->function()->compileTimeName());
+#endif
+ return true;
+ }
+
+ RootedAtom funName(cx, NameToFunctionName(cx, name, prefixKind));
+ if (!funName)
+ return false;
+ fun->setCompileTimeName(name);
+ return true;
+ }
+
+ uint32_t nameIndex;
+ if (!makeAtomIndex(name, &nameIndex))
+ return false;
+ if (!emitIndexOp(JSOP_STRING, nameIndex)) // FUN NAME
+ return false;
+ uint8_t kind = uint8_t(prefixKind);
+ if (!emit2(JSOP_SETFUNNAME, kind)) // FUN
+ return false;
+ return true;
+}
+
+bool
+BytecodeEmitter::emitInitializer(ParseNode* initializer, ParseNode* pattern)
+{
+ if (!emitTree(initializer))
+ return false;
+
+ if (!pattern->isInParens() && pattern->isKind(PNK_NAME) &&
+ initializer->isDirectRHSAnonFunction())
+ {
+ RootedAtom name(cx, pattern->name());
+ if (!setOrEmitSetFunName(initializer, name, FunctionPrefixKind::None))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BytecodeEmitter::emitInitializerInBranch(ParseNode* initializer, ParseNode* pattern)
+{
+ TDZCheckCache tdzCache(this);
+ return emitInitializer(initializer, pattern);
+}
+
class MOZ_STACK_CLASS IfThenElseEmitter
{
BytecodeEmitter* bce_;
@@ -4765,7 +4829,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
return false;
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ? ARRAY
return false;
- if (!emitConditionallyExecutedDestructuringLHS(member, flav)) // ... OBJ?
+ if (!emitDestructuringLHSInBranch(member, flav)) // ... OBJ?
return false;
if (!ifThenElse.emitElse()) // ... OBJ? ITER
@@ -4782,7 +4846,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
return false;
if (!emit1(JSOP_POP)) // ... OBJ? ARRAY
return false;
- if (!emitConditionallyExecutedDestructuringLHS(member, flav)) // ... OBJ?
+ if (!emitDestructuringLHSInBranch(member, flav)) // ... OBJ?
return false;
if (!isHead) {
@@ -4834,7 +4898,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
if (pndefault) {
// Emit only pndefault tree here, as undefined check in emitDefault
// should always be true.
- if (!emitConditionallyExecutedTree(pndefault)) // ... OBJ? ITER VALUE
+ if (!emitInitializerInBranch(pndefault, subpattern)) // ... OBJ? ITER VALUE
return false;
} else {
if (!isElision) {
@@ -4845,7 +4909,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
}
}
if (!isElision) {
- if (!emitConditionallyExecutedDestructuringLHS(subpattern, flav)) // ... OBJ? ITER
+ if (!emitDestructuringLHSInBranch(subpattern, flav)) // ... OBJ? ITER
return false;
} else if (pndefault) {
if (!emit1(JSOP_POP)) // ... OBJ? ITER
@@ -4872,12 +4936,12 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
return false;
if (pndefault) {
- if (!emitDefault(pndefault)) // ... OBJ? ITER VALUE
+ if (!emitDefault(pndefault, subpattern)) // ... OBJ? ITER VALUE
return false;
}
if (!isElision) {
- if (!emitConditionallyExecutedDestructuringLHS(subpattern, flav)) // ... OBJ? ITER
+ if (!emitDestructuringLHSInBranch(subpattern, flav)) // ... OBJ? ITER
return false;
} else {
if (!emit1(JSOP_POP)) // ... OBJ? ITER
@@ -4980,7 +5044,7 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla
return false;
if (subpattern->isKind(PNK_ASSIGN)) {
- if (!emitDefault(subpattern->pn_right))
+ if (!emitDefault(subpattern->pn_right, subpattern->pn_left))
return false;
subpattern = subpattern->pn_left;
}
@@ -5094,7 +5158,7 @@ BytecodeEmitter::emitSingleDeclaration(ParseNode* declList, ParseNode* decl,
if (!initializer && declList->isKind(PNK_VAR))
return true;
- auto emitRhs = [initializer, declList](BytecodeEmitter* bce, const NameLocation&, bool) {
+ auto emitRhs = [initializer, declList, decl](BytecodeEmitter* bce, const NameLocation&, bool) {
if (!initializer) {
// Lexical declarations are initialized to undefined without an
// initializer.
@@ -5105,7 +5169,7 @@ BytecodeEmitter::emitSingleDeclaration(ParseNode* declList, ParseNode* decl,
}
MOZ_ASSERT(initializer);
- return bce->emitTree(initializer);
+ return bce->emitInitializer(initializer, decl);
};
if (!emitInitializeName(decl, emitRhs))
@@ -5164,6 +5228,12 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
if (!EmitAssignmentRhs(bce, rhs, emittedBindOp ? 2 : 1))
return false;
+ if (!lhs->isInParens() && op == JSOP_NOP && rhs && rhs->isDirectRHSAnonFunction()) {
+ RootedAtom name(bce->cx, lhs->name());
+ if (!bce->setOrEmitSetFunName(rhs, name, FunctionPrefixKind::None))
+ return false;
+ }
+
// Emit the compound assignment op if there is one.
if (op != JSOP_NOP && !bce->emit1(op))
return false;
@@ -5788,7 +5858,7 @@ BytecodeEmitter::emitIf(ParseNode* pn)
if_again:
/* Emit code for the condition before pushing stmtInfo. */
- if (!emitConditionallyExecutedTree(pn->pn_kid1))
+ if (!emitTreeInBranch(pn->pn_kid1))
return false;
ParseNode* elseNode = pn->pn_kid3;
@@ -5801,7 +5871,7 @@ BytecodeEmitter::emitIf(ParseNode* pn)
}
/* Emit code for the then part. */
- if (!emitConditionallyExecutedTree(pn->pn_kid2))
+ if (!emitTreeInBranch(pn->pn_kid2))
return false;
if (elseNode) {
@@ -5814,7 +5884,7 @@ BytecodeEmitter::emitIf(ParseNode* pn)
}
/* Emit code for the else part. */
- if (!emitConditionallyExecutedTree(elseNode))
+ if (!emitTreeInBranch(elseNode))
return false;
}
@@ -6283,8 +6353,8 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
if (!updateSourceCoordNotes(decl->pn_pos.begin))
return false;
- auto emitRhs = [initializer](BytecodeEmitter* bce, const NameLocation&, bool) {
- return bce->emitTree(initializer);
+ auto emitRhs = [decl, initializer](BytecodeEmitter* bce, const NameLocation&, bool) {
+ return bce->emitInitializer(initializer, decl);
};
if (!emitInitializeName(decl, emitRhs))
@@ -6504,7 +6574,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
if (jmp.offset == -1 && !emitLoopEntry(forBody, jmp))
return false;
- if (!emitConditionallyExecutedTree(forBody))
+ if (!emitTreeInBranch(forBody))
return false;
// Set loop and enclosing "update" offsets, for continue. Note that we
@@ -6903,7 +6973,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
{
FunctionBox* funbox = pn->pn_funbox;
RootedFunction fun(cx, funbox->function());
- RootedAtom name(cx, fun->name());
+ RootedAtom name(cx, fun->explicitName());
MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
MOZ_ASSERT_IF(pn->isOp(JSOP_FUNWITHPROTO), needsProto);
@@ -7284,7 +7354,7 @@ BytecodeEmitter::emitWhile(ParseNode* pn)
if (!emitLoopHead(pn->pn_right, &top))
return false;
- if (!emitConditionallyExecutedTree(pn->pn_right))
+ if (!emitTreeInBranch(pn->pn_right))
return false;
if (!emitLoopEntry(pn->pn_left, jmp))
@@ -8017,7 +8087,7 @@ BytecodeEmitter::isRestParameter(ParseNode* pn, bool* result)
FunctionBox* funbox = sc->asFunctionBox();
RootedFunction fun(cx, funbox->function());
- if (!fun->hasRest()) {
+ if (!funbox->hasRest()) {
*result = false;
return true;
}
@@ -8449,13 +8519,13 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional)
if (!ifThenElse.emitCond())
return false;
- if (!emitConditionallyExecutedTree(&conditional.thenExpression()))
+ if (!emitTreeInBranch(&conditional.thenExpression()))
return false;
if (!ifThenElse.emitElse())
return false;
- if (!emitConditionallyExecutedTree(&conditional.elseExpression()))
+ if (!emitTreeInBranch(&conditional.elseExpression()))
return false;
if (!ifThenElse.emitEnd())
@@ -8532,6 +8602,10 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
op == JSOP_INITPROP_GETTER ||
op == JSOP_INITPROP_SETTER);
+ FunctionPrefixKind prefixKind = op == JSOP_INITPROP_GETTER ? FunctionPrefixKind::Get
+ : op == JSOP_INITPROP_SETTER ? FunctionPrefixKind::Set
+ : FunctionPrefixKind::None;
+
if (op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER)
objp.set(nullptr);
@@ -8573,6 +8647,12 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
case JSOP_INITHIDDENPROP_SETTER: op = JSOP_INITHIDDENELEM_SETTER; break;
default: MOZ_CRASH("Invalid op");
}
+ if (propdef->pn_right->isDirectRHSAnonFunction()) {
+ if (!emitDupAt(1))
+ return false;
+ if (!emit2(JSOP_SETFUNNAME, uint8_t(prefixKind)))
+ return false;
+ }
if (!emit1(op))
return false;
} else {
@@ -8597,6 +8677,11 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
objp.set(nullptr);
}
+ if (propdef->pn_right->isDirectRHSAnonFunction()) {
+ RootedAtom keyName(cx, key->pn_atom);
+ if (!setOrEmitSetFunName(propdef->pn_right, keyName, prefixKind))
+ return false;
+ }
if (!emitIndex32(op, index))
return false;
}
@@ -8960,7 +9045,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
EmitterScope* funScope = innermostEmitterScope;
bool hasParameterExprs = funbox->hasParameterExprs;
- bool hasRest = funbox->function()->hasRest();
+ bool hasRest = funbox->hasRest();
uint16_t argSlot = 0;
for (ParseNode* arg = pn->pn_head; arg != funBody; arg = arg->pn_next, argSlot++) {
@@ -9017,7 +9102,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
return false;
if (!emit1(JSOP_POP))
return false;
- if (!emitConditionallyExecutedTree(initializer))
+ if (!emitInitializerInBranch(initializer, bindingElement))
return false;
if (!emitJumpTargetAndPatch(jump))
return false;
@@ -9728,7 +9813,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
}
bool
-BytecodeEmitter::emitConditionallyExecutedTree(ParseNode* pn)
+BytecodeEmitter::emitTreeInBranch(ParseNode* pn)
{
// Code that may be conditionally executed always need their own TDZ
// cache.
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 1bb4191ee..9a2ddb568 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -435,7 +435,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
// Emit code for the tree rooted at pn with its own TDZ cache.
- MOZ_MUST_USE bool emitConditionallyExecutedTree(ParseNode* pn);
+ MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn);
// Emit global, eval, or module code for tree rooted at body. Always
// encompasses the entire source.
@@ -648,8 +648,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// the stack and emits code to destructure a single lhs expression (either a
// name or a compound []/{} expression).
MOZ_MUST_USE bool emitDestructuringLHS(ParseNode* target, DestructuringFlavor flav);
- MOZ_MUST_USE bool emitConditionallyExecutedDestructuringLHS(ParseNode* target,
- DestructuringFlavor flav);
+ MOZ_MUST_USE bool emitDestructuringLHSInBranch(ParseNode* target, DestructuringFlavor flav);
// emitDestructuringOps assumes the to-be-destructured value has been
// pushed on the stack and emits code to destructure each part of a [] or
@@ -678,7 +677,16 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// Check if the value on top of the stack is "undefined". If so, replace
// that value on the stack with the value defined by |defaultExpr|.
- MOZ_MUST_USE bool emitDefault(ParseNode* defaultExpr);
+ // |pattern| is a lhs node of the default expression. If it's an
+ // identifier and |defaultExpr| is an anonymous function, |SetFunctionName|
+ // is called at compile time.
+ MOZ_MUST_USE bool emitDefault(ParseNode* defaultExpr, ParseNode* pattern);
+
+ MOZ_MUST_USE bool setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
+ FunctionPrefixKind prefixKind);
+
+ MOZ_MUST_USE bool emitInitializer(ParseNode* initializer, ParseNode* pattern);
+ MOZ_MUST_USE bool emitInitializerInBranch(ParseNode* initializer, ParseNode* pattern);
MOZ_MUST_USE bool emitCallSiteObject(ParseNode* pn);
MOZ_MUST_USE bool emitTemplateString(ParseNode* pn);
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index add881900..0fd137796 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -665,6 +665,11 @@ class FullParseHandler
ParseNode* pn);
inline void setLastFunctionFormalParameterDestructuring(ParseNode* funcpn, ParseNode* pn);
+ void checkAndSetIsDirectRHSAnonFunction(ParseNode* pn) {
+ if (IsAnonymousFunctionDefinition(pn))
+ pn->setDirectRHSAnonFunction(true);
+ }
+
ParseNode* newFunctionDefinition() {
return new_<CodeNode>(PNK_FUNCTION, pos());
}
@@ -942,6 +947,8 @@ FullParseHandler::setLastFunctionFormalParameterDefault(ParseNode* funcpn, Parse
if (!pn)
return false;
+ checkAndSetIsDirectRHSAnonFunction(defaultValue);
+
funcpn->pn_body->pn_pos.end = pn->pn_pos.end;
ParseNode* pnchild = funcpn->pn_body->pn_head;
ParseNode* pnlast = funcpn->pn_body->last();
diff --git a/js/src/frontend/ParseNode-inl.h b/js/src/frontend/ParseNode-inl.h
index 395d09b5b..21bd83766 100644
--- a/js/src/frontend/ParseNode-inl.h
+++ b/js/src/frontend/ParseNode-inl.h
@@ -18,7 +18,7 @@ inline PropertyName*
ParseNode::name() const
{
MOZ_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME));
- JSAtom* atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->name() : pn_atom;
+ JSAtom* atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->explicitName() : pn_atom;
return atom->asPropertyName();
}
diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp
index f79baba9e..ece3a45df 100644
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -902,3 +902,21 @@ FunctionBox::trace(JSTracer* trc)
if (enclosingScope_)
TraceRoot(trc, &enclosingScope_, "funbox-enclosingScope");
}
+
+bool
+js::frontend::IsAnonymousFunctionDefinition(ParseNode* pn)
+{
+ // ES 2017 draft
+ // 12.15.2 (ArrowFunction, AsyncArrowFunction).
+ // 14.1.12 (FunctionExpression).
+ // 14.4.8 (GeneratorExpression).
+ // 14.6.8 (AsyncFunctionExpression)
+ if (pn->isKind(PNK_FUNCTION) && !pn->pn_funbox->function()->explicitName())
+ return true;
+
+ // 14.5.8 (ClassExpression)
+ if (pn->is<ClassNode>() && !pn->as<ClassNode>().names())
+ return true;
+
+ return false;
+}
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index d37aaaae0..ff26279af 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -450,6 +450,9 @@ class ParseNode
uint8_t pn_op; /* see JSOp enum and jsopcode.tbl */
uint8_t pn_arity:4; /* see ParseNodeArity enum */
bool pn_parens:1; /* this expr was enclosed in parens */
+ bool pn_rhs_anon_fun:1; /* this expr is anonymous function or class that
+ * is a direct RHS of PNK_ASSIGN or PNK_COLON of
+ * property, that needs SetFunctionName. */
ParseNode(const ParseNode& other) = delete;
void operator=(const ParseNode& other) = delete;
@@ -460,6 +463,7 @@ class ParseNode
pn_op(op),
pn_arity(arity),
pn_parens(false),
+ pn_rhs_anon_fun(false),
pn_pos(0, 0),
pn_next(nullptr)
{
@@ -472,6 +476,7 @@ class ParseNode
pn_op(op),
pn_arity(arity),
pn_parens(false),
+ pn_rhs_anon_fun(false),
pn_pos(pos),
pn_next(nullptr)
{
@@ -512,6 +517,13 @@ class ParseNode
bool isLikelyIIFE() const { return isInParens(); }
void setInParens(bool enabled) { pn_parens = enabled; }
+ bool isDirectRHSAnonFunction() const {
+ return pn_rhs_anon_fun;
+ }
+ void setDirectRHSAnonFunction(bool enabled) {
+ pn_rhs_anon_fun = enabled;
+ }
+
TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
ParseNode* pn_next; /* intrinsic link in parent PN_LIST */
@@ -1444,6 +1456,9 @@ FunctionFormalParametersList(ParseNode* fn, unsigned* numFormals)
return argsBody->pn_head;
}
+bool
+IsAnonymousFunctionDefinition(ParseNode* pn);
+
} /* namespace frontend */
} /* namespace js */
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index f42546eb5..f4c02720a 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -326,10 +326,14 @@ ParseContext::init()
if (fun->isNamedLambda()) {
if (!namedLambdaScope_->init(this))
return false;
- AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(fun->name());
+ AddDeclaredNamePtr p =
+ namedLambdaScope_->lookupDeclaredNameForAdd(fun->explicitName());
MOZ_ASSERT(!p);
- if (!namedLambdaScope_->addDeclaredName(this, p, fun->name(), DeclarationKind::Const))
+ if (!namedLambdaScope_->addDeclaredName(this, p, fun->explicitName(),
+ DeclarationKind::Const))
+ {
return false;
+ }
}
if (!functionScope_->init(this))
@@ -367,7 +371,7 @@ ParseContext::removeInnerFunctionBoxesForAnnexB(JSAtom* name)
{
for (uint32_t i = 0; i < innerFunctionBoxesForAnnexB_->length(); i++) {
if (FunctionBox* funbox = innerFunctionBoxesForAnnexB_[i]) {
- if (funbox->function()->name() == name)
+ if (funbox->function()->explicitName() == name)
innerFunctionBoxesForAnnexB_[i] = nullptr;
}
}
@@ -465,6 +469,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
usesApply(false),
usesThis(false),
usesReturn(false),
+ hasRest_(false),
funCxFlags()
{
// Functions created at parse time may be set singleton after parsing and
@@ -477,7 +482,6 @@ void
FunctionBox::initFromLazyFunction()
{
JSFunction* fun = function();
- length = fun->nargs() - fun->hasRest();
if (fun->lazyScript()->isDerivedClassConstructor())
setDerivedClassConstructor();
if (fun->lazyScript()->needsHomeObject())
@@ -492,8 +496,6 @@ FunctionBox::initStandaloneFunction(Scope* enclosingScope)
// Standalone functions are Function or Generator constructors and are
// always scoped to the global.
MOZ_ASSERT(enclosingScope->is<GlobalScope>());
- JSFunction* fun = function();
- length = fun->nargs() - fun->hasRest();
enclosingScope_ = enclosingScope;
allowNewTarget_ = true;
thisBinding_ = ThisBinding::Function;
@@ -836,7 +838,7 @@ Parser<ParseHandler>::reportBadReturn(Node pn, ParseReportKind kind,
unsigned errnum, unsigned anonerrnum)
{
JSAutoByteString name;
- if (JSAtom* atom = pc->functionBox()->function()->name()) {
+ if (JSAtom* atom = pc->functionBox()->function()->explicitName()) {
if (!AtomToPrintableString(context, atom, &name))
return false;
} else {
@@ -2214,6 +2216,8 @@ Parser<SyntaxParseHandler>::finishFunction()
lazy->setStrict();
lazy->setGeneratorKind(funbox->generatorKind());
lazy->setAsyncKind(funbox->asyncKind());
+ if (funbox->hasRest())
+ lazy->setHasRest();
if (funbox->isLikelyConstructorWrapper())
lazy->setLikelyConstructorWrapper();
if (funbox->isDerivedClassConstructor())
@@ -2757,7 +2761,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
}
hasRest = true;
- funbox->function()->setHasRest();
+ funbox->setHasRest();
if (!tokenStream.getToken(&tt))
return false;
@@ -3477,8 +3481,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!body)
return false;
- if ((kind != Method && !IsConstructorKind(kind)) && fun->name()) {
- RootedPropertyName propertyName(context, fun->name()->asPropertyName());
+ if ((kind != Method && !IsConstructorKind(kind)) && fun->explicitName()) {
+ RootedPropertyName propertyName(context, fun->explicitName()->asPropertyName());
if (!checkStrictBinding(propertyName, handler.getPosition(pn)))
return false;
}
@@ -4337,6 +4341,8 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To
if (!init)
return null();
+ handler.checkAndSetIsDirectRHSAnonFunction(init);
+
if (forHeadKind) {
// For for(;;) declarations, consistency with |for (;| parsing requires
// that the ';' first be examined as Operand, even though absence of a
@@ -4366,6 +4372,8 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
if (!initializer)
return false;
+ handler.checkAndSetIsDirectRHSAnonFunction(initializer);
+
if (forHeadKind) {
if (initialDeclaration) {
bool isForIn, isForOf;
@@ -5063,7 +5071,7 @@ Parser<FullParseHandler>::exportDeclaration()
if (!kid)
return null();
- if (!checkExportedName(kid->pn_funbox->function()->name()))
+ if (!checkExportedName(kid->pn_funbox->function()->explicitName()))
return null();
break;
@@ -6670,8 +6678,6 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
}
- // FIXME: Implement ES6 function "name" property semantics
- // (bug 883377).
RootedAtom funName(context);
switch (propType) {
case PropertyType::GetterNoExpressionClosure:
@@ -6694,6 +6700,8 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!fn)
return null();
+ handler.checkAndSetIsDirectRHSAnonFunction(fn);
+
JSOp op = JSOpFromPropertyType(propType);
if (!handler.addClassMethodDefinition(classMethods, propName, fn, op, isStatic))
return null();
@@ -7753,6 +7761,9 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return null();
}
+ if (kind == PNK_ASSIGN)
+ handler.checkAndSetIsDirectRHSAnonFunction(rhs);
+
return handler.newAssignment(kind, lhs, rhs, op);
}
@@ -9155,6 +9166,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (!propExpr)
return null();
+ handler.checkAndSetIsDirectRHSAnonFunction(propExpr);
+
if (foldConstants && !FoldConstants(context, &propExpr, this))
return null();
@@ -9268,6 +9281,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
return null();
}
+ handler.checkAndSetIsDirectRHSAnonFunction(rhs);
+
Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
if (!propExpr)
return null();
@@ -9278,8 +9293,6 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (!abortIfSyntaxParser())
return null();
} else {
- // FIXME: Implement ES6 function "name" property semantics
- // (bug 883377).
RootedAtom funName(context);
if (!tokenStream.isCurrentTokenType(TOK_RB)) {
funName = propAtom;
@@ -9295,6 +9308,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (!fn)
return null();
+ handler.checkAndSetIsDirectRHSAnonFunction(fn);
+
JSOp op = JSOpFromPropertyType(propType);
if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
return null();
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index 39df47c20..a6ac542f6 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -471,6 +471,7 @@ class FunctionBox : public ObjectBox, public SharedContext
bool usesApply:1; /* contains an f.apply() call */
bool usesThis:1; /* contains 'this' */
bool usesReturn:1; /* contains a 'return' statement */
+ bool hasRest_:1; /* has rest parameter */
FunctionContextFlags funCxFlags;
@@ -539,6 +540,11 @@ class FunctionBox : public ObjectBox, public SharedContext
bool isAsync() const { return asyncKind() == AsyncFunction; }
bool isArrow() const { return function()->isArrow(); }
+ bool hasRest() const { return hasRest_; }
+ void setHasRest() {
+ hasRest_ = true;
+ }
+
void setGeneratorKind(GeneratorKind kind) {
// A generator kind can be set at initialization, or when "yield" is
// first seen. In both cases the transition can only happen from
@@ -567,7 +573,7 @@ class FunctionBox : public ObjectBox, public SharedContext
void setHasInnerFunctions() { funCxFlags.hasInnerFunctions = true; }
bool hasSimpleParameterList() const {
- return !function()->hasRest() && !hasParameterExprs && !hasDestructuringArgs;
+ return !hasRest() && !hasParameterExprs && !hasDestructuringArgs;
}
bool hasMappedArgsObj() const {
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index 75c7e3333..b7f00605b 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -339,6 +339,9 @@ class SyntaxParseHandler
Node catchGuard, Node catchBody) { return true; }
MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(Node funcpn, Node pn) { return true; }
+
+ void checkAndSetIsDirectRHSAnonFunction(Node pn) {}
+
Node newFunctionDefinition() { return NodeFunctionDefinition; }
bool setComprehensionLambdaBody(Node pn, Node body) { return true; }
void setFunctionFormalParametersAndBody(Node pn, Node kid) {}