diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-12-20 13:13:38 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-12-20 13:13:38 -0200 |
| commit | 18afb90349fc1b698d179e29fdc014589c2e1145 (patch) | |
| tree | 0ebee0d47aa91ce4bdf580baa2e5639c361c9a9a | |
| parent | 22dd271cbba22c0765eb45296a957ecacf68755e (diff) | |
| download | lua-18afb90349fc1b698d179e29fdc014589c2e1145.tar.gz lua-18afb90349fc1b698d179e29fdc014589c2e1145.tar.bz2 lua-18afb90349fc1b698d179e29fdc014589c2e1145.zip | |
first version of stackless Lua
| -rw-r--r-- | ldo.c | 119 | ||||
| -rw-r--r-- | lvm.c | 87 |
2 files changed, 128 insertions, 78 deletions
| @@ -43,8 +43,15 @@ void luaD_init (lua_State *L, int stacksize) { | |||
| 43 | stacksize += EXTRA_STACK; | 43 | stacksize += EXTRA_STACK; |
| 44 | L->stack = luaM_newvector(L, stacksize, TObject); | 44 | L->stack = luaM_newvector(L, stacksize, TObject); |
| 45 | L->stacksize = stacksize; | 45 | L->stacksize = stacksize; |
| 46 | L->top = L->basefunc.base = L->stack + RESERVED_STACK_PREFIX; | 46 | L->top = L->stack + RESERVED_STACK_PREFIX; |
| 47 | restore_stack_limit(L); | 47 | restore_stack_limit(L); |
| 48 | luaM_reallocvector(L, L->base_ci, 0, 20, CallInfo); | ||
| 49 | L->ci = L->base_ci; | ||
| 50 | L->ci->base = L->top; | ||
| 51 | L->ci->savedpc = NULL; | ||
| 52 | L->ci->pc = NULL; | ||
| 53 | L->size_ci = 20; | ||
| 54 | L->end_ci = L->base_ci + L->size_ci; | ||
| 48 | } | 55 | } |
| 49 | 56 | ||
| 50 | 57 | ||
| @@ -98,35 +105,81 @@ void luaD_lineHook (lua_State *L, int line, lua_Hook linehook) { | |||
| 98 | if (L->allowhooks) { | 105 | if (L->allowhooks) { |
| 99 | lua_Debug ar; | 106 | lua_Debug ar; |
| 100 | ar.event = "line"; | 107 | ar.event = "line"; |
| 101 | ar._ci = L->ci; | 108 | ar._ci = L->ci - L->base_ci; |
| 102 | ar.currentline = line; | 109 | ar.currentline = line; |
| 103 | dohook(L, &ar, linehook); | 110 | dohook(L, &ar, linehook); |
| 104 | } | 111 | } |
| 105 | } | 112 | } |
| 106 | 113 | ||
| 107 | 114 | ||
| 108 | static void luaD_callHook (lua_State *L, lua_Hook callhook, | 115 | void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) { |
| 109 | const char *event) { | ||
| 110 | if (L->allowhooks) { | 116 | if (L->allowhooks) { |
| 111 | lua_Debug ar; | 117 | lua_Debug ar; |
| 112 | ar.event = event; | 118 | ar.event = event; |
| 113 | ar._ci = L->ci; | 119 | ar._ci = L->ci - L->base_ci; |
| 114 | L->ci->pc = NULL; /* function is not active */ | ||
| 115 | dohook(L, &ar, callhook); | 120 | dohook(L, &ar, callhook); |
| 116 | } | 121 | } |
| 117 | } | 122 | } |
| 118 | 123 | ||
| 119 | 124 | ||
| 120 | static StkId callCclosure (lua_State *L, const struct CClosure *cl) { | 125 | #define newci(L) ((++L->ci == L->end_ci) ? growci(L) : L->ci) |
| 126 | |||
| 127 | static CallInfo *growci (lua_State *L) { | ||
| 128 | lua_assert(L->ci == L->end_ci); | ||
| 129 | luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo); | ||
| 130 | L->ci = L->base_ci + L->size_ci; | ||
| 131 | L->size_ci *= 2; | ||
| 132 | L->end_ci = L->base_ci + L->size_ci; | ||
| 133 | return L->ci; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | StkId luaD_precall (lua_State *L, StkId func) { | ||
| 138 | CallInfo *ci; | ||
| 121 | int n; | 139 | int n; |
| 140 | if (ttype(func) != LUA_TFUNCTION) { | ||
| 141 | /* `func' is not a function; check the `function' tag method */ | ||
| 142 | const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); | ||
| 143 | if (ttype(tm) != LUA_TFUNCTION) | ||
| 144 | luaG_typeerror(L, func, "call"); | ||
| 145 | luaD_openstack(L, func); | ||
| 146 | setobj(func, tm); /* tag method is the new function to be called */ | ||
| 147 | } | ||
| 148 | lua_assert(ttype(func) == LUA_TFUNCTION); | ||
| 149 | ci = newci(L); | ||
| 150 | ci->base = func+1; | ||
| 151 | ci->savedpc = NULL; | ||
| 152 | ci->pc = NULL; | ||
| 153 | if (L->callhook) | ||
| 154 | luaD_callHook(L, L->callhook, "call"); | ||
| 155 | if (!clvalue(func)->c.isC) return NULL; | ||
| 156 | /* if is a C function, call it */ | ||
| 122 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | 157 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ |
| 123 | lua_unlock(L); | 158 | lua_unlock(L); |
| 124 | #if LUA_COMPATUPVALUES | 159 | #if LUA_COMPATUPVALUES |
| 125 | lua_pushupvalues(L); | 160 | lua_pushupvalues(L); |
| 126 | #endif | 161 | #endif |
| 127 | n = (*cl->f)(L); /* do the actual call */ | 162 | n = (*clvalue(func)->c.f)(L); /* do the actual call */ |
| 128 | lua_lock(L); | 163 | lua_lock(L); |
| 129 | return L->top - n; /* return index of first result */ | 164 | return L->top - n; |
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { | ||
| 169 | StkId res; | ||
| 170 | if (L->callhook) | ||
| 171 | luaD_callHook(L, L->callhook, "return"); | ||
| 172 | res = L->ci->base - 1; /* `func' = final position of 1st result */ | ||
| 173 | L->ci--; | ||
| 174 | /* move results to correct place */ | ||
| 175 | while (wanted != 0 && firstResult < L->top) { | ||
| 176 | setobj(res++, firstResult++); | ||
| 177 | wanted--; | ||
| 178 | } | ||
| 179 | while (wanted-- > 0) | ||
| 180 | setnilvalue(res++); | ||
| 181 | L->top = res; | ||
| 182 | luaC_checkGC(L); | ||
| 130 | } | 183 | } |
| 131 | 184 | ||
| 132 | 185 | ||
| @@ -136,36 +189,11 @@ static StkId callCclosure (lua_State *L, const struct CClosure *cl) { | |||
| 136 | ** When returns, all the results are on the stack, starting at the original | 189 | ** When returns, all the results are on the stack, starting at the original |
| 137 | ** function position. | 190 | ** function position. |
| 138 | */ | 191 | */ |
| 139 | void luaD_call (lua_State *L, StkId func) { | 192 | void luaD_call (lua_State *L, StkId func, int nResults) { |
| 140 | lua_Hook callhook; | 193 | StkId firstResult = luaD_precall(L, func); |
| 141 | StkId firstResult; | 194 | if (firstResult == NULL) /* is a Lua function? */ |
| 142 | CallInfo ci; | 195 | firstResult = luaV_execute(L, &clvalue(func)->l, func+1); /* call it */ |
| 143 | if (ttype(func) != LUA_TFUNCTION) { | 196 | luaD_poscall(L, nResults, firstResult); |
| 144 | /* `func' is not a function; check the `function' tag method */ | ||
| 145 | const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); | ||
| 146 | if (ttype(tm) != LUA_TFUNCTION) | ||
| 147 | luaG_typeerror(L, func, "call"); | ||
| 148 | luaD_openstack(L, func); | ||
| 149 | setobj(func, tm); /* tag method is the new function to be called */ | ||
| 150 | } | ||
| 151 | lua_assert(ttype(func) == LUA_TFUNCTION); | ||
| 152 | ci.prev = L->ci; /* chain new callinfo */ | ||
| 153 | L->ci = &ci; | ||
| 154 | ci.base = func+1; | ||
| 155 | callhook = L->callhook; | ||
| 156 | if (callhook) | ||
| 157 | luaD_callHook(L, callhook, "call"); | ||
| 158 | firstResult = (clvalue(func)->c.isC ? | ||
| 159 | callCclosure(L, &clvalue(func)->c) : | ||
| 160 | luaV_execute(L, &clvalue(func)->l, func+1)); | ||
| 161 | if (callhook) /* same hook that was active at entry */ | ||
| 162 | luaD_callHook(L, callhook, "return"); | ||
| 163 | L->ci = ci.prev; /* unchain callinfo */ | ||
| 164 | /* move results to `func' (to erase parameters and function) */ | ||
| 165 | while (firstResult < L->top) | ||
| 166 | setobj(func++, firstResult++); | ||
| 167 | L->top = func; | ||
| 168 | luaC_checkGC(L); | ||
| 169 | } | 197 | } |
| 170 | 198 | ||
| 171 | 199 | ||
| @@ -179,9 +207,7 @@ struct CallS { /* data to `f_call' */ | |||
| 179 | 207 | ||
| 180 | static void f_call (lua_State *L, void *ud) { | 208 | static void f_call (lua_State *L, void *ud) { |
| 181 | struct CallS *c = cast(struct CallS *, ud); | 209 | struct CallS *c = cast(struct CallS *, ud); |
| 182 | luaD_call(L, c->func); | 210 | luaD_call(L, c->func, c->nresults); |
| 183 | if (c->nresults != LUA_MULTRET) | ||
| 184 | luaD_adjusttop(L, c->func + c->nresults); | ||
| 185 | } | 211 | } |
| 186 | 212 | ||
| 187 | 213 | ||
| @@ -291,7 +317,7 @@ struct lua_longjmp { | |||
| 291 | jmp_buf b; | 317 | jmp_buf b; |
| 292 | struct lua_longjmp *previous; | 318 | struct lua_longjmp *previous; |
| 293 | volatile int status; /* error code */ | 319 | volatile int status; /* error code */ |
| 294 | CallInfo *ci; /* call info of active function that set protection */ | 320 | int ci; /* index of call info of active function that set protection */ |
| 295 | StkId top; /* top stack when protection was set */ | 321 | StkId top; /* top stack when protection was set */ |
| 296 | int allowhooks; /* `allowhook' state when protection was set */ | 322 | int allowhooks; /* `allowhook' state when protection was set */ |
| 297 | }; | 323 | }; |
| @@ -307,8 +333,7 @@ static void message (lua_State *L, const char *s) { | |||
| 307 | incr_top; | 333 | incr_top; |
| 308 | setsvalue(top+1, luaS_new(L, s)); | 334 | setsvalue(top+1, luaS_new(L, s)); |
| 309 | incr_top; | 335 | incr_top; |
| 310 | luaD_call(L, top); | 336 | luaD_call(L, top, 0); |
| 311 | L->top = top; | ||
| 312 | } | 337 | } |
| 313 | } | 338 | } |
| 314 | 339 | ||
| @@ -337,7 +362,7 @@ void luaD_breakrun (lua_State *L, int errcode) { | |||
| 337 | 362 | ||
| 338 | int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) { | 363 | int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) { |
| 339 | struct lua_longjmp lj; | 364 | struct lua_longjmp lj; |
| 340 | lj.ci = L->ci; | 365 | lj.ci = L->ci - L->base_ci; |
| 341 | lj.top = L->top; | 366 | lj.top = L->top; |
| 342 | lj.allowhooks = L->allowhooks; | 367 | lj.allowhooks = L->allowhooks; |
| 343 | lj.status = 0; | 368 | lj.status = 0; |
| @@ -346,7 +371,7 @@ int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) { | |||
| 346 | if (setjmp(lj.b) == 0) | 371 | if (setjmp(lj.b) == 0) |
| 347 | (*f)(L, ud); | 372 | (*f)(L, ud); |
| 348 | else { /* an error occurred: restore the state */ | 373 | else { /* an error occurred: restore the state */ |
| 349 | L->ci = lj.ci; | 374 | L->ci = L->base_ci + lj.ci; |
| 350 | L->top = lj.top; | 375 | L->top = lj.top; |
| 351 | L->allowhooks = lj.allowhooks; | 376 | L->allowhooks = lj.allowhooks; |
| 352 | restore_stack_limit(L); | 377 | restore_stack_limit(L); |
| @@ -97,14 +97,9 @@ static void callTM (lua_State *L, const TObject *f, | |||
| 97 | setobj(base+3, p3); /* 3th argument */ | 97 | setobj(base+3, p3); /* 3th argument */ |
| 98 | L->top++; | 98 | L->top++; |
| 99 | } | 99 | } |
| 100 | luaD_call(L, base); | 100 | luaD_call(L, base, (result ? 1 : 0)); |
| 101 | if (result) { /* need a result? */ | 101 | if (result) { /* need a result? */ |
| 102 | if (L->top == base) { /* are there valid results? */ | 102 | setobj(result, base); /* get it */ |
| 103 | setnilvalue(result); /* function had no results */ | ||
| 104 | } | ||
| 105 | else { | ||
| 106 | setobj(result, base); /* get first result */ | ||
| 107 | } | ||
| 108 | } | 103 | } |
| 109 | L->top = base; /* restore top */ | 104 | L->top = base; /* restore top */ |
| 110 | } | 105 | } |
| @@ -140,7 +135,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | |||
| 140 | if (ttype(tm) == LUA_TFUNCTION) | 135 | if (ttype(tm) == LUA_TFUNCTION) |
| 141 | callTM(L, tm, t, key, NULL, res); | 136 | callTM(L, tm, t, key, NULL, res); |
| 142 | else { | 137 | else { |
| 143 | t = tm; | 138 | t = (StkId)tm; /* ?? */ |
| 144 | goto init; /* return luaV_gettable(L, tm, key, res); */ | 139 | goto init; /* return luaV_gettable(L, tm, key, res); */ |
| 145 | } | 140 | } |
| 146 | } | 141 | } |
| @@ -169,7 +164,7 @@ void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { | |||
| 169 | if (ttype(tm) == LUA_TFUNCTION) | 164 | if (ttype(tm) == LUA_TFUNCTION) |
| 170 | callTM(L, tm, t, key, val, NULL); | 165 | callTM(L, tm, t, key, val, NULL); |
| 171 | else { | 166 | else { |
| 172 | t = tm; | 167 | t = (StkId)tm; /* ?? */ |
| 173 | goto init; /* luaV_settable(L, tm, key, val); */ | 168 | goto init; /* luaV_settable(L, tm, key, val); */ |
| 174 | } | 169 | } |
| 175 | } | 170 | } |
| @@ -311,15 +306,15 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
| 311 | ** some macros for common tasks in `luaV_execute' | 306 | ** some macros for common tasks in `luaV_execute' |
| 312 | */ | 307 | */ |
| 313 | 308 | ||
| 314 | #define runtime_check(L, c) { if (!(c)) return L->top; } | 309 | #define runtime_check(L, c) { if (!(c)) return 0; } |
| 315 | 310 | ||
| 316 | #define RA(i) (base+GETARG_A(i)) | 311 | #define RA(i) (base+GETARG_A(i)) |
| 317 | #define RB(i) (base+GETARG_B(i)) | 312 | #define RB(i) (base+GETARG_B(i)) |
| 318 | #define RC(i) (base+GETARG_C(i)) | 313 | #define RC(i) (base+GETARG_C(i)) |
| 319 | #define RKC(i) ((GETARG_C(i) < MAXSTACK) ? \ | 314 | #define RKC(i) ((GETARG_C(i) < MAXSTACK) ? \ |
| 320 | base+GETARG_C(i) : \ | 315 | base+GETARG_C(i) : \ |
| 321 | tf->k+GETARG_C(i)-MAXSTACK) | 316 | cl->p->k+GETARG_C(i)-MAXSTACK) |
| 322 | #define KBc(i) (tf->k+GETARG_Bc(i)) | 317 | #define KBc(i) (cl->p->k+GETARG_Bc(i)) |
| 323 | 318 | ||
| 324 | #define Arith(op, optm) { \ | 319 | #define Arith(op, optm) { \ |
| 325 | const TObject *b = RB(i); const TObject *c = RKC(i); \ | 320 | const TObject *b = RB(i); const TObject *c = RKC(i); \ |
| @@ -332,6 +327,16 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
| 332 | } | 327 | } |
| 333 | 328 | ||
| 334 | 329 | ||
| 330 | #define luaV_poscall(L,c,f) \ | ||
| 331 | if (c != NO_REG) { \ | ||
| 332 | luaD_poscall(L, c, f); \ | ||
| 333 | L->top = base + cl->p->maxstacksize; \ | ||
| 334 | } \ | ||
| 335 | else { \ | ||
| 336 | luaD_poscall(L, LUA_MULTRET, f); \ | ||
| 337 | } | ||
| 338 | |||
| 339 | |||
| 335 | #define dojump(pc, i) ((pc) += GETARG_sBc(i)) | 340 | #define dojump(pc, i) ((pc) += GETARG_sBc(i)) |
| 336 | 341 | ||
| 337 | /* | 342 | /* |
| @@ -339,17 +344,18 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
| 339 | ** Returns n such that the results are between [n,top). | 344 | ** Returns n such that the results are between [n,top). |
| 340 | */ | 345 | */ |
| 341 | StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | 346 | StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { |
| 342 | const Proto *const tf = cl->p; | ||
| 343 | const Instruction *pc; | 347 | const Instruction *pc; |
| 344 | lua_Hook linehook; | 348 | lua_Hook linehook; |
| 345 | if (tf->is_vararg) /* varargs? */ | 349 | reinit: |
| 346 | adjust_varargs(L, base, tf->numparams); | 350 | lua_assert(L->ci->savedpc == NULL); |
| 347 | if (base > L->stack_last - tf->maxstacksize) | 351 | if (cl->p->is_vararg) /* varargs? */ |
| 352 | adjust_varargs(L, base, cl->p->numparams); | ||
| 353 | if (base > L->stack_last - cl->p->maxstacksize) | ||
| 348 | luaD_stackerror(L); | 354 | luaD_stackerror(L); |
| 349 | luaD_adjusttop(L, base + tf->maxstacksize); | 355 | luaD_adjusttop(L, base + cl->p->maxstacksize); |
| 350 | pc = tf->code; | ||
| 351 | L->ci->pc = &pc; | 356 | L->ci->pc = &pc; |
| 352 | linehook = L->linehook; | 357 | linehook = L->ci->linehook = L->linehook; |
| 358 | pc = cl->p->code; | ||
| 353 | /* main loop of interpreter */ | 359 | /* main loop of interpreter */ |
| 354 | for (;;) { | 360 | for (;;) { |
| 355 | const Instruction i = *pc++; | 361 | const Instruction i = *pc++; |
| @@ -528,25 +534,44 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
| 528 | break; | 534 | break; |
| 529 | } | 535 | } |
| 530 | case OP_CALL: { | 536 | case OP_CALL: { |
| 531 | int c; | 537 | StkId firstResult; |
| 532 | int b = GETARG_B(i); | 538 | int b = GETARG_B(i); |
| 533 | if (b != NO_REG) | 539 | if (b != NO_REG) L->top = ra+b+1; |
| 534 | L->top = ra+b+1; | 540 | /* else previous instruction set top */ |
| 535 | luaD_call(L, ra); | 541 | firstResult = luaD_precall(L, ra); |
| 536 | c = GETARG_C(i); | 542 | if (firstResult) { |
| 537 | if (c != NO_REG) { | 543 | /* it was a C function (`precall' called it); adjust results */ |
| 538 | while (L->top < ra+c) setnilvalue(L->top++); | 544 | luaV_poscall(L, GETARG_C(i), firstResult); |
| 539 | L->top = base + tf->maxstacksize; | 545 | } |
| 546 | else { /* it is a Lua function: `call' it */ | ||
| 547 | CallInfo *ci = L->ci; | ||
| 548 | (ci-1)->savedpc = pc; | ||
| 549 | base = ci->base; | ||
| 550 | cl = &clvalue(base - 1)->l; | ||
| 551 | goto reinit; | ||
| 540 | } | 552 | } |
| 541 | break; | 553 | break; |
| 542 | } | 554 | } |
| 543 | case OP_RETURN: { | 555 | case OP_RETURN: { |
| 556 | CallInfo *ci; | ||
| 544 | int b; | 557 | int b; |
| 545 | luaF_close(L, base); | 558 | luaF_close(L, base); |
| 546 | b = GETARG_B(i); | 559 | b = GETARG_B(i); |
| 547 | if (b != NO_REG) | 560 | if (b != NO_REG) L->top = ra+b; |
| 548 | L->top = ra+b; | 561 | ci = L->ci - 1; |
| 549 | return ra; | 562 | if (ci->savedpc == NULL) |
| 563 | return ra; | ||
| 564 | else { /* previous function is Lua: continue its execution */ | ||
| 565 | lua_assert(ttype(ci->base-1) == LUA_TFUNCTION); | ||
| 566 | base = ci->base; /* restore previous values */ | ||
| 567 | linehook = ci->linehook; | ||
| 568 | cl = &clvalue(base - 1)->l; | ||
| 569 | pc = ci->savedpc; | ||
| 570 | ci->savedpc = NULL; | ||
| 571 | lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL); | ||
| 572 | luaV_poscall(L, GETARG_C(*(pc-1)), ra); | ||
| 573 | } | ||
| 574 | break; | ||
| 550 | } | 575 | } |
| 551 | case OP_FORPREP: { | 576 | case OP_FORPREP: { |
| 552 | if (luaV_tonumber(ra, ra) == NULL) | 577 | if (luaV_tonumber(ra, ra) == NULL) |
| @@ -623,7 +648,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
| 623 | Closure *ncl; | 648 | Closure *ncl; |
| 624 | int nup, j; | 649 | int nup, j; |
| 625 | luaV_checkGC(L, L->top); | 650 | luaV_checkGC(L, L->top); |
| 626 | p = tf->p[GETARG_Bc(i)]; | 651 | p = cl->p->p[GETARG_Bc(i)]; |
| 627 | nup = p->nupvalues; | 652 | nup = p->nupvalues; |
| 628 | ncl = luaF_newLclosure(L, nup); | 653 | ncl = luaF_newLclosure(L, nup); |
| 629 | ncl->l.p = p; | 654 | ncl->l.p = p; |
