summaryrefslogtreecommitdiffstats
path: root/js/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend')
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp74
-rw-r--r--js/src/frontend/BytecodeEmitter.h2
-rw-r--r--js/src/frontend/FoldConstants.cpp7
-rw-r--r--js/src/frontend/NameFunctions.cpp6
-rw-r--r--js/src/frontend/ParseNode.cpp11
-rw-r--r--js/src/frontend/Parser.cpp88
6 files changed, 107 insertions, 81 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index f4574b248..18cc7d954 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3459,10 +3459,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_CATCH:
MOZ_ASSERT(pn->isArity(PN_TERNARY));
- if (!checkSideEffects(pn->pn_kid1, answer))
- return false;
- if (*answer)
- return true;
+ if (ParseNode* name = pn->pn_kid1) {
+ if (!checkSideEffects(name, answer))
+ return false;
+ if (*answer)
+ return true;
+ }
if (ParseNode* cond = pn->pn_kid2) {
if (!checkSideEffects(cond, answer))
return false;
@@ -6495,8 +6497,8 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
}
MOZ_ASSERT(idx == count);
- ArrayObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
- newKind, arrayKind);
+ JSObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
+ newKind, arrayKind);
if (!obj)
return false;
@@ -6638,24 +6640,31 @@ BytecodeEmitter::emitCatch(ParseNode* pn)
return false;
ParseNode* pn2 = pn->pn_kid1;
- switch (pn2->getKind()) {
- case PNK_ARRAY:
- case PNK_OBJECT:
- if (!emitDestructuringOps(pn2, DestructuringDeclaration))
- return false;
- if (!emit1(JSOP_POP))
- return false;
- break;
-
- case PNK_NAME:
- if (!emitLexicalInitialization(pn2))
- return false;
- if (!emit1(JSOP_POP))
- return false;
- break;
-
- default:
- MOZ_ASSERT(0);
+ if (!pn2) {
+ // See ES2019 13.15.7 Runtime Semantics: CatchClauseEvaluation
+ // Catch variable was omitted: discard the exception.
+ if (!emit1(JSOP_POP))
+ return false;
+ } else {
+ switch (pn2->getKind()) {
+ case PNK_ARRAY:
+ case PNK_OBJECT:
+ if (!emitDestructuringOps(pn2, DestructuringDeclaration))
+ return false;
+ if (!emit1(JSOP_POP))
+ return false;
+ break;
+
+ case PNK_NAME:
+ if (!emitLexicalInitialization(pn2))
+ return false;
+ if (!emit1(JSOP_POP))
+ return false;
+ break;
+
+ default:
+ MOZ_ASSERT(0);
+ }
}
// If there is a guard expression, emit it and arrange to jump to the next
@@ -6899,7 +6908,9 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn)
EmitterScope emitterScope(this);
ScopeKind kind;
if (body->isKind(PNK_CATCH))
- kind = body->pn_kid1->isKind(PNK_NAME) ? ScopeKind::SimpleCatch : ScopeKind::Catch;
+ kind = (!body->pn_kid1 || body->pn_kid1->isKind(PNK_NAME)) ?
+ ScopeKind::SimpleCatch :
+ ScopeKind::Catch;
else
kind = ScopeKind::Lexical;
@@ -9623,7 +9634,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
return false;
}
- if (!emitArray(args, argc))
+ if (!emitArray(args, argc, JSOP_SPREADCALLARRAY))
return false;
if (optCodeEmitted) {
@@ -10138,11 +10149,11 @@ BytecodeEmitter::emitArrayLiteral(ParseNode* pn)
}
}
- return emitArray(pn->pn_head, pn->pn_count);
+ return emitArray(pn->pn_head, pn->pn_count, JSOP_NEWARRAY);
}
bool
-BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
+BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
{
/*
@@ -10153,6 +10164,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
* to avoid dup'ing and popping the array as each element is added, as
* JSOP_SETELEM/JSOP_SETPROP would do.
*/
+ MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY);
uint32_t nspread = 0;
for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
@@ -10173,7 +10185,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
// For arrays with spread, this is a very pessimistic allocation, the
// minimum possible final size.
- if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) // ARRAY
+ if (!emitUint32Operand(op, count - nspread)) // ARRAY
return false;
ParseNode* pn2 = pn;
@@ -11314,8 +11326,8 @@ BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offs
/* Maybe this offset was already set to a four-byte value. */
if (!(*sn & SN_4BYTE_OFFSET_FLAG)) {
/* Insert three dummy bytes that will be overwritten shortly. */
- if (MOZ_UNLIKELY(notes.length() + 3 > MaxSrcNotesLength)) {
- ReportAllocationOverflow(cx);
+ if (MOZ_UNLIKELY(notes.length() + 3 > MaxSrcNotesLength)) {
+ ReportAllocationOverflow(cx);
return false;
}
jssrcnote dummy = 0;
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 8ad409c11..77f77599c 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -543,7 +543,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitAtomOp(ParseNode* pn, JSOp op);
MOZ_MUST_USE bool emitArrayLiteral(ParseNode* pn);
- MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count);
+ MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count, JSOp op);
MOZ_MUST_USE bool emitArrayComp(ParseNode* pn);
MOZ_MUST_USE bool emitInternedScopeOp(uint32_t index, JSOp op);
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
index 16294c4a8..b460b92b6 100644
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -1260,9 +1260,10 @@ FoldCatch(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parse
MOZ_ASSERT(node->isKind(PNK_CATCH));
MOZ_ASSERT(node->isArity(PN_TERNARY));
- ParseNode*& declPattern = node->pn_kid1;
- if (!Fold(cx, &declPattern, parser, inGenexpLambda))
- return false;
+ if (ParseNode*& declPattern = node->pn_kid1) {
+ if (!Fold(cx, &declPattern, parser, inGenexpLambda))
+ return false;
+ }
if (ParseNode*& cond = node->pn_kid2) {
if (!FoldCondition(cx, &cond, parser, inGenexpLambda))
diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp
index 376be7624..db70bb5b4 100644
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -651,8 +651,10 @@ class NameResolver
// contain arbitrary expressions.
case PNK_CATCH:
MOZ_ASSERT(cur->isArity(PN_TERNARY));
- if (!resolve(cur->pn_kid1, prefix))
- return false;
+ if (cur->pn_kid1) {
+ if (!resolve(cur->pn_kid1, prefix))
+ return false;
+ }
if (cur->pn_kid2) {
if (!resolve(cur->pn_kid2, prefix))
return false;
diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp
index 42ae9451a..e01a41067 100644
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -409,13 +409,14 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushResult::Recyclable;
}
- // A catch node has first kid as catch-variable pattern, the second kid
- // as catch condition (which, if non-null, records the |<cond>| in
- // SpiderMonkey's |catch (e if <cond>)| extension), and third kid as the
- // statements in the catch block.
+ // A catch node has an (optional) first kid as catch-variable pattern,
+ // the second kid as (optional) catch condition (which, records the
+ // |<cond>| in SpiderMonkey's |catch (e if <cond>)| extension), and
+ // third kid as the statements in the catch block.
case PNK_CATCH: {
MOZ_ASSERT(pn->isArity(PN_TERNARY));
- stack->push(pn->pn_kid1);
+ if (pn->pn_kid1)
+ stack->push(pn->pn_kid1);
if (pn->pn_kid2)
stack->push(pn->pn_kid2);
stack->push(pn->pn_kid3);
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index cf9f1e27c..810d589be 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6901,57 +6901,67 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
/*
* Legal catch forms are:
* catch (lhs)
- * catch (lhs if <boolean_expression>)
+ * catch (lhs if <boolean_expression>) ** non-standard **
+ * catch ** ES2019 **
* where lhs is a name or a destructuring left-hand side.
- * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
+ * The second is legal only #ifdef JS_HAS_CATCH_GUARD
*/
- MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
-
- if (!tokenStream.getToken(&tt))
+ bool omittedBinding;
+ if (!tokenStream.matchToken(&omittedBinding, TOK_LC))
return null();
+
Node catchName;
- switch (tt) {
- case TOK_LB:
- case TOK_LC:
- catchName = destructuringDeclaration(DeclarationKind::CatchParameter,
- yieldHandling, tt);
- if (!catchName)
- return null();
- break;
+ Node catchGuard = null();
- default: {
- if (!TokenKindIsPossibleIdentifierName(tt)) {
- error(JSMSG_CATCH_IDENTIFIER);
- return null();
- }
+ if (omittedBinding) {
+ catchName = null();
+ } else {
+ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
- catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
- yieldHandling);
- if (!catchName)
+ if (!tokenStream.getToken(&tt))
return null();
- break;
- }
- }
+ switch (tt) {
+ case TOK_LB:
+ case TOK_LC:
+ catchName = destructuringDeclaration(DeclarationKind::CatchParameter,
+ yieldHandling, tt);
+ if (!catchName)
+ return null();
+ break;
+
+ default: {
+ if (!TokenKindIsPossibleIdentifierName(tt)) {
+ error(JSMSG_CATCH_IDENTIFIER);
+ return null();
+ }
+
+ catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
+ yieldHandling);
+ if (!catchName)
+ return null();
+ break;
+ }
+ }
- Node catchGuard = null();
#if JS_HAS_CATCH_GUARD
- /*
- * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
- * to avoid conflicting with the JS2/ECMAv4 type annotation
- * catchguard syntax.
- */
- bool matched;
- if (!tokenStream.matchToken(&matched, TOK_IF))
- return null();
- if (matched) {
- catchGuard = expr(InAllowed, yieldHandling, TripledotProhibited);
- if (!catchGuard)
+ /*
+ * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
+ * to avoid conflicting with the JS2/ECMAv4 type annotation
+ * catchguard syntax.
+ */
+ bool matched;
+ if (!tokenStream.matchToken(&matched, TOK_IF))
return null();
- }
+ if (matched) {
+ catchGuard = expr(InAllowed, yieldHandling, TripledotProhibited);
+ if (!catchGuard)
+ return null();
+ }
#endif
- MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
- MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
+ MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
+ }
Node catchBody = catchBlockStatement(yieldHandling, scope);
if (!catchBody)