/*static*/ JSBool ParallelArrayObject::constructHelper(JSContext *cx, MutableHandleFunction ctor, CallArgs &args0) { RootedObject result(cx, newInstance(cx)); if (!result) return false; if (cx->typeInferenceEnabled()) { jsbytecode *pc; RootedScript script(cx, cx->stack.currentScript(&pc)); if (script) { if (ctor->nonLazyScript()->shouldCloneAtCallsite) { ctor.set(CloneFunctionAtCallsite(cx, ctor, script, pc)); if (!ctor) return false; } // Create the type object for the PA. Add in the current // properties as definite properties if this type object is newly // created. To tell if it is newly created, we check whether it // has any properties yet or not, since any returned type object // must have been created by this same C++ code and hence would // already have properties if it had been returned before. types::TypeObject *paTypeObject = types::TypeScript::InitObject(cx, script, pc, JSProto_ParallelArray); if (!paTypeObject) return false; if (paTypeObject->getPropertyCount() == 0 && !paTypeObject->unknownProperties()) { if (!paTypeObject->addDefiniteProperties(cx, result)) return false; // addDefiniteProperties() above should have added one // property for each of the fixed slots: JS_ASSERT(paTypeObject->getPropertyCount() == NumFixedSlots); } result->setType(paTypeObject); } } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, args0.length(), &args)) return false; args.setCallee(ObjectValue(*ctor)); args.setThis(ObjectValue(*result)); for (uint32_t i = 0; i < args0.length(); i++) args[i] = args0[i]; if (!Invoke(cx, args)) return false; args0.rval().setObject(*result); return true; }
bool XDRState<mode>::codeFunction(MutableHandleFunction objp) { if (mode == XDR_DECODE) objp.set(nullptr); else MOZ_ASSERT(objp->nonLazyScript()->enclosingScope()->is<GlobalScope>()); if (!VersionCheck(this)) return false; RootedScope scope(cx(), &cx()->global()->emptyGlobalScope()); return XDRInterpretedFunction(this, scope, nullptr, objp); }
bool XDRState<mode>::codeFunction(MutableHandleFunction objp) { if (mode == XDR_DECODE) objp.set(nullptr); if (!VersionCheck(this)) return false; RootedObject staticLexical(cx(), &cx()->global()->lexicalScope().staticBlock()); return XDRInterpretedFunction(this, staticLexical, nullptr, objp); }
bool XDRState<mode>::codeFunction(MutableHandleFunction funp) { if (mode == XDR_DECODE) funp.set(nullptr); else MOZ_ASSERT(funp->nonLazyScript()->enclosingScope()->is<GlobalScope>()); if (!VersionCheck(this)) { postProcessContextErrors(cx()); return false; } RootedScope scope(cx(), &cx()->global()->emptyGlobalScope()); if (!XDRInterpretedFunction(this, scope, nullptr, funp)) { postProcessContextErrors(cx()); funp.set(nullptr); return false; } return true; }
// Compile a JS function body, which might appear as the value of an event // handler attribute in an HTML <INPUT> tag, or in a Function() constructor. bool frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options, const AutoNameVector &formals, const jschar *chars, size_t length) { // FIXME: make Function pass in two strings and parse them as arguments and // ProgramElements respectively. SkipRoot skip(cx, &chars); MaybeCallSourceHandler(cx, options, chars, length); if (!CheckLength(cx, length)) return false; ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals()); if (!ss) return false; if (options.filename && !ss->setFilename(cx, options.filename)) return false; JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss)); if (!sourceObject) return false; SourceCompressionToken sct(cx); JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE); if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) { if (!ss->setSourceCopy(cx, chars, length, true, &sct)) return false; } bool canLazilyParse = CanLazilyParse(cx, options); Maybe<Parser<SyntaxParseHandler> > syntaxParser; if (canLazilyParse) { syntaxParser.construct(cx, &cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ false, (Parser<SyntaxParseHandler> *) NULL, (LazyScript *) NULL); } JS_ASSERT(!options.forEval); Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ true, canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = &sct; parser.ss = ss; JS_ASSERT(fun); JS_ASSERT(fun->isTenured()); fun->setArgCount(formals.length()); // Speculatively parse using the default directives implied by the context. // If a directive is encountered (e.g., "use strict") that changes how the // function should have been parsed, we backup and reparse with the new set // of directives. Directives directives(options.strictOption); TokenStream::Position start(parser.keepAtoms); parser.tokenStream.tell(&start); ParseNode *fn; while (true) { Directives newDirectives = directives; fn = parser.standaloneFunctionBody(fun, formals, directives, &newDirectives); if (fn) break; if (parser.hadAbortedSyntaxParse()) { // Hit some unrecoverable ambiguity during an inner syntax parse. // Syntax parsing has now been disabled in the parser, so retry // the parse. parser.clearAbortedSyntaxParse(); } else { if (parser.tokenStream.hadError() || directives == newDirectives) return false; // Assignment must be monotonic to prevent reparsing iloops JS_ASSERT_IF(directives.strict(), newDirectives.strict()); JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS()); directives = newDirectives; } parser.tokenStream.seek(start); } if (!NameFunctions(cx, fn)) return false; if (fn->pn_funbox->function()->isInterpreted()) { JS_ASSERT(fun == fn->pn_funbox->function()); Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), false, options, /* staticLevel = */ 0, sourceObject, /* sourceStart = */ 0, length)); if (!script) return false; script->bindings = fn->pn_funbox->bindings; /* * The reason for checking fun->environment() below is that certain * consumers of JS::CompileFunction, namely * nsEventListenerManager::CompileEventHandlerInternal, passes in a * NULL environment. This compiled function is never used, but instead * is cloned immediately onto the right scope chain. */ BytecodeEmitter funbce(/* parent = */ NULL, &parser, fn->pn_funbox, script, /* insideEval = */ false, /* evalCaller = */ NullPtr(), fun->environment() && fun->environment()->is<GlobalObject>(), options.lineno); if (!funbce.init()) return false; if (!EmitFunctionScript(cx, &funbce, fn->pn_body)) return false; } else { fun.set(fn->pn_funbox->function()); JS_ASSERT(IsAsmJSModuleNative(fun->native())); } if (!SetSourceMap(cx, parser.tokenStream, ss)) return false; if (!sct.complete()) return false; return true; }
// Compile a JS function body, which might appear as the value of an event // handler attribute in an HTML <INPUT> tag, or in a Function() constructor. bool frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options, const AutoNameVector &formals, const jschar *chars, size_t length, bool isAsmJSRecompile) { SkipRoot skip(cx, &chars); if (!CheckLength(cx, length)) return false; ScriptSource *ss = cx->new_<ScriptSource>(); if (!ss) return false; if (options.filename && !ss->setFilename(cx, options.filename)) return false; JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss)); if (!sourceObject) return false; SourceCompressionToken sct(cx); JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE); if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) { if (!ss->setSourceCopy(cx, chars, length, true, &sct)) return false; } bool canLazilyParse = CanLazilyParse(cx, options); Maybe<Parser<SyntaxParseHandler> > syntaxParser; if (canLazilyParse) { syntaxParser.construct(cx, options, chars, length, /* foldConstants = */ false, (Parser<SyntaxParseHandler> *) NULL, (LazyScript *) NULL); } JS_ASSERT(!options.forEval); Parser<FullParseHandler> parser(cx, options, chars, length, /* foldConstants = */ true, canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = &sct; JS_ASSERT(fun); JS_ASSERT(fun->isTenured()); fun->setArgCount(formals.length()); /* FIXME: make Function format the source for a function definition. */ ParseNode *fn = CodeNode::create(PNK_FUNCTION, &parser.handler); if (!fn) return false; fn->pn_body = NULL; fn->pn_funbox = NULL; fn->pn_cookie.makeFree(); ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, &parser.handler); if (!argsbody) return false; argsbody->setOp(JSOP_NOP); argsbody->makeEmpty(); fn->pn_body = argsbody; Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), false, options, /* staticLevel = */ 0, sourceObject, /* sourceStart = */ 0, length)); if (!script) return false; // If the context is strict, immediately parse the body in strict // mode. Otherwise, we parse it normally. If we see a "use strict" // directive, we backup and reparse it as strict. TokenStream::Position start(parser.keepAtoms); parser.tokenStream.tell(&start); bool strict = StrictModeFromContext(cx); bool becameStrict; FunctionBox *funbox; ParseNode *pn; while (true) { pn = parser.standaloneFunctionBody(fun, formals, script, fn, &funbox, strict, &becameStrict); if (pn) break; if (parser.hadAbortedSyntaxParse()) { // Hit some unrecoverable ambiguity during an inner syntax parse. // Syntax parsing has now been disabled in the parser, so retry // the parse. parser.clearAbortedSyntaxParse(); } else { // If the function became strict, reparse in strict mode. if (strict || !becameStrict || parser.tokenStream.hadError()) return false; strict = true; } parser.tokenStream.seek(start); } if (!NameFunctions(cx, pn)) return false; if (fn->pn_body) { JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY)); fn->pn_body->append(pn); fn->pn_body->pn_pos = pn->pn_pos; pn = fn->pn_body; } bool generateBytecode = true; #ifdef JS_ION JS_ASSERT_IF(isAsmJSRecompile, fn->pn_funbox->useAsm); if (fn->pn_funbox->useAsm && !isAsmJSRecompile) { RootedFunction moduleFun(cx); if (!CompileAsmJS(cx, parser.tokenStream, fn, options, ss, /* bufStart = */ 0, /* bufEnd = */ length, &moduleFun)) return false; if (moduleFun) { funbox->object = moduleFun; fun.set(moduleFun); // replace the existing function with the LinkAsmJS native generateBytecode = false; } } #endif if (generateBytecode) { /* * The reason for checking fun->environment() below is that certain * consumers of JS::CompileFunction, namely * nsEventListenerManager::CompileEventHandlerInternal, passes in a * NULL environment. This compiled function is never used, but instead * is cloned immediately onto the right scope chain. */ BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* insideEval = */ false, /* evalCaller = */ NullPtr(), fun->environment() && fun->environment()->is<GlobalObject>(), options.lineno); if (!funbce.init()) return false; if (!EmitFunctionScript(cx, &funbce, pn)) return false; } if (!SetSourceMap(cx, parser.tokenStream, ss, script)) return false; if (!sct.complete()) return false; return true; }
// Compile a JS function body, which might appear as the value of an event // handler attribute in an HTML <INPUT> tag, or in a Function() constructor. bool frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options, const AutoNameVector &formals, const jschar *chars, size_t length, bool isAsmJSRecompile) { if (!CheckLength(cx, length)) return false; ScriptSource *ss = cx->new_<ScriptSource>(); if (!ss) return false; if (options.filename && !ss->setFilename(cx, options.filename)) return false; ScriptSourceHolder ssh(ss); SourceCompressionToken sct(cx); JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE); if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) { if (!ss->setSourceCopy(cx, chars, length, true, &sct)) return false; } options.setCompileAndGo(false); Parser<FullParseHandler> parser(cx, options, chars, length, /* foldConstants = */ true); if (!parser.init()) return false; parser.sct = &sct; JS_ASSERT(fun); fun->setArgCount(formals.length()); /* FIXME: make Function format the source for a function definition. */ ParseNode *fn = CodeNode::create(PNK_FUNCTION, &parser.handler); if (!fn) return false; fn->pn_body = NULL; fn->pn_funbox = NULL; fn->pn_cookie.makeFree(); ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, &parser.handler); if (!argsbody) return false; argsbody->setOp(JSOP_NOP); argsbody->makeEmpty(); fn->pn_body = argsbody; Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), false, options, /* staticLevel = */ 0, ss, /* sourceStart = */ 0, length)); if (!script) return false; // If the context is strict, immediately parse the body in strict // mode. Otherwise, we parse it normally. If we see a "use strict" // directive, we backup and reparse it as strict. TokenStream::Position start; parser.tokenStream.tell(&start); bool initiallyStrict = StrictModeFromContext(cx); bool becameStrict; FunctionBox *funbox; ParseNode *pn = parser.standaloneFunctionBody(fun, formals, script, fn, &funbox, initiallyStrict, &becameStrict); if (!pn) { if (initiallyStrict || !becameStrict || parser.tokenStream.hadError()) return false; // Reparse in strict mode. parser.tokenStream.seek(start); pn = parser.standaloneFunctionBody(fun, formals, script, fn, &funbox, /* strict = */ true); if (!pn) return false; } if (!NameFunctions(cx, pn)) return false; if (fn->pn_body) { JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY)); fn->pn_body->append(pn); fn->pn_body->pn_pos = pn->pn_pos; pn = fn->pn_body; } bool generateBytecode = true; #ifdef JS_ION JS_ASSERT_IF(isAsmJSRecompile, fn->pn_funbox->useAsm); if (fn->pn_funbox->useAsm && !isAsmJSRecompile) { RootedFunction moduleFun(cx); if (!CompileAsmJS(cx, parser.tokenStream, fn, options, ss, /* bufStart = */ 0, /* bufEnd = */ length, &moduleFun)) return false; if (moduleFun) { funbox->object = moduleFun; fun.set(moduleFun); // replace the existing function with the LinkAsmJS native generateBytecode = false; } } #endif if (generateBytecode) { BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ false, options.lineno); if (!funbce.init()) return false; if (!EmitFunctionScript(cx, &funbce, pn)) return false; } if (!SetSourceMap(cx, parser.tokenStream, ss, script)) return false; if (!sct.complete()) return false; return true; }
// Compile a JS function body, which might appear as the value of an event // handler attribute in an HTML <INPUT> tag, or in a Function() constructor. static bool CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options, const AutoNameVector &formals, SourceBufferHolder &srcBuf, HandleObject enclosingScope, GeneratorKind generatorKind) { js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime()); uint32_t logId = js::TraceLogCreateTextId(logger, options); js::AutoTraceLog scriptLogger(logger, logId); js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileFunction); // FIXME: make Function pass in two strings and parse them as arguments and // ProgramElements respectively. if (!CheckLength(cx, srcBuf)) return false; RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options)); if (!sourceObject) return false; ScriptSource *ss = sourceObject->source(); SourceCompressionTask sct(cx); MOZ_ASSERT(!options.sourceIsLazy); if (!cx->compartment()->options().discardSource()) { if (!ss->setSourceCopy(cx, srcBuf, true, &sct)) return false; } bool canLazilyParse = CanLazilyParse(cx, options); Maybe<Parser<SyntaxParseHandler> > syntaxParser; if (canLazilyParse) { syntaxParser.emplace(cx, &cx->tempLifoAlloc(), options, srcBuf.get(), srcBuf.length(), /* foldConstants = */ false, (Parser<SyntaxParseHandler> *) nullptr, (LazyScript *) nullptr); } MOZ_ASSERT(!options.forEval); Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, srcBuf.get(), srcBuf.length(), /* foldConstants = */ true, canLazilyParse ? syntaxParser.ptr() : nullptr, nullptr); parser.sct = &sct; parser.ss = ss; MOZ_ASSERT(fun); MOZ_ASSERT(fun->isTenured()); fun->setArgCount(formals.length()); // Speculatively parse using the default directives implied by the context. // If a directive is encountered (e.g., "use strict") that changes how the // function should have been parsed, we backup and reparse with the new set // of directives. Directives directives(options.strictOption); TokenStream::Position start(parser.keepAtoms); parser.tokenStream.tell(&start); ParseNode *fn; while (true) { Directives newDirectives = directives; fn = parser.standaloneFunctionBody(fun, formals, generatorKind, directives, &newDirectives); if (fn) break; if (parser.hadAbortedSyntaxParse()) { // Hit some unrecoverable ambiguity during an inner syntax parse. // Syntax parsing has now been disabled in the parser, so retry // the parse. parser.clearAbortedSyntaxParse(); } else { if (parser.tokenStream.hadError() || directives == newDirectives) return false; // Assignment must be monotonic to prevent reparsing iloops MOZ_ASSERT_IF(directives.strict(), newDirectives.strict()); MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS()); directives = newDirectives; } parser.tokenStream.seek(start); } if (!NameFunctions(cx, fn)) return false; if (!SetDisplayURL(cx, parser.tokenStream, ss)) return false; if (!SetSourceMap(cx, parser.tokenStream, ss)) return false; if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingScope, false, options, /* staticLevel = */ 0, sourceObject, /* sourceStart = */ 0, srcBuf.length())); if (!script) return false; script->bindings = fn->pn_funbox->bindings; /* * The reason for checking fun->environment() below is that certain * consumers of JS::CompileFunction, namely * EventListenerManager::CompileEventHandlerInternal, passes in a * nullptr environment. This compiled function is never used, but * instead is cloned immediately onto the right scope chain. */ BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script, /* lazyScript = */ js::NullPtr(), /* insideEval = */ false, /* evalCaller = */ js::NullPtr(), fun->environment() && fun->environment()->is<GlobalObject>(), options.lineno); if (!funbce.init()) return false; if (!EmitFunctionScript(cx, &funbce, fn->pn_body)) return false; } else { fun.set(fn->pn_funbox->function()); MOZ_ASSERT(IsAsmJSModuleNative(fun->native())); } if (!sct.complete()) return false; return true; }