mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-18 21:27:30 +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.
|
||||
*/
|
||||
MOZ_NEVER_INLINE bool
|
||||
BytecodeEmitter::emitSwitch(ParseNode* pn)
|
||||
BytecodeEmitter::emitSwitch(SwitchStatement* pn)
|
||||
{
|
||||
ParseNode* lexical = pn->pn_right;
|
||||
MOZ_ASSERT(lexical->isKind(PNK_LEXICALSCOPE));
|
||||
ParseNode* cases = lexical->scopeBody();
|
||||
ParseNode& lexical = pn->lexicalForCaseList();
|
||||
MOZ_ASSERT(lexical.isKind(PNK_LEXICALSCOPE));
|
||||
ParseNode* cases = lexical.scopeBody();
|
||||
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
|
||||
|
||||
SwitchEmitter se(this);
|
||||
if (!se.emitDiscriminant(Some(pn->pn_pos.begin)))
|
||||
return false;
|
||||
if (!emitTree(pn->pn_left))
|
||||
if (!emitTree(&pn->discriminant()))
|
||||
return false;
|
||||
|
||||
// Enter the scope before pushing the switch BreakableControl since all
|
||||
// breaks are under this scope.
|
||||
if (!lexical->isEmptyScope()) {
|
||||
if (!se.emitLexical(lexical->scopeBindings()))
|
||||
if (!lexical.isEmptyScope()) {
|
||||
if (!se.emitLexical(lexical.scopeBindings()))
|
||||
return false;
|
||||
|
||||
// A switch statement may contain hoisted functions inside its
|
||||
|
|
@ -2082,34 +2082,26 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
|
|||
}
|
||||
|
||||
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;
|
||||
if (caseCount == 0) {
|
||||
tableGen.finish(0);
|
||||
} else if (caseCount == 1 && firstCase->isDefault()) {
|
||||
caseCount = 0;
|
||||
tableGen.finish(0);
|
||||
} else {
|
||||
for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
|
||||
if (caseNode->isDefault()) {
|
||||
caseCount--; // one of the "cases" was the default
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tableGen.isInvalid())
|
||||
if (caseNode->isDefault())
|
||||
continue;
|
||||
|
||||
ParseNode* caseValue = caseNode->caseExpression();
|
||||
|
||||
if (caseValue->getKind() != PNK_NUMBER) {
|
||||
tableGen.setInvalid();
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t i;
|
||||
if (!NumberIsInt32(caseValue->pn_dval, &i)) {
|
||||
tableGen.setInvalid();
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tableGen.addNumber(i))
|
||||
|
|
@ -8664,7 +8656,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
|||
break;
|
||||
|
||||
case PNK_SWITCH:
|
||||
if (!emitSwitch(pn))
|
||||
if (!emitSwitch(&pn->as<SwitchStatement>()))
|
||||
return false;
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
|
||||
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);
|
||||
|
||||
enum DestructuringFlavor {
|
||||
|
|
|
|||
|
|
@ -661,9 +661,11 @@ class FullParseHandler
|
|||
return new_<TernaryNode>(kind, JSOP_NOP, target, nullptr, iteratedExpr, pos);
|
||||
}
|
||||
|
||||
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
|
||||
TokenPos pos(begin, caseList->pn_pos.end);
|
||||
return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
|
||||
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant,
|
||||
ParseNode* lexicalForCaseList, bool hasDefault)
|
||||
{
|
||||
return new_<SwitchStatement>(begin, discriminant, lexicalForCaseList, hasDefault);
|
||||
|
||||
}
|
||||
|
||||
ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* PNK_SWITCH binary pn_left: discriminant
|
||||
* pn_right: PNK_LEXICALSCOPE node that contains the list
|
||||
* 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
|
||||
* null if DefaultClause
|
||||
* pn_right: PNK_STATEMENTLIST node for this case's
|
||||
|
|
@ -589,6 +590,7 @@ class ParseNode
|
|||
union {
|
||||
unsigned iflags; /* JSITER_* flags for PNK_{COMPREHENSION,}FOR node */
|
||||
bool isStatic; /* only for PNK_CLASSMETHOD */
|
||||
bool hasDefault; /* only for PNK_SWITCH */
|
||||
};
|
||||
} binary;
|
||||
struct { /* one kid if unary */
|
||||
|
|
@ -1375,7 +1377,7 @@ struct CallSiteNode : public ListNode {
|
|||
|
||||
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.
|
||||
*/
|
||||
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 {
|
||||
ClassNames(ParseNode* outerBinding, ParseNode* innerBinding, const TokenPos& pos)
|
||||
: BinaryNode(PNK_CLASSNAMES, JSOP_NOP, pos, outerBinding, innerBinding)
|
||||
|
|
|
|||
|
|
@ -6506,7 +6506,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
|
|||
|
||||
handler.setEndPosition(caseList, pos().end);
|
||||
|
||||
return handler.newSwitchStatement(begin, discriminant, caseList);
|
||||
return handler.newSwitchStatement(begin, discriminant, caseList, seenDefault);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
|
|
|||
|
|
@ -343,7 +343,10 @@ class SyntaxParseHandler
|
|||
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 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 newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
|
||||
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue