aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2003-02-27 08:52:30 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2003-02-27 08:52:30 -0300
commit92f6e0c1bfb27cad95d99e99912e2e0c509dcc30 (patch)
tree1ab713c16652a5a4e667457041ce7364256a6b2c
parent5cd99b82b7fc11c527929e5e95f03767f6432d8e (diff)
downloadlua-92f6e0c1bfb27cad95d99e99912e2e0c509dcc30.tar.gz
lua-92f6e0c1bfb27cad95d99e99912e2e0c509dcc30.tar.bz2
lua-92f6e0c1bfb27cad95d99e99912e2e0c509dcc30.zip
no-nonsense debug information about tail calls
-rw-r--r--lbaselib.c5
-rw-r--r--ldblib.c9
-rw-r--r--ldebug.c122
-rw-r--r--ldo.c27
-rw-r--r--lstate.h3
-rw-r--r--lua.h5
-rw-r--r--lvm.c3
7 files changed, 101 insertions, 73 deletions
diff --git a/lbaselib.c b/lbaselib.c
index 7bf69c8f..9bb71492 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -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
diff --git a/ldblib.c b/ldblib.c
index bef81bdd..9bffa2c8 100644
--- a/ldblib.c
+++ b/ldblib.c
@@ -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
139static void hookf (lua_State *L, lua_Debug *ar) { 139static 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);
diff --git a/ldebug.c b/ldebug.c
index 39b27810..e308e080 100644
--- a/ldebug.c
+++ b/ldebug.c
@@ -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
94LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { 94LUA_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
153static 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
160static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) { 161static 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
193static void getname (lua_State *L, const TObject *f, lua_Debug *ar) { 189static 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 200static int getinfo (lua_State *L, const char *what, lua_Debug *ar,
202LUA_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
238LUA_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
483static Instruction getcurrentinstr (CallInfo *ci) {
484 return (!isLua(ci)) ? (Instruction)(-1) :
485 ci_func(ci)->l.p->code[currentpc(ci)];
486}
487
488
489static const char *getfuncname (CallInfo *ci, const char **name) { 493static 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
diff --git a/ldo.c b/ldo.c
index 057d5b30..253be07a 100644
--- a/ldo.c
+++ b/ldo.c
@@ -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
269static 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
264void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { 280void 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 */
diff --git a/lstate.h b/lstate.h
index 2e184839..6f8e4e6c 100644
--- a/lstate.h
+++ b/lstate.h
@@ -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 */
diff --git a/lua.h b/lua.h
index ed5bb614..b198d3d5 100644
--- a/lua.h
+++ b/lua.h
@@ -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 */
diff --git a/lvm.c b/lvm.c
index c66bbc8a..66d08e3f 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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;