Stage 1-1: Implement Function.prototype.toString revision proposal.

Tag #960
This commit is contained in:
wolfbeast 2019-02-02 12:47:28 +01:00 • committed by Roy Tam
commit b68de773fd
13 changed files with 330 additions and 154 deletions

View file

@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool canLazilyParse(); bool canLazilyParse();
bool createParser(); bool createParser();
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing()); bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
bool createScript(); bool createScript(uint32_t preludeStart = 0);
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext); bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives); bool handleParseFailure(const Directives& newDirectives);
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment); bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No
} }
bool bool
BytecodeCompiler::createScript() BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
{ {
script = JSScript::Create(cx, options, script = JSScript::Create(cx, options,
sourceObject, /* sourceStart = */ 0, sourceBuffer.length()); sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
preludeStart);
return script != nullptr; return script != nullptr;
} }
@ -456,7 +457,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
if (fn->pn_funbox->function()->isInterpreted()) { if (fn->pn_funbox->function()->isInterpreted()) {
MOZ_ASSERT(fun == fn->pn_funbox->function()); MOZ_ASSERT(fun == fn->pn_funbox->function());
if (!createScript()) if (!createScript(fn->pn_funbox->preludeStart))
return false; return false;
Maybe<BytecodeEmitter> emitter; Maybe<BytecodeEmitter> emitter;
@ -650,7 +651,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
MOZ_ASSERT(sourceObject); MOZ_ASSERT(sourceObject);
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject, Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
lazy->begin(), lazy->end())); lazy->begin(), lazy->end(),
lazy->preludeStart()));
if (!script) if (!script)
return false; return false;

View file

@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str);
* As above, but taking chars + length. * As above, but taking chars + length.
*/ */
bool bool
IsIdentifier(const char* chars, size_t length);
bool
IsIdentifier(const char16_t* chars, size_t length); IsIdentifier(const char16_t* chars, size_t length);
/* True if str is a keyword. Defined in TokenStream.cpp. */ /* True if str is a keyword. Defined in TokenStream.cpp. */

View file

@ -7834,7 +7834,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
Rooted<JSObject*> sourceObject(cx, script->sourceObject()); Rooted<JSObject*> sourceObject(cx, script->sourceObject());
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject, Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
funbox->bufStart, funbox->bufEnd)); funbox->bufStart, funbox->bufEnd,
funbox->preludeStart));
if (!script) if (!script)
return false; return false;

View file

