Bug 1317400 - Part 1: Implement Function.prototype.toString revision proposal. r=till
authorTooru Fujisawa <arai_a@mac.com>
Sat, 04 Mar 2017 20:36:02 +0900
changeset 346029 dd076a9610d4ede1314d5d3f36870a68c6a1d322
parent 346028 5d5f51eff4380778908063d6fcd9bb9d73df1b11
child 346030 2e84f5f909ff1d1bfa1a0dc864951079be59facd
push id38387
push usercbook@mozilla.com
push dateMon, 06 Mar 2017 10:11:11 +0000
treeherderautoland@937f89775395 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1317400
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1317400 - Part 1: Implement Function.prototype.toString revision proposal. r=till
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
js/src/frontend/TokenStream.cpp
js/src/jit-test/tests/asm.js/testSource.js
js/src/jit-test/tests/basic/function-tosource-bug779694.js
js/src/jit-test/tests/basic/function-tosource-constructor.js
js/src/jit-test/tests/basic/function-tosource-getset.js
js/src/jit-test/tests/basic/testLet.js
js/src/jit-test/tests/debug/Script-gc-02.js
js/src/jit-test/tests/debug/Script-gc-03.js
js/src/jit-test/tests/debug/Script-sourceStart-04.js
js/src/jit-test/tests/debug/Source-text-02.js
js/src/jit-test/tests/debug/bug1338914.js
js/src/jit-test/tests/latin1/assorted.js
js/src/jsapi.cpp
js/src/jsfun.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/tests/ecma_2017/AsyncFunctions/toSource.js
js/src/tests/ecma_2017/AsyncFunctions/toString.js
js/src/tests/ecma_6/Generators/runtime.js
js/src/tests/js1_5/Scope/regress-185485.js
js/src/tests/js1_7/extensions/regress-354945-01.js
js/src/tests/js1_7/extensions/regress-354945-02.js
js/src/tests/js1_8_5/regress/regress-584355.js
js/src/wasm/AsmJS.cpp
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -58,17 +58,17 @@ class MOZ_STACK_CLASS BytecodeCompiler
   private:
     JSScript* compileScript(HandleObject environment, SharedContext* sc);
     bool checkLength();
     bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
     bool maybeCompressSource();
     bool canLazilyParse();
     bool createParser();
     bool createSourceAndParser(const Maybe<uint32_t>& parameterListEnd = Nothing());
-    bool createScript();
+    bool createScript(uint32_t preludeStart = 0);
     bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
     bool handleParseFailure(const Directives& newDirectives);
     bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
     bool maybeCompleteCompressSource();
 
     AutoKeepAtoms keepAtoms;
 
     JSContext* cx;
@@ -276,20 +276,21 @@ bool
 BytecodeCompiler::createSourceAndParser(const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
 {
     return createScriptSource(parameterListEnd) &&
            maybeCompressSource() &&
            createParser();
 }
 
 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;
 }
 
 bool
 BytecodeCompiler::emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext)
 {
     BytecodeEmitter::EmitterMode emitterMode =
         options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
@@ -491,17 +492,17 @@ BytecodeCompiler::compileStandaloneFunct
                                         asyncKind, directives, &newDirectives);
         if (!fn && !handleParseFailure(newDirectives))
             return false;
     } while (!fn);
 
     if (fn->pn_funbox->function()->isInterpreted()) {
         MOZ_ASSERT(fun == fn->pn_funbox->function());
 
-        if (!createScript())
+        if (!createScript(fn->pn_funbox->preludeStart))
             return false;
 
         Maybe<BytecodeEmitter> emitter;
         if (!emplaceEmitter(emitter, fn->pn_funbox))
             return false;
         if (!emitter->emitFunctionScript(fn->pn_body))
             return false;
     } else {
@@ -681,17 +682,18 @@ frontend::CompileLazyFunction(JSContext*
                                                   lazy->asyncKind());
     if (!pn)
         return false;
 
     RootedScriptSource sourceObject(cx, lazy->sourceObject());
     MOZ_ASSERT(sourceObject);
 
     Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
-                                                  lazy->begin(), lazy->end()));
+                                                  lazy->begin(), lazy->end(),
+                                                  lazy->preludeStart()));
     if (!script)
         return false;
 
     if (lazy->isLikelyConstructorWrapper())
         script->setLikelyConstructorWrapper();
     if (lazy->hasBeenCloned())
         script->setHasBeenCloned();
 
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -109,16 +109,18 @@ CreateScriptSourceObject(JSContext* cx, 
  */
 bool
 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. */
 bool
 IsKeyword(JSLinearString* str);
 
 /* Trace all GC things reachable from parser. Defined in Parser.cpp. */
 void
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7833,17 +7833,18 @@ BytecodeEmitter::emitFunction(ParseNode*
             Rooted<JSScript*> parent(cx, script);
             MOZ_ASSERT(parent->getVersion() == parser->options().version);
             MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors());
             const TransitiveCompileOptions& transitiveOptions = parser->options();
             CompileOptions options(cx, transitiveOptions);
 
             Rooted<JSObject*> sourceObject(cx, script->sourceObject());
             Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
-                                                          funbox->bufStart, funbox->bufEnd));
+                                                          funbox->bufStart, funbox->bufEnd,
+                                                          funbox->preludeStart));
             if (!script)
                 return false;
 
             BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
                                  pn->pn_pos, emitterMode);
             if (!bce2.init())
                 return false;
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -450,29 +450,31 @@ UsedNameTracker::rewind(RewindToken toke
     scriptCounter_ = token.scriptId;
     scopeCounter_ = token.scopeId;
 
     for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront())
         r.front().value().resetToScope(token.scriptId, token.scopeId);
 }
 
 FunctionBox::FunctionBox(JSContext* 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),
     enclosingScope_(nullptr),
     namedLambdaBindings_(nullptr),
     functionScopeBindings_(nullptr),
     extraVarScopeBindings_(nullptr),
     functionNode(nullptr),
     bufStart(0),
     bufEnd(0),
     startLine(1),
     startColumn(0),
+    preludeStart(preludeStart),
     length(0),
     generatorKindBits_(GeneratorKindAsBits(generatorKind)),
     asyncKindBits_(AsyncKindAsBits(asyncKind)),
     isGenexpLambda(false),
     hasDestructuringArgs(false),
     hasParameterExprs(false),
     hasDirectEvalInParameterExpr(false),
     hasDuplicateParameters(false),
@@ -861,33 +863,35 @@ Parser<ParseHandler>::newObjectBox(JSObj
 
     traceListHead = objbox;
 
     return objbox;
 }
 
 template <typename ParseHandler>
 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,
                                      bool tryAnnexB)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT_IF(tryAnnexB, !pc->sc()->strict());
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
      */
     FunctionBox* funbox =
-        alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
-                                options().extraWarningsOption, generatorKind, asyncKind);
+        alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart,
+                                inheritedDirectives, options().extraWarningsOption,
+                                generatorKind, asyncKind);
     if (!funbox) {
         ReportOutOfMemory(context);
         return nullptr;
     }
 
     traceListHead = funbox;
     if (fn)
         handler.setFunctionBox(fn, funbox);
@@ -2380,16 +2384,17 @@ Parser<SyntaxParseHandler>::finishFuncti
         return false;
     }
 
     FunctionBox* funbox = pc->functionBox();
     RootedFunction fun(context, funbox->function());
     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;
 
     // Flags that need to be copied into the JSScript when we do the full
     // parse.
     if (pc->sc()->strict())
         lazy->setStrict();
@@ -2433,27 +2438,54 @@ Parser<FullParseHandler>::standaloneFunc
                                              const Maybe<uint32_t>& parameterListEnd,
                                              GeneratorKind generatorKind,
                                              FunctionAsyncKind asyncKind,
                                              Directives inheritedDirectives,
                                              Directives* newDirectives)
 {
     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.newFunctionStatement();
     if (!fn)
         return null();
 
     ParseNode* argsbody = handler.newList(PNK_PARAMSBODY);
     if (!argsbody)
         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);
 
     ParseContext funpc(this, funbox, newDirectives);
     if (!funpc.init())
         return null();
     funpc.setIsStandaloneFunctionBody();
