stacks.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* A stack holds a frame chain
  2. * Copyright (C) 1996,1997,2000,2001, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include "libguile/_scm.h"
  23. #include "libguile/control.h"
  24. #include "libguile/eval.h"
  25. #include "libguile/debug.h"
  26. #include "libguile/continuations.h"
  27. #include "libguile/struct.h"
  28. #include "libguile/macros.h"
  29. #include "libguile/procprop.h"
  30. #include "libguile/modules.h"
  31. #include "libguile/root.h"
  32. #include "libguile/strings.h"
  33. #include "libguile/vm.h" /* to capture vm stacks */
  34. #include "libguile/frames.h" /* vm frames */
  35. #include "libguile/validate.h"
  36. #include "libguile/stacks.h"
  37. #include "libguile/private-options.h"
  38. static SCM scm_sys_stacks;
  39. /* {Stacks}
  40. *
  41. * The stack is represented as a struct that holds a frame. The frame itself is
  42. * linked to the next frame, or #f.
  43. *
  44. * Stacks
  45. * Constructor
  46. * make-stack
  47. * Selectors
  48. * stack-id
  49. * stack-ref
  50. * Inspector
  51. * stack-length
  52. */
  53. /* Count number of debug info frames on a stack, beginning with FRAME.
  54. */
  55. static long
  56. stack_depth (SCM frame)
  57. {
  58. long n = 0;
  59. /* count frames, skipping boot frames */
  60. for (; scm_is_true (frame); frame = scm_frame_previous (frame))
  61. ++n;
  62. return n;
  63. }
  64. /* Narrow STACK by cutting away stackframes (mutatingly).
  65. *
  66. * Inner frames (most recent) are cut by advancing the frames pointer.
  67. * Outer frames are cut by decreasing the recorded length.
  68. *
  69. * Cut maximally INNER inner frames and OUTER outer frames using
  70. * the keys INNER_KEY and OUTER_KEY.
  71. *
  72. * Frames are cut away starting at the end points and moving towards
  73. * the center of the stack. The key is normally compared to the
  74. * operator in application frames. Frames up to and including the key
  75. * are cut.
  76. *
  77. * If INNER_KEY is #t a different scheme is used for inner frames:
  78. *
  79. * Frames up to but excluding the first source frame originating from
  80. * a user module are cut, except for possible application frames
  81. * between the user frame and the last system frame previously
  82. * encountered.
  83. */
  84. static SCM*
  85. find_prompt (SCM key)
  86. {
  87. SCM *fp;
  88. if (!scm_dynstack_find_prompt (&SCM_I_CURRENT_THREAD->dynstack, key,
  89. NULL, &fp, NULL, NULL, NULL))
  90. scm_misc_error ("make-stack", "Prompt tag not found while narrowing stack",
  91. scm_list_1 (key));
  92. return fp;
  93. }
  94. static void
  95. narrow_stack (SCM stack, SCM inner_cut, SCM outer_cut)
  96. {
  97. unsigned long int len;
  98. SCM frame;
  99. len = SCM_STACK_LENGTH (stack);
  100. frame = SCM_STACK_FRAME (stack);
  101. /* Cut inner part. */
  102. if (scm_is_true (scm_procedure_p (inner_cut)))
  103. {
  104. /* Cut until the given procedure is seen. */
  105. for (; len ;)
  106. {
  107. SCM proc = scm_frame_procedure (frame);
  108. len--;
  109. frame = scm_frame_previous (frame);
  110. if (scm_is_eq (proc, inner_cut))
  111. break;
  112. }
  113. }
  114. else if (scm_is_integer (inner_cut))
  115. {
  116. /* Cut specified number of frames. */
  117. long inner = scm_to_int (inner_cut);
  118. for (; inner && len; --inner)
  119. {
  120. len--;
  121. frame = scm_frame_previous (frame);
  122. }
  123. }
  124. else
  125. {
  126. /* Cut until the given prompt tag is seen. */
  127. SCM *fp = find_prompt (inner_cut);
  128. for (; len; len--, frame = scm_frame_previous (frame))
  129. if (fp == SCM_VM_FRAME_FP (frame) - SCM_VM_FRAME_OFFSET (frame))
  130. break;
  131. }
  132. SCM_SET_STACK_LENGTH (stack, len);
  133. SCM_SET_STACK_FRAME (stack, frame);
  134. /* Cut outer part. */
  135. if (scm_is_true (scm_procedure_p (outer_cut)))
  136. {
  137. /* Cut until the given procedure is seen. */
  138. for (; len ;)
  139. {
  140. frame = scm_stack_ref (stack, scm_from_long (len - 1));
  141. len--;
  142. if (scm_is_eq (scm_frame_procedure (frame), outer_cut))
  143. break;
  144. }
  145. }
  146. else if (scm_is_integer (outer_cut))
  147. {
  148. /* Cut specified number of frames. */
  149. long outer = scm_to_int (outer_cut);
  150. if (outer < len)
  151. len -= outer;
  152. else
  153. len = 0;
  154. }
  155. else
  156. {
  157. /* Cut until the given prompt tag is seen. */
  158. SCM *fp = find_prompt (outer_cut);
  159. while (len)
  160. {
  161. frame = scm_stack_ref (stack, scm_from_long (len - 1));
  162. len--;
  163. if (fp == SCM_VM_FRAME_FP (frame) - SCM_VM_FRAME_OFFSET (frame))
  164. break;
  165. }
  166. }
  167. SCM_SET_STACK_LENGTH (stack, len);
  168. }
  169. /* Stacks
  170. */
  171. SCM scm_stack_type;
  172. SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0,
  173. (SCM obj),
  174. "Return @code{#t} if @var{obj} is a calling stack.")
  175. #define FUNC_NAME s_scm_stack_p
  176. {
  177. return scm_from_bool(SCM_STACKP (obj));
  178. }
  179. #undef FUNC_NAME
  180. SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
  181. (SCM obj, SCM args),
  182. "Create a new stack. If @var{obj} is @code{#t}, the current\n"
  183. "evaluation stack is used for creating the stack frames,\n"
  184. "otherwise the frames are taken from @var{obj} (which must be\n"
  185. "a continuation or a frame object).\n"
  186. "\n"
  187. "@var{args} should be a list containing any combination of\n"
  188. "integer, procedure, prompt tag and @code{#t} values.\n"
  189. "\n"
  190. "These values specify various ways of cutting away uninteresting\n"
  191. "stack frames from the top and bottom of the stack that\n"
  192. "@code{make-stack} returns. They come in pairs like this:\n"
  193. "@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n"
  194. "@var{outer_cut_2} @dots{})}.\n"
  195. "\n"
  196. "Each @var{inner_cut_i} can be @code{#t}, an integer, a prompt\n"
  197. "tag, or a procedure. @code{#t} means to cut away all frames up\n"
  198. "to but excluding the first user module frame. An integer means\n"
  199. "to cut away exactly that number of frames. A prompt tag means\n"
  200. "to cut away all frames that are inside a prompt with the given\n"
  201. "tag. A procedure means to cut away all frames up to but\n"
  202. "excluding the application frame whose procedure matches the\n"
  203. "specified one.\n"
  204. "\n"
  205. "Each @var{outer_cut_i} can be an integer, a prompt tag, or a\n"
  206. "procedure. An integer means to cut away that number of frames.\n"
  207. "A prompt tag means to cut away all frames that are outside a\n"
  208. "prompt with the given tag. A procedure means to cut away\n"
  209. "frames down to but excluding the application frame whose\n"
  210. "procedure matches the specified one.\n"
  211. "\n"
  212. "If the @var{outer_cut_i} of the last pair is missing, it is\n"
  213. "taken as 0.")
  214. #define FUNC_NAME s_scm_make_stack
  215. {
  216. long n;
  217. SCM frame;
  218. SCM stack;
  219. SCM inner_cut, outer_cut;
  220. /* Extract a pointer to the innermost frame of whatever object
  221. scm_make_stack was given. */
  222. if (scm_is_eq (obj, SCM_BOOL_T))
  223. {
  224. SCM cont;
  225. struct scm_vm_cont *c;
  226. cont = scm_i_capture_current_stack ();
  227. c = SCM_VM_CONT_DATA (cont);
  228. frame = scm_c_make_frame (cont, c->fp + c->reloc,
  229. c->sp + c->reloc, c->ra,
  230. c->reloc);
  231. }
  232. else if (SCM_VM_FRAME_P (obj))
  233. frame = obj;
  234. else if (SCM_CONTINUATIONP (obj))
  235. /* FIXME: Narrowing to prompt tags should narrow with respect to the prompts
  236. that were in place when the continuation was captured. */
  237. frame = scm_i_continuation_to_frame (obj);
  238. else
  239. {
  240. SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
  241. /* not reached */
  242. }
  243. /* FIXME: is this even possible? */
  244. if (scm_is_true (frame)
  245. && SCM_PROGRAM_P (scm_frame_procedure (frame))
  246. && SCM_PROGRAM_IS_BOOT (scm_frame_procedure (frame)))
  247. frame = scm_frame_previous (frame);
  248. if (scm_is_false (frame))
  249. return SCM_BOOL_F;
  250. /* Count number of frames. Also get stack id tag and check whether
  251. there are more stackframes than we want to record
  252. (SCM_BACKTRACE_MAXDEPTH). */
  253. n = stack_depth (frame);
  254. /* Make the stack object. */
  255. stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL);
  256. SCM_SET_STACK_LENGTH (stack, n);
  257. SCM_SET_STACK_ID (stack, scm_stack_id (obj));
  258. SCM_SET_STACK_FRAME (stack, frame);
  259. /* Narrow the stack according to the arguments given to scm_make_stack. */
  260. SCM_VALIDATE_REST_ARGUMENT (args);
  261. while (n > 0 && !scm_is_null (args))
  262. {
  263. inner_cut = SCM_CAR (args);
  264. args = SCM_CDR (args);
  265. if (scm_is_null (args))
  266. {
  267. outer_cut = SCM_INUM0;
  268. }
  269. else
  270. {
  271. outer_cut = SCM_CAR (args);
  272. args = SCM_CDR (args);
  273. }
  274. narrow_stack (stack,
  275. inner_cut,
  276. outer_cut);
  277. n = SCM_STACK_LENGTH (stack);
  278. }
  279. if (n > 0)
  280. return stack;
  281. else
  282. return SCM_BOOL_F;
  283. }
  284. #undef FUNC_NAME
  285. SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
  286. (SCM stack),
  287. "Return the identifier given to @var{stack} by @code{start-stack}.")
  288. #define FUNC_NAME s_scm_stack_id
  289. {
  290. if (scm_is_eq (stack, SCM_BOOL_T)
  291. /* FIXME: frame case assumes frame still live on the stack, and no
  292. intervening start-stack. Hmm... */
  293. || SCM_VM_FRAME_P (stack))
  294. {
  295. /* Fetch most recent start-stack tag. */
  296. SCM stacks = scm_fluid_ref (scm_sys_stacks);
  297. return scm_is_pair (stacks) ? scm_caar (stacks) : SCM_BOOL_F;
  298. }
  299. else if (SCM_CONTINUATIONP (stack))
  300. /* FIXME: implement me */
  301. return SCM_BOOL_F;
  302. else
  303. {
  304. SCM_WRONG_TYPE_ARG (SCM_ARG1, stack);
  305. /* not reached */
  306. }
  307. }
  308. #undef FUNC_NAME
  309. SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
  310. (SCM stack, SCM index),
  311. "Return the @var{index}'th frame from @var{stack}.")
  312. #define FUNC_NAME s_scm_stack_ref
  313. {
  314. unsigned long int c_index;
  315. SCM frame;
  316. SCM_VALIDATE_STACK (1, stack);
  317. c_index = scm_to_unsigned_integer (index, 0, SCM_STACK_LENGTH(stack)-1);
  318. frame = SCM_STACK_FRAME (stack);
  319. while (c_index--)
  320. frame = scm_frame_previous (frame);
  321. return frame;
  322. }
  323. #undef FUNC_NAME
  324. SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
  325. (SCM stack),
  326. "Return the length of @var{stack}.")
  327. #define FUNC_NAME s_scm_stack_length
  328. {
  329. SCM_VALIDATE_STACK (1, stack);
  330. return scm_from_long (SCM_STACK_LENGTH (stack));
  331. }
  332. #undef FUNC_NAME
  333. void
  334. scm_init_stacks ()
  335. {
  336. scm_sys_stacks = scm_make_fluid ();
  337. scm_c_define ("%stacks", scm_sys_stacks);
  338. scm_stack_type = scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT),
  339. SCM_UNDEFINED);
  340. scm_set_struct_vtable_name_x (scm_stack_type,
  341. scm_from_latin1_symbol ("stack"));
  342. #include "libguile/stacks.x"
  343. }
  344. /*
  345. Local Variables:
  346. c-file-style: "gnu"
  347. End:
  348. */