@ -441,7 +441,8 @@ UsedNameTracker::rewind(RewindToken token)
} }
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, 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) GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead), : ObjectBox(fun, traceListHead),
SharedContext(cx, Kind::ObjectBox, directives, extraWarnings), SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
@ -454,6 +455,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
bufEnd(0), bufEnd(0),
startLine(1), startLine(1),
startColumn(0), startColumn(0),
preludeStart(preludeStart),
length(0), length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)), generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)),
@ -738,7 +740,8 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler> template <typename ParseHandler>
FunctionBox* FunctionBox*
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives, Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
Directives inheritedDirectives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB) bool tryAnnexB)
{ {
@ -753,8 +756,9 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheri
* function. * function.
*/ */
FunctionBox* funbox = FunctionBox* funbox =
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives, alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart,
options().extraWarningsOption, generatorKind, asyncKind); inheritedDirectives, options().extraWarningsOption,
generatorKind, asyncKind);
if (!funbox) { if (!funbox) {
ReportOutOfMemory(context); ReportOutOfMemory(context);
return nullptr; return nullptr;
@ -2214,6 +2218,7 @@ Parser<SyntaxParseHandler>::finishFunction()
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(), LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
pc->innerFunctionsForLazy, versionNumber(), pc->innerFunctionsForLazy, versionNumber(),
funbox->bufStart, funbox->bufEnd, funbox->bufStart, funbox->bufEnd,
funbox->preludeStart,
funbox->startLine, funbox->startColumn); funbox->startLine, funbox->startColumn);
if (!lazy) if (!lazy)
return false; return false;
@ -2267,6 +2272,33 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
{ {
MOZ_ASSERT(checkOptionsCalled); 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(); Node fn = handler.newFunctionDefinition();
if (!fn) if (!fn)
return null(); return null();
@ -2276,8 +2308,8 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null(); return null();
fn->pn_body = argsbody; fn->pn_body = argsbody;
FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives,
asyncKind, /* tryAnnexB = */ false); generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox) if (!funbox)
return null(); return null();
funbox->initStandaloneFunction(enclosingScope); funbox->initStandaloneFunction(enclosingScope);
@ -2295,7 +2327,6 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null(); return null();
} }
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand)) if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null(); return null();
if (tt != TOK_EOF) { if (tt != TOK_EOF) {
@ -2991,8 +3022,8 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
template <> template <>
bool bool
Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind, Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart,
bool tryAnnexB) FunctionSyntaxKind kind, bool tryAnnexB)
{ {
// When a lazily-parsed function is called, we only fully parse (and emit) // 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 // that function, not any of its nested children. The initial syntax-only
@ -3001,7 +3032,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
RootedFunction fun(context, handler.nextLazyInnerFunction()); RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator()); 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); fun->generatorKind(), fun->asyncKind(), tryAnnexB);
if (!funbox) if (!funbox)
return false; return false;
@ -3031,8 +3062,8 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
template <> template <>
bool bool
Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart,
bool tryAnnexB) FunctionSyntaxKind kind, bool tryAnnexB)
{ {
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing"); MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
} }
@ -3108,7 +3139,8 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::Node
Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yieldHandling, Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, InHandling inHandling,
YieldHandling yieldHandling,
HandleAtom funName, FunctionSyntaxKind kind, HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked) InvokedPrediction invoked)
@ -3132,7 +3164,7 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
// functions, which are also lazy. Instead, their free variables and // functions, which are also lazy. Instead, their free variables and
// source extents are recorded and may be skipped. // source extents are recorded and may be skipped.
if (handler.canSkipLazyInnerFunctions()) { if (handler.canSkipLazyInnerFunctions()) {
if (!skipLazyInnerFunction(pn, kind, tryAnnexB)) if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB))
return null(); return null();
return pn; return pn;
} }
@ -3165,8 +3197,9 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
// reparse a function due to failed syntax parsing and encountering new // reparse a function due to failed syntax parsing and encountering new
// "use foo" directives. // "use foo" directives.
while (true) { while (true) {
if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind, if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind,
asyncKind, tryAnnexB, directives, &newDirectives)) generatorKind, asyncKind, tryAnnexB, directives,
&newDirectives))
{ {
break; break;
} }
@ -3193,6 +3226,7 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
template <> template <>
bool bool
Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun, Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
uint32_t preludeStart,
InHandling inHandling, InHandling inHandling,
YieldHandling yieldHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionSyntaxKind kind,
@ -3226,14 +3260,15 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// Make a FunctionBox before we enter the syntax parser, because |pn| // Make a FunctionBox before we enter the syntax parser, because |pn|
// still expects a FunctionBox to be attached to it during BCE, and // still expects a FunctionBox to be attached to it during BCE, and
// the syntax parser cannot attach one to it. // the syntax parser cannot attach one to it.
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
asyncKind, tryAnnexB); generatorKind, asyncKind, tryAnnexB);
if (!funbox) if (!funbox)
return false; return false;
funbox->initWithEnclosingParseContext(pc, kind); funbox->initWithEnclosingParseContext(pc, kind);
if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling, if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart,
yieldHandling, kind, inheritedDirectives, newDirectives)) inHandling, yieldHandling, kind,
inheritedDirectives, newDirectives))
{ {
if (parser->hadAbortedSyntaxParse()) { if (parser->hadAbortedSyntaxParse()) {
// Try again with a full parse. UsedNameTracker needs to be // Try again with a full parse. UsedNameTracker needs to be
@ -3259,13 +3294,14 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
} while (false); } while (false);
// We failed to do a syntax parse above, so do the full parse. // We failed to do a syntax parse above, so do the full parse.
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
tryAnnexB, inheritedDirectives, newDirectives); generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
} }
template <> template <>
bool bool
Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun, Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun,
uint32_t preludeStart,
InHandling inHandling, InHandling inHandling,
YieldHandling yieldHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionSyntaxKind kind,
@ -3276,13 +3312,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction
Directives* newDirectives) Directives* newDirectives)
{ {
// This is already a syntax parser, so just parse the inner function. // This is already a syntax parser, so just parse the inner function.
return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind, return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
tryAnnexB, inheritedDirectives, newDirectives); generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
} }
template <typename ParseHandler> template <typename ParseHandler>
bool bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox,
uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling, InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, Directives inheritedDirectives, FunctionSyntaxKind kind, Directives inheritedDirectives,
Directives* newDirectives) Directives* newDirectives)
@ -3306,6 +3343,7 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox*
template <typename ParseHandler> template <typename ParseHandler>
bool bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling, InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@ -3317,14 +3355,14 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti
// parser. In that case, outerpc is a ParseContext from the full parser // parser. In that case, outerpc is a ParseContext from the full parser
// instead of the current top of the stack of the syntax parser. // instead of the current top of the stack of the syntax parser.
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
asyncKind, tryAnnexB); generatorKind, asyncKind, tryAnnexB);
if (!funbox) if (!funbox)
return false; return false;
funbox->initWithEnclosingParseContext(outerpc, kind); funbox->initWithEnclosingParseContext(outerpc, kind);
return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives, return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind,
newDirectives); inheritedDirectives, newDirectives);
} }
template <typename ParseHandler> template <typename ParseHandler>
@ -3359,8 +3397,8 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
return null(); return null();
Directives directives(strict); Directives directives(strict);
FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives,
/* tryAnnexB = */ false); generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox) if (!funbox)
return null(); return null();
funbox->initFromLazyFunction(); funbox->initFromLazyFunction();
@ -3529,8 +3567,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::Node
Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling,
FunctionAsyncKind asyncKind) DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)
{ {
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
@ -3579,8 +3617,8 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
} }
YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind, Node fun = functionDefinition(preludeStart, InAllowed, newYieldHandling, name, Statement,
asyncKind, PredictUninvoked); generatorKind, asyncKind, PredictUninvoked);
if (!fun) if (!fun)
return null(); return null();
@ -3597,7 +3635,8 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::Node
Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind) Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invoked,
FunctionAsyncKind asyncKind)
{ {
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
@ -3628,8 +3667,8 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
tokenStream.ungetToken(); tokenStream.ungetToken();
} }
return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind, return functionDefinition(preludeStart, InAllowed, yieldHandling, name, Expression,
asyncKind, invoked); generatorKind, asyncKind, invoked);
} }
/* /*
@ -5074,7 +5113,7 @@ Parser<FullParseHandler>::exportDeclaration()
} }
case TOK_FUNCTION: case TOK_FUNCTION:
kid = functionStmt(YieldIsKeyword, NameRequired); kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired);
if (!kid) if (!kid)
return null(); return null();
@ -5114,7 +5153,7 @@ Parser<FullParseHandler>::exportDeclaration()
ParseNode* nameNode = nullptr; ParseNode* nameNode = nullptr;
switch (tt) { switch (tt) {
case TOK_FUNCTION: case TOK_FUNCTION:
kid = functionStmt(YieldIsKeyword, AllowDefaultName); kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName);
if (!kid) if (!kid)
return null(); return null();
break; break;
@ -5131,7 +5170,7 @@ Parser<FullParseHandler>::exportDeclaration()
if (nextSameLine == TOK_FUNCTION) { if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(nextSameLine); tokenStream.consumeKnownToken(nextSameLine);
kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction); kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction);
if (!kid) if (!kid)
return null(); return null();
break; break;
@ -5232,7 +5271,7 @@ Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
// will report the strict mode error. // will report the strict mode error.
if (!pc->sc()->strict()) { if (!pc->sc()->strict()) {
tokenStream.consumeKnownToken(next, TokenStream::Operand); tokenStream.consumeKnownToken(next, TokenStream::Operand);
return functionStmt(yieldHandling, NameRequired); return functionStmt(pos().begin, yieldHandling, NameRequired);
} }
} }
@ -6182,7 +6221,7 @@ Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
return null(); return null();
} }
return functionStmt(yieldHandling, NameRequired); return functionStmt(pos().begin, yieldHandling, NameRequired);
} }
tokenStream.ungetToken(); tokenStream.ungetToken();
@ -6649,6 +6688,10 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken(); tokenStream.ungetToken();
} }
uint32_t nameOffset;
if (!tokenStream.peekOffset(&nameOffset))
return null();
PropertyType propType; PropertyType propType;
Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom); Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
if (!propName) if (!propName)
@ -6701,7 +6744,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB)) if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom; funName = propAtom;
} }
Node fn = methodDefinition(propType, funName); Node fn = methodDefinition(nameOffset, propType, funName);
if (!fn) if (!fn)
return null(); return null();
@ -7094,8 +7137,9 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
if (!tokenStream.peekTokenSameLine(&nextSameLine)) if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null(); return null();
if (nextSameLine == TOK_FUNCTION) { if (nextSameLine == TOK_FUNCTION) {
uint32_t preludeStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION); tokenStream.consumeKnownToken(TOK_FUNCTION);
return functionStmt(yieldHandling, NameRequired, AsyncFunction); return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction);
} }
} }
@ -7174,7 +7218,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// HoistableDeclaration[?Yield, ~Default] // HoistableDeclaration[?Yield, ~Default]
case TOK_FUNCTION: case TOK_FUNCTION:
return functionStmt(yieldHandling, NameRequired); return functionStmt(pos().begin, yieldHandling, NameRequired);
// ClassDeclaration[?Yield, ~Default] // ClassDeclaration[?Yield, ~Default]
case TOK_CLASS: case TOK_CLASS:
@ -7677,8 +7721,10 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
tokenStream.seek(start); tokenStream.seek(start);
if (!tokenStream.peekToken(&next, TokenStream::Operand)) if (!tokenStream.getToken(&next, TokenStream::Operand))
return null(); return null();
uint32_t preludeStart = pos().begin;
tokenStream.ungetToken();
GeneratorKind generatorKind = NotGenerator; GeneratorKind generatorKind = NotGenerator;
FunctionAsyncKind asyncKind = SyncFunction; FunctionAsyncKind asyncKind = SyncFunction;
@ -7702,7 +7748,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
} }
} }
Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr, Node arrowFunc = functionDefinition(preludeStart, inHandling, yieldHandling, nullptr,
Arrow, generatorKind, asyncKind); Arrow, generatorKind, asyncKind);
if (!arrowFunc) if (!arrowFunc)
return null(); return null();
@ -8054,8 +8100,8 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
// Create box for fun->object early to root it. // Create box for fun->object early to root it.
Directives directives(/* strict = */ outerpc->sc()->strict()); Directives directives(/* strict = */ outerpc->sc()->strict());
FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction, FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives,
/* tryAnnexB = */ false); StarGenerator, SyncFunction, /* tryAnnexB = */ false);
if (!genFunbox) if (!genFunbox)
return null(); return null();
genFunbox->isGenexpLambda = true; genFunbox->isGenexpLambda = true;
@ -8087,12 +8133,14 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
uint32_t end = pos().end;
handler.setBeginPosition(comp, begin); handler.setBeginPosition(comp, begin);
handler.setEndPosition(comp, pos().end); handler.setEndPosition(comp, end);
genFunbox->bufEnd = end;
handler.addStatementToList(body, comp); handler.addStatementToList(body, comp);
handler.setEndPosition(body, pos().end); handler.setEndPosition(body, end);
handler.setBeginPosition(genfn, begin); handler.setBeginPosition(genfn, begin);
handler.setEndPosition(genfn, pos().end); handler.setEndPosition(genfn, end);
Node generator = newDotGeneratorName(); Node generator = newDotGeneratorName();
if (!generator) if (!generator)
@ -9158,6 +9206,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (tt == TOK_RC) if (tt == TOK_RC)
break; break;
TokenPos namePos = pos();
tokenStream.ungetToken(); tokenStream.ungetToken();
PropertyType propType; PropertyType propType;
@ -9309,7 +9359,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
} }
} }
Node fn = methodDefinition(propType, funName); Node fn = methodDefinition(namePos.begin, propType, funName);
if (!fn) if (!fn)
return null(); return null();
@ -9336,13 +9386,15 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::Node
Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName) Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType,
HandleAtom funName)
{ {
FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); return functionDefinition(preludeStart, InAllowed, yieldHandling, funName, kind,
generatorKind, asyncKind);
} }
template <typename ParseHandler> template <typename ParseHandler>
@ -9404,7 +9456,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
switch (tt) { switch (tt) {
case TOK_FUNCTION: case TOK_FUNCTION:
return functionExpr(invoked); return functionExpr(pos().begin, invoked);
case TOK_CLASS: case TOK_CLASS:
return classDefinition(yieldHandling, ClassExpression, NameRequired); return classDefinition(yieldHandling, ClassExpression, NameRequired);
@ -9471,8 +9523,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
return null(); return null();
if (nextSameLine == TOK_FUNCTION) { if (nextSameLine == TOK_FUNCTION) {
uint32_t preludeStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION); tokenStream.consumeKnownToken(TOK_FUNCTION);
return functionExpr(PredictUninvoked, AsyncFunction); return functionExpr(preludeStart, PredictUninvoked, AsyncFunction);
} }
} }

