Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "frontend/BytecodeCompiler.h"
9 #include "jscntxt.h"
10 #include "jsscript.h"
12 #include "frontend/BytecodeEmitter.h"
13 #include "frontend/FoldConstants.h"
14 #include "frontend/NameFunctions.h"
15 #include "frontend/Parser.h"
16 #include "jit/AsmJSLink.h"
17 #include "vm/GlobalObject.h"
18 #include "vm/TraceLogging.h"
20 #include "jsobjinlines.h"
21 #include "jsscriptinlines.h"
23 #include "frontend/Parser-inl.h"
25 using namespace js;
26 using namespace js::frontend;
27 using mozilla::Maybe;
29 static bool
30 CheckLength(ExclusiveContext *cx, SourceBufferHolder &srcBuf)
31 {
32 // Note this limit is simply so we can store sourceStart and sourceEnd in
33 // JSScript as 32-bits. It could be lifted fairly easily, since the compiler
34 // is using size_t internally already.
35 if (srcBuf.length() > UINT32_MAX) {
36 if (cx->isJSContext())
37 JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, nullptr,
38 JSMSG_SOURCE_TOO_LONG);
39 return false;
40 }
41 return true;
42 }
44 static bool
45 SetDisplayURL(ExclusiveContext *cx, TokenStream &tokenStream, ScriptSource *ss)
46 {
47 if (tokenStream.hasDisplayURL()) {
48 if (!ss->setDisplayURL(cx, tokenStream.displayURL()))
49 return false;
50 }
51 return true;
52 }
54 static bool
55 SetSourceMap(ExclusiveContext *cx, TokenStream &tokenStream, ScriptSource *ss)
56 {
57 if (tokenStream.hasSourceMapURL()) {
58 if (!ss->setSourceMapURL(cx, tokenStream.sourceMapURL()))
59 return false;
60 }
61 return true;
62 }
64 static bool
65 CheckArgumentsWithinEval(JSContext *cx, Parser<FullParseHandler> &parser, HandleFunction fun)
66 {
67 if (fun->hasRest()) {
68 // It's an error to use |arguments| in a function that has a rest
69 // parameter.
70 parser.report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST);
71 return false;
72 }
74 // Force construction of arguments objects for functions that use
75 // |arguments| within an eval.
76 RootedScript script(cx, fun->getOrCreateScript(cx));
77 if (!script)
78 return false;
79 if (script->argumentsHasVarBinding()) {
80 if (!JSScript::argumentsOptimizationFailed(cx, script))
81 return false;
82 }
84 // It's an error to use |arguments| in a legacy generator expression.
85 if (script->isGeneratorExp() && script->isLegacyGenerator()) {
86 parser.report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
87 return false;
88 }
90 return true;
91 }
93 static bool
94 MaybeCheckEvalFreeVariables(ExclusiveContext *cxArg, HandleScript evalCaller, HandleObject scopeChain,
95 Parser<FullParseHandler> &parser,
96 ParseContext<FullParseHandler> &pc)
97 {
98 if (!evalCaller || !evalCaller->functionOrCallerFunction())
99 return true;
101 // Eval scripts are only compiled on the main thread.
102 JSContext *cx = cxArg->asJSContext();
104 // Watch for uses of 'arguments' within the evaluated script, both as
105 // free variables and as variables redeclared with 'var'.
106 RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
107 HandlePropertyName arguments = cx->names().arguments;
108 for (AtomDefnRange r = pc.lexdeps->all(); !r.empty(); r.popFront()) {
109 if (r.front().key() == arguments) {
110 if (!CheckArgumentsWithinEval(cx, parser, fun))
111 return false;
112 }
113 }
114 for (AtomDefnListMap::Range r = pc.decls().all(); !r.empty(); r.popFront()) {
115 if (r.front().key() == arguments) {
116 if (!CheckArgumentsWithinEval(cx, parser, fun))
117 return false;
118 }
119 }
121 // If the eval'ed script contains any debugger statement, force construction
122 // of arguments objects for the caller script and any other scripts it is
123 // transitively nested inside. The debugger can access any variable on the
124 // scope chain.
125 if (pc.sc->hasDebuggerStatement()) {
126 RootedObject scope(cx, scopeChain);
127 while (scope->is<ScopeObject>() || scope->is<DebugScopeObject>()) {
128 if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
129 RootedScript script(cx, scope->as<CallObject>().callee().getOrCreateScript(cx));
130 if (!script)
131 return false;
132 if (script->argumentsHasVarBinding()) {
133 if (!JSScript::argumentsOptimizationFailed(cx, script))
134 return false;
135 }
136 }
137 scope = scope->enclosingScope();
138 }
139 }
141 return true;
142 }
144 static inline bool
145 CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
146 {
147 return options.canLazilyParse &&
148 options.compileAndGo &&
149 !cx->compartment()->options().discardSource() &&
150 !options.sourceIsLazy &&
151 !(cx->compartment()->debugMode() &&
152 cx->compartment()->runtimeFromAnyThread()->debugHooks.newScriptHook);
153 }
155 static void
156 MarkFunctionsWithinEvalScript(JSScript *script)
157 {
158 // Mark top level functions in an eval script as being within an eval and,
159 // if applicable, inside a with statement.
161 if (!script->hasObjects())
162 return;
164 ObjectArray *objects = script->objects();
165 size_t start = script->innerObjectsStart();
167 for (size_t i = start; i < objects->length; i++) {
168 JSObject *obj = objects->vector[i];
169 if (obj->is<JSFunction>()) {
170 JSFunction *fun = &obj->as<JSFunction>();
171 if (fun->hasScript())
172 fun->nonLazyScript()->setDirectlyInsideEval();
173 else if (fun->isInterpretedLazy())
174 fun->lazyScript()->setDirectlyInsideEval();
175 }
176 }
177 }
179 void
180 frontend::MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
181 SourceBufferHolder &srcBuf)
182 {
183 JSSourceHandler listener = cx->runtime()->debugHooks.sourceHandler;
184 void *listenerData = cx->runtime()->debugHooks.sourceHandlerData;
186 if (listener) {
187 void *listenerTSData;
188 listener(options.filename(), options.lineno, srcBuf.get(), srcBuf.length(),
189 &listenerTSData, listenerData);
190 }
191 }
193 ScriptSourceObject *
194 frontend::CreateScriptSourceObject(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
195 {
196 ScriptSource *ss = cx->new_<ScriptSource>();
197 if (!ss)
198 return nullptr;
199 ScriptSourceHolder ssHolder(ss);
201 if (!ss->initFromOptions(cx, options))
202 return nullptr;
204 return ScriptSourceObject::create(cx, ss, options);
205 }
207 JSScript *
208 frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject scopeChain,
209 HandleScript evalCaller,
210 const ReadOnlyCompileOptions &options,
211 SourceBufferHolder &srcBuf,
212 JSString *source_ /* = nullptr */,
213 unsigned staticLevel /* = 0 */,
214 SourceCompressionTask *extraSct /* = nullptr */)
215 {
216 JS_ASSERT(srcBuf.get());
218 RootedString source(cx, source_);
220 js::TraceLogger *logger = nullptr;
221 if (cx->isJSContext())
222 logger = TraceLoggerForMainThread(cx->asJSContext()->runtime());
223 else
224 logger = TraceLoggerForCurrentThread();
225 uint32_t logId = js::TraceLogCreateTextId(logger, options);
226 js::AutoTraceLog scriptLogger(logger, logId);
227 js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileScript);
229 if (cx->isJSContext())
230 MaybeCallSourceHandler(cx->asJSContext(), options, srcBuf);
232 /*
233 * The scripted callerFrame can only be given for compile-and-go scripts
234 * and non-zero static level requires callerFrame.
235 */
236 JS_ASSERT_IF(evalCaller, options.compileAndGo);
237 JS_ASSERT_IF(evalCaller, options.forEval);
238 JS_ASSERT_IF(staticLevel != 0, evalCaller);
240 if (!CheckLength(cx, srcBuf))
241 return nullptr;
242 JS_ASSERT_IF(staticLevel != 0, !options.sourceIsLazy);
244 RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
245 if (!sourceObject)
246 return nullptr;
248 ScriptSource *ss = sourceObject->source();
250 SourceCompressionTask mysct(cx);
251 SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
253 if (!cx->compartment()->options().discardSource()) {
254 if (options.sourceIsLazy)
255 ss->setSourceRetrievable();
256 else if (!ss->setSourceCopy(cx, srcBuf, false, sct))
257 return nullptr;
258 }
260 bool canLazilyParse = CanLazilyParse(cx, options);
262 Maybe<Parser<SyntaxParseHandler> > syntaxParser;
263 if (canLazilyParse) {
264 syntaxParser.construct(cx, alloc, options, srcBuf.get(), srcBuf.length(),
265 /* foldConstants = */ false,
266 (Parser<SyntaxParseHandler> *) nullptr,
267 (LazyScript *) nullptr);
268 }
270 Parser<FullParseHandler> parser(cx, alloc, options, srcBuf.get(), srcBuf.length(),
271 /* foldConstants = */ true,
272 canLazilyParse ? &syntaxParser.ref() : nullptr, nullptr);
273 parser.sct = sct;
274 parser.ss = ss;
276 Directives directives(options.strictOption);
277 GlobalSharedContext globalsc(cx, scopeChain, directives, options.extraWarningsOption);
279 bool savedCallerFun = options.compileAndGo &&
280 evalCaller && evalCaller->functionOrCallerFunction();
281 Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), savedCallerFun,
282 options, staticLevel, sourceObject, 0,
283 srcBuf.length()));
284 if (!script)
285 return nullptr;
287 // We can specialize a bit for the given scope chain if that scope chain is the global object.
288 JSObject *globalScope =
289 scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : nullptr;
290 JS_ASSERT_IF(globalScope, globalScope->isNative());
291 JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
293 BytecodeEmitter::EmitterMode emitterMode =
294 options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
295 BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, options.forEval,
296 evalCaller, !!globalScope, options.lineno, emitterMode);
297 if (!bce.init())
298 return nullptr;
300 // Syntax parsing may cause us to restart processing of top level
301 // statements in the script. Use Maybe<> so that the parse context can be
302 // reset when this occurs.
303 Maybe<ParseContext<FullParseHandler> > pc;
305 pc.construct(&parser, (GenericParseContext *) nullptr, (ParseNode *) nullptr, &globalsc,
306 (Directives *) nullptr, staticLevel, /* bodyid = */ 0,
307 /* blockScopeDepth = */ 0);
308 if (!pc.ref().init(parser.tokenStream))
309 return nullptr;
311 /* If this is a direct call to eval, inherit the caller's strictness. */
312 if (evalCaller && evalCaller->strict())
313 globalsc.strict = true;
315 if (options.compileAndGo) {
316 if (source) {
317 /*
318 * Save eval program source in script->atoms[0] for the
319 * eval cache (see EvalCacheLookup in jsobj.cpp).
320 */
321 JSAtom *atom = AtomizeString(cx, source);
322 jsatomid _;
323 if (!atom || !bce.makeAtomIndex(atom, &_))
324 return nullptr;
325 }
327 if (evalCaller && evalCaller->functionOrCallerFunction()) {
328 /*
329 * An eval script in a caller frame needs to have its enclosing
330 * function captured in case it refers to an upvar, and someone
331 * wishes to decompile it while it's running.
332 */
333 JSFunction *fun = evalCaller->functionOrCallerFunction();
334 Directives directives(/* strict = */ fun->strict());
335 ObjectBox *funbox = parser.newFunctionBox(/* fn = */ nullptr, fun, pc.addr(),
336 directives, fun->generatorKind());
337 if (!funbox)
338 return nullptr;
339 bce.objectList.add(funbox);
340 }
341 }
343 bool canHaveDirectives = true;
344 for (;;) {
345 TokenKind tt = parser.tokenStream.peekToken(TokenStream::Operand);
346 if (tt <= TOK_EOF) {
347 if (tt == TOK_EOF)
348 break;
349 JS_ASSERT(tt == TOK_ERROR);
350 return nullptr;
351 }
353 TokenStream::Position pos(parser.keepAtoms);
354 parser.tokenStream.tell(&pos);
356 ParseNode *pn = parser.statement(canHaveDirectives);
357 if (!pn) {
358 if (parser.hadAbortedSyntaxParse()) {
359 // Parsing inner functions lazily may lead the parser into an
360 // unrecoverable state and may require starting over on the top
361 // level statement. Restart the parse; syntax parsing has
362 // already been disabled for the parser and the result will not
363 // be ambiguous.
364 parser.clearAbortedSyntaxParse();
365 parser.tokenStream.seek(pos);
367 // Destroying the parse context will destroy its free
368 // variables, so check if any deoptimization is needed.
369 if (!MaybeCheckEvalFreeVariables(cx, evalCaller, scopeChain, parser, pc.ref()))
370 return nullptr;
372 pc.destroy();
373 pc.construct(&parser, (GenericParseContext *) nullptr, (ParseNode *) nullptr,
374 &globalsc, (Directives *) nullptr, staticLevel, /* bodyid = */ 0,
375 script->bindings.numBlockScoped());
376 if (!pc.ref().init(parser.tokenStream))
377 return nullptr;
378 JS_ASSERT(parser.pc == pc.addr());
380 pn = parser.statement();
381 }
382 if (!pn) {
383 JS_ASSERT(!parser.hadAbortedSyntaxParse());
384 return nullptr;
385 }
386 }
388 // Accumulate the maximum block scope depth, so that EmitTree can assert
389 // when emitting JSOP_GETLOCAL that the local is indeed within the fixed
390 // part of the stack frame.
391 script->bindings.updateNumBlockScoped(pc.ref().blockScopeDepth);
393 if (canHaveDirectives) {
394 if (!parser.maybeParseDirective(/* stmtList = */ nullptr, pn, &canHaveDirectives))
395 return nullptr;
396 }
398 if (!FoldConstants(cx, &pn, &parser))
399 return nullptr;
401 if (!NameFunctions(cx, pn))
402 return nullptr;
404 if (!EmitTree(cx, &bce, pn))
405 return nullptr;
407 parser.handler.freeTree(pn);
408 }
410 if (!MaybeCheckEvalFreeVariables(cx, evalCaller, scopeChain, parser, pc.ref()))
411 return nullptr;
413 if (!SetDisplayURL(cx, parser.tokenStream, ss))
414 return nullptr;
416 if (!SetSourceMap(cx, parser.tokenStream, ss))
417 return nullptr;
419 /*
420 * Source map URLs passed as a compile option (usually via a HTTP source map
421 * header) override any source map urls passed as comment pragmas.
422 */
423 if (options.sourceMapURL()) {
424 if (!ss->setSourceMapURL(cx, options.sourceMapURL()))
425 return nullptr;
426 }
428 /*
429 * Nowadays the threaded interpreter needs a last return instruction, so we
430 * do have to emit that here.
431 */
432 if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
433 return nullptr;
435 // Global/eval script bindings are always empty (all names are added to the
436 // scope dynamically via JSOP_DEFFUN/VAR). They may have block-scoped
437 // locals, however, which are allocated to the fixed part of the stack
438 // frame.
439 InternalHandle<Bindings*> bindings(script, &script->bindings);
440 if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, nullptr,
441 pc.ref().blockScopeDepth))
442 return nullptr;
444 if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
445 return nullptr;
447 // Note that this marking must happen before we tell Debugger
448 // about the new script, in case Debugger delazifies the script's
449 // inner functions.
450 if (options.forEval)
451 MarkFunctionsWithinEvalScript(script);
453 bce.tellDebuggerAboutCompiledScript(cx);
455 if (sct && !extraSct && !sct->complete())
456 return nullptr;
458 return script;
459 }
461 bool
462 frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const jschar *chars, size_t length)
463 {
464 JS_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
466 CompileOptions options(cx, lazy->version());
467 options.setOriginPrincipals(lazy->originPrincipals())
468 .setFileAndLine(lazy->source()->filename(), lazy->lineno())
469 .setColumn(lazy->column())
470 .setCompileAndGo(true)
471 .setNoScriptRval(false)
472 .setSelfHostingMode(false);
474 js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
475 uint32_t logId = js::TraceLogCreateTextId(logger, options);
476 js::AutoTraceLog scriptLogger(logger, logId);
477 js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileLazy);
479 Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars, length,
480 /* foldConstants = */ true, nullptr, lazy);
482 uint32_t staticLevel = lazy->staticLevel(cx);
484 Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
485 JS_ASSERT(!lazy->isLegacyGenerator());
486 ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict(),
487 lazy->generatorKind());
488 if (!pn)
489 return false;
491 if (!NameFunctions(cx, pn))
492 return false;
494 RootedObject enclosingScope(cx, lazy->enclosingScope());
495 RootedScriptSource sourceObject(cx, lazy->sourceObject());
496 JS_ASSERT(sourceObject);
498 Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingScope, false,
499 options, staticLevel,
500 sourceObject, lazy->begin(), lazy->end()));
501 if (!script)
502 return false;
504 script->bindings = pn->pn_funbox->bindings;
506 if (lazy->directlyInsideEval())
507 script->setDirectlyInsideEval();
508 if (lazy->usesArgumentsAndApply())
509 script->setUsesArgumentsAndApply();
510 if (lazy->hasBeenCloned())
511 script->setHasBeenCloned();
513 BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval,
514 /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true,
515 options.lineno, BytecodeEmitter::LazyFunction);
516 if (!bce.init())
517 return false;
519 if (lazy->treatAsRunOnce())
520 bce.lazyRunOnceLambda = true;
522 return EmitFunctionScript(cx, &bce, pn->pn_body);
523 }
525 // Compile a JS function body, which might appear as the value of an event
526 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
527 static bool
528 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
529 const AutoNameVector &formals, SourceBufferHolder &srcBuf,
530 GeneratorKind generatorKind)
531 {
532 js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
533 uint32_t logId = js::TraceLogCreateTextId(logger, options);
534 js::AutoTraceLog scriptLogger(logger, logId);
535 js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileFunction);
537 // FIXME: make Function pass in two strings and parse them as arguments and
538 // ProgramElements respectively.
540 MaybeCallSourceHandler(cx, options, srcBuf);
542 if (!CheckLength(cx, srcBuf))
543 return false;
545 RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
546 if (!sourceObject)
547 return nullptr;
548 ScriptSource *ss = sourceObject->source();
550 SourceCompressionTask sct(cx);
551 JS_ASSERT(!options.sourceIsLazy);
552 if (!cx->compartment()->options().discardSource()) {
553 if (!ss->setSourceCopy(cx, srcBuf, true, &sct))
554 return false;
555 }
557 bool canLazilyParse = CanLazilyParse(cx, options);
559 Maybe<Parser<SyntaxParseHandler> > syntaxParser;
560 if (canLazilyParse) {
561 syntaxParser.construct(cx, &cx->tempLifoAlloc(),
562 options, srcBuf.get(), srcBuf.length(),
563 /* foldConstants = */ false,
564 (Parser<SyntaxParseHandler> *) nullptr,
565 (LazyScript *) nullptr);
566 }
568 JS_ASSERT(!options.forEval);
570 Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(),
571 options, srcBuf.get(), srcBuf.length(),
572 /* foldConstants = */ true,
573 canLazilyParse ? &syntaxParser.ref() : nullptr, nullptr);
574 parser.sct = &sct;
575 parser.ss = ss;
577 JS_ASSERT(fun);
578 JS_ASSERT(fun->isTenured());
580 fun->setArgCount(formals.length());
582 // Speculatively parse using the default directives implied by the context.
583 // If a directive is encountered (e.g., "use strict") that changes how the
584 // function should have been parsed, we backup and reparse with the new set
585 // of directives.
586 Directives directives(options.strictOption);
588 TokenStream::Position start(parser.keepAtoms);
589 parser.tokenStream.tell(&start);
591 ParseNode *fn;
592 while (true) {
593 Directives newDirectives = directives;
594 fn = parser.standaloneFunctionBody(fun, formals, generatorKind, directives, &newDirectives);
595 if (fn)
596 break;
598 if (parser.hadAbortedSyntaxParse()) {
599 // Hit some unrecoverable ambiguity during an inner syntax parse.
600 // Syntax parsing has now been disabled in the parser, so retry
601 // the parse.
602 parser.clearAbortedSyntaxParse();
603 } else {
604 if (parser.tokenStream.hadError() || directives == newDirectives)
605 return false;
607 // Assignment must be monotonic to prevent reparsing iloops
608 JS_ASSERT_IF(directives.strict(), newDirectives.strict());
609 JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
610 directives = newDirectives;
611 }
613 parser.tokenStream.seek(start);
614 }
616 if (!NameFunctions(cx, fn))
617 return false;
619 if (fn->pn_funbox->function()->isInterpreted()) {
620 JS_ASSERT(fun == fn->pn_funbox->function());
622 Rooted<JSScript*> script(cx, JSScript::Create(cx, js::NullPtr(), false, options,
623 /* staticLevel = */ 0, sourceObject,
624 /* sourceStart = */ 0, srcBuf.length()));
625 if (!script)
626 return false;
628 script->bindings = fn->pn_funbox->bindings;
630 /*
631 * The reason for checking fun->environment() below is that certain
632 * consumers of JS::CompileFunction, namely
633 * EventListenerManager::CompileEventHandlerInternal, passes in a
634 * nullptr environment. This compiled function is never used, but
635 * instead is cloned immediately onto the right scope chain.
636 */
637 BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script,
638 /* insideEval = */ false, /* evalCaller = */ js::NullPtr(),
639 fun->environment() && fun->environment()->is<GlobalObject>(),
640 options.lineno);
641 if (!funbce.init())
642 return false;
644 if (!EmitFunctionScript(cx, &funbce, fn->pn_body))
645 return false;
646 } else {
647 fun.set(fn->pn_funbox->function());
648 JS_ASSERT(IsAsmJSModuleNative(fun->native()));
649 }
651 if (!SetDisplayURL(cx, parser.tokenStream, ss))
652 return false;
654 if (!SetSourceMap(cx, parser.tokenStream, ss))
655 return false;
657 if (!sct.complete())
658 return false;
660 return true;
661 }
663 bool
664 frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun,
665 const ReadOnlyCompileOptions &options,
666 const AutoNameVector &formals, JS::SourceBufferHolder &srcBuf)
667 {
668 return CompileFunctionBody(cx, fun, options, formals, srcBuf, NotGenerator);
669 }
671 bool
672 frontend::CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun,
673 const ReadOnlyCompileOptions &options, const AutoNameVector &formals,
674 JS::SourceBufferHolder &srcBuf)
675 {
676 return CompileFunctionBody(cx, fun, options, formals, srcBuf, StarGenerator);
677 }