mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-04 06:17:30 +09:00
Issue #2142 - Set anonymous function name in field initializer
This was done wildly different in m-c 1552875, in the interest of keeping |setOrEmitSetFunName| around it is implemented differently here.
This commit is contained in:
parent
f0b06f5ad6
commit
c206114966
3 changed files with 66 additions and 14 deletions
|
|
@ -1234,7 +1234,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||||
MOZ_ASSERT(pn->is<AssignmentNode>());
|
MOZ_ASSERT(pn->is<AssignmentNode>());
|
||||||
*answer = true;
|
*answer = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case PNK_SETTHIS:
|
case PNK_SETTHIS:
|
||||||
MOZ_ASSERT(pn->is<BinaryNode>());
|
MOZ_ASSERT(pn->is<BinaryNode>());
|
||||||
*answer = true;
|
*answer = true;
|
||||||
|
|
@ -1385,7 +1385,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||||
MOZ_ASSERT(pn->is<ListNode>());
|
MOZ_ASSERT(pn->is<ListNode>());
|
||||||
*answer = true;
|
*answer = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case PNK_OPTCHAIN:
|
case PNK_OPTCHAIN:
|
||||||
MOZ_ASSERT(pn->is<UnaryNode>());
|
MOZ_ASSERT(pn->is<UnaryNode>());
|
||||||
*answer = true;
|
*answer = true;
|
||||||
|
|
@ -3002,6 +3002,21 @@ BytecodeEmitter::emitSetClassConstructorName(JSAtom* name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BytecodeEmitter::emitSetFunctionNameFromStack(uint8_t offset)
|
||||||
|
{
|
||||||
|
// [stack] KEY ... FUN
|
||||||
|
if (!emitDupAt(offset))
|
||||||
|
return false;
|
||||||
|
// [stack] KEY ... FUN KEY
|
||||||
|
uint8_t kind = uint8_t(FunctionPrefixKind::None);
|
||||||
|
if (!emit2(JSOP_SETFUNNAME, kind)) {
|
||||||
|
// [stack] KEY ... FUN
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitInitializer(ParseNode* initializer, ParseNode* pattern)
|
BytecodeEmitter::emitInitializer(ParseNode* initializer, ParseNode* pattern)
|
||||||
{
|
{
|
||||||
|
|
@ -3715,6 +3730,23 @@ BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
||||||
Maybe<ElemOpEmitter> eoe;
|
Maybe<ElemOpEmitter> eoe;
|
||||||
|
|
||||||
uint8_t offset = 1;
|
uint8_t offset = 1;
|
||||||
|
// Anonymous functions get their inferred name in simple assignments:
|
||||||
|
// x = function() {}; // x.name === "x"
|
||||||
|
// In this case, rhs->isDirectRHSAnonFunction() from parsing the statement.
|
||||||
|
// To suppress this, put the variable in parentheses:
|
||||||
|
// (x) = function() {}; // x.name === undefined
|
||||||
|
// In normal property assignments (`obj.x = function(){}`), the anonymous
|
||||||
|
// function does not have a computed name and rhs->isDirectRHSAnonFunction()==false.
|
||||||
|
// However, in field initializers (`class C { x = function(){} }`), field
|
||||||
|
// initialization is implemented via a property or elem assignment *and*
|
||||||
|
// rhs->isDirectRHSAnonFunction() is set. In this case (detected by `isInit`),
|
||||||
|
// we'll assign the name of the function using the same plumbing as binding assignments.
|
||||||
|
// For PNK_NAME and PNK_DOT, the name is compile-time constant, and is stored in `anonFunctionName`.
|
||||||
|
// For PNK_ELEM, we grab it from the stack before emitting the actual assignment.
|
||||||
|
RootedAtom anonFunctionName(cx);
|
||||||
|
bool inferFunctionName = !isCompound &&
|
||||||
|
rhs && rhs->isDirectRHSAnonFunction() && !lhs->isInParens() &&
|
||||||
|
(lhs->isKind(PNK_NAME) || isInit);
|
||||||
|
|
||||||
switch (lhs->getKind()) {
|
switch (lhs->getKind()) {
|
||||||
case PNK_NAME: {
|
case PNK_NAME: {
|
||||||
|
|
@ -3723,6 +3755,9 @@ BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
||||||
isCompound
|
isCompound
|
||||||
? NameOpEmitter::Kind::CompoundAssignment
|
? NameOpEmitter::Kind::CompoundAssignment
|
||||||
: NameOpEmitter::Kind::SimpleAssignment);
|
: NameOpEmitter::Kind::SimpleAssignment);
|
||||||
|
if (inferFunctionName) {
|
||||||
|
anonFunctionName = lhs->name();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PNK_DOT: {
|
case PNK_DOT: {
|
||||||
|
|
@ -3739,6 +3774,9 @@ BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
||||||
if (!poe->prepareForObj()) {
|
if (!poe->prepareForObj()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (inferFunctionName) {
|
||||||
|
anonFunctionName = &prop->name();
|
||||||
|
}
|
||||||
if (isSuper) {
|
if (isSuper) {
|
||||||
UnaryNode* base = &prop->expression().as<UnaryNode>();
|
UnaryNode* base = &prop->expression().as<UnaryNode>();
|
||||||
if (!emitGetThisForSuperBase(base)) { // THIS SUPERBASE
|
if (!emitGetThisForSuperBase(base)) { // THIS SUPERBASE
|
||||||
|
|
@ -3869,14 +3907,23 @@ BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
||||||
if (!EmitAssignmentRhs(this, rhs, offset)) // ... VAL? RHS
|
if (!EmitAssignmentRhs(this, rhs, offset)) // ... VAL? RHS
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (lhs->isKind(PNK_NAME)) {
|
// Assign inferred function name
|
||||||
// Assign inferred function name, unless the lhs is parenthesized
|
if (inferFunctionName) {
|
||||||
if (rhs && rhs->isDirectRHSAnonFunction() && !lhs->isInParens()) {
|
MOZ_ASSERT(!isCompound);
|
||||||
MOZ_ASSERT(!isCompound);
|
if (anonFunctionName) {
|
||||||
RootedAtom name(cx, lhs->name());
|
// Name is an atom known at compile time
|
||||||
if (!setOrEmitSetFunName(rhs, name)) { // ENV? VAL? RHS
|
MOZ_ASSERT_IF(!lhs->isKind(PNK_NAME), isInit);
|
||||||
|
if (!setOrEmitSetFunName(rhs, anonFunctionName)) { // ENV? VAL? RHS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (lhs->isKind(PNK_ELEM)) {
|
||||||
|
// offset points to the SP relative to RHS. // [Simple,Super] offset = 4
|
||||||
|
// Find KEY relative to that. // {offset} THIS KEY SUPERBASE FUN
|
||||||
|
// // [Simple,Other] offset = 3
|
||||||
|
// // {offset} OBJ KEY FUN
|
||||||
|
MOZ_ASSERT(offset >= 2);
|
||||||
|
if (!emitSetFunctionNameFromStack(offset - 2))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6977,7 +7024,7 @@ BytecodeEmitter::isRestParameter(ParseNode* pn)
|
||||||
|
|
||||||
FunctionBox* funbox = sc->asFunctionBox();
|
FunctionBox* funbox = sc->asFunctionBox();
|
||||||
RootedFunction fun(cx, funbox->function());
|
RootedFunction fun(cx, funbox->function());
|
||||||
if (!funbox->hasRest())
|
if (!funbox->hasRest())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!pn->isKind(PNK_NAME)) {
|
if (!pn->isKind(PNK_NAME)) {
|
||||||
|
|
@ -7750,7 +7797,7 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
||||||
// [stack] CTOR? OBJ CTOR? KEY VAL
|
// [stack] CTOR? OBJ CTOR? KEY VAL
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case JSOP_INITPROP:
|
case JSOP_INITPROP:
|
||||||
if (!pe.emitInitIndexProp(isPropertyAnonFunctionOrClass)) {
|
if (!pe.emitInitIndexProp(isPropertyAnonFunctionOrClass)) {
|
||||||
|
|
@ -7838,7 +7885,7 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
||||||
break;
|
break;
|
||||||
default: MOZ_CRASH("Invalid op");
|
default: MOZ_CRASH("Invalid op");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7896,7 +7943,7 @@ FieldInitializers
|
||||||
BytecodeEmitter::setupFieldInitializers(ListNode* classMembers)
|
BytecodeEmitter::setupFieldInitializers(ListNode* classMembers)
|
||||||
{
|
{
|
||||||
size_t numFields = 0;
|
size_t numFields = 0;
|
||||||
|
|
||||||
for (ParseNode* propdef : classMembers->contents()) {
|
for (ParseNode* propdef : classMembers->contents()) {
|
||||||
if (propdef->is<ClassField>()) {
|
if (propdef->is<ClassField>()) {
|
||||||
FunctionNode* initializer = propdef->as<ClassField>().initializer();
|
FunctionNode* initializer = propdef->as<ClassField>().initializer();
|
||||||
|
|
@ -9220,7 +9267,7 @@ BytecodeEmitter::emitOptionalTree(
|
||||||
ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
ParseNodeKind kind = pn->getKind();
|
ParseNodeKind kind = pn->getKind();
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case PNK_OPTDOT: {
|
case PNK_OPTDOT: {
|
||||||
|
|
@ -9477,7 +9524,7 @@ AllocSrcNote(ExclusiveContext* cx, SrcNotesVector& notes, unsigned* index)
|
||||||
ReportAllocationOverflow(cx);
|
ReportAllocationOverflow(cx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notes.growBy(1)) {
|
if (!notes.growBy(1)) {
|
||||||
ReportOutOfMemory(cx);
|
ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -690,6 +690,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
MOZ_MUST_USE bool setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name);
|
MOZ_MUST_USE bool setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name);
|
||||||
MOZ_MUST_USE bool setFunName(JSFunction* fun, JSAtom* name);
|
MOZ_MUST_USE bool setFunName(JSFunction* fun, JSAtom* name);
|
||||||
MOZ_MUST_USE bool emitSetClassConstructorName(JSAtom* name);
|
MOZ_MUST_USE bool emitSetClassConstructorName(JSAtom* name);
|
||||||
|
MOZ_MUST_USE bool emitSetFunctionNameFromStack(uint8_t offset);
|
||||||
|
|
||||||
MOZ_MUST_USE bool emitInitializer(ParseNode* initializer, ParseNode* pattern);
|
MOZ_MUST_USE bool emitInitializer(ParseNode* initializer, ParseNode* pattern);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8005,6 +8005,10 @@ Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH
|
||||||
if (!initializerExpr)
|
if (!initializerExpr)
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In `class { x = function() {} }`, the anon function can get a name.
|
||||||
|
handler.checkAndSetIsDirectRHSAnonFunction(initializerExpr);
|
||||||
|
|
||||||
wholeInitializerPos = pos();
|
wholeInitializerPos = pos();
|
||||||
wholeInitializerPos.begin = firstTokenPos.begin;
|
wholeInitializerPos.begin = firstTokenPos.begin;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue