Part 1: Implement ES6 function name property semantics

Issue #78
This commit is contained in:
janekptacijarabaci 2018-03-19 15:47:10 +01:00 • committed by Roy Tam
commit 748c69d7fd
30 changed files with 750 additions and 81 deletions

View file

@ -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;