diff options
Diffstat (limited to 'js/src/frontend')
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 74 | ||||
-rw-r--r-- | js/src/frontend/BytecodeEmitter.h | 2 | ||||
-rw-r--r-- | js/src/frontend/FoldConstants.cpp | 7 | ||||
-rw-r--r-- | js/src/frontend/NameFunctions.cpp | 6 | ||||
-rw-r--r-- | js/src/frontend/ParseNode.cpp | 11 | ||||
-rw-r--r-- | js/src/frontend/Parser.cpp | 88 |
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) |