diff --git a/jscompile.c b/jscompile.c index d4f23fb..855a83e 100644 --- a/jscompile.c +++ b/jscompile.c @@ -42,6 +42,7 @@ static js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *bo F->filename = js_intern(J, J->filename); F->line = name ? name->line : params ? params->line : body ? body->line : 1; F->script = script; + F->name = name ? name->string : ""; cfunbody(J, F, name, params, body); @@ -102,8 +103,14 @@ static int addstring(JF, const char *value) return F->strlen++; } -static void addlocal(JF, const char *name) +static void addlocal(JF, const char *name, int reuse) { + if (reuse) { + int i; + for (i = 0; i < F->varlen; ++i) + if (!strcmp(F->vartab[i], name)) + return; + } if (F->varlen >= F->varcap) { F->varcap = F->varcap ? F->varcap * 2 : 16; F->vartab = realloc(F->vartab, F->varcap * sizeof *F->vartab); @@ -114,9 +121,9 @@ static void addlocal(JF, const char *name) static int findlocal(JF, const char *name) { int i; - for (i = 0; i < F->varlen; ++i) + for (i = F->varlen - 1; i >= 0; --i) if (!strcmp(F->vartab[i], name)) - return i; + return i + 1; return -1; } @@ -154,7 +161,7 @@ static void emitlocal(JF, int oploc, int opvar, const char *name) i = findlocal(J, F, name); if (i >= 0) { emit(J, F, oploc); - emitraw(J, F, i + 1); + emitraw(J, F, i); return; } } @@ -1093,9 +1100,6 @@ static void analyze(JF, js_Ast *node) } } - if (node->type == EXP_VAR) - addlocal(J, F, node->a->string); - if (node->a) analyze(J, F, node->a); if (node->b) analyze(J, F, node->b); if (node->c) analyze(J, F, node->c); @@ -1115,18 +1119,27 @@ static void cparams(JF, js_Ast *list) { F->numparams = listlength(list); while (list) { - addlocal(J, F, list->a->string); + addlocal(J, F, list->a->string, 0); list = list->b; } } -static void cvardecs(JF) +static void cvardecs(JF, js_Ast *node) { - int i; - for (i = 0; i < F->varlen; ++i) { - emit(J, F, OP_UNDEF); - emitstring(J, F, OP_INITVAR, F->vartab[i]); + if (isfun(node->type)) + return; /* stop at inner functions */ + + if (node->type == EXP_VAR) { + if (F->lightweight) + addlocal(J, F, node->a->string, 1); + else + emitstring(J, F, OP_DEFVAR, node->a->string); } + + if (node->a) cvardecs(J, F, node->a); + if (node->b) cvardecs(J, F, node->b); + if (node->c) cvardecs(J, F, node->c); + if (node->d) cvardecs(J, F, node->d); } static void cfundecs(JF, js_Ast *list) @@ -1134,7 +1147,6 @@ static void cfundecs(JF, js_Ast *list) while (list) { js_Ast *stm = list->a; if (stm->type == AST_FUNDEC) { - addlocal(J, F, stm->a->string); emitfunction(J, F, newfun(J, stm->a, stm->b, stm->c, 0)); emitstring(J, F, OP_INITVAR, stm->a->string); } @@ -1147,32 +1159,25 @@ static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body) F->lightweight = 1; F->arguments = 0; - cparams(J, F, params); - - if (name) { - F->name = name->string; - addlocal(J, F, name->string); - } else { - F->name = ""; - } - if (body) analyze(J, F, body); - if (!F->lightweight) { - cvardecs(J, F); - cfundecs(J, F, body); - } + cparams(J, F, params); if (name) { - if (F->lightweight) - emit(J, F, OP_CURRENT); - else - emitfunction(J, F, F); - emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, name->string); - emit(J, F, OP_POP); + emit(J, F, OP_CURRENT); + if (F->lightweight) { + addlocal(J, F, name->string, 0); + emit(J, F, OP_INITLOCAL); + emitraw(J, F, findlocal(J, F, name->string)); + } else { + emitstring(J, F, OP_INITVAR, name->string); + } } + cvardecs(J, F, body); + cfundecs(J, F, body); + if (F->script) { emit(J, F, OP_UNDEF); cstmlist(J, F, body); diff --git a/jscompile.h b/jscompile.h index f813970..6f07360 100644 --- a/jscompile.h +++ b/jscompile.h @@ -42,6 +42,7 @@ enum js_OpCode OP_DELLOCAL, /* -N- false */ OP_INITVAR, /* -S- */ + OP_DEFVAR, /* -S- */ OP_GETVAR, /* -S- */ OP_SETVAR, /* -S- */ OP_DELVAR, /* -S- */ diff --git a/jsdump.c b/jsdump.c index 3225b15..1053fa3 100644 --- a/jsdump.c +++ b/jsdump.c @@ -756,6 +756,7 @@ void jsC_dumpfunction(js_State *J, js_Function *F) break; case OP_INITVAR: + case OP_DEFVAR: case OP_GETVAR: case OP_SETVAR: case OP_DELVAR: @@ -772,6 +773,10 @@ void jsC_dumpfunction(js_State *J, js_Function *F) case OP_GETLOCAL: case OP_SETLOCAL: case OP_DELLOCAL: + printf(" %d (%s)", *p, F->vartab[*p-1]); + ++p; + break; + case OP_NUMBER_N: case OP_INITPROP_N: case OP_CALL: diff --git a/jsrun.c b/jsrun.c index 2cd5265..d95737c 100644 --- a/jsrun.c +++ b/jsrun.c @@ -687,11 +687,16 @@ js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment return E; } -static void js_decvar(js_State *J, const char *name, int idx) +static void js_initvar(js_State *J, const char *name, int idx) { jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL); } +static void js_defvar(js_State *J, const char *name) +{ + jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, NULL, NULL, NULL); +} + static void js_getvar(js_State *J, const char *name) { js_Environment *E = J->E; @@ -787,12 +792,27 @@ static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment saveE = J->E; J->E = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope); + + if (F->arguments) { + js_newobject(J); + js_currentfunction(J); + js_defproperty(J, -2, "callee", JS_DONTENUM); + js_pushnumber(J, n); + js_defproperty(J, -2, "length", JS_DONTENUM); + for (i = 0; i < n; ++i) { + js_copy(J, i + 1); + js_setindex(J, -2, i); + } + js_initvar(J, "arguments", -1); + js_pop(J, 1); + } + for (i = 0; i < F->numparams; ++i) { if (i < n) - js_decvar(J, F->vartab[i], i + 1); + js_initvar(J, F->vartab[i], i + 1); else { js_pushundefined(J); - js_decvar(J, F->vartab[i], -1); + js_initvar(J, F->vartab[i], -1); js_pop(J, 1); } } @@ -1041,10 +1061,14 @@ static void jsR_run(js_State *J, js_Function *F) break; case OP_INITVAR: - js_decvar(J, ST[*pc++], -1); + js_initvar(J, ST[*pc++], -1); js_pop(J, 1); break; + case OP_DEFVAR: + js_defvar(J, ST[*pc++]); + break; + case OP_GETVAR: js_getvar(J, ST[*pc++]); break;