@@ -2461,17 +2493,16 @@ Parser<FullParseHandler>::standaloneFunc
     YieldHandling yieldHandling = GetYieldHandling(generatorKind);
     AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
     if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
                                          parameterListEnd, /* isStandaloneFunction = */ true))
     {
         return null();
     }
 
-    TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
     if (tt != TOK_EOF) {
         error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
         return null();
     }
 
     if (!FoldConstants(context, &fn, this))
@@ -3106,27 +3137,27 @@ Parser<ParseHandler>::functionArguments(
         return false;
     }
 
     return true;
 }
 
 template <>
 bool
-Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind,
-                                                bool tryAnnexB)
+Parser<FullParseHandler>::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
     // parse recorded the free variables of nested functions and their extents,
     // so we can skip over them after accounting for their free variables.
 
     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;
 
     LazyScript* lazy = fun->lazyScript();
     if (lazy->needsHomeObject())
         funbox->setNeedsHomeObject();
     if (lazy->isExprBody())
@@ -3153,18 +3184,18 @@ Parser<FullParseHandler>::skipLazyInnerF
     }
 #endif
 
     return true;
 }
 
 template <>
 bool
-Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind,
-                                                  bool tryAnnexB)
+Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart,
+                                                  FunctionSyntaxKind kind, bool tryAnnexB)
 {
     MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
                                                      TokenKind* ttp)
@@ -3230,29 +3261,30 @@ Parser<ParseHandler>::templateLiteral(Yi
 
         handler.addList(nodeList, pn);
     } while (tt == TOK_TEMPLATE_HEAD);
     return nodeList;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::functionDefinition(Node pn, InHandling inHandling,
+Parser<ParseHandler>::functionDefinition(Node pn, uint32_t preludeStart,
+                                         InHandling inHandling,
                                          YieldHandling yieldHandling, HandleAtom funName,
                                          FunctionSyntaxKind kind,
                                          GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                                          bool tryAnnexB /* = false */)
 {
     MOZ_ASSERT_IF(kind == Statement, funName);
 
     // 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.
     if (handler.canSkipLazyInnerFunctions()) {
-        if (!skipLazyInnerFunction(pn, kind, tryAnnexB))
+        if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB))
             return null();
         return pn;
     }
 
     RootedObject proto(context);
     if (generatorKind == StarGenerator || asyncKind == AsyncFunction) {
         // If we are off thread, the generator meta-objects have
         // already been created by js::StartOffThreadParseTask, so cx will not
@@ -3275,18 +3307,19 @@ Parser<ParseHandler>::functionDefinition
 
     TokenStream::Position start(keepAtoms);
     tokenStream.tell(&start);
 
     // Parse the inner function. The following is a loop as we may attempt to
     // 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;
         }
 
         // Return on error.
         if (tokenStream.hadError() || directives == newDirectives)
             return null();
 
@@ -3303,16 +3336,17 @@ Parser<ParseHandler>::functionDefinition
     }
 
     return pn;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
+                                                      uint32_t preludeStart,
                                                       InHandling inHandling,
                                                       YieldHandling yieldHandling,
                                                       FunctionSyntaxKind kind,
                                                       GeneratorKind generatorKind,
                                                       FunctionAsyncKind asyncKind,
                                                       bool tryAnnexB,
                                                       Directives inheritedDirectives,
                                                       Directives* newDirectives)
@@ -3336,24 +3370,25 @@ Parser<FullParseHandler>::trySyntaxParse
         TokenStream::Position position(keepAtoms);
         tokenStream.tell(&position);
         if (!parser->tokenStream.seek(position, tokenStream))
             return false;
 
         // 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
                 // rewound to just before we tried the syntax parse for
                 // correctness.
                 parser->clearAbortedSyntaxParse();
                 usedNames.rewind(token);
                 MOZ_ASSERT_IF(!parser->context->helperThread(),
@@ -3369,40 +3404,42 @@ Parser<FullParseHandler>::trySyntaxParse
             return false;
 
         // Update the end position of the parse node.
         pn->pn_pos.end = tokenStream.currentToken().pos.end;
         return true;
     } 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<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun,
+                                                        uint32_t preludeStart,
                                                         InHandling inHandling,
                                                         YieldHandling yieldHandling,
                                                         FunctionSyntaxKind kind,
                                                         GeneratorKind generatorKind,
                                                         FunctionAsyncKind asyncKind,
                                                         bool tryAnnexB,
                                                         Directives inheritedDirectives,
                                                         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 <typename ParseHandler>
 bool
 Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox,
+                                    uint32_t preludeStart,
                                     InHandling inHandling, YieldHandling yieldHandling,
                                     FunctionSyntaxKind kind, Directives inheritedDirectives,
                                     Directives* newDirectives)
 {
     // Note that it is possible for outerpc != this->pc, as we may be
     // attempting to syntax parse an inner function from an outer full
     // parser. In that case, outerpc is a ParseContext from the full parser
     // instead of the current top of the stack of the syntax parser.
@@ -3416,35 +3453,36 @@ Parser<ParseHandler>::innerFunction(Node
         return false;
 
     return leaveInnerFunction(outerpc);
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::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)
 {
     // Note that it is possible for outerpc != this->pc, as we may be
     // attempting to syntax parse an inner function from an outer full
     // 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 <typename ParseHandler>
 bool
 Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj)
 {
     Node cookedNode = noSubstitutionTaggedTemplate();
     if (!cookedNode)
@@ -3469,18 +3507,18 @@ Parser<FullParseHandler>::standaloneLazy
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     Node pn = handler.newFunctionStatement();
     if (!pn)
         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();
 
     Directives newDirectives = directives;
     ParseContext funpc(this, funbox, &newDirectives);
     if (!funpc.init())
         return null();
@@ -3657,18 +3695,18 @@ Parser<ParseHandler>::functionFormalPara
     handler.setEndPosition(pn, pos().end);
     handler.setFunctionBody(pn, body);
 
     return true;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
-                                   FunctionAsyncKind asyncKind)
+Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling,
+                                   DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
     // 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(),
@@ -3741,23 +3779,24 @@ Parser<ParseHandler>::functionStmt(Yield
             return null();
     }
 
     Node pn = handler.newFunctionStatement();
     if (!pn)
         return null();
 
     YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
-    return functionDefinition(pn, InAllowed, newYieldHandling, name, Statement, generatorKind,
-                              asyncKind, tryAnnexB);
+    return functionDefinition(pn, preludeStart, InAllowed, newYieldHandling, name, Statement,
+                              generatorKind, asyncKind, tryAnnexB);
 }
 
 template <typename ParseHandler>
 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));
 
     AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
     GeneratorKind generatorKind = NotGenerator;
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return null();
@@ -3785,18 +3824,18 @@ Parser<ParseHandler>::functionExpr(Invok
 
     Node pn = handler.newFunctionExpression();
     if (!pn)
         return null();
 
     if (invoked)
         pn = handler.setLikelyIIFE(pn);
 
-    return functionDefinition(pn, InAllowed, yieldHandling, name, Expression, generatorKind,
-                              asyncKind);
+    return functionDefinition(pn, preludeStart, InAllowed, yieldHandling, name, Expression,
+                              generatorKind, asyncKind);
 }
 
 /*
  * Return true if this node, known to be an unparenthesized string literal,
  * could be the string of a directive in a Directive Prologue. Directive
  * strings never contain escape sequences or line continuations.
  * isEscapeFreeStringLiteral, below, checks whether the node itself could be
  * a directive.
@@ -5310,25 +5349,25 @@ Parser<ParseHandler>::exportVariableStat
     if (!processExport(node))
         return null();
 
     return node;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin,
+Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
                                                 FunctionAsyncKind asyncKind /* = SyncFunction */)
 {
     if (!abortIfSyntaxParser())
         return null();
 
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
-    Node kid = functionStmt(YieldIsKeyword, NameRequired, asyncKind);
+    Node kid = functionStmt(preludeStart, YieldIsKeyword, NameRequired, asyncKind);
     if (!kid)
         return null();
 
     if (!checkExportedNameForFunction(kid))
         return null();
 
     Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
     if (!node)
@@ -5390,26 +5429,26 @@ Parser<ParseHandler>::exportLexicalDecla
     if (!processExport(node))
         return null();
 
     return node;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin,
-                                                           FunctionAsyncKind asyncKind
-                                                           /* = SyncFunction */)
+Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
+                                                       FunctionAsyncKind asyncKind
+                                                       /* = SyncFunction */)
 {
     if (!abortIfSyntaxParser())
         return null();
 
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
-    Node kid = functionStmt(YieldIsKeyword, AllowDefaultName, asyncKind);
+    Node kid = functionStmt(preludeStart, YieldIsKeyword, AllowDefaultName, asyncKind);
     if (!kid)
         return null();
 
     Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end));
     if (!node)
         return null();
 
     if (!processExport(node))
