js/src/frontend/BytecodeCompiler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 }

mercurial