diff options
author | David Walter Seikel | 2012-01-23 23:36:30 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-23 23:36:30 +1000 |
commit | 6523585c66c04cea54df50013df8886b589847d8 (patch) | |
tree | 0b22aee7064166d88595eda260ca2d17c0773da5 /libraries/luajit-2.0/src/lj_debug.c | |
parent | Update the EFL to what I'm actually using, coz I'm using some stuff not yet r... (diff) | |
download | SledjHamr-6523585c66c04cea54df50013df8886b589847d8.zip SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.gz SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.bz2 SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.xz |
Add luaproc and LuaJIT libraries.
Two versions of LuaJIT, the stable release, and the dev version. Try the dev version first, until ih fails badly.
Diffstat (limited to '')
-rw-r--r-- | libraries/luajit-2.0/src/lj_debug.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/libraries/luajit-2.0/src/lj_debug.c b/libraries/luajit-2.0/src/lj_debug.c new file mode 100644 index 0000000..89434aa --- /dev/null +++ b/libraries/luajit-2.0/src/lj_debug.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* | ||
2 | ** Debugging and introspection. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #define lj_debug_c | ||
7 | #define LUA_CORE | ||
8 | |||
9 | #include "lj_obj.h" | ||
10 | #include "lj_err.h" | ||
11 | #include "lj_debug.h" | ||
12 | #include "lj_str.h" | ||
13 | #include "lj_tab.h" | ||
14 | #include "lj_state.h" | ||
15 | #include "lj_frame.h" | ||
16 | #include "lj_bc.h" | ||
17 | #if LJ_HASJIT | ||
18 | #include "lj_jit.h" | ||
19 | #endif | ||
20 | |||
21 | /* -- Frames -------------------------------------------------------------- */ | ||
22 | |||
23 | /* Get frame corresponding to a level. */ | ||
24 | cTValue *lj_debug_frame(lua_State *L, int level, int *size) | ||
25 | { | ||
26 | cTValue *frame, *nextframe, *bot = tvref(L->stack); | ||
27 | /* Traverse frames backwards. */ | ||
28 | for (nextframe = frame = L->base-1; frame > bot; ) { | ||
29 | if (frame_gc(frame) == obj2gco(L)) | ||
30 | level++; /* Skip dummy frames. See lj_meta_call(). */ | ||
31 | if (level-- == 0) { | ||
32 | *size = (int)(nextframe - frame); | ||
33 | return frame; /* Level found. */ | ||
34 | } | ||
35 | nextframe = frame; | ||
36 | if (frame_islua(frame)) { | ||
37 | frame = frame_prevl(frame); | ||
38 | } else { | ||
39 | if (frame_isvarg(frame)) | ||
40 | level++; /* Skip vararg pseudo-frame. */ | ||
41 | frame = frame_prevd(frame); | ||
42 | } | ||
43 | } | ||
44 | *size = level; | ||
45 | return NULL; /* Level not found. */ | ||
46 | } | ||
47 | |||
48 | /* Invalid bytecode position. */ | ||
49 | #define NO_BCPOS (~(BCPos)0) | ||
50 | |||
51 | /* Return bytecode position for function/frame or NO_BCPOS. */ | ||
52 | static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | ||
53 | { | ||
54 | const BCIns *ins; | ||
55 | GCproto *pt; | ||
56 | BCPos pos; | ||
57 | lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD); | ||
58 | if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */ | ||
59 | return NO_BCPOS; | ||
60 | } else if (nextframe == NULL) { /* Lua function on top. */ | ||
61 | void *cf = cframe_raw(L->cframe); | ||
62 | if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf)) | ||
63 | return NO_BCPOS; | ||
64 | ins = cframe_pc(cf); /* Only happens during error/hook handling. */ | ||
65 | } else { | ||
66 | if (frame_islua(nextframe)) { | ||
67 | ins = frame_pc(nextframe); | ||
68 | } else if (frame_iscont(nextframe)) { | ||
69 | ins = frame_contpc(nextframe); | ||
70 | } else { | ||
71 | /* Lua function below errfunc/gc/hook: find cframe to get the PC. */ | ||
72 | void *cf = cframe_raw(L->cframe); | ||
73 | TValue *f = L->base-1; | ||
74 | if (cf == NULL) | ||
75 | return NO_BCPOS; | ||
76 | while (f > nextframe) { | ||
77 | if (frame_islua(f)) { | ||
78 | f = frame_prevl(f); | ||
79 | } else { | ||
80 | if (frame_isc(f)) | ||
81 | cf = cframe_raw(cframe_prev(cf)); | ||
82 | f = frame_prevd(f); | ||
83 | } | ||
84 | } | ||
85 | if (cframe_prev(cf)) | ||
86 | cf = cframe_raw(cframe_prev(cf)); | ||
87 | ins = cframe_pc(cf); | ||
88 | } | ||
89 | } | ||
90 | pt = funcproto(fn); | ||
91 | pos = proto_bcpos(pt, ins) - 1; | ||
92 | #if LJ_HASJIT | ||
93 | if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */ | ||
94 | GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); | ||
95 | lua_assert(bc_isret(bc_op(ins[-1]))); | ||
96 | pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); | ||
97 | } | ||
98 | #endif | ||
99 | return pos; | ||
100 | } | ||
101 | |||
102 | /* -- Line numbers -------------------------------------------------------- */ | ||
103 | |||
104 | /* Get line number for a bytecode position. */ | ||
105 | BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc) | ||
106 | { | ||
107 | const void *lineinfo = proto_lineinfo(pt); | ||
108 | if (pc <= pt->sizebc && lineinfo) { | ||
109 | BCLine first = pt->firstline; | ||
110 | if (pc == pt->sizebc) return first + pt->numline; | ||
111 | if (pc-- == 0) return first; | ||
112 | if (pt->numline < 256) | ||
113 | return first + (BCLine)((const uint8_t *)lineinfo)[pc]; | ||
114 | else if (pt->numline < 65536) | ||
115 | return first + (BCLine)((const uint16_t *)lineinfo)[pc]; | ||
116 | else | ||
117 | return first + (BCLine)((const uint32_t *)lineinfo)[pc]; | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* Get line number for function/frame. */ | ||
123 | static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | ||
124 | { | ||
125 | BCPos pc = debug_framepc(L, fn, nextframe); | ||
126 | if (pc != NO_BCPOS) { | ||
127 | GCproto *pt = funcproto(fn); | ||
128 | lua_assert(pc <= pt->sizebc); | ||
129 | return lj_debug_line(pt, pc); | ||
130 | } | ||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | /* -- Variable names ------------------------------------------------------ */ | ||
135 | |||
136 | /* Read ULEB128 value. */ | ||
137 | static uint32_t debug_read_uleb128(const uint8_t **pp) | ||
138 | { | ||
139 | const uint8_t *p = *pp; | ||
140 | uint32_t v = *p++; | ||
141 | if (LJ_UNLIKELY(v >= 0x80)) { | ||
142 | int sh = 0; | ||
143 | v &= 0x7f; | ||
144 | do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); | ||
145 | } | ||
146 | *pp = p; | ||
147 | return v; | ||
148 | } | ||
149 | |||
150 | /* Get name of a local variable from slot number and PC. */ | ||
151 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) | ||
152 | { | ||
153 | const uint8_t *p = proto_varinfo(pt); | ||
154 | if (p) { | ||
155 | BCPos lastpc = 0; | ||
156 | for (;;) { | ||
157 | const char *name = (const char *)p; | ||
158 | uint32_t vn = *p++; | ||
159 | BCPos startpc, endpc; | ||
160 | if (vn < VARNAME__MAX) { | ||
161 | if (vn == VARNAME_END) break; /* End of varinfo. */ | ||
162 | } else { | ||
163 | while (*p++) ; /* Skip over variable name string. */ | ||
164 | } | ||
165 | lastpc = startpc = lastpc + debug_read_uleb128(&p); | ||
166 | if (startpc > pc) break; | ||
167 | endpc = startpc + debug_read_uleb128(&p); | ||
168 | if (pc < endpc && slot-- == 0) { | ||
169 | if (vn < VARNAME__MAX) { | ||
170 | #define VARNAMESTR(name, str) str "\0" | ||
171 | name = VARNAMEDEF(VARNAMESTR); | ||
172 | #undef VARNAMESTR | ||
173 | if (--vn) while (*name++ || --vn) ; | ||
174 | } | ||
175 | return name; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | /* Get name of local variable from 1-based slot number and function/frame. */ | ||
183 | static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | ||
184 | const char **name, BCReg slot1) | ||
185 | { | ||
186 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; | ||
187 | uint32_t size = (uint32_t)ar->i_ci >> 16; | ||
188 | TValue *frame = tvref(L->stack) + offset; | ||
189 | TValue *nextframe = size ? frame + size : NULL; | ||
190 | GCfunc *fn = frame_func(frame); | ||
191 | BCPos pc = debug_framepc(L, fn, nextframe); | ||
192 | if (pc != NO_BCPOS && | ||
193 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) | ||
194 | ; | ||
195 | else if (slot1 > 0 && frame + slot1 < (nextframe ? nextframe : L->top)) | ||
196 | *name = "(*temporary)"; | ||
197 | else | ||
198 | *name = NULL; | ||
199 | return frame+slot1; | ||
200 | } | ||
201 | |||
202 | /* Get name of upvalue. */ | ||
203 | const char *lj_debug_uvname(GCproto *pt, uint32_t idx) | ||
204 | { | ||
205 | const uint8_t *p = proto_uvinfo(pt); | ||
206 | lua_assert(idx < pt->sizeuv); | ||
207 | if (!p) return ""; | ||
208 | if (idx) while (*p++ || --idx) ; | ||
209 | return (const char *)p; | ||
210 | } | ||
211 | |||
212 | /* Get name and value of upvalue. */ | ||
213 | const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp) | ||
214 | { | ||
215 | if (tvisfunc(o)) { | ||
216 | GCfunc *fn = funcV(o); | ||
217 | if (isluafunc(fn)) { | ||
218 | GCproto *pt = funcproto(fn); | ||
219 | if (idx < pt->sizeuv) { | ||
220 | *tvp = uvval(&gcref(fn->l.uvptr[idx])->uv); | ||
221 | return lj_debug_uvname(pt, idx); | ||
222 | } | ||
223 | } else { | ||
224 | if (idx < fn->c.nupvalues) { | ||
225 | *tvp = &fn->c.upvalue[idx]; | ||
226 | return ""; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | /* Deduce name of an object from slot number and PC. */ | ||
234 | const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot, | ||
235 | const char **name) | ||
236 | { | ||
237 | const char *lname; | ||
238 | restart: | ||
239 | lname = debug_varname(pt, proto_bcpos(pt, ip), slot); | ||
240 | if (lname != NULL) { *name = lname; return "local"; } | ||
241 | while (--ip > proto_bc(pt)) { | ||
242 | BCIns ins = *ip; | ||
243 | BCOp op = bc_op(ins); | ||
244 | BCReg ra = bc_a(ins); | ||
245 | if (bcmode_a(op) == BCMbase) { | ||
246 | if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins))) | ||
247 | return NULL; | ||
248 | } else if (bcmode_a(op) == BCMdst && ra == slot) { | ||
249 | switch (bc_op(ins)) { | ||
250 | case BC_MOV: | ||
251 | if (ra == slot) { slot = bc_d(ins); goto restart; } | ||
252 | break; | ||
253 | case BC_GGET: | ||
254 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins)))); | ||
255 | return "global"; | ||
256 | case BC_TGETS: | ||
257 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); | ||
258 | if (ip > proto_bc(pt)) { | ||
259 | BCIns insp = ip[-1]; | ||
260 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 && | ||
261 | bc_d(insp) == bc_b(ins)) | ||
262 | return "method"; | ||
263 | } | ||
264 | return "field"; | ||
265 | case BC_UGET: | ||
266 | *name = lj_debug_uvname(pt, bc_d(ins)); | ||
267 | return "upvalue"; | ||
268 | default: | ||
269 | return NULL; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | /* Deduce function name from caller of a frame. */ | ||
277 | const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | ||
278 | { | ||
279 | TValue *pframe; | ||
280 | GCfunc *fn; | ||
281 | BCPos pc; | ||
282 | if (frame_isvarg(frame)) | ||
283 | frame = frame_prevd(frame); | ||
284 | pframe = frame_prev(frame); | ||
285 | fn = frame_func(pframe); | ||
286 | pc = debug_framepc(L, fn, frame); | ||
287 | if (pc != NO_BCPOS) { | ||
288 | GCproto *pt = funcproto(fn); | ||
289 | const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)]; | ||
290 | MMS mm = bcmode_mm(bc_op(*ip)); | ||
291 | if (mm == MM_call) { | ||
292 | BCReg slot = bc_a(*ip); | ||
293 | if (bc_op(*ip) == BC_ITERC) slot -= 3; | ||
294 | return lj_debug_slotname(pt, ip, slot, name); | ||
295 | } else if (mm != MM__MAX) { | ||
296 | *name = strdata(mmname_str(G(L), mm)); | ||
297 | return "metamethod"; | ||
298 | } | ||
299 | } | ||
300 | return NULL; | ||
301 | } | ||
302 | |||
303 | /* -- Source code locations ----------------------------------------------- */ | ||
304 | |||
305 | /* Generate shortened source name. */ | ||
306 | void lj_debug_shortname(char *out, GCstr *str) | ||
307 | { | ||
308 | const char *src = strdata(str); | ||
309 | if (*src == '=') { | ||
310 | strncpy(out, src+1, LUA_IDSIZE); /* Remove first char. */ | ||
311 | out[LUA_IDSIZE-1] = '\0'; /* Ensures null termination. */ | ||
312 | } else if (*src == '@') { /* Output "source", or "...source". */ | ||
313 | size_t len = str->len-1; | ||
314 | src++; /* Skip the `@' */ | ||
315 | if (len >= LUA_IDSIZE) { | ||
316 | src += len-(LUA_IDSIZE-4); /* Get last part of file name. */ | ||
317 | *out++ = '.'; *out++ = '.'; *out++ = '.'; | ||
318 | } | ||
319 | strcpy(out, src); | ||
320 | } else { /* Output [string "string"]. */ | ||
321 | size_t len; /* Length, up to first control char. */ | ||
322 | for (len = 0; len < LUA_IDSIZE-12; len++) | ||
323 | if (((const unsigned char *)src)[len] < ' ') break; | ||
324 | strcpy(out, "[string \""); out += 9; | ||
325 | if (src[len] != '\0') { /* Must truncate? */ | ||
326 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; | ||
327 | strncpy(out, src, len); out += len; | ||
328 | strcpy(out, "..."); out += 3; | ||
329 | } else { | ||
330 | strcpy(out, src); out += len; | ||
331 | } | ||
332 | strcpy(out, "\"]"); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /* Add current location of a frame to error message. */ | ||
337 | void lj_debug_addloc(lua_State *L, const char *msg, | ||
338 | cTValue *frame, cTValue *nextframe) | ||
339 | { | ||
340 | if (frame) { | ||
341 | GCfunc *fn = frame_func(frame); | ||
342 | if (isluafunc(fn)) { | ||
343 | BCLine line = debug_frameline(L, fn, nextframe); | ||
344 | if (line >= 0) { | ||
345 | char buf[LUA_IDSIZE]; | ||
346 | lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); | ||
347 | lj_str_pushf(L, "%s:%d: %s", buf, line, msg); | ||
348 | return; | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | lj_str_pushf(L, "%s", msg); | ||
353 | } | ||
354 | |||
355 | /* Push location string for a bytecode position to Lua stack. */ | ||
356 | void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) | ||
357 | { | ||
358 | GCstr *name = proto_chunkname(pt); | ||
359 | const char *s = strdata(name); | ||
360 | MSize i, len = name->len; | ||
361 | BCLine line = lj_debug_line(pt, pc); | ||
362 | if (*s == '@') { | ||
363 | s++; len--; | ||
364 | for (i = len; i > 0; i--) | ||
365 | if (s[i] == '/' || s[i] == '\\') { | ||
366 | s += i+1; | ||
367 | break; | ||
368 | } | ||
369 | lj_str_pushf(L, "%s:%d", s, line); | ||
370 | } else if (len > 40) { | ||
371 | lj_str_pushf(L, "%p:%d", pt, line); | ||
372 | } else if (*s == '=') { | ||
373 | lj_str_pushf(L, "%s:%d", s+1, line); | ||
374 | } else { | ||
375 | lj_str_pushf(L, "\"%s\":%d", s, line); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | /* -- Public debug API ---------------------------------------------------- */ | ||
380 | |||
381 | /* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */ | ||
382 | |||
383 | LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n) | ||
384 | { | ||
385 | const char *name; | ||
386 | TValue *o = debug_localname(L, ar, &name, (BCReg)n); | ||
387 | if (name) { | ||
388 | copyTV(L, L->top, o); | ||
389 | incr_top(L); | ||
390 | } | ||
391 | return name; | ||
392 | } | ||
393 | |||
394 | LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n) | ||
395 | { | ||
396 | const char *name; | ||
397 | TValue *o = debug_localname(L, ar, &name, (BCReg)n); | ||
398 | if (name) | ||
399 | copyTV(L, o, L->top-1); | ||
400 | L->top--; | ||
401 | return name; | ||
402 | } | ||
403 | |||
404 | LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) | ||
405 | { | ||
406 | int status = 1; | ||
407 | TValue *frame = NULL; | ||
408 | TValue *nextframe = NULL; | ||
409 | GCfunc *fn; | ||
410 | if (*what == '>') { | ||
411 | TValue *func = L->top - 1; | ||
412 | api_check(L, tvisfunc(func)); | ||
413 | fn = funcV(func); | ||
414 | L->top--; | ||
415 | what++; | ||
416 | } else { | ||
417 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; | ||
418 | uint32_t size = (uint32_t)ar->i_ci >> 16; | ||
419 | lua_assert(offset != 0); | ||
420 | frame = tvref(L->stack) + offset; | ||
421 | if (size) nextframe = frame + size; | ||
422 | lua_assert(frame <= tvref(L->maxstack) && | ||
423 | (!nextframe || nextframe <= tvref(L->maxstack))); | ||
424 | fn = frame_func(frame); | ||
425 | lua_assert(fn->c.gct == ~LJ_TFUNC); | ||
426 | } | ||
427 | for (; *what; what++) { | ||
428 | if (*what == 'S') { | ||
429 | if (isluafunc(fn)) { | ||
430 | GCproto *pt = funcproto(fn); | ||
431 | BCLine firstline = pt->firstline; | ||
432 | GCstr *name = proto_chunkname(pt); | ||
433 | ar->source = strdata(name); | ||
434 | lj_debug_shortname(ar->short_src, name); | ||
435 | ar->linedefined = (int)firstline; | ||
436 | ar->lastlinedefined = (int)(firstline + pt->numline); | ||
437 | ar->what = firstline ? "Lua" : "main"; | ||
438 | } else { | ||
439 | ar->source = "=[C]"; | ||
440 | ar->short_src[0] = '['; | ||
441 | ar->short_src[1] = 'C'; | ||
442 | ar->short_src[2] = ']'; | ||
443 | ar->short_src[3] = '\0'; | ||
444 | ar->linedefined = -1; | ||
445 | ar->lastlinedefined = -1; | ||
446 | ar->what = "C"; | ||
447 | } | ||
448 | } else if (*what == 'l') { | ||
449 | ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1; | ||
450 | } else if (*what == 'u') { | ||
451 | ar->nups = fn->c.nupvalues; | ||
452 | } else if (*what == 'n') { | ||
453 | ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL; | ||
454 | if (ar->namewhat == NULL) { | ||
455 | ar->namewhat = ""; | ||
456 | ar->name = NULL; | ||
457 | } | ||
458 | } else if (*what == 'f') { | ||
459 | setfuncV(L, L->top, fn); | ||
460 | incr_top(L); | ||
461 | } else if (*what == 'L') { | ||
462 | if (isluafunc(fn)) { | ||
463 | GCtab *t = lj_tab_new(L, 0, 0); | ||
464 | GCproto *pt = funcproto(fn); | ||
465 | const void *lineinfo = proto_lineinfo(pt); | ||
466 | if (lineinfo) { | ||
467 | BCLine first = pt->firstline; | ||
468 | int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4; | ||
469 | MSize i, szl = pt->sizebc-1; | ||
470 | for (i = 0; i < szl; i++) { | ||
471 | BCLine line = first + | ||
472 | (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] : | ||
473 | sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] : | ||
474 | (BCLine)((const uint32_t *)lineinfo)[i]); | ||
475 | setboolV(lj_tab_setint(L, t, line), 1); | ||
476 | } | ||
477 | } | ||
478 | settabV(L, L->top, t); | ||
479 | } else { | ||
480 | setnilV(L->top); | ||
481 | } | ||
482 | incr_top(L); | ||
483 | } else { | ||
484 | status = 0; /* Bad option. */ | ||
485 | } | ||
486 | } | ||
487 | return status; | ||
488 | } | ||
489 | |||
490 | LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) | ||
491 | { | ||
492 | int size; | ||
493 | cTValue *frame = lj_debug_frame(L, level, &size); | ||
494 | if (frame) { | ||
495 | ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack)); | ||
496 | return 1; | ||
497 | } else { | ||
498 | ar->i_ci = level - size; | ||
499 | return 0; | ||
500 | } | ||
501 | } | ||
502 | |||