From 75db97cb3772fc0693947ec17c5954a04cb234a8 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 14:48:24 +0100 Subject: Bug 1320388: Move JSFunction::HAS_REST to JSScript and LazyScript Issue #78 [Depends on] Bug 883377: Implement ES6 function "name" property semantics --- js/src/frontend/BytecodeEmitter.cpp | 6 +++--- js/src/frontend/Parser.cpp | 8 ++++---- js/src/frontend/SharedContext.h | 8 +++++++- 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'js/src/frontend') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 1e9d8f224..6ceb3ed7a 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; } @@ -8017,7 +8017,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; } @@ -8960,7 +8960,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++) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f42546eb5..78e47ceb3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -465,6 +465,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 +478,6 @@ void FunctionBox::initFromLazyFunction() { JSFunction* fun = function(); - length = fun->nargs() - fun->hasRest(); if (fun->lazyScript()->isDerivedClassConstructor()) setDerivedClassConstructor(); if (fun->lazyScript()->needsHomeObject()) @@ -492,8 +492,6 @@ FunctionBox::initStandaloneFunction(Scope* enclosingScope) // Standalone functions are Function or Generator constructors and are // always scoped to the global. MOZ_ASSERT(enclosingScope->is()); - JSFunction* fun = function(); - length = fun->nargs() - fun->hasRest(); enclosingScope_ = enclosingScope; allowNewTarget_ = true; thisBinding_ = ThisBinding::Function; @@ -2214,6 +2212,8 @@ Parser::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 +2757,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } hasRest = true; - funbox->function()->setHasRest(); + funbox->setHasRest(); if (!tokenStream.getToken(&tt)) return false; 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 { -- cgit v1.2.3 From 213f9ea384c71eac84667d65a21dc96e422798db Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 14:55:56 +0100 Subject: Bug 1320042: Rename BytecodeEmitter::emitConditionallyExecuted{SOMETHING} to BytecodeEmitter::emit{SOMETHING}InBranch Issue #78 [Depends on] Bug 883377: Implement ES6 function "name" property semantics --- js/src/frontend/BytecodeEmitter.cpp | 32 ++++++++++++++++---------------- js/src/frontend/BytecodeEmitter.h | 5 ++--- 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'js/src/frontend') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 6ceb3ed7a..0a1b4ffe1 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -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); @@ -4507,7 +4507,7 @@ BytecodeEmitter::emitDefault(ParseNode* defaultExpr) return false; if (!emit1(JSOP_POP)) // . return false; - if (!emitConditionallyExecutedTree(defaultExpr)) // DEFAULTVALUE + if (!emitTreeInBranch(defaultExpr)) // DEFAULTVALUE return false; if (!emitJumpTargetAndPatch(jump)) return false; @@ -4765,7 +4765,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 +4782,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 +4834,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 (!emitTreeInBranch(pndefault)) // ... OBJ? ITER VALUE return false; } else { if (!isElision) { @@ -4845,7 +4845,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 @@ -4877,7 +4877,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav } if (!isElision) { - if (!emitConditionallyExecutedDestructuringLHS(subpattern, flav)) // ... OBJ? ITER + if (!emitDestructuringLHSInBranch(subpattern, flav)) // ... OBJ? ITER return false; } else { if (!emit1(JSOP_POP)) // ... OBJ? ITER @@ -5788,7 +5788,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 +5801,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 +5814,7 @@ BytecodeEmitter::emitIf(ParseNode* pn) } /* Emit code for the else part. */ - if (!emitConditionallyExecutedTree(elseNode)) + if (!emitTreeInBranch(elseNode)) return false; } @@ -6504,7 +6504,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 @@ -7284,7 +7284,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)) @@ -8449,13 +8449,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()) @@ -9017,7 +9017,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) return false; if (!emit1(JSOP_POP)) return false; - if (!emitConditionallyExecutedTree(initializer)) + if (!emitTreeInBranch(initializer)) return false; if (!emitJumpTargetAndPatch(jump)) return false; @@ -9728,7 +9728,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..08e0eb54f 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 -- cgit v1.2.3 From 5ef44cf6484b9dfd49c0174ac2969a29587a1bbd Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 15:47:10 +0100 Subject: Part 1: Implement ES6 function name property semantics Issue #78 --- js/src/frontend/BytecodeEmitter.cpp | 111 +++++++++++++++++++++++++++++++---- js/src/frontend/BytecodeEmitter.h | 11 +++- js/src/frontend/FullParseHandler.h | 7 +++ js/src/frontend/ParseNode-inl.h | 2 +- js/src/frontend/ParseNode.cpp | 18 ++++++ js/src/frontend/ParseNode.h | 15 +++++ js/src/frontend/Parser.cpp | 35 +++++++---- js/src/frontend/SyntaxParseHandler.h | 3 + 8 files changed, 178 insertions(+), 24 deletions(-) (limited to 'js/src/frontend') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 0a1b4ffe1..205bbf3d9 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4070,7 +4070,7 @@ BytecodeEmitter::isRunOnceLambda() FunctionBox* funbox = sc->asFunctionBox(); return !funbox->argumentsHasLocalBinding() && !funbox->isGenerator() && - !funbox->function()->name(); + !funbox->function()->explicitName(); } bool @@ -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,79 @@ BytecodeEmitter::emitDefault(ParseNode* defaultExpr) return false; if (!emit1(JSOP_POP)) // . return false; - if (!emitTreeInBranch(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; + if (fun->hasGuessedAtom()) + fun->clearGuessedAtom(); + 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_; @@ -4834,7 +4900,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav if (pndefault) { // Emit only pndefault tree here, as undefined check in emitDefault // should always be true. - if (!emitTreeInBranch(pndefault)) // ... OBJ? ITER VALUE + if (!emitInitializerInBranch(pndefault, subpattern)) // ... OBJ? ITER VALUE return false; } else { if (!isElision) { @@ -4872,7 +4938,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav return false; if (pndefault) { - if (!emitDefault(pndefault)) // ... OBJ? ITER VALUE + if (!emitDefault(pndefault, subpattern)) // ... OBJ? ITER VALUE return false; } @@ -4980,7 +5046,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 +5160,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 +5171,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 +5230,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; @@ -6283,8 +6355,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)) @@ -6903,7 +6975,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); @@ -8532,6 +8604,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 +8649,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 +8679,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; } @@ -9017,7 +9104,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) return false; if (!emit1(JSOP_POP)) return false; - if (!emitTreeInBranch(initializer)) + if (!emitInitializerInBranch(initializer, bindingElement)) return false; if (!emitJumpTargetAndPatch(jump)) return false; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 08e0eb54f..9a2ddb568 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -677,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_(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() && !pn->as().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 78e47ceb3..3106702cf 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; } } @@ -3477,8 +3481,8 @@ Parser::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::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::initializerInNameDeclaration(Node decl, Node binding, if (!initializer) return false; + handler.checkAndSetIsDirectRHSAnonFunction(initializer); + if (forHeadKind) { if (initialDeclaration) { bool isForIn, isForOf; @@ -5063,7 +5071,7 @@ Parser::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::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::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::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::objectLiteral(YieldHandling yieldHandling, PossibleError* if (!propExpr) return null(); + handler.checkAndSetIsDirectRHSAnonFunction(propExpr); + if (foldConstants && !FoldConstants(context, &propExpr, this)) return null(); @@ -9268,6 +9281,8 @@ Parser::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::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::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/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) {} -- cgit v1.2.3 From f67a2b88d7e8780f4ae81419338004b6fd781567 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 15:51:02 +0100 Subject: Part 2: Call NameFunctions after emitting Issue #78 --- js/src/frontend/BytecodeCompiler.cpp | 27 +++++++++++++++------------ js/src/frontend/BytecodeEmitter.cpp | 2 -- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'js/src/frontend') 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 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 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 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 205bbf3d9..457218178 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4539,8 +4539,6 @@ BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name, RootedAtom funName(cx, NameToFunctionName(cx, name, prefixKind)); if (!funName) return false; - if (fun->hasGuessedAtom()) - fun->clearGuessedAtom(); fun->setCompileTimeName(name); return true; } -- cgit v1.2.3 From 6085bfdcecc2529c1037f813e70583c2a776677d Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 18:11:08 +0100 Subject: Follow up: A opening bracket { was added; Added "function()->explicitName()" instead of "function()->name()" Issue #78 --- js/src/frontend/BytecodeEmitter.cpp | 2 +- js/src/frontend/Parser.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'js/src/frontend') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 457218178..acf734794 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5158,7 +5158,7 @@ BytecodeEmitter::emitSingleDeclaration(ParseNode* declList, ParseNode* decl, if (!initializer && declList->isKind(PNK_VAR)) return true; - auto emitRhs = [initializer, declList, decl](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. diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3106702cf..f4c02720a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -838,7 +838,7 @@ Parser::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 { -- cgit v1.2.3