diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2008-08-13 14:02:42 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2008-08-13 14:02:42 -0300 |
commit | fdbb243ff9980870c54676f3b2597b110ab82864 (patch) | |
tree | 37c1d31df7addd0638c8b26b28e6f4a0b6024a88 | |
parent | c1565c16edc487f32d87d1742a7c8e76d0b10236 (diff) | |
download | lua-fdbb243ff9980870c54676f3b2597b110ab82864.tar.gz lua-fdbb243ff9980870c54676f3b2597b110ab82864.tar.bz2 lua-fdbb243ff9980870c54676f3b2597b110ab82864.zip |
first steps towards yielding through longjump
-rw-r--r-- | ldo.c | 33 | ||||
-rw-r--r-- | ldo.h | 8 | ||||
-rw-r--r-- | lvm.c | 71 |
3 files changed, 50 insertions, 62 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.c,v 2.45 2007/03/27 14:11:38 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.46 2008/01/18 22:36:50 roberto Exp roberto $ |
3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -193,6 +193,7 @@ void luaD_callhook (lua_State *L, int event, int line) { | |||
193 | ar.i_ci = cast_int(L->ci - L->base_ci); | 193 | ar.i_ci = cast_int(L->ci - L->base_ci); |
194 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | 194 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ |
195 | L->ci->top = L->top + LUA_MINSTACK; | 195 | L->ci->top = L->top + LUA_MINSTACK; |
196 | L->ci->status |= 1; /* this level is running a hook */ | ||
196 | lua_assert(L->ci->top <= L->stack_last); | 197 | lua_assert(L->ci->top <= L->stack_last); |
197 | L->allowhook = 0; /* cannot call hooks inside a hook */ | 198 | L->allowhook = 0; /* cannot call hooks inside a hook */ |
198 | lua_unlock(L); | 199 | lua_unlock(L); |
@@ -202,6 +203,7 @@ void luaD_callhook (lua_State *L, int event, int line) { | |||
202 | L->allowhook = 1; | 203 | L->allowhook = 1; |
203 | L->ci->top = restorestack(L, ci_top); | 204 | L->ci->top = restorestack(L, ci_top); |
204 | L->top = restorestack(L, top); | 205 | L->top = restorestack(L, top); |
206 | L->ci->status &= ~1; /* this level is not running a hook anymore */ | ||
205 | } | 207 | } |
206 | } | 208 | } |
207 | 209 | ||
@@ -264,6 +266,9 @@ static StkId tryfuncTM (lua_State *L, StkId func) { | |||
264 | (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) | 266 | (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) |
265 | 267 | ||
266 | 268 | ||
269 | /* | ||
270 | ** returns true if function has been executed (C function) | ||
271 | */ | ||
267 | int luaD_precall (lua_State *L, StkId func, int nresults) { | 272 | int luaD_precall (lua_State *L, StkId func, int nresults) { |
268 | LClosure *cl; | 273 | LClosure *cl; |
269 | ptrdiff_t funcr; | 274 | ptrdiff_t funcr; |
@@ -292,6 +297,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
292 | lua_assert(ci->top <= L->stack_last); | 297 | lua_assert(ci->top <= L->stack_last); |
293 | L->savedpc = p->code; /* starting point */ | 298 | L->savedpc = p->code; /* starting point */ |
294 | ci->tailcalls = 0; | 299 | ci->tailcalls = 0; |
300 | ci->status = 0; | ||
295 | ci->nresults = nresults; | 301 | ci->nresults = nresults; |
296 | for (st = L->top; st < ci->top; st++) | 302 | for (st = L->top; st < ci->top; st++) |
297 | setnilvalue(st); | 303 | setnilvalue(st); |
@@ -301,7 +307,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
301 | luaD_callhook(L, LUA_HOOKCALL, -1); | 307 | luaD_callhook(L, LUA_HOOKCALL, -1); |
302 | L->savedpc--; /* correct 'pc' */ | 308 | L->savedpc--; /* correct 'pc' */ |
303 | } | 309 | } |
304 | return PCRLUA; | 310 | return 0; |
305 | } | 311 | } |
306 | else { /* if is a C function, call it */ | 312 | else { /* if is a C function, call it */ |
307 | CallInfo *ci; | 313 | CallInfo *ci; |
@@ -318,12 +324,8 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
318 | lua_unlock(L); | 324 | lua_unlock(L); |
319 | n = (*curr_func(L)->c.f)(L); /* do the actual call */ | 325 | n = (*curr_func(L)->c.f)(L); /* do the actual call */ |
320 | lua_lock(L); | 326 | lua_lock(L); |
321 | if (n < 0) /* yielding? */ | 327 | luaD_poscall(L, L->top - n); |
322 | return PCRYIELD; | 328 | return 1; |
323 | else { | ||
324 | luaD_poscall(L, L->top - n); | ||
325 | return PCRC; | ||
326 | } | ||
327 | } | 329 | } |
328 | } | 330 | } |
329 | 331 | ||
@@ -378,7 +380,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { | |||
378 | else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) | 380 | else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) |
379 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ | 381 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ |
380 | } | 382 | } |
381 | if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ | 383 | if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ |
382 | luaV_execute(L, 1); /* call it */ | 384 | luaV_execute(L, 1); /* call it */ |
383 | g->nCcalls--; | 385 | g->nCcalls--; |
384 | luaC_checkGC(L); | 386 | luaC_checkGC(L); |
@@ -390,8 +392,8 @@ static void resume (lua_State *L, void *ud) { | |||
390 | CallInfo *ci = L->ci; | 392 | CallInfo *ci = L->ci; |
391 | if (L->status == LUA_OK) { /* start coroutine? */ | 393 | if (L->status == LUA_OK) { /* start coroutine? */ |
392 | lua_assert(ci == L->base_ci && firstArg > L->base); | 394 | lua_assert(ci == L->base_ci && firstArg > L->base); |
393 | if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) | 395 | if (luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* C function? */ |
394 | return; | 396 | return; /* done */ |
395 | } | 397 | } |
396 | else { /* resuming from previous yield */ | 398 | else { /* resuming from previous yield */ |
397 | lua_assert(L->status == LUA_YIELD); | 399 | lua_assert(L->status == LUA_YIELD); |
@@ -434,14 +436,14 @@ LUA_API int lua_resume (lua_State *L, int nargs) { | |||
434 | return resume_error(L, "C stack overflow"); | 436 | return resume_error(L, "C stack overflow"); |
435 | L->baseCcalls = ++G(L)->nCcalls; | 437 | L->baseCcalls = ++G(L)->nCcalls; |
436 | status = luaD_rawrunprotected(L, resume, L->top - nargs); | 438 | status = luaD_rawrunprotected(L, resume, L->top - nargs); |
437 | if (status != LUA_OK) { /* error? */ | 439 | if (status != LUA_OK && status != LUA_YIELD) { /* error? */ |
438 | L->status = cast_byte(status); /* mark thread as `dead' */ | 440 | L->status = cast_byte(status); /* mark thread as `dead' */ |
439 | luaD_seterrorobj(L, status, L->top); | 441 | luaD_seterrorobj(L, status, L->top); |
440 | L->ci->top = L->top; | 442 | L->ci->top = L->top; |
441 | } | 443 | } |
442 | else { | 444 | else { |
443 | lua_assert(L->baseCcalls == G(L)->nCcalls); | 445 | lua_assert(L->baseCcalls == G(L)->nCcalls); |
444 | status = L->status; | 446 | lua_assert(status == L->status); |
445 | } | 447 | } |
446 | --G(L)->nCcalls; | 448 | --G(L)->nCcalls; |
447 | L->baseCcalls = 0; | 449 | L->baseCcalls = 0; |
@@ -457,8 +459,11 @@ LUA_API int lua_yield (lua_State *L, int nresults) { | |||
457 | luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); | 459 | luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); |
458 | L->base = L->top - nresults; /* protect stack slots below */ | 460 | L->base = L->top - nresults; /* protect stack slots below */ |
459 | L->status = LUA_YIELD; | 461 | L->status = LUA_YIELD; |
462 | if (!isLua(L->ci)) /* not inside a hook? */ | ||
463 | luaD_throw(L, LUA_YIELD); | ||
464 | lua_assert(L->ci->status & 1); /* must be inside a hook */ | ||
460 | lua_unlock(L); | 465 | lua_unlock(L); |
461 | return -1; | 466 | return 0; /* otherwise, return to 'luaD_callhook' */ |
462 | } | 467 | } |
463 | 468 | ||
464 | 469 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.h,v 2.8 2006/07/11 15:53:29 roberto Exp roberto $ | 2 | ** $Id: ldo.h,v 2.9 2008/07/03 14:24:36 roberto Exp roberto $ |
3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -28,12 +28,6 @@ | |||
28 | #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) | 28 | #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) |
29 | 29 | ||
30 | 30 | ||
31 | /* results from luaD_precall */ | ||
32 | #define PCRLUA 0 /* initiated a call to a Lua function */ | ||
33 | #define PCRC 1 /* did a call to a C function */ | ||
34 | #define PCRYIELD 2 /* C funtion yielded */ | ||
35 | |||
36 | |||
37 | /* type of protected functions, to be ran by `runprotected' */ | 31 | /* type of protected functions, to be ran by `runprotected' */ |
38 | typedef void (*Pfunc) (lua_State *L, void *ud); | 32 | typedef void (*Pfunc) (lua_State *L, void *ud); |
39 | 33 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.73 2007/09/10 17:59:32 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.74 2008/04/02 16:16:06 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -415,7 +415,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { | |||
415 | traceexec(L); | 415 | traceexec(L); |
416 | if (L->status == LUA_YIELD) { /* did hook yield? */ | 416 | if (L->status == LUA_YIELD) { /* did hook yield? */ |
417 | L->savedpc--; /* undo increment */ | 417 | L->savedpc--; /* undo increment */ |
418 | return; | 418 | luaD_throw(L, LUA_YIELD); |
419 | } | 419 | } |
420 | base = L->base; | 420 | base = L->base; |
421 | } | 421 | } |
@@ -595,51 +595,40 @@ void luaV_execute (lua_State *L, int nexeccalls) { | |||
595 | int b = GETARG_B(i); | 595 | int b = GETARG_B(i); |
596 | int nresults = GETARG_C(i) - 1; | 596 | int nresults = GETARG_C(i) - 1; |
597 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ | 597 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ |
598 | switch (luaD_precall(L, ra, nresults)) { | 598 | if (luaD_precall(L, ra, nresults)) { /* C function? */ |
599 | case PCRLUA: { | 599 | if (nresults >= 0) L->top = L->ci->top; /* adjust results */ |
600 | nexeccalls++; | 600 | base = L->base; |
601 | goto reentry; /* restart luaV_execute over new Lua function */ | 601 | continue; |
602 | } | 602 | } |
603 | case PCRC: { | 603 | else { /* Lua function */ |
604 | /* it was a C function (`precall' called it); adjust results */ | 604 | nexeccalls++; |
605 | if (nresults >= 0) L->top = L->ci->top; | 605 | goto reentry; /* restart luaV_execute over new Lua function */ |
606 | base = L->base; | ||
607 | continue; | ||
608 | } | ||
609 | default: { | ||
610 | return; /* yield */ | ||
611 | } | ||
612 | } | 606 | } |
613 | } | 607 | } |
614 | case OP_TAILCALL: { | 608 | case OP_TAILCALL: { |
615 | int b = GETARG_B(i); | 609 | int b = GETARG_B(i); |
616 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ | 610 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ |
617 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); | 611 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); |
618 | switch (luaD_precall(L, ra, LUA_MULTRET)) { | 612 | if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ |
619 | case PCRLUA: { | 613 | base = L->base; |
620 | /* tail call: put new frame in place of previous one */ | 614 | continue; |
621 | CallInfo *ci = L->ci - 1; /* previous frame */ | 615 | } |
622 | int aux; | 616 | else { |
623 | StkId func = ci->func; | 617 | /* tail call: put new frame in place of previous one */ |
624 | StkId pfunc = (ci+1)->func; /* previous function index */ | 618 | CallInfo *ci = L->ci - 1; /* previous frame */ |
625 | if (L->openupval) luaF_close(L, ci->base); | 619 | int aux; |
626 | L->base = ci->base = ci->func + ((ci+1)->base - pfunc); | 620 | StkId func = ci->func; |
627 | for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ | 621 | StkId pfunc = (ci+1)->func; /* previous function index */ |
628 | setobjs2s(L, func+aux, pfunc+aux); | 622 | if (L->openupval) luaF_close(L, ci->base); |
629 | ci->top = L->top = func+aux; /* correct top */ | 623 | L->base = ci->base = ci->func + ((ci+1)->base - pfunc); |
630 | lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); | 624 | for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ |
631 | ci->savedpc = L->savedpc; | 625 | setobjs2s(L, func+aux, pfunc+aux); |
632 | ci->tailcalls++; /* one more call lost */ | 626 | ci->top = L->top = func+aux; /* correct top */ |
633 | L->ci--; /* remove new frame */ | 627 | lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); |
634 | goto reentry; | 628 | ci->savedpc = L->savedpc; |
635 | } | 629 | ci->tailcalls++; /* one more call lost */ |
636 | case PCRC: { /* it was a C function (`precall' called it) */ | 630 | L->ci--; /* remove new frame */ |
637 | base = L->base; | 631 | goto reentry; |
638 | continue; | ||
639 | } | ||
640 | default: { | ||
641 | return; /* yield */ | ||
642 | } | ||
643 | } | 632 | } |
644 | } | 633 | } |
645 | case OP_RETURN: { | 634 | case OP_RETURN: { |