// 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, HandleFunction fun, CompileOptions options, const AutoNameVector &formals, StableCharPtr chars, size_t length) { if (!CheckLength(cx, length)) return false; ScriptSource *ss = cx->new_<ScriptSource>(); if (!ss) return false; ScriptSourceHolder ssh(cx->runtime, 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 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 = FunctionNode::create(PNK_NAME, &parser); if (!fn) return false; fn->pn_body = NULL; fn->pn_cookie.makeFree(); ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, &parser); 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; } BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* callerFrame = */ NULL, /* hasGlobalScope = */ false, options.lineno); if (!funbce.init()) 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; } if (!SetSourceMap(cx, parser.tokenStream, ss, script)) return false; if (!EmitFunctionScript(cx, &funbce, pn)) return false; if (!sct.complete()) return false; return true; }
bool js::IsAsmJSModule(HandleFunction fun) { return fun->isNative() && fun->maybeNative() == LinkAsmJS; }
bool js::IsAsmJSFunction(HandleFunction fun) { return fun->isNative() && fun->maybeNative() == CallAsmJS; }
// 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, HandleFunction fun, CompileOptions options, const AutoNameVector &formals, const jschar *chars, size_t length) { if (!CheckLength(cx, length)) return false; ScriptSource *ss = cx->new_<ScriptSource>(); if (!ss) return false; ScriptSourceHolder ssh(cx->runtime, 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 parser(cx, options, chars, length, /* foldConstants = */ true); if (!parser.init()) return false; parser.sct = &sct; JS_ASSERT(fun); StrictMode sms = StrictModeFromContext(cx); FunctionBox *funbox = parser.newFunctionBox(fun, /* outerpc = */ NULL, sms); SharedContext funsc(cx, /* scopeChain = */ NULL, funbox, sms); fun->setArgCount(formals.length()); unsigned staticLevel = 0; ParseContext funpc(&parser, &funsc, staticLevel, /* bodyid = */ 0); if (!funpc.init()) return false; /* FIXME: make Function format the source for a function definition. */ ParseNode *fn = FunctionNode::create(PNK_NAME, &parser); if (!fn) return false; fn->pn_body = NULL; fn->pn_cookie.makeFree(); ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, &parser); if (!argsbody) return false; argsbody->setOp(JSOP_NOP); argsbody->makeEmpty(); fn->pn_body = argsbody; for (unsigned i = 0; i < formals.length(); i++) { if (!DefineArg(&parser, fn, formals[i])) return false; } /* * After we're done parsing, we must fold constants, analyze any nested * functions, and generate code for this function, including a stop opcode * at the end. */ ParseNode *pn = parser.functionBody(Parser::StatementListBody); if (!pn) return false; if (!parser.tokenStream.matchToken(TOK_EOF)) { parser.reportError(NULL, JSMSG_SYNTAX_ERROR); return false; } if (!FoldConstants(cx, pn, &parser)) return false; Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), false, options, staticLevel, ss, 0, length)); if (!script) return false; InternalHandle<Bindings*> bindings(script, &script->bindings); if (!funpc.generateFunctionBindings(cx, bindings)) return false; BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, /* callerFrame = */ NULL, /* hasGlobalScope = */ false, options.lineno); if (!funbce.init()) 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; } if (!SetSourceMap(cx, parser.tokenStream, ss, script)) return false; if (!EmitFunctionScript(cx, &funbce, pn)) return false; return true; }