diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2003-02-27 08:52:30 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2003-02-27 08:52:30 -0300 |
commit | 92f6e0c1bfb27cad95d99e99912e2e0c509dcc30 (patch) | |
tree | 1ab713c16652a5a4e667457041ce7364256a6b2c | |
parent | 5cd99b82b7fc11c527929e5e95f03767f6432d8e (diff) | |
download | lua-92f6e0c1bfb27cad95d99e99912e2e0c509dcc30.tar.gz lua-92f6e0c1bfb27cad95d99e99912e2e0c509dcc30.tar.bz2 lua-92f6e0c1bfb27cad95d99e99912e2e0c509dcc30.zip |
no-nonsense debug information about tail calls
-rw-r--r-- | lbaselib.c | 5 | ||||
-rw-r--r-- | ldblib.c | 9 | ||||
-rw-r--r-- | ldebug.c | 122 | ||||
-rw-r--r-- | ldo.c | 27 | ||||
-rw-r--r-- | lstate.h | 3 | ||||
-rw-r--r-- | lua.h | 5 | ||||
-rw-r--r-- | lvm.c | 3 |
7 files changed, 101 insertions, 73 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lbaselib.c,v 1.122 2003/02/24 16:50:41 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.123 2003/02/24 16:54:20 roberto Exp roberto $ |
3 | ** Basic library | 3 | ** Basic library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -123,6 +123,9 @@ static void getfunc (lua_State *L) { | |||
123 | if (lua_getstack(L, level, &ar) == 0) | 123 | if (lua_getstack(L, level, &ar) == 0) |
124 | luaL_argerror(L, 1, "invalid level"); | 124 | luaL_argerror(L, 1, "invalid level"); |
125 | lua_getinfo(L, "f", &ar); | 125 | lua_getinfo(L, "f", &ar); |
126 | if (lua_isnil(L, -1)) | ||
127 | luaL_error(L, "cannot get/set environment (tail call at level %d)", | ||
128 | level); | ||
126 | } | 129 | } |
127 | } | 130 | } |
128 | 131 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldblib.c,v 1.76 2002/12/19 11:11:55 roberto Exp roberto $ | 2 | ** $Id: ldblib.c,v 1.77 2002/12/20 10:26:33 roberto Exp roberto $ |
3 | ** Interface from Lua to its debug API | 3 | ** Interface from Lua to its debug API |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -137,7 +137,8 @@ static const char KEY_HOOK = 'h'; | |||
137 | 137 | ||
138 | 138 | ||
139 | static void hookf (lua_State *L, lua_Debug *ar) { | 139 | static void hookf (lua_State *L, lua_Debug *ar) { |
140 | static const char *const hooknames[] = {"call", "return", "line", "count"}; | 140 | static const char *const hooknames[] = |
141 | {"call", "return", "line", "count", "tail return"}; | ||
141 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | 142 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); |
142 | lua_rawget(L, LUA_REGISTRYINDEX); | 143 | lua_rawget(L, LUA_REGISTRYINDEX); |
143 | if (lua_isfunction(L, -1)) { | 144 | if (lua_isfunction(L, -1)) { |
@@ -259,8 +260,8 @@ static int errorfb (lua_State *L) { | |||
259 | default: { | 260 | default: { |
260 | if (*ar.what == 'm') /* main? */ | 261 | if (*ar.what == 'm') /* main? */ |
261 | lua_pushfstring(L, " in main chunk"); | 262 | lua_pushfstring(L, " in main chunk"); |
262 | else if (*ar.what == 'C') /* C function? */ | 263 | else if (*ar.what == 'C' || *ar.what == 't') |
263 | lua_pushfstring(L, "%s", ar.short_src); | 264 | lua_pushliteral(L, " ?"); /* C function or tail call */ |
264 | else | 265 | else |
265 | lua_pushfstring(L, " in function <%s:%d>", | 266 | lua_pushfstring(L, " in function <%s:%d>", |
266 | ar.short_src, ar.linedefined); | 267 | ar.short_src, ar.linedefined); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldebug.c,v 1.144 2003/02/11 10:46:24 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 1.145 2003/02/19 10:28:58 roberto Exp roberto $ |
3 | ** Debug Interface | 3 | ** Debug Interface |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -93,13 +93,21 @@ LUA_API int lua_gethookcount (lua_State *L) { | |||
93 | 93 | ||
94 | LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { | 94 | LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { |
95 | int status; | 95 | int status; |
96 | int ci; | 96 | CallInfo *ci; |
97 | lua_lock(L); | 97 | lua_lock(L); |
98 | ci = (L->ci - L->base_ci) - level; | 98 | for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { |
99 | if (ci <= 0) status = 0; /* there is no such level */ | 99 | level--; |
100 | if (!(ci->state & CI_C)) /* Lua function? */ | ||
101 | level -= ci->u.l.tailcalls; /* skip lost tail calls */ | ||
102 | } | ||
103 | if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ | ||
104 | else if (level < 0) { /* level is of a lost tail call */ | ||
105 | status = 1; | ||
106 | ar->i_ci = 0; | ||
107 | } | ||
100 | else { | 108 | else { |
101 | ar->i_ci = ci; | ||
102 | status = 1; | 109 | status = 1; |
110 | ar->i_ci = ci - L->base_ci; | ||
103 | } | 111 | } |
104 | lua_unlock(L); | 112 | lua_unlock(L); |
105 | return status; | 113 | return status; |
@@ -150,31 +158,19 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { | |||
150 | } | 158 | } |
151 | 159 | ||
152 | 160 | ||
153 | static void infoLproto (lua_Debug *ar, Proto *f) { | ||
154 | ar->source = getstr(f->source); | ||
155 | ar->linedefined = f->lineDefined; | ||
156 | ar->what = "Lua"; | ||
157 | } | ||
158 | |||
159 | |||
160 | static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) { | 161 | static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) { |
161 | Closure *cl; | 162 | Closure *cl = clvalue(func); |
162 | if (ttisfunction(func)) | ||
163 | cl = clvalue(func); | ||
164 | else { | ||
165 | luaG_runerror(L, "value for `lua_getinfo' is not a function"); | ||
166 | cl = NULL; /* to avoid warnings */ | ||
167 | } | ||
168 | if (cl->c.isC) { | 163 | if (cl->c.isC) { |
169 | ar->source = "=[C]"; | 164 | ar->source = "=[C]"; |
170 | ar->linedefined = -1; | 165 | ar->linedefined = -1; |
171 | ar->what = "C"; | 166 | ar->what = "C"; |
172 | } | 167 | } |
173 | else | 168 | else { |
174 | infoLproto(ar, cl->l.p); | 169 | ar->source = getstr(cl->l.p->source); |
170 | ar->linedefined = cl->l.p->lineDefined; | ||
171 | ar->what = (ar->linedefined == 0) ? "main" : "Lua"; | ||
172 | } | ||
175 | luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); | 173 | luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); |
176 | if (ar->linedefined == 0) | ||
177 | ar->what = "main"; | ||
178 | } | 174 | } |
179 | 175 | ||
180 | 176 | ||
@@ -190,29 +186,20 @@ static const char *travglobals (lua_State *L, const TObject *o) { | |||
190 | } | 186 | } |
191 | 187 | ||
192 | 188 | ||
193 | static void getname (lua_State *L, const TObject *f, lua_Debug *ar) { | 189 | static void info_tailcall (lua_State *L, lua_Debug *ar) { |
194 | /* try to find a name for given function */ | 190 | ar->name = ar->namewhat = ""; |
195 | if ((ar->name = travglobals(L, f)) != NULL) | 191 | ar->what = "tail"; |
196 | ar->namewhat = "global"; | 192 | ar->linedefined = ar->currentline = -1; |
197 | else ar->namewhat = ""; /* not found */ | 193 | ar->source = "=(tail call)"; |
194 | luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); | ||
195 | ar->nups = 0; | ||
196 | setnilvalue(L->top); | ||
198 | } | 197 | } |
199 | 198 | ||
200 | 199 | ||
201 | 200 | static int getinfo (lua_State *L, const char *what, lua_Debug *ar, | |
202 | LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { | 201 | StkId f, CallInfo *ci) { |
203 | StkId f; | ||
204 | CallInfo *ci; | ||
205 | int status = 1; | 202 | int status = 1; |
206 | lua_lock(L); | ||
207 | if (*what != '>') { /* function is active? */ | ||
208 | ci = L->base_ci + ar->i_ci; | ||
209 | f = ci->base - 1; | ||
210 | } | ||
211 | else { | ||
212 | what++; /* skip the `>' */ | ||
213 | ci = NULL; | ||
214 | f = L->top - 1; | ||
215 | } | ||
216 | for (; *what; what++) { | 203 | for (; *what; what++) { |
217 | switch (*what) { | 204 | switch (*what) { |
218 | case 'S': { | 205 | case 'S': { |
@@ -224,25 +211,48 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { | |||
224 | break; | 211 | break; |
225 | } | 212 | } |
226 | case 'u': { | 213 | case 'u': { |
227 | ar->nups = (ttisfunction(f)) ? clvalue(f)->c.nupvalues : 0; | 214 | ar->nups = clvalue(f)->c.nupvalues; |
228 | break; | 215 | break; |
229 | } | 216 | } |
230 | case 'n': { | 217 | case 'n': { |
231 | ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; | 218 | ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; |
232 | if (ar->namewhat == NULL) | 219 | if (ar->namewhat == NULL) { |
233 | getname(L, f, ar); | 220 | /* try to find a global name */ |
221 | if ((ar->name = travglobals(L, f)) != NULL) | ||
222 | ar->namewhat = "global"; | ||
223 | else ar->namewhat = ""; /* not found */ | ||
224 | } | ||
234 | break; | 225 | break; |
235 | } | 226 | } |
236 | case 'f': { | 227 | case 'f': { |
237 | setobj2s(L->top, f); | 228 | setobj2s(L->top, f); |
238 | status = 2; | ||
239 | break; | 229 | break; |
240 | } | 230 | } |
241 | default: status = 0; /* invalid option */ | 231 | default: status = 0; /* invalid option */ |
242 | } | 232 | } |
243 | } | 233 | } |
244 | if (!ci) L->top--; /* pop function */ | 234 | return status; |
245 | if (status == 2) incr_top(L); | 235 | } |
236 | |||
237 | |||
238 | LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { | ||
239 | int status = 1; | ||
240 | lua_lock(L); | ||
241 | if (*what == '>') { | ||
242 | StkId f = L->top - 1; | ||
243 | if (!ttisfunction(f)) | ||
244 | luaG_runerror(L, "value for `lua_getinfo' is not a function"); | ||
245 | status = getinfo(L, what + 1, ar, f, NULL); | ||
246 | L->top--; /* pop function */ | ||
247 | } | ||
248 | else if (ar->i_ci != 0) { /* no tail call? */ | ||
249 | CallInfo *ci = L->base_ci + ar->i_ci; | ||
250 | lua_assert(ttisfunction(ci->base - 1)); | ||
251 | status = getinfo(L, what, ar, ci->base - 1, ci); | ||
252 | } | ||
253 | else | ||
254 | info_tailcall(L, ar); | ||
255 | if (strchr(what, 'f')) incr_top(L); | ||
246 | lua_unlock(L); | 256 | lua_unlock(L); |
247 | return status; | 257 | return status; |
248 | } | 258 | } |
@@ -480,18 +490,16 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { | |||
480 | } | 490 | } |
481 | 491 | ||
482 | 492 | ||
483 | static Instruction getcurrentinstr (CallInfo *ci) { | ||
484 | return (!isLua(ci)) ? (Instruction)(-1) : | ||
485 | ci_func(ci)->l.p->code[currentpc(ci)]; | ||
486 | } | ||
487 | |||
488 | |||
489 | static const char *getfuncname (CallInfo *ci, const char **name) { | 493 | static const char *getfuncname (CallInfo *ci, const char **name) { |
490 | Instruction i; | 494 | Instruction i; |
495 | if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1)) | ||
496 | return NULL; /* calling function is not Lua (or is unknown) */ | ||
491 | ci--; /* calling function */ | 497 | ci--; /* calling function */ |
492 | i = getcurrentinstr(ci); | 498 | i = ci_func(ci)->l.p->code[currentpc(ci)]; |
493 | return (GET_OPCODE(i) == OP_CALL ? getobjname(ci, GETARG_A(i), name) | 499 | if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL) |
494 | : NULL); /* no useful name found */ | 500 | return getobjname(ci, GETARG_A(i), name); |
501 | else | ||
502 | return NULL; /* no useful name can be found */ | ||
495 | } | 503 | } |
496 | 504 | ||
497 | 505 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.c,v 1.212 2003/01/23 11:31:38 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 1.213 2003/02/13 16:08:47 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 | */ |
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | 32 | ||
33 | 33 | ||
34 | |||
34 | /* | 35 | /* |
35 | ** {====================================================== | 36 | ** {====================================================== |
36 | ** Error-recovery functions (based on long jumps) | 37 | ** Error-recovery functions (based on long jumps) |
@@ -161,7 +162,10 @@ void luaD_callhook (lua_State *L, int event, int line) { | |||
161 | lua_Debug ar; | 162 | lua_Debug ar; |
162 | ar.event = event; | 163 | ar.event = event; |
163 | ar.currentline = line; | 164 | ar.currentline = line; |
164 | ar.i_ci = L->ci - L->base_ci; | 165 | if (event == LUA_HOOKTAILRET) |
166 | ar.i_ci = 0; /* tail call; no debug information about it */ | ||
167 | else | ||
168 | ar.i_ci = L->ci - L->base_ci; | ||
165 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | 169 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ |
166 | L->ci->top = L->top + LUA_MINSTACK; | 170 | L->ci->top = L->top + LUA_MINSTACK; |
167 | L->allowhook = 0; /* cannot call hooks inside a hook */ | 171 | L->allowhook = 0; /* cannot call hooks inside a hook */ |
@@ -232,6 +236,7 @@ StkId luaD_precall (lua_State *L, StkId func) { | |||
232 | L->base = L->ci->base = restorestack(L, funcr) + 1; | 236 | L->base = L->ci->base = restorestack(L, funcr) + 1; |
233 | ci->top = L->base + p->maxstacksize; | 237 | ci->top = L->base + p->maxstacksize; |
234 | ci->u.l.savedpc = p->code; /* starting point */ | 238 | ci->u.l.savedpc = p->code; /* starting point */ |
239 | ci->u.l.tailcalls = 0; | ||
235 | ci->state = CI_SAVEDPC; | 240 | ci->state = CI_SAVEDPC; |
236 | while (L->top < ci->top) | 241 | while (L->top < ci->top) |
237 | setnilvalue(L->top++); | 242 | setnilvalue(L->top++); |
@@ -261,13 +266,21 @@ StkId luaD_precall (lua_State *L, StkId func) { | |||
261 | } | 266 | } |
262 | 267 | ||
263 | 268 | ||
269 | static StkId callrethooks (lua_State *L, StkId firstResult) { | ||
270 | ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ | ||
271 | luaD_callhook(L, LUA_HOOKRET, -1); | ||
272 | if (!(L->ci->state & CI_C)) { /* Lua function? */ | ||
273 | while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ | ||
274 | luaD_callhook(L, LUA_HOOKTAILRET, -1); | ||
275 | } | ||
276 | return restorestack(L, fr); | ||
277 | } | ||
278 | |||
279 | |||
264 | void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { | 280 | void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { |
265 | StkId res; | 281 | StkId res; |
266 | if (L->hookmask & LUA_MASKRET) { | 282 | if (L->hookmask & LUA_MASKRET) |
267 | ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ | 283 | firstResult = callrethooks(L, firstResult); |
268 | luaD_callhook(L, LUA_HOOKRET, -1); | ||
269 | firstResult = restorestack(L, fr); | ||
270 | } | ||
271 | res = L->base - 1; /* res == final position of 1st result */ | 284 | res = L->base - 1; /* res == final position of 1st result */ |
272 | L->ci--; | 285 | L->ci--; |
273 | L->base = L->ci->base; /* restore base */ | 286 | L->base = L->ci->base; /* restore base */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 1.107 2002/11/22 18:01:46 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 1.108 2002/11/25 17:47:13 roberto Exp roberto $ |
3 | ** Global State | 3 | ** Global State |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -80,6 +80,7 @@ typedef struct CallInfo { | |||
80 | struct { /* for Lua functions */ | 80 | struct { /* for Lua functions */ |
81 | const Instruction *savedpc; | 81 | const Instruction *savedpc; |
82 | const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ | 82 | const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ |
83 | int tailcalls; /* number of tail calls lost under this entry */ | ||
83 | } l; | 84 | } l; |
84 | struct { /* for C functions */ | 85 | struct { /* for C functions */ |
85 | int dummy; /* just to avoid an empty struct */ | 86 | int dummy; /* just to avoid an empty struct */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lua.h,v 1.172 2003/02/18 16:13:15 roberto Exp roberto $ | 2 | ** $Id: lua.h,v 1.173 2003/02/24 16:54:20 roberto Exp roberto $ |
3 | ** Lua - An Extensible Extension Language | 3 | ** Lua - An Extensible Extension Language |
4 | ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil | 4 | ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil |
5 | ** http://www.lua.org mailto:info@lua.org | 5 | ** http://www.lua.org mailto:info@lua.org |
@@ -317,6 +317,7 @@ LUA_API int lua_pushupvalues (lua_State *L); | |||
317 | #define LUA_HOOKRET 1 | 317 | #define LUA_HOOKRET 1 |
318 | #define LUA_HOOKLINE 2 | 318 | #define LUA_HOOKLINE 2 |
319 | #define LUA_HOOKCOUNT 3 | 319 | #define LUA_HOOKCOUNT 3 |
320 | #define LUA_HOOKTAILRET 4 | ||
320 | 321 | ||
321 | 322 | ||
322 | /* | 323 | /* |
@@ -351,7 +352,7 @@ struct lua_Debug { | |||
351 | int event; | 352 | int event; |
352 | const char *name; /* (n) */ | 353 | const char *name; /* (n) */ |
353 | const char *namewhat; /* (n) `global', `local', `field', `method' */ | 354 | const char *namewhat; /* (n) `global', `local', `field', `method' */ |
354 | const char *what; /* (S) `Lua' function, `C' function, Lua `main' */ | 355 | const char *what; /* (S) `Lua', `C', `main', `tail' */ |
355 | const char *source; /* (S) */ | 356 | const char *source; /* (S) */ |
356 | int currentline; /* (l) */ | 357 | int currentline; /* (l) */ |
357 | int nups; /* (u) number of upvalues */ | 358 | int nups; /* (u) number of upvalues */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 1.275 2003/02/11 10:46:24 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 1.276 2003/02/18 16:02:56 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 | */ |
@@ -648,6 +648,7 @@ StkId luaV_execute (lua_State *L) { | |||
648 | (L->ci - 1)->top = L->top = base+aux; /* correct top */ | 648 | (L->ci - 1)->top = L->top = base+aux; /* correct top */ |
649 | lua_assert(L->ci->state & CI_SAVEDPC); | 649 | lua_assert(L->ci->state & CI_SAVEDPC); |
650 | (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; | 650 | (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; |
651 | (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ | ||
651 | (L->ci - 1)->state = CI_SAVEDPC; | 652 | (L->ci - 1)->state = CI_SAVEDPC; |
652 | L->ci--; /* remove new frame */ | 653 | L->ci--; /* remove new frame */ |
653 | L->base = L->ci->base; | 654 | L->base = L->ci->base; |