From b68de773fd9af42dfed60e0a00162ee6f6e02662 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 12:47:28 +0100 Subject: [PATCH 01/37] Stage 1-1: Implement Function.prototype.toString revision proposal. Tag #960 --- js/src/frontend/BytecodeCompiler.cpp | 12 +- js/src/frontend/BytecodeCompiler.h | 2 + js/src/frontend/BytecodeEmitter.cpp | 3 +- js/src/frontend/Parser.cpp | 167 ++++++++++++++++++--------- js/src/frontend/Parser.h | 28 +++-- js/src/frontend/SharedContext.h | 5 +- js/src/frontend/TokenStream.cpp | 6 + js/src/frontend/TokenStream.h | 7 ++ js/src/jsapi.cpp | 46 ++++++-- js/src/jsfun.cpp | 90 ++++++++++----- js/src/jsscript.cpp | 47 ++++++-- js/src/jsscript.h | 49 +++++--- js/src/wasm/AsmJS.cpp | 22 ++-- 13 files changed, 330 insertions(+), 154 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 76afe80b13..b5be5f5acd 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler bool canLazilyParse(); bool createParser(); bool createSourceAndParser(Maybe parameterListEnd = Nothing()); - bool createScript(); + bool createScript(uint32_t preludeStart = 0); bool emplaceEmitter(Maybe& emitter, SharedContext* sharedContext); bool handleParseFailure(const Directives& newDirectives); bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment); @@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe parameterListEnd /* = No } bool -BytecodeCompiler::createScript() +BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */) { script = JSScript::Create(cx, options, - sourceObject, /* sourceStart = */ 0, sourceBuffer.length()); + sourceObject, /* sourceStart = */ 0, sourceBuffer.length(), + preludeStart); return script != nullptr; } @@ -456,7 +457,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); - if (!createScript()) + if (!createScript(fn->pn_funbox->preludeStart)) return false; Maybe emitter; @@ -650,7 +651,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha MOZ_ASSERT(sourceObject); Rooted script(cx, JSScript::Create(cx, options, sourceObject, - lazy->begin(), lazy->end())); + lazy->begin(), lazy->end(), + lazy->preludeStart())); if (!script) return false; diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 72e9676395..0bc1ab2abf 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str); * As above, but taking chars + length. */ bool +IsIdentifier(const char* chars, size_t length); +bool IsIdentifier(const char16_t* chars, size_t length); /* True if str is a keyword. Defined in TokenStream.cpp. */ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 4eb7bf880c..c5e62ae340 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -7834,7 +7834,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted sourceObject(cx, script->sourceObject()); Rooted script(cx, JSScript::Create(cx, options, sourceObject, - funbox->bufStart, funbox->bufEnd)); + funbox->bufStart, funbox->bufEnd, + funbox->preludeStart)); if (!script) return false; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 209265a584..1ba725a829 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -441,7 +441,8 @@ UsedNameTracker::rewind(RewindToken token) } FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, - JSFunction* fun, Directives directives, bool extraWarnings, + JSFunction* fun, uint32_t preludeStart, + Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), SharedContext(cx, Kind::ObjectBox, directives, extraWarnings), @@ -454,6 +455,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac bufEnd(0), startLine(1), startColumn(0), + preludeStart(preludeStart), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)), @@ -738,7 +740,8 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox* -Parser::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives, +Parser::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + Directives inheritedDirectives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB) { @@ -753,8 +756,9 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, Directives inheri * function. */ FunctionBox* funbox = - alloc.new_(context, alloc, traceListHead, fun, inheritedDirectives, - options().extraWarningsOption, generatorKind, asyncKind); + alloc.new_(context, alloc, traceListHead, fun, preludeStart, + inheritedDirectives, options().extraWarningsOption, + generatorKind, asyncKind); if (!funbox) { ReportOutOfMemory(context); return nullptr; @@ -2214,6 +2218,7 @@ Parser::finishFunction() LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(), pc->innerFunctionsForLazy, versionNumber(), funbox->bufStart, funbox->bufEnd, + funbox->preludeStart, funbox->startLine, funbox->startColumn); if (!lazy) return false; @@ -2267,6 +2272,33 @@ Parser::standaloneFunction(HandleFunction fun, { MOZ_ASSERT(checkOptionsCalled); + // Skip prelude. + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + if (asyncKind == AsyncFunction) { + MOZ_ASSERT(tt == TOK_ASYNC); + if (!tokenStream.getToken(&tt)) + return null(); + } + MOZ_ASSERT(tt == TOK_FUNCTION); + + if (!tokenStream.getToken(&tt)) + return null(); + if (generatorKind == StarGenerator && asyncKind == SyncFunction) { + MOZ_ASSERT(tt == TOK_MUL); + if (!tokenStream.getToken(&tt)) + return null(); + } + + // Skip function name, if present. + if (tt == TOK_NAME || tt == TOK_YIELD) { + MOZ_ASSERT(tokenStream.currentName() == fun->explicitName()); + } else { + MOZ_ASSERT(fun->explicitName() == nullptr); + tokenStream.ungetToken(); + } + Node fn = handler.newFunctionDefinition(); if (!fn) return null(); @@ -2276,8 +2308,8 @@ Parser::standaloneFunction(HandleFunction fun, return null(); fn->pn_body = argsbody; - FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, - asyncKind, /* tryAnnexB = */ false); + FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives, + generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); funbox->initStandaloneFunction(enclosingScope); @@ -2295,7 +2327,6 @@ Parser::standaloneFunction(HandleFunction fun, return null(); } - TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { @@ -2991,8 +3022,8 @@ Parser::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct template <> bool -Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind, - bool tryAnnexB) +Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, + FunctionSyntaxKind kind, bool tryAnnexB) { // When a lazily-parsed function is called, we only fully parse (and emit) // that function, not any of its nested children. The initial syntax-only @@ -3001,7 +3032,7 @@ Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); - FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false), + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false), fun->generatorKind(), fun->asyncKind(), tryAnnexB); if (!funbox) return false; @@ -3031,8 +3062,8 @@ Parser::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin template <> bool -Parser::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, - bool tryAnnexB) +Parser::skipLazyInnerFunction(Node pn, uint32_t preludeStart, + FunctionSyntaxKind kind, bool tryAnnexB) { MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing"); } @@ -3108,7 +3139,8 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(InHandling inHandling, YieldHandling yieldHandling, +Parser::functionDefinition(uint32_t preludeStart, InHandling inHandling, + YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked) @@ -3132,7 +3164,7 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. if (handler.canSkipLazyInnerFunctions()) { - if (!skipLazyInnerFunction(pn, kind, tryAnnexB)) + if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB)) return null(); return pn; } @@ -3165,8 +3197,9 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi // reparse a function due to failed syntax parsing and encountering new // "use foo" directives. while (true) { - if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind, - asyncKind, tryAnnexB, directives, &newDirectives)) + if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, directives, + &newDirectives)) { break; } @@ -3193,6 +3226,7 @@ Parser::functionDefinition(InHandling inHandling, YieldHandling yi template <> bool Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3226,14 +3260,15 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // Make a FunctionBox before we enter the syntax parser, because |pn| // still expects a FunctionBox to be attached to it during BCE, and // the syntax parser cannot attach one to it. - FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, - asyncKind, tryAnnexB); + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(pc, kind); - if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling, - yieldHandling, kind, inheritedDirectives, newDirectives)) + if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart, + inHandling, yieldHandling, kind, + inheritedDirectives, newDirectives)) { if (parser->hadAbortedSyntaxParse()) { // Try again with a full parse. UsedNameTracker needs to be @@ -3259,13 +3294,14 @@ Parser::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct } while (false); // We failed to do a syntax parse above, so do the full parse. - return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, - tryAnnexB, inheritedDirectives, newDirectives); + return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template <> bool Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3276,13 +3312,14 @@ Parser::trySyntaxParseInnerFunction(Node pn, HandleFunction Directives* newDirectives) { // This is already a syntax parser, so just parse the inner function. - return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, - tryAnnexB, inheritedDirectives, newDirectives); + return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template bool Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives) @@ -3306,6 +3343,7 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* template bool Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, + uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3317,14 +3355,14 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti // parser. In that case, outerpc is a ParseContext from the full parser // instead of the current top of the stack of the syntax parser. - FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, - asyncKind, tryAnnexB); + FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(outerpc, kind); - return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives, - newDirectives); + return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind, + inheritedDirectives, newDirectives); } template @@ -3359,8 +3397,8 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict return null(); Directives directives(strict); - FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, - /* tryAnnexB = */ false); + FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives, + generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); funbox->initFromLazyFunction(); @@ -3529,8 +3567,8 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, template typename ParseHandler::Node -Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, - FunctionAsyncKind asyncKind) +Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling, + DefaultHandling defaultHandling, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3579,8 +3617,8 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling } YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind, - asyncKind, PredictUninvoked); + Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement, + generatorKind, asyncKind, PredictUninvoked); if (!fun) return null(); @@ -3597,7 +3635,8 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling template typename ParseHandler::Node -Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind) +Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invoked, + FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -3628,8 +3667,8 @@ Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind tokenStream.ungetToken(); } - return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind, - asyncKind, invoked); + return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression, + generatorKind, asyncKind, invoked); } /* @@ -5074,7 +5113,7 @@ Parser::exportDeclaration() } case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, NameRequired); + kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); if (!kid) return null(); @@ -5114,7 +5153,7 @@ Parser::exportDeclaration() ParseNode* nameNode = nullptr; switch (tt) { case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, AllowDefaultName); + kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName); if (!kid) return null(); break; @@ -5131,7 +5170,7 @@ Parser::exportDeclaration() if (nextSameLine == TOK_FUNCTION) { tokenStream.consumeKnownToken(nextSameLine); - kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction); + kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction); if (!kid) return null(); break; @@ -5232,7 +5271,7 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) // will report the strict mode error. if (!pc->sc()->strict()) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); } } @@ -6182,7 +6221,7 @@ Parser::labeledItem(YieldHandling yieldHandling) return null(); } - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); } tokenStream.ungetToken(); @@ -6649,6 +6688,10 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } + uint32_t nameOffset; + if (!tokenStream.peekOffset(&nameOffset)) + return null(); + PropertyType propType; Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom); if (!propName) @@ -6701,7 +6744,7 @@ Parser::classDefinition(YieldHandling yieldHandling, if (!tokenStream.isCurrentTokenType(TOK_RB)) funName = propAtom; } - Node fn = methodDefinition(propType, funName); + Node fn = methodDefinition(nameOffset, propType, funName); if (!fn) return null(); @@ -7094,8 +7137,9 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(yieldHandling, NameRequired, AsyncFunction); + return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); } } @@ -7174,7 +7218,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // HoistableDeclaration[?Yield, ~Default] case TOK_FUNCTION: - return functionStmt(yieldHandling, NameRequired); + return functionStmt(pos().begin, yieldHandling, NameRequired); // ClassDeclaration[?Yield, ~Default] case TOK_CLASS: @@ -7677,8 +7721,10 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl tokenStream.seek(start); - if (!tokenStream.peekToken(&next, TokenStream::Operand)) + if (!tokenStream.getToken(&next, TokenStream::Operand)) return null(); + uint32_t preludeStart = pos().begin; + tokenStream.ungetToken(); GeneratorKind generatorKind = NotGenerator; FunctionAsyncKind asyncKind = SyncFunction; @@ -7702,7 +7748,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr, + Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -8054,8 +8100,8 @@ Parser::generatorComprehensionLambda(unsigned begin) // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc()->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction, - /* tryAnnexB = */ false); + FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives, + StarGenerator, SyncFunction, /* tryAnnexB = */ false); if (!genFunbox) return null(); genFunbox->isGenexpLambda = true; @@ -8087,12 +8133,14 @@ Parser::generatorComprehensionLambda(unsigned begin) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); + uint32_t end = pos().end; handler.setBeginPosition(comp, begin); - handler.setEndPosition(comp, pos().end); + handler.setEndPosition(comp, end); + genFunbox->bufEnd = end; handler.addStatementToList(body, comp); - handler.setEndPosition(body, pos().end); + handler.setEndPosition(body, end); handler.setBeginPosition(genfn, begin); - handler.setEndPosition(genfn, pos().end); + handler.setEndPosition(genfn, end); Node generator = newDotGeneratorName(); if (!generator) @@ -9158,6 +9206,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; + TokenPos namePos = pos(); + tokenStream.ungetToken(); PropertyType propType; @@ -9309,7 +9359,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* } } - Node fn = methodDefinition(propType, funName); + Node fn = methodDefinition(namePos.begin, propType, funName); if (!fn) return null(); @@ -9336,13 +9386,15 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* template typename ParseHandler::Node -Parser::methodDefinition(PropertyType propType, HandleAtom funName) +Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, + HandleAtom funName) { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); + return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind, + generatorKind, asyncKind); } template @@ -9404,7 +9456,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling switch (tt) { case TOK_FUNCTION: - return functionExpr(invoked); + return functionExpr(pos().begin, invoked); case TOK_CLASS: return classDefinition(yieldHandling, ClassExpression, NameRequired); @@ -9471,8 +9523,9 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling return null(); if (nextSameLine == TOK_FUNCTION) { + uint32_t preludeStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionExpr(PredictUninvoked, AsyncFunction); + return functionExpr(preludeStart, PredictUninvoked, AsyncFunction); } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 12642fad82..090931f5b4 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -954,7 +954,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * cx->tempLifoAlloc. */ ObjectBox* newObjectBox(JSObject* obj); - FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives, + FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + Directives directives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB); @@ -1034,8 +1035,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Parse an inner function given an enclosing ParseContext and a // FunctionBox for the inner function. - bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling, - YieldHandling yieldHandling, FunctionSyntaxKind kind, + bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, + FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives); // Parse a function's formal parameters and its body assuming its function @@ -1088,9 +1090,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, + Node functionStmt(uint32_t preludeStart, + YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind = SyncFunction); - Node functionExpr(InvokedPrediction invoked = PredictUninvoked, + Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked, FunctionAsyncKind asyncKind = SyncFunction); Node statementList(YieldHandling yieldHandling); @@ -1222,7 +1225,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool tryNewTarget(Node& newTarget); bool checkAndMarkSuperScope(); - Node methodDefinition(PropertyType propType, HandleAtom funName); + Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName); /* * Additional JS parsers. @@ -1230,7 +1233,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, + Node functionDefinition(uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked = PredictUninvoked); @@ -1321,14 +1325,16 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, GeneratorKind generatorKind, bool* tryAnnexB); - bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB); - bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, + bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, + bool tryAnnexB); + bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling, - YieldHandling yieldHandling, FunctionSyntaxKind kind, + bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart, + InHandling inHandling, YieldHandling yieldHandling, + FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index a6ac542f67..b20417d5d3 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t bufEnd; uint32_t startLine; uint32_t startColumn; + uint32_t preludeStart; uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ @@ -476,8 +477,8 @@ class FunctionBox : public ObjectBox, public SharedContext FunctionContextFlags funCxFlags; FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun, - Directives directives, bool extraWarnings, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind); + uint32_t preludeStart, Directives directives, bool extraWarnings, + GeneratorKind generatorKind, FunctionAsyncKind asyncKind); MutableHandle namedLambdaBindings() { MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms()); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 179a7c2447..b040d29981 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -171,6 +171,12 @@ frontend::IsIdentifier(JSLinearString* str) : ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length()); } +bool +frontend::IsIdentifier(const char* chars, size_t length) +{ + return ::IsIdentifier(chars, length); +} + bool frontend::IsIdentifier(const char16_t* chars, size_t length) { diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 5d6b4b795a..77eea3d81e 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -570,6 +570,13 @@ class MOZ_STACK_CLASS TokenStream return true; } + MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) { + TokenPos pos; + if (!peekTokenPos(&pos, modifier)) + return false; + *offset = pos.begin; + return true; + } // This is like peekToken(), with one exception: if there is an EOL // between the end of the current token and the start of the next token, it // return true and store TOK_EOL in |*ttp|. In that case, no token with diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 6114b81576..f78f94dc12 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4250,7 +4250,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun) */ static bool CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, - const char* name, + HandleAtom name, bool isInvalidName, SourceBufferHolder& srcBuf, uint32_t parameterListEnd, HandleObject enclosingEnv, HandleScope enclosingScope, MutableHandleFunction fun) @@ -4261,13 +4261,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, assertSameCompartment(cx, enclosingEnv); RootedAtom funAtom(cx); - if (name) { - funAtom = Atomize(cx, name, strlen(name)); - if (!funAtom) - return false; - } - - fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom, + fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, + isInvalidName ? nullptr : name, /* proto = */ nullptr, gc::AllocKind::FUNCTION, TenuredObject, enclosingEnv)); @@ -4285,11 +4280,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, return false; } + // When function name is not a valid identifier, the generated function + // source in srcBuf doesn't have a function name. Set it here. + if (isInvalidName) + fun->setAtom(name); + return true; } static MOZ_MUST_USE bool -BuildFunctionString(unsigned nargs, const char* const* argnames, +BuildFunctionString(const char* name, size_t nameLen, + unsigned nargs, const char* const* argnames, const SourceBufferHolder& srcBuf, StringBuffer* out, uint32_t* parameterListEnd) { @@ -4298,6 +4299,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames, if (!out->ensureTwoByteChars()) return false; + if (!out->append("function ")) + return false; + if (name) { + if (!out->append(name, nameLen)) + return false; + } if (!out->append("(")) return false; for (unsigned i = 0; i < nargs; i++) { @@ -4334,15 +4341,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain, if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope)) return false; + size_t nameLen = 0; + bool isInvalidName = false; + RootedAtom nameAtom(cx); + if (name) { + nameLen = strlen(name); + nameAtom = Atomize(cx, name, nameLen); + if (!nameAtom) + return false; + + // If name is not valid identifier + if (!js::frontend::IsIdentifier(name, nameLen)) + isInvalidName = true; + } + uint32_t parameterListEnd; StringBuffer funStr(cx); - if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, ¶meterListEnd)) + if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf, + &funStr, ¶meterListEnd)) { return false; + } size_t newLen = funStr.length(); SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership); - return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun); + return CompileFunction(cx, options, nameAtom, isInvalidName, newSrcBuf, parameterListEnd, env, + scope, fun); } JS_PUBLIC_API(bool) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 98311be2f0..bdc2edff8f 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -781,8 +781,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) RootedFunction functionProto(cx, &functionProto_->as()); - const char* rawSource = "() {\n}"; + const char* rawSource = "function () {\n}"; size_t sourceLen = strlen(rawSource); + size_t begin = 9; + MOZ_ASSERT(rawSource[begin] == '('); mozilla::UniquePtr source(InflateString(cx, rawSource, &sourceLen)); if (!source) return nullptr; @@ -804,8 +806,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) RootedScript script(cx, JSScript::Create(cx, options, sourceObject, - 0, - ss->length())); + begin, + ss->length(), + 0)); if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) return nullptr; @@ -985,53 +988,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) } } - if (fun->isAsync()) { - if (!out.append("async ")) - return nullptr; - } - - bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() || - fun->isGetter() || fun->isSetter(); + bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow(); bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); - // If we're not in pretty mode, put parentheses around lambda functions and methods. - if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) { + // If we're not in pretty mode, put parentheses around lambda functions + // so that eval returns lambda, not function statement. + if (haveSource && !prettyPrint && funIsNonArrowLambda) { if (!out.append("(")) return nullptr; } - if (!fun->isArrow()) { - bool ok; - if (fun->isStarGenerator() && !fun->isAsync()) - ok = out.append("function* "); - else - ok = out.append("function "); - if (!ok) - return nullptr; - } - if (fun->explicitName()) { - if (!out.append(fun->explicitName())) - return nullptr; - } if (haveSource && !script->scriptSource()->hasSourceData() && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) { return nullptr; } + + auto AppendPrelude = [&out, &fun]() { + if (fun->isAsync()) { + if (!out.append("async ")) + return false; + } + + if (!fun->isArrow()) { + if (!out.append("function")) + return false; + + if (fun->isStarGenerator()) { + if (!out.append('*')) + return false; + } + } + + if (fun->explicitName()) { + if (!out.append(' ')) + return false; + if (!out.append(fun->explicitName())) + return false; + } + return true; + }; + if (haveSource) { - Rooted src(cx, script->sourceData(cx)); + Rooted src(cx, script->sourceDataWithPrelude(cx)); if (!src) return nullptr; if (!out.append(src)) return nullptr; - if (!prettyPrint && funIsMethodOrNonArrowLambda) { + if (!prettyPrint && funIsNonArrowLambda) { if (!out.append(")")) return nullptr; } } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { - if (!out.append("() {\n ") || + if (!AppendPrelude() || + !out.append("() {\n ") || !out.append("[sourceless code]") || !out.append("\n}")) { @@ -1042,13 +1054,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) bool derived = fun->infallibleIsDefaultClassConstructor(cx); if (derived && fun->isDerivedClassConstructor()) { - if (!out.append("(...args) {\n ") || + if (!AppendPrelude() || + !out.append("(...args) {\n ") || !out.append("super(...args);\n}")) { return nullptr; } } else { - if (!out.append("() {\n ")) + if (!AppendPrelude() || + !out.append("() {\n ")) return nullptr; if (!derived) { @@ -1635,7 +1649,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator StringBuffer sb(cx); - if (!sb.append('(')) + if (isAsync) { + if (!sb.append("async ")) + return false; + } + if (!sb.append("function")) + return false; + if (isStarGenerator && !isAsync) { + if (!sb.append('*')) + return false; + } + + if (!sb.append(" anonymous(")) return false; if (args.length() > 1) { @@ -1662,6 +1687,9 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator } } + if (!sb.append('\n')) + return false; + // Remember the position of ")". Maybe parameterListEnd = Some(uint32_t(sb.length())); MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')'); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 9f914943ec..33ae56d6fc 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri { uint32_t begin = script->sourceStart(); uint32_t end = script->sourceEnd(); + uint32_t preludeStart = script->preludeStart(); uint32_t lineno = script->lineno(); uint32_t column = script->column(); @@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri packedFields = lazy->packedFields(); MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(end == lazy->end()); + MOZ_ASSERT(preludeStart == lazy->preludeStart()); MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(column == lazy->column()); // We can assert we have no inner functions because we don't @@ -255,7 +257,7 @@ XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript scri if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, - packedFields, begin, end, lineno, column)); + packedFields, begin, end, preludeStart, lineno, column)); // As opposed to XDRLazyScript, we need to restore the runtime bits // of the script, as we are trying to match the fact this function @@ -517,7 +519,7 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip sourceObject = &enclosingScript->sourceObject()->as(); } - script = JSScript::Create(cx, options, sourceObject, 0, 0); + script = JSScript::Create(cx, options, sourceObject, 0, 0, 0); if (!script) return false; @@ -600,6 +602,8 @@ js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, HandleScrip return false; if (!xdr->codeUint32(&script->sourceEnd_)) return false; + if (!xdr->codeUint32(&script->preludeStart_)) + return false; if (!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || @@ -930,6 +934,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript { uint32_t begin; uint32_t end; + uint32_t preludeStart; uint32_t lineno; uint32_t column; uint64_t packedFields; @@ -943,12 +948,14 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript begin = lazy->begin(); end = lazy->end(); + preludeStart = lazy->preludeStart(); lineno = lazy->lineno(); column = lazy->column(); packedFields = lazy->packedFields(); } if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || + !xdr->codeUint32(&preludeStart) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint64(&packedFields)) { @@ -957,7 +964,7 @@ js::XDRLazyScript(XDRState* xdr, HandleScope enclosingScope, HandleScript if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, - packedFields, begin, end, lineno, column)); + packedFields, begin, end, preludeStart, lineno, column)); if (!lazy) return false; fun->initLazyScript(lazy); @@ -1430,6 +1437,13 @@ JSScript::sourceData(JSContext* cx) return scriptSource()->substring(cx, sourceStart(), sourceEnd()); } +JSFlatString* +JSScript::sourceDataWithPrelude(JSContext* cx) +{ + MOZ_ASSERT(scriptSource()->hasSourceData()); + return scriptSource()->substring(cx, preludeStart(), sourceEnd()); +} + UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() : cache_(nullptr), sourceChunk_() { @@ -2428,7 +2442,8 @@ JSScript::initCompartment(ExclusiveContext* cx) /* static */ JSScript* JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, - HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd) + HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, + uint32_t preludeStart) { MOZ_ASSERT(bufStart <= bufEnd); @@ -2450,6 +2465,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, script->setSourceObject(sourceObject); script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; + script->preludeStart_ = preludeStart; return script; } @@ -3382,7 +3398,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src) .setNoScriptRval(src->noScriptRval()) .setVersion(src->getVersion()); - return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd()); + return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(), + src->preludeStart()); } JSScript* @@ -3932,7 +3949,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) } LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + uint32_t begin, uint32_t end, + uint32_t preludeStart, uint32_t lineno, uint32_t column) : script_(nullptr), function_(fun), enclosingScope_(nullptr), @@ -3941,6 +3959,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, packedFields_(packedFields), begin_(begin), end_(end), + preludeStart_(preludeStart), lineno_(lineno), column_(column) { @@ -3990,7 +4009,7 @@ LazyScript::maybeForwardedScriptSource() const /* static */ LazyScript* LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column) + uint32_t preludeStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4018,7 +4037,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, cx->compartment()->scheduleDelazificationForDebugger(); - return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column); + return new (res) LazyScript(fun, table.forget(), packed, begin, end, + preludeStart, lineno, column); } /* static */ LazyScript* @@ -4026,7 +4046,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + uint32_t begin, uint32_t end, + uint32_t preludeStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4049,7 +4070,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.isDerivedClassConstructor = false; p.needsHomeObject = false; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column); + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + lineno, column); if (!res) return nullptr; @@ -4070,7 +4092,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column) + uint32_t preludeStart, uint32_t lineno, uint32_t column) { // Dummy atom which is not a valid property name. RootedAtom dummyAtom(cx, cx->names().comma); @@ -4079,7 +4101,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, // holding this lazy script. HandleFunction dummyFun = fun; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column); + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + lineno, column); if (!res) return nullptr; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 87da79901d..bb86355810 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -575,10 +575,6 @@ class ScriptSource introductionOffset_ = offset; hasIntroductionOffset_ = true; } - - uint32_t parameterListEnd() const { - return parameterListEnd_; - } }; class ScriptSourceHolder @@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ - /* Range of characters in scriptSource which contains this script's source. */ + // Range of characters in scriptSource which contains this script's source. + // each field points the following location. + // + // function * f(a, b) { return a + b; } + // ^ ^ ^ + // | | | + // | sourceStart_ sourceEnd_ + // | + // preludeStart_ + // uint32_t sourceStart_; uint32_t sourceEnd_; + uint32_t preludeStart_; // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if @@ -1020,7 +1026,7 @@ class JSScript : public js::gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - // Currently no padding is needed. + uint32_t padding; #endif // @@ -1031,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell static JSScript* Create(js::ExclusiveContext* cx, const JS::ReadOnlyCompileOptions& options, js::HandleObject sourceObject, uint32_t sourceStart, - uint32_t sourceEnd); + uint32_t sourceEnd, uint32_t preludeStart); void initCompartment(js::ExclusiveContext* cx); @@ -1178,6 +1184,10 @@ class JSScript : public js::gc::TenuredCell return sourceEnd_; } + size_t preludeStart() const { + return preludeStart_; + } + bool noScriptRval() const { return noScriptRval_; } @@ -1501,7 +1511,8 @@ class JSScript : public js::gc::TenuredCell bool mayReadFrameArgsDirectly(); JSFlatString* sourceData(JSContext* cx); - + JSFlatString* sourceDataWithPrelude(JSContext* cx); + static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); void setSourceObject(JSObject* object); @@ -1920,7 +1931,8 @@ class LazyScript : public gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - uint32_t padding; + // uint32_t padding; + // Currently no padding is needed. #endif private: @@ -1960,20 +1972,25 @@ class LazyScript : public gc::TenuredCell }; // Source location for the script. + // See the comment in JSScript for the details. uint32_t begin_; uint32_t end_; + uint32_t preludeStart_; + // Line and column of |begin_| position, that is the position where we + // start parsing. uint32_t lineno_; uint32_t column_; LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); + uint32_t begin, uint32_t end, uint32_t preludeStart, + uint32_t lineno, uint32_t column); // Create a LazyScript without initializing the closedOverBindings and the // innerFunctions. To be GC-safe, the caller must initialize both vectors // with valid atoms and functions. static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); public: static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits; @@ -1985,7 +2002,7 @@ class LazyScript : public gc::TenuredCell const frontend::AtomVector& closedOverBindings, Handle> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); // Create a LazyScript and initialize the closedOverBindings and the // innerFunctions with dummy values to be replaced in a later initialization @@ -2000,7 +2017,7 @@ class LazyScript : public gc::TenuredCell HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t lineno, uint32_t column); + uint32_t preludeStart, uint32_t lineno, uint32_t column); void initRuntimeFields(uint64_t packedFields); @@ -2173,6 +2190,9 @@ class LazyScript : public gc::TenuredCell uint32_t end() const { return end_; } + uint32_t preludeStart() const { + return preludeStart_; + } uint32_t lineno() const { return lineno_; } @@ -2199,7 +2219,8 @@ class LazyScript : public gc::TenuredCell }; /* If this fails, add/remove padding within LazyScript. */ -JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0); +static_assert(sizeof(LazyScript) % js::gc::CellSize == 0, + "Size of LazyScript must be an integral multiple of js::gc::CellSize"); struct ScriptAndCounts { diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 2237d1d7f0..2b66903637 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -318,6 +318,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod // Function constructor, this will be the first character in the function // source. Otherwise, it will be the opening parenthesis of the arguments // list. + uint32_t preludeStart; uint32_t srcStart; uint32_t srcBodyStart; bool strict; @@ -1758,6 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator if (!asmJSMetadata_) return false; + asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart; asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin; asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end; asmJSMetadata_->strict = parser_.pc->sc()->strict() && @@ -7049,6 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) TokenStream& tokenStream = m.tokenStream(); tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand); + uint32_t preludeStart = tokenStream.currentToken().pos.begin; *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end); TokenKind tk; @@ -7071,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) ParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator, + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator, SyncFunction, /* tryAnnexB = */ false); if (!funbox) return false; @@ -8054,7 +8057,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me return false; } - uint32_t begin = metadata.srcStart; + uint32_t begin = metadata.preludeStart; uint32_t end = metadata.srcEndAfterCurly(); Rooted src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) @@ -8085,7 +8088,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; - SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership); + SourceBufferHolder srcBuf(chars, end - begin, ownership); if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing())) return false; @@ -8537,6 +8540,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded return true; // See AsmJSMetadata comment as well as ModuleValidator::init(). + asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart; asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin; asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end; asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict(); @@ -8834,7 +8838,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda MOZ_ASSERT(IsAsmJSModule(fun)); const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS(); - uint32_t begin = metadata.srcStart; + uint32_t begin = metadata.preludeStart; uint32_t end = metadata.srcEndAfterCurly(); ScriptSource* source = metadata.scriptSource.get(); @@ -8843,17 +8847,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda if (addParenToLambda && fun->isLambda() && !out.append("(")) return nullptr; - if (!out.append("function ")) - return nullptr; - - if (fun->explicitName() && !out.append(fun->explicitName())) - return nullptr; - bool haveSource = source->hasSourceData(); if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) return nullptr; if (!haveSource) { + if (!out.append("function ")) + return nullptr; + if (fun->explicitName() && !out.append(fun->explicitName())) + return nullptr; if (!out.append("() {\n [sourceless code]\n}")) return nullptr; } else { From 9081722152add431bb6566ca767128f827fab0fc Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 13:51:57 +0100 Subject: [PATCH 02/37] Stage 1-2: Remove a space after comma in parameter list for generated function source. --- js/src/jsfun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index bdc2edff8f..e624aa415b 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1681,7 +1681,7 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator if (i < args.length() - 2) { // Step 9.d.iii. - if (!sb.append(", ")) + if (!sb.append(",")) return false; } } From f2622bd19f635d5c7eb100c933a211f8f06343f1 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 14:29:54 +0100 Subject: [PATCH 03/37] Stage 1-3: Generate better source in Object.prototype.toSource. Tag #960. --- js/src/builtin/Object.cpp | 280 ++++++++++++++++++++++++++------------ 1 file changed, 193 insertions(+), 87 deletions(-) diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index cd4ac122c9..389bb57dbb 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -9,11 +9,13 @@ #include "mozilla/ArrayUtils.h" #include "jscntxt.h" +#include "jsstr.h" #include "builtin/Eval.h" #include "frontend/BytecodeCompiler.h" #include "jit/InlinableNatives.h" #include "js/UniquePtr.h" +#include "vm/AsyncFunction.h" #include "vm/StringBuffer.h" #include "jsobjinlines.h" @@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp) return true; } +template +static bool +Consume(const CharT*& s, const CharT* e, const char *chars) +{ + size_t len = strlen(chars); + if (s + len >= e) + return false; + if (!EqualChars(s, chars, len)) + return false; + s += len; + return true; +} + +template +static void +ConsumeSpaces(const CharT*& s, const CharT* e) +{ + while (*s == ' ' && s < e) + s++; +} + /* * Given a function source string, return the offset and length of the part * between '(function $name' and ')'. @@ -133,37 +156,53 @@ static bool ArgsAndBodySubstring(mozilla::Range chars, size_t* outOffset, size_t* outLen) { const CharT* const start = chars.begin().get(); - const CharT* const end = chars.end().get(); const CharT* s = start; + const CharT* e = chars.end().get(); - uint8_t parenChomp = 0; - if (s[0] == '(') { + if (s == e) + return false; + + // Remove enclosing parentheses. + if (*s == '(' && *(e - 1) == ')') { s++; - parenChomp = 1; + e--; } - /* Try to jump "function" keyword. */ - s = js_strchr_limit(s, ' ', end); - if (!s) - return false; + (void) Consume(s, e, "async"); + ConsumeSpaces(s, e); + (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set")); + ConsumeSpaces(s, e); + (void) Consume(s, e, "*"); + ConsumeSpaces(s, e); - /* - * Jump over the function's name: it can't be encoded as part - * of an ECMA getter or setter. - */ - s = js_strchr_limit(s, '(', end); - if (!s) - return false; - - if (*s == ' ') + // Jump over the function's name. + if (Consume(s, e, "[")) { + s = js_strchr_limit(s, ']', e); + if (!s) + return false; s++; + ConsumeSpaces(s, e); + if (*s != '(') + return false; + } else { + s = js_strchr_limit(s, '(', e); + if (!s) + return false; + } *outOffset = s - start; - *outLen = end - s - parenChomp; + *outLen = e - s; MOZ_ASSERT(*outOffset + *outLen <= chars.length()); return true; } +enum class PropertyKind { + Getter, + Setter, + Method, + Normal +}; + JSString* js::ObjectToSource(JSContext* cx, HandleObject obj) { @@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) if (!buf.append('{')) return nullptr; - RootedValue v0(cx), v1(cx); - MutableHandleValue val[2] = {&v0, &v1}; - - RootedString str0(cx), str1(cx); - MutableHandleString gsop[2] = {&str0, &str1}; - AutoIdVector idv(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv)) return nullptr; bool comma = false; - for (size_t i = 0; i < idv.length(); ++i) { - RootedId id(cx, idv[i]); - Rooted desc(cx); - if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) - return nullptr; - - int valcnt = 0; - if (desc.object()) { - if (desc.isAccessorDescriptor()) { - if (desc.hasGetterObject() && desc.getterObject()) { - val[valcnt].setObject(*desc.getterObject()); - gsop[valcnt].set(cx->names().get); - valcnt++; - } - if (desc.hasSetterObject() && desc.setterObject()) { - val[valcnt].setObject(*desc.setterObject()); - gsop[valcnt].set(cx->names().set); - valcnt++; - } - } else { - valcnt = 1; - val[0].set(desc.value()); - gsop[0].set(nullptr); - } - } - + auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool { /* Convert id to a string. */ RootedString idstr(cx); if (JSID_IS_SYMBOL(id)) { RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id))); idstr = ValueToSource(cx, v); if (!idstr) - return nullptr; + return false; } else { RootedValue idv(cx, IdToValue(id)); idstr = ToString(cx, idv); if (!idstr) - return nullptr; + return false; /* - * If id is a string that's not an identifier, or if it's a negative - * integer, then it must be quoted. + * If id is a string that's not an identifier, or if it's a + * negative integer, then it must be quoted. */ if (JSID_IS_ATOM(id) ? !IsIdentifier(JSID_TO_ATOM(id)) @@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) { idstr = QuoteString(cx, idstr, char16_t('\'')); if (!idstr) - return nullptr; + return false; } } - for (int j = 0; j < valcnt; j++) { - /* Convert val[j] to its canonical source form. */ - JSString* valsource = ValueToSource(cx, val[j]); - if (!valsource) - return nullptr; + RootedString valsource(cx, ValueToSource(cx, val)); + if (!valsource) + return false; - RootedLinearString valstr(cx, valsource->ensureLinear(cx)); - if (!valstr) - return nullptr; + RootedLinearString valstr(cx, valsource->ensureLinear(cx)); + if (!valstr) + return false; - size_t voffset = 0; - size_t vlength = valstr->length(); + if (comma && !buf.append(", ")) + return false; + comma = true; - /* - * Remove '(function ' from the beginning of valstr and ')' from the - * end so that we can put "get" in front of the function definition. - */ - if (gsop[j] && IsFunctionObject(val[j])) { + size_t voffset, vlength; + + // Methods and accessors can return exact syntax of source, that fits + // into property without adding property name or "get"/"set" prefix. + // Use the exact syntax when the following conditions are met: + // + // * It's a function object + // (exclude proxies) + // * Function's kind and property's kind are same + // (this can be false for dynamically defined properties) + // * Function has explicit name + // (this can be false for computed property and dynamically defined + // properties) + // * Function's name and property's name are same + // (this can be false for dynamically defined properties) + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { + RootedFunction fun(cx); + if (val.toObject().is()) { + fun = &val.toObject().as(); + // Method's case should be checked on caller. + if (((fun->isGetter() && kind == PropertyKind::Getter) || + (fun->isSetter() && kind == PropertyKind::Setter) || + kind == PropertyKind::Method) && + fun->explicitName()) + { + bool result; + if (!EqualStrings(cx, fun->explicitName(), idstr, &result)) + return false; + + if (result) { + if (!buf.append(valstr)) + return false; + return true; + } + } + } + + { + // When falling back try to generate a better string + // representation by skipping the prelude, and also removing + // the enclosing parentheses. bool success; JS::AutoCheckCannotGC nogc; if (valstr->hasLatin1Chars()) @@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) else success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength); if (!success) - gsop[j].set(nullptr); + kind = PropertyKind::Normal; } - if (comma && !buf.append(", ")) - return nullptr; - comma = true; + if (kind == PropertyKind::Getter) { + if (!buf.append("get ")) + return false; + } else if (kind == PropertyKind::Setter) { + if (!buf.append("set ")) + return false; + } else if (kind == PropertyKind::Method && fun) { + if (IsWrappedAsyncFunction(fun)) { + if (!buf.append("async ")) + return false; + } - if (gsop[j]) { - if (!buf.append(gsop[j]) || !buf.append(' ')) + if (fun->isStarGenerator()) { + if (!buf.append('*')) + return false; + } + } + } + + bool needsBracket = JSID_IS_SYMBOL(id); + if (needsBracket && !buf.append('[')) + return false; + if (!buf.append(idstr)) + return false; + if (needsBracket && !buf.append(']')) + return false; + + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { + if (!buf.appendSubstring(valstr, voffset, vlength)) + return false; + } else { + if (!buf.append(':')) + return false; + if (!buf.append(valstr)) + return false; + } + return true; + }; + + RootedId id(cx); + Rooted desc(cx); + RootedValue val(cx); + RootedFunction fun(cx); + for (size_t i = 0; i < idv.length(); ++i) { + id = idv[i]; + if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) + return nullptr; + + if (!desc.object()) + continue; + + if (desc.isAccessorDescriptor()) { + if (desc.hasGetterObject() && desc.getterObject()) { + val.setObject(*desc.getterObject()); + if (!AddProperty(id, val, PropertyKind::Getter)) return nullptr; } - if (JSID_IS_SYMBOL(id) && !buf.append('[')) - return nullptr; - if (!buf.append(idstr)) - return nullptr; - if (JSID_IS_SYMBOL(id) && !buf.append(']')) - return nullptr; - if (!buf.append(gsop[j] ? ' ' : ':')) - return nullptr; - - if (!buf.appendSubstring(valstr, voffset, vlength)) - return nullptr; + if (desc.hasSetterObject() && desc.setterObject()) { + val.setObject(*desc.setterObject()); + if (!AddProperty(id, val, PropertyKind::Setter)) + return nullptr; + } + continue; } + + val.set(desc.value()); + if (IsFunctionObject(val, fun.address())) { + if (IsWrappedAsyncFunction(fun)) + fun = GetUnwrappedAsyncFunction(fun); + + if (fun->isMethod()) { + if (!AddProperty(id, val, PropertyKind::Method)) + return nullptr; + continue; + } + } + + if (!AddProperty(id, val, PropertyKind::Normal)) + return nullptr; } if (!buf.append('}')) From 5676f63f4155de591ab0c0a0884a5dd2dd1847c4 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 3 Feb 2019 08:21:19 +0100 Subject: [PATCH 04/37] Stage 1-4: Update tests --- .../test/browser_webconsole_output_02.js | 4 +- .../server/tests/unit/test_listsources-04.js | 4 +- js/src/jit-test/tests/asm.js/testSource.js | 48 +-- .../basic/function-tosource-bug779694.js | 2 +- .../basic/function-tosource-constructor.js | 16 +- .../tests/basic/function-tosource-getset.js | 10 +- js/src/jit-test/tests/basic/testLet.js | 2 +- js/src/jit-test/tests/debug/Script-gc-02.js | 2 +- js/src/jit-test/tests/debug/Script-gc-03.js | 2 +- .../tests/debug/Script-sourceStart-04.js | 4 +- js/src/jit-test/tests/debug/Source-text-02.js | 1 + js/src/jit-test/tests/latin1/assorted.js | 6 +- js/src/jit-test/tests/latin1/function.js | 4 +- .../ecma_2017/Function/Object-toSource.js | 370 ++++++++++++++++++ js/src/tests/ecma_2017/Function/browser.js | 0 js/src/tests/ecma_2017/Function/shell.js | 0 js/src/tests/ecma_6/Generators/runtime.js | 2 +- js/src/tests/js1_5/Scope/regress-185485.js | 2 +- .../js1_7/extensions/regress-354945-01.js | 2 +- .../js1_7/extensions/regress-354945-02.js | 2 +- .../tests/js1_8_5/regress/regress-584355.js | 2 +- .../webstorage/storage_string_conversion.html | 6 +- toolkit/modules/tests/xpcshell/test_Log.js | 6 +- 23 files changed, 434 insertions(+), 63 deletions(-) create mode 100644 js/src/tests/ecma_2017/Function/Object-toSource.js create mode 100644 js/src/tests/ecma_2017/Function/browser.js create mode 100644 js/src/tests/ecma_2017/Function/shell.js diff --git a/devtools/client/webconsole/test/browser_webconsole_output_02.js b/devtools/client/webconsole/test/browser_webconsole_output_02.js index 4c61cf0416..837ec673c4 100644 --- a/devtools/client/webconsole/test/browser_webconsole_output_02.js +++ b/devtools/client/webconsole/test/browser_webconsole_output_02.js @@ -24,7 +24,7 @@ var inputTests = [ { input: "(function() { return 42; })", output: "function ()", - printOutput: "function () { return 42; }", + printOutput: "function() { return 42; }", suppressClick: true }, @@ -40,7 +40,7 @@ var inputTests = [ { input: "testobj1.testfn2", output: "function testfn2()", - printOutput: "function () { return 42; }", + printOutput: "function() { return 42; }", suppressClick: true }, diff --git a/devtools/server/tests/unit/test_listsources-04.js b/devtools/server/tests/unit/test_listsources-04.js index 6da99a6cec..8e1a57bf02 100644 --- a/devtools/server/tests/unit/test_listsources-04.js +++ b/devtools/server/tests/unit/test_listsources-04.js @@ -29,12 +29,12 @@ function run_test_with_server(server, cb) { addSources(debuggee); threadClient.getSources(Task.async(function* (res) { - do_check_true(res.sources.length === 3, "3 sources exist"); + do_check_eq(res.sources.length, 3, "3 sources exist"); yield threadClient.reconfigure({ useSourceMaps: false }); threadClient.getSources(function(res) { - do_check_true(res.sources.length === 1, "1 source exist"); + do_check_eq(res.sources.length, 1, "1 source exist"); client.close().then(cb); }); })); diff --git a/js/src/jit-test/tests/asm.js/testSource.js b/js/src/jit-test/tests/asm.js/testSource.js index b44c52a6bc..d7ad428640 100644 --- a/js/src/jit-test/tests/asm.js/testSource.js +++ b/js/src/jit-test/tests/asm.js/testSource.js @@ -32,7 +32,7 @@ var f0 = function() { } -funcBody1 = funcBody.replace('function f0','function '); +funcBody1 = funcBody.replace('function f0','function'); assertEq(f0.toString(), funcBody1); assertEq(f0.toSource(), '(' + funcBody1 + ')'); @@ -48,14 +48,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f0 = new Function(bodyOnly); -assertEq(f0.toString(), "function anonymous() {\n" + bodyOnly + "\n}"); -assertEq(f0.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})"); +assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}"); +assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function(bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous() {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})"); } })(); @@ -91,7 +91,7 @@ f1 = function(glob) { } -funcBody1 = funcBody.replace('function f1', 'function '); +funcBody1 = funcBody.replace('function f1', 'function'); assertEq(f1.toString(), funcBody1); assertEq(f1.toSource(), '(' + funcBody1 + ')'); @@ -107,14 +107,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f1 = new Function('glob', bodyOnly); -assertEq(f1.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}"); -assertEq(f1.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})"); +assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}"); +assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})"); } })(); @@ -144,14 +144,14 @@ var funcBody = 'function f2(glob, ffi) {\n\ assertEq(f2.toString(), funcBody); assertEq(f2.toSource(), funcBody); -f2 = function (glob, ffi) { +f2 = function(glob, ffi) { "use asm"; function g() {} return g; } -funcBody1 = funcBody.replace('function f2', 'function '); +funcBody1 = funcBody.replace('function f2', 'function'); assertEq(f2.toString(), funcBody1); assertEq(f2.toSource(), '(' + funcBody1 + ')'); @@ -167,14 +167,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f2 = new Function('glob', 'ffi', bodyOnly); -assertEq(f2.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}"); -assertEq(f2.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})"); +assertEq(f2.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}"); +assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', 'ffi', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})"); } })(); @@ -204,14 +204,14 @@ var funcBody = 'function f3(glob, ffi, heap) {\n\ assertEq(f3.toString(), funcBody); assertEq(f3.toSource(), funcBody); -f3 = function (glob, ffi, heap) { +f3 = function(glob, ffi, heap) { "use asm"; function g() {} return g; } -funcBody1 = funcBody.replace('function f3', 'function '); +funcBody1 = funcBody.replace('function f3', 'function'); assertEq(f3.toString(), funcBody1); assertEq(f3.toSource(), '(' + funcBody1 + ')'); @@ -227,14 +227,14 @@ assertEq(g.toString(), funcBody2); assertEq(g.toSource(), '(' + funcBody2 + ')'); f3 = new Function('glob', 'ffi', 'heap', bodyOnly); -assertEq(f3.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}"); -assertEq(f3.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})"); +assertEq(f3.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}"); +assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})"); if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var m = new Function('glob', 'ffi', 'heap', bodyOnly); assertEq(isAsmJSModuleLoadedFromCache(m), true); - assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}"); - assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})"); + assertEq(m.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}"); + assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})"); } })(); @@ -243,7 +243,7 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) { (function() { var funcSource = - `function (glob, ffi, heap) { + `function(glob, ffi, heap) { "use asm"; function g() {} return g; @@ -252,7 +252,7 @@ var funcSource = var f4 = eval("\"use strict\";\n(" + funcSource + ")"); var expectedToString = funcSource; -var expectedToSource = '(' + expectedToString + ')' +var expectedToSource = '(' + expectedToString + ')'; assertEq(f4.toString(), expectedToString); assertEq(f4.toSource(), expectedToSource); diff --git a/js/src/jit-test/tests/basic/function-tosource-bug779694.js b/js/src/jit-test/tests/basic/function-tosource-bug779694.js index 3893d3ff2c..782b2594bc 100644 --- a/js/src/jit-test/tests/basic/function-tosource-bug779694.js +++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js @@ -5,4 +5,4 @@ for (var i=0; i<400; ++i) { x += String.fromCharCode(i * 289); } var s = "'" + x + "'"; -assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}"); +assertEq(Function("evt", s).toString(), "function anonymous(evt\n) {\n" + s + "\n}"); diff --git a/js/src/jit-test/tests/basic/function-tosource-constructor.js b/js/src/jit-test/tests/basic/function-tosource-constructor.js index e1d1443640..9a8961fe2c 100644 --- a/js/src/jit-test/tests/basic/function-tosource-constructor.js +++ b/js/src/jit-test/tests/basic/function-tosource-constructor.js @@ -1,14 +1,14 @@ var f = Function("a", "b", "return a + b;"); -assertEq(f.toString(), "function anonymous(a, b) {\nreturn a + b;\n}"); -assertEq(f.toSource(), "(function anonymous(a, b) {\nreturn a + b;\n})"); +assertEq(f.toString(), "function anonymous(a,b\n) {\nreturn a + b;\n}"); +assertEq(f.toSource(), "(function anonymous(a,b\n) {\nreturn a + b;\n})"); assertEq(decompileFunction(f), f.toString()); f = Function("a", "...rest", "return rest[42] + b;"); -assertEq(f.toString(), "function anonymous(a, ...rest) {\nreturn rest[42] + b;\n}"); -assertEq(f.toSource(), "(function anonymous(a, ...rest) {\nreturn rest[42] + b;\n})") +assertEq(f.toString(), "function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n}"); +assertEq(f.toSource(), "(function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n})") assertEq(decompileFunction(f), f.toString()); f = Function(""); -assertEq(f.toString(), "function anonymous() {\n\n}"); +assertEq(f.toString(), "function anonymous(\n) {\n\n}"); f = Function("", "(abc)"); -assertEq(f.toString(), "function anonymous() {\n(abc)\n}"); -f = Function("", "return function (a, b) a + b;")(); -assertEq(f.toString(), "function (a, b) a + b"); +assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}"); +f = Function("", "return function (a,b) a + b;")(); +assertEq(f.toString(), "function (a,b) a + b"); diff --git a/js/src/jit-test/tests/basic/function-tosource-getset.js b/js/src/jit-test/tests/basic/function-tosource-getset.js index 36c6d010e7..1804d38f2f 100644 --- a/js/src/jit-test/tests/basic/function-tosource-getset.js +++ b/js/src/jit-test/tests/basic/function-tosource-getset.js @@ -1,7 +1,7 @@ var o = {get prop() a + b, set prop(x) a + b}; var prop = Object.getOwnPropertyDescriptor(o, "prop"); -assertEq(prop.get.toString(), "function get prop() a + b"); -assertEq(prop.get.toSource(), "(function get prop() a + b)"); -assertEq(prop.set.toString(), "function set prop(x) a + b"); -assertEq(prop.set.toSource(), "(function set prop(x) a + b)"); -assertEq(o.toSource(), "({get prop () a + b, set prop (x) a + b})"); +assertEq(prop.get.toString(), "get prop() { a + b; }"); +assertEq(prop.get.toSource(), "get prop() { a + b; }"); +assertEq(prop.set.toString(), "set prop(x) { a + b; }"); +assertEq(prop.set.toSource(), "set prop(x) { a + b; }"); +assertEq(o.toSource(), "({get prop() { a + b; }, set prop(x) { a + b; }})"); diff --git a/js/src/jit-test/tests/basic/testLet.js b/js/src/jit-test/tests/basic/testLet.js index 263c3eb8a3..9a2f391973 100644 --- a/js/src/jit-test/tests/basic/testLet.js +++ b/js/src/jit-test/tests/basic/testLet.js @@ -9,7 +9,7 @@ function test(str, arg, result) var fun = new Function('x', str); var got = fun.toSource(); - var expect = '(function anonymous(x) {\n' + str + '\n})'; + var expect = '(function anonymous(x\n) {\n' + str + '\n})'; if (got !== expect) { print("GOT: " + got); print("EXPECT: " + expect); diff --git a/js/src/jit-test/tests/debug/Script-gc-02.js b/js/src/jit-test/tests/debug/Script-gc-02.js index 04dd4b220f..9689a6ebe4 100644 --- a/js/src/jit-test/tests/debug/Script-gc-02.js +++ b/js/src/jit-test/tests/debug/Script-gc-02.js @@ -10,5 +10,5 @@ assertEq(arr.length, 10); gc(); for (var i = 0; i < arr.length; i++) - assertEq(arr[i].lineCount, 3); + assertEq(arr[i].lineCount, 4); diff --git a/js/src/jit-test/tests/debug/Script-gc-03.js b/js/src/jit-test/tests/debug/Script-gc-03.js index 30c3e8dbca..5ecb4556f2 100644 --- a/js/src/jit-test/tests/debug/Script-gc-03.js +++ b/js/src/jit-test/tests/debug/Script-gc-03.js @@ -10,6 +10,6 @@ assertEq(arr.length, 100); gc(g); for (var i = 0; i < arr.length; i++) - assertEq(arr[i].lineCount, 3); + assertEq(arr[i].lineCount, 4); gc(); diff --git a/js/src/jit-test/tests/debug/Script-sourceStart-04.js b/js/src/jit-test/tests/debug/Script-sourceStart-04.js index 2aa382b7b4..4546818e47 100644 --- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js +++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js @@ -20,6 +20,6 @@ function test(string, range) { } test("eval('2 * 3')", [0, 5]); -test("new Function('2 * 3')", [0, 12]); -test("new Function('x', 'x * x')", [0, 13]); +test("new Function('2 * 3')", [0, 31]); +test("new Function('x', 'x * x')", [0, 32]); assertEq(count, 6); diff --git a/js/src/jit-test/tests/debug/Source-text-02.js b/js/src/jit-test/tests/debug/Source-text-02.js index 64cfce92a4..46e76015ec 100644 --- a/js/src/jit-test/tests/debug/Source-text-02.js +++ b/js/src/jit-test/tests/debug/Source-text-02.js @@ -3,6 +3,7 @@ let g = newGlobal(); let dbg = new Debugger(g); +var text; var count = 0; dbg.onNewScript = function (script) { ++count; diff --git a/js/src/jit-test/tests/latin1/assorted.js b/js/src/jit-test/tests/latin1/assorted.js index cef79cb96f..1389a1adae 100644 --- a/js/src/jit-test/tests/latin1/assorted.js +++ b/js/src/jit-test/tests/latin1/assorted.js @@ -12,18 +12,18 @@ var o = {}; Object.defineProperty(o, "prop", {get: function() { return 1; }, set: function() { return 2; }, enumerable: true, configurable: true}); -assertEq(o.toSource(), "({get prop () { return 1; }, set prop () { return 2; }})"); +assertEq(o.toSource(), "({get prop() { return 1; }, set prop() { return 2; }})"); // obj.toSource TwoByte Object.defineProperty(o, "prop", {get: function() { return "\u1200"; }, set: function() { return "\u1200"; }, enumerable: true}); -assertEq(o.toSource(), '({get prop () { return "\\u1200"; }, set prop () { return "\\u1200"; }})'); +assertEq(o.toSource(), '({get prop() { return "\\u1200"; }, set prop() { return "\\u1200"; }})'); var ff = function() { return 10; }; ff.toSource = function() { return "((11))"; } Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true}); -assertEq(o.toSource(), "({prop:((11)), prop:((11))})"); +assertEq(o.toSource(), "({get prop(11), set prop(11)})"); // XDR load(libdir + 'bytecode-cache.js'); diff --git a/js/src/jit-test/tests/latin1/function.js b/js/src/jit-test/tests/latin1/function.js index a0dedf2516..07a76733a3 100644 --- a/js/src/jit-test/tests/latin1/function.js +++ b/js/src/jit-test/tests/latin1/function.js @@ -6,11 +6,11 @@ function test() { var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1); assertEq(f(10, 20), 60); - assertEq(f.toSource().includes("arg1\u1200, arg2"), true); + assertEq(f.toSource().includes("arg1\u1200,arg2"), true); var bodyTwoByte = "return arg1\u1200 + arg2;"; f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte); assertEq(f(30, 40), 70); - assertEq(f.toSource().includes("arg1\u1200, arg2"), true); + assertEq(f.toSource().includes("arg1\u1200,arg2"), true); } test(); diff --git a/js/src/tests/ecma_2017/Function/Object-toSource.js b/js/src/tests/ecma_2017/Function/Object-toSource.js new file mode 100644 index 0000000000..33b9e588ee --- /dev/null +++ b/js/src/tests/ecma_2017/Function/Object-toSource.js @@ -0,0 +1,370 @@ +var BUGNUMBER = 1317400; +var summary = "Function string representation in Object.prototype.toSource"; + +print(BUGNUMBER + ": " + summary); + +// Methods. + +assertEq(({ foo(){} }).toSource(), + "({foo(){}})"); +assertEq(({ *foo(){} }).toSource(), + "({*foo(){}})"); +assertEq(({ async foo(){} }).toSource(), + "({async foo(){}})"); + +assertEq(({ 1(){} }).toSource(), + "({1(){}})"); + +// Methods with more spacing. +// Spacing is kept. + +assertEq(({ foo (){} }).toSource(), + "({foo (){}})"); +assertEq(({ foo () {} }).toSource(), + "({foo () {}})"); + +// Methods with computed name. +// Method syntax is composed. + +let name = "foo"; +assertEq(({ [name](){} }).toSource(), + "({foo(){}})"); +assertEq(({ *[name](){} }).toSource(), + "({*foo(){}})"); +assertEq(({ async [name](){} }).toSource(), + "({async foo(){}})"); + +assertEq(({ [ Symbol.iterator ](){} }).toSource(), + "({[Symbol.iterator](){}})"); + +// Accessors. + +assertEq(({ get foo(){} }).toSource(), + "({get foo(){}})"); +assertEq(({ set foo(v){} }).toSource(), + "({set foo(v){}})"); + +// Accessors with computed name. +// Method syntax is composed. + +assertEq(({ get [name](){} }).toSource(), + "({get foo(){}})"); +assertEq(({ set [name](v){} }).toSource(), + "({set foo(v){}})"); + +assertEq(({ get [ Symbol.iterator ](){} }).toSource(), + "({get [Symbol.iterator](){}})"); +assertEq(({ set [ Symbol.iterator ](v){} }).toSource(), + "({set [Symbol.iterator](v){}})"); + +// Getter and setter with same name. +// Getter always comes before setter. + +assertEq(({ get foo(){}, set foo(v){} }).toSource(), + "({get foo(){}, set foo(v){}})"); +assertEq(({ set foo(v){}, get foo(){} }).toSource(), + "({get foo(){}, set foo(v){}})"); + +// Normal properties. + +assertEq(({ foo: function(){} }).toSource(), + "({foo:(function(){})})"); +assertEq(({ foo: function bar(){} }).toSource(), + "({foo:(function bar(){})})"); +assertEq(({ foo: function*(){} }).toSource(), + "({foo:(function*(){})})"); +assertEq(({ foo: async function(){} }).toSource(), + "({foo:(async function(){})})"); + +// Normal properties with computed name. + +assertEq(({ [ Symbol.iterator ]: function(){} }).toSource(), + "({[Symbol.iterator]:(function(){})})"); + +// Dynamically defined properties with function expression. +// Never become a method syntax. + +let obj = {}; +obj.foo = function() {}; +assertEq(obj.toSource(), + "({foo:(function() {})})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function() {}}); +assertEq(obj.toSource(), + "({})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({foo:(function() {})})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true}); +assertEq(obj.toSource(), + "({foo:(function bar() {})})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {value: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({[Symbol.iterator]:(function() {})})"); + +// Dynamically defined property with other object's method. +// Method syntax is composed. + +let method = ({foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "foo", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({bar() {}})"); + +method = ({*foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({*bar() {}})"); + +method = ({async foo() {}}).foo; + +obj = {}; +Object.defineProperty(obj, "bar", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({async bar() {}})"); + +// Dynamically defined accessors. +// Accessor syntax is composed. + +obj = {}; +Object.defineProperty(obj, "foo", {get: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {get: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get [Symbol.iterator]() {}})"); + +obj = {}; +Object.defineProperty(obj, Symbol.iterator, {set: function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set [Symbol.iterator]() {}})"); + +// Dynamically defined accessors with other object's accessors. +// Accessor syntax is composed. + +let accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set; +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set; +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +// Methods with proxy. +// Treated as normal property. + +method = ({foo() {}}).foo; +let handler = { + get(that, name) { + if (name == "toSource") { + return function() { + return that.toSource(); + }; + } + return that[name]; + } +}; +let proxy = new Proxy(method, handler); + +obj = {}; +Object.defineProperty(obj, "foo", {value: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({foo:foo() {}})"); + +// Accessors with proxy. +// Accessor syntax is composed. + +accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get; +proxy = new Proxy(accessor, handler); + +obj = {}; +Object.defineProperty(obj, "foo", {get: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: proxy, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +// Methods from other global. +// Treated as normal property. + +let g = newGlobal(); + +method = g.eval("({ foo() {} }).foo"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: method, enumerable: true}); +assertEq(obj.toSource(), + "({foo:foo() {}})"); + +// Accessors from other global. +// Accessor syntax is composed. + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {get: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({get foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: accessor, enumerable: true}); +assertEq(obj.toSource(), + "({set foo(v) {}})"); + +// **** Some weird cases **** + +// Accessors with generator or async. + +obj = {}; +Object.defineProperty(obj, "foo", {get: function*() {}, enumerable: true}); +assertEq(obj.toSource(), + "({get foo() {}})"); + +obj = {}; +Object.defineProperty(obj, "foo", {set: async function() {}, enumerable: true}); +assertEq(obj.toSource(), + "({set foo() {}})"); + +// Modified toSource. + +obj = { foo() {} }; +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({hello})"); + +obj = { foo() {} }; +obj.foo.toSource = () => "bar() {}"; +assertEq(obj.toSource(), + "({bar() {}})"); + +// Modified toSource with different method name. + +obj = {}; +Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: function* bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +obj = {}; +Object.defineProperty(obj, "foo", {value: async function bar() {}, enumerable: true}); +obj.foo.toSource = () => "hello"; +assertEq(obj.toSource(), + "({foo:hello})"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_2017/Function/browser.js b/js/src/tests/ecma_2017/Function/browser.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/ecma_2017/Function/shell.js b/js/src/tests/ecma_2017/Function/shell.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/tests/ecma_6/Generators/runtime.js b/js/src/tests/ecma_6/Generators/runtime.js index c4d3bb6a66..7146eef9ff 100644 --- a/js/src/tests/ecma_6/Generators/runtime.js +++ b/js/src/tests/ecma_6/Generators/runtime.js @@ -109,7 +109,7 @@ function TestGeneratorFunction() { // Doesn't matter particularly what string gets serialized, as long // as it contains "function*" and "yield 10". assertEq(GeneratorFunction('yield 10').toString(), - "function* anonymous() {\nyield 10\n}"); + "function* anonymous(\n) {\nyield 10\n}"); } TestGeneratorFunction(); diff --git a/js/src/tests/js1_5/Scope/regress-185485.js b/js/src/tests/js1_5/Scope/regress-185485.js index 19d190eeaa..a75bf885a9 100644 --- a/js/src/tests/js1_5/Scope/regress-185485.js +++ b/js/src/tests/js1_5/Scope/regress-185485.js @@ -94,7 +94,7 @@ with (x) } status = inSection(5); actual = x.g.toString(); -expect = (function () {}).toString(); +expect = (function() {}).toString(); addThis(); diff --git a/js/src/tests/js1_7/extensions/regress-354945-01.js b/js/src/tests/js1_7/extensions/regress-354945-01.js index 76f1a3c82f..1c57db0f7f 100644 --- a/js/src/tests/js1_7/extensions/regress-354945-01.js +++ b/js/src/tests/js1_7/extensions/regress-354945-01.js @@ -6,7 +6,7 @@ //----------------------------------------------------------------------------- var BUGNUMBER = 354945; var summary = 'Do not crash with new Iterator'; -var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value'; +var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value'; var actual; diff --git a/js/src/tests/js1_7/extensions/regress-354945-02.js b/js/src/tests/js1_7/extensions/regress-354945-02.js index 261bf7de17..abef90f77f 100644 --- a/js/src/tests/js1_7/extensions/regress-354945-02.js +++ b/js/src/tests/js1_7/extensions/regress-354945-02.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value'; + expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value'; var obj = {}; obj.__iterator__ = function(){ }; try diff --git a/js/src/tests/js1_8_5/regress/regress-584355.js b/js/src/tests/js1_8_5/regress/regress-584355.js index 4ddfe65d35..7d1b81a2ec 100644 --- a/js/src/tests/js1_8_5/regress/regress-584355.js +++ b/js/src/tests/js1_8_5/regress/regress-584355.js @@ -1,5 +1,5 @@ var actual; -var expect = "function f() { ff (); }"; +var expect = "function f () { ff (); }"; function fun() { (new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) (); } diff --git a/testing/web-platform/tests/webstorage/storage_string_conversion.html b/testing/web-platform/tests/webstorage/storage_string_conversion.html index 518b27521c..c76eddfec3 100644 --- a/testing/web-platform/tests/webstorage/storage_string_conversion.html +++ b/testing/web-platform/tests/webstorage/storage_string_conversion.html @@ -22,21 +22,21 @@ storage.b = 0; assert_equals(storage.b, "0"); storage.c = function(){}; - assert_equals(storage.c, "function (){}"); + assert_equals(storage.c, "function(){}"); storage.setItem('d', null); assert_equals(storage.d, "null"); storage.setItem('e', 0); assert_equals(storage.e, "0"); storage.setItem('f', function(){}); - assert_equals(storage.f, "function (){}"); + assert_equals(storage.f, "function(){}"); storage['g'] = null; assert_equals(storage.g, "null"); storage['h'] = 0; assert_equals(storage.h, "0"); storage['i'] = function(){}; - assert_equals(storage.f, "function (){}"); + assert_equals(storage.f, "function(){}"); }, name + " only stores strings"); }); diff --git a/toolkit/modules/tests/xpcshell/test_Log.js b/toolkit/modules/tests/xpcshell/test_Log.js index 429bbcc503..6aee99c936 100644 --- a/toolkit/modules/tests/xpcshell/test_Log.js +++ b/toolkit/modules/tests/xpcshell/test_Log.js @@ -381,12 +381,12 @@ add_task(function* log_message_with_params() { ob = function() {}; ob.toJSON = function() {throw "oh noes JSON"}; do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}), - 'Fail is (function () {})'); + 'Fail is (function() {})'); // Fall back to .toString if both .toJSON and .toSource fail. ob.toSource = function() {throw "oh noes SOURCE"}; do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}), - 'Fail is function () {}'); + 'Fail is function() {}'); // Fall back to '[object]' if .toJSON, .toSource and .toString fail. ob.toString = function() {throw "oh noes STRING"}; @@ -450,7 +450,7 @@ add_task(function* log_message_with_params() { // doesn't cause the logger to fail. let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}}; do_check_eq(formatMessage("Broken valueOf ${}", vOf), - 'Broken valueOf ({a:1, valueOf:(function () {throw "oh noes valueOf"})})'); + 'Broken valueOf ({a:1, valueOf:(function() {throw "oh noes valueOf"})})'); // Test edge cases of bad data to formatter: // If 'params' is not an object, format it as a basic type. From e9ffb69b023c0b373b6a5b748a7fa951b4ddea4f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 20:54:29 +0200 Subject: [PATCH 05/37] Split Parser::report into Parser::zeport (a temporary name) that uses the current offset, and Parser::reportWithNode that derives it from a Node. --- js/src/frontend/BytecodeEmitter.cpp | 6 +- js/src/frontend/Parser.cpp | 387 +++++++++++++--------------- js/src/frontend/Parser.h | 13 +- js/src/frontend/TokenStream.h | 1 + 4 files changed, 198 insertions(+), 209 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c5e62ae340..71289e84a7 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3559,9 +3559,11 @@ BytecodeEmitter::maybeSetSourceMap() if (parser->options().sourceMapURL()) { // Warn about the replacement, but use the new one. if (parser->ss->hasSourceMapURL()) { - if(!parser->report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA, - parser->ss->filename(), "//# sourceMappingURL")) + if (!parser->reportNoOffset(ParseWarning, false, JSMSG_ALREADY_HAS_PRAGMA, + parser->ss->filename(), "//# sourceMappingURL")) + { return false; + } } if (!parser->ss->setSourceMapURL(cx, parser->options().sourceMapURL())) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1ba725a829..26b3c2c255 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -69,7 +69,7 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - report(ParseError, false, null(), errno); \ + zeport(ParseError, false, errno); \ return null(); \ } \ JS_END_MACRO @@ -596,7 +596,18 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o template bool -Parser::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) +Parser::zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(kind, strict, pos().begin, errorNumber, args); + va_end(args); + return result; +} + +template +bool +Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) { uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin; @@ -826,8 +837,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, - "script", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -850,7 +860,7 @@ Parser::reportBadReturn(Node pn, ParseReportKind kind, } else { errnum = anonerrnum; } - return report(kind, pc->sc()->strict(), pn, errnum, name.ptr()); + return reportWithNode(kind, pc->sc()->strict(), pn, errnum, name.ptr()); } /* @@ -941,7 +951,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -953,11 +963,8 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - if (!report(ParseStrictError, pc->sc()->strict(), null(), - JSMSG_DUPLICATE_FORMAL, bytes.ptr())) - { + if (!zeport(ParseStrictError, pc->sc()->strict(), JSMSG_DUPLICATE_FORMAL, bytes.ptr())) return false; - } } *duplicatedParam = true; @@ -1239,7 +1246,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -1446,8 +1453,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1912,7 +1918,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + zeport(ParseError, false, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2010,7 +2016,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2330,8 +2336,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, - "function body", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2736,7 +2741,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - report(ParseError, false, null(), + zeport(ParseError, false, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2769,13 +2774,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST); + zeport(ParseError, false, JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2787,15 +2792,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - report(ParseError, false, null(), - JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2806,7 +2810,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - report(ParseError, false, null(), JSMSG_NO_REST_NAME); + zeport(ParseError, false, JSMSG_NO_REST_NAME); return false; } } @@ -2817,7 +2821,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2845,7 +2849,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - report(ParseError, false, null(), JSMSG_RESERVED_ID, "await"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); return false; } @@ -2865,12 +2869,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - report(ParseError, false, null(), JSMSG_MISSING_FORMAL); + zeport(ParseError, false, JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS); + zeport(ParseError, false, JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2885,12 +2889,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT); + zeport(ParseError, false, JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS); + zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); return false; } @@ -2934,12 +2938,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - report(ParseError, false, null(), - JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL); + zeport(ParseError, false, JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2952,7 +2955,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3082,7 +3085,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - report(ParseError, false, null(), JSMSG_TEMPLSTR_UNTERM_EXPR); + zeport(ParseError, false, JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3474,7 +3477,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - report(ParseError, false, null(), JSMSG_BAD_ARROW_ARGS); + zeport(ParseError, false, JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3482,7 +3485,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END); + zeport(ParseError, false, JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3495,7 +3498,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); + zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3504,7 +3507,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); + zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3537,7 +3540,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY); + zeport(ParseError, false, JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3595,7 +3598,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3612,7 +3615,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT); + zeport(ParseError, false, JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3648,7 +3651,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3693,10 +3696,11 @@ template bool Parser::checkUnescapedName() { - if (!tokenStream.currentToken().nameContainsEscape()) + const Token& token = tokenStream.currentToken(); + if (!token.nameContainsEscape()) return true; - report(ParseError, false, null(), JSMSG_ESCAPED_KEYWORD); + reportWithOffset(ParseError, false, token.pos.begin, JSMSG_ESCAPED_KEYWORD); return false; } @@ -3820,7 +3824,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL); + zeport(ParseError, false, JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3828,7 +3832,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); + return reportWithNode(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; @@ -3860,10 +3864,8 @@ Parser::statementList(YieldHandling yieldHandling) if (tt == TOK_EOF || tt == TOK_RC) break; if (afterReturn) { - TokenPos pos(0, 0); - if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) + if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) return null(); - statementBegin = pos.begin; } Node next = statementListItem(yieldHandling, canHaveDirectives); if (!next) { @@ -3909,7 +3911,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN)) + if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -3966,7 +3968,8 @@ Parser::PossibleError::hasError(ErrorKind kind) template void -Parser::PossibleError::setPending(ErrorKind kind, Node pn, unsigned errorNumber) +Parser::PossibleError::setPending(ErrorKind kind, const TokenPos& pos, + unsigned errorNumber) { // Don't overwrite a previously recorded error. if (hasError(kind)) @@ -3975,23 +3978,25 @@ Parser::PossibleError::setPending(ErrorKind kind, Node pn, unsigne // If we report an error later, we'll do it from the position where we set // the state to pending. Error& err = error(kind); - err.offset_ = (pn ? parser_.handler.getPosition(pn) : parser_.pos()).begin; + err.offset_ = pos.begin; err.errorNumber_ = errorNumber; err.state_ = ErrorState::Pending; } template void -Parser::PossibleError::setPendingDestructuringError(Node pn, unsigned errorNumber) +Parser::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos, + unsigned errorNumber) { - setPending(ErrorKind::Destructuring, pn, errorNumber); + setPending(ErrorKind::Destructuring, pos, errorNumber); } template void -Parser::PossibleError::setPendingExpressionError(Node pn, unsigned errorNumber) +Parser::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos, + unsigned errorNumber) { - setPending(ErrorKind::Expression, pn, errorNumber); + setPending(ErrorKind::Expression, pos, errorNumber); } template @@ -4066,7 +4071,7 @@ Parser::checkAssignmentToCall(Node target, unsigned msg) // concerned about sites using this in dead code, so forbid it only in // strict mode code (or if the werror option has been set), and otherwise // warn. - return report(ParseStrictError, pc->sc()->strict(), target, msg); + return reportWithNode(ParseStrictError, pc->sc()->strict(), target, msg); } template <> @@ -4079,7 +4084,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybe::checkDestructuringName(ParseNode* expr, Maybename()); - return noteDeclaredName(name, *maybeDecl, handler.getPosition(expr)); + return noteDeclaredName(name, *maybeDecl, expr->pn_pos); } // Otherwise this is an expression in destructuring outside a declaration. @@ -4171,7 +4176,7 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, ParseNode* target; if (element->isKind(PNK_SPREAD)) { if (element->pn_next) { - report(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); + reportWithNode(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); return false; } target = element->pn_kid; @@ -4234,7 +4239,7 @@ Parser::checkDestructuringPattern(ParseNode* pattern, PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { - report(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); + reportWithNode(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } @@ -4373,14 +4378,7 @@ Parser::declarationPattern(Node decl, DeclarationKind declKind, To } } - TokenKind token; - if (!tokenStream.getToken(&token, TokenStream::None)) - return null(); - - if (token != TOK_ASSIGN) { - report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_DECL); - return null(); - } + MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); Node init = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling, TripledotProhibited); @@ -4430,7 +4428,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (var/let/const x = ... of ...); // BAD if (isForOf) { - report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); return false; } @@ -4439,15 +4437,15 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (let/const x = ... in ...); // BAD if (DeclarationKindIsLexical(declKind)) { - report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); return false; } // This leaves only initialized for-in |var| declarations. ES6 // forbids these; later ES un-forbids in non-strict mode code. *forHeadKind = PNK_FORIN; - if (!report(ParseStrictError, pc->sc()->strict(), initializer, - JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), initializer, + JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) { return false; } @@ -4495,7 +4493,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME); + zeport(ParseError, false, JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4555,7 +4553,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token // Normal const declarations, and const declarations in for(;;) // heads, must be initialized. if (declKind == DeclarationKind::Const) { - report(ParseError, false, binding, JSMSG_BAD_CONST_DECL); + reportWithNode(ParseError, false, binding, JSMSG_BAD_CONST_DECL); return null(); } } @@ -4695,7 +4693,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_NO_BINDING_NAME); + zeport(ParseError, false, JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4707,7 +4705,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + zeport(ParseError, false, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4749,7 +4747,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - report(ParseError, false, null(), JSMSG_AS_AFTER_IMPORT_STAR); + reportWithOffset(ParseError, false, pos().begin, JSMSG_AS_AFTER_IMPORT_STAR); return false; } @@ -4804,7 +4802,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + zeport(ParseError, false, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4853,7 +4851,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - report(ParseError, false, null(), JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + zeport(ParseError, false, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4869,7 +4867,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_CLAUSE); + zeport(ParseError, false, JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4882,7 +4880,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT); + zeport(ParseError, false, JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4920,7 +4918,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - report(ParseError, false, null(), JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + zeport(ParseError, false, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4963,7 +4961,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - report(ParseError, false, null(), JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + zeport(ParseError, false, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4996,14 +4994,8 @@ Parser::exportDeclaration() bool foundAs; if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as)) return null(); - if (foundAs) { - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) - return null(); - if (tt != TOK_NAME) { - report(ParseError, false, null(), JSMSG_NO_EXPORT_NAME); - return null(); - } - } + if (foundAs) + MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME); Node exportName = newName(tokenStream.currentName()); if (!exportName) @@ -5088,7 +5080,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - report(ParseError, false, null(), JSMSG_FROM_AFTER_EXPORT_STAR); + zeport(ParseError, false, JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5224,7 +5216,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT); + zeport(ParseError, false, JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5300,7 +5292,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT)) + if (!zeport(ParseExtraWarning, false, JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5426,7 +5418,7 @@ Parser::validateForInOrOfLHSExpression(Node target, PossibleError* if (handler.isFunctionCall(target)) return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); - report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); + reportWithNode(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); return false; } @@ -5547,7 +5539,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // // See ES6 13.7. if (isForOf && letIsIdentifier) { - report(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); + reportWithNode(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); return false; } @@ -5698,7 +5690,7 @@ Parser::forStatement(YieldHandling yieldHandling) iflags |= JSITER_ENUMERATE; } else { if (isForEach) { - report(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); + reportWithNode(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); return null(); } @@ -5774,7 +5766,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS); + zeport(ParseError, false, JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5788,7 +5780,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - report(ParseError, false, null(), JSMSG_BAD_SWITCH); + zeport(ParseError, false, JSMSG_BAD_SWITCH); return null(); } @@ -5807,10 +5799,8 @@ Parser::switchStatement(YieldHandling yieldHandling) if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT) break; if (afterReturn) { - TokenPos pos(0, 0); - if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) + if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) return null(); - statementBegin = pos.begin; } Node stmt = statementListItem(yieldHandling); if (!stmt) @@ -5872,8 +5862,10 @@ Parser::continueStatement(YieldHandling yieldHandling) for (;;) { stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { - report(ParseError, false, null(), - foundLoop ? JSMSG_LABEL_NOT_FOUND : JSMSG_BAD_CONTINUE); + if (foundLoop) + zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + else + reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); } @@ -5893,7 +5885,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - report(ParseError, false, null(), JSMSG_BAD_CONTINUE); + zeport(ParseError, false, JSMSG_BAD_CONTINUE); return null(); } @@ -5923,7 +5915,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); + zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -5932,7 +5924,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(isBreakTarget)) { - report(ParseError, false, null(), JSMSG_TOUGH_BREAK); + reportWithOffset(ParseError, false, begin, JSMSG_TOUGH_BREAK); return null(); } } @@ -6082,7 +6074,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6170,7 +6162,7 @@ Parser::withStatement(YieldHandling yieldHandling) // warning under JSOPTION_EXTRA_WARNINGS. See // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. if (pc->sc()->strict()) { - if (!report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH)) + if (!zeport(ParseStrictError, true, JSMSG_STRICT_CODE_WITH)) return null(); } @@ -6209,7 +6201,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - report(ParseError, false, null(), JSMSG_GENERATOR_LABEL); + zeport(ParseError, false, JSMSG_GENERATOR_LABEL); return null(); } @@ -6217,7 +6209,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - report(ParseError, false, null(), JSMSG_FUNCTION_LABEL); + zeport(ParseError, false, JSMSG_FUNCTION_LABEL); return null(); } @@ -6240,13 +6232,13 @@ Parser::labeledStatement(YieldHandling yieldHandling) return stmt->label() == label; }; + uint32_t begin = pos().begin; + if (pc->findInnermostStatement(hasSameLabel)) { - report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL); + reportWithOffset(ParseError, false, begin, JSMSG_DUPLICATE_LABEL); return null(); } - uint32_t begin = pos().begin; - tokenStream.consumeKnownToken(TOK_COLON); /* Push a label struct and parse the statement. */ @@ -6270,11 +6262,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW); + zeport(ParseError, false, JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW); + zeport(ParseError, false, JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6348,7 +6340,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - report(ParseError, false, null(), JSMSG_CATCH_AFTER_GENERAL); + zeport(ParseError, false, JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6396,7 +6388,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER); + zeport(ParseError, false, JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6464,7 +6456,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY); + zeport(ParseError, false, JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6609,7 +6601,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT); + zeport(ParseError, false, JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6670,7 +6662,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6702,7 +6694,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF); + zeport(ParseError, false, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6712,17 +6704,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { - report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); return null(); } if (seenConstructor) { - report(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); + reportWithNode(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { - report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6949,8 +6941,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, - "lexical declarations"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -7004,7 +6995,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7032,12 +7023,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7051,11 +7042,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7096,7 +7087,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!zeport(ParseWarning, false, JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7190,7 +7181,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7242,11 +7233,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY); + zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7291,8 +7282,8 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7449,7 +7440,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - report(ParseError, false, null(), JSMSG_BAD_POW_LEFTSIDE); + zeport(ParseError, false, JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7530,7 +7521,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS); + zeport(ParseError, false, JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7669,7 +7660,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); @@ -7708,7 +7699,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_LINE_BREAK_BEFORE_ARROW); + zeport(ParseError, false, JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -7853,10 +7844,11 @@ Parser::reportIfArgumentsEvalTarget(Node nameNode) if (!chars) return true; - if (!report(ParseStrictError, pc->sc()->strict(), nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) + bool strict = pc->sc()->strict(); + if (!reportWithNode(ParseStrictError, strict, nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - MOZ_ASSERT(!pc->sc()->strict(), + MOZ_ASSERT(!strict, "an error should have been reported if this was strict mode " "code"); return true; @@ -7908,7 +7900,7 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign break; } - report(ParseError, pc->sc()->strict(), target, errnum, extra); + reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); return false; } @@ -8014,7 +8006,8 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. if (handler.isNameAnyParentheses(expr)) { - if (!report(ParseStrictError, pc->sc()->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND)) + bool strict = pc->sc()->strict(); + if (!reportWithNode(ParseStrictError, strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); pc->sc()->setBindingsAccessedDynamically(); } @@ -8026,7 +8019,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - report(ParseError, false, null(), JSMSG_RESERVED_ID, "await"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); return null(); } @@ -8179,7 +8172,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - report(ParseError, false, null(), JSMSG_LET_COMP_BINDING); + zeport(ParseError, false, JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8190,7 +8183,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME); + zeport(ParseError, false, JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8251,7 +8244,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN)) + if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8436,13 +8429,8 @@ Parser::argumentList(YieldHandling yieldHandling, Node listNode, b } } - TokenKind tt; - if (!tokenStream.getToken(&tt)) - return false; - if (tt != TOK_RP) { - report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS); - return false; - } + MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS); + handler.setEndPosition(listNode, pos().end); return true; } @@ -8533,14 +8521,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property"); + zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT); + zeport(ParseError, false, JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8551,7 +8539,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member"); + zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8563,12 +8551,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - report(ParseError, false, null(), JSMSG_BAD_SUPERCALL); + zeport(ParseError, false, JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - report(ParseError, false, null(), JSMSG_BAD_SUPER); + zeport(ParseError, false, JSMSG_BAD_SUPER); return null(); } @@ -8595,7 +8583,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - report(ParseError, false, null(), JSMSG_SELFHOSTED_METHOD_CALL); + zeport(ParseError, false, JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8677,7 +8665,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - report(ParseError, false, null(), JSMSG_BAD_SUPER); + zeport(ParseError, false, JSMSG_BAD_SUPER); return null(); } @@ -8730,7 +8718,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, badName); + zeport(ParseError, false, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8739,7 +8727,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8775,7 +8763,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_BAD_STRICT_ASSIGN, badName); + zeport(ParseError, false, JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8785,7 +8773,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, badName); + zeport(ParseError, false, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8794,7 +8782,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield"); + zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8893,7 +8881,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG); + zeport(ParseError, false, JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8936,7 +8924,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro break; } if (tt == TOK_TRIPLEDOT && possibleError) - possibleError->setPendingDestructuringError(null(), JSMSG_REST_WITH_COMMA); + possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA); } } @@ -9003,7 +8991,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); return null(); } @@ -9116,7 +9104,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } @@ -9126,7 +9114,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9135,7 +9123,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - report(ParseError, false, null(), JSMSG_BAD_PROP_ID); + zeport(ParseError, false, JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9156,7 +9144,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - report(ParseError, false, null(), JSMSG_COLON_AFTER_ID); + zeport(ParseError, false, JSMSG_COLON_AFTER_ID); return null(); } @@ -9231,14 +9219,15 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Directly report the error when we're not in a // destructuring context. if (!possibleError) { - report(ParseError, false, propName, JSMSG_DUPLICATE_PROTO_PROPERTY); + reportWithOffset(ParseError, false, namePos.begin, + JSMSG_DUPLICATE_PROTO_PROPERTY); return null(); } // Otherwise delay error reporting until we've determined // whether or not we're destructuring. - possibleError->setPendingExpressionError(propName, - JSMSG_DUPLICATE_PROTO_PROPERTY); + possibleError->setPendingExpressionErrorAt(namePos, + JSMSG_DUPLICATE_PROTO_PROPERTY); } seenPrototypeMutation = true; @@ -9246,8 +9235,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // __proto__: v mutates [[Prototype]]. Getters, setters, // method/generator definitions, computed property name // versions of all of these, and shorthands do not. - uint32_t begin = handler.getPosition(propName).begin; - if (!handler.addPrototypeMutation(literal, begin, propExpr)) + if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) return null(); } else { if (!handler.isConstant(propExpr)) @@ -9267,7 +9255,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9292,7 +9280,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9316,14 +9304,14 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - report(ParseError, false, null(), JSMSG_COLON_AFTER_ID); + zeport(ParseError, false, JSMSG_COLON_AFTER_ID); return null(); } // Here we set a pending error so that later in the parse, once we've // determined whether or not we're destructuring, the error can be // reported or ignored appropriately. - possibleError->setPendingExpressionError(null(), JSMSG_COLON_AFTER_ID); + possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } Node rhs; @@ -9375,7 +9363,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST); + zeport(ParseError, false, JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9424,8 +9412,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "target", TokenKindToDesc(next)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9480,7 +9467,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9568,8 +9555,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9591,7 +9577,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } @@ -9600,7 +9586,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9610,7 +9596,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9622,8 +9608,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(tt)); + zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9648,7 +9633,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9666,7 +9651,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) + // if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 090931f5b4..88d7051089 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -769,13 +769,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * * Ex: * PossibleError possibleError(*this); - * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID); + * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID); * // A JSMSG_BAD_PROP_ID ParseError is reported, returns false. * if (!possibleError.checkForExpressionError()) * return false; // we reach this point with a pending exception * * PossibleError possibleError(*this); - * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID); + * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID); * // Returns true, no error is reported. * if (!possibleError.checkForDestructuringError()) * return false; // not reached, no pending exception @@ -815,7 +815,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Set a pending error. Only a single error may be set per instance and // error kind. - void setPending(ErrorKind kind, Node pn, unsigned errorNumber); + void setPending(ErrorKind kind, const TokenPos& pos, unsigned errorNumber); // If there is a pending error, report it and return false, otherwise // return true. @@ -830,12 +830,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Set a pending destructuring error. Only a single error may be set // per instance, i.e. subsequent calls to this method are ignored and // won't overwrite the existing pending error. - void setPendingDestructuringError(Node pn, unsigned errorNumber); + void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber); // Set a pending expression error. Only a single error may be set per // instance, i.e. subsequent calls to this method are ignored and won't // overwrite the existing pending error. - void setPendingExpressionError(Node pn, unsigned errorNumber); + void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber); // If there is a pending destructuring error, report it and return // false, otherwise return true. Clears any pending expression error. @@ -907,7 +907,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); + bool zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 77eea3d81e..03a5800729 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -577,6 +577,7 @@ class MOZ_STACK_CLASS TokenStream *offset = pos.begin; return true; } + // This is like peekToken(), with one exception: if there is an EOL // between the end of the current token and the start of the next token, it // return true and store TOK_EOL in |*ttp|. In that case, no token with From 70fbb46d9e477ddd553ac7cbd7b5ea61c3de2b17 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:01:54 +0200 Subject: [PATCH 06/37] Remove the |bool strict| argument from the report-at-current-offset Parser function (zeport). zeport => qeport --- js/src/frontend/Parser.cpp | 256 +++++++++++++++++++------------------ js/src/frontend/Parser.h | 9 +- 2 files changed, 140 insertions(+), 125 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 26b3c2c255..a292878503 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -69,7 +69,7 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - zeport(ParseError, false, errno); \ + qeport(ParseError, errno); \ return null(); \ } \ JS_END_MACRO @@ -596,15 +596,26 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o template bool -Parser::zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +Parser::qeport(ParseReportKind kind, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, strict, pos().begin, errorNumber, args); + bool result = reportHelper(kind, false, pos().begin, errorNumber, args); va_end(args); return result; } +template +bool +Parser::strictModeError(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args); + va_end(args); + return res; +} + template bool Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) @@ -837,7 +848,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -951,7 +962,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -963,7 +974,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - if (!zeport(ParseStrictError, pc->sc()->strict(), JSMSG_DUPLICATE_FORMAL, bytes.ptr())) + if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.ptr())) return false; } @@ -1246,7 +1257,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -1453,7 +1464,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1918,7 +1929,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - zeport(ParseError, false, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + qeport(ParseError, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2016,7 +2027,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2336,7 +2347,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - zeport(ParseError, false, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2741,8 +2752,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - zeport(ParseError, false, - kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); + qeport(ParseError, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2774,13 +2784,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - zeport(ParseError, false, JSMSG_PARAMETER_AFTER_REST); + qeport(ParseError, JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2792,14 +2802,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2810,7 +2820,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - zeport(ParseError, false, JSMSG_NO_REST_NAME); + qeport(ParseError, JSMSG_NO_REST_NAME); return false; } } @@ -2821,7 +2831,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2849,7 +2859,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); + qeport(ParseError, JSMSG_RESERVED_ID, "await"); return false; } @@ -2869,12 +2879,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - zeport(ParseError, false, JSMSG_MISSING_FORMAL); + qeport(ParseError, JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - zeport(ParseError, false, JSMSG_TOO_MANY_FUN_ARGS); + qeport(ParseError, JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2889,12 +2899,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - zeport(ParseError, false, JSMSG_REST_WITH_DEFAULT); + qeport(ParseError, JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - zeport(ParseError, false, JSMSG_BAD_DUP_ARGS); + qeport(ParseError, JSMSG_BAD_DUP_ARGS); return false; } @@ -2938,11 +2948,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - zeport(ParseError, false, JSMSG_PAREN_AFTER_FORMAL); + qeport(ParseError, JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2955,7 +2965,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - zeport(ParseError, false, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3085,7 +3095,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - zeport(ParseError, false, JSMSG_TEMPLSTR_UNTERM_EXPR); + qeport(ParseError, JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3477,7 +3487,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - zeport(ParseError, false, JSMSG_BAD_ARROW_ARGS); + qeport(ParseError, JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3485,7 +3495,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - zeport(ParseError, false, JSMSG_UNEXPECTED_PARAMLIST_END); + qeport(ParseError, JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3498,7 +3508,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); + qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3507,7 +3517,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - zeport(ParseError, false, JSMSG_CURLY_BEFORE_BODY); + qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3540,7 +3550,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - zeport(ParseError, false, JSMSG_CURLY_AFTER_BODY); + qeport(ParseError, JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3598,7 +3608,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3615,7 +3625,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - zeport(ParseError, false, JSMSG_UNNAMED_FUNCTION_STMT); + qeport(ParseError, JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3651,7 +3661,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3824,7 +3834,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - zeport(ParseError, false, JSMSG_DEPRECATED_OCTAL); + qeport(ParseError, JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3911,7 +3921,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) + if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -4493,7 +4503,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - zeport(ParseError, false, JSMSG_NO_VARIABLE_NAME); + qeport(ParseError, JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4693,7 +4703,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - zeport(ParseError, false, JSMSG_NO_BINDING_NAME); + qeport(ParseError, JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4705,7 +4715,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - zeport(ParseError, false, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + qeport(ParseError, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4802,7 +4812,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - zeport(ParseError, false, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + qeport(ParseError, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4851,7 +4861,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - zeport(ParseError, false, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + qeport(ParseError, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4867,7 +4877,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - zeport(ParseError, false, JSMSG_FROM_AFTER_IMPORT_CLAUSE); + qeport(ParseError, JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4880,7 +4890,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - zeport(ParseError, false, JSMSG_DECLARATION_AFTER_IMPORT); + qeport(ParseError, JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4918,7 +4928,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - zeport(ParseError, false, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + qeport(ParseError, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4961,7 +4971,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - zeport(ParseError, false, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + qeport(ParseError, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -5080,7 +5090,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - zeport(ParseError, false, JSMSG_FROM_AFTER_EXPORT_STAR); + qeport(ParseError, JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5216,7 +5226,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - zeport(ParseError, false, JSMSG_DECLARATION_AFTER_EXPORT); + qeport(ParseError, JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5292,7 +5302,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!zeport(ParseExtraWarning, false, JSMSG_EMPTY_CONSEQUENT)) + if (!qeport(ParseExtraWarning, JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5766,7 +5776,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - zeport(ParseError, false, JSMSG_TOO_MANY_DEFAULTS); + qeport(ParseError, JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5780,7 +5790,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - zeport(ParseError, false, JSMSG_BAD_SWITCH); + qeport(ParseError, JSMSG_BAD_SWITCH); return null(); } @@ -5863,7 +5873,7 @@ Parser::continueStatement(YieldHandling yieldHandling) stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { if (foundLoop) - zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + qeport(ParseError, JSMSG_LABEL_NOT_FOUND); else reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); @@ -5885,7 +5895,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - zeport(ParseError, false, JSMSG_BAD_CONTINUE); + qeport(ParseError, JSMSG_BAD_CONTINUE); return null(); } @@ -5915,7 +5925,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - zeport(ParseError, false, JSMSG_LABEL_NOT_FOUND); + qeport(ParseError, JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -6074,7 +6084,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6155,14 +6165,13 @@ Parser::withStatement(YieldHandling yieldHandling) MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH)); uint32_t begin = pos().begin; - // In most cases, we want the constructs forbidden in strict mode code to be - // a subset of those that JSOPTION_EXTRA_WARNINGS warns about, and we should - // use reportStrictModeError. However, 'with' is the sole instance of a - // construct that is forbidden in strict mode code, but doesn't even merit a - // warning under JSOPTION_EXTRA_WARNINGS. See + // Usually we want the constructs forbidden in strict mode code to be a + // subset of those that ContextOptions::extraWarnings() warns about, and we + // use strictModeError directly. But while 'with' is forbidden in strict + // mode code, it doesn't even merit a warning in non-strict code. See // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. if (pc->sc()->strict()) { - if (!zeport(ParseStrictError, true, JSMSG_STRICT_CODE_WITH)) + if (!strictModeError(JSMSG_STRICT_CODE_WITH)) return null(); } @@ -6201,7 +6210,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - zeport(ParseError, false, JSMSG_GENERATOR_LABEL); + qeport(ParseError, JSMSG_GENERATOR_LABEL); return null(); } @@ -6209,7 +6218,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - zeport(ParseError, false, JSMSG_FUNCTION_LABEL); + qeport(ParseError, JSMSG_FUNCTION_LABEL); return null(); } @@ -6262,11 +6271,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - zeport(ParseError, false, JSMSG_MISSING_EXPR_AFTER_THROW); + qeport(ParseError, JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - zeport(ParseError, false, JSMSG_LINE_BREAK_AFTER_THROW); + qeport(ParseError, JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6340,7 +6349,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - zeport(ParseError, false, JSMSG_CATCH_AFTER_GENERAL); + qeport(ParseError, JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6388,7 +6397,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - zeport(ParseError, false, JSMSG_CATCH_IDENTIFIER); + qeport(ParseError, JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6456,7 +6465,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - zeport(ParseError, false, JSMSG_CATCH_OR_FINALLY); + qeport(ParseError, JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6601,7 +6610,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - zeport(ParseError, false, JSMSG_UNNAMED_CLASS_STMT); + qeport(ParseError, JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6662,8 +6671,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, - "property name", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6694,7 +6702,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - zeport(ParseError, false, JSMSG_BAD_METHOD_DEF); + qeport(ParseError, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6941,7 +6949,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -6995,7 +7003,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7023,12 +7031,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - zeport(ParseError, false, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7042,11 +7050,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); + qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); + qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7087,7 +7095,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!zeport(ParseWarning, false, JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!qeport(ParseWarning, JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7181,7 +7189,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - zeport(ParseError, false, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7233,11 +7241,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - zeport(ParseError, false, JSMSG_CATCH_WITHOUT_TRY); + qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - zeport(ParseError, false, JSMSG_FINALLY_WITHOUT_TRY); + qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7282,7 +7290,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7440,7 +7448,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - zeport(ParseError, false, JSMSG_BAD_POW_LEFTSIDE); + qeport(ParseError, JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7521,7 +7529,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - zeport(ParseError, false, JSMSG_BAD_DESTRUCT_ASS); + qeport(ParseError, JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7660,7 +7668,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); @@ -7699,7 +7707,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - zeport(ParseError, false, JSMSG_LINE_BREAK_BEFORE_ARROW); + qeport(ParseError, JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -8019,7 +8027,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - zeport(ParseError, false, JSMSG_RESERVED_ID, "await"); + qeport(ParseError, JSMSG_RESERVED_ID, "await"); return null(); } @@ -8172,7 +8180,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - zeport(ParseError, false, JSMSG_LET_COMP_BINDING); + qeport(ParseError, JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8183,7 +8191,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - zeport(ParseError, false, JSMSG_OF_AFTER_FOR_NAME); + qeport(ParseError, JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8244,7 +8252,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!zeport(ParseExtraWarning, false, JSMSG_EQUAL_AS_ASSIGN)) + if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8521,14 +8529,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "property"); + qeport(ParseError, JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - zeport(ParseError, false, JSMSG_NAME_AFTER_DOT); + qeport(ParseError, JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8539,7 +8547,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - zeport(ParseError, false, JSMSG_BAD_SUPERPROP, "member"); + qeport(ParseError, JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8551,12 +8559,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - zeport(ParseError, false, JSMSG_BAD_SUPERCALL); + qeport(ParseError, JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - zeport(ParseError, false, JSMSG_BAD_SUPER); + qeport(ParseError, JSMSG_BAD_SUPER); return null(); } @@ -8583,7 +8591,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - zeport(ParseError, false, JSMSG_SELFHOSTED_METHOD_CALL); + qeport(ParseError, JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8665,7 +8673,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - zeport(ParseError, false, JSMSG_BAD_SUPER); + qeport(ParseError, JSMSG_BAD_SUPER); return null(); } @@ -8718,7 +8726,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_RESERVED_ID, badName); + qeport(ParseError, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8727,7 +8735,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); + qeport(ParseError, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8763,7 +8771,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_BAD_STRICT_ASSIGN, badName); + qeport(ParseError, JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8773,7 +8781,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - zeport(ParseError, false, JSMSG_RESERVED_ID, badName); + qeport(ParseError, JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8782,7 +8790,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - zeport(ParseError, false, JSMSG_RESERVED_ID, "yield"); + qeport(ParseError, JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8881,7 +8889,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - zeport(ParseError, false, JSMSG_ARRAY_INIT_TOO_BIG); + qeport(ParseError, JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8991,7 +8999,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - zeport(ParseError, false, JSMSG_ASYNC_GENERATOR); + qeport(ParseError, JSMSG_ASYNC_GENERATOR); return null(); } @@ -9104,7 +9112,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } @@ -9114,7 +9122,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9123,7 +9131,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - zeport(ParseError, false, JSMSG_BAD_PROP_ID); + qeport(ParseError, JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9144,7 +9152,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - zeport(ParseError, false, JSMSG_COLON_AFTER_ID); + qeport(ParseError, JSMSG_COLON_AFTER_ID); return null(); } @@ -9255,7 +9263,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9280,7 +9288,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - zeport(ParseError, false, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9304,7 +9312,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - zeport(ParseError, false, JSMSG_COLON_AFTER_ID); + qeport(ParseError, JSMSG_COLON_AFTER_ID); return null(); } @@ -9363,7 +9371,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - zeport(ParseError, false, JSMSG_CURLY_AFTER_LIST); + qeport(ParseError, JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9412,7 +9420,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9467,7 +9475,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9555,7 +9563,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9577,8 +9585,8 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, - "rest argument name", TokenKindToDesc(next)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, + "rest argument name", TokenKindToDesc(next)); return null(); } } @@ -9586,7 +9594,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9596,7 +9604,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9608,7 +9616,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - zeport(ParseError, false, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9633,7 +9641,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!qeport(ParseWarning, JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9651,7 +9659,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!zeport(ParseWarning, false, JSMSG_DEPRECATED_FOR_EACH)) + // if (!qeport(ParseWarning, JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 88d7051089..402b977ba1 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,12 +907,19 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool zeport(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + bool qeport(ParseReportKind kind, unsigned errorNumber, ...); bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); + /* + * Handle a strict mode error at the current offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); From a652eb1916584d8abe4d4e8f692d197f7039ecff Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:25:28 +0200 Subject: [PATCH 07/37] Change report at current offset to warning(), extraWarning() and error() --- js/src/frontend/Parser.cpp | 263 ++++++++++++++++++++----------------- js/src/frontend/Parser.h | 13 +- 2 files changed, 153 insertions(+), 123 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a292878503..8ad8813b5b 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -63,13 +63,13 @@ using BindingIter = ParseContext::Scope::BindingIter; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; /* Read a token. Report an error and return null() if that token isn't of type tt. */ -#define MUST_MATCH_TOKEN_MOD(tt, modifier, errno) \ +#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ if (token != tt) { \ - qeport(ParseError, errno); \ + error(errorNumber); \ return null(); \ } \ JS_END_MACRO @@ -595,12 +595,37 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o } template -bool -Parser::qeport(ParseReportKind kind, unsigned errorNumber, ...) +void +Parser::error(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, false, pos().begin, errorNumber, args); +#ifdef DEBUG + bool result = +#endif + reportHelper(ParseError, false, pos().begin, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +template +bool +Parser::warning(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args); + va_end(args); + return result; +} + +template +bool +Parser::extraWarning(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args); va_end(args); return result; } @@ -848,7 +873,7 @@ Parser::parse() if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt)); return null(); } if (foldConstants) { @@ -962,7 +987,7 @@ Parser::notePositionalFormalParameter(Node fn, HandlePropertyName { if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) { if (disallowDuplicateParams) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -1257,7 +1282,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name); if (p) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -1464,7 +1489,7 @@ Parser::checkStatementsEOF() if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return false; } return true; @@ -1929,7 +1954,7 @@ Parser::evalBody(EvalSharedContext* evalsc) // script. if (hasUsedName(context->names().arguments)) { if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) { - qeport(ParseError, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + error(JSMSG_BAD_GENEXP_BODY, js_arguments_str); return nullptr; } } @@ -2027,7 +2052,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt)); return null(); } @@ -2347,7 +2372,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); if (tt != TOK_EOF) { - qeport(ParseError, JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); + error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt)); return null(); } @@ -2752,7 +2777,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, firstTokenModifier)) return false; if (tt != TOK_LP) { - qeport(ParseError, kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); + error(kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL); return false; } @@ -2784,13 +2809,13 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn AtomVector& positionalFormals = pc->positionalFormalParameterNames(); if (IsGetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); + error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } while (true) { if (hasRest) { - qeport(ParseError, JSMSG_PARAMETER_AFTER_REST); + error(JSMSG_PARAMETER_AFTER_REST); return false; } @@ -2802,14 +2827,14 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the rest parameter. - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2820,7 +2845,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { - qeport(ParseError, JSMSG_NO_REST_NAME); + error(JSMSG_NO_REST_NAME); return false; } } @@ -2831,7 +2856,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn disallowDuplicateParams = true; if (duplicatedParam) { // Has duplicated args before the destructuring parameter. - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2859,7 +2884,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // case: // // async await => 1 - qeport(ParseError, JSMSG_RESERVED_ID, "await"); + error(JSMSG_RESERVED_ID, "await"); return false; } @@ -2879,12 +2904,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn } default: - qeport(ParseError, JSMSG_MISSING_FORMAL); + error(JSMSG_MISSING_FORMAL); return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { - qeport(ParseError, JSMSG_TOO_MANY_FUN_ARGS); + error(JSMSG_TOO_MANY_FUN_ARGS); return false; } @@ -2899,12 +2924,12 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn MOZ_ASSERT(!parenFreeArrow); if (hasRest) { - qeport(ParseError, JSMSG_REST_WITH_DEFAULT); + error(JSMSG_REST_WITH_DEFAULT); return false; } disallowDuplicateParams = true; if (duplicatedParam) { - qeport(ParseError, JSMSG_BAD_DUP_ARGS); + error(JSMSG_BAD_DUP_ARGS); return false; } @@ -2948,11 +2973,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; if (tt != TOK_RP) { if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } - qeport(ParseError, JSMSG_PAREN_AFTER_FORMAL); + error(JSMSG_PAREN_AFTER_FORMAL); return false; } } @@ -2965,7 +2990,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->function()->setArgCount(positionalFormals.length()); } else if (IsSetterKind(kind)) { - qeport(ParseError, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); + error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -3095,7 +3120,7 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RC) { - qeport(ParseError, JSMSG_TEMPLSTR_UNTERM_EXPR); + error(JSMSG_TEMPLSTR_UNTERM_EXPR); return false; } @@ -3487,7 +3512,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_ARROW)) return false; if (!matched) { - qeport(ParseError, JSMSG_BAD_ARROW_ARGS); + error(JSMSG_BAD_ARROW_ARGS); return false; } } @@ -3495,7 +3520,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // When parsing something for new Function() we have to make sure to // only treat a certain part of the source as a parameter list. if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) { - qeport(ParseError, JSMSG_UNEXPECTED_PARAMLIST_END); + error(JSMSG_UNEXPECTED_PARAMLIST_END); return false; } @@ -3508,7 +3533,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || IsConstructorKind(kind)) { - qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); + error(JSMSG_CURLY_BEFORE_BODY); return false; } @@ -3517,7 +3542,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!warnOnceAboutExprClosure()) return false; #else - qeport(ParseError, JSMSG_CURLY_BEFORE_BODY); + error(JSMSG_CURLY_BEFORE_BODY); return false; #endif } @@ -3550,7 +3575,7 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) return false; if (!matched) { - qeport(ParseError, JSMSG_CURLY_AFTER_BODY); + error(JSMSG_CURLY_AFTER_BODY); return false; } funbox->bufEnd = pos().end; @@ -3608,7 +3633,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3625,7 +3650,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan tokenStream.ungetToken(); } else { /* Unnamed function expressions are forbidden in statement context. */ - qeport(ParseError, JSMSG_UNNAMED_FUNCTION_STMT); + error(JSMSG_UNNAMED_FUNCTION_STMT); return null(); } @@ -3661,7 +3686,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } generatorKind = StarGenerator; @@ -3834,7 +3859,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // occur in the directive prologue -- octal escapes -- and // complain now. if (tokenStream.sawOctalEscape()) { - qeport(ParseError, JSMSG_DEPRECATED_OCTAL); + error(JSMSG_DEPRECATED_OCTAL); return false; } pc->sc()->strictScript = true; @@ -3921,7 +3946,7 @@ Parser::condition(InHandling inHandling, YieldHandling yieldHandli /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(pn)) { - if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) + if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) return null(); } return pn; @@ -4503,7 +4528,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token { // Anything other than TOK_YIELD or TOK_NAME is an error. if (tt != TOK_NAME && tt != TOK_YIELD) { - qeport(ParseError, JSMSG_NO_VARIABLE_NAME); + error(JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4703,7 +4728,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { - qeport(ParseError, JSMSG_NO_BINDING_NAME); + error(JSMSG_NO_BINDING_NAME); return false; } } else { @@ -4715,7 +4740,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor JSAutoByteString bytes; if (!AtomToPrintableString(context, importName, &bytes)) return false; - qeport(ParseError, JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); return false; } } @@ -4812,7 +4837,7 @@ Parser::importDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); if (!pc->atModuleLevel()) { - qeport(ParseError, JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -4861,7 +4886,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_LC && tt != TOK_MUL) { - qeport(ParseError, JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); + error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT); return null(); } @@ -4877,7 +4902,7 @@ Parser::importDeclaration() return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - qeport(ParseError, JSMSG_FROM_AFTER_IMPORT_CLAUSE); + error(JSMSG_FROM_AFTER_IMPORT_CLAUSE); return null(); } @@ -4890,7 +4915,7 @@ Parser::importDeclaration() // equivalent to |import {} from 'a'|. importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; } else { - qeport(ParseError, JSMSG_DECLARATION_AFTER_IMPORT); + error(JSMSG_DECLARATION_AFTER_IMPORT); return null(); } @@ -4928,7 +4953,7 @@ Parser::checkExportedName(JSAtom* exportName) if (!AtomToPrintableString(context, exportName, &str)) return false; - qeport(ParseError, JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); + error(JSMSG_DUPLICATE_EXPORT_NAME, str.ptr()); return false; } @@ -4971,7 +4996,7 @@ Parser::exportDeclaration() MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); if (!pc->atModuleLevel()) { - qeport(ParseError, JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); return null(); } @@ -5090,7 +5115,7 @@ Parser::exportDeclaration() if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - qeport(ParseError, JSMSG_FROM_AFTER_EXPORT_STAR); + error(JSMSG_FROM_AFTER_EXPORT_STAR); return null(); } @@ -5226,7 +5251,7 @@ Parser::exportDeclaration() MOZ_FALLTHROUGH; default: - qeport(ParseError, JSMSG_DECLARATION_AFTER_EXPORT); + error(JSMSG_DECLARATION_AFTER_EXPORT); return null(); } @@ -5302,7 +5327,7 @@ Parser::ifStatement(YieldHandling yieldHandling) if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); if (tt == TOK_SEMI) { - if (!qeport(ParseExtraWarning, JSMSG_EMPTY_CONSEQUENT)) + if (!extraWarning(JSMSG_EMPTY_CONSEQUENT)) return null(); } @@ -5776,7 +5801,7 @@ Parser::switchStatement(YieldHandling yieldHandling) switch (tt) { case TOK_DEFAULT: if (seenDefault) { - qeport(ParseError, JSMSG_TOO_MANY_DEFAULTS); + error(JSMSG_TOO_MANY_DEFAULTS); return null(); } seenDefault = true; @@ -5790,7 +5815,7 @@ Parser::switchStatement(YieldHandling yieldHandling) break; default: - qeport(ParseError, JSMSG_BAD_SWITCH); + error(JSMSG_BAD_SWITCH); return null(); } @@ -5873,7 +5898,7 @@ Parser::continueStatement(YieldHandling yieldHandling) stmt = ParseContext::Statement::findNearest(stmt, isLoop); if (!stmt) { if (foundLoop) - qeport(ParseError, JSMSG_LABEL_NOT_FOUND); + error(JSMSG_LABEL_NOT_FOUND); else reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); return null(); @@ -5895,7 +5920,7 @@ Parser::continueStatement(YieldHandling yieldHandling) break; } } else if (!pc->findInnermostStatement(isLoop)) { - qeport(ParseError, JSMSG_BAD_CONTINUE); + error(JSMSG_BAD_CONTINUE); return null(); } @@ -5925,7 +5950,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(hasSameLabel)) { - qeport(ParseError, JSMSG_LABEL_NOT_FOUND); + error(JSMSG_LABEL_NOT_FOUND); return null(); } } else { @@ -6084,7 +6109,7 @@ Parser::yieldExpression(InHandling inHandling) return null(); if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return null(); } @@ -6210,7 +6235,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // GeneratorDeclaration is only matched by HoistableDeclaration in // StatementListItem, so generators can't be inside labels. if (next == TOK_MUL) { - qeport(ParseError, JSMSG_GENERATOR_LABEL); + error(JSMSG_GENERATOR_LABEL); return null(); } @@ -6218,7 +6243,7 @@ Parser::labeledItem(YieldHandling yieldHandling) // is ever matched. Per Annex B.3.2 that modifies this text, this // applies only to strict mode code. if (pc->sc()->strict()) { - qeport(ParseError, JSMSG_FUNCTION_LABEL); + error(JSMSG_FUNCTION_LABEL); return null(); } @@ -6271,11 +6296,11 @@ Parser::throwStatement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { - qeport(ParseError, JSMSG_MISSING_EXPR_AFTER_THROW); + error(JSMSG_MISSING_EXPR_AFTER_THROW); return null(); } if (tt == TOK_EOL) { - qeport(ParseError, JSMSG_LINE_BREAK_AFTER_THROW); + error(JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -6349,7 +6374,7 @@ Parser::tryStatement(YieldHandling yieldHandling) /* Check for another catch after unconditional catch. */ if (hasUnconditionalCatch) { - qeport(ParseError, JSMSG_CATCH_AFTER_GENERAL); + error(JSMSG_CATCH_AFTER_GENERAL); return null(); } @@ -6397,7 +6422,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } default: - qeport(ParseError, JSMSG_CATCH_IDENTIFIER); + error(JSMSG_CATCH_IDENTIFIER); return null(); } @@ -6465,7 +6490,7 @@ Parser::tryStatement(YieldHandling yieldHandling) tokenStream.ungetToken(); } if (!catchList && !finallyBlock) { - qeport(ParseError, JSMSG_CATCH_OR_FINALLY); + error(JSMSG_CATCH_OR_FINALLY); return null(); } @@ -6610,7 +6635,7 @@ Parser::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } else { // Class statements must have a bound name - qeport(ParseError, JSMSG_UNNAMED_CLASS_STMT); + error(JSMSG_UNNAMED_CLASS_STMT); return null(); } } else { @@ -6671,7 +6696,7 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); if (tt == TOK_RC) { tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } @@ -6702,7 +6727,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - qeport(ParseError, JSMSG_BAD_METHOD_DEF); + error(JSMSG_BAD_METHOD_DEF); return null(); } @@ -6949,7 +6974,7 @@ Parser::statement(YieldHandling yieldHandling) } if (forbiddenLetDeclaration) { - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations"); return null(); } } @@ -7003,7 +7028,7 @@ Parser::statement(YieldHandling yieldHandling) // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7031,12 +7056,12 @@ Parser::statement(YieldHandling yieldHandling) // statement of |if| or |else|, but Parser::consequentOrAlternative // handles that). case TOK_FUNCTION: - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); return null(); // |class| is also forbidden by lookahead restriction. case TOK_CLASS: - qeport(ParseError, JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); + error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes"); return null(); // ImportDeclaration (only inside modules) @@ -7050,11 +7075,11 @@ Parser::statement(YieldHandling yieldHandling) // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); + error(JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); + error(JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7095,7 +7120,7 @@ Parser::statementListItem(YieldHandling yieldHandling, if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) { if (!abortIfSyntaxParser()) return null(); - if (!qeport(ParseWarning, JSMSG_USE_ASM_DIRECTIVE_FAIL)) + if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL)) return null(); } return expressionStatement(yieldHandling); @@ -7189,7 +7214,7 @@ Parser::statementListItem(YieldHandling yieldHandling, // detected this way, so don't bother passing around an extra parameter // everywhere. if (!pc->isFunctionBox()) { - qeport(ParseError, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return null(); } return returnStatement(yieldHandling); @@ -7241,11 +7266,11 @@ Parser::statementListItem(YieldHandling yieldHandling, // Miscellaneous error cases arguably better caught here than elsewhere. case TOK_CATCH: - qeport(ParseError, JSMSG_CATCH_WITHOUT_TRY); + error(JSMSG_CATCH_WITHOUT_TRY); return null(); case TOK_FINALLY: - qeport(ParseError, JSMSG_FINALLY_WITHOUT_TRY); + error(JSMSG_FINALLY_WITHOUT_TRY); return null(); // NOTE: default case handled in the ExpressionStatement section. @@ -7290,8 +7315,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!tokenStream.peekToken(&tt)) return null(); if (tt != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -7448,7 +7472,7 @@ Parser::orExpr1(InHandling inHandling, YieldHandling yieldHandling return null(); // Report an error for unary expressions on the LHS of **. if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) { - qeport(ParseError, JSMSG_BAD_POW_LEFTSIDE); + error(JSMSG_BAD_POW_LEFTSIDE); return null(); } pnk = BinaryOpTokenKindToParseNodeKind(tok); @@ -7529,7 +7553,7 @@ Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor if (handler.isUnparenthesizedDestructuringPattern(target)) { if (flavor == CompoundAssignment) { - qeport(ParseError, JSMSG_BAD_DESTRUCT_ASS); + error(JSMSG_BAD_DESTRUCT_ASS); return false; } @@ -7668,8 +7692,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt)) return null(); if (tt != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "'=>' after argument list", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt)); return null(); } @@ -7707,7 +7730,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL); if (next != TOK_ARROW) { - qeport(ParseError, JSMSG_LINE_BREAK_BEFORE_ARROW); + error(JSMSG_LINE_BREAK_BEFORE_ARROW); return null(); } tokenStream.consumeKnownToken(TOK_ARROW); @@ -8027,7 +8050,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t if (!pc->isAsync()) { // TOK_AWAIT can be returned in module, even if it's not inside // async function. - qeport(ParseError, JSMSG_RESERVED_ID, "await"); + error(JSMSG_RESERVED_ID, "await"); return null(); } @@ -8180,7 +8203,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); RootedPropertyName name(context, tokenStream.currentName()); if (name == context->names().let) { - qeport(ParseError, JSMSG_LET_COMP_BINDING); + error(JSMSG_LET_COMP_BINDING); return null(); } TokenPos namePos = pos(); @@ -8191,7 +8214,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) return null(); if (!matched) { - qeport(ParseError, JSMSG_OF_AFTER_FOR_NAME); + error(JSMSG_OF_AFTER_FOR_NAME); return null(); } @@ -8252,7 +8275,7 @@ Parser::comprehensionIf(GeneratorKind comprehensionKind) /* Check for (a = b) and warn about possible (a == b) mistype. */ if (handler.isUnparenthesizedAssignment(cond)) { - if (!qeport(ParseExtraWarning, JSMSG_EQUAL_AS_ASSIGN)) + if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) return null(); } @@ -8529,14 +8552,14 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (tt == TOK_NAME) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - qeport(ParseError, JSMSG_BAD_SUPERPROP, "property"); + error(JSMSG_BAD_SUPERPROP, "property"); return null(); } nextMember = handler.newPropertyAccess(lhs, field, pos().end); if (!nextMember) return null(); } else { - qeport(ParseError, JSMSG_NAME_AFTER_DOT); + error(JSMSG_NAME_AFTER_DOT); return null(); } } else if (tt == TOK_LB) { @@ -8547,7 +8570,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { - qeport(ParseError, JSMSG_BAD_SUPERPROP, "member"); + error(JSMSG_BAD_SUPERPROP, "member"); return null(); } nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end); @@ -8559,12 +8582,12 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling { if (handler.isSuperBase(lhs)) { if (!pc->sc()->allowSuperCall()) { - qeport(ParseError, JSMSG_BAD_SUPERCALL); + error(JSMSG_BAD_SUPERCALL); return null(); } if (tt != TOK_LP) { - qeport(ParseError, JSMSG_BAD_SUPER); + error(JSMSG_BAD_SUPER); return null(); } @@ -8591,7 +8614,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } else { if (options().selfHostingMode && handler.isPropertyAccess(lhs)) { - qeport(ParseError, JSMSG_SELFHOSTED_METHOD_CALL); + error(JSMSG_SELFHOSTED_METHOD_CALL); return null(); } @@ -8673,7 +8696,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling } if (handler.isSuperBase(lhs)) { - qeport(ParseError, JSMSG_BAD_SUPER); + error(JSMSG_BAD_SUPER); return null(); } @@ -8726,7 +8749,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, ? "static" : nullptr; if (badName) { - qeport(ParseError, JSMSG_RESERVED_ID, badName); + error(JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8735,7 +8758,7 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling, pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - qeport(ParseError, JSMSG_RESERVED_ID, "yield"); + error(JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8771,7 +8794,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "eval" : nullptr; if (badName) { - qeport(ParseError, JSMSG_BAD_STRICT_ASSIGN, badName); + error(JSMSG_BAD_STRICT_ASSIGN, badName); return nullptr; } @@ -8781,7 +8804,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) ? "static" : nullptr; if (badName) { - qeport(ParseError, JSMSG_RESERVED_ID, badName); + error(JSMSG_RESERVED_ID, badName); return nullptr; } } @@ -8790,7 +8813,7 @@ Parser::bindingIdentifier(YieldHandling yieldHandling) pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { - qeport(ParseError, JSMSG_RESERVED_ID, "yield"); + error(JSMSG_RESERVED_ID, "yield"); return nullptr; } } @@ -8889,7 +8912,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro TokenStream::Modifier modifier = TokenStream::Operand; for (; ; index++) { if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - qeport(ParseError, JSMSG_ARRAY_INIT_TOO_BIG); + error(JSMSG_ARRAY_INIT_TOO_BIG); return null(); } @@ -8999,7 +9022,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } if (isAsync && isGenerator) { - qeport(ParseError, JSMSG_ASYNC_GENERATOR); + error(JSMSG_ASYNC_GENERATOR); return null(); } @@ -9112,7 +9135,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, } default: - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } @@ -9122,7 +9145,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_COLON) { if (isGenerator) { - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } *propType = PropertyType::Normal; @@ -9131,7 +9154,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { if (isGenerator) { - qeport(ParseError, JSMSG_BAD_PROP_ID); + error(JSMSG_BAD_PROP_ID); return null(); } tokenStream.ungetToken(); @@ -9152,7 +9175,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - qeport(ParseError, JSMSG_COLON_AFTER_ID); + error(JSMSG_COLON_AFTER_ID); return null(); } @@ -9263,7 +9286,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9288,7 +9311,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (propToken != TOK_NAME && propToken != TOK_YIELD) { - qeport(ParseError, JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); + error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); return null(); } @@ -9312,7 +9335,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Destructuring defaults are definitely not allowed in this object literal, // because of something the caller knows about the preceding code. // For example, maybe the preceding token is an operator: `x + {y=z}`. - qeport(ParseError, JSMSG_COLON_AFTER_ID); + error(JSMSG_COLON_AFTER_ID); return null(); } @@ -9371,7 +9394,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* if (tt == TOK_RC) break; if (tt != TOK_COMMA) { - qeport(ParseError, JSMSG_CURLY_AFTER_LIST); + error(JSMSG_CURLY_AFTER_LIST); return null(); } } @@ -9420,7 +9443,7 @@ Parser::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } @@ -9475,8 +9498,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.peekToken(&next)) return null(); if (next != TOK_ARROW) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "expression", TokenKindToDesc(TOK_RP)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP)); return null(); } @@ -9563,7 +9585,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // name, closing parenthesis, and arrow, and allow it only if all are // present. if (tripledotHandling != TripledotAllowed) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } @@ -9585,8 +9607,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling // or "arguments" should be prohibited. Argument-parsing code // handles that. if (next != TOK_NAME && next != TOK_YIELD) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "rest argument name", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } } @@ -9594,8 +9615,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!tokenStream.getToken(&next)) return null(); if (next != TOK_RP) { - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "closing parenthesis", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next)); return null(); } @@ -9604,8 +9624,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (next != TOK_ARROW) { // Advance the scanner for proper error location reporting. tokenStream.consumeKnownToken(next); - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, - "'=>' after argument list", TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next)); return null(); } @@ -9616,7 +9635,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TripledotHandling } default: - qeport(ParseError, JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); return null(); } } @@ -9641,7 +9660,7 @@ Parser::warnOnceAboutExprClosure() return true; if (!cx->compartment()->warnedAboutExprClosure) { - if (!qeport(ParseWarning, JSMSG_DEPRECATED_EXPR_CLOSURE)) + if (!warning(JSMSG_DEPRECATED_EXPR_CLOSURE)) return false; cx->compartment()->warnedAboutExprClosure = true; } @@ -9659,7 +9678,7 @@ Parser::warnOnceAboutForEach() if (!cx->compartment()->warnedAboutForEach) { // Disabled warning spew. - // if (!qeport(ParseWarning, JSMSG_DEPRECATED_FOR_EACH)) + // if (!warning(JSMSG_DEPRECATED_FOR_EACH)) // return false; cx->compartment()->warnedAboutForEach = true; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 402b977ba1..feead0e63c 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,12 +907,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool qeport(ParseReportKind kind, unsigned errorNumber, ...); bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, ...); + /* Report the given error at the current offset. */ + void error(unsigned errorNumber, ...); + /* * Handle a strict mode error at the current offset. Report an error if in * strict mode code, or warn if not, using the given error number and @@ -920,6 +922,15 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter */ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + /* Report the given warning at the current offset. */ + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + + /* + * If extra warnings are enabled, report the given warning at the current + * offset. + */ + MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); + Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser* syntaxParser, LazyScript* lazyOuterFunction); From 1f00dc49d418685ddf710ca6986915f4f0db80c2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:30:52 +0200 Subject: [PATCH 08/37] Specify an explicit offset when warning about "use asm" found in the directive prologue of a script (rather than a function body). --- js/src/frontend/FullParseHandler.h | 2 +- js/src/frontend/Parser.cpp | 9 +++++---- js/src/frontend/SyntaxParseHandler.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 0fd1377962..da068e5af2 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -845,7 +845,7 @@ class FullParseHandler MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) { return parenthesize(pn); } - void setPrologue(ParseNode* pn) { + void setInDirectivePrologue(ParseNode* pn) { pn->pn_prologue = true; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8ad8813b5b..afbf4c4c95 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3811,10 +3811,10 @@ Parser::asmJS(Node list) */ template bool -Parser::maybeParseDirective(Node list, Node pn, bool* cont) +Parser::maybeParseDirective(Node list, Node possibleDirective, bool* cont) { TokenPos directivePos; - JSAtom* directive = handler.isStringExprStatement(pn, &directivePos); + JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos); *cont = !!directive; if (!*cont) @@ -3831,7 +3831,7 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) // directive in the future. We don't want to interfere with people // taking advantage of directive-prologue-enabled features that appear // in other browsers first. - handler.setPrologue(pn); + handler.setInDirectivePrologue(possibleDirective); if (directive == context->names().useStrict) { // Functions with non-simple parameter lists (destructuring, @@ -3867,7 +3867,8 @@ Parser::maybeParseDirective(Node list, Node pn, bool* cont) } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return reportWithNode(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL); + return reportWithOffset(ParseWarning, false, directivePos.begin, + JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index b7f00605be..85695ba9c2 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -519,7 +519,7 @@ class SyntaxParseHandler MOZ_MUST_USE Node setLikelyIIFE(Node pn) { return pn; // Remain in syntax-parse mode. } - void setPrologue(Node pn) {} + void setInDirectivePrologue(Node pn) {} bool isConstant(Node pn) { return false; } From e92f878a930c7f34503fd38f9c419f6e0bfd965b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:32:55 +0200 Subject: [PATCH 09/37] Track strict mode errors in unary deletions correctly when syntax-parsing. --- js/src/frontend/Parser.cpp | 19 +++++++++++++++++-- js/src/frontend/Parser.h | 7 +++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index afbf4c4c95..f625595a2c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -641,6 +641,17 @@ Parser::strictModeError(unsigned errorNumber, ...) return res; } +template +bool +Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args); + va_end(args); + return res; +} + template bool Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) @@ -8031,6 +8042,10 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } case TOK_DELETE: { + uint32_t exprOffset; + if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) + return null(); + Node expr = unaryExpr(yieldHandling, TripledotProhibited); if (!expr) return null(); @@ -8038,9 +8053,9 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t // Per spec, deleting any unary expression is valid -- it simply // returns true -- except for one case that is illegal in strict mode. if (handler.isNameAnyParentheses(expr)) { - bool strict = pc->sc()->strict(); - if (!reportWithNode(ParseStrictError, strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND)) return null(); + pc->sc()->setBindingsAccessedDynamically(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index feead0e63c..c8914a2d78 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -922,6 +922,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter */ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + /* + * Handle a strict mode error at the given offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); + /* Report the given warning at the current offset. */ MOZ_MUST_USE bool warning(unsigned errorNumber, ...); From 9a97be75ac37f86312210c335eb7c6ed1238ffce Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:38:21 +0200 Subject: [PATCH 10/37] Track strict mode errors in for...in and for...of correctly when syntax-parsing. --- js/src/frontend/Parser.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f625595a2c..5981881d3c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4458,6 +4458,10 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN)); + uint32_t initializerOffset; + if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) + return false; + Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed, yieldHandling, TripledotProhibited); if (!initializer) @@ -4491,11 +4495,8 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // This leaves only initialized for-in |var| declarations. ES6 // forbids these; later ES un-forbids in non-strict mode code. *forHeadKind = PNK_FORIN; - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), initializer, - JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) - { + if (!strictModeErrorAt(initializerOffset, JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) return false; - } *forInOrOfExpression = expressionAfterForInOrOf(PNK_FORIN, yieldHandling); if (!*forInOrOfExpression) From 5cb16b488f0a1b56e47b03717489a4ff2b62e280 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 04:22:27 +0200 Subject: [PATCH 11/37] Move part of Parser::functionDefinition into callers. --- js/src/frontend/Parser.cpp | 46 ++++++++++++++++++++++++-------------- js/src/frontend/Parser.h | 5 ++--- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5981881d3c..8466d7c1c1 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3188,22 +3188,14 @@ Parser::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node -Parser::functionDefinition(uint32_t preludeStart, InHandling inHandling, +Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind) { MOZ_ASSERT_IF(kind == Statement, funName); MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); - Node pn = handler.newFunctionDefinition(); - if (!pn) - return null(); - - if (invoked) - pn = handler.setLikelyIIFE(pn); - // Note the declared name and check for early errors. bool tryAnnexB = false; if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) @@ -3665,9 +3657,13 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement, - generatorKind, asyncKind, PredictUninvoked); + Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, + name, Statement, generatorKind, asyncKind); if (!fun) return null(); @@ -3716,8 +3712,15 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo tokenStream.ungetToken(); } - return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression, - generatorKind, asyncKind, invoked); + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + if (invoked) + pn = handler.setLikelyIIFE(pn); + + return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression, + generatorKind, asyncKind); } /* @@ -7783,7 +7786,11 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr, + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -9429,8 +9436,13 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind, - generatorKind, asyncKind); + + Node pn = handler.newFunctionDefinition(); + if (!pn) + return null(); + + return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName, + kind, generatorKind, asyncKind); } template diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index c8914a2d78..3bfb4ae311 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1259,11 +1259,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(uint32_t preludeStart, + Node functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked = PredictUninvoked); + GeneratorKind generatorKind, FunctionAsyncKind asyncKind); // Parse a function body. Pass StatementListBody if the body is a list of // statements; pass ExpressionBody if the body is a single expression. From da1cb60dc3318962efa23bdf724d97e974f61f4b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:22:55 +0200 Subject: [PATCH 12/37] Move the Parser::checkFunctionDefinition call into its callers. --- js/src/frontend/FullParseHandler.h | 15 ++- js/src/frontend/ParseNode.h | 8 +- js/src/frontend/Parser.cpp | 176 ++++++++++++++------------- js/src/frontend/Parser.h | 5 +- js/src/frontend/SyntaxParseHandler.h | 5 +- js/src/wasm/AsmJS.cpp | 2 +- 6 files changed, 116 insertions(+), 95 deletions(-) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index da068e5af2..b619cf24c1 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -670,9 +670,18 @@ class FullParseHandler pn->setDirectRHSAnonFunction(true); } - ParseNode* newFunctionDefinition() { - return new_(PNK_FUNCTION, pos()); + ParseNode* newFunctionStatement() { + return new_(PNK_FUNCTION, JSOP_NOP, pos()); } + + ParseNode* newFunctionExpression() { + return new_(PNK_FUNCTION, JSOP_LAMBDA, pos()); + } + + ParseNode* newArrowFunction() { + return new_(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos()); + } + bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) { MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST)); ParseNode* paramsBody = newList(PNK_PARAMSBODY, body); @@ -699,7 +708,7 @@ class FullParseHandler } ParseNode* newModule() { - return new_(PNK_MODULE, pos()); + return new_(PNK_MODULE, JSOP_NOP, pos()); } ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) { diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c58dab431b..c3523afe4b 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -926,10 +926,14 @@ struct ListNode : public ParseNode struct CodeNode : public ParseNode { - CodeNode(ParseNodeKind kind, const TokenPos& pos) - : ParseNode(kind, JSOP_NOP, PN_CODE, pos) + CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos) + : ParseNode(kind, op, PN_CODE, pos) { MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE); + MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP); + MOZ_ASSERT(op == JSOP_NOP || // statement, module + op == JSOP_LAMBDA_ARROW || // arrow function + op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c. MOZ_ASSERT(!pn_body); MOZ_ASSERT(!pn_objbox); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8466d7c1c1..c34e4d5638 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2352,7 +2352,7 @@ Parser::standaloneFunction(HandleFunction fun, tokenStream.ungetToken(); } - Node fn = handler.newFunctionDefinition(); + Node fn = handler.newFunctionStatement(); if (!fn) return null(); @@ -3010,60 +3010,54 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn template bool -Parser::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, +Parser::checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind, bool* tryAnnexB) { - if (kind == Statement) { - TokenPos pos = handler.getPosition(pn); - RootedPropertyName funName(context, funAtom->asPropertyName()); + TokenPos pos = handler.getPosition(pn); - // In sloppy mode, Annex B.3.2 allows labelled function - // declarations. Otherwise it is a parse error. - ParseContext::Statement* declaredInStmt = pc->innermostStatement(); - if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { - MOZ_ASSERT(!pc->sc()->strict(), - "labeled functions shouldn't be parsed in strict mode"); + // In sloppy mode, Annex B.3.2 allows labelled function + // declarations. Otherwise it is a parse error. + ParseContext::Statement* declaredInStmt = pc->innermostStatement(); + if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { + MOZ_ASSERT(!pc->sc()->strict(), + "labeled functions shouldn't be parsed in strict mode"); - // Find the innermost non-label statement. Report an error if it's - // unbraced: functions can't appear in it. Otherwise the statement - // (or its absence) determines the scope the function's bound in. - while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) - declaredInStmt = declaredInStmt->enclosing(); + // Find the innermost non-label statement. Report an error if it's + // unbraced: functions can't appear in it. Otherwise the statement + // (or its absence) determines the scope the function's bound in. + while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) + declaredInStmt = declaredInStmt->enclosing(); - if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); + return false; + } + } + + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + + if (!pc->sc()->strict() && generatorKind == NotGenerator) { + // In sloppy mode, try Annex B.3.3 semantics. If making an + // additional 'var' binding of the same name does not throw an + // early error, do so. This 'var' binding would be assigned + // the function object when its declaration is reached, not at + // the start of the block. + + if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) return false; - } } - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - - if (!pc->sc()->strict() && generatorKind == NotGenerator) { - // Under sloppy mode, try Annex B.3.3 semantics. If making an - // additional 'var' binding of the same name does not throw an - // early error, do so. This 'var' binding would be assigned - // the function object when its declaration is reached, not at - // the start of the block. - - if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } - - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; - - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); - } + if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) + return false; } else { - // A function expression does not introduce any binding. - handler.setOp(pn, kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA); + if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) + return false; + + // Body-level functions in modules are always closed over. + if (pc->atModuleLevel()) + pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); } return true; @@ -3191,16 +3185,12 @@ typename ParseHandler::Node Parser::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + bool tryAnnexB /* = false */) { MOZ_ASSERT_IF(kind == Statement, funName); MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); - // Note the declared name and check for early errors. - bool tryAnnexB = false; - if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB)) - return null(); - // When fully parsing a LazyScript, we do not fully reparse its inner // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. @@ -3433,7 +3423,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict { MOZ_ASSERT(checkOptionsCalled); - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionStatement(); if (!pn) return null(); @@ -3657,13 +3647,18 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionStatement(); if (!pn) return null(); + // Note the declared name and check for early errors. + bool tryAnnexB = false; + if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB)) + return null(); + YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, - name, Statement, generatorKind, asyncKind); + name, Statement, generatorKind, asyncKind, tryAnnexB); if (!fun) return null(); @@ -3712,7 +3707,7 @@ Parser::functionExpr(uint32_t preludeStart, InvokedPrediction invo tokenStream.ungetToken(); } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionExpression(); if (!pn) return null(); @@ -6583,31 +6578,6 @@ JSOpFromPropertyType(PropertyType propType) } } -static FunctionSyntaxKind -FunctionSyntaxKindFromPropertyType(PropertyType propType) -{ - switch (propType) { - case PropertyType::Getter: - return Getter; - case PropertyType::GetterNoExpressionClosure: - return GetterNoExpressionClosure; - case PropertyType::Setter: - return Setter; - case PropertyType::SetterNoExpressionClosure: - return SetterNoExpressionClosure; - case PropertyType::Method: - case PropertyType::GeneratorMethod: - case PropertyType::AsyncMethod: - return Method; - case PropertyType::Constructor: - return ClassConstructor; - case PropertyType::DerivedConstructor: - return DerivedClassConstructor; - default: - MOZ_CRASH("unexpected property type"); - } -} - static GeneratorKind GeneratorKindFromPropertyType(PropertyType propType) { @@ -7786,7 +7756,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl } } - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newArrowFunction(); if (!pn) return null(); @@ -8125,10 +8095,9 @@ template typename ParseHandler::Node Parser::generatorComprehensionLambda(unsigned begin) { - Node genfn = handler.newFunctionDefinition(); + Node genfn = handler.newFunctionExpression(); if (!genfn) return null(); - handler.setOp(genfn, JSOP_LAMBDA); ParseContext* outerpc = pc; @@ -9432,12 +9401,47 @@ typename ParseHandler::Node Parser::methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName) { - FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); + FunctionSyntaxKind kind; + switch (propType) { + case PropertyType::Getter: + kind = Getter; + break; + + case PropertyType::GetterNoExpressionClosure: + kind = GetterNoExpressionClosure; + break; + + case PropertyType::Setter: + kind = Setter; + break; + + case PropertyType::SetterNoExpressionClosure: + kind = SetterNoExpressionClosure; + break; + + case PropertyType::Method: + case PropertyType::GeneratorMethod: + case PropertyType::AsyncMethod: + kind = Method; + break; + + case PropertyType::Constructor: + kind = ClassConstructor; + break; + + case PropertyType::DerivedConstructor: + kind = DerivedClassConstructor; + break; + + default: + MOZ_CRASH("Parser: methodDefinition: unexpected property type"); + } + GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node pn = handler.newFunctionDefinition(); + Node pn = handler.newFunctionExpression(); if (!pn) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 3bfb4ae311..dc9c16adbc 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1262,7 +1262,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind); + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + bool tryAnnexB = false); // Parse a function body. Pass StatementListBody if the body is a list of // statements; pass ExpressionBody if the body is a single expression. @@ -1348,7 +1349,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, + bool checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 85695ba9c2..00ea9d35dd 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -342,7 +342,10 @@ class SyntaxParseHandler void checkAndSetIsDirectRHSAnonFunction(Node pn) {} - Node newFunctionDefinition() { return NodeFunctionDefinition; } + Node newFunctionStatement() { return NodeFunctionDefinition; } + Node newFunctionExpression() { return NodeFunctionDefinition; } + Node newArrowFunction() { return NodeFunctionDefinition; } + bool setComprehensionLambdaBody(Node pn, Node body) { return true; } void setFunctionFormalParametersAndBody(Node pn, Node kid) {} void setFunctionBody(Node pn, Node kid) {} diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 2b66903637..a318d67a9b 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -7064,7 +7064,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) if (!name) return false; - ParseNode* fn = m.parser().handler.newFunctionDefinition(); + ParseNode* fn = m.parser().handler.newFunctionStatement(); if (!fn) return false; From 092b87b756744fcf09a607258f5e5e44fed586ae Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:26:49 +0200 Subject: [PATCH 13/37] Inline GeneratorKindFromPropertyType and AsyncKindFromPropertyType. Trivially inlines these into their sole caller. --- js/src/frontend/Parser.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c34e4d5638..5a42b75b00 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6578,24 +6578,6 @@ JSOpFromPropertyType(PropertyType propType) } } -static GeneratorKind -GeneratorKindFromPropertyType(PropertyType propType) -{ - if (propType == PropertyType::GeneratorMethod) - return StarGenerator; - if (propType == PropertyType::AsyncMethod) - return StarGenerator; - return NotGenerator; -} - -static FunctionAsyncKind -AsyncKindFromPropertyType(PropertyType propType) -{ - if (propType == PropertyType::AsyncMethod) - return AsyncFunction; - return SyncFunction; -} - template typename ParseHandler::Node Parser::classDefinition(YieldHandling yieldHandling, @@ -9437,8 +9419,15 @@ Parser::methodDefinition(uint32_t preludeStart, PropertyType propT MOZ_CRASH("Parser: methodDefinition: unexpected property type"); } - GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); - FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); + GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod || + propType == PropertyType::AsyncMethod) + ? StarGenerator + : NotGenerator; + + FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod) + ? AsyncFunction + : SyncFunction; + YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); Node pn = handler.newFunctionExpression(); From 9191d0d06beab17a4d56b588e16ddc69e800be4e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:36:09 +0200 Subject: [PATCH 14/37] Inline Parser::checkFunctionDefinition into its sole caller. --- js/src/frontend/Parser.cpp | 112 ++++++++++++++++--------------------- js/src/frontend/Parser.h | 2 - 2 files changed, 49 insertions(+), 65 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5a42b75b00..34d87528f1 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1307,7 +1307,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // Functions in block have complex allowances in sloppy mode for being // labelled that other lexical declarations do not have. Those checks // are more complex than calling checkLexicalDeclarationDirectlyWithin- - // Block and are done in checkFunctionDefinition. + // Block and are done inline in callers. ParseContext::Scope* scope = pc->innermostScope(); if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) { @@ -3008,61 +3008,6 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return true; } -template -bool -Parser::checkFunctionDefinition(HandlePropertyName funName, Node pn, - GeneratorKind generatorKind, bool* tryAnnexB) -{ - TokenPos pos = handler.getPosition(pn); - - // In sloppy mode, Annex B.3.2 allows labelled function - // declarations. Otherwise it is a parse error. - ParseContext::Statement* declaredInStmt = pc->innermostStatement(); - if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { - MOZ_ASSERT(!pc->sc()->strict(), - "labeled functions shouldn't be parsed in strict mode"); - - // Find the innermost non-label statement. Report an error if it's - // unbraced: functions can't appear in it. Otherwise the statement - // (or its absence) determines the scope the function's bound in. - while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) - declaredInStmt = declaredInStmt->enclosing(); - - if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); - return false; - } - } - - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - - if (!pc->sc()->strict() && generatorKind == NotGenerator) { - // In sloppy mode, try Annex B.3.3 semantics. If making an - // additional 'var' binding of the same name does not throw an - // early error, do so. This 'var' binding would be assigned - // the function object when its declaration is reached, not at - // the start of the block. - - if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } - - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; - - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); - } - - return true; -} - template <> bool Parser::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, @@ -3618,12 +3563,30 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan } } - RootedPropertyName name(context); - GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; + // In sloppy mode, Annex B.3.2 allows labelled function declarations. + // Otherwise it's a parse error. + ParseContext::Statement* declaredInStmt = pc->innermostStatement(); + if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) { + MOZ_ASSERT(!pc->sc()->strict(), + "labeled functions shouldn't be parsed in strict mode"); + + // Find the innermost non-label statement. Report an error if it's + // unbraced: functions can't appear in it. Otherwise the statement + // (or its absence) determines the scope the function's bound in. + while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) + declaredInStmt = declaredInStmt->enclosing(); + + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + error(JSMSG_SLOPPY_FUNCTION_LABEL); + return null(); + } + } + TokenKind tt; if (!tokenStream.getToken(&tt)) return null(); + GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; if (tt == TOK_MUL) { if (asyncKind != SyncFunction) { error(JSMSG_ASYNC_GENERATOR); @@ -3634,6 +3597,7 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } + RootedPropertyName name(context); if (tt == TOK_NAME || tt == TOK_YIELD) { name = bindingIdentifier(yieldHandling); if (!name) @@ -3647,13 +3611,35 @@ Parser::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); } - Node pn = handler.newFunctionStatement(); - if (!pn) - return null(); - // Note the declared name and check for early errors. bool tryAnnexB = false; - if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB)) + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + + if (!pc->sc()->strict() && generatorKind == NotGenerator) { + // In sloppy mode, try Annex B.3.3 semantics. If making an + // additional 'var' binding of the same name does not throw an + // early error, do so. This 'var' binding would be assigned + // the function object when its declaration is reached, not at + // the start of the block. + if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB)) + return null(); + } + + if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos())) + return null(); + } else { + if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos())) + return null(); + + // Body-level functions in modules are always closed over. + if (pc->atModuleLevel()) + pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); + } + + Node pn = handler.newFunctionStatement(); + if (!pn) return null(); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index dc9c16adbc..13580846b8 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1349,8 +1349,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool checkFunctionDefinition(HandlePropertyName funName, Node pn, - GeneratorKind generatorKind, bool* tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, bool tryAnnexB); bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, From 07c1fa20ea1dc601575344cf9d32282e762b2633 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:39:27 +0200 Subject: [PATCH 15/37] Introduce Parser::errorAt This reduces reporting an error at a particular offset to its bare essentials, simplifying calls. --- js/src/frontend/Parser.cpp | 71 +++++++++++++++++++++----------------- js/src/frontend/Parser.h | 3 ++ 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 34d87528f1..b494cc9663 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -608,6 +608,20 @@ Parser::error(unsigned errorNumber, ...) va_end(args); } +template +void +Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportHelper(ParseError, false, offset, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + template bool Parser::warning(unsigned errorNumber, ...) @@ -940,8 +954,7 @@ Parser::checkStrictBinding(PropertyName* name, TokenPos pos) JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; - return reportWithOffset(ParseStrictError, pc->sc()->strict(), pos.begin, - JSMSG_BAD_BINDING, bytes.ptr()); + return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr()); } return true; @@ -977,8 +990,7 @@ Parser::reportRedeclaration(HandlePropertyName name, DeclarationKi JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return; - reportWithOffset(ParseError, false, pos.begin, JSMSG_REDECLARED_VAR, - DeclarationKindString(kind), bytes.ptr()); + errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr()); } // notePositionalFormalParameter is called for both the arguments of a regular @@ -1247,11 +1259,11 @@ Parser::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::S if (!StatementKindIsBraced(stmt.kind()) && stmt.kind() != StatementKind::ForLoopLexicalHead) { - reportWithOffset(ParseError, false, pos.begin, - stmt.kind() == StatementKind::Label - ? JSMSG_LEXICAL_DECL_LABEL - : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, - DeclarationKindString(kind)); + errorAt(pos.begin, + stmt.kind() == StatementKind::Label + ? JSMSG_LEXICAL_DECL_LABEL + : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, + DeclarationKindString(kind)); return false; } @@ -1341,7 +1353,7 @@ Parser::noteDeclaredName(HandlePropertyName name, DeclarationKind // contain 'let'. (CatchParameter is the only lexical binding form // without this restriction.) if (name == context->names().let) { - reportWithOffset(ParseError, false, pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET); + errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET); return false; } @@ -3730,7 +3742,7 @@ Parser::checkUnescapedName() if (!token.nameContainsEscape()) return true; - reportWithOffset(ParseError, false, token.pos.begin, JSMSG_ESCAPED_KEYWORD); + errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD); return false; } @@ -3840,8 +3852,7 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo : funbox->hasParameterExprs ? "default" : "rest"; - reportWithOffset(ParseError, false, directivePos.begin, - JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind); + errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind); return false; } } @@ -4038,7 +4049,7 @@ Parser::PossibleError::checkForError(ErrorKind kind) return true; Error& err = error(kind); - parser_.reportWithOffset(ParseError, false, err.offset_, err.errorNumber_); + parser_.errorAt(err.offset_, err.errorNumber_); return false; } @@ -4327,11 +4338,11 @@ Parser::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin Node res = destructuringDeclaration(kind, yieldHandling, tt); if (res) { if (pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); + errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); return null(); } if (pc->lastAwaitOffset != startAwaitOffset) { - reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); + errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); return null(); } } @@ -4779,7 +4790,7 @@ Parser::namedImportsOrNamespaceImport(TokenKind tt, Node impor return false; if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - reportWithOffset(ParseError, false, pos().begin, JSMSG_AS_AFTER_IMPORT_STAR); + error(JSMSG_AS_AFTER_IMPORT_STAR); return false; } @@ -5662,7 +5673,7 @@ Parser::forStatement(YieldHandling yieldHandling) Node init = startNode; if (isForEach) { - reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP); + errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP); return null(); } @@ -5897,7 +5908,7 @@ Parser::continueStatement(YieldHandling yieldHandling) if (foundLoop) error(JSMSG_LABEL_NOT_FOUND); else - reportWithOffset(ParseError, false, begin, JSMSG_BAD_CONTINUE); + errorAt(begin, JSMSG_BAD_CONTINUE); return null(); } @@ -5956,7 +5967,7 @@ Parser::breakStatement(YieldHandling yieldHandling) }; if (!pc->findInnermostStatement(isBreakTarget)) { - reportWithOffset(ParseError, false, begin, JSMSG_TOUGH_BREAK); + errorAt(begin, JSMSG_TOUGH_BREAK); return null(); } } @@ -6111,8 +6122,7 @@ Parser::yieldExpression(InHandling inHandling) } if (pc->functionBox()->isArrow()) { - reportWithOffset(ParseError, false, begin, - JSMSG_YIELD_IN_ARROW, js_yield_str); + errorAt(begin, JSMSG_YIELD_IN_ARROW, js_yield_str); return null(); } @@ -6120,8 +6130,7 @@ Parser::yieldExpression(InHandling inHandling) pc->functionBox()->function()->isGetter() || pc->functionBox()->function()->isSetter()) { - reportWithOffset(ParseError, false, begin, - JSMSG_YIELD_IN_METHOD, js_yield_str); + errorAt(begin, JSMSG_YIELD_IN_METHOD, js_yield_str); return null(); } @@ -6266,7 +6275,7 @@ Parser::labeledStatement(YieldHandling yieldHandling) uint32_t begin = pos().begin; if (pc->findInnermostStatement(hasSameLabel)) { - reportWithOffset(ParseError, false, begin, JSMSG_DUPLICATE_LABEL); + errorAt(begin, JSMSG_DUPLICATE_LABEL); return null(); } @@ -8297,8 +8306,7 @@ Parser::comprehension(GeneratorKind comprehensionKind) return null(); if (comprehensionKind != NotGenerator && pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, - JSMSG_BAD_GENEXP_BODY, js_yield_str); + errorAt(pc->lastYieldOffset, JSMSG_BAD_GENEXP_BODY, js_yield_str); return null(); } @@ -8360,11 +8368,11 @@ Parser::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling) Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited); if (res) { if (pc->lastYieldOffset != startYieldOffset) { - reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); + errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT); return null(); } if (pc->lastAwaitOffset != startAwaitOffset) { - reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); + errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT); return null(); } } @@ -9211,8 +9219,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* // Directly report the error when we're not in a // destructuring context. if (!possibleError) { - reportWithOffset(ParseError, false, namePos.begin, - JSMSG_DUPLICATE_PROTO_PROPERTY); + errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); return null(); } @@ -9459,7 +9466,7 @@ Parser::tryNewTarget(Node &newTarget) return false; if (!pc->sc()->allowNewTarget()) { - reportWithOffset(ParseError, false, begin, JSMSG_BAD_NEWTARGET); + errorAt(begin, JSMSG_BAD_NEWTARGET); return false; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 13580846b8..efbaebafd1 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -915,6 +915,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); + /* Report the given error at the given offset. */ + void errorAt(uint32_t offset, unsigned errorNumber, ...); + /* * Handle a strict mode error at the current offset. Report an error if in * strict mode code, or warn if not, using the given error number and From f1f8d377a98be45041708352cf3422c1c2a285b2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:54:09 +0200 Subject: [PATCH 16/37] Remove Parser::reportBadReturn Report simpler errors that don't use the offset of a node as location. --- js/src/frontend/Parser.cpp | 23 +++----------------- js/src/frontend/Parser.h | 2 -- js/src/js.msg | 4 ++-- js/src/tests/js1_7/geniter/regress-352197.js | 2 +- js/src/tests/js1_8/genexps/regress-683738.js | 8 +++---- testing/xpcshell/selftest.py | 2 +- 6 files changed, 11 insertions(+), 30 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index b494cc9663..0099ed19d9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -909,21 +909,6 @@ Parser::parse() return pn; } -template -bool -Parser::reportBadReturn(Node pn, ParseReportKind kind, - unsigned errnum, unsigned anonerrnum) -{ - JSAutoByteString name; - if (JSAtom* atom = pc->functionBox()->function()->explicitName()) { - if (!AtomToPrintableString(context, atom, &name)) - return false; - } else { - errnum = anonerrnum; - } - return reportWithNode(kind, pc->sc()->strict(), pn, errnum, name.ptr()); -} - /* * Strict mode forbids introducing new definitions for 'eval', 'arguments', or * for any strict mode reserved keyword. @@ -6023,10 +6008,9 @@ Parser::returnStatement(YieldHandling yieldHandling) if (!pn) return null(); + /* Disallow "return v;" in legacy generators. */ if (pc->isLegacyGenerator() && exprNode) { - /* Disallow "return v;" in legacy generators. */ - reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN, - JSMSG_BAD_ANON_GENERATOR_RETURN); + errorAt(begin, JSMSG_BAD_GENERATOR_RETURN); return null(); } @@ -6141,8 +6125,7 @@ Parser::yieldExpression(InHandling inHandling) ) { /* As in Python (see PEP-255), disallow return v; in generators. */ - reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN, - JSMSG_BAD_ANON_GENERATOR_RETURN); + errorAt(begin, JSMSG_BAD_GENERATOR_RETURN); return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index efbaebafd1..27a10458bc 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1445,8 +1445,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter static Node null() { return ParseHandler::null(); } - bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum); - JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); TokenPos pos() const { return tokenStream.currentToken().pos; } diff --git a/js/src/js.msg b/js/src/js.msg index a276dab944..42a48c3a5f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -186,7 +186,6 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") -MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") @@ -200,7 +199,8 @@ MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loo MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side") MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding") MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'") -MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") +MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value") +MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") diff --git a/js/src/tests/js1_7/geniter/regress-352197.js b/js/src/tests/js1_7/geniter/regress-352197.js index 7982e12ee0..495717af70 100644 --- a/js/src/tests/js1_7/geniter/regress-352197.js +++ b/js/src/tests/js1_7/geniter/regress-352197.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: anonymous generator function returns a value/; + expect = /TypeError: can't use 'yield' in a function that can return a value/; try { var gen = eval('(function() { { return 5; } yield 3; })'); diff --git a/js/src/tests/js1_8/genexps/regress-683738.js b/js/src/tests/js1_8/genexps/regress-683738.js index de563645da..b0309a90ea 100644 --- a/js/src/tests/js1_8/genexps/regress-683738.js +++ b/js/src/tests/js1_8/genexps/regress-683738.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = "generator function foo returns a value"; + expect = "can't use 'yield' in a function that can return a value"; try { actual = 'No Error'; @@ -32,7 +32,7 @@ function test() } reportCompare(expect, actual, summary + ": 1"); - expect = "generator function foo returns a value"; + expect = "generator function can't return a value"; try { actual = 'No Error'; @@ -44,7 +44,7 @@ function test() } reportCompare(expect, actual, summary + ": 2"); - expect = "generator function foo returns a value"; + expect = "can't use 'yield' in a function that can return a value"; try { actual = 'No Error'; @@ -56,7 +56,7 @@ function test() } reportCompare(expect, actual, summary + ": 3"); - expect = "generator function foo returns a value"; + expect = "generator function can't return a value"; try { actual = 'No Error'; diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py index 856f505fc1..071ab5eda6 100644 --- a/testing/xpcshell/selftest.py +++ b/testing/xpcshell/selftest.py @@ -1162,7 +1162,7 @@ add_test({ self.assertTestResult(False) self.assertInLog(TEST_FAIL_STRING) - self.assertInLog("TypeError: generator function run_test returns a value at") + self.assertInLog("TypeError: generator function can't return a value at") self.assertInLog("test_error.js:4") self.assertNotInLog(TEST_PASS_STRING) From 42d2e161dbd970c08cc6e6b140c4d707ee7e2142 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 07:30:00 +0200 Subject: [PATCH 17/37] Report bad-class-member errors using a specified offset instead of a node's offset. --- js/src/frontend/Parser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0099ed19d9..2702f30750 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6673,7 +6673,7 @@ Parser::classDefinition(YieldHandling yieldHandling, propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { - error(JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } @@ -6683,17 +6683,17 @@ Parser::classDefinition(YieldHandling yieldHandling, propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { - reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } if (seenConstructor) { - reportWithNode(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor"); + errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { - reportWithNode(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); + errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } From 8542ac5f61ad494caf6b0dc54d47757661a9ed2e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:31:01 +0200 Subject: [PATCH 18/37] Report for-loop-decl-with-initializer errors using a specified offset instead of a node's offset. --- js/src/frontend/Parser.cpp | 4 ++-- js/src/js.msg | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2702f30750..a265204778 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4459,7 +4459,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (var/let/const x = ... of ...); // BAD if (isForOf) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL); return false; } @@ -4468,7 +4468,7 @@ Parser::initializerInNameDeclaration(Node decl, Node binding, // // for (let/const x = ... in ...); // BAD if (DeclarationKindIsLexical(declKind)) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE); + errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL); return false; } diff --git a/js/src/js.msg b/js/src/js.msg index 42a48c3a5f..a19e3aa851 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -262,6 +262,8 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module") +MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") +MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") From 218c8ce05cc859dcf8047a2634622b1e5fc18a04 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:33:24 +0200 Subject: [PATCH 19/37] Introduce Parser::warningAt This reduces reporting an warning at a particular offset to its bare essentials, simplifying calls. --- js/src/frontend/Parser.cpp | 26 ++++++++++++++++---------- js/src/frontend/Parser.h | 5 +++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a265204778..43f39dc23b 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -633,6 +633,17 @@ Parser::warning(unsigned errorNumber, ...) return result; } +template +bool +Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + bool result = reportHelper(ParseWarning, false, offset, errorNumber, args); + va_end(args); + return result; +} + template bool Parser::extraWarning(unsigned errorNumber, ...) @@ -3858,8 +3869,7 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo } else if (directive == context->names().useAsm) { if (pc->isFunctionBox()) return asmJS(list); - return reportWithOffset(ParseWarning, false, directivePos.begin, - JSMSG_USE_ASM_DIRECTIVE_FAIL); + return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL); } } return true; @@ -3903,11 +3913,9 @@ Parser::statementList(YieldHandling yieldHandling) if (!warnedAboutStatementsAfterReturn) { if (afterReturn) { if (!handler.isStatementPermittedAfterReturnStatement(next)) { - if (!reportWithOffset(ParseWarning, false, statementBegin, - JSMSG_STMT_AFTER_RETURN)) - { + if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) return null(); - } + warnedAboutStatementsAfterReturn = true; } } else if (handler.isReturnStatement(next)) { @@ -5836,11 +5844,9 @@ Parser::switchStatement(YieldHandling yieldHandling) if (!warnedAboutStatementsAfterReturn) { if (afterReturn) { if (!handler.isStatementPermittedAfterReturnStatement(stmt)) { - if (!reportWithOffset(ParseWarning, false, statementBegin, - JSMSG_STMT_AFTER_RETURN)) - { + if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) return null(); - } + warnedAboutStatementsAfterReturn = true; } } else if (handler.isReturnStatement(stmt)) { diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 27a10458bc..6bd7e586e2 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -909,8 +909,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter public: bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); - bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, - ...); /* Report the given error at the current offset. */ void error(unsigned errorNumber, ...); @@ -935,6 +933,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter /* Report the given warning at the current offset. */ MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + /* Report the given warning at the given offset. */ + MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); + /* * If extra warnings are enabled, report the given warning at the current * offset. From 166a9654a81a698bf9874f5738c326ff79a05696 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:34:17 +0200 Subject: [PATCH 20/37] Remove Parser::reportWithOffset since it's no longer used. --- js/src/frontend/Parser.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 43f39dc23b..9f9169950a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -701,18 +701,6 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned return result; } -template -bool -Parser::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, ...) -{ - va_list args; - va_start(args, errorNumber); - bool result = reportHelper(kind, strict, offset, errorNumber, args); - va_end(args); - return result; -} - template <> bool Parser::abortIfSyntaxParser() From ade86b0f209dfd06c63c10dbd6b59b4633770748 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:37:12 +0200 Subject: [PATCH 21/37] Report the error for uninitialized const-declaration in for(;;) loop head using an explicit offset. --- js/src/frontend/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9f9169950a..fe30328de3 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4577,7 +4577,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token // Normal const declarations, and const declarations in for(;;) // heads, must be initialized. if (declKind == DeclarationKind::Const) { - reportWithNode(ParseError, false, binding, JSMSG_BAD_CONST_DECL); + errorAt(namePos.begin, JSMSG_BAD_CONST_DECL); return null(); } } From 71dc0dd5c0832732610b03fd256b62b1799f4b63 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:41:42 +0200 Subject: [PATCH 22/37] Report some errors about invalid left-hand-sides in for-in/of loop heads using code with an explicitly computed offset. --- js/src/frontend/Parser.cpp | 62 ++++++++++++++++---------------------- js/src/frontend/Parser.h | 2 -- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fe30328de3..94573fce79 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5415,37 +5415,6 @@ Parser::matchInOrOf(bool* isForInp, bool* isForOfp) return true; } -template -bool -Parser::validateForInOrOfLHSExpression(Node target, PossibleError* possibleError) -{ - if (handler.isUnparenthesizedDestructuringPattern(target)) - return checkDestructuringPattern(target, Nothing(), possibleError); - - // All other permitted targets are simple. - if (!reportIfNotValidSimpleAssignmentTarget(target, ForInOrOfTarget)) - return false; - - if (handler.isPropertyAccess(target)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // The arguments/eval identifiers are simple in non-strict mode code, - // but warn to discourage use nonetheless. - if (!reportIfArgumentsEvalTarget(target)) - return false; - - handler.adjustGetToSet(target); - return true; - } - - if (handler.isFunctionCall(target)) - return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE); - - reportWithNode(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE); - return false; -} - template bool Parser::forHeadStart(YieldHandling yieldHandling, @@ -5526,6 +5495,10 @@ Parser::forHeadStart(YieldHandling yieldHandling, return *forInitialPart != null(); } + uint32_t exprOffset; + if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand)) + return false; + // Finally, handle for-loops that start with expressions. Pass // |InProhibited| so that |in| isn't parsed in a RelationalExpression as a // binary operator. |in| makes it a for-in loop, *not* an |in| expression. @@ -5569,8 +5542,29 @@ Parser::forHeadStart(YieldHandling yieldHandling, *forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF; - if (!validateForInOrOfLHSExpression(*forInitialPart, &possibleError)) + // Verify the left-hand side expression doesn't have a forbidden form. + if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) { + if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError)) + return false; + } else if (handler.isNameAnyParentheses(*forInitialPart)) { + const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context); + if (chars) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + return false; + } + + handler.adjustGetToSet(*forInitialPart); + } else if (handler.isPropertyAccess(*forInitialPart)) { + // Permitted: no additional testing/fixup needed. + } else if (handler.isFunctionCall(*forInitialPart)) { + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE)) + return false; + } else { + errorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE); return false; + } + if (!possibleError.checkForExpressionError()) return false; @@ -7869,10 +7863,6 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign case CompoundAssignment: errnum = JSMSG_BAD_LEFTSIDE_OF_ASS; break; - - case ForInOrOfTarget: - errnum = JSMSG_BAD_FOR_LEFTSIDE; - break; } reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 6bd7e586e2..e3827d9535 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1139,7 +1139,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node* forInitialPart, mozilla::Maybe& forLetImpliedScope, Node* forInOrOfExpression); - bool validateForInOrOfLHSExpression(Node target, PossibleError* possibleError); Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling); Node switchStatement(YieldHandling yieldHandling); @@ -1338,7 +1337,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter KeyedDestructuringAssignment, IncrementAssignment, DecrementAssignment, - ForInOrOfTarget }; bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor, From d21544720937bf17de9de49e1e1f1d9a68378a1f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:44:48 +0200 Subject: [PATCH 23/37] Remove for-in/of loop parsing code that redundantly marks the loop target as assigned -- Parser::forHeadStart already does this. --- js/src/frontend/Parser.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 94573fce79..c979e38c37 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5715,12 +5715,6 @@ Parser::forStatement(YieldHandling yieldHandling) stmt.refineForKind(StatementKind::ForOfLoop); } - if (!handler.isDeclarationList(target)) { - MOZ_ASSERT(!forLoopLexicalScope); - if (!checkAndMarkAsAssignmentLhs(target, PlainAssignment)) - return null(); - } - // Parser::declaration consumed everything up to the closing ')'. That // token follows an {Assignment,}Expression, so the next token must be // consumed as if an operator continued the expression, i.e. as None. From e9b63ee1fe95868e7f66a132697cb754ac4469e6 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:46:15 +0200 Subject: [PATCH 24/37] Simplify checking of the left-hand side of assignment and compound assignment expressions. --- js/src/frontend/Parser.cpp | 74 +++++++++++++++----------------------- js/src/frontend/Parser.h | 4 --- 2 files changed, 28 insertions(+), 50 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c979e38c37..3a5b5d6d7c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7470,45 +7470,6 @@ Parser::condExpr1(InHandling inHandling, YieldHandling yieldHandli return handler.newConditional(condition, thenExpr, elseExpr); } -template -bool -Parser::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor, - PossibleError* possibleError) -{ - MOZ_ASSERT(flavor != KeyedDestructuringAssignment, - "destructuring must use special checking/marking code, not " - "this method"); - - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (flavor == CompoundAssignment) { - error(JSMSG_BAD_DESTRUCT_ASS); - return false; - } - - return checkDestructuringPattern(target, Nothing(), possibleError); - } - - // All other permitted targets are simple. - if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) - return false; - - if (handler.isPropertyAccess(target)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // The arguments/eval identifiers are simple in non-strict mode code, - // but warn to discourage use nonetheless. - if (!reportIfArgumentsEvalTarget(target)) - return false; - - handler.adjustGetToSet(target); - return true; - } - - MOZ_ASSERT(handler.isFunctionCall(target)); - return checkAssignmentToCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS); -} - class AutoClearInDestructuringDecl { ParseContext* pc_; @@ -7553,6 +7514,8 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); + uint32_t exprOffset = pos().begin; + bool endsExpr; if (tt == TOK_NAME) { @@ -7752,9 +7715,33 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return lhs; } - AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment; - if (!checkAndMarkAsAssignmentLhs(lhs, flavor, &possibleErrorInner)) + // Verify the left-hand side expression doesn't have a forbidden form. + if (handler.isUnparenthesizedDestructuringPattern(lhs)) { + if (kind != PNK_ASSIGN) { + error(JSMSG_BAD_DESTRUCT_ASS); + return null(); + } + + if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner)) + return null(); + } else if (handler.isNameAnyParentheses(lhs)) { + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + return null(); + } + + handler.adjustGetToSet(lhs); + } else if (handler.isPropertyAccess(lhs)) { + // Permitted: no additional testing/fixup needed. + } else if (handler.isFunctionCall(lhs)) { + if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS)) + return null(); + } else { + errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS); return null(); + } + if (!possibleErrorInner.checkForExpressionError()) return null(); @@ -7852,11 +7839,6 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign case KeyedDestructuringAssignment: errnum = JSMSG_BAD_DESTRUCT_TARGET; break; - - case PlainAssignment: - case CompoundAssignment: - errnum = JSMSG_BAD_LEFTSIDE_OF_ASS; - break; } reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index e3827d9535..70d382501a 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1332,15 +1332,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter } enum AssignmentFlavor { - PlainAssignment, - CompoundAssignment, KeyedDestructuringAssignment, IncrementAssignment, DecrementAssignment, }; - bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor, - PossibleError* possibleError=nullptr); bool matchInOrOf(bool* isForInp, bool* isForOfp); bool hasUsedFunctionSpecialName(HandlePropertyName name); From de1ec588d2fb40b29a0e4894df2f0e698bb68df4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:47:27 +0200 Subject: [PATCH 25/37] Specify an explicit offset when reporting an error for a for-of loop whose target is an expression that begins with 'let'. --- js/src/frontend/Parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3a5b5d6d7c..3f793ffcfe 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5536,7 +5536,7 @@ Parser::forHeadStart(YieldHandling yieldHandling, // // See ES6 13.7. if (isForOf && letIsIdentifier) { - reportWithNode(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS); + errorAt(exprOffset, JSMSG_LET_STARTING_FOROF_LHS); return false; } From 598c71feb0dcd275558c56f980c0eb4f8a3ffc80 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:55:02 +0200 Subject: [PATCH 26/37] Inline Parser::checkAssignmentToCall into its sole caller. --- js/src/frontend/Parser.cpp | 19 +++++-------------- js/src/frontend/Parser.h | 2 -- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3f793ffcfe..041c92fa74 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4084,19 +4084,6 @@ Parser::PossibleError::transferErrorsTo(PossibleError* other) transferErrorTo(ErrorKind::Expression, other); } -template -bool -Parser::checkAssignmentToCall(Node target, unsigned msg) -{ - MOZ_ASSERT(handler.isFunctionCall(target)); - - // Assignment to function calls is forbidden in ES6. We're still somewhat - // concerned about sites using this in dead code, so forbid it only in - // strict mode code (or if the werror option has been set), and otherwise - // warn. - return reportWithNode(ParseStrictError, pc->sc()->strict(), target, msg); -} - template <> bool Parser::checkDestructuringName(ParseNode* expr, Maybe maybeDecl) @@ -7862,7 +7849,11 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla if (!reportIfArgumentsEvalTarget(target)) return false; } else if (handler.isFunctionCall(target)) { - if (!checkAssignmentToCall(target, JSMSG_BAD_INCOP_OPERAND)) + // Assignment to function calls is forbidden in ES6. We're still + // somewhat concerned about sites using this in dead code, so forbid it + // only in strict mode code (or if the werror option has been set), and + // otherwise warn. + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) return false; } return true; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 70d382501a..8bffafc42a 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1432,8 +1432,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkDestructuringObject(Node objectPattern, mozilla::Maybe maybeDecl); bool checkDestructuringName(Node expr, mozilla::Maybe maybeDecl); - bool checkAssignmentToCall(Node node, unsigned errnum); - Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); } From fd2042225e437354a14edc5b017feb53554a2428 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:56:39 +0200 Subject: [PATCH 27/37] Simplify increment/decrement operand checking. --- js/src/frontend/Parser.cpp | 34 ++++++++++++++++++---------------- js/src/frontend/Parser.h | 2 +- js/src/js.msg | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 041c92fa74..5c4d509dd6 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7834,20 +7834,18 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign template bool -Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor flavor) +Parser::checkAndMarkAsIncOperand(Node target) { - MOZ_ASSERT(flavor == IncrementAssignment || flavor == DecrementAssignment); - - // Check. - if (!reportIfNotValidSimpleAssignmentTarget(target, flavor)) - return false; - - // Mark. if (handler.isNameAnyParentheses(target)) { - // Assignment to arguments/eval is allowed outside strict mode code, - // but it's dodgy. Report a strict warning (error, if werror was set). - if (!reportIfArgumentsEvalTarget(target)) - return false; + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(target, context)) { + if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, + JSMSG_BAD_STRICT_ASSIGN, chars)) + { + return false; + } + } + } else if (handler.isPropertyAccess(target)) { + // Permitted: no additional testing/fixup needed. } else if (handler.isFunctionCall(target)) { // Assignment to function calls is forbidden in ES6. We're still // somewhat concerned about sites using this in dead code, so forbid it @@ -7855,7 +7853,13 @@ Parser::checkAndMarkAsIncOperand(Node target, AssignmentFlavor fla // otherwise warn. if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) return false; + } else { + reportWithNode(ParseError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND); + return false; } + + MOZ_ASSERT(isValidSimpleAssignmentTarget(target, PermitAssignmentToFunctionCalls), + "inconsistent increment/decrement operand validation"); return true; } @@ -7922,8 +7926,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2); if (!pn2) return null(); - AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment; - if (!checkAndMarkAsIncOperand(pn2, flavor)) + if (!checkAndMarkAsIncOperand(pn2)) return null(); return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, begin, @@ -7977,8 +7980,7 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t return null(); if (tt == TOK_INC || tt == TOK_DEC) { tokenStream.consumeKnownToken(tt); - AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment; - if (!checkAndMarkAsIncOperand(pn, flavor)) + if (!checkAndMarkAsIncOperand(pn)) return null(); return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, begin, diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8bffafc42a..c50f8e47de 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1377,7 +1377,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportIfArgumentsEvalTarget(Node nameNode); bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); - bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor); + bool checkAndMarkAsIncOperand(Node kid); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); diff --git a/js/src/js.msg b/js/src/js.msg index a19e3aa851..2901b88cc3 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -202,7 +202,7 @@ MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in ' MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value") MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") -MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") +MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") From 33d09dce8be76cb789c217c41dda7f0dce0c692b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:05:22 +0200 Subject: [PATCH 28/37] Simplify checking of targets within destructuring patterns. --- js/src/frontend/Parser.cpp | 86 +++++++------------------------------- js/src/frontend/Parser.h | 9 ---- js/src/js.msg | 1 - 3 files changed, 14 insertions(+), 82 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5c4d509dd6..3e7c25c19c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4113,22 +4113,23 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, + JSMSG_BAD_STRICT_ASSIGN, chars)) + { + return false; + } + } + + return true; } - // Nothing further to do for property accesses. - MOZ_ASSERT(handler.isPropertyAccess(expr)); - return true; + if (handler.isPropertyAccess(expr)) + return true; + + reportWithNode(ParseError, pc->sc()->strict(), expr, JSMSG_BAD_DESTRUCT_TARGET); + return false; } template <> @@ -7773,65 +7774,6 @@ Parser::isValidSimpleAssignmentTarget(Node node, return false; } -template -bool -Parser::reportIfArgumentsEvalTarget(Node nameNode) -{ - const char* chars = handler.nameIsArgumentsEvalAnyParentheses(nameNode, context); - if (!chars) - return true; - - bool strict = pc->sc()->strict(); - if (!reportWithNode(ParseStrictError, strict, nameNode, JSMSG_BAD_STRICT_ASSIGN, chars)) - return false; - - MOZ_ASSERT(!strict, - "an error should have been reported if this was strict mode " - "code"); - return true; -} - -template -bool -Parser::reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor) -{ - FunctionCallBehavior behavior = flavor == KeyedDestructuringAssignment - ? ForbidAssignmentToFunctionCalls - : PermitAssignmentToFunctionCalls; - if (isValidSimpleAssignmentTarget(target, behavior)) - return true; - - if (handler.isNameAnyParentheses(target)) { - // Use a special error if the target is arguments/eval. This ensures - // targeting these names is consistently a SyntaxError (which error numbers - // below don't guarantee) while giving us a nicer error message. - if (!reportIfArgumentsEvalTarget(target)) - return false; - } - - unsigned errnum = 0; - const char* extra = nullptr; - - switch (flavor) { - case IncrementAssignment: - errnum = JSMSG_BAD_OPERAND; - extra = "increment"; - break; - - case DecrementAssignment: - errnum = JSMSG_BAD_OPERAND; - extra = "decrement"; - break; - - case KeyedDestructuringAssignment: - errnum = JSMSG_BAD_DESTRUCT_TARGET; - break; - } - - reportWithNode(ParseError, pc->sc()->strict(), target, errnum, extra); - return false; -} - template bool Parser::checkAndMarkAsIncOperand(Node target) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index c50f8e47de..0baaac3bc4 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1331,12 +1331,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter #endif } - enum AssignmentFlavor { - KeyedDestructuringAssignment, - IncrementAssignment, - DecrementAssignment, - }; - bool matchInOrOf(bool* isForInp, bool* isForOfp); bool hasUsedFunctionSpecialName(HandlePropertyName name); @@ -1374,9 +1368,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); private: - bool reportIfArgumentsEvalTarget(Node nameNode); - bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor); - bool checkAndMarkAsIncOperand(Node kid); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); diff --git a/js/src/js.msg b/js/src/js.msg index 2901b88cc3..4ded69a255 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -205,7 +205,6 @@ MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} i MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") -MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'") MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id") MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function") From a389b4e151bdd8ced4eebff25ed247ed45e7e7e5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:11:04 +0200 Subject: [PATCH 29/37] Report errors for bad increment/decrement operands using explicitly-specified offsets. --- js/src/frontend/Parser.cpp | 55 ++++++++++++++++++-------------------- js/src/frontend/Parser.h | 2 +- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3e7c25c19c..3b1cadbff7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7776,31 +7776,28 @@ Parser::isValidSimpleAssignmentTarget(Node node, template bool -Parser::checkAndMarkAsIncOperand(Node target) +Parser::checkIncDecOperand(Node operand, uint32_t operandOffset) { - if (handler.isNameAnyParentheses(target)) { - if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(target, context)) { - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, - JSMSG_BAD_STRICT_ASSIGN, chars)) - { + if (handler.isNameAnyParentheses(operand)) { + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(operand, context)) { + if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - } } - } else if (handler.isPropertyAccess(target)) { + } else if (handler.isPropertyAccess(operand)) { // Permitted: no additional testing/fixup needed. - } else if (handler.isFunctionCall(target)) { + } else if (handler.isFunctionCall(operand)) { // Assignment to function calls is forbidden in ES6. We're still // somewhat concerned about sites using this in dead code, so forbid it // only in strict mode code (or if the werror option has been set), and // otherwise warn. - if (!reportWithNode(ParseStrictError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND)) + if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND)) return false; } else { - reportWithNode(ParseError, pc->sc()->strict(), target, JSMSG_BAD_INCOP_OPERAND); + errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND); return false; } - MOZ_ASSERT(isValidSimpleAssignmentTarget(target, PermitAssignmentToFunctionCalls), + MOZ_ASSERT(isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls), "inconsistent increment/decrement operand validation"); return true; } @@ -7865,14 +7862,14 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t TokenKind tt2; if (!tokenStream.getToken(&tt2, TokenStream::Operand)) return null(); - Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2); - if (!pn2) - return null(); - if (!checkAndMarkAsIncOperand(pn2)) + + uint32_t operandOffset = pos().begin; + Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2); + if (!operand || !checkIncDecOperand(operand, operandOffset)) return null(); + return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, - begin, - pn2); + begin, operand); } case TOK_DELETE: { @@ -7912,23 +7909,23 @@ Parser::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } default: { - Node pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, + Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, possibleError, invoked); - if (!pn) + if (!expr) return null(); /* Don't look across a newline boundary for a postfix incop. */ if (!tokenStream.peekTokenSameLine(&tt)) return null(); - if (tt == TOK_INC || tt == TOK_DEC) { - tokenStream.consumeKnownToken(tt); - if (!checkAndMarkAsIncOperand(pn)) - return null(); - return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, - begin, - pn); - } - return pn; + + if (tt != TOK_INC && tt != TOK_DEC) + return expr; + + tokenStream.consumeKnownToken(tt); + if (!checkIncDecOperand(expr, begin)) + return null(); + return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, + begin, expr); } } } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 0baaac3bc4..a7e48c1a40 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1368,7 +1368,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls); private: - bool checkAndMarkAsIncOperand(Node kid); + bool checkIncDecOperand(Node operand, uint32_t operandOffset); bool checkStrictAssignment(Node lhs); bool checkStrictBinding(PropertyName* name, TokenPos pos); From ff81b6b3d8f180a2e8701315630bf4c84974eac9 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:18:36 +0200 Subject: [PATCH 30/37] Remove Parser::reportWithNode and its remaining callers. All of the callsites have a full ParseNode* at hand, of which the offset can be directly accessed. --- js/src/frontend/Parser.cpp | 30 +++++++----------------------- js/src/frontend/Parser.h | 1 - 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3b1cadbff7..c08ba48897 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -677,19 +677,6 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . return res; } -template -bool -Parser::reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...) -{ - uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin; - - va_list args; - va_start(args, errorNumber); - bool result = reportHelper(kind, strict, offset, errorNumber, args); - va_end(args); - return result; -} - template bool Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) @@ -4094,7 +4081,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS); return false; } @@ -4104,7 +4091,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybepn_pos.begin, JSMSG_NO_VARIABLE_NAME); return false; } @@ -4115,11 +4102,8 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, - JSMSG_BAD_STRICT_ASSIGN, chars)) - { + if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) return false; - } } return true; @@ -4128,7 +4112,7 @@ Parser::checkDestructuringName(ParseNode* expr, Maybesc()->strict(), expr, JSMSG_BAD_DESTRUCT_TARGET); + errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET); return false; } @@ -4187,7 +4171,7 @@ Parser::checkDestructuringArray(ParseNode* arrayPattern, ParseNode* target; if (element->isKind(PNK_SPREAD)) { if (element->pn_next) { - reportWithNode(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST); + errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST); return false; } target = element->pn_kid; @@ -4250,7 +4234,7 @@ Parser::checkDestructuringPattern(ParseNode* pattern, PossibleError* possibleError /* = nullptr */) { if (pattern->isKind(PNK_ARRAYCOMP)) { - reportWithNode(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE); + errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE); return false; } @@ -5696,7 +5680,7 @@ Parser::forStatement(YieldHandling yieldHandling) iflags |= JSITER_ENUMERATE; } else { if (isForEach) { - reportWithNode(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP); + errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP); return null(); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index a7e48c1a40..196c71fa5d 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -907,7 +907,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, va_list args); public: - bool reportWithNode(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); /* Report the given error at the current offset. */ From d8bcfdb867f2e165da8a9e6a432599261c081b0c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:20:43 +0200 Subject: [PATCH 31/37] Inline Parser::reportHelper into its callers. --- js/src/frontend/Parser.cpp | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c08ba48897..30a627a65b 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -603,7 +603,7 @@ Parser::error(unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportHelper(ParseError, false, pos().begin, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -617,7 +617,7 @@ Parser::errorAt(uint32_t offset, unsigned errorNumber, ...) #ifdef DEBUG bool result = #endif - reportHelper(ParseError, false, offset, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -628,7 +628,8 @@ Parser::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args); + bool result = + tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } @@ -639,7 +640,8 @@ Parser::warningAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseWarning, false, offset, errorNumber, args); + bool result = + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } @@ -650,7 +652,7 @@ Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args); + bool result = tokenStream.reportStrictWarningErrorNumberVA(pos().begin, errorNumber, args); va_end(args); return result; } @@ -661,7 +663,9 @@ Parser::strictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args); + bool res = + tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(), + errorNumber, args); va_end(args); return res; } @@ -672,7 +676,8 @@ Parser::strictModeErrorAt(uint32_t offset, unsigned errorNumber, . { va_list args; va_start(args, errorNumber); - bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args); + bool res = + tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args); va_end(args); return res; } @@ -683,7 +688,23 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args); + bool result = false; + uint32_t offset = TokenStream::NoOffset; + switch (kind) { + case ParseError: + result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + break; + case ParseWarning: + result = + tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + break; + case ParseExtraWarning: + result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); + break; + case ParseStrictError: + result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); + break; + } va_end(args); return result; } From eea318fce49861819bf9b382998d5f994b0430c8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:22:00 +0200 Subject: [PATCH 32/37] Remove Parser::reportHelper since it's no longer used. --- js/src/frontend/Parser.cpp | 24 ------------------------ js/src/frontend/Parser.h | 3 --- 2 files changed, 27 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 30a627a65b..189f27bc41 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -570,30 +570,6 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope) computeInWith(enclosingScope); } -template -bool -Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, va_list args) -{ - bool result = false; - switch (kind) { - case ParseError: - result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); - break; - case ParseWarning: - result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); - break; - case ParseExtraWarning: - result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); - break; - case ParseStrictError: - result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); - break; - } - return result; -} - template void Parser::error(unsigned errorNumber, ...) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 196c71fa5d..156a1c1b07 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -903,9 +903,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); } void freeTree(Node node) { handler.freeTree(node); } - private: - bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, - unsigned errorNumber, va_list args); public: bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); From 0c3fb437a9b1c64bf6677c7bed75a4c591bbf550 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:26:49 +0200 Subject: [PATCH 33/37] Rename TokenStream::reportStrictWarningErrorNumberVA to TokenStream::reportExtraWarningErrorNumberVA for clarity. Emit Extra Warnings instead of Strict Warnings from the BCE where it makes sense. --- js/src/frontend/BytecodeEmitter.cpp | 8 ++++---- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/frontend/Parser.cpp | 4 ++-- js/src/frontend/TokenStream.cpp | 2 +- js/src/frontend/TokenStream.h | 3 +-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 71289e84a7..b3dd6d777a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3608,13 +3608,13 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) } bool -BytecodeEmitter::reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...) +BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) { TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportStrictWarningErrorNumberVA(pos.begin, errorNumber, args); + bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args); va_end(args); return result; } @@ -8707,13 +8707,13 @@ BytecodeEmitter::emitStatement(ParseNode* pn) } if (directive) { - if (!reportStrictWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive)) + if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive)) return false; } } else { current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin); current->lastColumn = 0; - if (!reportStrictWarning(pn2, JSMSG_USELESS_EXPR)) + if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR)) return false; } } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 04307c8c19..32668a34ca 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -388,7 +388,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter } bool reportError(ParseNode* pn, unsigned errorNumber, ...); - bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...); + bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...); bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...); // If pn contains a useful expression, return true with *answer set to true. diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 189f27bc41..daacbb50bf 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -628,7 +628,7 @@ Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = tokenStream.reportStrictWarningErrorNumberVA(pos().begin, errorNumber, args); + bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args); va_end(args); return result; } @@ -675,7 +675,7 @@ Parser::reportNoOffset(ParseReportKind kind, bool strict, unsigned tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); break; case ParseExtraWarning: - result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args); + result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args); break; case ParseStrictError: result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index b040d29981..8438ff7c52 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -786,7 +786,7 @@ TokenStream::reportWarning(unsigned errorNumber, ...) } bool -TokenStream::reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) +TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) { if (!options().extraWarningsOption) return true; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 03a5800729..6ba9fba5a6 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -375,8 +375,7 @@ class MOZ_STACK_CLASS TokenStream va_list args); bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, va_list args); - bool reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, - va_list args); + bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args); // asm.js reporter void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...); From 4a60de1031f7f19d0c73f601954f1ef26f89cb54 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 20:35:14 +0200 Subject: [PATCH 34/37] Revert "add a nullptr check in nsSVGUtils::PaintFrameWithEffects" This reverts commit 00baf283622b47ad7926c6e62364854d3dfbc00a. --- layout/svg/nsSVGUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index b8794a05d0..0bded21ffe 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -685,7 +685,7 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame, bool isOK = effectProperties.HasNoFilterOrHasValidFilter(); nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK); nsSVGMaskFrame *maskFrame = effectProperties.GetFirstMaskFrame(&isOK); - if (!isOK || !maskFrame) { + if (!isOK) { // Some resource is invalid. We shouldn't paint anything. return DrawResult::SUCCESS; } From 59d70056173f443ef1abcf08c890c4ffa338aad4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 22:12:00 +0200 Subject: [PATCH 35/37] Add nullcheck in nsSVGUtils::PaintFrameWithEffects Some SVGs define a mask but an invalid mask frame. Check to make sure we have a `maskFrame` that isn't null before trying to use it. This resolves #1034 --- layout/svg/nsSVGUtils.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 0bded21ffe..98e5f9b5fe 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -734,9 +734,12 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame, RefPtr maskSurface; if (maskUsage.shouldGenerateMaskLayer) { - maskSurface = - maskFrame->GetMaskForMaskedFrame(&aContext, aFrame, aTransform, - maskUsage.opacity, &maskTransform); + // Make sure we have a mask frame. + if (maskFrame) { + maskSurface = + maskFrame->GetMaskForMaskedFrame(&aContext, aFrame, aTransform, + maskUsage.opacity, &maskTransform); + } if (!maskSurface) { // Entire surface is clipped out. From 42aff1f6cb55991bcc499cc58e543a5580985012 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 11 Apr 2019 14:47:51 +0200 Subject: [PATCH 36/37] Add IDCAC 2.9.9 to blocklist for causing severe issues. --- application/palemoon/app/blocklist.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/application/palemoon/app/blocklist.xml b/application/palemoon/app/blocklist.xml index d557841697..fa594aabea 100644 --- a/application/palemoon/app/blocklist.xml +++ b/application/palemoon/app/blocklist.xml @@ -1,5 +1,5 @@ - @@ -2524,6 +2524,11 @@ xmlns="http://www.mozilla.org/2006/addons-blocklist"> + + + + + From 21193dac4c1c9694ef6e78ce921d2700ed954727 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 11 Apr 2019 14:50:00 +0200 Subject: [PATCH 37/37] Update code of conduct to be community-encompassing. --- docs/CODE_OF_CONDUCT.md | 42 +++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md index 68d1dcc604..858419982b 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/CODE_OF_CONDUCT.md @@ -1,10 +1,30 @@ -# Contributor Code of Conduct -This code of conduct is intended to lay down the basis on which we, as a community of developers and maintainers, work with each other and with others outside of the community. As always when dealing with groups of people from many different backgrounds, there are no hard and fast rules here, and the intention is not to lay down any sort of restrictive frame to work in, but rather to clarify how we (prefer to) approach each other when working together as volunteers/professionals to improve our respective projects, products and life. +# Community Code of Conduct + +This code of conduct is intended to lay down the basis on which we, as a community of developers, maintainers and users, work with each other and with others outside of the community. As always when dealing with groups of people from many different backgrounds, there are no hard and fast rules here, and the intention is not to lay down any sort of restrictive frame to work in, but rather to clarify how we (prefer to) approach each other when working together as volunteers/professionals to improve our respective projects, products and life. ## Our Goal with this Code of Conduct -We, as contributors and maintainers, aim to create a _focused but welcoming_ environment for others; collaboration, acceptance and respect are the cornerstones upon which we must build our community, otherwise there is no future for it. As such, we want to keep participation in our project and community free of harassment. We therefore ask of everyone, new contributors and long-standing members alike, to be accepting of others regardless of their age, ethnicity, level of experience, nationality, personal appearance, race, religion, or sexual orientation. None of these (and alike) attributes should influence how we work together in this project, and should not be grounds to judge or dismiss work done. +We, as contributors and maintainers, aim to create a _focused but welcoming_ environment for others; collaboration, acceptance and respect are the cornerstones upon which we must build our community, otherwise there is no future for it. As such, we want to ensure smooth communication and keep participation in our project and community free of harassment. We therefore ask of everyone, new contributors and long-standing members alike, to be accepting of others regardless of their age, ethnicity, level of experience, nationality, personal appearance, race, religion, or sexual orientation. None of these (and alike) attributes should influence how we work together in this project, and should not be grounds to judge or dismiss work done. + +## Community of adults, language, and expected tolerance + +To achieve the required level of focus needed, Our community as a whole targets exclusively **adult** participants with a common level of tolerance. This means that the expected conduct and tolerance levels should be fitting the average adult mindset and all participants in the community are assumed to be of adult age or having the mental capacity of an adult. + +When dealing with others in the community, please mind your language use. Try to avoid common curse words or blasphemous expressions. Using strong language is fine, but excessive use of coarse language is frowned upon. Although everyone is assumed to be of adult age (see previous point), and you may be upset about something, you're kindly requested to keep your use of language under control. + +Please keep in mind that the community is made up of people from all walks of life. You are asked to show a reasonable level of tolerance towards other community members, even if their method of approach is different than what you are used to or not the way you would approach others. Many computer software developers are very direct in their approaches or replies because their profession requires them to be focused and efficient in communication; our community has a larger than average percentage of developers among their ranks so you should expect more direct and "things as they are" responses in communication than you might expect in other communities. Be tolerant of this and try to follow instructions if they are given! +Conversely, try to keep in mind that other community members may not have the same level of computer skill you do and may need more guidance than you can provide. In that case, please forward the user(s) to the Pale Moon forum in a kind manner or (if already there) step back and excuse yourself and ask someone else to provide further assistance in lieu of getting upset or frustrated. + +Our community is primarily using English as a communication language. Please, at all times, use English when creating tracker issues or asking something of developers. The only exception is the foreign language boards on the forum where you can communicate in non-English languages with other community members to get assistance or discuss things, and of course private communication can be in any language you wish. + +Please do not try to unnecessarily mask your identity. We are all people here, with personalities and identities. It is much easier to relate to and assist someone who actually tries to approach others with a personal identity than someone who goes at length to mask themselves. None of the topics in our community should be personally or ideologically sensitive, so there will be no need to hide/cloak/mask yourself. + +Please do not start discussions about politics, religion, or other touchy subjects that are not necessarily related to the platform and its applications (off-topic) and can easily lead to an very unwelcome atmosphere. Although enforcing of this point will be done leniently, you are asked to apply common sense and stop a particular line of conversation if it gets too heated or opinionated for the community's overall atmosphere. If you want to continue an off-topic or in-depth discussion with someone about such topics, please take it to private chat/channels! + +If your background, religion, upbringing or other social factors make you more sensitive than average in terms of social interaction, imagery and/or language use, and if you easily take offense or are prone to moral outrage over opinions of others, then please understand that this community may possibly not be a good match for you or require you to put in extra effort to be a content member. You should consider this before you decide to join the community in that case, and understand it may require effort to adjust to our average level of tolerance. + +Of course, it should be clear that your participation in our community is at all times one of your own free will. You may leave at any time you wish, for any reason or no reason at all. We do, however, ask of you in that case that no matter the reason, you treat the community you are leaving with respect and honor the choices made for and in it, and do not externalize your grievances with the community as a whole or any specific members in it. If you feel a compelling need to do so (i.e. to go on a "ragequit crusade") then please consider first escalating this to the owner to work things out as adults in private before making a potentially self-damaging mess of things. ## Examples of acceptable and unacceptable behavior @@ -13,9 +33,10 @@ Please note that these lists are examples and not exhaustive. If you have any do Examples of behavior that helps create a positive working environment: * Using friendly, neutral and welcoming language. +* Being tolerant to the occasional strong language expression and not taking offense at the drop of a hat. * Being clear in your descriptions and not assuming the reader has any sort of prior knowledge of what you are talking about. -* Being courteous (use "please" when you ask something of someone). -* Being respectful of differing viewpoints and experiences. +* Being courteous (use "please" when you ask someone to do something for you). +* Being respectful of differing viewpoints, backgrounds and experiences. * Gracefully accepting constructive criticism, even if you disagree with such criticism. * Similarly, accepting that someone may not act on criticism given. * Focusing on what is best for the community and its projects instead of individuals. @@ -25,7 +46,8 @@ Examples of unacceptable behavior: * Unwelcome personal attention or advances (sexual or otherwise). If someone asks you to stop approaching them, please respect that. * Displaying disproportionate levels of moral outrage and offense, especially when in response to someone's opinion. -* Bullying, trolling, insulting/derogatory comments, and personal or political attacks. +* Bullying, trolling, uncalled-for insulting/derogatory comments, and personal or political attacks. +* Being disruptive to ongoing discussions (e.g. by purposefully making a technical discussion into a sociopolitical one or trying to derail topical discussions). * Public or private harassment of other community members/contributors. * Publishing others' personal/private information, such as a physical or electronic address, without explicit permission. * Other conduct which could reasonably be considered inappropriate in a professional/workplace setting. @@ -34,7 +56,7 @@ Examples of unacceptable behavior: Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and above all fair corrective action in response to instances of unacceptable behavior. -Corrective action: Project staff has the right and responsibility to evaluate, and if necessary to remove, edit, or reject any comments, repository commits, code changes, wiki edits, issues or issue comments, and other contributions that are not aligned with this Code of Conduct or the community's or projects' best interests, or to ban (temporarily or permanently) any contributor, community member or maintainer for other behaviors that they deem inappropriate, threatening, offensive, or harmful. In cases where there is no clear and definitive breach of rules or common sense, it is expected that staff members consult with project leadership before bans are issued to discuss the severity and intended action. +Corrective action: Project staff has the right and responsibility to evaluate, and if necessary to remove, edit, or reject any comments, repository commits, code changes, wiki edits, issues or issue comments, and other contributions that are not aligned with this Code of Conduct or the community's or projects' best interests, or to ban (temporarily or permanently) any contributor, community member or maintainer for other behaviors that they deem inappropriate, threatening, disproportionately offensive, or harmful. In cases where there is no clear and definitive breach of rules or common sense, it is expected that staff members consult with project leadership before bans are issued to discuss the severity and intended action. ## Applicability @@ -42,9 +64,9 @@ This Code of Conduct applies within project spaces (forum, website, IRC, reposit ## Enforcing this Code of Conduct -We expect our community to apply a good measure of self-regulation when it comes to the conduct displayed by its members. We believe that any community of adults is capable of applying the concepts of common sense, common decency and common courtesy to interactions between its members. -That said, there are always exception situations possible where things need to be escalated, which is where this section comes into play. -Incidents involving abusive, harassing, or otherwise unacceptable behavior that need to be escalated for resolution may be reported by contacting the project owner at moonchild@palemoon.org. The project owner will then review and investigate all complaints and related communication of the case, and will respond in a way that they deem appropriate for the circumstances. +**We expect our community to apply a good measure of self-regulation when it comes to the conduct displayed by its members. We believe that any community of adults is capable of applying the concepts of common sense, common decency and common courtesy to interactions between its members.** +That said, there are always exceptional situations possible where things need to be escalated, which is where this section comes into play. +Incidents involving abusive, harassing, or otherwise unacceptable behavior that need to be escalated for resolution may be reported by contacting the project owner at moonchild@palemoon.org. The project owner will then review and investigate all complaints and related communication of the case, and will respond in a way that they deem appropriate for the circumstances. It is imperative that any such reports are complete (nothing left out), true to fact, and presented in a coherent fashion. ## Confidentiality