mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-29 10:37:33 +09:00
Issue #2173 - Store the info about the existence of the default case into the switch ParseNode
Based-on: m-c 1477157
This commit is contained in:
parent
fa1193b8c9
commit
36b5a56242
6 changed files with 68 additions and 27 deletions
|
|
@ -2047,23 +2047,23 @@ BytecodeEmitter::emitNumberOp(double dval)
|
||||||
* into emitTree which is recursive and uses relatively little stack space.
|
* into emitTree which is recursive and uses relatively little stack space.
|
||||||
*/
|
*/
|
||||||
MOZ_NEVER_INLINE bool
|
MOZ_NEVER_INLINE bool
|
||||||
BytecodeEmitter::emitSwitch(ParseNode* pn)
|
BytecodeEmitter::emitSwitch(SwitchStatement* pn)
|
||||||
{
|
{
|
||||||
ParseNode* lexical = pn->pn_right;
|
ParseNode& lexical = pn->lexicalForCaseList();
|
||||||
MOZ_ASSERT(lexical->isKind(PNK_LEXICALSCOPE));
|
MOZ_ASSERT(lexical.isKind(PNK_LEXICALSCOPE));
|
||||||
ParseNode* cases = lexical->scopeBody();
|
ParseNode* cases = lexical.scopeBody();
|
||||||
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
|
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
|
||||||
|
|
||||||
SwitchEmitter se(this);
|
SwitchEmitter se(this);
|
||||||
if (!se.emitDiscriminant(Some(pn->pn_pos.begin)))
|
if (!se.emitDiscriminant(Some(pn->pn_pos.begin)))
|
||||||
return false;
|
return false;
|
||||||
if (!emitTree(pn->pn_left))
|
if (!emitTree(&pn->discriminant()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Enter the scope before pushing the switch BreakableControl since all
|
// Enter the scope before pushing the switch BreakableControl since all
|
||||||
// breaks are under this scope.
|
// breaks are under this scope.
|
||||||
if (!lexical->isEmptyScope()) {
|
if (!lexical.isEmptyScope()) {
|
||||||
if (!se.emitLexical(lexical->scopeBindings()))
|
if (!se.emitLexical(lexical.scopeBindings()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// A switch statement may contain hoisted functions inside its
|
// A switch statement may contain hoisted functions inside its
|
||||||
|
|
@ -2082,34 +2082,26 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
SwitchEmitter::TableGenerator tableGen(this);
|
SwitchEmitter::TableGenerator tableGen(this);
|
||||||
uint32_t caseCount = cases->pn_count;
|
uint32_t caseCount = cases->pn_count - (pn->hasDefault() ? 1 : 0);
|
||||||
CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
|
CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
|
||||||
if (caseCount == 0) {
|
if (caseCount == 0) {
|
||||||
tableGen.finish(0);
|
tableGen.finish(0);
|
||||||
} else if (caseCount == 1 && firstCase->isDefault()) {
|
|
||||||
caseCount = 0;
|
|
||||||
tableGen.finish(0);
|
|
||||||
} else {
|
} else {
|
||||||
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
|
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
|
||||||
if (caseNode->isDefault()) {
|
if (caseNode->isDefault())
|
||||||
caseCount--; // one of the "cases" was the default
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tableGen.isInvalid())
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ParseNode* caseValue = caseNode->caseExpression();
|
ParseNode* caseValue = caseNode->caseExpression();
|
||||||
|
|
||||||
if (caseValue->getKind() != PNK_NUMBER) {
|
if (caseValue->getKind() != PNK_NUMBER) {
|
||||||
tableGen.setInvalid();
|
tableGen.setInvalid();
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t i;
|
int32_t i;
|
||||||
if (!NumberIsInt32(caseValue->pn_dval, &i)) {
|
if (!NumberIsInt32(caseValue->pn_dval, &i)) {
|
||||||
tableGen.setInvalid();
|
tableGen.setInvalid();
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tableGen.addNumber(i))
|
if (!tableGen.addNumber(i))
|
||||||
|
|
@ -8664,7 +8656,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PNK_SWITCH:
|
case PNK_SWITCH:
|
||||||
if (!emitSwitch(pn))
|
if (!emitSwitch(&pn->as<SwitchStatement>()))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -591,7 +591,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn);
|
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
|
MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
|
||||||
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
|
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
|
||||||
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(ParseNode* pn);
|
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* pn);
|
||||||
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(ParseNode* pn);
|
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(ParseNode* pn);
|
||||||
|
|
||||||
enum DestructuringFlavor {
|
enum DestructuringFlavor {
|
||||||
|
|
|
||||||
|
|
@ -661,9 +661,11 @@ class FullParseHandler
|
||||||
return new_<TernaryNode>(kind, JSOP_NOP, target, nullptr, iteratedExpr, pos);
|
return new_<TernaryNode>(kind, JSOP_NOP, target, nullptr, iteratedExpr, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
|
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant,
|
||||||
TokenPos pos(begin, caseList->pn_pos.end);
|
ParseNode* lexicalForCaseList, bool hasDefault)
|
||||||
return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
|
{
|
||||||
|
return new_<SwitchStatement>(begin, discriminant, lexicalForCaseList, hasDefault);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
|
ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,7 @@ IsTypeofKind(ParseNodeKind kind)
|
||||||
* PNK_SWITCH binary pn_left: discriminant
|
* PNK_SWITCH binary pn_left: discriminant
|
||||||
* pn_right: PNK_LEXICALSCOPE node that contains the list
|
* pn_right: PNK_LEXICALSCOPE node that contains the list
|
||||||
* of PNK_CASE nodes, with at most one default node.
|
* of PNK_CASE nodes, with at most one default node.
|
||||||
|
* hasDefault: true if there's a default case
|
||||||
* PNK_CASE binary pn_left: case-expression if CaseClause, or
|
* PNK_CASE binary pn_left: case-expression if CaseClause, or
|
||||||
* null if DefaultClause
|
* null if DefaultClause
|
||||||
* pn_right: PNK_STATEMENTLIST node for this case's
|
* pn_right: PNK_STATEMENTLIST node for this case's
|
||||||
|
|
@ -589,6 +590,7 @@ class ParseNode
|
||||||
union {
|
union {
|
||||||
unsigned iflags; /* JSITER_* flags for PNK_{COMPREHENSION,}FOR node */
|
unsigned iflags; /* JSITER_* flags for PNK_{COMPREHENSION,}FOR node */
|
||||||
bool isStatic; /* only for PNK_CLASSMETHOD */
|
bool isStatic; /* only for PNK_CLASSMETHOD */
|
||||||
|
bool hasDefault; /* only for PNK_SWITCH */
|
||||||
};
|
};
|
||||||
} binary;
|
} binary;
|
||||||
struct { /* one kid if unary */
|
struct { /* one kid if unary */
|
||||||
|
|
@ -1375,7 +1377,7 @@ struct CallSiteNode : public ListNode {
|
||||||
|
|
||||||
struct ClassMethod : public BinaryNode {
|
struct ClassMethod : public BinaryNode {
|
||||||
/*
|
/*
|
||||||
* Method defintions often keep a name and function body that overlap,
|
* Method definitions often keep a name and function body that overlap,
|
||||||
* so explicitly define the beginning and end here.
|
* so explicitly define the beginning and end here.
|
||||||
*/
|
*/
|
||||||
ClassMethod(ParseNode* name, ParseNode* body, JSOp op, bool isStatic)
|
ClassMethod(ParseNode* name, ParseNode* body, JSOp op, bool isStatic)
|
||||||
|
|
@ -1401,6 +1403,48 @@ struct ClassMethod : public BinaryNode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SwitchStatement : public BinaryNode {
|
||||||
|
SwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* lexicalForCaseList,
|
||||||
|
bool hasDefault)
|
||||||
|
: BinaryNode(PNK_SWITCH, JSOP_NOP,
|
||||||
|
TokenPos(begin, lexicalForCaseList->pn_pos.end),
|
||||||
|
discriminant, lexicalForCaseList)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
MOZ_ASSERT(lexicalForCaseList->isKind(PNK_LEXICALSCOPE));
|
||||||
|
ParseNode* cases = lexicalForCaseList->scopeBody();
|
||||||
|
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
|
||||||
|
bool found = false;
|
||||||
|
CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
|
||||||
|
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
|
||||||
|
if (caseNode->isDefault()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(found == hasDefault);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pn_u.binary.hasDefault = hasDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool test(const ParseNode& node) {
|
||||||
|
bool match = node.isKind(PNK_SWITCH);
|
||||||
|
MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseNode& discriminant() const {
|
||||||
|
return *pn_u.binary.left;
|
||||||
|
}
|
||||||
|
ParseNode& lexicalForCaseList() const {
|
||||||
|
return *pn_u.binary.right;
|
||||||
|
}
|
||||||
|
bool hasDefault() const {
|
||||||
|
return pn_u.binary.hasDefault;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct ClassNames : public BinaryNode {
|
struct ClassNames : public BinaryNode {
|
||||||
ClassNames(ParseNode* outerBinding, ParseNode* innerBinding, const TokenPos& pos)
|
ClassNames(ParseNode* outerBinding, ParseNode* innerBinding, const TokenPos& pos)
|
||||||
: BinaryNode(PNK_CLASSNAMES, JSOP_NOP, pos, outerBinding, innerBinding)
|
: BinaryNode(PNK_CLASSNAMES, JSOP_NOP, pos, outerBinding, innerBinding)
|
||||||
|
|
|
||||||
|
|
@ -6506,7 +6506,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
|
||||||
|
|
||||||
handler.setEndPosition(caseList, pos().end);
|
handler.setEndPosition(caseList, pos().end);
|
||||||
|
|
||||||
return handler.newSwitchStatement(begin, discriminant, caseList);
|
return handler.newSwitchStatement(begin, discriminant, caseList, seenDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,10 @@ class SyntaxParseHandler
|
||||||
Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
|
Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
|
||||||
Node newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { return NodeGeneric; }
|
Node newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { return NodeGeneric; }
|
||||||
Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
|
Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
|
||||||
Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
|
Node newSwitchStatement(uint32_t begin, Node discriminant, Node lexicalForCaseList, bool hasDefault)
|
||||||
|
{
|
||||||
|
return NodeGeneric;
|
||||||
|
}
|
||||||
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
|
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
|
||||||
Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
|
Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
|
||||||
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
|
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue