// 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, Bindings *bindings, const jschar *chars, size_t length) { if (!CheckLength(cx, length)) return NULL; ScriptSource *ss = cx->new_<ScriptSource>(); if (!ss) return NULL; AutoAttachToRuntime attacher(cx->runtime, ss); SourceCompressionToken sct(cx); if (!ss->setSourceCopy(cx, chars, length, true, &sct)) return NULL; options.setCompileAndGo(false); Parser parser(cx, options, chars, length, /* foldConstants = */ true); if (!parser.init()) return false; parser.sct = &sct; JS_ASSERT(fun); SharedContext funsc(cx, /* scopeChain = */ NULL, fun, /* funbox = */ NULL, StrictModeFromContext(cx)); funsc.bindings.transfer(bindings); fun->setArgCount(funsc.bindings.numArgs()); unsigned staticLevel = 0; TreeContext funtc(&parser, &funsc, staticLevel, /* bodyid = */ 0); if (!funtc.init()) return false; Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), false, options, staticLevel, ss, 0, length)); if (!script) return false; StackFrame *nullCallerFrame = NULL; BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, nullCallerFrame, /* hasGlobalScope = */ false, options.lineno); if (!funbce.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; unsigned nargs = fun->nargs; if (nargs) { /* * NB: do not use AutoLocalNameArray because it will release space * allocated from cx->tempLifoAlloc by DefineArg. */ BindingVector names(cx); if (!GetOrderedBindings(cx, funsc.bindings, &names)) return false; for (unsigned i = 0; i < nargs; i++) { if (!DefineArg(fn, names[i].maybeName, i, &parser)) 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; if (!AnalyzeFunctions(&parser, nullCallerFrame)) 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 (!EmitFunctionScript(cx, &funbce, pn)) 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, 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; if (!funpc.generateFunctionBindings(cx, &script->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; }
// 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(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_FUNCTION, &parser); if (!fn) return false; fn->pn_body = NULL; fn->pn_funbox = 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 = */ NullFramePtr(), /* 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; }
// 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, JSPrincipals *principals, JSPrincipals *originPrincipals, Bindings *bindings, const jschar *chars, size_t length, const char *filename, unsigned lineno, JSVersion version) { Parser parser(cx, principals, originPrincipals, chars, length, filename, lineno, version, /* foldConstants = */ true, /* compileAndGo = */ false); if (!parser.init()) return false; JS_ASSERT(fun); SharedContext funsc(cx, /* scopeChain = */ NULL, fun, /* funbox = */ NULL, StrictModeFromContext(cx)); funsc.bindings.transfer(bindings); fun->setArgCount(funsc.bindings.numArgs()); unsigned staticLevel = 0; TreeContext funtc(&parser, &funsc, staticLevel, /* bodyid = */ 0); if (!funtc.init()) return false; Rooted<JSScript*> script(cx, JSScript::Create(cx, /* enclosingScope = */ NullPtr(), /* savedCallerFun = */ false, principals, originPrincipals, /* compileAndGo = */ false, /* noScriptRval = */ false, version, staticLevel)); if (!script) return false; StackFrame *nullCallerFrame = NULL; BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, nullCallerFrame, /* hasGlobalScope = */ false, lineno); if (!funbce.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; unsigned nargs = fun->nargs; if (nargs) { /* * NB: do not use AutoLocalNameArray because it will release space * allocated from cx->tempLifoAlloc by DefineArg. */ BindingNames names(cx); if (!funsc.bindings.getLocalNameArray(cx, &names)) return false; for (unsigned i = 0; i < nargs; i++) { if (!DefineArg(fn, names[i].maybeAtom, i, &parser)) 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; if (!AnalyzeFunctions(&parser, nullCallerFrame)) 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 (!EmitFunctionScript(cx, &funbce, pn)) return false; return true; }