Threaded interpreter, first step toward more aggressive optimizations (121414, r=shaver).

This commit is contained in:
brendan%mozilla.org 2005-11-19 03:20:17 +00:00
parent 3940b258b4
commit d190f94f8e
7 changed files with 729 additions and 533 deletions

View File

@ -2774,7 +2774,7 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO
: JSFRAME_COMPILING;
cx->fp = &frame;
ok = js_EmitTree(cx, cg, body);
ok = js_EmitTree(cx, cg, body) && js_Emit1(cx, cg, JSOP_STOP) >= 0;
cx->fp = fp;
if (!ok)
return JS_FALSE;

View File

@ -1931,9 +1931,10 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
if (!fun)
goto bad;
fun->u.script = js_NewScript(cx, 0, 0, 0);
fun->u.script = js_NewScript(cx, 1, 0, 0);
if (!fun->u.script)
goto bad;
fun->u.script->code[0] = JSOP_STOP;
fun->interpreted = JS_TRUE;
return proto;

File diff suppressed because it is too large Load Diff

View File

@ -392,3 +392,9 @@ OPDEF(JSOP_LITOPX, 191,"litopx", NULL, 5, 0, 0, 12, JOF_LITOPX
OPDEF(JSOP_STARTXML, 192,"startxml", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_STARTXMLEXPR, 193,"startxmlexpr",NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_SETMETHOD, 194,"setmethod", NULL, 3, 2, 1, 1, JOF_CONST|JOF_PROP)
/*
* Stop interpretation, emitted at end of script to save the threaded bytecode
* interpreter an extra branch test on every DO_NEXT_OP (see jsinterp.c).
*/
OPDEF(JSOP_STOP, 195,"stop", NULL, 1, 0, 0, 0, JOF_BYTE)

View File

@ -483,14 +483,17 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
#endif
/*
* No need to emit code here -- Statements already has, for each
* No need to emit bytecode here -- Statements already has, for each
* statement in turn. Search for TCF_COMPILING in Statements, below.
* That flag is set for every tc == &cg->treeContext, and it implies
* that the tc can be downcast to a cg and used to emit code during
* parsing, rather than at the end of the parse phase.
*
* Update: the threaded interpreter needs a stop instruction, so we
* do have to emit that here.
*/
JS_ASSERT(cg->treeContext.flags & TCF_COMPILING);
ok = JS_TRUE;
ok = js_Emit1(cx, cg, JSOP_STOP) >= 0;
}
#ifdef METER_PARSENODES
@ -705,10 +708,17 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
: JSFRAME_COMPILING;
cx->fp = &frame;
/* Ensure that the body looks like a block statement to js_EmitTree. */
/*
* Farble the body so that it looks like a block statement to js_EmitTree,
* which is called beneath FunctionBody (see Statements, further below in
* this file).
*
* NB: with threaded interpretation, we must emit a stop opcode at the end
* of every scripted function and top-level script.
*/
CURRENT_TOKEN(ts).type = TOK_LC;
pn = FunctionBody(cx, ts, fun, &funcg.treeContext);
if (!pn) {
if (!pn || js_Emit1(cx, &funcg, JSOP_STOP) < 0) {
ok = JS_FALSE;
} else {
/*

View File

@ -423,15 +423,21 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
* nsrcnotes and ntrynotes fields to come before everything except magic,
* length, prologLength, and version, so that srcnote and trynote storage
* can be allocated as part of the JSScript (along with bytecode storage).
*
* So far, the magic number has not changed for every jsopcode.tbl change.
* We stipulate forward compatibility by requiring old bytecodes never to
* change or go away (modulo a few exceptions before the XDR interfaces
* evolved, and a few exceptions during active trunk development). With
* the addition of JSOP_STOP to support JS_THREADED_INTERP, we make a new
* magic number (_5) so that we know to append JSOP_STOP to old scripts
* when deserializing.
*/
if (xdr->mode == JSXDR_ENCODE)
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
if (!JS_XDRUint32(xdr, &magic))
return JS_FALSE;
if (magic != JSXDR_MAGIC_SCRIPT_4 &&
magic != JSXDR_MAGIC_SCRIPT_3 &&
magic != JSXDR_MAGIC_SCRIPT_2 &&
magic != JSXDR_MAGIC_SCRIPT_1) {
JS_ASSERT((uint32)JSXDR_MAGIC_SCRIPT_5 - (uint32)JSXDR_MAGIC_SCRIPT_1 == 4);
if (magic - (uint32)JSXDR_MAGIC_SCRIPT_1 > 4) {
if (!hasMagic) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_SCRIPT_MAGIC);
@ -484,7 +490,11 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
}
if (xdr->mode == JSXDR_DECODE) {
script = js_NewScript(cx, length, nsrcnotes, ntrynotes);
size_t alloclength = length;
if (magic < JSXDR_MAGIC_SCRIPT_5)
++alloclength; /* add a byte for JSOP_STOP */
script = js_NewScript(cx, alloclength, nsrcnotes, ntrynotes);
if (!script)
return JS_FALSE;
if (magic >= JSXDR_MAGIC_SCRIPT_2) {
@ -510,13 +520,25 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
goto error;
}
if (magic < JSXDR_MAGIC_SCRIPT_4) {
if (!JS_XDRUint32(xdr, &nsrcnotes))
goto error;
if (magic < JSXDR_MAGIC_SCRIPT_5) {
if (xdr->mode == JSXDR_DECODE) {
notes = (jssrcnote *) JS_malloc(cx, nsrcnotes * sizeof(jssrcnote));
if (!notes)
/*
* Append JSOP_STOP to old scripts, to relieve the interpreter
* from having to bounds-check pc. Also take care to increment
* length, as it is used below and must count all bytecode.
*/
script->code[length++] = JSOP_STOP;
}
if (magic < JSXDR_MAGIC_SCRIPT_4) {
if (!JS_XDRUint32(xdr, &nsrcnotes))
goto error;
if (xdr->mode == JSXDR_DECODE) {
notes = (jssrcnote *)
JS_malloc(cx, nsrcnotes * sizeof(jssrcnote));
if (!notes)
goto error;
}
}
}

View File

@ -186,7 +186,8 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
#define JSXDR_MAGIC_SCRIPT_2 0xdead0002
#define JSXDR_MAGIC_SCRIPT_3 0xdead0003
#define JSXDR_MAGIC_SCRIPT_4 0xdead0004
#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_4
#define JSXDR_MAGIC_SCRIPT_5 0xdead0005
#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_5
JS_END_EXTERN_C