@@ -5484,26 +5523,27 @@ Parser<ParseHandler>::exportDefault(uint
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
 
     if (!checkExportedName(context->names().default_))
         return null();
 
     switch (tt) {
       case TOK_FUNCTION:
-        return exportDefaultFunctionDeclaration(begin);
+        return exportDefaultFunctionDeclaration(begin, pos().begin);
 
       case TOK_ASYNC: {
         TokenKind nextSameLine = TOK_EOF;
         if (!tokenStream.peekTokenSameLine(&nextSameLine))
             return null();
 
         if (nextSameLine == TOK_FUNCTION) {
+            uint32_t preludeStart = pos().begin;
             tokenStream.consumeKnownToken(TOK_FUNCTION);
-            return exportDefaultFunctionDeclaration(begin, AsyncFunction);
+            return exportDefaultFunctionDeclaration(begin, preludeStart, AsyncFunction);
         }
 
         tokenStream.ungetToken();
         return exportDefaultAssignExpr(begin);
       }
 
       case TOK_CLASS:
         return exportDefaultClassDeclaration(begin);
@@ -5539,26 +5579,27 @@ Parser<ParseHandler>::exportDeclaration(
 
       case TOK_LC:
         return exportClause(begin);
 
       case TOK_VAR:
         return exportVariableStatement(begin);
 
       case TOK_FUNCTION:
-        return exportFunctionDeclaration(begin);
+        return exportFunctionDeclaration(begin, pos().begin);
 
       case TOK_ASYNC: {
         TokenKind nextSameLine = TOK_EOF;
         if (!tokenStream.peekTokenSameLine(&nextSameLine))
             return null();
 
         if (nextSameLine == TOK_FUNCTION) {
+            uint32_t preludeStart = pos().begin;
             tokenStream.consumeKnownToken(TOK_FUNCTION);
-            return exportFunctionDeclaration(begin, AsyncFunction);
+            return exportFunctionDeclaration(begin, preludeStart, AsyncFunction);
         }
 
         error(JSMSG_DECLARATION_AFTER_EXPORT);
         return null();
       }
 
       case TOK_CLASS:
         return exportClassDeclaration(begin);
@@ -5650,17 +5691,17 @@ Parser<ParseHandler>::consequentOrAltern
         }
 
         ParseContext::Statement stmt(pc, StatementKind::Block);
         ParseContext::Scope scope(this);
         if (!scope.init(pc))
             return null();
 
         TokenPos funcPos = pos();
-        Node fun = functionStmt(yieldHandling, NameRequired);
+        Node fun = functionStmt(pos().begin, yieldHandling, NameRequired);
         if (!fun)
             return null();
 
         Node block = handler.newStatementList(funcPos);
         if (!block)
             return null();
 
         handler.addStatementToList(block, fun);
@@ -6563,17 +6604,17 @@ Parser<ParseHandler>::labeledItem(YieldH
         // Per 13.13.1 it's a syntax error if LabelledItem: FunctionDeclaration
         // is ever matched.  Per Annex B.3.2 that modifies this text, this
         // applies only to strict mode code.
         if (pc->sc()->strict()) {
             error(JSMSG_FUNCTION_LABEL);
             return null();
         }
 
-        return functionStmt(yieldHandling, NameRequired);
+        return functionStmt(pos().begin, yieldHandling, NameRequired);
     }
 
     tokenStream.ungetToken();
     return statement(yieldHandling);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
@@ -7037,17 +7078,17 @@ Parser<ParseHandler>::classDefinition(Yi
           case PropertyType::Constructor:
           case PropertyType::DerivedConstructor:
             funName = name;
             break;
           default:
             if (!tokenStream.isCurrentTokenType(TOK_RB))
                 funName = propAtom;
         }
-        Node fn = methodDefinition(propType, funName);
+        Node fn = methodDefinition(nameOffset, propType, funName);
         if (!fn)
             return null();
 
         handler.checkAndSetIsDirectRHSAnonFunction(fn);
 
         JSOp op = JSOpFromPropertyType(propType);
         if (!handler.addClassMethodDefinition(classMethods, propName, fn, op, isStatic))
             return null();
@@ -7425,18 +7466,19 @@ Parser<ParseHandler>::statementListItem(
         if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling))
             return lexicalDeclaration(yieldHandling, DeclarationKind::Let);
 
         if (tt == TOK_ASYNC) {
             TokenKind nextSameLine = TOK_EOF;
             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);
             }
         }
 
         if (next == TOK_COLON)
             return labeledStatement(yieldHandling);
 
         return expressionStatement(yieldHandling);
       }