View file

@ -954,7 +954,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
* cx->tempLifoAlloc. * cx->tempLifoAlloc.
*/ */
ObjectBox* newObjectBox(JSObject* obj); 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, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB); bool tryAnnexB);
@ -1034,8 +1035,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse an inner function given an enclosing ParseContext and a // Parse an inner function given an enclosing ParseContext and a
// FunctionBox for the inner function. // FunctionBox for the inner function.
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling, bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart,
YieldHandling yieldHandling, FunctionSyntaxKind kind, InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
Directives inheritedDirectives, Directives* newDirectives); Directives inheritedDirectives, Directives* newDirectives);
// Parse a function's formal parameters and its body assuming its function // 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' * Some parsers have two versions: an always-inlined version (with an 'i'
* suffix) and a never-inlined version (with an 'n' suffix). * 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); FunctionAsyncKind asyncKind = SyncFunction);
Node functionExpr(InvokedPrediction invoked = PredictUninvoked, Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked,
FunctionAsyncKind asyncKind = SyncFunction); FunctionAsyncKind asyncKind = SyncFunction);
Node statementList(YieldHandling yieldHandling); Node statementList(YieldHandling yieldHandling);
@ -1222,7 +1225,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool tryNewTarget(Node& newTarget); bool tryNewTarget(Node& newTarget);
bool checkAndMarkSuperScope(); bool checkAndMarkSuperScope();
Node methodDefinition(PropertyType propType, HandleAtom funName); Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
/* /*
* Additional JS parsers. * Additional JS parsers.
@ -1230,7 +1233,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
Node funcpn); Node funcpn);
Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, Node functionDefinition(uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
FunctionSyntaxKind kind, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked = PredictUninvoked); InvokedPrediction invoked = PredictUninvoked);
@ -1321,14 +1325,16 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind, bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
GeneratorKind generatorKind, bool* tryAnnexB); GeneratorKind generatorKind, bool* tryAnnexB);
bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB); bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind,
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, bool tryAnnexB);
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling, InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives); Directives inheritedDirectives, Directives* newDirectives);
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling, bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart,
YieldHandling yieldHandling, FunctionSyntaxKind kind, InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives); Directives inheritedDirectives, Directives* newDirectives);

View file

@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext
uint32_t bufEnd; uint32_t bufEnd;
uint32_t startLine; uint32_t startLine;
uint32_t startColumn; uint32_t startColumn;
uint32_t preludeStart;
uint16_t length; uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
@ -476,8 +477,8 @@ class FunctionBox : public ObjectBox, public SharedContext
FunctionContextFlags funCxFlags; FunctionContextFlags funCxFlags;
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun, FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
Directives directives, bool extraWarnings, GeneratorKind generatorKind, uint32_t preludeStart, Directives directives, bool extraWarnings,
FunctionAsyncKind asyncKind); GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
MutableHandle<LexicalScope::Data*> namedLambdaBindings() { MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms()); MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());

View file

@ -171,6 +171,12 @@ frontend::IsIdentifier(JSLinearString* str)
: ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length()); : ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
} }
bool
frontend::IsIdentifier(const char* chars, size_t length)
{
return ::IsIdentifier(chars, length);
}
bool bool
frontend::IsIdentifier(const char16_t* chars, size_t length) frontend::IsIdentifier(const char16_t* chars, size_t length)
{ {

View file

@ -570,6 +570,13 @@ class MOZ_STACK_CLASS TokenStream
return true; 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 // 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 // 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 // return true and store TOK_EOL in |*ttp|. In that case, no token with

View file

@ -4250,7 +4250,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
*/ */
static bool static bool
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char* name, HandleAtom name, bool isInvalidName,
SourceBufferHolder& srcBuf, uint32_t parameterListEnd, SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
HandleObject enclosingEnv, HandleScope enclosingScope, HandleObject enclosingEnv, HandleScope enclosingScope,
MutableHandleFunction fun) MutableHandleFunction fun)
@ -4261,13 +4261,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
assertSameCompartment(cx, enclosingEnv); assertSameCompartment(cx, enclosingEnv);
RootedAtom funAtom(cx); RootedAtom funAtom(cx);
if (name) { fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
funAtom = Atomize(cx, name, strlen(name)); isInvalidName ? nullptr : name,
if (!funAtom)
return false;
}
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
/* proto = */ nullptr, /* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject, gc::AllocKind::FUNCTION, TenuredObject,
enclosingEnv)); enclosingEnv));
@ -4285,11 +4280,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
return false; 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; return true;
} }
static MOZ_MUST_USE bool 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, const SourceBufferHolder& srcBuf, StringBuffer* out,
uint32_t* parameterListEnd) uint32_t* parameterListEnd)
{ {
@ -4298,6 +4299,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames,
if (!out->ensureTwoByteChars()) if (!out->ensureTwoByteChars())
return false; return false;
if (!out->append("function "))
return false;
if (name) {
if (!out->append(name, nameLen))
return false;
}
if (!out->append("(")) if (!out->append("("))
return false; return false;
for (unsigned i = 0; i < nargs; i++) { for (unsigned i = 0; i < nargs; i++) {
@ -4334,15 +4341,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope)) if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
return false; 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; uint32_t parameterListEnd;
StringBuffer funStr(cx); StringBuffer funStr(cx);
if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, &parameterListEnd)) if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf,
&funStr, &parameterListEnd)) {
return false; return false;
}
size_t newLen = funStr.length(); size_t newLen = funStr.length();
SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership); 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) JS_PUBLIC_API(bool)

View file

@ -781,8 +781,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
RootedFunction functionProto(cx, &functionProto_->as<JSFunction>()); RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
const char* rawSource = "() {\n}"; const char* rawSource = "function () {\n}";
size_t sourceLen = strlen(rawSource); size_t sourceLen = strlen(rawSource);
size_t begin = 9;
MOZ_ASSERT(rawSource[begin] == '(');
mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen)); mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen));
if (!source) if (!source)
return nullptr; return nullptr;
@ -804,8 +806,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
RootedScript script(cx, JSScript::Create(cx, RootedScript script(cx, JSScript::Create(cx,
options, options,
sourceObject, sourceObject,
0, begin,
ss->length())); ss->length(),
0));
if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
return nullptr; return nullptr;
@ -985,53 +988,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
} }
} }
if (fun->isAsync()) { bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow();
if (!out.append("async "))
return nullptr;
}
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter();
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
// If we're not in pretty mode, put parentheses around lambda functions and methods. // If we're not in pretty mode, put parentheses around lambda functions
if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) { // so that eval returns lambda, not function statement.
if (haveSource && !prettyPrint && funIsNonArrowLambda) {
if (!out.append("(")) if (!out.append("("))
return nullptr; 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() && if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource)) !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{ {
return nullptr; 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) { if (haveSource) {
Rooted<JSFlatString*> src(cx, script->sourceData(cx)); Rooted<JSFlatString*> src(cx, script->sourceDataWithPrelude(cx));
if (!src) if (!src)
return nullptr; return nullptr;
if (!out.append(src)) if (!out.append(src))
return nullptr; return nullptr;
if (!prettyPrint && funIsMethodOrNonArrowLambda) { if (!prettyPrint && funIsNonArrowLambda) {
if (!out.append(")")) if (!out.append(")"))
return nullptr; return nullptr;
} }
} else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
if (!out.append("() {\n ") || if (!AppendPrelude() ||
!out.append("() {\n ") ||
!out.append("[sourceless code]") || !out.append("[sourceless code]") ||
!out.append("\n}")) !out.append("\n}"))
{ {
@ -1042,13 +1054,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
bool derived = fun->infallibleIsDefaultClassConstructor(cx); bool derived = fun->infallibleIsDefaultClassConstructor(cx);
if (derived && fun->isDerivedClassConstructor()) { if (derived && fun->isDerivedClassConstructor()) {
if (!out.append("(...args) {\n ") || if (!AppendPrelude() ||
!out.append("(...args) {\n ") ||
!out.append("super(...args);\n}")) !out.append("super(...args);\n}"))
{ {
return nullptr; return nullptr;
} }
} else { } else {
if (!out.append("() {\n ")) if (!AppendPrelude() ||
!out.append("() {\n "))
return nullptr; return nullptr;
if (!derived) { if (!derived) {
@ -1635,7 +1649,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
StringBuffer sb(cx); 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; return false;
if (args.length() > 1) { if (args.length() > 1) {
@ -1662,6 +1687,9 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
} }
} }
if (!sb.append('\n'))
return false;
// Remember the position of ")". // Remember the position of ")".
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length())); Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')'); MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');

View file

@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
{ {
uint32_t begin = script->sourceStart(); uint32_t begin = script->sourceStart();
uint32_t end = script->sourceEnd(); uint32_t end = script->sourceEnd();
uint32_t preludeStart = script->preludeStart();
uint32_t lineno = script->lineno(); uint32_t lineno = script->lineno();
uint32_t column = script->column(); uint32_t column = script->column();
@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
packedFields = lazy->packedFields(); packedFields = lazy->packedFields();
MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(begin == lazy->begin());
MOZ_ASSERT(end == lazy->end()); MOZ_ASSERT(end == lazy->end());
MOZ_ASSERT(preludeStart == lazy->preludeStart());
MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(lineno == lazy->lineno());
MOZ_ASSERT(column == lazy->column()); MOZ_ASSERT(column == lazy->column());
// We can assert we have no inner functions because we don't // We can assert we have no inner functions because we don't
@ -255,7 +257,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
if (mode == XDR_DECODE) { if (mode == XDR_DECODE) {
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, 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 // As opposed to XDRLazyScript, we need to restore the runtime bits
// of the script, as we are trying to match the fact this function // of the script, as we are trying to match the fact this function
@ -517,7 +519,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>(); sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
} }
script = JSScript::Create(cx, options, sourceObject, 0, 0); script = JSScript::Create(cx, options, sourceObject, 0, 0, 0);
if (!script) if (!script)
return false; return false;
@ -600,6 +602,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
return false; return false;
if (!xdr->codeUint32(&script->sourceEnd_)) if (!xdr->codeUint32(&script->sourceEnd_))
return false; return false;
if (!xdr->codeUint32(&script->preludeStart_))
return false;
if (!xdr->codeUint32(&lineno) || if (!xdr->codeUint32(&lineno) ||
!xdr->codeUint32(&column) || !xdr->codeUint32(&column) ||
@ -930,6 +934,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
{ {
uint32_t begin; uint32_t begin;
uint32_t end; uint32_t end;
uint32_t preludeStart;
uint32_t lineno; uint32_t lineno;
uint32_t column; uint32_t column;
uint64_t packedFields; uint64_t packedFields;
@ -943,12 +948,14 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
begin = lazy->begin(); begin = lazy->begin();
end = lazy->end(); end = lazy->end();
preludeStart = lazy->preludeStart();
lineno = lazy->lineno(); lineno = lazy->lineno();
column = lazy->column(); column = lazy->column();
packedFields = lazy->packedFields(); packedFields = lazy->packedFields();
} }
if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
!xdr->codeUint32(&preludeStart) ||
!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
!xdr->codeUint64(&packedFields)) !xdr->codeUint64(&packedFields))
{ {
@ -957,7 +964,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
if (mode == XDR_DECODE) { if (mode == XDR_DECODE) {
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
packedFields, begin, end, lineno, column)); packedFields, begin, end, preludeStart, lineno, column));
if (!lazy) if (!lazy)
return false; return false;
fun->initLazyScript(lazy); fun->initLazyScript(lazy);
@ -1430,6 +1437,13 @@ JSScript::sourceData(JSContext* cx)
return scriptSource()->substring(cx, sourceStart(), sourceEnd()); return scriptSource()->substring(cx, sourceStart(), sourceEnd());
} }
JSFlatString*
JSScript::sourceDataWithPrelude(JSContext* cx)
{
MOZ_ASSERT(scriptSource()->hasSourceData());
return scriptSource()->substring(cx, preludeStart(), sourceEnd());
}
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
: cache_(nullptr), sourceChunk_() : cache_(nullptr), sourceChunk_()
{ {
@ -2428,7 +2442,8 @@ JSScript::initCompartment(ExclusiveContext* cx)
/* static */ JSScript* /* static */ JSScript*
JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, 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); MOZ_ASSERT(bufStart <= bufEnd);
@ -2450,6 +2465,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
script->setSourceObject(sourceObject); script->setSourceObject(sourceObject);
script->sourceStart_ = bufStart; script->sourceStart_ = bufStart;
script->sourceEnd_ = bufEnd; script->sourceEnd_ = bufEnd;
script->preludeStart_ = preludeStart;
return script; return script;
} }
@ -3382,7 +3398,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
.setNoScriptRval(src->noScriptRval()) .setNoScriptRval(src->noScriptRval())
.setVersion(src->getVersion()); .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* JSScript*
@ -3932,7 +3949,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
} }
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, 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), : script_(nullptr),
function_(fun), function_(fun),
enclosingScope_(nullptr), enclosingScope_(nullptr),
@ -3941,6 +3959,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
packedFields_(packedFields), packedFields_(packedFields),
begin_(begin), begin_(begin),
end_(end), end_(end),
preludeStart_(preludeStart),
lineno_(lineno), lineno_(lineno),
column_(column) column_(column)
{ {
@ -3990,7 +4009,7 @@ LazyScript::maybeForwardedScriptSource() const
/* static */ LazyScript* /* static */ LazyScript*
LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
uint64_t packedFields, uint32_t begin, uint32_t end, 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 { union {
PackedView p; PackedView p;
@ -4018,7 +4037,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
cx->compartment()->scheduleDelazificationForDebugger(); 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* /* static */ LazyScript*
@ -4026,7 +4046,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
const frontend::AtomVector& closedOverBindings, const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions, Handle<GCVector<JSFunction*, 8>> innerFunctions,
JSVersion version, 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 { union {
PackedView p; PackedView p;
@ -4049,7 +4070,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
p.isDerivedClassConstructor = false; p.isDerivedClassConstructor = false;
p.needsHomeObject = 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) if (!res)
return nullptr; return nullptr;
@ -4070,7 +4092,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
HandleScript script, HandleScope enclosingScope, HandleScript script, HandleScope enclosingScope,
HandleScript enclosingScript, HandleScript enclosingScript,
uint64_t packedFields, uint32_t begin, uint32_t end, 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. // Dummy atom which is not a valid property name.
RootedAtom dummyAtom(cx, cx->names().comma); RootedAtom dummyAtom(cx, cx->names().comma);
@ -4079,7 +4101,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
// holding this lazy script. // holding this lazy script.
HandleFunction dummyFun = fun; 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) if (!res)
return nullptr; return nullptr;

View file

@ -575,10 +575,6 @@ class ScriptSource
introductionOffset_ = offset; introductionOffset_ = offset;
hasIntroductionOffset_ = true; hasIntroductionOffset_ = true;
} }
uint32_t parameterListEnd() const {
return parameterListEnd_;
}
}; };
class ScriptSourceHolder class ScriptSourceHolder
@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell
uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ 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 sourceStart_;
uint32_t sourceEnd_; uint32_t sourceEnd_;
uint32_t preludeStart_;
// Number of times the script has been called or has had backedges taken. // 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 // 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. // instead of private to suppress -Wunused-private-field compiler warnings.
protected: protected:
#if JS_BITS_PER_WORD == 32 #if JS_BITS_PER_WORD == 32
// Currently no padding is needed. uint32_t padding;
#endif #endif
// //
@ -1031,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell
static JSScript* Create(js::ExclusiveContext* cx, static JSScript* Create(js::ExclusiveContext* cx,
const JS::ReadOnlyCompileOptions& options, const JS::ReadOnlyCompileOptions& options,
js::HandleObject sourceObject, uint32_t sourceStart, js::HandleObject sourceObject, uint32_t sourceStart,
uint32_t sourceEnd); uint32_t sourceEnd, uint32_t preludeStart);
void initCompartment(js::ExclusiveContext* cx); void initCompartment(js::ExclusiveContext* cx);
@ -1178,6 +1184,10 @@ class JSScript : public js::gc::TenuredCell
return sourceEnd_; return sourceEnd_;
} }
size_t preludeStart() const {
return preludeStart_;
}
bool noScriptRval() const { bool noScriptRval() const {
return noScriptRval_; return noScriptRval_;
} }
@ -1501,6 +1511,7 @@ class JSScript : public js::gc::TenuredCell
bool mayReadFrameArgsDirectly(); bool mayReadFrameArgsDirectly();
JSFlatString* sourceData(JSContext* cx); JSFlatString* sourceData(JSContext* cx);
JSFlatString* sourceDataWithPrelude(JSContext* cx);
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
@ -1920,7 +1931,8 @@ class LazyScript : public gc::TenuredCell
// instead of private to suppress -Wunused-private-field compiler warnings. // instead of private to suppress -Wunused-private-field compiler warnings.
protected: protected:
#if JS_BITS_PER_WORD == 32 #if JS_BITS_PER_WORD == 32
uint32_t padding; // uint32_t padding;
// Currently no padding is needed.
#endif #endif
private: private:
@ -1960,20 +1972,25 @@ class LazyScript : public gc::TenuredCell
}; };
// Source location for the script. // Source location for the script.
// See the comment in JSScript for the details.
uint32_t begin_; uint32_t begin_;
uint32_t end_; 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 lineno_;
uint32_t column_; uint32_t column_;
LazyScript(JSFunction* fun, void* table, uint64_t packedFields, 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 // Create a LazyScript without initializing the closedOverBindings and the
// innerFunctions. To be GC-safe, the caller must initialize both vectors // innerFunctions. To be GC-safe, the caller must initialize both vectors
// with valid atoms and functions. // with valid atoms and functions.
static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun, static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
uint64_t packedData, uint32_t begin, uint32_t end, 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: public:
static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits; static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits;
@ -1985,7 +2002,7 @@ class LazyScript : public gc::TenuredCell
const frontend::AtomVector& closedOverBindings, const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions, Handle<GCVector<JSFunction*, 8>> innerFunctions,
JSVersion version, uint32_t begin, uint32_t end, 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 // Create a LazyScript and initialize the closedOverBindings and the
// innerFunctions with dummy values to be replaced in a later initialization // 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 script, HandleScope enclosingScope,
HandleScript enclosingScript, HandleScript enclosingScript,
uint64_t packedData, uint32_t begin, uint32_t end, 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); void initRuntimeFields(uint64_t packedFields);
@ -2173,6 +2190,9 @@ class LazyScript : public gc::TenuredCell
uint32_t end() const { uint32_t end() const {
return end_; return end_;
} }
uint32_t preludeStart() const {
return preludeStart_;
}
uint32_t lineno() const { uint32_t lineno() const {
return lineno_; return lineno_;
} }
@ -2199,7 +2219,8 @@ class LazyScript : public gc::TenuredCell
}; };
/* If this fails, add/remove padding within LazyScript. */ /* 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 struct ScriptAndCounts
{ {

View file

@ -318,6 +318,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
// Function constructor, this will be the first character in the function // Function constructor, this will be the first character in the function
// source. Otherwise, it will be the opening parenthesis of the arguments // source. Otherwise, it will be the opening parenthesis of the arguments
// list. // list.
uint32_t preludeStart;
uint32_t srcStart; uint32_t srcStart;
uint32_t srcBodyStart; uint32_t srcBodyStart;
bool strict; bool strict;
@ -1758,6 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator
if (!asmJSMetadata_) if (!asmJSMetadata_)
return false; return false;
asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin; asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end; asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
asmJSMetadata_->strict = parser_.pc->sc()->strict() && asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
@ -7049,6 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
TokenStream& tokenStream = m.tokenStream(); TokenStream& tokenStream = m.tokenStream();
tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand); tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
uint32_t preludeStart = tokenStream.currentToken().pos.begin;
*line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end); *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
TokenKind tk; TokenKind tk;
@ -7071,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
ParseContext* outerpc = m.parser().pc; ParseContext* outerpc = m.parser().pc;
Directives directives(outerpc); 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); SyncFunction, /* tryAnnexB = */ false);
if (!funbox) if (!funbox)
return false; return false;
@ -8054,7 +8057,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
return false; return false;
} }
uint32_t begin = metadata.srcStart; uint32_t begin = metadata.preludeStart;
uint32_t end = metadata.srcEndAfterCurly(); uint32_t end = metadata.srcEndAfterCurly();
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end)); Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
if (!src) if (!src)
@ -8085,7 +8088,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership ? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership; : SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership); SourceBufferHolder srcBuf(chars, end - begin, ownership);
if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing())) if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
return false; return false;
@ -8537,6 +8540,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded
return true; return true;
// See AsmJSMetadata comment as well as ModuleValidator::init(). // 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->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin;
asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end; asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict(); 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)); MOZ_ASSERT(IsAsmJSModule(fun));
const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS(); const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
uint32_t begin = metadata.srcStart; uint32_t begin = metadata.preludeStart;
uint32_t end = metadata.srcEndAfterCurly(); uint32_t end = metadata.srcEndAfterCurly();
ScriptSource* source = metadata.scriptSource.get(); ScriptSource* source = metadata.scriptSource.get();
@ -8843,17 +8847,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
if (addParenToLambda && fun->isLambda() && !out.append("(")) if (addParenToLambda && fun->isLambda() && !out.append("("))
return nullptr; return nullptr;
if (!out.append("function "))
return nullptr;
if (fun->explicitName() && !out.append(fun->explicitName()))
return nullptr;
bool haveSource = source->hasSourceData(); bool haveSource = source->hasSourceData();
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
return nullptr; return nullptr;
if (!haveSource) { if (!haveSource) {
if (!out.append("function "))
return nullptr;
if (fun->explicitName() && !out.append(fun->explicitName()))
return nullptr;
if (!out.append("() {\n [sourceless code]\n}")) if (!out.append("() {\n [sourceless code]\n}"))
return nullptr; return nullptr;
} else { } else {