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 375039 dd076a9610d4ede1314d5d3f36870a68c6a1d322
parent 375038 5d5f51eff4380778908063d6fcd9bb9d73df1b11
child 375040 2e84f5f909ff1d1bfa1a0dc864951079be59facd
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1317400
milestone54.0a1
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))