@@ -7502,17 +7544,17 @@ Parser<ParseHandler>::statementListItem(
       // DebuggerStatement
       case TOK_DEBUGGER:
         return debuggerStatement();
 
       // Declaration[Yield]:
 
       //   HoistableDeclaration[?Yield, ~Default]
       case TOK_FUNCTION:
-        return functionStmt(yieldHandling, NameRequired);
+        return functionStmt(pos().begin, yieldHandling, NameRequired);
 
       //   ClassDeclaration[?Yield, ~Default]
       case TOK_CLASS:
         return classDefinition(yieldHandling, ClassStatement, NameRequired);
 
       //   LexicalDeclaration[In, ?Yield]
       //     LetOrConst BindingList[?In, ?Yield]
       case TOK_CONST:
@@ -7969,18 +8011,20 @@ Parser<ParseHandler>::assignExpr(InHandl
         bool isBlock = false;
         if (!tokenStream.peekToken(&next, TokenStream::Operand))
             return null();
         if (next == TOK_LC)
             isBlock = true;
 
         tokenStream.seek(start);
 
-        if (!tokenStream.peekToken(&next, TokenStream::Operand))
-            return null();
+        if (!tokenStream.getToken(&next, TokenStream::Operand))
+            return null();
+        uint32_t preludeStart = pos().begin;
+        tokenStream.ungetToken();
 
         FunctionAsyncKind asyncKind = SyncFunction;
 
         if (next == TOK_ASYNC) {
             tokenStream.consumeKnownToken(next, TokenStream::Operand);
 
             TokenKind nextSameLine = TOK_EOF;
             if (!tokenStream.peekTokenSameLine(&nextSameLine))
@@ -7992,17 +8036,17 @@ Parser<ParseHandler>::assignExpr(InHandl
                 asyncKind = AsyncFunction;
             }
         }
 
         Node pn = handler.newArrowFunction();
         if (!pn)
             return null();
 
-        Node arrowFunc = functionDefinition(pn, inHandling, yieldHandling, nullptr,
+        Node arrowFunc = functionDefinition(pn, preludeStart, inHandling, yieldHandling, nullptr,
                                             Arrow, NotGenerator, asyncKind);
         if (!arrowFunc)
             return null();
 
         if (isBlock) {
             // This arrow function could be a non-trailing member of a comma
             // expression or a semicolon terminating a full expression.  If so,
             // the next token is that comma/semicolon, gotten with None:
@@ -8306,18 +8350,18 @@ Parser<ParseHandler>::generatorComprehen
 
     RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression,
                                             StarGenerator, SyncFunction, proto));
     if (!fun)
         return null();
 
     // 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;
     genFunbox->initWithEnclosingParseContext(outerpc, Expression);
 
     ParseContext genpc(this, genFunbox, /* newDirectives = */ nullptr);
     if (!genpc.init())
         return null();
@@ -8339,22 +8383,24 @@ Parser<ParseHandler>::generatorComprehen
         return null();
 
     Node comp = comprehension(StarGenerator);
     if (!comp)
         return null();
 
     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)
         return null();
     if (!handler.prependInitialYield(body, generator))
         return null();
 
     if (!propagateFreeNamesAndMarkClosedOverBindings(pc->varScope()))
@@ -9535,17 +9581,17 @@ Parser<ParseHandler>::objectLiteral(Yiel
 
                 if (propType == PropertyType::Getter || propType == PropertyType::Setter) {
                     funName = prefixAccessorName(propType, propAtom);
                     if (!funName)
                         return null();
                 }
             }
 
-            Node fn = methodDefinition(propType, funName);
+            Node fn = methodDefinition(namePos.begin, propType, funName);
             if (!fn)
                 return null();
 
             handler.checkAndSetIsDirectRHSAnonFunction(fn);
 
             JSOp op = JSOpFromPropertyType(propType);
             if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
                 return null();
@@ -9562,17 +9608,18 @@ Parser<ParseHandler>::objectLiteral(Yiel
     }
 
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName)
+Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType,
+                                       HandleAtom funName)
 {
     FunctionSyntaxKind kind;
     switch (propType) {
       case PropertyType::Getter:
         kind = Getter;
         break;
 
       case PropertyType::GetterNoExpressionClosure:
@@ -9614,17 +9661,18 @@ Parser<ParseHandler>::methodDefinition(P
                                   : SyncFunction;
 
     YieldHandling yieldHandling = GetYieldHandling(generatorKind);
 
     Node pn = handler.newFunctionExpression();
     if (!pn)
         return null();
 
-    return functionDefinition(pn, InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
+    return functionDefinition(pn, preludeStart, InAllowed, yieldHandling, funName, kind,
+                              generatorKind, asyncKind);
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::tryNewTarget(Node &newTarget)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NEW));
 
@@ -9673,17 +9721,17 @@ Parser<ParseHandler>::primaryExpr(YieldH
                                   InvokedPrediction invoked /* = PredictUninvoked */)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
     if (!CheckRecursionLimit(context))
         return null();
 
     switch (tt) {
       case TOK_FUNCTION:
-        return functionExpr(invoked);
+        return functionExpr(pos().begin, invoked);
 
       case TOK_CLASS:
         return classDefinition(yieldHandling, ClassExpression, NameRequired);
 
       case TOK_LB:
         return arrayInitializer(yieldHandling, possibleError);
 
       case TOK_LC:
@@ -9743,18 +9791,19 @@ Parser<ParseHandler>::primaryExpr(YieldH
         }
 
         if (tt == TOK_ASYNC) {
             TokenKind nextSameLine = TOK_EOF;
             if (!tokenStream.peekTokenSameLine(&nextSameLine))
                 return null();
 
             if (nextSameLine == TOK_FUNCTION) {
+                uint32_t preludeStart = pos().begin;
                 tokenStream.consumeKnownToken(TOK_FUNCTION);
-                return functionExpr(PredictUninvoked, AsyncFunction);
+                return functionExpr(preludeStart, PredictUninvoked, AsyncFunction);
             }
         }
 
         Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
         if (!name)
             return null();
 
         return identifierReference(name);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1052,17 +1052,18 @@ class Parser final : public ParserBase, 
      */
     Node parse();
 
     /*
      * Allocate a new parsed object or function container from
      * 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);
 
     /*
      * Create a new function object given a name (which is optional if this is
      * a function expression).
      */
     JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind,
@@ -1120,18 +1121,19 @@ class Parser final : public ParserBase, 
 
     // Parse a function, given only its arguments and body. Used for lazily
     // parsed functions.
     Node standaloneLazyFunction(HandleFunction fun, bool strict,
                                 GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
 
     // 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
     // ParseContext is already on the stack.
     bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
                                          Node pn, FunctionSyntaxKind kind,
                                          const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing(),
                                          bool isStandaloneFunction = false);
@@ -1153,19 +1155,20 @@ class Parser final : public ParserBase, 
      * Parsers whose name has a '1' suffix leave the TokenStream state
      * pointing to the token one past the end of the parsed fragment.  For a
      * number of the parsers this is convenient and avoids a lot of
      * unnecessary ungetting and regetting of tokens.
      *
      * 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);
 
     Node blockStatement(YieldHandling yieldHandling,
                         unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
     Node doWhileStatement(YieldHandling yieldHandling);
     Node whileStatement(YieldHandling yieldHandling);
@@ -1207,22 +1210,22 @@ class Parser final : public ParserBase, 
 
     bool processExport(Node node);
     bool processExportFrom(Node node);
 
     Node exportFrom(uint32_t begin, Node specList);
     Node exportBatch(uint32_t begin);
     bool checkLocalExportNames(Node node);
     Node exportClause(uint32_t begin);
-    Node exportFunctionDeclaration(uint32_t begin,
+    Node exportFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
                                    FunctionAsyncKind asyncKind = SyncFunction);
     Node exportVariableStatement(uint32_t begin);
     Node exportClassDeclaration(uint32_t begin);
     Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind);
-    Node exportDefaultFunctionDeclaration(uint32_t begin,
+    Node exportDefaultFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
                                           FunctionAsyncKind asyncKind = SyncFunction);
     Node exportDefaultClassDeclaration(uint32_t begin);
     Node exportDefaultAssignExpr(uint32_t begin);
     Node exportDefault(uint32_t begin);
     Node exportDeclaration();
 
     Node expressionStatement(YieldHandling yieldHandling,
                              InvokedPrediction invoked = PredictUninvoked);
@@ -1305,25 +1308,26 @@ class Parser final : public ParserBase, 
                      TokenKind tt, PossibleError* possibleError,
                      InvokedPrediction invoked = PredictUninvoked);
     Node exprInParens(InHandling inHandling, YieldHandling yieldHandling,
                       TripledotHandling tripledotHandling, PossibleError* possibleError = nullptr);
 
     bool tryNewTarget(Node& newTarget);
     bool checkAndMarkSuperScope();
 
-    Node methodDefinition(PropertyType propType, HandleAtom funName);
+    Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
 
     /*
      * Additional JS parsers.
      */
     bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
                            Node funcpn);
 
-    Node functionDefinition(Node func, InHandling inHandling, YieldHandling yieldHandling,
+    Node functionDefinition(Node func, uint32_t preludeStart,
+                            InHandling inHandling, YieldHandling yieldHandling,
                             HandleAtom name, FunctionSyntaxKind kind,
                             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.
     enum FunctionBodyType { StatementListBody, ExpressionBody };
     Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
@@ -1403,24 +1407,26 @@ class Parser final : public ParserBase, 
     bool hasUsedFunctionSpecialName(HandlePropertyName name);
     bool declareFunctionArgumentsObject();
     bool declareFunctionThis();
     Node newInternalDotName(HandlePropertyName name);
     Node newThisName();
     Node newDotGeneratorName();
     bool declareDotGeneratorName();
 
-    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);
     bool finishFunctionScopes(bool isStandaloneFunction);
     bool finishFunction(bool isStandaloneFunction = false);
     bool leaveInnerFunction(ParseContext* outerpc);
 
     bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier);
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -445,16 +445,17 @@ class FunctionBox : public ObjectBox, pu
     void initWithEnclosingScope(Scope* enclosingScope);
 
   public:
     ParseNode*      functionNode;           /* back pointer used by asm.js for error messages */
     uint32_t        bufStart;
     uint32_t        bufEnd;
     uint32_t        startLine;
     uint32_t        startColumn;
+    uint32_t        preludeStart;
     uint16_t        length;
 
     uint8_t         generatorKindBits_;     /* The GeneratorKind of this function. */
     uint8_t         asyncKindBits_;         /* The FunctionAsyncKing of this function. */
 
     bool            isGenexpLambda:1;       /* lambda from generator expression */
     bool            hasDestructuringArgs:1; /* parameter list contains destructuring expression */
     bool            hasParameterExprs:1;    /* parameter list contains expressions */
