From e547de64c80b98d661999c0788c09210d9d4a37e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 12:47:28 +0100 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 76afe80b1..b5be5f5ac 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 72e967639..0bc1ab2ab 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 4eb7bf880..c5e62ae34 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 209265a58..1ba725a82 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 12642fad8..090931f5b 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 a6ac542f6..b20417d5d 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 179a7c244..b040d2998 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 5d6b4b795..77eea3d81 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 37d023bd4..9ee29ffe4 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 bcb0da80b..4412362c2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -815,8 +815,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; @@ -838,8 +840,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; @@ -1019,53 +1022,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}")) { @@ -1076,13 +1088,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) { @@ -1669,7 +1683,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) { @@ -1696,6 +1721,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 9f914943e..33ae56d6f 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 87da79901..bb8635581 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 2237d1d7f..2b6690363 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 { -- cgit v1.2.3 From 4ee0411274b7ded730da8cb87f016d53dab56533 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 13:51:57 +0100 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 4412362c2..be11bf436 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1715,7 +1715,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; } } -- cgit v1.2.3 From 90f6b2704658a554a12ed3c37545cb6474fbcf51 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 2 Feb 2019 14:29:54 +0100 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index cd4ac122c..389bb57db 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] == '(') { - s++; - parenChomp = 1; - } - - /* Try to jump "function" keyword. */ - s = js_strchr_limit(s, ' ', end); - if (!s) + if (s == e) return false; - /* - * 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; + // Remove enclosing parentheses. + if (*s == '(' && *(e - 1) == ')') { + s++; + e--; + } - if (*s == ' ') + (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. + 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; + + if (comma && !buf.append(", ")) + return false; + comma = true; + + 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; - size_t voffset = 0; - size_t vlength = valstr->length(); + if (result) { + if (!buf.append(valstr)) + return false; + return 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])) { + { + // 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(' ')) - return nullptr; + if (fun->isStarGenerator()) { + if (!buf.append('*')) + return false; + } } - 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; + } + 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 nullptr; + 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 (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('}')) -- cgit v1.2.3 From ae4af7b7e598b4fec037254a1fd03ac3495695a4 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 3 Feb 2019 08:21:19 +0100 Subject: Stage 1-4: Update tests --- js/src/jit-test/tests/asm.js/testSource.js | 48 +-- .../tests/basic/function-tosource-bug779694.js | 2 +- .../tests/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 +- .../jit-test/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 +- js/src/tests/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 +- js/src/tests/js1_7/extensions/regress-354945-01.js | 2 +- js/src/tests/js1_7/extensions/regress-354945-02.js | 2 +- js/src/tests/js1_8_5/regress/regress-584355.js | 2 +- 19 files changed, 424 insertions(+), 53 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 (limited to 'js/src') diff --git a/js/src/jit-test/tests/asm.js/testSource.js b/js/src/jit-test/tests/asm.js/testSource.js index b44c52a6b..d7ad42864 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 3893d3ff2..782b2594b 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 e1d144364..9a8961fe2 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 36c6d010e..1804d38f2 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 263c3eb8a..9a2f39197 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 04dd4b220..9689a6ebe 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 30c3e8dbc..5ecb4556f 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 2aa382b7b..4546818e4 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 64cfce92a..46e76015e 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 cef79cb96..1389a1ada 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 a0dedf251..07a76733a 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 000000000..33b9e588e --- /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 000000000..e69de29bb 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 000000000..e69de29bb diff --git a/js/src/tests/ecma_6/Generators/runtime.js b/js/src/tests/ecma_6/Generators/runtime.js index c4d3bb6a6..7146eef9f 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 19d190eea..a75bf885a 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 76f1a3c82..1c57db0f7 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 261bf7de1..abef90f77 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 4ddfe65d3..7d1b81a2e 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 ();")) (); } -- cgit v1.2.3 From 0b999100f6c0b7b90d1167237621826e0e6a808a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 26 Mar 2019 18:30:57 +0100 Subject: Simplify some alias sets in IonMonkey. --- js/src/jit/AliasAnalysisShared.cpp | 3 ++- js/src/jit/MIR.h | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index ae28327ca..81c0fd067 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -102,7 +102,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_SetDisjointTypedElements: case MDefinition::Op_ArrayPopShift: case MDefinition::Op_ArrayPush: - case MDefinition::Op_ArraySlice: case MDefinition::Op_LoadTypedArrayElementHole: case MDefinition::Op_StoreTypedArrayElementHole: case MDefinition::Op_LoadFixedSlot: @@ -126,6 +125,7 @@ GetObject(const MDefinition* ins) object = ins->getOperand(0); break; case MDefinition::Op_GetPropertyCache: + case MDefinition::Op_CallGetProperty: case MDefinition::Op_LoadTypedArrayElementStatic: case MDefinition::Op_StoreTypedArrayElementStatic: case MDefinition::Op_GetDOMProperty: @@ -148,6 +148,7 @@ GetObject(const MDefinition* ins) case MDefinition::Op_WasmLoadGlobalVar: case MDefinition::Op_WasmStoreGlobalVar: case MDefinition::Op_ArrayJoin: + case MDefinition::Op_ArraySlice: return nullptr; default: #ifdef DEBUG diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index b2e84322f..fb0f22fc3 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9910,10 +9910,6 @@ class MArraySlice return unboxedType_; } - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) | - AliasSet::ObjectFields); - } bool possiblyCalls() const override { return true; } @@ -11837,7 +11833,8 @@ class MCallGetProperty AliasSet getAliasSet() const override { if (!idempotent_) return AliasSet::Store(AliasSet::Any); - return AliasSet::None(); + return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | + AliasSet::DynamicSlot); } bool possiblyCalls() const override { return true; -- cgit v1.2.3 From 25779d371c571e4f51792af3e3c5588b3186e934 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 30 Mar 2019 19:10:17 +0100 Subject: Issue #187: Remove solaris conditional code. --- js/src/builtin/TestingFunctions.cpp | 4 -- js/src/ctypes/CTypes.cpp | 4 -- js/src/gc/Memory.cpp | 85 ---------------------------------- js/src/jsapi-tests/testGCAllocator.cpp | 12 +---- js/src/jsnativestack.cpp | 14 ------ js/src/vm/Time.cpp | 11 ----- js/src/wasm/WasmSignalHandlers.cpp | 2 +- 7 files changed, 2 insertions(+), 130 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 373b6c9ed..c896ce5d1 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -240,11 +240,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) if (!JS_SetProperty(cx, info, "intl-api", value)) return false; -#if defined(SOLARIS) - value = BooleanValue(false); -#else value = BooleanValue(true); -#endif if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) return false; diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 0facd0009..d6adfac2c 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -20,10 +20,6 @@ #include #endif -#if defined(SOLARIS) -#include -#endif - #ifdef HAVE_SSIZE_T #include #endif diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 26da75469..268e1e489 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -17,11 +17,6 @@ #include "jswin.h" #include -#elif defined(SOLARIS) - -#include -#include - #elif defined(XP_UNIX) #include @@ -408,86 +403,6 @@ DeallocateMappedContent(void* p, size_t length) # endif -#elif defined(SOLARIS) - -#ifndef MAP_NOSYNC -# define MAP_NOSYNC 0 -#endif - -void -InitMemorySubsystem() -{ - if (pageSize == 0) - pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE)); -} - -void* -MapAlignedPages(size_t size, size_t alignment) -{ - MOZ_ASSERT(size >= alignment); - MOZ_ASSERT(size >= allocGranularity); - MOZ_ASSERT(size % alignment == 0); - MOZ_ASSERT(size % pageSize == 0); - MOZ_ASSERT_IF(alignment < allocGranularity, allocGranularity % alignment == 0); - MOZ_ASSERT_IF(alignment > allocGranularity, alignment % allocGranularity == 0); - - int prot = PROT_READ | PROT_WRITE; - int flags = MAP_PRIVATE | MAP_ANON | MAP_ALIGN | MAP_NOSYNC; - - void* p = mmap((caddr_t)alignment, size, prot, flags, -1, 0); - if (p == MAP_FAILED) - return nullptr; - return p; -} - -static void* -MapAlignedPagesLastDitch(size_t size, size_t alignment) -{ - return nullptr; -} - -void -UnmapPages(void* p, size_t size) -{ - MOZ_ALWAYS_TRUE(0 == munmap((caddr_t)p, size)); -} - -bool -MarkPagesUnused(void* p, size_t size) -{ - MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0); - return true; -} - -bool -MarkPagesInUse(void* p, size_t size) -{ - if (!DecommitEnabled()) - return; - - MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0); -} - -size_t -GetPageFaultCount() -{ - return 0; -} - -void* -AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) -{ - // Not implemented. - return nullptr; -} - -// Deallocate mapped memory for object. -void -DeallocateMappedContent(void* p, size_t length) -{ - // Not implemented. -} - #elif defined(XP_UNIX) void diff --git a/js/src/jsapi-tests/testGCAllocator.cpp b/js/src/jsapi-tests/testGCAllocator.cpp index 2c5c58a29..d203019ec 100644 --- a/js/src/jsapi-tests/testGCAllocator.cpp +++ b/js/src/jsapi-tests/testGCAllocator.cpp @@ -14,8 +14,6 @@ #if defined(XP_WIN) #include "jswin.h" #include -#elif defined(SOLARIS) -// This test doesn't apply to Solaris. #elif defined(XP_UNIX) #include #include @@ -39,8 +37,6 @@ BEGIN_TEST(testGCAllocator) # else // Various APIs are unavailable. This test is disabled. return true; # endif -#elif defined(SOLARIS) - return true; #elif defined(XP_UNIX) PageSize = size_t(sysconf(_SC_PAGESIZE)); #else @@ -301,12 +297,6 @@ void* mapMemory(size_t length) { return nullptr; } void unmapPages(void* p, size_t size) { } # endif -#elif defined(SOLARIS) // This test doesn't apply to Solaris. - -void* mapMemoryAt(void* desired, size_t length) { return nullptr; } -void* mapMemory(size_t length) { return nullptr; } -void unmapPages(void* p, size_t size) { } - #elif defined(XP_UNIX) void* @@ -377,7 +367,7 @@ unmapPages(void* p, size_t size) MOZ_RELEASE_ASSERT(errno == ENOMEM); } -#else // !defined(XP_WIN) && !defined(SOLARIS) && !defined(XP_UNIX) +#else // !defined(XP_WIN) && !defined(XP_UNIX) #error "Memory mapping functions are not defined for your OS." #endif END_TEST(testGCAllocator) diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 166a5a4f7..95e0f8da7 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -71,20 +71,6 @@ js::GetNativeStackBaseImpl() # endif } -#elif defined(SOLARIS) - -#include - -JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); - -void* -js::GetNativeStackBaseImpl() -{ - stack_t st; - stack_getbounds(&st); - return static_cast(st.ss_sp) + st.ss_size; -} - #elif defined(AIX) #include diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp index 69e2cc41d..87531c148 100644 --- a/js/src/vm/Time.cpp +++ b/js/src/vm/Time.cpp @@ -11,9 +11,6 @@ #include "mozilla/DebugOnly.h" #include "mozilla/MathAlgorithms.h" -#ifdef SOLARIS -#define _REENTRANT 1 -#endif #include #include @@ -33,10 +30,6 @@ #ifdef XP_UNIX -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ -extern int gettimeofday(struct timeval* tv); -#endif - #include #endif /* XP_UNIX */ @@ -49,11 +42,7 @@ PRMJ_Now() { struct timeval tv; -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ - gettimeofday(&tv); -#else gettimeofday(&tv, 0); -#endif /* _SVID_GETTOD */ return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec); } diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp index 78d21369d..c4733cc96 100644 --- a/js/src/wasm/WasmSignalHandlers.cpp +++ b/js/src/wasm/WasmSignalHandlers.cpp @@ -130,7 +130,7 @@ class AutoSetHandlingSegFault # define EPC_sig(p) ((p)->sc_pc) # define RFP_sig(p) ((p)->sc_regs[30]) # endif -#elif defined(__linux__) || defined(SOLARIS) +#elif defined(__linux__) # if defined(__linux__) # define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i]) # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP]) -- cgit v1.2.3 From 6b968b13d9cab02d8634facc87ae39e51dee4020 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 30 Mar 2019 20:03:33 +0100 Subject: Issue #187: Remove solaris 1st party code OS checks. --- js/src/Makefile.in | 10 ---------- js/src/ctypes/libffi/testsuite/libffi.call/float2.c | 10 ---------- js/src/moz.build | 8 -------- 3 files changed, 28 deletions(-) (limited to 'js/src') diff --git a/js/src/Makefile.in b/js/src/Makefile.in index b007954b1..7f49a3718 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -146,16 +146,6 @@ ifeq ($(OS_ARCH),AIX) # 1540-1608: anonymous unions using static data members CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 -endif -endif -ifeq ($(OS_ARCH),SunOS) -ifeq ($(TARGET_CPU),sparc) - -ifdef GNU_CC -CFLAGS += -mcpu=v9 -CXXFLAGS += -mcpu=v9 -endif # GNU_CC - endif endif diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float2.c b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c index a0b296cf4..dfdef0598 100644 --- a/js/src/ctypes/libffi/testsuite/libffi.call/float2.c +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c @@ -32,21 +32,11 @@ int main (void) f = 3.14159; -#if 1 - /* This is ifdef'd out for now. long double support under SunOS/gcc - is pretty much non-existent. You'll get the odd bus error in library - routines like printf(). */ printf ("%Lf\n", ldblit(f)); -#endif ld = 666; ffi_call(&cif, FFI_FN(ldblit), &ld, values); -#if 1 - /* This is ifdef'd out for now. long double support under SunOS/gcc - is pretty much non-existent. You'll get the odd bus error in library - routines like printf(). */ printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON); -#endif /* These are not always the same!! Check for a reasonable delta */ if (ld - ldblit(f) < LDBL_EPSILON) diff --git a/js/src/moz.build b/js/src/moz.build index a3283b5d6..888741138 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -722,14 +722,6 @@ if CONFIG['OS_ARCH'] == 'Linux': 'dl', ] -if CONFIG['OS_ARCH'] == 'SunOS': - OS_LIBS += [ - 'posix4', - 'dl', - 'nsl', - 'socket', - ] - OS_LIBS += CONFIG['REALTIME_LIBS'] CFLAGS += CONFIG['MOZ_ICU_CFLAGS'] -- cgit v1.2.3 From 5d409fdca92e085dad2f9c80b42f33afe4f10800 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 31 Mar 2019 18:43:10 +0200 Subject: Remove AIX 1st party code OS checks, part 1 Issue #186 --- js/src/Makefile.in | 11 ----------- js/src/jsnativestack.cpp | 15 --------------- 2 files changed, 26 deletions(-) (limited to 'js/src') diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 7f49a3718..20678c68c 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -138,17 +138,6 @@ distclean:: CFLAGS += $(MOZ_ZLIB_CFLAGS) -# Silence warnings on AIX/HP-UX from non-GNU compilers -ifndef GNU_CC -ifeq ($(OS_ARCH),AIX) -# Suppress warnings from xlC -# 1540-1281: offsetof() on null non-POD types -# 1540-1608: anonymous unions using static data members -CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 -CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 -endif -endif - $(LIBRARY_NAME).pc: js.pc cp $^ $@ diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 95e0f8da7..98f8fc741 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -71,21 +71,6 @@ js::GetNativeStackBaseImpl() # endif } -#elif defined(AIX) - -#include - -JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); - -void* -js::GetNativeStackBaseImpl() -{ - ucontext_t context; - getcontext(&context); - return static_cast(context.uc_stack.ss_sp) + - context.uc_stack.ss_size; -} - #elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__) void* js::GetNativeStackBaseImpl() -- cgit v1.2.3 From a2786c051173286c9d7ccee2c3c6a19c15966322 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 1 Apr 2019 00:11:06 +0200 Subject: Remove AIX 1st party code OS checks, part 2 Issue #186 --- js/src/jstypes.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 75774e5b8..6cfb3d4ad 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -147,13 +147,7 @@ # define JS_64BIT # endif #elif defined(__GNUC__) -/* Additional GCC defines are when running on Solaris, AIX, and HPUX */ -# if defined(__x86_64__) || defined(__sparcv9) || \ - defined(__64BIT__) || defined(__LP64__) -# define JS_64BIT -# endif -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Sun Studio C/C++ */ -# if defined(__x86_64) || defined(__sparcv9) +# if defined(__x86_64__) || defined(__64BIT__) # define JS_64BIT # endif #elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */ -- cgit v1.2.3 From 8bbd0d556c0bf583b16076844b9e263a5f996495 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 20:54:29 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c5e62ae34..71289e84a 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 1ba725a82..26b3c2c25 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 090931f5b..88d705108 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 77eea3d81..03a580072 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 -- cgit v1.2.3 From 68c4eea34dc0ddf680036db62f1b9daeb131cfba Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:01:54 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 26b3c2c25..a29287850 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 88d705108..402b977ba 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); -- cgit v1.2.3 From 2950deb043a403377a589046acaa38cfe3dc9876 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:25:28 +0200 Subject: Change report at current offset to warning(), extraWarning() and error() --- js/src/frontend/Parser.cpp | 261 ++++++++++++++++++++++++--------------------- js/src/frontend/Parser.h | 13 ++- 2 files changed, 152 insertions(+), 122 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a29287850..8ad8813b5 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 @@ -594,13 +594,38 @@ Parser::reportHelper(ParseReportKind kind, bool strict, uint32_t o return result; } +template +void +Parser::error(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#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::qeport(ParseReportKind kind, unsigned errorNumber, ...) +Parser::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportHelper(kind, false, pos().begin, errorNumber, args); + 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 402b977ba..feead0e63 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); -- cgit v1.2.3 From 1ee96e39db760004c33a235ea691ab06bac21375 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:30:52 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 0fd137796..da068e5af 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 8ad8813b5..afbf4c4c9 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 b7f00605b..85695ba9c 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; } -- cgit v1.2.3 From 11a1f58b9a0ebf83c17087a89e6b4ba83748374a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:32:55 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index afbf4c4c9..f625595a2 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 feead0e63..c8914a2d7 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, ...); -- cgit v1.2.3 From dcf64bd2ffd24d1c0d046af810c3270656081663 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 5 Apr 2019 21:38:21 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f625595a2..5981881d3 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) -- cgit v1.2.3 From 96899aa847ab7495e3b7baaa413cf50a5eaaffff Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 04:22:27 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5981881d3..8466d7c1c 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 c8914a2d7..3bfb4ae31 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. -- cgit v1.2.3 From 7333618581b018ca73c3482e2d5547765f6c3a1d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:22:55 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index da068e5af..b619cf24c 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 c58dab431..c3523afe4 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 8466d7c1c..c34e4d563 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()); - - // 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; - } - } + TokenPos pos = handler.getPosition(pn); - if (declaredInStmt) { - MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); - MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); + // 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"); - 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. + // 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 (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB)) - return false; - } + if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) { + reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL); + return false; + } + } - if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos)) - return false; - } else { - if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos)) - return false; + if (declaredInStmt) { + MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label); + MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind())); - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver(); + 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 { - // 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 3bfb4ae31..dc9c16adb 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 85695ba9c..00ea9d35d 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 2b6690363..a318d67a9 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; -- cgit v1.2.3 From 239003468d0617ca34b5e78627f014207b4e63ee Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:26:49 +0200 Subject: Inline GeneratorKindFromPropertyType and AsyncKindFromPropertyType. Trivially inlines these into their sole caller. --- js/src/frontend/Parser.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c34e4d563..5a42b75b0 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(); -- cgit v1.2.3 From 386cc5ee17b4e144fdffda1742031aa0cba7373a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:36:09 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5a42b75b0..34d87528f 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 dc9c16adb..13580846b 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, -- cgit v1.2.3 From 7d56f431ccc11f3b5e2e6deec331bd9c7a06cf80 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:39:27 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 34d87528f..b494cc966 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 13580846b..efbaebafd 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 -- cgit v1.2.3 From 4c4f8091e620a35d6d20a5b0ccc6c118e9b8e5e5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 06:54:09 +0200 Subject: 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 ++++---- 5 files changed, 10 insertions(+), 29 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index b494cc966..0099ed19d 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 efbaebafd..27a10458b 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 a276dab94..42a48c3a5 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 7982e12ee..495717af7 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 de563645d..b0309a90e 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'; -- cgit v1.2.3 From f5c293d3e82581740558c79cf752bccc0420199c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 07:30:00 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0099ed19d..2702f3075 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(); } -- cgit v1.2.3 From d7b76a5a5286475fcba1663028032a7ea834daed Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:31:01 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 2702f3075..a26520477 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 42a48c3a5..a19e3aa85 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") -- cgit v1.2.3 From 940a6ceb9a5b3d8c7c2ed53da67f5c14cc84925c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:33:24 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a26520477..43f39dc23 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 27a10458b..6bd7e586e 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. -- cgit v1.2.3 From 51e2758e02a6187228e35f58bfa0e1752870476b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:34:17 +0200 Subject: Remove Parser::reportWithOffset since it's no longer used. --- js/src/frontend/Parser.cpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 43f39dc23..9f9169950 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() -- cgit v1.2.3 From d60cfce5e4b2e7ecf344b86c1bd4a712490a8c52 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:37:12 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9f9169950..fe30328de 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(); } } -- cgit v1.2.3 From 4a62cbec61620f54bfb3949d9165c4dd406c2444 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:41:42 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fe30328de..94573fce7 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 6bd7e586e..e3827d953 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, -- cgit v1.2.3 From 8e8d0ed75c076b4b92e2971ff877b104dafeffca Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:44:48 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 94573fce7..c979e38c3 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. -- cgit v1.2.3 From b579e0567c887743d24c2745065b71bb06fea4f8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:46:15 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c979e38c3..3a5b5d6d7 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 e3827d953..70d382501 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); -- cgit v1.2.3 From f4fec66e094281465ce1d143e00b0c9bda4863af Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:47:27 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3a5b5d6d7..3f793ffcf 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; } -- cgit v1.2.3 From 194e6155211353738bb14ffd1ca9e9662a455b0e Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:55:02 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3f793ffcf..041c92fa7 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 70d382501..8bffafc42 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); } -- cgit v1.2.3 From 8580bf233e69da042e3d33cad56ca6f42ce441a4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 10:56:39 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 041c92fa7..5c4d509dd 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 8bffafc42..c50f8e47d 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 a19e3aa85..2901b88cc 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") -- cgit v1.2.3 From 74672745e6d1932a4aa7fa6a8cd6ab09fd9de4fe Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:05:22 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 5c4d509dd..3e7c25c19 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 c50f8e47d..0baaac3bc 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 2901b88cc..4ded69a25 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") -- cgit v1.2.3 From 7ea8efe0cb3199566b86a2b7ad4cb99df8620324 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:11:04 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3e7c25c19..3b1cadbff 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 0baaac3bc..a7e48c1a4 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); -- cgit v1.2.3 From 4f62fda966af85252f8345e51d694cd6d3a063c8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:18:36 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3b1cadbff..c08ba4889 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 a7e48c1a4..196c71fa5 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. */ -- cgit v1.2.3 From f38ef66b7b9f1d1c85c5d8a7a5bbaa5f6c3c9948 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:20:43 +0200 Subject: Inline Parser::reportHelper into its callers. --- js/src/frontend/Parser.cpp | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c08ba4889..30a627a65 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; } -- cgit v1.2.3 From e88f15157f90cb2115d30dd7fc61704637536cd5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:22:00 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 30a627a65..189f27bc4 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 196c71fa5..156a1c1b0 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, ...); -- cgit v1.2.3 From a5d22aa6106fbd3c8cec12333b14d4c65cd98647 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 6 Apr 2019 11:26:49 +0200 Subject: 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(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 71289e84a..b3dd6d777 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 04307c8c1..32668a34c 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 189f27bc4..daacbb50b 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 b040d2998..8438ff7c5 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 03a580072..6ba9fba5a 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, ...); -- cgit v1.2.3 From 51af3decb97f7eed3fa92dfddb89be22828a0275 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 25 Apr 2019 16:45:28 +0200 Subject: Remove useless assert. Resolves #1055. --- js/src/frontend/Parser.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'js/src') diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index daacbb50b..3b7a0e612 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2310,7 +2310,6 @@ Parser::standaloneFunction(HandleFunction fun, if (!tokenStream.getToken(&tt)) return null(); if (asyncKind == AsyncFunction) { - MOZ_ASSERT(tt == TOK_ASYNC); if (!tokenStream.getToken(&tt)) return null(); } -- cgit v1.2.3 From 5a65d8739d0ad6ef446b278a25fd955f0c734fb1 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 11:59:46 +0300 Subject: Improve dead compartment collection js/src --- js/src/jsgc.cpp | 198 +++++++++++++++++++++++++++++------------------- js/src/jsgc.h | 13 +++- js/src/jswatchpoint.cpp | 21 ++--- 3 files changed, 141 insertions(+), 91 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 8cee9ec09..1e8e4fc8d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1524,20 +1524,11 @@ GCMarker::delayMarkingChildren(const void* thing) } inline void -ArenaLists::prepareForIncrementalGC(JSRuntime* rt) +ArenaLists::prepareForIncrementalGC() { - for (auto i : AllAllocKinds()) { - FreeSpan* span = freeLists[i]; - if (span != &placeholder) { - if (!span->isEmpty()) { - Arena* arena = span->getArena(); - arena->allocatedDuringIncremental = true; - rt->gc.marker.delayMarkingArena(arena); - } else { - freeLists[i] = &placeholder; - } - } - } + purge(); + for (auto i : AllAllocKinds()) + arenaLists[i].moveCursorToEnd(); } /* Compacting GC */ @@ -2251,7 +2242,7 @@ GCRuntime::updateTypeDescrObjects(MovingTracer* trc, Zone* zone) { zone->typeDescrObjects.sweep(); for (auto r = zone->typeDescrObjects.all(); !r.empty(); r.popFront()) - UpdateCellPointers(trc, r.front().get()); + UpdateCellPointers(trc, r.front()); } void @@ -3579,6 +3570,23 @@ RelazifyFunctions(Zone* zone, AllocKind kind) } } +static bool +ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) +{ + // Normally we collect all scheduled zones. + if (reason != JS::gcreason::COMPARTMENT_REVIVED) + return zone->isGCScheduled(); + + // If we are repeating a GC becuase we noticed dead compartments haven't + // been collected, then only collect zones contianing those compartments. + for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { + if (comp->scheduledForDestruction) + return true; + } + + return false; +} + bool GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock) { @@ -3602,7 +3610,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces #endif /* Set up which zones will be collected. */ - if (zone->isGCScheduled()) { + if (ShouldCollectZone(zone, reason)) { if (!zone->isAtomsZone()) { any = true; zone->setGCState(Zone::Mark); @@ -3621,7 +3629,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { c->marked = false; c->scheduledForDestruction = false; - c->maybeAlive = false; + c->maybeAlive = c->hasBeenEntered() || !c->zone()->isGCScheduled(); if (shouldPreserveJITCode(c, currentTime, reason, canAllocateMoreCode)) c->zone()->setPreservingCode(true); } @@ -3640,6 +3648,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces * keepAtoms() will only change on the main thread, which we are currently * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. + + + + + + */ if (isFull && !rt->keepAtoms()) { Zone* atomsZone = rt->atomsCompartment(lock)->zone(); @@ -3655,15 +3669,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces return false; /* - * At the end of each incremental slice, we call prepareForIncrementalGC, - * which marks objects in all arenas that we're currently allocating - * into. This can cause leaks if unreachable objects are in these - * arenas. This purge call ensures that we only mark arenas that have had - * allocations after the incremental GC started. + * Ensure that after the start of a collection we don't allocate into any + * existing arenas, as this can cause unreachable things to be marked. */ if (isIncremental) { for (GCZonesIter zone(rt); !zone.done(); zone.next()) - zone->arenas.purge(); + zone->arenas.prepareForIncrementalGC(); } MemProfiler::MarkTenuredStart(rt); @@ -3747,13 +3758,11 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); - if (isIncremental) { - gcstats::AutoPhase ap3(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); - bufferGrayRoots(); - } - - markCompartments(); - + if (isIncremental) { + bufferGrayRoots(); + markCompartments(); + } + return true; } @@ -3766,9 +3775,14 @@ GCRuntime::markCompartments() * This code ensures that if a compartment is "dead", then it will be * collected in this GC. A compartment is considered dead if its maybeAlive * flag is false. The maybeAlive flag is set if: - * (1) the compartment has incoming cross-compartment edges, or - * (2) an object in the compartment was marked during root marking, either - * as a black root or a gray root. + * (1) the compartment has been entered (set in beginMarkPhase() above) + * (2) the compartment is not being collected (set in beginMarkPhase() + * above) + * (3) an object in the compartment was marked during root marking, either + * as a black root or a gray root (set in RootMarking.cpp), or + * (4) the compartment has incoming cross-compartment edges from another + * compartment that has maybeAlive set (set by this method). + * * If the maybeAlive is false, then we set the scheduledForDestruction flag. * At the end of the GC, we look for compartments where * scheduledForDestruction is true. These are compartments that were somehow @@ -3786,26 +3800,37 @@ GCRuntime::markCompartments() * allocation and read barriers during JS_TransplantObject and the like. */ - /* Set the maybeAlive flag based on cross-compartment edges. */ - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { + /* Propagate the maybeAlive flag via cross-compartment edges. */ + + Vector workList; + + for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { + if (comp->maybeAlive) { + if (!workList.append(comp)) + return; + } + } + while (!workList.empty()) { + JSCompartment* comp = workList.popCopy(); + for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { if (e.front().key().is()) continue; JSCompartment* dest = e.front().mutableKey().compartment(); - if (dest) + if (dest && !dest->maybeAlive) { dest->maybeAlive = true; + if (!workList.append(dest)) + return; + } } } - /* - * For black roots, code in gc/Marking.cpp will already have set maybeAlive - * during MarkRuntime. - */ - - /* Propogate maybeAlive to scheduleForDestruction. */ - for (GCCompartmentsIter c(rt); !c.done(); c.next()) { - if (!c->maybeAlive && !rt->isAtomsCompartment(c)) - c->scheduledForDestruction = true; + + /* Set scheduleForDestruction based on maybeAlive. */ + + for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) { + MOZ_ASSERT(!comp->scheduledForDestruction); + if (!comp->maybeAlive && !rt->isAtomsCompartment(comp)) + comp->scheduledForDestruction = true; } } @@ -5306,7 +5331,7 @@ AutoGCSlice::~AutoGCSlice() for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) { if (zone->isGCMarking()) { zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit); - zone->arenas.prepareForIncrementalGC(runtime); + zone->arenas.purge(); } else { zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); } @@ -5487,9 +5512,9 @@ gc::AbortReason gc::IsIncrementalGCUnsafe(JSRuntime* rt) { MOZ_ASSERT(!rt->mainThread.suppressGC); - - if (rt->keepAtoms()) - return gc::AbortReason::KeepAtomsSet; + + if (rt->keepAtoms()) + return gc::AbortReason::KeepAtomsSet; if (!rt->gc.isIncrementalGCAllowed()) return gc::AbortReason::IncrementalDisabled; @@ -5498,9 +5523,17 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt) } void -GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock) +GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, + AutoLockForExclusiveAccess& lock) { AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); + if (unsafeReason == AbortReason::None) { + if (reason == JS::gcreason::COMPARTMENT_REVIVED) + unsafeReason = gc::AbortReason::CompartmentRevived; + else if (mode != JSGC_MODE_INCREMENTAL) + unsafeReason = gc::AbortReason::ModeChange; + } + if (unsafeReason != AbortReason::None) { resetIncrementalGC(unsafeReason, lock); budget.makeUnlimited(); @@ -5508,12 +5541,7 @@ GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& return; } - if (mode != JSGC_MODE_INCREMENTAL) { - resetIncrementalGC(AbortReason::ModeChange, lock); - budget.makeUnlimited(); - stats.nonincremental(AbortReason::ModeChange); - return; - } + if (isTooMuchMalloc()) { budget.makeUnlimited(); @@ -5660,6 +5688,10 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: } State prevState = incrementalState; + + + + if (nonincrementalByAPI) { // Reset any in progress incremental GC if this was triggered via the @@ -5672,7 +5704,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: stats.nonincremental(gc::AbortReason::NonIncrementalRequested); budget.makeUnlimited(); } else { - budgetIncrementalGC(budget, session.lock); + budgetIncrementalGC(reason, budget, session.lock); } /* The GC was reset, so we need a do-over. */ @@ -5764,6 +5796,22 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) return true; } +bool +GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) +{ + MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental); + + if (!isIncremental || isIncrementalGCInProgress()) + return false; + + for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { + if (c->scheduledForDestruction) + return true; + } + + return false; +} + void GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) { @@ -5782,27 +5830,23 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R do { poked = false; bool wasReset = gcCycle(nonincrementalByAPI, budget, reason); - - /* Need to re-schedule all zones for GC. */ - if (poked && cleanUpEverything) + + bool repeatForDeadZone = false; + if (poked && cleanUpEverything) { + /* Need to re-schedule all zones for GC. */ JS::PrepareForFullGC(rt->contextFromMainThread()); - /* - * This code makes an extra effort to collect compartments that we - * thought were dead at the start of the GC. See the large comment in - * beginMarkPhase. - */ - bool repeatForDeadZone = false; - if (!nonincrementalByAPI && !isIncrementalGCInProgress()) { - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - if (c->scheduledForDestruction) { - nonincrementalByAPI = true; - repeatForDeadZone = true; - reason = JS::gcreason::COMPARTMENT_REVIVED; - c->zone()->scheduleGC(); - } - } - } + + } else if (shouldRepeatForDeadZone(reason) && !wasReset) { + /* + * This code makes an extra effort to collect compartments that we + * thought were dead at the start of the GC. See the large comment + * in beginMarkPhase. + */ + repeatForDeadZone = true; + reason = JS::gcreason::COMPARTMENT_REVIVED; + } + /* * If we reset an existing GC, we need to start a new one. Also, we @@ -7070,4 +7114,4 @@ js::gc::detail::CellIsMarkedGrayIfKnown(const Cell* cell) } return detail::CellIsMarkedGray(tc); -} +} \ No newline at end of file diff --git a/js/src/jsgc.h b/js/src/jsgc.h index d3cf31fe7..aa42d474c 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -61,7 +61,8 @@ enum class State { D(ModeChange) \ D(MallocBytesTrigger) \ D(GCBytesTrigger) \ - D(ZoneChange) + D(ZoneChange) \ + D(CompartmentRevived) enum class AbortReason { #define MAKE_REASON(name) name, GC_ABORT_REASONS(MAKE_REASON) @@ -353,7 +354,6 @@ struct SortedArenaListSegment * be treated as an invariant, however, as the free lists may be cleared, * leaving arenas previously used for allocation partially full. Sorting order * is restored during sweeping. - * Arenas following the cursor should not be full. */ class ArenaList { @@ -453,6 +453,11 @@ class ArenaList { check(); return !*cursorp_; } + + void moveCursorToEnd() { + while (!isCursorAtEnd()) + cursorp_ = &(*cursorp_)->next; + } // This can return nullptr. Arena* arenaAfterCursor() const { @@ -739,7 +744,7 @@ class ArenaLists freeLists[i] = &placeholder; } - inline void prepareForIncrementalGC(JSRuntime* rt); + inline void prepareForIncrementalGC(); /* Check if this arena is in use. */ bool arenaIsInUse(Arena* arena, AllocKind kind) const { @@ -1504,4 +1509,4 @@ UninlinedIsInsideNursery(const gc::Cell* cell); } /* namespace js */ -#endif /* jsgc_h */ +#endif /* jsgc_h */ \ No newline at end of file diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index 3cf43e219..68afa4a59 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -185,17 +185,18 @@ WatchpointMap::markAll(JSTracer* trc) { for (Map::Enum e(map); !e.empty(); e.popFront()) { Map::Entry& entry = e.front(); - WatchKey key = entry.key(); - WatchKey prior = key; - MOZ_ASSERT(JSID_IS_STRING(prior.id) || JSID_IS_INT(prior.id) || JSID_IS_SYMBOL(prior.id)); - - TraceEdge(trc, const_cast(&key.object), - "held Watchpoint object"); - TraceEdge(trc, const_cast(&key.id), "WatchKey::id"); + JSObject* object = entry.key().object; + jsid id = entry.key().id; + JSObject* priorObject = object; + jsid priorId = id; + MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId)); + + TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object"); + TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id"); TraceEdge(trc, &entry.value().closure, "Watchpoint::closure"); - if (prior.object != key.object || prior.id != key.id) - e.rekeyFront(key); + if (priorObject != object || priorId != id) + e.rekeyFront(WatchKey(object, id)); } } @@ -242,4 +243,4 @@ WatchpointMap::trace(WeakMapTracer* trc) JS::GCCellPtr(entry.key().object.get()), JS::GCCellPtr(entry.value().closure.get())); } -} +} \ No newline at end of file -- cgit v1.2.3 From 2cb4d2ee571b91ec2480d2fba17e600a3843ddba Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 12:02:24 +0300 Subject: Improve dead compartment collection js/src/gc --- js/src/gc/GCRuntime.h | 6 ++++-- js/src/gc/RootMarking.cpp | 4 ++-- js/src/gc/Zone.cpp | 17 ++++++++++++++++- js/src/gc/Zone.h | 13 ++++++++++--- 4 files changed, 32 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 5c2576efd..16260a4e3 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -900,7 +900,8 @@ class GCRuntime void requestMajorGC(JS::gcreason::Reason reason); SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis); - void budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock); + void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, + AutoLockForExclusiveAccess& lock); void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock); // Assert if the system state is such that we should never @@ -915,6 +916,7 @@ class GCRuntime void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL; MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason); + bool shouldRepeatForDeadZone(JS::gcreason::Reason reason); void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock); @@ -1348,4 +1350,4 @@ class MOZ_RAII AutoMaybeStartBackgroundAllocation } /* namespace js */ -#endif +#endif \ No newline at end of file diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 93264084b..ed7b8fb6f 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -478,6 +478,7 @@ js::gc::GCRuntime::bufferGrayRoots() for (GCZonesIter zone(rt); !zone.done(); zone.next()) MOZ_ASSERT(zone->gcGrayRoots.empty()); + gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); BufferGrayRootsTracer grayBufferer(rt); if (JSTraceDataOp op = grayRootTracer.op) @@ -539,5 +540,4 @@ GCRuntime::resetBufferedGrayRoots() const "Do not clear the gray buffers unless we are Failed or becoming Unused"); for (GCZonesIter zone(rt); !zone.done(); zone.next()) zone->gcGrayRoots.clearAndFree(); -} - +} \ No newline at end of file diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index ed099341c..ecfb9a38c 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -370,6 +370,21 @@ Zone::fixupAfterMovingGC() fixupInitialShapeTable(); } +bool +Zone::addTypeDescrObject(JSContext* cx, HandleObject obj) +{ + // Type descriptor objects are always tenured so we don't need post barriers + // on the set. + MOZ_ASSERT(!IsInsideNursery(obj)); + + if (!typeDescrObjects.put(obj)) { + ReportOutOfMemory(cx); + return false; + } + + return true; +} + ZoneList::ZoneList() : head(nullptr), tail(nullptr) {} @@ -468,4 +483,4 @@ JS_PUBLIC_API(void) JS::shadow::RegisterWeakCache(JS::Zone* zone, WeakCache* cachep) { zone->registerWeakCache(cachep); -} +} \ No newline at end of file diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 50d06319d..24f4648f7 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -349,10 +349,17 @@ struct Zone : public JS::shadow::Zone, // Keep track of all TypeDescr and related objects in this compartment. // This is used by the GC to trace them all first when compacting, since the // TypedObject trace hook may access these objects. - using TypeDescrObjectSet = js::GCHashSet, - js::MovableCellHasher>, + + // + // There are no barriers here - the set contains only tenured objects so no + // post-barrier is required, and these are weak references so no pre-barrier + // is required. + using TypeDescrObjectSet = js::GCHashSet, js::SystemAllocPolicy>; JS::WeakCache typeDescrObjects; + + bool addTypeDescrObject(JSContext* cx, HandleObject obj); // Malloc counter to measure memory pressure for GC scheduling. It runs from @@ -734,4 +741,4 @@ class ZoneAllocPolicy } // namespace js -#endif // gc_Zone_h +#endif // gc_Zone_h \ No newline at end of file -- cgit v1.2.3 From bb1fad0fa728c7e95c6e06dfae63254b2c2e2966 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 12:05:03 +0300 Subject: Improve dead compartment collection js/src/builtin --- js/src/builtin/TypedObject.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index ae74f01bf..95704ee46 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -652,7 +652,7 @@ ArrayMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, obj)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(obj)) { + if (!cx->zone()->addTypeDescrObject(cx, obj)) { ReportOutOfMemory(cx); return nullptr; } @@ -993,8 +993,8 @@ StructMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, descr)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(descr) || - !cx->zone()->typeDescrObjects.put(fieldTypeVec)) + if (!cx->zone()->addTypeDescrObject(cx, descr) || + !cx->zone()->addTypeDescrObject(cx, fieldTypeVec)) { ReportOutOfMemory(cx); return nullptr; @@ -1165,10 +1165,8 @@ DefineSimpleTypeDescr(JSContext* cx, if (!CreateTraceList(cx, descr)) return false; - if (!cx->zone()->typeDescrObjects.put(descr)) { - ReportOutOfMemory(cx); + if (!cx->zone()->addTypeDescrObject(cx, descr)) return false; - } return true; } @@ -3005,4 +3003,4 @@ TypeDescr::finalize(FreeOp* fop, JSObject* obj) TypeDescr& descr = obj->as(); if (descr.hasTraceList()) js_free(const_cast(descr.traceList())); -} +} \ No newline at end of file -- cgit v1.2.3 From 44e59151e3e7678626202482c72e2696bcc17769 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 12:32:23 +0300 Subject: Space to comment. --- js/src/jsgc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'js/src') diff --git a/js/src/jsgc.h b/js/src/jsgc.h index aa42d474c..8626e3e38 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -354,6 +354,7 @@ struct SortedArenaListSegment * be treated as an invariant, however, as the free lists may be cleared, * leaving arenas previously used for allocation partially full. Sorting order * is restored during sweeping. + * Arenas following the cursor should not be full. */ class ArenaList { -- cgit v1.2.3 From d57c13c6d8700eebfe7042ae52e31a6ac1bb28a1 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 15:31:58 +0300 Subject: Add newline at end of files js/src --- js/src/jsgc.cpp | 2 +- js/src/jsgc.h | 2 +- js/src/jswatchpoint.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 1e8e4fc8d..ad3d7093d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -7114,4 +7114,4 @@ js::gc::detail::CellIsMarkedGrayIfKnown(const Cell* cell) } return detail::CellIsMarkedGray(tc); -} \ No newline at end of file +} diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 8626e3e38..5d3c37286 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1510,4 +1510,4 @@ UninlinedIsInsideNursery(const gc::Cell* cell); } /* namespace js */ -#endif /* jsgc_h */ \ No newline at end of file +#endif /* jsgc_h */ diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index 68afa4a59..f147a07dc 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -243,4 +243,4 @@ WatchpointMap::trace(WeakMapTracer* trc) JS::GCCellPtr(entry.key().object.get()), JS::GCCellPtr(entry.value().closure.get())); } -} \ No newline at end of file +} -- cgit v1.2.3 From 22116f9a70e23e69d0830265901736f6d6dcf6f6 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 15:33:52 +0300 Subject: add newline at end of files js/src/gc --- js/src/gc/GCRuntime.h | 2 +- js/src/gc/RootMarking.cpp | 2 +- js/src/gc/Zone.cpp | 2 +- js/src/gc/Zone.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 16260a4e3..72910c615 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -1350,4 +1350,4 @@ class MOZ_RAII AutoMaybeStartBackgroundAllocation } /* namespace js */ -#endif \ No newline at end of file +#endif diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index ed7b8fb6f..b09ee6e00 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -540,4 +540,4 @@ GCRuntime::resetBufferedGrayRoots() const "Do not clear the gray buffers unless we are Failed or becoming Unused"); for (GCZonesIter zone(rt); !zone.done(); zone.next()) zone->gcGrayRoots.clearAndFree(); -} \ No newline at end of file +} diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index ecfb9a38c..7681f15c5 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -483,4 +483,4 @@ JS_PUBLIC_API(void) JS::shadow::RegisterWeakCache(JS::Zone* zone, WeakCache* cachep) { zone->registerWeakCache(cachep); -} \ No newline at end of file +} diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 24f4648f7..d337fe85c 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -741,4 +741,4 @@ class ZoneAllocPolicy } // namespace js -#endif // gc_Zone_h \ No newline at end of file +#endif // gc_Zone_h -- cgit v1.2.3 From 6f15c693f77159c83189de7c6610b8a6e1317736 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Mon, 29 Apr 2019 15:36:04 +0300 Subject: Add newline at end of file js/src/builtin --- js/src/builtin/TypedObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 95704ee46..0dfc1123a 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -3003,4 +3003,4 @@ TypeDescr::finalize(FreeOp* fop, JSObject* obj) TypeDescr& descr = obj->as(); if (descr.hasTraceList()) js_free(const_cast(descr.traceList())); -} \ No newline at end of file +} -- cgit v1.2.3 From 0e70828f2c84cc0ac9afd85d14eb30b5fc8358dd Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 02:16:38 +0300 Subject: tab to spaces js/src --- js/src/jsgc.cpp | 78 ++++++++++++++++++++++++------------------------- js/src/jsgc.h | 10 +++---- js/src/jswatchpoint.cpp | 4 +-- 3 files changed, 46 insertions(+), 46 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index ad3d7093d..283eb22b0 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1527,7 +1527,7 @@ inline void ArenaLists::prepareForIncrementalGC() { purge(); - for (auto i : AllAllocKinds()) + for (auto i : AllAllocKinds()) arenaLists[i].moveCursorToEnd(); } @@ -3573,18 +3573,18 @@ RelazifyFunctions(Zone* zone, AllocKind kind) static bool ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) { - // Normally we collect all scheduled zones. - if (reason != JS::gcreason::COMPARTMENT_REVIVED) - return zone->isGCScheduled(); + // Normally we collect all scheduled zones. + if (reason != JS::gcreason::COMPARTMENT_REVIVED) + return zone->isGCScheduled(); - // If we are repeating a GC becuase we noticed dead compartments haven't - // been collected, then only collect zones contianing those compartments. - for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { - if (comp->scheduledForDestruction) - return true; - } - - return false; + // If we are repeating a GC becuase we noticed dead compartments haven't + // been collected, then only collect zones contianing those compartments. + for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { + if (comp->scheduledForDestruction) + return true; + } + + return false; } bool @@ -5527,12 +5527,12 @@ GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, AutoLockForExclusiveAccess& lock) { AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); - if (unsafeReason == AbortReason::None) { - if (reason == JS::gcreason::COMPARTMENT_REVIVED) - unsafeReason = gc::AbortReason::CompartmentRevived; - else if (mode != JSGC_MODE_INCREMENTAL) - unsafeReason = gc::AbortReason::ModeChange; - } + if (unsafeReason == AbortReason::None) { + if (reason == JS::gcreason::COMPARTMENT_REVIVED) + unsafeReason = gc::AbortReason::CompartmentRevived; + else if (mode != JSGC_MODE_INCREMENTAL) + unsafeReason = gc::AbortReason::ModeChange; + } if (unsafeReason != AbortReason::None) { resetIncrementalGC(unsafeReason, lock); @@ -5799,17 +5799,17 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) bool GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason) { - MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental); - - if (!isIncremental || isIncrementalGCInProgress()) - return false; - - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - if (c->scheduledForDestruction) - return true; - } - - return false; + MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental); + + if (!isIncremental || isIncrementalGCInProgress()) + return false; + + for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { + if (c->scheduledForDestruction) + return true; + } + + return false; } void @@ -5831,21 +5831,21 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R poked = false; bool wasReset = gcCycle(nonincrementalByAPI, budget, reason); - bool repeatForDeadZone = false; + bool repeatForDeadZone = false; if (poked && cleanUpEverything) { - /* Need to re-schedule all zones for GC. */ + /* Need to re-schedule all zones for GC. */ JS::PrepareForFullGC(rt->contextFromMainThread()); } else if (shouldRepeatForDeadZone(reason) && !wasReset) { - /* - * This code makes an extra effort to collect compartments that we - * thought were dead at the start of the GC. See the large comment - * in beginMarkPhase. - */ - repeatForDeadZone = true; - reason = JS::gcreason::COMPARTMENT_REVIVED; - } + /* + * This code makes an extra effort to collect compartments that we + * thought were dead at the start of the GC. See the large comment + * in beginMarkPhase. + */ + repeatForDeadZone = true; + reason = JS::gcreason::COMPARTMENT_REVIVED; + } /* diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 5d3c37286..85b9f5f4a 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -62,7 +62,7 @@ enum class State { D(MallocBytesTrigger) \ D(GCBytesTrigger) \ D(ZoneChange) \ - D(CompartmentRevived) + D(CompartmentRevived) enum class AbortReason { #define MAKE_REASON(name) name, GC_ABORT_REASONS(MAKE_REASON) @@ -455,10 +455,10 @@ class ArenaList { return !*cursorp_; } - void moveCursorToEnd() { - while (!isCursorAtEnd()) - cursorp_ = &(*cursorp_)->next; - } + void moveCursorToEnd() { + while (!isCursorAtEnd()) + cursorp_ = &(*cursorp_)->next; + } // This can return nullptr. Arena* arenaAfterCursor() const { diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index f147a07dc..e37323555 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -187,8 +187,8 @@ WatchpointMap::markAll(JSTracer* trc) Map::Entry& entry = e.front(); JSObject* object = entry.key().object; jsid id = entry.key().id; - JSObject* priorObject = object; - jsid priorId = id; + JSObject* priorObject = object; + jsid priorId = id; MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId)); TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object"); -- cgit v1.2.3 From 9fb6b925fb249d3dd9f467142410a2e605736784 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 02:20:36 +0300 Subject: tab to spaces js/src/gc --- js/src/gc/GCRuntime.h | 4 ++-- js/src/gc/RootMarking.cpp | 2 +- js/src/gc/Zone.cpp | 24 ++++++++++++------------ js/src/gc/Zone.h | 12 ++++++------ 4 files changed, 21 insertions(+), 21 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 72910c615..f102e9ef0 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -901,7 +901,7 @@ class GCRuntime void requestMajorGC(JS::gcreason::Reason reason); SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis); void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, - AutoLockForExclusiveAccess& lock); + AutoLockForExclusiveAccess& lock); void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock); // Assert if the system state is such that we should never @@ -916,7 +916,7 @@ class GCRuntime void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL; MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason); - bool shouldRepeatForDeadZone(JS::gcreason::Reason reason); + bool shouldRepeatForDeadZone(JS::gcreason::Reason reason); void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index b09ee6e00..f5969bc1f 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -478,7 +478,7 @@ js::gc::GCRuntime::bufferGrayRoots() for (GCZonesIter zone(rt); !zone.done(); zone.next()) MOZ_ASSERT(zone->gcGrayRoots.empty()); - gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); + gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS); BufferGrayRootsTracer grayBufferer(rt); if (JSTraceDataOp op = grayRootTracer.op) diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 7681f15c5..f0cdde012 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -373,18 +373,18 @@ Zone::fixupAfterMovingGC() bool Zone::addTypeDescrObject(JSContext* cx, HandleObject obj) { - // Type descriptor objects are always tenured so we don't need post barriers - // on the set. - MOZ_ASSERT(!IsInsideNursery(obj)); - - if (!typeDescrObjects.put(obj)) { - ReportOutOfMemory(cx); - return false; - } - - return true; -} - + // Type descriptor objects are always tenured so we don't need post barriers + // on the set. + MOZ_ASSERT(!IsInsideNursery(obj)); + + if (!typeDescrObjects.put(obj)) { + ReportOutOfMemory(cx); + return false; + } + + return true; +} + ZoneList::ZoneList() : head(nullptr), tail(nullptr) {} diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index d337fe85c..c8520ed55 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -350,16 +350,16 @@ struct Zone : public JS::shadow::Zone, // This is used by the GC to trace them all first when compacting, since the // TypedObject trace hook may access these objects. - // - // There are no barriers here - the set contains only tenured objects so no - // post-barrier is required, and these are weak references so no pre-barrier - // is required. - using TypeDescrObjectSet = js::GCHashSet, js::SystemAllocPolicy>; JS::WeakCache typeDescrObjects; - bool addTypeDescrObject(JSContext* cx, HandleObject obj); + bool addTypeDescrObject(JSContext* cx, HandleObject obj); // Malloc counter to measure memory pressure for GC scheduling. It runs from -- cgit v1.2.3 From 4d03ec5c22ff2ac288808ad008a94634a53745da Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 02:43:47 +0300 Subject: remaining tabs to space js/src/jsgc.cpp --- js/src/jsgc.cpp | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 283eb22b0..589e478f4 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3758,11 +3758,11 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); - if (isIncremental) { + if (isIncremental) { bufferGrayRoots(); - markCompartments(); - } - + markCompartments(); + } + return true; } @@ -3778,11 +3778,11 @@ GCRuntime::markCompartments() * (1) the compartment has been entered (set in beginMarkPhase() above) * (2) the compartment is not being collected (set in beginMarkPhase() * above) - * (3) an object in the compartment was marked during root marking, either - * as a black root or a gray root (set in RootMarking.cpp), or + * (3) an object in the compartment was marked during root marking, either + * as a black root or a gray root (set in RootMarking.cpp), or * (4) the compartment has incoming cross-compartment edges from another - * compartment that has maybeAlive set (set by this method). - * + * compartment that has maybeAlive set (set by this method). + * * If the maybeAlive is false, then we set the scheduledForDestruction flag. * At the end of the GC, we look for compartments where * scheduledForDestruction is true. These are compartments that were somehow @@ -3802,35 +3802,35 @@ GCRuntime::markCompartments() /* Propagate the maybeAlive flag via cross-compartment edges. */ - Vector workList; - - for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { - if (comp->maybeAlive) { - if (!workList.append(comp)) - return; - } - } - while (!workList.empty()) { - JSCompartment* comp = workList.popCopy(); - for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { + Vector workList; + + for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) { + if (comp->maybeAlive) { + if (!workList.append(comp)) + return; + } + } + while (!workList.empty()) { + JSCompartment* comp = workList.popCopy(); + for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { if (e.front().key().is()) continue; JSCompartment* dest = e.front().mutableKey().compartment(); if (dest && !dest->maybeAlive) { dest->maybeAlive = true; - if (!workList.append(dest)) - return; - } + if (!workList.append(dest)) + return; + } } } /* Set scheduleForDestruction based on maybeAlive. */ - for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) { - MOZ_ASSERT(!comp->scheduledForDestruction); - if (!comp->maybeAlive && !rt->isAtomsCompartment(comp)) - comp->scheduledForDestruction = true; + for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) { + MOZ_ASSERT(!comp->scheduledForDestruction); + if (!comp->maybeAlive && !rt->isAtomsCompartment(comp)) + comp->scheduledForDestruction = true; } } -- cgit v1.2.3 From a2dbd23b0428ccc09a8daf52ebbc50d7141d0cd5 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 12:22:51 +0300 Subject: Remove some empty lines --- js/src/jsgc.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 589e478f4..70d392973 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3649,10 +3649,6 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. - - - - */ if (isFull && !rt->keepAtoms()) { @@ -5689,9 +5685,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: State prevState = incrementalState; - - - if (nonincrementalByAPI) { // Reset any in progress incremental GC if this was triggered via the -- cgit v1.2.3 From 0c8c58314cb4e22d975a5802094073cd03c99d17 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 12:37:16 +0300 Subject: Remove rest of empty lines. --- js/src/jsgc.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 70d392973..a1296f0d8 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3648,9 +3648,8 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces * keepAtoms() will only change on the main thread, which we are currently * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. - - */ + if (isFull && !rt->keepAtoms()) { Zone* atomsZone = rt->atomsCompartment(lock)->zone(); if (atomsZone->isGCScheduled()) { @@ -5684,7 +5683,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: } State prevState = incrementalState; - if (nonincrementalByAPI) { // Reset any in progress incremental GC if this was triggered via the -- cgit v1.2.3 From 31ea8c7e934bd4dd78ef44dc9dfd47bd27bdf0a3 Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 13:22:57 +0300 Subject: Whitespaces, typo, tabs to space Remove whitespaces, correct comment typo, one more tab to space --- js/src/jsgc.cpp | 12 ++++++------ js/src/jsgc.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index a1296f0d8..f528b2d70 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3578,7 +3578,7 @@ ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) return zone->isGCScheduled(); // If we are repeating a GC becuase we noticed dead compartments haven't - // been collected, then only collect zones contianing those compartments. + // been collected, then only collect zones containing those compartments. for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { if (comp->scheduledForDestruction) return true; @@ -3753,8 +3753,8 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); - if (isIncremental) { - bufferGrayRoots(); + if (isIncremental) { + bufferGrayRoots(); markCompartments(); } @@ -5508,8 +5508,8 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt) { MOZ_ASSERT(!rt->mainThread.suppressGC); - if (rt->keepAtoms()) - return gc::AbortReason::KeepAtomsSet; + if (rt->keepAtoms()) + return gc::AbortReason::KeepAtomsSet; if (!rt->gc.isIncrementalGCAllowed()) return gc::AbortReason::IncrementalDisabled; @@ -5519,7 +5519,7 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt) void GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget, - AutoLockForExclusiveAccess& lock) + AutoLockForExclusiveAccess& lock) { AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); if (unsafeReason == AbortReason::None) { diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 85b9f5f4a..d00d2aef6 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -354,7 +354,7 @@ struct SortedArenaListSegment * be treated as an invariant, however, as the free lists may be cleared, * leaving arenas previously used for allocation partially full. Sorting order * is restored during sweeping. - + * Arenas following the cursor should not be full. */ class ArenaList { -- cgit v1.2.3 From 2ec2389d7f887d263b76e43af1d40e8b529db40e Mon Sep 17 00:00:00 2001 From: win7-7 Date: Tue, 30 Apr 2019 15:07:04 +0300 Subject: Braces and one more typo fix for comment --- js/src/jsgc.cpp | 5 +++-- js/src/jsgc.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'js/src') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index f528b2d70..194468c5d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1527,8 +1527,9 @@ inline void ArenaLists::prepareForIncrementalGC() { purge(); - for (auto i : AllAllocKinds()) + for (auto i : AllAllocKinds()) { arenaLists[i].moveCursorToEnd(); + } } /* Compacting GC */ @@ -3577,7 +3578,7 @@ ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) if (reason != JS::gcreason::COMPARTMENT_REVIVED) return zone->isGCScheduled(); - // If we are repeating a GC becuase we noticed dead compartments haven't + // If we are repeating a GC because we noticed dead compartments haven't // been collected, then only collect zones containing those compartments. for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { if (comp->scheduledForDestruction) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index d00d2aef6..952fd6bae 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -456,8 +456,9 @@ class ArenaList { } void moveCursorToEnd() { - while (!isCursorAtEnd()) + while (!isCursorAtEnd()) { cursorp_ = &(*cursorp_)->next; + } } // This can return nullptr. -- cgit v1.2.3 From 3ded48cbe3529811f8638fde9f392bc915c35163 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 13 May 2019 15:45:32 +0000 Subject: Unhook Unboxed Objects option --- js/src/jsapi.cpp | 3 --- js/src/jsapi.h | 25 ++++++++++++------------- js/src/shell/js.cpp | 3 --- 3 files changed, 12 insertions(+), 19 deletions(-) (limited to 'js/src') diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f78f94dc1..9ee29ffe4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6434,9 +6434,6 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v } jit::JitOptions.jumpThreshold = value; break; - case JSJITCOMPILER_UNBOXED_OBJECTS: - jit::JitOptions.disableUnboxedObjects = !value; - break; case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE: jit::JitOptions.asmJSAtomicsEnable = !!value; break; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 1f726f2e5..005d2278e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5783,20 +5783,19 @@ JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); extern JS_PUBLIC_API(void) JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); -#define JIT_COMPILER_OPTIONS(Register) \ - Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ - Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ - Register(ION_GVN_ENABLE, "ion.gvn.enable") \ - Register(ION_FORCE_IC, "ion.forceinlineCaches") \ - Register(ION_ENABLE, "ion.enable") \ +#define JIT_COMPILER_OPTIONS(Register) \ + Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ + Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ + Register(ION_GVN_ENABLE, "ion.gvn.enable") \ + Register(ION_FORCE_IC, "ion.forceinlineCaches") \ + Register(ION_ENABLE, "ion.enable") \ Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \ - Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ - Register(BASELINE_ENABLE, "baseline.enable") \ - Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ - Register(JUMP_THRESHOLD, "jump-threshold") \ - Register(UNBOXED_OBJECTS, "unboxed_objects") \ - Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ - Register(WASM_TEST_MODE, "wasm.test-mode") \ + Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ + Register(BASELINE_ENABLE, "baseline.enable") \ + Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_TEST_MODE, "wasm.test-mode") \ Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") typedef enum JSJitCompilerOption { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8d144417a..193d8d22b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -7276,9 +7276,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op) if (op.getBoolOption("wasm-check-bce")) jit::JitOptions.wasmAlwaysCheckBounds = true; - if (op.getBoolOption("no-unboxed-objects")) - jit::JitOptions.disableUnboxedObjects = true; - if (const char* str = op.getStringOption("cache-ir-stubs")) { if (strcmp(str, "on") == 0) jit::JitOptions.disableCacheIR = false; -- cgit v1.2.3 From 9a3141515f051b6622f564ba75c171822854a7ac Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 14 May 2019 11:44:11 +0000 Subject: remove unboxed code chunk (wip1) --- js/src/jit/BaselineInspector.cpp | 31 +-- js/src/jit/BaselineInspector.h | 9 +- js/src/jit/IonBuilder.cpp | 80 +------- js/src/jit/IonBuilder.h | 4 - js/src/jit/MCallOptimize.cpp | 8 +- js/src/vm/UnboxedObject.cpp | 400 --------------------------------------- 6 files changed, 25 insertions(+), 507 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index c9e09bed7..9c7b88fb2 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -96,13 +96,8 @@ VectorAppendNoDuplicate(S& list, T value) static bool AddReceiver(const ReceiverGuard& receiver, - BaselineInspector::ReceiverVector& receivers, - BaselineInspector::ObjectGroupVector& convertUnboxedGroups) + BaselineInspector::ReceiverVector& receivers) { - if (receiver.group && receiver.group->maybeUnboxedLayout()) { - if (receiver.group->unboxedLayout().nativeGroup()) - return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group); - } return VectorAppendNoDuplicate(receivers, receiver); } @@ -170,16 +165,12 @@ GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* r } bool -BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups) +BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers) { // Return a list of the receivers seen by the baseline IC for the current // op. Empty lists indicate no receivers are known, or there was an - // uncacheable access. convertUnboxedGroups is used for unboxed object - // groups which have been seen, but have had instances converted to native - // objects and should be eagerly converted by Ion. + // uncacheable access. MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(convertUnboxedGroups.empty()); if (!hasBaselineScript()) return true; @@ -207,7 +198,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv return true; } - if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) + if (!AddReceiver(receiver, receivers)) return false; stub = stub->next(); @@ -700,14 +691,12 @@ bool BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty, - ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups) + ReceiverVector& receivers) { if (!hasBaselineScript()) return false; MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(convertUnboxedGroups.empty()); *holder = nullptr; const ICEntry& entry = icEntryFromPC(pc); @@ -719,7 +708,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap { ICGetPropCallGetter* nstub = static_cast(stub); bool isOwn = nstub->isOwnGetter(); - if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups)) + if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers)) return false; if (!*holder) { @@ -751,21 +740,19 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap if (!*holder) return false; - MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty())); + MOZ_ASSERT(*isOwnProperty == (receivers.empty())); return true; } bool BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonSetter, bool* isOwnProperty, - ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups) + ReceiverVector& receivers) { if (!hasBaselineScript()) return false; MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(convertUnboxedGroups.empty()); *holder = nullptr; const ICEntry& entry = icEntryFromPC(pc); @@ -774,7 +761,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) { ICSetPropCallSetter* nstub = static_cast(stub); bool isOwn = nstub->isOwnSetter(); - if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups)) + if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers)) return false; if (!*holder) { diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index 961df18aa..4a1791798 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -95,8 +95,7 @@ class BaselineInspector public: typedef Vector ReceiverVector; typedef Vector ObjectGroupVector; - MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups); + MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers); SetElemICInspector setElemICInspector(jsbytecode* pc) { return makeICInspector(pc, ICStub::SetElem_Fallback); @@ -131,12 +130,10 @@ class BaselineInspector MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, - bool* isOwnProperty, ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups); + bool* isOwnProperty, ReceiverVector& receivers); MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, JSFunction** commonSetter, bool* isOwnProperty, - ReceiverVector& receivers, - ObjectGroupVector& convertUnboxedGroups); + ReceiverVector& receivers); MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot, JSObject** prototypeObject); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 54d05cac4..28fa53aa8 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -9012,8 +9012,6 @@ IonBuilder::jsop_getelem() } obj = maybeUnboxForPropertyAccess(obj); - if (obj->type() == MIRType::Object) - obj = convertUnboxedObjects(obj); bool emitted = false; @@ -10137,7 +10135,7 @@ IonBuilder::jsop_setelem() MDefinition* value = current->pop(); MDefinition* index = current->pop(); - MDefinition* object = convertUnboxedObjects(current->pop()); + MDefinition* object = current->pop(); trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet()); trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet()); @@ -11496,8 +11494,6 @@ IonBuilder::jsop_getprop(PropertyName* name) } obj = maybeUnboxForPropertyAccess(obj); - if (obj->type() == MIRType::Object) - obj = convertUnboxedObjects(obj); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, name, types); @@ -11939,49 +11935,6 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool* emitted, fieldPrediction, fieldTypeObj); } -MDefinition* -IonBuilder::convertUnboxedObjects(MDefinition* obj) -{ - // If obj might be in any particular unboxed group which should be - // converted to a native representation, perform that conversion. This does - // not guarantee the object will not have such a group afterwards, if the - // object's possible groups are not precisely known. - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject() || !types->objectOrSentinel()) - return obj; - - BaselineInspector::ObjectGroupVector list(alloc()); - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i); - if (!key || !key->isGroup()) - continue; - - if (UnboxedLayout* layout = key->group()->maybeUnboxedLayout()) { - AutoEnterOOMUnsafeRegion oomUnsafe; - if (layout->nativeGroup() && !list.append(key->group())) - oomUnsafe.crash("IonBuilder::convertUnboxedObjects"); - } - } - - return convertUnboxedObjects(obj, list); -} - -MDefinition* -IonBuilder::convertUnboxedObjects(MDefinition* obj, - const BaselineInspector::ObjectGroupVector& list) -{ - for (size_t i = 0; i < list.length(); i++) { - ObjectGroup* group = list[i]; - if (TemporaryTypeSet* types = obj->resultTypeSet()) { - if (!types->hasType(TypeSet::ObjectType(group))) - continue; - } - obj = MConvertUnboxedObjectToNative::New(alloc(), obj, group); - current->add(obj->toInstruction()); - } - return obj; -} - bool IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, BarrierKind barrier, TemporaryTypeSet* types) @@ -12163,14 +12116,11 @@ IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* nam MDefinition* IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, - const BaselineInspector::ObjectGroupVector& convertUnboxedGroups, bool isOwnProperty) { MOZ_ASSERT(holder); MOZ_ASSERT(holderShape); - obj = convertUnboxedObjects(obj, convertUnboxedGroups); - if (isOwnProperty) { MOZ_ASSERT(receivers.empty()); return addShapeGuard(obj, holderShape, Bailout_ShapeGuard); @@ -12194,10 +12144,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName JSObject* foundProto = nullptr; bool isOwnProperty = false; BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter, - &globalShape, &isOwnProperty, - receivers, convertUnboxedGroups)) + &globalShape, &isOwnProperty, receivers)) { return true; } @@ -12213,8 +12161,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName // If type information is bad, we can still optimize the getter if we // shape guard. obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, - receivers, convertUnboxedGroups, - isOwnProperty); + receivers, isOwnProperty); if (!obj) return false; } @@ -12381,15 +12328,12 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName MOZ_ASSERT(*emitted == false); BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); - if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) + if (!inspector->maybeInfoForPropertyOp(pc, receivers)) return false; if (!canInlinePropertyOpShapes(receivers)) return true; - obj = convertUnboxedObjects(obj, convertUnboxedGroups); - MIRType rvalType = types->getKnownMIRType(); if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) rvalType = MIRType::Value; @@ -12692,7 +12636,7 @@ bool IonBuilder::jsop_setprop(PropertyName* name) { MDefinition* value = current->pop(); - MDefinition* obj = convertUnboxedObjects(current->pop()); + MDefinition* obj = current->pop(); bool emitted = false; startTrackingOptimizations(); @@ -12765,10 +12709,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, JSObject* foundProto = nullptr; bool isOwnProperty; BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter, - &isOwnProperty, - receivers, convertUnboxedGroups)) + &isOwnProperty, receivers)) { trackOptimizationOutcome(TrackedOutcome::NoProtoFound); return true; @@ -12783,8 +12725,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, // If type information is bad, we can still optimize the setter if we // shape guard. obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, - receivers, convertUnboxedGroups, - isOwnProperty); + receivers, isOwnProperty); if (!obj) return false; } @@ -13146,15 +13087,12 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, } BaselineInspector::ReceiverVector receivers(alloc()); - BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); - if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) + if (!inspector->maybeInfoForPropertyOp(pc, receivers)) return false; if (!canInlinePropertyOpShapes(receivers)) return true; - obj = convertUnboxedObjects(obj, convertUnboxedGroups); - if (receivers.length() == 1) { if (!receivers[0].group) { // Monomorphic store to a native object. @@ -13884,7 +13822,7 @@ IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec) bool IonBuilder::jsop_in() { - MDefinition* obj = convertUnboxedObjects(current->pop()); + MDefinition* obj = current->pop(); MDefinition* id = current->pop(); bool emitted = false; diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index f24ef30c8..2880c7ea1 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1041,7 +1041,6 @@ class IonBuilder MDefinition* addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, - const BaselineInspector::ObjectGroupVector& convertUnboxedGroups, bool isOwnProperty); MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name, @@ -1059,9 +1058,6 @@ class IonBuilder ResultWithOOM testNotDefinedProperty(MDefinition* obj, jsid id); uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed); - MDefinition* convertUnboxedObjects(MDefinition* obj); - MDefinition* convertUnboxedObjects(MDefinition* obj, - const BaselineInspector::ObjectGroupVector& list); uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, JSValueType* punboxedType); MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 01755094a..41ccd0ca7 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -615,7 +615,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) OBJECT_FLAG_LENGTH_OVERFLOW | OBJECT_FLAG_ITERATED; - MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); + MDefinition* obj = callInfo.thisArg(); TemporaryTypeSet* thisTypes = obj->resultTypeSet(); if (!thisTypes) return InliningStatus_NotInlined; @@ -743,7 +743,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) return InliningStatus_NotInlined; } - MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); + MDefinition* obj = callInfo.thisArg(); MDefinition* value = callInfo.getArg(0); if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, nullptr, &value, /* canModify = */ false)) @@ -822,7 +822,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) return InliningStatus_NotInlined; } - MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); + MDefinition* obj = callInfo.thisArg(); // Ensure |this| and result are objects. if (getInlineReturnType() != MIRType::Object) @@ -2152,7 +2152,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo) if (callInfo.argc() != 3) return InliningStatus_NotInlined; - MDefinition* obj = convertUnboxedObjects(callInfo.getArg(0)); + MDefinition* obj = callInfo.getArg(0); MDefinition* id = callInfo.getArg(1); MDefinition* value = callInfo.getArg(2); diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 3018ace67..d7ad91de4 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -1655,227 +1655,12 @@ const Class UnboxedArrayObject::class_ = { // API ///////////////////////////////////////////////////////////////////// -static bool -UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype) -{ - if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32) - return true; - if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL) - return true; - return false; -} - -static bool -CombineUnboxedTypes(const Value& value, JSValueType* existing) -{ - JSValueType type = value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType(); - - if (*existing == JSVAL_TYPE_MAGIC || *existing == type || UnboxedTypeIncludes(type, *existing)) { - *existing = type; - return true; - } - if (UnboxedTypeIncludes(*existing, type)) - return true; - return false; -} - -// Return whether the property names and types in layout are a subset of the -// specified vector. -static bool -PropertiesAreSuperset(const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout) -{ - for (size_t i = 0; i < layout->properties().length(); i++) { - const UnboxedLayout::Property& layoutProperty = layout->properties()[i]; - bool found = false; - for (size_t j = 0; j < properties.length(); j++) { - if (layoutProperty.name == properties[j].name) { - found = (layoutProperty.type == properties[j].type); - break; - } - } - if (!found) - return false; - } - return true; -} - -static bool -CombinePlainObjectProperties(PlainObject* obj, Shape* templateShape, - UnboxedLayout::PropertyVector& properties) -{ - // All preliminary objects must have been created with enough space to - // fill in their unboxed data inline. This is ensured either by using - // the largest allocation kind (which limits the maximum size of an - // unboxed object), or by using an allocation kind that covers all - // properties in the template, as the space used by unboxed properties - // is less than or equal to that used by boxed properties. - MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >= - Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan())); - - if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) { - // Only use an unboxed representation if all created objects match - // the template shape exactly. - return false; - } - - for (size_t i = 0; i < templateShape->slotSpan(); i++) { - Value val = obj->getSlot(i); - - JSValueType& existing = properties[i].type; - if (!CombineUnboxedTypes(val, &existing)) - return false; - } - - return true; -} - -static bool -CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* elementType) -{ - if (obj->inDictionaryMode() || - obj->lastProperty()->propid() != AtomToId(cx->names().length) || - !obj->lastProperty()->previous()->isEmptyShape()) - { - // Only use an unboxed representation if the object has no properties. - return false; - } - - for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { - Value val = obj->getDenseElement(i); - - // For now, unboxed arrays cannot have holes. - if (val.isMagic(JS_ELEMENTS_HOLE)) - return false; - - if (!CombineUnboxedTypes(val, elementType)) - return false; - } - - return true; -} - -static size_t -ComputePlainObjectLayout(ExclusiveContext* cx, Shape* templateShape, - UnboxedLayout::PropertyVector& properties) -{ - // Fill in the names for all the object's properties. - for (Shape::Range r(templateShape); !r.empty(); r.popFront()) { - size_t slot = r.front().slot(); - MOZ_ASSERT(!properties[slot].name); - properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName(); - } - - // Fill in all the unboxed object's property offsets. - uint32_t offset = 0; - - // Search for an existing unboxed layout which is a subset of this one. - // If there are multiple such layouts, use the largest one. If we're able - // to find such a layout, use the same property offsets for the shared - // properties, which will allow us to generate better code if the objects - // have a subtype/supertype relation and are accessed at common sites. - UnboxedLayout* bestExisting = nullptr; - for (UnboxedLayout* existing : cx->compartment()->unboxedLayouts) { - if (PropertiesAreSuperset(properties, existing)) { - if (!bestExisting || - existing->properties().length() > bestExisting->properties().length()) - { - bestExisting = existing; - } - } - } - if (bestExisting) { - for (size_t i = 0; i < bestExisting->properties().length(); i++) { - const UnboxedLayout::Property& existingProperty = bestExisting->properties()[i]; - for (size_t j = 0; j < templateShape->slotSpan(); j++) { - if (existingProperty.name == properties[j].name) { - MOZ_ASSERT(existingProperty.type == properties[j].type); - properties[j].offset = existingProperty.offset; - } - } - } - offset = bestExisting->size(); - } - - // Order remaining properties from the largest down for the best space - // utilization. - static const size_t typeSizes[] = { 8, 4, 1 }; - - for (size_t i = 0; i < ArrayLength(typeSizes); i++) { - size_t size = typeSizes[i]; - for (size_t j = 0; j < templateShape->slotSpan(); j++) { - if (properties[j].offset != UINT32_MAX) - continue; - JSValueType type = properties[j].type; - if (UnboxedTypeSize(type) == size) { - offset = JS_ROUNDUP(offset, size); - properties[j].offset = offset; - offset += size; - } - } - } - - // The final offset is the amount of data needed by the object. - return offset; -} - -static bool -SetLayoutTraceList(ExclusiveContext* cx, UnboxedLayout* layout) -{ - // Figure out the offsets of any objects or string properties. - Vector objectOffsets, stringOffsets; - for (size_t i = 0; i < layout->properties().length(); i++) { - const UnboxedLayout::Property& property = layout->properties()[i]; - MOZ_ASSERT(property.offset != UINT32_MAX); - if (property.type == JSVAL_TYPE_OBJECT) { - if (!objectOffsets.append(property.offset)) - return false; - } else if (property.type == JSVAL_TYPE_STRING) { - if (!stringOffsets.append(property.offset)) - return false; - } - } - - // Construct the layout's trace list. - if (!objectOffsets.empty() || !stringOffsets.empty()) { - Vector entries; - if (!entries.appendAll(stringOffsets) || - !entries.append(-1) || - !entries.appendAll(objectOffsets) || - !entries.append(-1) || - !entries.append(-1)) - { - return false; - } - int32_t* traceList = cx->zone()->pod_malloc(entries.length()); - if (!traceList) - return false; - PodCopy(traceList, entries.begin(), entries.length()); - layout->setTraceList(traceList); - } - - return true; -} - static inline Value NextValue(Handle> values, size_t* valueCursor) { return values[(*valueCursor)++]; } -static bool -GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle> values) -{ - if (!values.append(Int32Value(obj->length()))) - return false; - if (!values.append(Int32Value(obj->getDenseInitializedLength()))) - return false; - for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { - if (!values.append(obj->getDenseElement(i))) - return false; - } - return true; -} - void UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, Handle> values, size_t* valueCursor) @@ -1901,16 +1686,6 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor))); } -static bool -GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle> values) -{ - for (size_t i = 0; i < obj->slotSpan(); i++) { - if (!values.append(obj->getSlot(i))) - return false; - } - return true; -} - void UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, Handle> values, size_t* valueCursor) @@ -1921,181 +1696,6 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); } -bool -js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape, - ObjectGroup* group, PreliminaryObjectArray* objects) -{ - bool isArray = !templateShape; - - // Unboxed arrays are nightly only for now. The getenv() call will be - // removed when they are on by default. See bug 1153266. - if (isArray) { -#ifdef NIGHTLY_BUILD - if (!getenv("JS_OPTION_USE_UNBOXED_ARRAYS")) { - if (!cx->options().unboxedArrays()) - return true; - } -#else - return true; -#endif - } else { - if (jit::JitOptions.disableUnboxedObjects) - return true; - } - - MOZ_ASSERT_IF(templateShape, !templateShape->getObjectFlags()); - - if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global())) - return true; - - if (!isArray && templateShape->slotSpan() == 0) - return true; - - UnboxedLayout::PropertyVector properties; - if (!isArray) { - if (!properties.appendN(UnboxedLayout::Property(), templateShape->slotSpan())) - return false; - } - JSValueType elementType = JSVAL_TYPE_MAGIC; - - size_t objectCount = 0; - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - JSObject* obj = objects->get(i); - if (!obj) - continue; - - if (obj->isSingleton() || obj->group() != group) - return true; - - objectCount++; - - if (isArray) { - if (!CombineArrayObjectElements(cx, &obj->as(), &elementType)) - return true; - } else { - if (!CombinePlainObjectProperties(&obj->as(), templateShape, properties)) - return true; - } - } - - size_t layoutSize = 0; - if (isArray) { - // Don't use an unboxed representation if we couldn't determine an - // element type for the objects. - if (UnboxedTypeSize(elementType) == 0) - return true; - } else { - if (objectCount <= 1) { - // If only one of the objects has been created, it is more likely - // to have new properties added later. This heuristic is not used - // for array objects, where we might want an unboxed representation - // even if there is only one large array. - return true; - } - - for (size_t i = 0; i < templateShape->slotSpan(); i++) { - // We can't use an unboxed representation if e.g. all the objects have - // a null value for one of the properties, as we can't decide what type - // it is supposed to have. - if (UnboxedTypeSize(properties[i].type) == 0) - return true; - } - - // Make sure that all properties on the template shape are property - // names, and not indexes. - for (Shape::Range r(templateShape); !r.empty(); r.popFront()) { - jsid id = r.front().propid(); - uint32_t dummy; - if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy)) - return true; - } - - layoutSize = ComputePlainObjectLayout(cx, templateShape, properties); - - // The entire object must be allocatable inline. - if (UnboxedPlainObject::offsetOfData() + layoutSize > JSObject::MAX_BYTE_SIZE) - return true; - } - - UniquePtr& layout = enter.unboxedLayoutToCleanUp; - MOZ_ASSERT(!layout); - layout = group->zone()->make_unique(); - if (!layout) - return false; - - if (isArray) { - layout->initArray(elementType); - } else { - if (!layout->initProperties(properties, layoutSize)) - return false; - - // The unboxedLayouts list only tracks layouts for plain objects. - cx->compartment()->unboxedLayouts.insertFront(layout.get()); - - if (!SetLayoutTraceList(cx, layout.get())) - return false; - } - - // We've determined that all the preliminary objects can use the new layout - // just constructed, so convert the existing group to use the unboxed class, - // and update the preliminary objects to use the new layout. Do the - // fallible stuff first before modifying any objects. - - // Get an empty shape which we can use for the preliminary objects. - const Class* clasp = isArray ? &UnboxedArrayObject::class_ : &UnboxedPlainObject::class_; - Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0); - if (!newShape) { - cx->recoverFromOutOfMemory(); - return false; - } - - // Accumulate a list of all the values in each preliminary object, and - // update their shapes. - Rooted> values(cx, GCVector(cx)); - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - JSObject* obj = objects->get(i); - if (!obj) - continue; - - bool ok; - if (isArray) - ok = GetValuesFromPreliminaryArrayObject(&obj->as(), &values); - else - ok = GetValuesFromPreliminaryPlainObject(&obj->as(), &values); - - if (!ok) { - cx->recoverFromOutOfMemory(); - return false; - } - } - - if (TypeNewScript* newScript = group->newScript()) - layout->setNewScript(newScript); - - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - if (JSObject* obj = objects->get(i)) - obj->as().setLastPropertyMakeNonNative(newShape); - } - - group->setClasp(clasp); - group->setUnboxedLayout(layout.release()); - - size_t valueCursor = 0; - for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) { - JSObject* obj = objects->get(i); - if (!obj) - continue; - - if (isArray) - obj->as().fillAfterConvert(cx, values, &valueCursor); - else - obj->as().fillAfterConvert(cx, values, &valueCursor); - } - - MOZ_ASSERT(valueCursor == values.length()); - return true; -} - DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements, ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t, ShouldUpdateTypes); -- cgit v1.2.3 From 3b36a43e8ecc34199759691897e18168bbb261e2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 02:06:04 +0000 Subject: Remove initial chunk of Unboxed Objects machinery part 2 --- js/src/vm/TypeInference.cpp | 5 ----- js/src/vm/UnboxedObject.h | 7 ------- 2 files changed, 12 deletions(-) (limited to 'js/src') diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 4775a2dea..fe89fac9c 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3577,7 +3577,6 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro } } - TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects); if (group->maybeUnboxedLayout()) return; @@ -3861,10 +3860,6 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, PodCopy(initializerList, initializerVector.begin(), initializerVector.length()); } - // Try to use an unboxed representation for the group. - if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(), group, preliminaryObjects)) - return false; - js_delete(preliminaryObjects); preliminaryObjects = nullptr; diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index ecff8be5b..779dd14c7 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -317,13 +317,6 @@ class UnboxedPlainObject : public JSObject } }; -// Try to construct an UnboxedLayout for each of the preliminary objects, -// provided they all match the template shape. If successful, converts the -// preliminary objects and their group to the new unboxed representation. -bool -TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape, - ObjectGroup* group, PreliminaryObjectArray* objects); - inline gc::AllocKind UnboxedLayout::getAllocKind() const { -- cgit v1.2.3 From d40bcc350ce47de4a92dd1dc7f7162dc1154678b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 13:18:33 +0000 Subject: Remove Unboxed Objects in ScalarReplacement A note about the Scalar Replacement Changes: The M{Load,Store}Unboxed* instructions in theory could be used to manipulate and analyze typed arrays. However, TypedArrays should already be excluded from eligibility because of the potential for cross-thread sharing in a SharedArrayBuffer world, and so the only support in Scalar Replacement here is for Unboxed Objects, meaning it can all be removed. --- js/src/jit/ScalarReplacement.cpp | 112 --------------------------------------- 1 file changed, 112 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 4614b2162..2065c0371 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -13,7 +13,6 @@ #include "jit/MIR.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" -#include "vm/UnboxedObject.h" #include "jsobjinlines.h" @@ -183,25 +182,6 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault) JitSpewDef(JitSpew_Escape, "is escaped by\n", def); return true; - case MDefinition::Op_LoadUnboxedScalar: - case MDefinition::Op_StoreUnboxedScalar: - case MDefinition::Op_LoadUnboxedObjectOrNull: - case MDefinition::Op_StoreUnboxedObjectOrNull: - case MDefinition::Op_LoadUnboxedString: - case MDefinition::Op_StoreUnboxedString: - // Not escaped if it is the first argument. - if (def->indexOf(*i) != 0) { - JitSpewDef(JitSpew_Escape, "is escaped by\n", def); - return true; - } - - if (!def->getOperand(1)->isConstant()) { - JitSpewDef(JitSpew_Escape, "is addressed with unknown index\n", def); - return true; - } - - break; - case MDefinition::Op_PostWriteBarrier: break; @@ -305,12 +285,6 @@ class ObjectMemoryView : public MDefinitionVisitorDefaultNoop void visitGuardShape(MGuardShape* ins); void visitFunctionEnvironment(MFunctionEnvironment* ins); void visitLambda(MLambda* ins); - void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins); - void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins); - void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins); - void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins); - void visitStoreUnboxedString(MStoreUnboxedString* ins); - void visitLoadUnboxedString(MLoadUnboxedString* ins); private: void storeOffset(MInstruction* ins, size_t offset, MDefinition* value); @@ -656,21 +630,6 @@ ObjectMemoryView::visitLambda(MLambda* ins) ins->setIncompleteObject(); } -static size_t -GetOffsetOf(MDefinition* index, size_t width, int32_t baseOffset) -{ - int32_t idx = index->toConstant()->toInt32(); - MOZ_ASSERT(idx >= 0); - MOZ_ASSERT(baseOffset >= 0 && size_t(baseOffset) >= UnboxedPlainObject::offsetOfData()); - return idx * width + baseOffset - UnboxedPlainObject::offsetOfData(); -} - -static size_t -GetOffsetOf(MDefinition* index, Scalar::Type type, int32_t baseOffset) -{ - return GetOffsetOf(index, Scalar::byteSize(type), baseOffset); -} - void ObjectMemoryView::storeOffset(MInstruction* ins, size_t offset, MDefinition* value) { @@ -700,77 +659,6 @@ ObjectMemoryView::loadOffset(MInstruction* ins, size_t offset) ins->block()->discard(ins); } -void -ObjectMemoryView::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) -{ - // Skip stores made on other objects. - if (ins->elements() != obj_) - return; - - size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment()); - storeOffset(ins, offset, ins->value()); -} - -void -ObjectMemoryView::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) -{ - // Skip loads made on other objects. - if (ins->elements() != obj_) - return; - - // Replace load by the slot value. - size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment()); - loadOffset(ins, offset); -} - -void -ObjectMemoryView::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins) -{ - // Skip stores made on other objects. - if (ins->elements() != obj_) - return; - - // Clone the state and update the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - storeOffset(ins, offset, ins->value()); -} - -void -ObjectMemoryView::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) -{ - // Skip loads made on other objects. - if (ins->elements() != obj_) - return; - - // Replace load by the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - loadOffset(ins, offset); -} - -void -ObjectMemoryView::visitStoreUnboxedString(MStoreUnboxedString* ins) -{ - // Skip stores made on other objects. - if (ins->elements() != obj_) - return; - - // Clone the state and update the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - storeOffset(ins, offset, ins->value()); -} - -void -ObjectMemoryView::visitLoadUnboxedString(MLoadUnboxedString* ins) -{ - // Skip loads made on other objects. - if (ins->elements() != obj_) - return; - - // Replace load by the slot value. - size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment()); - loadOffset(ins, offset); -} - static bool IndexOf(MDefinition* ins, int32_t* res) { -- cgit v1.2.3 From 5fd4b87267ba8f3c667533b0336554a7cc008876 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 19:37:25 +0000 Subject: Remove unboxed objects from GC --- js/src/gc/Marking.cpp | 46 +--------------------------------- js/src/gc/Tracer.cpp | 69 ++------------------------------------------------- js/src/jsgc.cpp | 6 ----- 3 files changed, 3 insertions(+), 118 deletions(-) (limited to 'js/src') diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 3ea4c9d29..47d2314c1 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -18,6 +18,7 @@ #include "builtin/ModuleObject.h" #include "gc/GCInternals.h" #include "gc/Policy.h" +#include "gc/StoreBuffer-inl.h" #include "jit/IonCode.h" #include "js/SliceBudget.h" #include "vm/ArgumentsObject.h" @@ -28,7 +29,6 @@ #include "vm/Shape.h" #include "vm/Symbol.h" #include "vm/TypedArrayObject.h" -#include "vm/UnboxedObject.h" #include "wasm/WasmJS.h" #include "jscompartmentinlines.h" @@ -37,7 +37,6 @@ #include "gc/Nursery-inl.h" #include "vm/String-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; @@ -1395,14 +1394,6 @@ js::ObjectGroup::traceChildren(JSTracer* trc) if (maybePreliminaryObjects()) maybePreliminaryObjects()->trace(trc); - if (maybeUnboxedLayout()) - unboxedLayout().trace(trc); - - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) { - TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group"); - setOriginalUnboxedGroup(unboxedGroup); - } - if (JSObject* descr = maybeTypeDescr()) { TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr"); setTypeDescr(&descr->as()); @@ -1436,12 +1427,6 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group) if (group->maybePreliminaryObjects()) group->maybePreliminaryObjects()->trace(this); - if (group->maybeUnboxedLayout()) - group->unboxedLayout().trace(this); - - if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) - traverseEdge(group, unboxedGroup); - if (TypeDescr* descr = group->maybeTypeDescr()) traverseEdge(group, static_cast(descr)); @@ -1484,23 +1469,6 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar return nullptr; } - if (clasp == &UnboxedPlainObject::class_) { - JSObject** pexpando = obj->as().addressOfExpando(); - if (*pexpando) - f(pexpando, mozilla::Forward(args)...); - - UnboxedPlainObject& unboxed = obj->as(); - const UnboxedLayout& layout = check == CheckGeneration::DoChecks - ? unboxed.layout() - : unboxed.layoutDontCheckGeneration(); - if (layout.traceList()) { - VisitTraceList(f, layout.traceList(), unboxed.data(), - mozilla::Forward(args)...); - } - - return nullptr; - } - clasp->doTrace(trc, obj); if (!clasp->isNative()) @@ -2293,18 +2261,6 @@ static inline void TraceWholeCell(TenuringTracer& mover, JSObject* object) { mover.traceObject(object); - - // Additionally trace the expando object attached to any unboxed plain - // objects. Baseline and Ion can write properties to the expando while - // only adding a post barrier to the owning unboxed object. Note that - // it isn't possible for a nursery unboxed object to have a tenured - // expando, so that adding a post barrier on the original object will - // capture any tenured->nursery edges in the expando as well. - - if (object->is()) { - if (UnboxedExpandoObject* expando = object->as().maybeExpando()) - expando->traceChildren(&mover); - } } static inline void diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index 63cd9b08a..3416464dd 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -201,80 +201,15 @@ gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape) } while (shape); } -// Object groups can point to other object groups via an UnboxedLayout or the -// the original unboxed group link. There can potentially be deep or cyclic -// chains of such groups to trace through without going through a thing that -// participates in cycle collection. These need to be handled iteratively to -// avoid blowing the stack when running the cycle collector's callback tracer. -struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer -{ - explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer) - : JS::CallbackTracer(innerTracer->runtime(), DoNotTraceWeakMaps), - innerTracer(innerTracer) - {} - - void onChild(const JS::GCCellPtr& thing) override; - - JS::CallbackTracer* innerTracer; - Vector seen, worklist; -}; - -void -ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing) -{ - if (thing.is()) { - // The CC does not care about BaseShapes, and no additional GC things - // will be reached by following this edge. - return; - } - - if (thing.is() || thing.is()) { - // Invoke the inner cycle collector callback on this child. It will not - // recurse back into TraceChildren. - innerTracer->onChild(thing); - return; - } - - if (thing.is()) { - // If this group is required to be in an ObjectGroup chain, trace it - // via the provided worklist rather than continuing to recurse. - ObjectGroup& group = thing.as(); - if (group.maybeUnboxedLayout()) { - for (size_t i = 0; i < seen.length(); i++) { - if (seen[i] == &group) - return; - } - if (seen.append(&group) && worklist.append(&group)) { - return; - } else { - // If append fails, keep tracing normally. The worst that will - // happen is we end up overrecursing. - } - } - } - - TraceChildren(this, thing.asCell(), thing.kind()); -} - void gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group) { MOZ_ASSERT(trc->isCallbackTracer()); - // Early return if this group is not required to be in an ObjectGroup chain. - if (!group->maybeUnboxedLayout()) - return group->traceChildren(trc); - - ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer()); - group->traceChildren(&groupTracer); - - while (!groupTracer.worklist.empty()) { - ObjectGroup* innerGroup = groupTracer.worklist.popCopy(); - innerGroup->traceChildren(&groupTracer); - } + group->traceChildren(trc); } - + /*** Traced Edge Printer *************************************************************************/ static size_t diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 194468c5d..b2ee8d67b 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6190,12 +6190,6 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) for (auto group = source->zone()->cellIter(); !group.done(); group.next()) { group->setGeneration(target->zone()->types.generation); group->compartment_ = target; - - // Remove any unboxed layouts from the list in the off thread - // compartment. These do not need to be reinserted in the target - // compartment's list, as the list is not required to be complete. - if (UnboxedLayout* layout = group->maybeUnboxedLayoutDontCheckGeneration()) - layout->detachFromCompartment(); } // Fixup zone pointers in source's zone to refer to target's zone. -- cgit v1.2.3 From 8feffe7079e516a63a6cc5fd9b2c759c7431cf33 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 15 May 2019 20:56:36 +0000 Subject: Remove unboxed object code from iteration. --- js/src/jsiter.cpp | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) (limited to 'js/src') diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index c1ae5dc15..004c7fc0d 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -157,8 +157,11 @@ SortComparatorIntegerIds(jsid a, jsid b, bool* lessOrEqualp) } static bool -EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags, Maybe& ht, - AutoIdVector* props, Handle unboxed = nullptr) +EnumerateNativeProperties(JSContext* cx, + HandleNativeObject pobj, + unsigned flags, + Maybe& ht, + AutoIdVector* props) { bool enumerateSymbols; if (flags & JSITER_SYMBOLSONLY) { @@ -220,16 +223,6 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags return false; } - if (unboxed) { - // If |unboxed| is set then |pobj| is the expando for an unboxed - // plain object we are enumerating. Add the unboxed properties - // themselves here since they are all property names that were - // given to the object before any of the expando's properties. - MOZ_ASSERT(pobj->is()); - if (!EnumerateExtraProperties(cx, unboxed, flags, ht, props)) - return false; - } - size_t initialLength = props->length(); /* Collect all unique property names from this object's shape. */ @@ -355,22 +348,12 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props) do { if (pobj->getOpsEnumerate()) { - if (pobj->is() && pobj->as().maybeExpando()) { - // Special case unboxed objects with an expando object. - RootedNativeObject expando(cx, pobj->as().maybeExpando()); - if (!EnumerateNativeProperties(cx, expando, flags, ht, props, - pobj.as())) - { - return false; - } - } else { - if (!EnumerateExtraProperties(cx, pobj, flags, ht, props)) - return false; + if (!EnumerateExtraProperties(cx, pobj, flags, ht, props)) + return false; - if (pobj->isNative()) { - if (!EnumerateNativeProperties(cx, pobj.as(), flags, ht, props)) - return false; - } + if (pobj->isNative()) { + if (!EnumerateNativeProperties(cx, pobj.as(), flags, ht, props)) + return false; } } else if (pobj->isNative()) { // Give the object a chance to resolve all lazy properties @@ -785,11 +768,6 @@ CanCompareIterableObjectToCache(JSObject* obj) { if (obj->isNative()) return obj->as().hasEmptyElements(); - if (obj->is()) { - if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) - return expando->hasEmptyElements(); - return true; - } return false; } -- cgit v1.2.3 From a5c2961c4e8c0459959fc35e493e58be8e7763d6 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 00:50:49 +0000 Subject: Remove array header --- js/src/jsarray.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7a67c0095..1c05704b8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -45,7 +45,6 @@ #include "vm/Caches-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; -- cgit v1.2.3 From 543fa1674bcb4f8c40f0ef6e4c5514ea161def5a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 13:13:36 +0000 Subject: Remove Unboxed Objects from vm/ Part 1 + fix deprot --- js/src/jit/OptimizationTracking.cpp | 2 ++ js/src/jit/SharedIC.cpp | 1 + js/src/jsarray.cpp | 1 + js/src/jsobj.cpp | 1 + js/src/vm/Interpreter-inl.h | 13 ++++--------- js/src/vm/Interpreter.cpp | 7 +------ 6 files changed, 10 insertions(+), 15 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 308def041..b42634d43 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -15,9 +15,11 @@ #include "jit/JitcodeMap.h" #include "jit/JitSpewer.h" #include "js/TrackedOptimizationInfo.h" +#include "vm/UnboxedObject.h" #include "vm/ObjectGroup-inl.h" #include "vm/TypeInference-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 767cff661..2475dfb22 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -27,6 +27,7 @@ #endif #include "jit/VMFunctions.h" #include "vm/Interpreter.h" +#include "vm/NativeObject-inl.h" #include "jit/MacroAssembler-inl.h" #include "vm/Interpreter-inl.h" diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 1c05704b8..7a67c0095 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -45,6 +45,7 @@ #include "vm/Caches-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index b17c845bb..7852b3365 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -54,6 +54,7 @@ #include "vm/RegExpStaticsObject.h" #include "vm/Shape.h" #include "vm/TypedArrayCommon.h" +#include "vm/UnboxedObject-inl.h" #include "jsatominlines.h" #include "jsboolinlines.h" diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 5f476c4ff..710f1d89b 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -22,7 +22,6 @@ #include "vm/EnvironmentObject-inl.h" #include "vm/Stack-inl.h" #include "vm/String-inl.h" -#include "vm/UnboxedObject-inl.h" namespace js { @@ -337,14 +336,10 @@ InitGlobalLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvAr inline bool InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs) { - if (obj->is() || obj->is()) { - unsigned propAttrs = GetInitDataPropAttrs(op); - return NativeDefineProperty(cx, obj.as(), id, rhs, nullptr, nullptr, - propAttrs); - } - - MOZ_ASSERT(obj->as().layout().lookup(id)); - return PutProperty(cx, obj, id, rhs, false); + MOZ_ASSERT(obj->is() || obj->is()); + unsigned propAttrs = GetInitDataPropAttrs(op); + return NativeDefineProperty(cx, obj.as(), id, rhs, + nullptr, nullptr, propAttrs); } inline bool diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index e6d6630c4..3cf2deb83 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4111,7 +4111,7 @@ CASE(JSOP_INITHOMEOBJECT) /* Load the home object */ ReservedRooted obj(&rootObject0); obj = ®S.sp[int(-2 - skipOver)].toObject(); - MOZ_ASSERT(obj->is() || obj->is() || obj->is()); + MOZ_ASSERT(obj->is() || obj->is()); func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, ObjectValue(*obj)); } @@ -4927,15 +4927,10 @@ js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc, return nullptr; if (group->maybePreliminaryObjects()) { group->maybePreliminaryObjects()->maybeAnalyze(cx, group); - if (group->maybeUnboxedLayout()) - group->maybeUnboxedLayout()->setAllocationSite(script, pc); } if (group->shouldPreTenure() || group->maybePreliminaryObjects()) newKind = TenuredObject; - - if (group->maybeUnboxedLayout()) - return UnboxedPlainObject::create(cx, group, newKind); } RootedObject obj(cx); -- cgit v1.2.3 From fa8bfa1a00ca88dd0ff5f8dcfb89dee5fd01c639 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 19:54:19 +0000 Subject: Remove unboxed object code from jit, Part 1 --- js/src/jit/AliasAnalysisShared.cpp | 2 - js/src/jit/CodeGenerator.cpp | 61 ------------ js/src/jit/CodeGenerator.h | 3 - js/src/jit/IonAnalysis.cpp | 2 - js/src/jit/IonBuilder.cpp | 192 +----------------------------------- js/src/jit/IonBuilder.h | 6 -- js/src/jit/Lowering.cpp | 26 ----- js/src/jit/Lowering.h | 3 - js/src/jit/MIR.cpp | 161 +++++------------------------- js/src/jit/MIR.h | 131 ------------------------ js/src/jit/MOpcodes.h | 3 - js/src/jit/shared/LIR-shared.h | 48 --------- js/src/jit/shared/LOpcodes-shared.h | 3 - js/src/vm/TypeInference.cpp | 11 --- js/src/vm/TypeInference.h | 1 - 15 files changed, 26 insertions(+), 627 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index 81c0fd067..3b83df74e 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -114,8 +114,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_GuardObjectGroup: case MDefinition::Op_GuardObjectIdentity: case MDefinition::Op_GuardClass: - case MDefinition::Op_GuardUnboxedExpando: - case MDefinition::Op_LoadUnboxedExpando: case MDefinition::Op_LoadSlot: case MDefinition::Op_StoreSlot: case MDefinition::Op_InArray: diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 16d026092..6d1fb6b9b 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3031,15 +3031,6 @@ GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard, { if (guard.group) { masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss); - - Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando()); - if (guard.shape) { - masm.loadPtr(expandoAddress, scratch); - masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss); - masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss); - } else if (checkNullExpando) { - masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss); - } } else { masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss); } @@ -3077,13 +3068,6 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch); masm.loadTypedOrValue(Address(scratch, offset), output); } - } else { - masm.comment("loadUnboxedProperty"); - const UnboxedLayout::Property* property = - receiver.group->unboxedLayout().lookup(mir->name()); - Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset); - - masm.loadUnboxedProperty(propertyAddr, property->type, output); } if (i == mir->numReceivers() - 1) { @@ -3124,8 +3108,6 @@ EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type) masm.patchableCallPreBarrier(address, MIRType::Object); else if (type == JSVAL_TYPE_STRING) masm.patchableCallPreBarrier(address, MIRType::String); - else - MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type)); } void @@ -3161,13 +3143,6 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis emitPreBarrier(addr); masm.storeConstantOrRegister(value, addr); } - } else { - const UnboxedLayout::Property* property = - receiver.group->unboxedLayout().lookup(mir->name()); - Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset); - - EmitUnboxedPreBarrier(masm, propertyAddr, property->type); - masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr); } if (i == mir->numReceivers() - 1) { @@ -3332,27 +3307,6 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir) masm.bind(&done); } -void -CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir) -{ - Label miss; - - Register obj = ToRegister(lir->object()); - masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual, - Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss); - - bailoutFrom(&miss, lir->snapshot()); -} - -void -CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir) -{ - Register obj = ToRegister(lir->object()); - Register result = ToRegister(lir->getDef(0)); - - masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result); -} - void CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) { @@ -8576,21 +8530,6 @@ static const VMFunction ConvertUnboxedArrayObjectToNativeInfo = FunctionInfo(UnboxedArrayObject::convertToNative, "UnboxedArrayObject::convertToNative"); -void -CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir) -{ - Register object = ToRegister(lir->getOperand(0)); - - OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray() - ? ConvertUnboxedArrayObjectToNativeInfo - : ConvertUnboxedPlainObjectToNativeInfo, - lir, ArgList(object), StoreNothing()); - - masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()), - ImmGCPtr(lir->mir()->group()), ool->entry()); - masm.bind(ool->rejoin()); -} - typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue); static const VMFunction ArrayPopDenseInfo = FunctionInfo(jit::ArrayPopDense, "ArrayPopDense"); diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index b226f6cc9..292f163b5 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -148,8 +148,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir); void visitGuardObjectIdentity(LGuardObjectIdentity* guard); void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir); - void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir); - void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir); void visitTypeBarrierV(LTypeBarrierV* lir); void visitTypeBarrierO(LTypeBarrierO* lir); void visitMonitorTypes(LMonitorTypes* lir); @@ -310,7 +308,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitFallibleStoreElementV(LFallibleStoreElementV* lir); void visitFallibleStoreElementT(LFallibleStoreElementT* lir); void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir); - void visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir); void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj, Register elementsTemp, Register lengthTemp, TypedOrValueRegister out); void visitArrayPopShiftV(LArrayPopShiftV* lir); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index d255c32a8..41c71c9c3 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -3515,8 +3515,6 @@ PassthroughOperand(MDefinition* def) return def->toConvertElementsToDoubles()->elements(); if (def->isMaybeCopyElementsForWrite()) return def->toMaybeCopyElementsForWrite()->object(); - if (def->isConvertUnboxedObjectToNative()) - return def->toConvertUnboxedObjectToNative()->object(); return nullptr; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 28fa53aa8..af85011be 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -32,7 +32,6 @@ #include "vm/EnvironmentObject-inl.h" #include "vm/NativeObject-inl.h" #include "vm/ObjectGroup-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; @@ -6392,7 +6391,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction* target, MDefinition* callee) JSObject* templateObject = inspector->getTemplateObject(pc); if (!templateObject) return nullptr; - if (!templateObject->is() && !templateObject->is()) + if (!templateObject->is()) return nullptr; if (templateObject->staticPrototype() != proto) return nullptr; @@ -6429,7 +6428,7 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee) JSObject* templateObject = inspector->getTemplateObject(pc); if (!templateObject) return nullptr; - if (!templateObject->is() && !templateObject->is()) + if (!templateObject->is()) return nullptr; Shape* shape = target->lookupPure(compartment->runtime()->names().prototype); @@ -7718,8 +7717,6 @@ IonBuilder::jsop_initprop(PropertyName* name) if (templateObject->is()) { if (!templateObject->as().containsPure(name)) useSlowPath = true; - } else { - MOZ_ASSERT(templateObject->as().layout().lookup(name)); } } else { useSlowPath = true; @@ -8178,8 +8175,7 @@ IonBuilder::maybeMarkEmpty(MDefinition* ins) static bool ClassHasEffectlessLookup(const Class* clasp) { - return (clasp == &UnboxedPlainObject::class_) || - (clasp == &UnboxedArrayObject::class_) || + return (clasp == &UnboxedArrayObject::class_) || IsTypedObjectClass(clasp) || (clasp->isNative() && !clasp->getOpsLookupProperty()); } @@ -10970,11 +10966,8 @@ IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_ } // Definite slots will always be fixed slots when they are in the - // allowable range for fixed slots, except for objects which were - // converted from unboxed objects and have a smaller allocation size. + // allowable range for fixed slots. size_t nfixed = NativeObject::MAX_FIXED_SLOTS; - if (ObjectGroup* group = key->group()->maybeOriginalUnboxedGroup()) - nfixed = gc::GetGCKindSlots(group->unboxedLayout().getAllocKind()); uint32_t propertySlot = property.maybeTypes()->definiteSlot(); if (slot == UINT32_MAX) { @@ -11031,8 +11024,6 @@ IonBuilder::getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, JSValu return UINT32_MAX; } - key->watchStateChangeForUnboxedConvertedToNative(constraints()); - if (offset == UINT32_MAX) { offset = property->offset; *punboxedType = property->type; @@ -11565,11 +11556,6 @@ IonBuilder::jsop_getprop(PropertyName* name) if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted) return emitted; - // Try to emit loads from unboxed objects. - trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed); - if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted) - return emitted; - // Try to inline a common property getter, or make a call. trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter); if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted) @@ -12085,34 +12071,6 @@ IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset, return load; } -bool -IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name, - BarrierKind barrier, TemporaryTypeSet* types) -{ - MOZ_ASSERT(*emitted == false); - - JSValueType unboxedType; - uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType); - if (offset == UINT32_MAX) - return true; - - if (obj->type() != MIRType::Object) { - MGuardObject* guard = MGuardObject::New(alloc(), obj); - current->add(guard); - obj = guard; - } - - MInstruction* load = loadUnboxedProperty(obj, offset, unboxedType, barrier, types); - current->push(load); - - if (!pushTypeBarrier(load, types, barrier)) - return false; - - trackOptimizationSuccess(); - *emitted = true; - return true; -} - MDefinition* IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, const BaselineInspector::ReceiverVector& receivers, @@ -12356,45 +12314,6 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName return true; } - if (receivers[0].shape) { - // Monomorphic load from an unboxed object expando. - spew("Inlining monomorphic unboxed expando GETPROP"); - - obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard); - obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard); - - MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj); - current->add(expando); - - expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard); - - Shape* shape = receivers[0].shape->searchLinear(NameToId(name)); - MOZ_ASSERT(shape); - - if (!loadSlot(expando, shape, rvalType, barrier, types)) - return false; - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; - return true; - } - - // Monomorphic load from an unboxed object. - ObjectGroup* group = receivers[0].group; - if (obj->resultTypeSet() && !obj->resultTypeSet()->hasType(TypeSet::ObjectType(group))) - return true; - - obj = addGroupGuard(obj, group, Bailout_ShapeGuard); - - const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name); - MInstruction* load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types); - current->push(load); - - if (!pushTypeBarrier(load, types, barrier)) - return false; - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; return true; } @@ -12669,13 +12588,6 @@ IonBuilder::jsop_setprop(PropertyName* name) bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value, /* canModify = */ true); - if (!forceInlineCaches()) { - // Try to emit stores to unboxed objects. - trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed); - if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted) - return emitted; - } - // Add post barrier if needed. The instructions above manage any post // barriers they need directly. if (NeedsPostBarrier(value)) @@ -13040,40 +12952,6 @@ IonBuilder::storeUnboxedValue(MDefinition* obj, MDefinition* elements, int32_t e return store; } -bool -IonBuilder::setPropTryUnboxed(bool* emitted, MDefinition* obj, - PropertyName* name, MDefinition* value, - bool barrier, TemporaryTypeSet* objTypes) -{ - MOZ_ASSERT(*emitted == false); - - if (barrier) { - trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier); - return true; - } - - JSValueType unboxedType; - uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType); - if (offset == UINT32_MAX) - return true; - - if (obj->type() != MIRType::Object) { - MGuardObject* guard = MGuardObject::New(alloc(), obj); - current->add(guard); - obj = guard; - } - - MInstruction* store = storeUnboxedProperty(obj, offset, unboxedType, value); - - current->push(value); - - if (!resumeAfter(store)) - return false; - - *emitted = true; - return true; -} - bool IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, @@ -13112,46 +12990,6 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, return true; } - if (receivers[0].shape) { - // Monomorphic store to an unboxed object expando. - spew("Inlining monomorphic unboxed expando SETPROP"); - - obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard); - obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard); - - MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj); - current->add(expando); - - expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard); - - Shape* shape = receivers[0].shape->searchLinear(NameToId(name)); - MOZ_ASSERT(shape); - - bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); - if (!storeSlot(expando, shape, value, needsBarrier)) - return false; - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; - return true; - } - - // Monomorphic store to an unboxed object. - spew("Inlining monomorphic unboxed SETPROP"); - - ObjectGroup* group = receivers[0].group; - if (!objTypes->hasType(TypeSet::ObjectType(group))) - return true; - - obj = addGroupGuard(obj, group, Bailout_ShapeGuard); - - const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name); - storeUnboxedProperty(obj, property->offset, property->type, value); - - current->push(value); - - trackOptimizationOutcome(TrackedOutcome::Monomorphic); - *emitted = true; return true; } @@ -14178,19 +14016,6 @@ IonBuilder::addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bail return guard; } -MInstruction* -IonBuilder::addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind) -{ - MGuardUnboxedExpando* guard = MGuardUnboxedExpando::New(alloc(), obj, hasExpando, bailoutKind); - current->add(guard); - - // If a shape guard failed in the past, don't optimize group guards. - if (failedShapeGuard_) - guard->setNotMovable(); - - return guard; -} - MInstruction* IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers) @@ -14200,15 +14025,6 @@ IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj, // Monomorphic guard on a native object. return addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard); } - - if (!receivers[0].shape) { - // Guard on an unboxed object that does not have an expando. - obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard); - return addUnboxedExpandoGuard(obj, /* hasExpando = */ false, Bailout_ShapeGuard); - } - - // Monomorphic receiver guards are not yet supported when the receiver - // is an unboxed object with an expando. } MGuardReceiverPolymorphic* guard = MGuardReceiverPolymorphic::New(alloc(), obj); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 2880c7ea1..77528ad37 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -401,7 +401,6 @@ class IonBuilder MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind); MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind); - MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind); MInstruction* addSharedTypedArrayGuard(MDefinition* obj); MInstruction* @@ -441,8 +440,6 @@ class IonBuilder BarrierKind barrier, TemporaryTypeSet* types); MOZ_MUST_USE bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name, BarrierKind barrier, TemporaryTypeSet* types); - MOZ_MUST_USE bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name, - BarrierKind barrier, TemporaryTypeSet* types); MOZ_MUST_USE bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name, TemporaryTypeSet* types); MOZ_MUST_USE bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, @@ -475,9 +472,6 @@ class IonBuilder MOZ_MUST_USE bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, bool barrier, TemporaryTypeSet* objTypes); - MOZ_MUST_USE bool setPropTryUnboxed(bool* emitted, MDefinition* obj, - PropertyName* name, MDefinition* value, - bool barrier, TemporaryTypeSet* objTypes); MOZ_MUST_USE bool setPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, bool barrier, TemporaryTypeSet* objTypes); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 709de9987..aafa57c09 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3251,14 +3251,6 @@ LIRGenerator::visitStoreUnboxedString(MStoreUnboxedString* ins) add(lir, ins); } -void -LIRGenerator::visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins) -{ - LInstruction* check = new(alloc()) LConvertUnboxedObjectToNative(useRegister(ins->object())); - add(check, ins); - assignSafepoint(check, ins); -} - void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) { @@ -3776,24 +3768,6 @@ LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins) redefine(ins, ins->object()); } -void -LIRGenerator::visitGuardUnboxedExpando(MGuardUnboxedExpando* ins) -{ - LGuardUnboxedExpando* guard = - new(alloc()) LGuardUnboxedExpando(useRegister(ins->object())); - assignSnapshot(guard, ins->bailoutKind()); - add(guard, ins); - redefine(ins, ins->object()); -} - -void -LIRGenerator::visitLoadUnboxedExpando(MLoadUnboxedExpando* ins) -{ - LLoadUnboxedExpando* lir = - new(alloc()) LLoadUnboxedExpando(useRegisterAtStart(ins->object())); - define(lir, ins); -} - void LIRGenerator::visitAssertRange(MAssertRange* ins) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 9b4095aec..e36620bce 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -232,7 +232,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitFallibleStoreElement(MFallibleStoreElement* ins); void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins); void visitStoreUnboxedString(MStoreUnboxedString* ins); - void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins); void visitEffectiveAddress(MEffectiveAddress* ins); void visitArrayPopShift(MArrayPopShift* ins); void visitArrayPush(MArrayPush* ins); @@ -256,8 +255,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitGuardObject(MGuardObject* ins); void visitGuardString(MGuardString* ins); void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins); - void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins); - void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins); void visitPolyInlineGuard(MPolyInlineGuard* ins); void visitAssertRange(MAssertRange* ins); void visitCallGetProperty(MCallGetProperty* ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 287b87582..1f33b2174 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -4810,35 +4810,8 @@ MBeta::printOpcode(GenericPrinter& out) const bool MCreateThisWithTemplate::canRecoverOnBailout() const { - MOZ_ASSERT(templateObject()->is() || templateObject()->is()); - MOZ_ASSERT_IF(templateObject()->is(), - !templateObject()->as().denseElementsAreCopyOnWrite()); - return true; -} - -bool -OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject) -{ - const UnboxedLayout& layout = - templateObject->as().layoutDontCheckGeneration(); - - const UnboxedLayout::PropertyVector& properties = layout.properties(); - MOZ_ASSERT(properties.length() < 255); - - // Allocate an array of indexes, where the top of each field correspond to - // the index of the operand in the MObjectState instance. - if (!map.init(alloc, layout.size())) - return false; - - // Reset all indexes to 0, which is an error code. - for (size_t i = 0; i < map.length(); i++) - map[i] = 0; - - // Map the property offsets to the indexes of MObjectState operands. - uint8_t index = 1; - for (size_t i = 0; i < properties.length(); i++, index++) - map[properties[i].offset] = index; - + MOZ_ASSERT(templateObject()->is()); + MOZ_ASSERT(!templateObject()->as().denseElementsAreCopyOnWrite()); return true; } @@ -4858,17 +4831,11 @@ MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandInd setResultType(MIRType::Object); setRecoveredOnBailout(); - if (templateObject->is()) { - NativeObject* nativeObject = &templateObject->as(); - numSlots_ = nativeObject->slotSpan(); - numFixedSlots_ = nativeObject->numFixedSlots(); - } else { - const UnboxedLayout& layout = - templateObject->as().layoutDontCheckGeneration(); - // Same as UnboxedLayout::makeNativeGroup - numSlots_ = layout.properties().length(); - numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind()); - } + MOZ_ASSERT(templateObject->is()); + + NativeObject* nativeObject = &templateObject->as(); + numSlots_ = nativeObject->slotSpan(); + numFixedSlots_ = nativeObject->numFixedSlots(); operandIndex_ = operandIndex; } @@ -4905,39 +4872,21 @@ MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefine // the template object. This is needed to account values which are baked in // the template objects and not visible in IonMonkey, such as the // uninitialized-lexical magic value of call objects. - if (templateObject->is()) { - UnboxedPlainObject& unboxedObject = templateObject->as(); - const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration(); - const UnboxedLayout::PropertyVector& properties = layout.properties(); - - for (size_t i = 0; i < properties.length(); i++) { - Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true); - MDefinition *def = undefinedVal; - if (!val.isUndefined()) { - MConstant* ins = val.isObject() ? - MConstant::NewConstraintlessObject(alloc, &val.toObject()) : - MConstant::New(alloc, val); - block()->insertBefore(this, ins); - def = ins; - } - initSlot(i, def); - } - } else { - NativeObject& nativeObject = templateObject->as(); - MOZ_ASSERT(nativeObject.slotSpan() == numSlots()); - - for (size_t i = 0; i < numSlots(); i++) { - Value val = nativeObject.getSlot(i); - MDefinition *def = undefinedVal; - if (!val.isUndefined()) { - MConstant* ins = val.isObject() ? - MConstant::NewConstraintlessObject(alloc, &val.toObject()) : - MConstant::New(alloc, val); - block()->insertBefore(this, ins); - def = ins; - } - initSlot(i, def); + NativeObject& nativeObject = templateObject->as(); + MOZ_ASSERT(nativeObject.slotSpan() == numSlots()); + + MOZ_ASSERT(templateObject->is()); + for (size_t i = 0; i < numSlots(); i++) { + Value val = nativeObject.getSlot(i); + MDefinition *def = undefinedVal; + if (!val.isUndefined()) { + MConstant* ins = val.isObject() ? + MConstant::NewConstraintlessObject(alloc, &val.toObject()) : + MConstant::New(alloc, val); + block()->insertBefore(this, ins); + def = ins; } + initSlot(i, def); } return true; } @@ -4948,14 +4897,7 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj) JSObject* templateObject = templateObjectOf(obj); MOZ_ASSERT(templateObject, "Unexpected object creation."); - OperandIndexMap* operandIndex = nullptr; - if (templateObject->is()) { - operandIndex = new(alloc) OperandIndexMap; - if (!operandIndex || !operandIndex->init(alloc, templateObject)) - return nullptr; - } - - MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex); + MObjectState* res = new(alloc) MObjectState(templateObject, nullptr); if (!res || !res->init(alloc, obj)) return nullptr; return res; @@ -5862,35 +5804,6 @@ MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) return MConstant::New(alloc, Int32Value(index)); } -MConvertUnboxedObjectToNative* -MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group) -{ - MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group); - - ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup(); - - // Make a new type set for the result of this instruction which replaces - // the input group with the native group we will convert it to. - TemporaryTypeSet* types = obj->resultTypeSet(); - if (types && !types->unknownObject()) { - TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc()); - if (newTypes) { - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) - continue; - if (key->unknownProperties() || !key->isGroup() || key->group() != group) - newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc()); - else - newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc()); - } - res->setResultTypeSet(newTypes); - } - } - - return res; -} - bool jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id) @@ -5945,8 +5858,6 @@ jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* o elementType = layout.elementType(); else return JSVAL_TYPE_MAGIC; - - key->watchStateChangeForUnboxedConvertedToNative(constraints); } return elementType; @@ -6579,23 +6490,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* } } - // Perform additional filtering to make sure that any unboxed property - // being written can accommodate the value. - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (key && key->isGroup() && key->group()->maybeUnboxedLayout()) { - const UnboxedLayout& layout = key->group()->unboxedLayout(); - if (name) { - const UnboxedLayout::Property* property = layout.lookup(name); - if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue)) - return true; - } else { - if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue)) - return true; - } - } - } - if (success) return false; @@ -6626,17 +6520,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* MOZ_ASSERT(excluded); - // If the excluded object is a group with an unboxed layout, make sure it - // does not have a corresponding native group. Objects with the native - // group might appear even though they are not in the type set. - if (excluded->isGroup()) { - if (UnboxedLayout* layout = excluded->group()->maybeUnboxedLayout()) { - if (layout->nativeGroup()) - return true; - excluded->watchStateChangeForUnboxedConvertedToNative(constraints); - } - } - *pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true); return false; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index fb0f22fc3..3e0421789 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -30,7 +30,6 @@ #include "vm/EnvironmentObject.h" #include "vm/SharedMem.h" #include "vm/TypedArrayCommon.h" -#include "vm/UnboxedObject.h" // Undo windows.h damage on Win64 #undef MemoryBarrier @@ -9742,59 +9741,6 @@ class MStoreUnboxedString ALLOW_CLONE(MStoreUnboxedString) }; -// Passes through an object, after ensuring it is converted from an unboxed -// object to a native representation. -class MConvertUnboxedObjectToNative - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - CompilerObjectGroup group_; - - explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group) - : MUnaryInstruction(obj), - group_(group) - { - setGuard(); - setMovable(); - setResultType(MIRType::Object); - } - - public: - INSTRUCTION_HEADER(ConvertUnboxedObjectToNative) - NAMED_OPERANDS((0, object)) - - static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj, - ObjectGroup* group); - - ObjectGroup* group() const { - return group_; - } - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - return ins->toConvertUnboxedObjectToNative()->group() == group(); - } - AliasSet getAliasSet() const override { - // This instruction can read and write to all parts of the object, but - // is marked as non-effectful so it can be consolidated by LICM and GVN - // and avoid inhibiting other optimizations. - // - // This is valid to do because when unboxed objects might have a native - // group they can be converted to, we do not optimize accesses to the - // unboxed objects and do not guard on their group or shape (other than - // in this opcode). - // - // Later accesses can assume the object has a native representation - // and optimize accordingly. Those accesses cannot be reordered before - // this instruction, however. This is prevented by chaining this - // instruction with the object itself, in the same way as MBoundsCheck. - return AliasSet::None(); - } - bool appendRoots(MRootList& roots) const override { - return roots.append(group_); - } -}; - // Array.prototype.pop or Array.prototype.shift on a dense array. class MArrayPopShift : public MUnaryInstruction, @@ -11174,11 +11120,6 @@ class MGuardShape setMovable(); setResultType(MIRType::Object); setResultTypeSet(obj->resultTypeSet()); - - // Disallow guarding on unboxed object shapes. The group is better to - // guard on, and guarding on the shape can interact badly with - // MConvertUnboxedObjectToNative. - MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_); } public: @@ -11273,11 +11214,6 @@ class MGuardObjectGroup setGuard(); setMovable(); setResultType(MIRType::Object); - - // Unboxed groups which might be converted to natives can't be guarded - // on, due to MConvertUnboxedObjectToNative. - MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(), - !group->unboxedLayoutDontCheckGeneration().nativeGroup()); } public: @@ -11386,73 +11322,6 @@ class MGuardClass ALLOW_CLONE(MGuardClass) }; -// Guard on the presence or absence of an unboxed object's expando. -class MGuardUnboxedExpando - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - bool requireExpando_; - BailoutKind bailoutKind_; - - MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind) - : MUnaryInstruction(obj), - requireExpando_(requireExpando), - bailoutKind_(bailoutKind) - { - setGuard(); - setMovable(); - setResultType(MIRType::Object); - } - - public: - INSTRUCTION_HEADER(GuardUnboxedExpando) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool requireExpando() const { - return requireExpando_; - } - BailoutKind bailoutKind() const { - return bailoutKind_; - } - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando()) - return false; - return true; - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } -}; - -// Load an unboxed plain object's expando. -class MLoadUnboxedExpando - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - private: - explicit MLoadUnboxedExpando(MDefinition* object) - : MUnaryInstruction(object) - { - setResultType(MIRType::Object); - setMovable(); - } - - public: - INSTRUCTION_HEADER(LoadUnboxedExpando) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } -}; - // Load from vp[slot] (slots that are not inline in an object). class MLoadSlot : public MUnaryInstruction, diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index fddc1e637..b80d1baf9 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -187,8 +187,6 @@ namespace jit { _(GuardObjectGroup) \ _(GuardObjectIdentity) \ _(GuardClass) \ - _(GuardUnboxedExpando) \ - _(LoadUnboxedExpando) \ _(ArrayLength) \ _(SetArrayLength) \ _(GetNextEntryForIterator) \ @@ -219,7 +217,6 @@ namespace jit { _(StoreUnboxedScalar) \ _(StoreUnboxedObjectOrNull) \ _(StoreUnboxedString) \ - _(ConvertUnboxedObjectToNative) \ _(ArrayPopShift) \ _(ArrayPush) \ _(ArraySlice) \ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index f4adcc63c..f386d5256 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5891,22 +5891,6 @@ class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0> } }; -// If necessary, convert an unboxed object in a particular group to its native -// representation. -class LConvertUnboxedObjectToNative : public LInstructionHelper<0, 1, 0> -{ - public: - LIR_HEADER(ConvertUnboxedObjectToNative) - - explicit LConvertUnboxedObjectToNative(const LAllocation& object) { - setOperand(0, object); - } - - MConvertUnboxedObjectToNative* mir() { - return mir_->toConvertUnboxedObjectToNative(); - } -}; - class LArrayPopShiftV : public LInstructionHelper { public: @@ -7429,38 +7413,6 @@ class LGuardReceiverPolymorphic : public LInstructionHelper<0, 1, 1> } }; -class LGuardUnboxedExpando : public LInstructionHelper<0, 1, 0> -{ - public: - LIR_HEADER(GuardUnboxedExpando) - - explicit LGuardUnboxedExpando(const LAllocation& in) { - setOperand(0, in); - } - const LAllocation* object() { - return getOperand(0); - } - const MGuardUnboxedExpando* mir() const { - return mir_->toGuardUnboxedExpando(); - } -}; - -class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(LoadUnboxedExpando) - - explicit LLoadUnboxedExpando(const LAllocation& in) { - setOperand(0, in); - } - const LAllocation* object() { - return getOperand(0); - } - const MLoadUnboxedExpando* mir() const { - return mir_->toLoadUnboxedExpando(); - } -}; - // Guard that a value is in a TypeSet. class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1> { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index fe2ab5ea3..6912e8904 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -258,8 +258,6 @@ _(GuardObjectGroup) \ _(GuardObjectIdentity) \ _(GuardClass) \ - _(GuardUnboxedExpando) \ - _(LoadUnboxedExpando) \ _(TypeBarrierV) \ _(TypeBarrierO) \ _(MonitorTypes) \ @@ -287,7 +285,6 @@ _(StoreElementT) \ _(StoreUnboxedScalar) \ _(StoreUnboxedPointer) \ - _(ConvertUnboxedObjectToNative) \ _(ArrayPopShiftV) \ _(ArrayPopShiftT) \ _(ArrayPushV) \ diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index fe89fac9c..9e0342382 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -1995,17 +1995,6 @@ TypeSet::ObjectKey::watchStateChangeForTypedArrayData(CompilerConstraintList* co ConstraintDataFreezeObjectForTypedArrayData(tarray))); } -void -TypeSet::ObjectKey::watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints) -{ - HeapTypeSetKey objectProperty = property(JSID_EMPTY); - LifoAlloc* alloc = constraints->alloc(); - - typedef CompilerConstraintInstance T; - constraints->add(alloc->new_(alloc, objectProperty, - ConstraintDataFreezeObjectForUnboxedConvertedToNative())); -} - static void ObjectStateChange(ExclusiveContext* cxArg, ObjectGroup* group, bool markingUnknown) { diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 0f1cd4936..04fed448c 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -262,7 +262,6 @@ class TypeSet bool hasStableClassAndProto(CompilerConstraintList* constraints); void watchStateChangeForInlinedCall(CompilerConstraintList* constraints); void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints); - void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints); HeapTypeSetKey property(jsid id); void ensureTrackedProperty(JSContext* cx, jsid id); -- cgit v1.2.3 From 201d8ee48926569fee200fbc9b4d506554869b5d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 16 May 2019 21:34:42 +0000 Subject: Remove Unboxed Objects from vm/ - Part 2 --- js/src/jsobj.cpp | 75 ++++++++++----------------------------------- js/src/vm/ReceiverGuard.cpp | 1 - js/src/vm/ReceiverGuard.h | 5 --- 3 files changed, 17 insertions(+), 64 deletions(-) (limited to 'js/src') diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 7852b3365..f22ecb445 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -870,9 +870,6 @@ static inline JSObject* CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group, NewObjectKind newKind) { - if (group->maybeUnboxedLayout() && newKind != SingletonObject) - return UnboxedPlainObject::create(cx, group, newKind); - if (TypeNewScript* newScript = group->newScript()) { if (newScript->analyzed()) { // The definite properties analysis has been performed for this @@ -1167,46 +1164,27 @@ static bool GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj, MutableHandle properties) { - if (obj->is()) { - PlainObject* nobj = &obj->as(); - - if (!properties.appendN(IdValuePair(), nobj->slotSpan())) - return false; + MOZ_ASSERT(obj->is()); + PlainObject* nobj = &obj->as(); - for (Shape::Range r(nobj->lastProperty()); !r.empty(); r.popFront()) { - Shape& shape = r.front(); - MOZ_ASSERT(shape.isDataDescriptor()); - uint32_t slot = shape.slot(); - properties[slot].get().id = shape.propid(); - properties[slot].get().value = nobj->getSlot(slot); - } - - for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) { - Value v = nobj->getDenseElement(i); - if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v))) - return false; - } + if (!properties.appendN(IdValuePair(), nobj->slotSpan())) + return false; - return true; + for (Shape::Range r(nobj->lastProperty()); !r.empty(); r.popFront()) { + Shape& shape = r.front(); + MOZ_ASSERT(shape.isDataDescriptor()); + uint32_t slot = shape.slot(); + properties[slot].get().id = shape.propid(); + properties[slot].get().value = nobj->getSlot(slot); } - if (obj->is()) { - UnboxedPlainObject* nobj = &obj->as(); - - const UnboxedLayout& layout = nobj->layout(); - if (!properties.appendN(IdValuePair(), layout.properties().length())) + for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) { + Value v = nobj->getDenseElement(i); + if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v))) return false; - - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - properties[i].get().id = NameToId(property.name); - properties[i].get().value = nobj->getValue(property); - } - - return true; } - MOZ_CRASH("Bad object kind"); + return true; } static bool @@ -1228,8 +1206,9 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin /* NB: Keep this in sync with XDRObjectLiteral. */ MOZ_ASSERT_IF(obj->isSingleton(), cx->compartment()->behaviors().getSingletonsAsTemplates()); - MOZ_ASSERT(obj->is() || obj->is() || - obj->is() || obj->is()); + MOZ_ASSERT(obj->is() || + obj->is() || + obj->is()); MOZ_ASSERT(newKind != SingletonObject); if (obj->is() || obj->is()) { @@ -1348,7 +1327,6 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) { if (mode == XDR_ENCODE) { MOZ_ASSERT(obj->is() || - obj->is() || obj->is() || obj->is()); isArray = (obj->is() || obj->is()) ? 1 : 0; @@ -2334,11 +2312,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** // us the resolve hook won't define a property with this id. if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) return false; - } else if (obj->is()) { - if (obj->as().containsUnboxedOrExpandoProperty(cx, id)) { - MarkNonNativePropertyFound(propp); - return true; - } } else if (obj->is()) { if (obj->as().containsProperty(cx, id)) { MarkNonNativePropertyFound(propp); @@ -2591,11 +2564,6 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object break; } - // Convert unboxed objects to their native representations before changing - // their prototype/group, as they depend on the group for their layout. - if (!MaybeConvertUnboxedObjectToNative(cx, obj)) - return false; - Rooted taggedProto(cx, TaggedProto(proto)); if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto)) return false; @@ -2619,9 +2587,6 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I if (!obj->nonProxyIsExtensible()) return result.succeed(); - if (!MaybeConvertUnboxedObjectToNative(cx, obj)) - return false; - // Force lazy properties to be resolved. AutoIdVector props(cx); if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props)) @@ -3715,12 +3680,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const if (IsProxy(this)) return as().allocKindForTenure(); - // Unboxed plain objects are sized according to the data they store. - if (is()) { - size_t nbytes = as().layoutDontCheckGeneration().size(); - return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes); - } - // Unboxed arrays use inline data if their size is small enough. if (is()) { const UnboxedArrayObject* nobj = &as(); diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp index 97df908c3..11c2d0727 100644 --- a/js/src/vm/ReceiverGuard.cpp +++ b/js/src/vm/ReceiverGuard.cpp @@ -7,7 +7,6 @@ #include "vm/ReceiverGuard.h" #include "builtin/TypedObject.h" -#include "vm/UnboxedObject.h" #include "jsobjinlines.h" using namespace js; diff --git a/js/src/vm/ReceiverGuard.h b/js/src/vm/ReceiverGuard.h index 459cc0012..c14f0d83b 100644 --- a/js/src/vm/ReceiverGuard.h +++ b/js/src/vm/ReceiverGuard.h @@ -28,11 +28,6 @@ namespace js { // TypedObject: The structure of a typed object is determined by its group. // All typed objects with the same group have the same class, prototype, and // own properties. -// -// UnboxedPlainObject: The structure of an unboxed plain object is determined -// by its group and its expando object's shape, if there is one. All unboxed -// plain objects with the same group and expando shape have the same -// properties except those stored in the expando's dense elements. class HeapReceiverGuard; class RootedReceiverGuard; -- cgit v1.2.3 From 354c6dceecdad5e58e2763e937ad5053e8b7d897 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 17 May 2019 01:04:30 +0000 Subject: Implement String.prototype.trimStart and trimEnd. This renames our internal function names because *Left and *Right might be deprecated and have to be removed later, making that trivial. Resolves #1089 --- js/src/builtin/String.js | 12 ++++++------ js/src/jsstr.cpp | 16 ++++++++++------ js/src/jsstr.h | 4 ++-- js/src/vm/SelfHosting.cpp | 6 ++++-- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'js/src') diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index e5b2ad552..f830b1aa2 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -828,16 +828,16 @@ function String_static_trim(string) { return callFunction(std_String_trim, string); } -function String_static_trimLeft(string) { +function String_static_trimStart(string) { if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimLeft'); - return callFunction(std_String_trimLeft, string); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimStart'); + return callFunction(std_String_trimStart, string); } -function String_static_trimRight(string) { +function String_static_trimEnd(string) { if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimRight'); - return callFunction(std_String_trimRight, string); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimEnd'); + return callFunction(std_String_trimEnd, string); } function String_static_toLocaleLowerCase(string) { diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index e3b5708ca..7765b1197 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1970,14 +1970,14 @@ js::str_trim(JSContext* cx, unsigned argc, Value* vp) } bool -js::str_trimLeft(JSContext* cx, unsigned argc, Value* vp) +js::str_trimStart(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return TrimString(cx, args, true, false); } bool -js::str_trimRight(JSContext* cx, unsigned argc, Value* vp) +js::str_trimEnd(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); return TrimString(cx, args, false, true); @@ -2568,8 +2568,10 @@ static const JSFunctionSpec string_methods[] = { JS_FN("startsWith", str_startsWith, 1,0), JS_FN("endsWith", str_endsWith, 1,0), JS_FN("trim", str_trim, 0,0), - JS_FN("trimLeft", str_trimLeft, 0,0), - JS_FN("trimRight", str_trimRight, 0,0), + JS_FN("trimLeft", str_trimStart, 0,0), + JS_FN("trimStart", str_trimStart, 0,0), + JS_FN("trimRight", str_trimEnd, 0,0), + JS_FN("trimEnd", str_trimEnd, 0,0), JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0), JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0), JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0), @@ -2881,8 +2883,10 @@ static const JSFunctionSpec string_static_methods[] = { JS_SELF_HOSTED_FN("startsWith", "String_static_startsWith", 2,0), JS_SELF_HOSTED_FN("endsWith", "String_static_endsWith", 2,0), JS_SELF_HOSTED_FN("trim", "String_static_trim", 1,0), - JS_SELF_HOSTED_FN("trimLeft", "String_static_trimLeft", 1,0), - JS_SELF_HOSTED_FN("trimRight", "String_static_trimRight", 1,0), + JS_SELF_HOSTED_FN("trimLeft", "String_static_trimStart", 1,0), + JS_SELF_HOSTED_FN("trimStart", "String_static_trimStart", 1,0), + JS_SELF_HOSTED_FN("trimRight", "String_static_trimEnd", 1,0), + JS_SELF_HOSTED_FN("trimEnd", "String_static_trimEnd", 1,0), JS_SELF_HOSTED_FN("toLocaleLowerCase","String_static_toLocaleLowerCase",1,0), JS_SELF_HOSTED_FN("toLocaleUpperCase","String_static_toLocaleUpperCase",1,0), JS_SELF_HOSTED_FN("normalize", "String_static_normalize", 1,0), diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 118118839..38fbfa85e 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -367,10 +367,10 @@ extern bool str_trim(JSContext* cx, unsigned argc, Value* vp); extern bool -str_trimLeft(JSContext* cx, unsigned argc, Value* vp); +str_trimStart(JSContext* cx, unsigned argc, Value* vp); extern bool -str_trimRight(JSContext* cx, unsigned argc, Value* vp); +str_trimEnd(JSContext* cx, unsigned argc, Value* vp); extern bool str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 328a960b6..ccd4cc8d7 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2200,8 +2200,10 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("std_String_charAt", str_charAt, 1,0, StringCharAt), JS_FN("std_String_endsWith", str_endsWith, 1,0), JS_FN("std_String_trim", str_trim, 0,0), - JS_FN("std_String_trimLeft", str_trimLeft, 0,0), - JS_FN("std_String_trimRight", str_trimRight, 0,0), + JS_FN("std_String_trimLeft", str_trimStart, 0,0), + JS_FN("std_String_trimStart", str_trimStart, 0,0), + JS_FN("std_String_trimRight", str_trimEnd, 0,0), + JS_FN("std_String_trimEnd", str_trimEnd, 0,0), JS_FN("std_String_toLocaleLowerCase", str_toLocaleLowerCase, 0,0), JS_FN("std_String_toLocaleUpperCase", str_toLocaleUpperCase, 0,0), JS_FN("std_String_normalize", str_normalize, 0,0), -- cgit v1.2.3 From 162e22a7de3026b676156a2aad29909fe3795dba Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 19 May 2019 23:11:17 +0200 Subject: Implement array.flat and array.flatMap Self-hosted implementation that adds both functions and adds them to @@unscopables as specced in ES2019. Resolves #1095 --- js/src/builtin/Array.js | 108 +++++++++++++++++++++++++++++++ js/src/jsarray.cpp | 7 ++ js/src/tests/ecma_6/Array/unscopables.js | 2 + js/src/vm/CommonPropertyNames.h | 2 + 4 files changed, 119 insertions(+) (limited to 'js/src') diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 30e6fb35f..05fc41bc1 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -1073,6 +1073,114 @@ function ArrayConcat(arg1) { return A; } +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function ArrayFlatMap(mapperFunction/*, thisArg*/) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + if (!IsCallable(mapperFunction)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction)); + + // Step 4. + var T = arguments.length > 1 ? arguments[1] : undefined; + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T); + + // Step 7. + return A; +} + +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function ArrayFlat(/* depth */) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + var depthNum = 1; + + // Step 4. + if (arguments.length > 0 && arguments[0] !== undefined) + depthNum = ToInteger(arguments[0]); + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, depthNum); + + // Step 7. + return A; +} + +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) { + // Step 1. + var targetIndex = start; + + // Steps 2-3. + for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { + // Steps 3.a-c. + if (sourceIndex in source) { + // Step 3.c.i. + var element = source[sourceIndex]; + + if (mapperFunction) { + // Step 3.c.ii.1. + assert(arguments.length === 7, "thisArg is present"); + + // Step 3.c.ii.2. + element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source); + } + + // Step 3.c.iii. + var shouldFlatten = false; + + // Step 3.c.iv. + if (depth > 0) { + // Step 3.c.iv.1. + shouldFlatten = IsArray(element); + } + + // Step 3.c.v. + if (shouldFlatten) { + // Step 3.c.v.1. + var elementLen = ToLength(element.length); + + // Step 3.c.v.2. + // Recursive call to walk the depth. + targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1); + } else { + // Step 3.c.vi.1. + if (targetIndex >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + // Step 3.c.vi.2. + _DefineDataProperty(target, targetIndex, element); + + // Step 3.c.vi.3. + targetIndex++; + } + } + } + + // Step 4. + return targetIndex; +} + function ArrayStaticConcat(arr, arg1) { if (arguments.length < 1) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat'); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7a67c0095..3b4c957dc 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3169,6 +3169,11 @@ static const JSFunctionSpec array_methods[] = { /* ES7 additions */ JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2,0), + + /* ES2019 additions */ + JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0,0), + JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1,0), + JS_FS_END }; @@ -3333,6 +3338,8 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto) !DefineProperty(cx, unscopables, cx->names().fill, value) || !DefineProperty(cx, unscopables, cx->names().find, value) || !DefineProperty(cx, unscopables, cx->names().findIndex, value) || + !DefineProperty(cx, unscopables, cx->names().flat, value) || + !DefineProperty(cx, unscopables, cx->names().flatMap, value) || !DefineProperty(cx, unscopables, cx->names().includes, value) || !DefineProperty(cx, unscopables, cx->names().keys, value) || !DefineProperty(cx, unscopables, cx->names().values, value)) diff --git a/js/src/tests/ecma_6/Array/unscopables.js b/js/src/tests/ecma_6/Array/unscopables.js index 6685309a0..56b3aa520 100644 --- a/js/src/tests/ecma_6/Array/unscopables.js +++ b/js/src/tests/ecma_6/Array/unscopables.js @@ -26,6 +26,8 @@ assertDeepEq(keys, [ "fill", "find", "findIndex", + "flat", + "flatMap", "includes", "keys", "values" diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index e971dc844..8a36df083 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -115,6 +115,8 @@ macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \ macro(fix, fix, "fix") \ macro(flags, flags, "flags") \ + macro(flat, flat, "flat") \ + macro(flatMap, flatMap, "flatMap") \ macro(float32, float32, "float32") \ macro(Float32x4, Float32x4, "Float32x4") \ macro(float64, float64, "float64") \ -- cgit v1.2.3 From 41731a7f31a1724e74b32eb7be87de2719f977c3 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 20 May 2019 02:50:01 +0200 Subject: =?UTF-8?q?Implement=20Symbol=E2=80=8B.prototype=E2=80=8B.descript?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #1096 --- js/src/builtin/SymbolObject.cpp | 29 +++++++++++++++++++++++++++++ js/src/builtin/SymbolObject.h | 4 ++++ 2 files changed, 33 insertions(+) (limited to 'js/src') diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index cf48402d6..ae38d5371 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -33,6 +33,7 @@ SymbolObject::create(JSContext* cx, JS::HandleSymbol symbol) } const JSPropertySpec SymbolObject::properties[] = { + JS_PSG("description", descriptionGetter, 0), JS_PS_END }; @@ -227,6 +228,34 @@ SymbolObject::toPrimitive(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } +// ES2019 Stage 4 Draft / November 28, 2018 +// Symbol description accessor +// See: https://tc39.github.io/proposal-Symbol-description/ +bool +SymbolObject::descriptionGetter_impl(JSContext* cx, const CallArgs& args) +{ + // Get symbol object pointer. + HandleValue thisv = args.thisv(); + MOZ_ASSERT(IsSymbol(thisv)); + Rooted sym(cx, thisv.isSymbol() + ? thisv.toSymbol() + : thisv.toObject().as().unbox()); + + // Return the symbol's description if present, otherwise return undefined. + if (JSString* str = sym->description()) + args.rval().setString(str); + else + args.rval().setUndefined(); + return true; +} + +bool +SymbolObject::descriptionGetter(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, args); +} + JSObject* js::InitSymbolClass(JSContext* cx, HandleObject obj) { diff --git a/js/src/builtin/SymbolObject.h b/js/src/builtin/SymbolObject.h index 0f204b494..e10b42d53 100644 --- a/js/src/builtin/SymbolObject.h +++ b/js/src/builtin/SymbolObject.h @@ -52,6 +52,10 @@ class SymbolObject : public NativeObject static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp); + // Properties defined on Symbol.prototype. + static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc, Value *vp); + static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; static const JSFunctionSpec staticMethods[]; -- cgit v1.2.3 From e24e6346b70d3d212e9c9b7aa14f79f1d3ea86e8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 25 May 2019 00:31:24 +0200 Subject: Fix architecture flag for PPC64 Fixes #1092 --- js/src/jstypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/src') diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 6cfb3d4ad..04ffbe00d 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -147,7 +147,7 @@ # define JS_64BIT # endif #elif defined(__GNUC__) -# if defined(__x86_64__) || defined(__64BIT__) +# if defined(__x86_64__) || defined(__LP64__) # define JS_64BIT # endif #elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */ -- cgit v1.2.3 From a24d62130932b8104f931f925288d3abc9105684 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Sat, 25 May 2019 15:41:06 +0200 Subject: [js, ARM] Always check error return from BufferOffset::diffB. We were missing error checks at two points. In one case an error return is meaningful; in another case it is not, as the problem should have been guarded against at a higher level by emitting far jump islands soon enough during pasteup of compiled code. --- js/src/jit/arm/Assembler-arm.cpp | 7 ++++++- js/src/jit/arm/MacroAssembler-arm.cpp | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'js/src') diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index 2830f0695..1e20da1c8 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -2401,7 +2401,12 @@ Assembler::as_b(Label* l, Condition c) if (oom()) return BufferOffset(); - as_b(BufferOffset(l).diffB(ret), c, ret); + BOffImm off = BufferOffset(l).diffB(ret); + if (off.isInvalid()) { + m_buffer.fail_bail(); + return BufferOffset(); + } + as_b(off, c, ret); #ifdef JS_DISASM_ARM spewBranch(m_buffer.getInstOrNull(ret), l); #endif diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index d40578514..a4161ab00 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -5012,7 +5012,10 @@ void MacroAssembler::patchCall(uint32_t callerOffset, uint32_t calleeOffset) { BufferOffset inst(callerOffset - 4); - as_bl(BufferOffset(calleeOffset).diffB(inst), Always, inst); + BOffImm off = BufferOffset(calleeOffset).diffB(inst); + MOZ_RELEASE_ASSERT(!off.isInvalid(), + "Failed to insert necessary far jump islands"); + as_bl(off, Always, inst); } CodeOffset -- cgit v1.2.3 From 6cc615bbe5224cf74fc302a6fb72d0de56feb719 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 28 May 2019 18:03:08 +0200 Subject: Improve efficiency of (C++) heap allocations related to BytecodeEmitter::code. While there, also add some sanity checks and clean up code. --- js/src/frontend/BytecodeEmitter.cpp | 28 ++++++++++++++++++---------- js/src/frontend/BytecodeEmitter.h | 10 ++++++---- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'js/src') diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index b3dd6d777..c524184d6 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2260,12 +2260,14 @@ BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* bool BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset) { - *offset = code().length(); + size_t oldLength = code().length(); + *offset = ptrdiff_t(oldLength); - // Start it off moderately large to avoid repeated resizings early on. - // ~98% of cases fit within 1024 bytes. - if (code().capacity() == 0 && !code().reserve(1024)) - return false; + size_t newLength = oldLength + size_t(delta); + if (MOZ_UNLIKELY(newLength > MaxBytecodeLength)) { + ReportAllocationOverflow(cx); + return false; + } if (!code().growBy(delta)) { ReportOutOfMemory(cx); @@ -10697,17 +10699,19 @@ BytecodeEmitter::emitTreeInBranch(ParseNode* pn) static bool AllocSrcNote(ExclusiveContext* cx, SrcNotesVector& notes, unsigned* index) { - // Start it off moderately large to avoid repeated resizings early on. - // ~99% of cases fit within 256 bytes. - if (notes.capacity() == 0 && !notes.reserve(256)) - return false; + size_t oldLength = notes.length(); + if (MOZ_UNLIKELY(oldLength + 1 > MaxSrcNotesLength)) { + ReportAllocationOverflow(cx); + return false; + } + if (!notes.growBy(1)) { ReportOutOfMemory(cx); return false; } - *index = notes.length() - 1; + *index = oldLength; return true; } @@ -10833,6 +10837,10 @@ BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offs /* Maybe this offset was already set to a four-byte value. */ if (!(*sn & SN_4BYTE_OFFSET_FLAG)) { /* Insert three dummy bytes that will be overwritten shortly. */ + if (MOZ_UNLIKELY(notes.length() + 3 > MaxSrcNotesLength)) { + ReportAllocationOverflow(cx); + return false; + } jssrcnote dummy = 0; if (!(sn = notes.insert(sn, dummy)) || !(sn = notes.insert(sn, dummy)) || diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 32668a34c..814fa11d4 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -109,10 +109,12 @@ struct CGYieldOffsetList { void finish(YieldOffsetArray& array, uint32_t prologueLength); }; -// Use zero inline elements because these go on the stack and affect how many -// nested functions are possible. -typedef Vector BytecodeVector; -typedef Vector SrcNotesVector; +static size_t MaxBytecodeLength = INT32_MAX; +static size_t MaxSrcNotesLength = INT32_MAX; + +// Have a few inline elements to avoid heap allocation for tiny sequences. +typedef Vector BytecodeVector; +typedef Vector SrcNotesVector; // Linked list of jump instructions that need to be patched. The linked list is // stored in the bytes of the incomplete bytecode that will be patched, so no -- cgit v1.2.3 From 50062bdfc004c8e24e3344ffe6991894ee0e6d09 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 29 May 2019 11:08:31 +0200 Subject: Fix #1091 deprot --- js/src/jit/IonCaches.cpp | 1 + js/src/jit/Recover.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'js/src') diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 96e488ea8..0208db6ae 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -31,6 +31,7 @@ #include "jit/shared/Lowering-shared-inl.h" #include "vm/Interpreter-inl.h" #include "vm/Shape-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 13bf9224b..6fd71f377 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -30,6 +30,7 @@ #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; -- cgit v1.2.3