@@ -474,18 +475,18 @@ class FunctionBox : public ObjectBox, pu
     bool            hasRest_:1;             /* has rest parameter */
     bool            isExprBody_:1;          /* arrow function with expression
                                              * body or expression closure:
                                              * function(x) x*x */
 
     FunctionContextFlags funCxFlags;
 
     FunctionBox(JSContext* 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<LexicalScope::Data*> namedLambdaBindings() {
         MOZ_ASSERT(context->keepAtoms);
         return MutableHandle<LexicalScope::Data*>::fromMarkedLocation(&namedLambdaBindings_);
     }
 
     MutableHandle<FunctionScope::Data*> functionScopeBindings() {
         MOZ_ASSERT(context->keepAtoms);
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -169,16 +169,22 @@ frontend::IsIdentifier(JSLinearString* s
 {
     JS::AutoCheckCannotGC nogc;
     return str->hasLatin1Chars()
            ? ::IsIdentifier(str->latin1Chars(nogc), str->length())
            : ::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)
 {
     return ::IsIdentifier(chars, length);
 }
 
 bool
 frontend::IsKeyword(JSLinearString* str)
 {
--- a/js/src/jit-test/tests/asm.js/testSource.js
+++ b/js/src/jit-test/tests/asm.js/testSource.js
@@ -27,40 +27,40 @@ assertEq(f0.toSource(), funcBody);
 
 var f0 = function() {
     "use asm";
     function g() {}
     return g;
 
 }
 
-funcBody1 = funcBody.replace('function f0','function ');
+funcBody1 = funcBody.replace('function f0','function');
 assertEq(f0.toString(), funcBody1);
 assertEq(f0.toSource(), '(' + funcBody1 + ')');
 
 var g = function g0() {
     "use asm";
     function g() {}
     return g;
 
 }
 
 funcBody2 = funcBody.replace('function f0', 'function g0');
 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})");
 }
 
 })();
 
 (function() {
 /*
  * ONE ARGUMENT
  */
@@ -86,40 +86,40 @@ assertEq(f1.toSource(), funcBody);
 
 f1 = function(glob) {
     "use asm";
     function g() {}
     return g;
 
 }
 
-funcBody1 = funcBody.replace('function f1', 'function ');
+funcBody1 = funcBody.replace('function f1', 'function');
 assertEq(f1.toString(), funcBody1);
 assertEq(f1.toSource(), '(' + funcBody1 + ')');
 
 var g = function g0(glob) {
     "use asm";
     function g() {}
     return g;
 
 }
 
 funcBody2 = funcBody.replace('function f1', 'function g0');
 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})");
 }
 
 })();
 
 
 (function() {
 /*
  * TWO ARGUMENTS
@@ -139,47 +139,47 @@ var funcBody =  'function f2(glob, ffi) 
     "use asm";\n\
     function g() {}\n\
     return g;\n\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 + ')');
 
 var g = function g0(glob, ffi) {
     "use asm";
     function g() {}
     return g;
 
 }
 
 var funcBody2 = funcBody.replace('function f2', 'function g0');
 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})");
 }
 
 })();
 
 
 (function() {
 /*
  * THREE ARGUMENTS
@@ -199,65 +199,65 @@ var funcBody =  'function f3(glob, ffi, 
     "use asm";\n\
     function g() {}\n\
     return g;\n\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 + ')');
 
 var g = function g0(glob, ffi, heap) {
     "use asm";
     function g() {}
     return g;
 
 }
 
 funcBody2 = funcBody.replace('function f3', 'function g0');
 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})");
 }
 
 })();
 
 /* Modules in "use strict" context */
 (function() {
 
 var funcSource =
-    `function (glob, ffi, heap) {
+    `function(glob, ffi, heap) {
         "use asm";
         function g() {}
         return g;
     }`;
 
 var f4 = eval("\"use strict\";\n(" + funcSource + ")");
 
 var expectedToString = funcSource;
-var expectedToSource = '(' + expectedToString + ')'
+var expectedToSource = '(' + expectedToString + ')';
 
 assertEq(f4.toString(), expectedToString);
 assertEq(f4.toSource(), expectedToSource);
 
 if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
     var f5 = eval("\"use strict\";\n(" + funcSource + ")");
     assertEq(isAsmJSModuleLoadedFromCache(f5), true);
     assertEq(f5.toString(), expectedToString);
--- a/js/src/jit-test/tests/basic/function-tosource-bug779694.js
+++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js
@@ -1,8 +1,8 @@
 // This test creates poorly compressible input, which tests certain paths in
 // source code compression.
 var x = "";
 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}");
--- 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}");
+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");
--- 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; }})");
--- a/js/src/jit-test/tests/basic/testLet.js
+++ b/js/src/jit-test/tests/basic/testLet.js
@@ -6,17 +6,17 @@ function test(str, arg, result)
 {
     arg = arg || 'ponies';
     if (arguments.length < 3)
         result = 'ponies';
 
     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);
         assertEq(got, expect);
     }
 
     // test reflection logic
     Reflect.parse(got);
--- a/js/src/jit-test/tests/debug/Script-gc-02.js
+++ b/js/src/jit-test/tests/debug/Script-gc-02.js
@@ -5,10 +5,10 @@ var dbg = Debugger(g);
 var arr = [];
 dbg.onDebuggerStatement = function (frame) { arr.push(frame.script); };
 g.eval("for (var i = 0; i < 10; i++) Function('debugger;')();");
 assertEq(arr.length, 10);
 
 gc();
 
 for (var i = 0; i < arr.length; i++)
-    assertEq(arr[i].lineCount, 3);
+    assertEq(arr[i].lineCount, 4);
 
--- a/js/src/jit-test/tests/debug/Script-gc-03.js
+++ b/js/src/jit-test/tests/debug/Script-gc-03.js
@@ -5,11 +5,11 @@ var dbg = Debugger(g);
 var arr = [];
 dbg.onDebuggerStatement = function (frame) { arr.push(frame.script); };
 g.eval("for (var i = 0; i < 100; i++) Function('debugger;')();");
 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();
--- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js
+++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js
@@ -15,11 +15,11 @@ function test(string, range) {
             assertEq(script.sourceLength, range[1]);
         }
     }
 
     g.eval(string);
 }
 
 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);
--- a/js/src/jit-test/tests/debug/Source-text-02.js
+++ b/js/src/jit-test/tests/debug/Source-text-02.js
@@ -1,13 +1,14 @@
 // Nested compilation units (say, an eval with in an eval) should have the
 // correct sources attributed to them.
 let g = newGlobal();
 let dbg = new Debugger(g);
 
+var text;
 var count = 0;
 dbg.onNewScript = function (script) {
     ++count;
     if (count % 2 == 0)
         assertEq(script.source.text, text);
 }
 
 g.eval("eval('" + (text = "") + "')");
--- a/js/src/jit-test/tests/debug/bug1338914.js
+++ b/js/src/jit-test/tests/debug/bug1338914.js
@@ -3,9 +3,9 @@
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 var scripts = dbg.findScripts();
 assertEq(scripts.length > 0, true);
 var fpScripts = scripts.filter(s => s.source.introductionType == "Function.prototype");
 assertEq(fpScripts.length, 1);
 var source = fpScripts[0].source;
-assertEq(source.text, "() {\n}");
+assertEq(source.text, "function () {\n}");
--- a/js/src/jit-test/tests/latin1/assorted.js
+++ b/js/src/jit-test/tests/latin1/assorted.js
@@ -7,23 +7,23 @@ assertEq(isLatin1(ast.body[0].id.name), 
 var ast = Reflect.parse("function f\u1200() { return 3; }");
 assertEq(ast.body[0].id.name, "f\u1200");
 
 // obj.toSource Latin1
 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))})");
 
 // XDR
 load(libdir + 'bytecode-cache.js');
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4314,34 +4314,29 @@ JS_GetFunctionScript(JSContext* cx, Hand
 /*
  * enclosingScope is a scope, if any (e.g. a WithScope).  If the scope is the
  * global scope, this must be null.
  *
  * enclosingEnv is an environment to use, if it's not the global.
  */
 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)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     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));
     if (!fun)
         return false;
 
     // Make sure the static scope chain matches up when we have a
     // non-syntactic scope.
@@ -4349,29 +4344,41 @@ CompileFunction(JSContext* cx, const Rea
                   enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
 
     if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
                                              Some(parameterListEnd), enclosingScope))
     {
         return false;
     }
 
+    // When function name is not valid identifier, generated function source
+    // in srcBuf doesn't have 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)
 {
     MOZ_ASSERT(out);
     MOZ_ASSERT(parameterListEnd);
 
     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++) {
         if (i != 0) {
             if (!out->append(", "))
                 return false;
         }
         if (!out->append(argnames[i], strlen(argnames[i])))
@@ -4398,25 +4405,43 @@ JS::CompileFunction(JSContext* cx, AutoO
                     const char* name, unsigned nargs, const char* const* argnames,
                     SourceBufferHolder& srcBuf, MutableHandleFunction fun)
 {
     RootedObject env(cx);
     RootedScope scope(cx);
     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, &parameterListEnd))
+    if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf,
+                             &funStr, &parameterListEnd))
+    {
         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)
 JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
                     const ReadOnlyCompileOptions& options,
                     const char* name, unsigned nargs, const char* const* argnames,
                     const char16_t* chars, size_t length, MutableHandleFunction fun)
 {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -835,18 +835,20 @@ CreateFunctionPrototype(JSContext* cx, J
         NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
                              enclosingEnv, nullptr, objectProto, AllocKind::FUNCTION,
                              SingletonObject);
     if (!functionProto_)
         return nullptr;
 
     RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
 
-    const char* rawSource = "() {\n}";
+    const char* rawSource = "function () {\n}";
     size_t sourceLen = strlen(rawSource);
+    size_t begin = 9;
+    MOZ_ASSERT(rawSource[begin] == '(');
     mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen));
     if (!source)
         return nullptr;
 
     ScriptSource* ss = cx->new_<ScriptSource>();
     if (!ss)
         return nullptr;
     ScriptSourceHolder ssHolder(ss);
@@ -861,18 +863,19 @@ CreateFunctionPrototype(JSContext* cx, J
         return nullptr;
     RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss));
     if (!sourceObject || !ScriptSourceObject::initFromOptions(cx, sourceObject, options))
         return nullptr;
 
     RootedScript script(cx, JSScript::Create(cx,
                                              options,
                                              sourceObject,
-                                             0,
-                                             ss->length()));
+                                             begin,
+                                             ss->length(),
+                                             0));
     if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
         return nullptr;
 
     functionProto->initScript(script);
     ObjectGroup* protoGroup = JSObject::getGroup(cx, functionProto);
     if (!protoGroup)
         return nullptr;
 
@@ -994,77 +997,89 @@ js::FunctionToString(JSContext* cx, Hand
                 !out.append("}"))
             {
                 return nullptr;
             }
             return out.finishString();
         }
     }
 
-    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->isAsync()) {
-        if (!out.append("async "))
-            return nullptr;
-    }
-    if (!fun->isArrow()) {
-        bool ok;
-        if (fun->isStarGenerator())
-            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<JSFlatString*> src(cx, JSScript::sourceData(cx, script));
+        Rooted<JSFlatString*> src(cx, JSScript::sourceDataWithPrelude(cx, script));
         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}"))
         {
             return nullptr;
         }
     } else {
         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) {
                 if (!out.append("[native code]"))
                     return nullptr;
             }
 
             if (!out.append("\n}"))
@@ -1634,17 +1649,28 @@ FunctionConstructor(JSContext* cx, const
     CompileOptions options(cx);
     options.setMutedErrors(mutedErrors)
            .setFileAndLine(filename, 1)
            .setNoScriptRval(false)
            .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
 
     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) {
         RootedString str(cx);
 
         // Steps 5-6, 9.
         unsigned n = args.length() - 1;
 
@@ -1661,16 +1687,19 @@ FunctionConstructor(JSContext* cx, const
             if (i < args.length() - 2) {
                 // Step 9.d.iii.
                 if (!sb.append(", "))
                     return false;
             }
         }
     }
 
+    if (!sb.append('\n'))
+        return false;
+
     // Remember the position of ")".
     Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
     MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
 
     if (!sb.append(FunctionConstructorMedialSigils))
         return false;
 
     if (args.length() > 0) {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -232,38 +232,40 @@ XDRRelazificationInfo(XDRState<mode>* xd
     MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
 
     JSContext* cx = xdr->cx();
 
     uint64_t packedFields;
     {
         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();
 
         if (mode == XDR_ENCODE) {
             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
             // relazify scripts with inner functions.  See
             // JSFunction::createScriptForLazilyInterpretedFunction.
             MOZ_ASSERT(lazy->numInnerFunctions() == 0);
         }
 
         if (!xdr->codeUint64(&packedFields))
             return false;
 
         if (mode == XDR_DECODE) {
             RootedScriptSource sourceObject(cx, &script->scriptSourceUnwrap());
             lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
-                                        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
             // has already been parsed and that it would need to be re-lazified.
             lazy->initRuntimeFields(packedFields);
         }
     }
 
@@ -538,17 +540,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
                 if (!sourceObject ||
                     !ScriptSourceObject::initFromOptions(cx, sourceObject, *options))
                 {
                     return false;
                 }
             }
         }
 
-        script = JSScript::Create(cx, *options, sourceObject, 0, 0);
+        script = JSScript::Create(cx, *options, sourceObject, 0, 0, 0);
         if (!script)
             return false;
 
         // Set the script in its function now so that inner scripts to be
         // decoded may iterate the static scope chain.
         if (fun)
             fun->initScript(script);
     } else {
@@ -627,16 +629,18 @@ js::XDRScript(XDRState<mode>* xdr, Handl
     if (scriptBits & (1 << OwnSource)) {
         if (!sourceObject->source()->performXDR<mode>(xdr))
             return false;
     }
     if (!xdr->codeUint32(&script->sourceStart_))
         return false;
     if (!xdr->codeUint32(&script->sourceEnd_))
         return false;
+    if (!xdr->codeUint32(&script->preludeStart_))
+        return false;
 
     if (!xdr->codeUint32(&lineno) ||
         !xdr->codeUint32(&column) ||
         !xdr->codeUint32(&nfixed) ||
         !xdr->codeUint32(&nslots))
     {
         return false;
     }
@@ -946,44 +950,47 @@ js::XDRLazyScript(XDRState<mode>* xdr, H
                   HandleScriptSource sourceObject, HandleFunction fun,
                   MutableHandle<LazyScript*> lazy)
 {
     JSContext* cx = xdr->cx();
 
     {
         uint32_t begin;
         uint32_t end;
+        uint32_t preludeStart;
         uint32_t lineno;
         uint32_t column;
         uint64_t packedFields;
 
         if (mode == XDR_ENCODE) {
             // Note: it's possible the LazyScript has a non-null script_ pointer
             // to a JSScript. We don't encode it: we can just delazify the
             // lazy script.
 
             MOZ_ASSERT(fun == lazy->functionNonDelazifying());
 
             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))
         {
             return false;
         }
 
         if (mode == XDR_DECODE) {
             lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
-                                        packedFields, begin, end, lineno, column));
+                                        packedFields, begin, end, preludeStart, lineno, column));
             if (!lazy)
                 return false;
             fun->initLazyScript(lazy);
         }
     }
 
     // Code closed-over bindings.
     if (!XDRLazyClosedOverBindings(xdr, lazy))
@@ -1446,16 +1453,23 @@ JSScript::loadSource(JSContext* cx, Scri
 
 /* static */ JSFlatString*
 JSScript::sourceData(JSContext* cx, HandleScript script)
 {
     MOZ_ASSERT(script->scriptSource()->hasSourceData());
     return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd());
 }
 
+/* static */ JSFlatString*
+JSScript::sourceDataWithPrelude(JSContext* cx, HandleScript script)
+{
+    MOZ_ASSERT(script->scriptSource()->hasSourceData());
+    return script->scriptSource()->substring(cx, script->preludeStart(), script->sourceEnd());
+}
+
 UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
   : cache_(nullptr), sourceChunk_()
 {
 }
 
 void
 UncompressedSourceCache::AutoHoldEntry::holdEntry(UncompressedSourceCache* cache,
                                                   const ScriptSourceChunk& sourceChunk)
@@ -2505,17 +2519,18 @@ ScriptDataSize(uint32_t nscopes, uint32_
 void
 JSScript::initCompartment(JSContext* cx)
 {
     compartment_ = cx->compartment();
 }
 
 /* static */ JSScript*
 JSScript::Create(JSContext* 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);
 
     RootedScript script(cx, Allocate<JSScript>(cx));
     if (!script)
         return nullptr;
 
     PodZero(script.get());
@@ -2527,16 +2542,17 @@ JSScript::Create(JSContext* cx, const Re
     script->treatAsRunOnce_ = options.isRunOnce;
 
     script->version = options.version;
     MOZ_ASSERT(script->getVersion() == options.version);     // assert that no overflow occurred
 
     script->setSourceObject(sourceObject);
     script->sourceStart_ = bufStart;
     script->sourceEnd_ = bufEnd;
+    script->preludeStart_ = preludeStart;
 
 #ifdef MOZ_VTUNE
     script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
 #endif
 
     return script;
 }
 
@@ -3473,17 +3489,18 @@ CreateEmptyScriptForClone(JSContext* cx,
     }
 
     CompileOptions options(cx);
     options.setMutedErrors(src->mutedErrors())
            .setSelfHostingMode(src->selfHosted())
            .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*
 js::CloneGlobalScript(JSContext* cx, ScopeKind scopeKind, HandleScript src)
 {
     MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
 
     RootedScript dst(cx, CreateEmptyScriptForClone(cx, src));
@@ -4025,25 +4042,27 @@ JSScript::formalIsAliased(unsigned argSl
 
 bool
 JSScript::formalLivesInArgumentsObject(unsigned argSlot)
 {
     return argsObjAliasesFormals() && !formalIsAliased(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),
     sourceObject_(nullptr),
     table_(table),
     packedFields_(packedFields),
     begin_(begin),
     end_(end),
+    preludeStart_(preludeStart),
     lineno_(lineno),
     column_(column)
 {
     MOZ_ASSERT(begin <= end);
 }
 
 void
 LazyScript::initScript(JSScript* script)
@@ -4083,17 +4102,17 @@ ScriptSource*
 LazyScript::maybeForwardedScriptSource() const
 {
     return UncheckedUnwrap(MaybeForwarded(sourceObject()))->as<ScriptSourceObject>().source();
 }
 
 /* static */ LazyScript*
 LazyScript::CreateRaw(JSContext* 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;
         uint64_t packed;
     };
 
     packed = packedFields;
 
@@ -4111,25 +4130,27 @@ LazyScript::CreateRaw(JSContext* cx, Han
     }
 
     LazyScript* res = Allocate<LazyScript>(cx);
     if (!res)
         return nullptr;
 
     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*
 LazyScript::Create(JSContext* cx, HandleFunction fun,
                    const frontend::AtomVector& closedOverBindings,
                    Handle<GCVector<JSFunction*, 8>> 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;
         uint64_t packedFields;
     };
 
     p.version = version;
     p.shouldDeclareArguments = false;
@@ -4143,17 +4164,18 @@ LazyScript::Create(JSContext* cx, Handle
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.hasDirectEval = false;
     p.isLikelyConstructorWrapper = false;
     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;
 
     JSAtom** resClosedOverBindings = res->closedOverBindings();
     for (size_t i = 0; i < res->numClosedOverBindings(); i++)
         resClosedOverBindings[i] = closedOverBindings[i];
 
     GCPtrFunction* resInnerFunctions = res->innerFunctions();
@@ -4164,26 +4186,27 @@ LazyScript::Create(JSContext* cx, Handle
     return res;
 }
 
 /* static */ LazyScript*
 LazyScript::Create(JSContext* cx, HandleFunction fun,
                    HandleScript script, HandleScope enclosingScope,
                    HandleScriptSource sourceObject,
                    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);
 
     // Dummy function which is not a valid function as this is the one which is
     // 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;
 
     // Fill with dummies, to be GC-safe after the initialization of the free
     // variables and inner functions.
     size_t i, num;
     JSAtom** closedOverBindings = res->closedOverBindings();
     for (i = 0, num = res->numClosedOverBindings(); i < num; i++)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -576,20 +576,16 @@ class ScriptSource
     }
     void setIntroductionOffset(uint32_t offset) {
         MOZ_ASSERT(!hasIntroductionOffset());
         MOZ_ASSERT(offset <= (uint32_t)INT32_MAX);
         introductionOffset_ = offset;
         hasIntroductionOffset_ = true;
     }
 
-    uint32_t parameterListEnd() const {
-        return parameterListEnd_;
-    }
-
     // Return wether an XDR encoder is present or not.
     bool hasEncoder() const { return bool(xdrEncoder_); }
 
     // Create a new XDR encoder, and encode the top-level JSScript. The result
     // of the encoding would be available in the |buffer| provided as argument,
     // as soon as |xdrFinalize| is called and all xdr function calls returned
     // successfully.
     bool xdrEncodeTopLevel(JSContext* cx, JS::TranscodeBuffer& buffer, HandleScript script);
@@ -880,19 +876,29 @@ class JSScript : public js::gc::TenuredC
     uint32_t        mainOffset_;/* offset of main entry point from code, after
                                    predef'ing prologue */
 
     uint32_t        nfixed_;    /* fixed frame slots */
     uint32_t        nslots_;    /* slots plus maximum stack depth */
 
     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_;
 
 #ifdef MOZ_VTUNE
     // Unique Method ID passed to the VTune profiler, or 0 if unset.
     // Allows attribution of different jitcode to the same source script.
     uint32_t        vtuneMethodId_;
     // Extra padding to maintain JSScript as a multiple of gc::CellSize.
     uint32_t        __vtune_unused_padding_;
 #endif
@@ -1052,28 +1058,28 @@ class JSScript : public js::gc::TenuredC
 
     bool hasRest_:1;
     bool isExprBody_:1;
 
     // Add padding so JSScript is gc::Cell aligned. Make padding protected
     // 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
 
     //
     // End of fields.  Start methods.
     //
 
   public:
     static JSScript* Create(JSContext* cx,
                             const JS::ReadOnlyCompileOptions& options,
                             js::HandleObject sourceObject, uint32_t sourceStart,
-                            uint32_t sourceEnd);
+                            uint32_t sourceEnd, uint32_t preludeStart);
 
     void initCompartment(JSContext* cx);
 
     // Three ways ways to initialize a JSScript. Callers of partiallyInit()
     // are responsible for notifying the debugger after successfully creating
     // any kind (function or other) of new JSScript.  However, callers of
     // fullyInitFromEmitter() do not need to do this.
     static bool partiallyInit(JSContext* cx, JS::Handle<JSScript*> script,
@@ -1214,16 +1220,20 @@ class JSScript : public js::gc::TenuredC
     uint32_t sourceStart() const {
         return sourceStart_;
     }
 
     uint32_t sourceEnd() const {
         return sourceEnd_;
     }
 
+    size_t preludeStart() const {
+        return preludeStart_;
+    }
+
     bool noScriptRval() const {
         return noScriptRval_;
     }
 
     bool strict() const {
         return strict_;
     }
 
@@ -1547,16 +1557,17 @@ class JSScript : public js::gc::TenuredC
         return bodyScope()->is<js::GlobalScope>();
     }
 
     // Returns true if the script may read formal arguments on the stack
     // directly, via lazy arguments or a rest parameter.
     bool mayReadFrameArgsDirectly();
 
     static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script);
+    static JSFlatString* sourceDataWithPrelude(JSContext* cx, JS::HandleScript script);
 
     static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
 
     void setSourceObject(JSObject* object);
     JSObject* sourceObject() const {
         return sourceObject_;
     }
     js::ScriptSourceObject& scriptSourceUnwrap() const;
@@ -1975,17 +1986,17 @@ class LazyScript : public gc::TenuredCel
 
     // Heap allocated table with any free variables or inner functions.
     void* table_;
 
     // Add padding so LazyScript is gc::Cell aligned. Make padding protected
     // instead of private to suppress -Wunused-private-field compiler warnings.
   protected:
 #if JS_BITS_PER_WORD == 32
-    uint32_t padding;
+    // Currently no padding is needed.
 #endif
 
   private:
     static const uint32_t NumClosedOverBindingsBits = 20;
     static const uint32_t NumInnerFunctionsBits = 20;
 
     struct PackedView {
         // Assorted bits that should really be in ScriptSourceObject.
@@ -2020,57 +2031,62 @@ class LazyScript : public gc::TenuredCel
     };
 
     union {
         PackedView p_;
         uint64_t packedFields_;
     };
 
     // 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(JSContext* 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;
     static const uint32_t NumInnerFunctionsLimit = 1 << NumInnerFunctionsBits;
 
     // Create a LazyScript and initialize closedOverBindings and innerFunctions
     // with the provided vectors.
     static LazyScript* Create(JSContext* cx, HandleFunction fun,
                               const frontend::AtomVector& closedOverBindings,
                               Handle<GCVector<JSFunction*, 8>> 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
     // phase.
     //
     // The "script" argument to this function can be null.  If it's non-null,
     // then this LazyScript should be associated with the given JSScript.
     //
     // The sourceObject and enclosingScope arguments may be null if the
     // enclosing function is also lazy.
     static LazyScript* Create(JSContext* cx, HandleFunction fun,
                               HandleScript script, HandleScope enclosingScope,
                               HandleScriptSource sourceObject,
                               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);
 
     static inline JSFunction* functionDelazifying(JSContext* cx, Handle<LazyScript*>);
     JSFunction* functionNonDelazifying() const {
         return function_;
     }
 
@@ -2241,16 +2257,19 @@ class LazyScript : public gc::TenuredCel
         return scriptSource()->filename();
     }
     uint32_t begin() const {
         return begin_;
     }
     uint32_t end() const {
         return end_;
     }
+    uint32_t preludeStart() const {
+        return preludeStart_;
+    }
     uint32_t lineno() const {
         return lineno_;
     }
     uint32_t column() const {
         return column_;
     }
 
     bool hasUncompiledEnclosingScript() const;
@@ -2267,17 +2286,18 @@ class LazyScript : public gc::TenuredCel
     }
 
     uint64_t packedFields() const {
         return packedFields_;
     }
 };
 
 /* 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
 {
     /* This structure is stored and marked from the JSRuntime. */
     JSScript* script;
     ScriptCounts scriptCounts;
 
     inline explicit ScriptAndCounts(JSScript* script);
--- a/js/src/tests/ecma_2017/AsyncFunctions/toSource.js
+++ b/js/src/tests/ecma_2017/AsyncFunctions/toSource.js
@@ -13,12 +13,12 @@ assertEq(async function (a, b, c) { awai
 
 assertEq((async (a, b, c) => await a).toSource(),
          "async (a, b, c) => await a");
 
 assertEq((async (a, b, c) => { await a; }).toSource(),
          "async (a, b, c) => { await a; }");
 
 assertEq({ async foo(a, b, c) { await a; } }.foo.toSource(),
-         "(async function foo(a, b, c) { await a; })");
+         "async foo(a, b, c) { await a; }");
 
 if (typeof reportCompare === "function")
     reportCompare(true, true);
--- a/js/src/tests/ecma_2017/AsyncFunctions/toString.js
+++ b/js/src/tests/ecma_2017/AsyncFunctions/toString.js
@@ -13,12 +13,12 @@ assertEq(async function (a, b, c) { awai
 
 assertEq((async (a, b, c) => await a).toString(),
          "async (a, b, c) => await a");
 
 assertEq((async (a, b, c) => { await a; }).toString(),
          "async (a, b, c) => { await a; }");
 
 assertEq({ async foo(a, b, c) { await a; } }.foo.toString(),
-         "async function foo(a, b, c) { await a; }");
+         "async foo(a, b, c) { await a; }");
 
 if (typeof reportCompare === "function")
     reportCompare(true, true);
--- a/js/src/tests/ecma_6/Generators/runtime.js
+++ b/js/src/tests/ecma_6/Generators/runtime.js
@@ -104,17 +104,17 @@ function TestGeneratorFunction() {
     assertTrue(GeneratorFunction('a', 'return a') instanceof GeneratorFunction);
     assertSyntaxError("GeneratorFunction('yield', 'return yield')");
     assertTrue(GeneratorFunction('with (x) return foo;') instanceof GeneratorFunction);
     assertSyntaxError("GeneratorFunction('\"use strict\"; with (x) return foo;')");
 
     // 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();
 
 
 function TestPerGeneratorPrototype() {
     assertNotEq((function*(){}).prototype, (function*(){}).prototype);
     assertNotEq((function*(){}).prototype, g.prototype);
     assertEq(typeof GeneratorFunctionPrototype, "object");
--- a/js/src/tests/js1_5/Scope/regress-185485.js
+++ b/js/src/tests/js1_5/Scope/regress-185485.js
@@ -89,17 +89,17 @@ addThis();
  * would newly define |g| in global scope -
  */
 with (x)
 {
   var g = function() {}
 }
 status = inSection(5);
 actual = x.g.toString();
-expect = (function () {}).toString();
+expect = (function() {}).toString();
 addThis();
 
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_7/extensions/regress-354945-01.js
+++ b/js/src/tests/js1_7/extensions/regress-354945-01.js
@@ -1,17 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //-----------------------------------------------------------------------------
 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;
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
 function test()
--- a/js/src/tests/js1_7/extensions/regress-354945-02.js
+++ b/js/src/tests/js1_7/extensions/regress-354945-02.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('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
   {
     for(t in (obj)) { }
   }
   catch(ex)
   {
--- a/js/src/tests/js1_8_5/regress/regress-584355.js
+++ b/js/src/tests/js1_8_5/regress/regress-584355.js
@@ -1,7 +1,7 @@
 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 ();")) ();
 }
 fun();
 reportCompare(expect, actual, "");
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -317,16 +317,17 @@ struct js::AsmJSMetadata : Metadata, Asm
     // deserialization contexts. Thus, they must be set explicitly using the
     // ambient Parser/ScriptSource after deserialization.
     //
     // srcStart refers to the offset in the ScriptSource to the beginning of
     // the asm.js module function. If the function has been created with the
     // 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;
     ScriptSourceHolder      scriptSource;
 
     uint32_t srcEndBeforeCurly() const {
         return srcStart + srcLength;
     }
@@ -1743,16 +1744,17 @@ class MOZ_STACK_CLASS ModuleValidator
             ReportOverRecursed(cx_);
     }
 
     bool init() {
         asmJSMetadata_ = cx_->new_<AsmJSMetadata>();
         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() &&
                                  !parser_.pc->sc()->hasExplicitUseStrict();
         asmJSMetadata_->scriptSource.reset(parser_.ss);
 
         if (!globalMap_.init() || !sigMap_.init() || !importMap_.init())
             return false;
@@ -7037,16 +7039,17 @@ CheckStatement(FunctionValidator& f, Par
 }
 
 static bool
 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;
     if (!tokenStream.getToken(&tk, TokenStream::Operand))
         return false;
     if (!TokenKindIsPossibleIdentifier(tk))
         return false;  // The regular parser will throw a SyntaxError, no need to m.fail.
 
@@ -7059,17 +7062,17 @@ ParseFunction(ModuleValidator& m, ParseN
         return false;
 
     RootedFunction& fun = m.dummyFunction();
     fun->setAtom(name);
     fun->setArgCount(0);
 
     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;
     funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);
 
     Directives newDirectives = directives;
     ParseContext funpc(&m.parser(), funbox, &newDirectives);
     if (!funpc.init())
@@ -8056,17 +8059,17 @@ HandleInstantiationFailure(JSContext* cx
     bool haveSource = source->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
         return false;
     if (!haveSource) {
         JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled");
         return false;
     }
 
-    uint32_t begin = metadata.srcStart;
+    uint32_t begin = metadata.preludeStart;
     uint32_t end = metadata.srcEndAfterCurly();
     Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
     if (!src)
         return false;
 
     RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
                                                name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
                                                TenuredObject));
@@ -8087,17 +8090,17 @@ HandleInstantiationFailure(JSContext* cx
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, src))
         return false;
 
     const char16_t* chars = stableChars.twoByteRange().begin().get();
     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;
 
     // Call the function we just recompiled.
     args.setCallee(ObjectValue(*fun));
     return InternalCallOrConstruct(cx, args, args.isConstructing() ? CONSTRUCT : NO_CONSTRUCT);
 }
 
@@ -8533,16 +8536,17 @@ LookupAsmJSModuleInCache(JSContext* cx, 
     ModuleCharsForLookup moduleChars;
     cursor = moduleChars.deserialize(cursor);
     if (!moduleChars.match(parser))
         return true;
 
     MOZ_RELEASE_ASSERT(cursor == entry.memory + entry.serializedSize);
 
     // 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();
     asmJSMetadata->scriptSource.reset(parser.ss);
 
     if (!parser.tokenStream.advance(asmJSMetadata->srcEndBeforeCurly()))
         return false;
 
@@ -8833,36 +8837,34 @@ js::IsAsmJSModuleLoadedFromCache(JSConte
 // asm.js toString/toSource support
 
 JSString*
 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();
 
     StringBuffer out(cx);
 
     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 {
         Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
         if (!src)
             return nullptr;
 
         if (!out.append(src))