1 /*
2 * top level loop, aux functions for the debugger, stepper for CLISP
3 * Bruno Haible 1990-2005, 2016-2017
4 * ILISP friendliness: Marcus Daniels 8.4.1994
5 * Sam Steingold 2001-2011
6 * German comments translated into English: Stefan Kain 2004-08-30
7 */
8
9 #include "lispbibl.c"
10
11
12 /* -----------------------------------------------------------------------
13 Top-Level-Loop
14
15 SYS::READ-FORM realizes the following features of the top-level REP loop
16 and of the debug REP loop:
17
18 - The prompt. When the input stream is interactive, a prompt is printed
19 that reminds the user that the system is expecting a Lisp form.
20 "> " or "1. Break> " or something like this.
21 When the input stream is not interactive, such as in "clisp < in.lisp",
22 no prompt is emitted, because these prompt would accumulate on standard
23 output, without being useful.
24 We use the criterion "interactive", not the criterion "output device =
25 input device", because in situations like "clisp | tee logfile", which
26 are interactive but with different devices for input and output, the
27 prompt is desirable.
28
29 - The continuation prompt [not yet implemented]. When the input stream is
30 interactive a short prompt is printed after each newline that reminds
31 the user if the reader is reading a string "..." or symbol |...| which
32 is not yet complete.
33
34 - The key/command bindings. The user can enter some special words like
35 "help", ":q", "continue", "abort", which are recognized as commands.
36 They can be given as argument or via SYS::*KEY-BINDINGS*. (The name of
37 this variable comes from the Atari ST time, when most of the commands
38 were accessible through function keys F1..F10.) Example:
39
40 [1]> (/ 0)
41
42 *** - division by zero
43 The following restarts are available:
44 ABORT :R1 ABORT
45
46 Break 1 [2]> abort
47
48 [3]>
49
50 - Support for paste: When a user pastes a couple of forms into the command
51 line, all are executed.
52
53 [1]> (setq x 3) (setq y 4) (setq z (sqrt (+ (* x x) (* y y))))
54 3
55 [2]>
56 4
57 [3]>
58 5
59 [4]>
60
61 - Likewise for multiline paste:
62
63 [1]> (setq x 3)
64 (setq y 4)
65 (setq z (sqrt (+ (* x x) (* y y))))
66 3
67 [2]>
68 4
69 [3]>
70 5
71 [4]>
72
73 - Separation of form input and data input.
74
75 Form input is not mistakenly considered as data. Example:
76
77 [1]> (read-line) (cons 'a 'b)
78 data
79 "data" ;
80 NIL
81 [2]>
82 (A . B)
83 [3]>
84
85 *not*
86
87 [1]> (read-line) (cons 'a 'b)
88 "(cons 'a 'b)" ;
89 NIL
90 [2]>
91
92 Data input is not mistakenly considered as forms. Example:
93
94 [1]> (read-char)
95 abcdef
96 #\a
97 [2]>
98
99 *not*
100
101 [1]> (read-char)
102 abcdef
103 #\a
104 [2]>
105 *** - EVAL: variable BCDEF has no value
106
107
108 (SYS::READ-FORM ostream istream prompt [commandlist])
109 read one form (interactively) from the input stream.
110 instead of the form, we also recognize special commands from commandlist
111 (a fresh alist) or SYS::*KEY-BINDINGS*
112 > STACK_1: prompt, a string
113 > STACK_0: commandlist (fresh aliste) or #<UNBOUND>
114 < STACK_1: Output-Stream *standard-output*
115 < STACK_0: Input-Stream *standard-input*
116 < mv_space/mv_count: value = form, NIL or (on EOF) T, T
117 can trigger GC */
read_form(void)118 local maygc Values read_form(void)
119 { /*
120 (defun read-form (ostream istream prompt &optional (command-list nil))
121 (loop
122 (let ((raw (terminal-raw istream nil)))
123 (when (interactive-stream-p istream)
124 (fresh-line ostream)
125 (write-string prompt ostream)
126 (force-output ostream))
127 (let* ((eof-value "EOF")
128 (form (let ((*read-suppress* nil)
129 (*key-bindings* (nreconc command-list
130 *key-bindings*)))
131 (read istream nil eof-value nil))))
132 (terminal-raw istream raw)
133 (if (eql form eof-value)
134 (progn (clear-input istream) (setq istream *debug-io*))
135 (progn (clear-input-upto-newline istream)
136 (return (values form nil)))))))) */
137 #if STACKCHECKR
138 var gcv_object_t* STACKbefore = STACK; /* retain STACK for later */
139 #endif
140 pushSTACK(STACK_1); pushSTACK(STACK_1);
141 STACK_3 = var_stream(S(standard_output),strmflags_wr_ch_B); /* ostream := *STANDARD-OUTPUT* */
142 STACK_2 = var_stream(S(standard_input),strmflags_rd_ch_B); /* istream := *STANDARD-INPUT* */
143 /* stack layout: ostream, istream, prompt, command-list. */
144 pushSTACK(STACK_2);
145 pushSTACK(STACK_3); pushSTACK(NIL); funcall(L(terminal_raw),2);
146 pushSTACK(value1);
147 /* stack layout: ostream, istream, prompt, command-list, inputstream, raw. */
148 if (listen_char(STACK_4) == LISTEN_EOF
149 && !boundp(Symbol_value(S(terminal_read_stream))))
150 goto eof;
151 /* already have characters available (and not in ilisp_mode) -> no prompt */
152 if (ilisp_mode || interactive_stream_p(STACK_4)) {
153 /* interactive input-stream -> prompt output: */
154 #if 0
155 fresh_line(&STACK_5); /* (FRESH-LINE ostream) */
156 #else
157 /* the same, but avoiding infinite recursion
158 (let ((*recurse-count-standard-output*
159 (1+ *recurse-count-standard-output*)))
160 (when (> *recurse-count-standard-output* 3)
161 (setq *recurse-count-standard-output* 0)
162 (makunbound (quote *standard-output*))
163 (let ((*recurse-count-debug-io* (1+ *recurse-count-debug-io*)))
164 (when (> *recurse-count-debug-io* 3)
165 (setq *recurse-count-debug-io* 0)
166 (makunbound (quote *debug-io*))
167 (symbol-stream (quote *debug-io*) :io))
168 (symbol-stream (quote *standard-output*) :output)))
169 (fresh-line *standard-output*)) */
170 /* (incf sys::*recurse-count-standard-output*) */
171 dynamic_bind(S(recurse_count_standard_output),
172 fixnum_inc(Symbol_value(S(recurse_count_standard_output)),1));
173 if (!posfixnump(Symbol_value(S(recurse_count_standard_output))))
174 /* should be fixnum >=0; otherwise emergency correction */
175 Symbol_value(S(recurse_count_standard_output)) = Fixnum_0;
176 if (posfixnum_to_V(Symbol_value(S(recurse_count_standard_output))) > 3) {
177 /* too many nested i/o errors. */
178 Symbol_value(S(recurse_count_standard_output)) = Fixnum_0;
179 Symbol_value(S(standard_output)) = unbound;
180 /* (incf sys::*recurse-count-debug-io*): */
181 dynamic_bind(S(recurse_count_debug_io),
182 fixnum_inc(Symbol_value(S(recurse_count_debug_io)),1));
183 if (!posfixnump(Symbol_value(S(recurse_count_debug_io))))
184 /* should be fixnum >=0; otherwise emergency correction */
185 Symbol_value(S(recurse_count_debug_io)) = Fixnum_0;
186 if (posfixnum_to_V(Symbol_value(S(recurse_count_debug_io))) > 3) {
187 /* too many nested i/o errors. */
188 Symbol_value(S(recurse_count_debug_io)) = Fixnum_0;
189 Symbol_value(S(debug_io)) = unbound;
190 var_stream(S(debug_io),strmflags_rd_ch_B|strmflags_wr_ch_B);
191 }
192 STACK_(5+3+3) = var_stream(S(standard_output),strmflags_wr_ch_B); /* ostream := *STANDARD-OUTPUT* */
193 dynamic_unbind(S(recurse_count_debug_io));
194 }
195 fresh_line(&STACK_(5+3)); /* (FRESH-LINE ostream) */
196 dynamic_unbind(S(recurse_count_standard_output));
197 #endif
198 write_string(&STACK_5,STACK_3); /* (WRITE-STRING prompt ostream) */
199 force_output(STACK_5);
200 } /* Prompt OK */
201 {
202 var gcv_object_t* inputstream_ = &STACK_1;
203 #if 0
204 /* That proves nevertheless awkward: If one presses CTRL-C during input,
205 then one has some commands then in the BREAK loop doubly in the list */
206 {
207 var object list = Symbol_value(S(key_bindings)); /* old Key-Bindings */
208 if (boundp(STACK_2)) /* command-list supplied? */
209 list = nreconc(STACK_2,list); /* add in front */
210 dynamic_bind(S(key_bindings),list); /* bind SYS::*KEY-BINDINGS* */
211 }
212 #else
213 {
214 var object list = (!boundp(STACK_2) ? NIL : (object)STACK_2);
215 dynamic_bind(S(key_bindings),list); /* bind SYS::*KEY-BINDINGS* */
216 }
217 #endif
218 #if !defined(TERMINAL_USES_KEYBOARD) /* Atari - function keys */
219 var bool terminal_read_stream_bound = false;
220 if (interactive_stream_p(*(inputstream_ STACKop 3)) /* only for interactive input streams */
221 && !boundp(Symbol_value(S(terminal_read_stream)))) {
222 /* look for commands, not forms:
223 (multiple-value-bind (line flag) (read-line istream)
224 (let ((h (assoc line *key-bindings* :test (function string-equal))))
225 (when h (funcall (cdr h)) (return t)))
226 (setq istream
227 (make-concatenated-stream
228 (make-string-input-stream
229 (if flag line
230 (concatenate (quote string) line (string #\Newline))))
231 istream))) */
232 do {
233 /* this loop is for win32 and its C-z RET abomination: after
234 C-z (EOF) is processed, there is an empty line in the stream */
235 pushSTACK(*inputstream_); pushSTACK(NIL); pushSTACK(NIL);
236 funcall(L(read_line),3); /* (READ-LINE istream nil nil) */
237 if (nullp(value1)) { /* EOF at line start? */
238 dynamic_unbind(S(key_bindings));
239 goto eof;
240 }
241 } while (Sstring_length(value1) == 0);
242 var object line = value1; /* non-trivial line */
243 /* NB: READ-LINE returns a SIMPLE-STRING in CLISP, so line is simple */
244 { /* search for line in *KEY-BINDINGS*: */
245 var object alist = Symbol_value(S(key_bindings));
246 var uintL input_len = Sstring_length(line);
247 for (;consp(alist);alist = Cdr(alist))
248 if (mconsp(Car(alist)) && simple_string_p(Car(Car(alist)))) {
249 var object key = Car(Car(alist));
250 sstring_un_realloc(key);
251 var uintL len = Sstring_length(key);
252 /* check whether the line starts with the key and a whitespace */
253 if ((len <= input_len) && string_eqcomp_ci(line,0,key,0,len)) {
254 if (len == input_len) goto found;
255 /* now len < input_len */
256 { var chart ch = schar(line,len);
257 if (cint_white_p(as_cint(ch))) goto found;
258 }
259 if (false) { found:
260 pushSTACK(Cdr(Car(alist))); /* save the function */
261 pushSTACK(subsstring(line,len,input_len));
262 funcall(STACK_1,1); /* call the appropriate function */
263 skipSTACK(1); /* drop the function */
264 dynamic_unbind(S(key_bindings));
265 goto eof;
266 }
267 }
268 }
269 }
270 /* create string-input-stream for this line: */
271 if (nullp(value2)) {
272 pushSTACK(line); pushSTACK(O(newline_string));
273 line = string_concat(2); /* maybe need another Newline */
274 }
275 pushSTACK(line); funcall(L(make_string_input_stream),1);
276 /* make concatenated-stream: */
277 pushSTACK(value1); pushSTACK(*inputstream_);
278 funcall(L(make_concatenated_stream),2);
279 dynamic_bind(S(terminal_read_stream),value1);
280 terminal_read_stream_bound = true;
281 *inputstream_ = Symbol_value(S(terminal_read_stream));
282 } else if (streamp(Symbol_value(S(terminal_read_stream)))) {
283 var object stream = Symbol_value(S(terminal_read_stream));
284 Symbol_value(S(terminal_read_stream)) = unbound;
285 dynamic_bind(S(terminal_read_stream),stream);
286 terminal_read_stream_bound = true;
287 *inputstream_ = Symbol_value(S(terminal_read_stream));
288 }
289 #endif /* !defined(TERMINAL_USES_KEYBOARD) */
290 dynamic_bind(S(read_suppress),NIL); /* *READ-SUPPRESS* = NIL */
291 /* read object (recursive-p=NIL, whitespace-p=NIL): */
292 var object obj = stream_read(inputstream_,NIL,NIL);
293 dynamic_unbind(S(read_suppress));
294 #if !defined(TERMINAL_USES_KEYBOARD)
295 if (terminal_read_stream_bound) {
296 var object old_trs = Symbol_value(S(terminal_read_stream));
297 dynamic_unbind(S(terminal_read_stream));
298 if (streamp(old_trs)) {
299 /* maybe need to process something from the first line? */
300 var object strm_list = TheStream(old_trs)->strm_concat_list;
301 pushSTACK(obj); /* save before PEEK-CHAR */
302 pushSTACK(old_trs); /* save before PEEK-CHAR */
303 Symbol_value(S(terminal_read_stream)) =
304 (consp(strm_list) && !nullp(Cdr(strm_list))
305 /* some input on the first line was not processed ? */
306 && (pushSTACK(T), pushSTACK(Car(strm_list)),
307 pushSTACK(NIL), pushSTACK(eof_value),
308 funcall(L(peek_char),4), !eq(value1,eof_value)))
309 ? STACK_0 : (gcv_object_t)unbound;
310 skipSTACK(1); /* drop old_trs */
311 obj = popSTACK();
312 }
313 }
314 #endif
315 dynamic_unbind(S(key_bindings));
316 if (!eq(obj,eof_value)) { /* EOF test (after whitespace) */
317 pushSTACK(obj);
318 pushSTACK(STACK_(4+1)); pushSTACK(STACK_(0+1+1)); funcall(L(terminal_raw),2);
319 /* If not at the beginning of a line, delete input till EOL: */
320 if (interactive_stream_p(STACK_(4+1))
321 && !eq(stream_get_lastchar(STACK_(4+1)),ascii_char(NL))) {
322 while (LISTEN_AVAIL == listen_char(STACK_(4+1))) {
323 var object ch = peek_char(&STACK_(4+1));
324 if (eq(ch,eof_value))
325 break;
326 read_char(&STACK_(4+1));
327 if (eq(ch,ascii_char(NL)))
328 break;
329 }
330 }
331 VALUES2(popSTACK(), NIL); /* (values obj NIL) */
332 skipSTACK(4);
333 #if STACKCHECKR
334 if (STACK != STACKbefore) /* verify if Stack is cleaned up */
335 abort(); /* if not --> go to Debugger */
336 #endif
337 return;
338 }
339 }
340 eof: /* reached EOF */
341 pushSTACK(STACK_4); pushSTACK(STACK_(0+1)); funcall(L(terminal_raw),2);
342 /* call (CLEAR-INPUT istream) to eat EOF from an interactive stream,
343 because a continuable program could misunderstand the EOF: */
344 clear_input(STACK_4);
345 VALUES2(T,T); /* (values T T) */
346 skipSTACK(4);
347 #if STACKCHECKR
348 if (STACK != STACKbefore) /* verify that STACK is cleaned up */
349 abort(); /* if not --> go to Debugger */
350 #endif
351 }
352
353 /* (SYS::READ-FORM prompt [commandlist])
354 reads a form (interactively) from *standard-input*.
355 prompt must be a String.
356 A special key from commandlist (a fresh
357 Alist) or SYS::*KEY-BINDINGS* can be entered instead of a form.
358 Values: form, NIL or (on EOF) T, T */
359 LISPFUN(read_form,seclass_default,1,1,norest,nokey,0,NIL)
360 { read_form(); skipSTACK(2); }
361
362 /* (SYS::READ-EVAL-PRINT prompt [commandlist])
363 reads a form, evaluates it and prints the values.
364 prompt must be a String.
365 A special key from commandlist (a fresh
366 Alist) or SYS::*KEY-BINDINGS* can be entered instead of a form.
367 Values: NIL or (on special key or EOF) T */
368 LISPFUN(read_eval_print,seclass_default,1,1,norest,nokey,0,NIL)
369 /* (defun read-eval-print (prompt &optional (command-list nil))
370 (multiple-value-bind (form flag)
371 (read-form *standard-output* *standard-input* prompt command-list)
372 (if flag
373 form ; return T
374 (progn
375 (setq +++ ++ ++ + + - - form)
376 (let ((vals (multiple-value-list (eval-env form [currentEnvironment]))))
377 (setq /// // // / / vals)
378 (setq *** ** ** * * (first vals))
379 ; primitive:
380 #|(do ((ostream *standard-output*)
381 (L vals (cdr L)))
382 ((atom L))
383 (write (car L) ostream)
384 (when (consp (cdr L))
385 (write-string " ;" ostream)
386 (terpri ostream)))
387 |#; avoid unnecessary empty line between input and output:
388 (let ((ostream *standard-output*))
389 (fresh-line ostream)
390 (when (consp vals)
391 (write (car vals) ostream)
392 (do ((L (cdr vals) (cdr L)))
393 ((atom L))
394 (write-string " ;" ostream)
395 (terpri ostream)
396 (write (car L) ostream)))
397 (elastic-newline ostream)))
398 nil)))) */
399 {
400 read_form(); /* read form */
401 /* stack layout: ostream, istream. */
402 if (!nullp(value2)) { /* flag ? */
403 mv_count=1; skipSTACK(2); return; /* return T as value */
404 }
405 Symbol_value(S(plus3)) = Symbol_value(S(plus2)); /* (SETQ +++ ++) */
406 Symbol_value(S(plus2)) = Symbol_value(S(plus)); /* (SETQ ++ +) */
407 Symbol_value(S(plus)) = Symbol_value(S(minus)); /* (SETQ + -) */
408 Symbol_value(S(minus)) = value1; /* (SETQ - form) */
409 eval(value1); /* evaluate form (in current environment) */
410 pushSTACK(value1); /* save a value */
411 mv_to_list(); /* pack values into list */
412 /* stack layout: ..., val1, vals. */
413 Symbol_value(S(slash3)) = Symbol_value(S(slash2)); /* (SETQ /// //) */
414 Symbol_value(S(slash2)) = Symbol_value(S(slash)); /* (SETQ // /) */
415 Symbol_value(S(slash)) = STACK_0; /* (SETQ / vals) */
416 Symbol_value(S(star3)) = Symbol_value(S(star2)); /* (SETQ *** **) */
417 Symbol_value(S(star2)) = Symbol_value(S(star)); /* (SETQ ** *) */
418 Symbol_value(S(star)) = STACK_1; /* (SETQ * val1) */
419 /* print values to ostream := value from *STANDARD-OUTPUT**/
420 STACK_(1+2) = var_stream(S(standard_output),strmflags_wr_ch_B);
421 #if 0
422 if (mconsp(STACK_0)) {
423 while (1) {
424 var object valsr = STACK_0;
425 STACK_0 = Cdr(valsr);
426 terpri(&STACK_(1+2));
427 prin1(&STACK_(1+2),Car(valsr)); /* print next value */
428 /* ';' as separator before end of line: */
429 if (matomp(STACK_0))
430 break;
431 write_ascii_char(&STACK_(1+2),' ');
432 write_ascii_char(&STACK_(1+2),';');
433 }
434 }
435 #else
436 /* avoid unnecessary empty line between input and output:
437 (There still appears an unnecessary empty line on the screen,
438 if stdin is attached to the terminal and stdout is a pipe, that
439 in the end goes to the terminal again - i.e. via '| tee logfile'.
440 In this case we have to - because of 'logfile' - print an NL to
441 stdout, and because stdin prints an NL at the end of line
442 automatically, this new line really cannot be avoided.) */
443 fresh_line(&STACK_(1+2)); /* (fresh-line ostream) */
444 if (mconsp(STACK_0)) {
445 while (1) {
446 var object valsr = STACK_0;
447 STACK_0 = Cdr(valsr);
448 prin1(&STACK_(1+2),Car(valsr)); /* print next value */
449 /* ';' as separator before end of line: */
450 if (matomp(STACK_0))
451 break;
452 write_ascii_char(&STACK_(1+2),' ');
453 write_ascii_char(&STACK_(1+2),';');
454 terpri(&STACK_(1+2));
455 }
456 }
457 #endif
458 elastic_newline(&STACK_(1+2));
459 skipSTACK(4);
460 VALUES1(NIL);
461 }
462
463 /* Starts the default driver (Read-Eval-Print-Loop)
464 driver(); */
driver(void)465 global void driver (void)
466 {
467 var p_backtrace_t bt_save = back_trace;
468 var struct backtrace_t bt_here;
469 bt_here.bt_next = back_trace;
470 bt_here.bt_function = L(driver);
471 bt_here.bt_stack = STACK STACKop -1;
472 bt_here.bt_num_arg = -1;
473 back_trace = &bt_here;
474 while (1) {
475 var object driverfun = Symbol_value(S(driverstar)); /* value of *DRIVER* */
476 if (nullp(driverfun))
477 break;
478 funcall(driverfun,0); /* call with 0 arguments */
479 }
480 /* Default-Driver: */
481 Symbol_value(S(break_count)) = Fixnum_0; /* SYS::*BREAK-COUNT* := 0 */
482 { /* then, build up the driver-frame: */
483 var gcv_object_t* top_of_frame = STACK; /* pointer on top of frame */
484 var sp_jmp_buf returner; /* memorize return point */
485 finish_entry_frame(DRIVER,returner,,;);
486 /* this is the entry point. */
487 while (1) {
488 /* execute (SYS::READ-EVAL-PRINT "> "): */
489 pushSTACK(O(prompt_string)); /* Prompt "> " */
490 funcall(L(read_eval_print),1);
491 if (eq(value1,T)) /* EOF has been read -> terminate loop */
492 break;
493 }
494 skipSTACK(2); /* skip driver-frame */
495 }
496 back_trace = bt_save;
497 }
498
499 /* Starts a secondary driver (Read-Eval-Print-Loop)
500 break_driver(continuable_p);
501 > continuable_p == can be continued after the driver finishes
502 can trigger GC */
break_driver(bool continuable_p)503 global maygc void break_driver (bool continuable_p) {
504 if (quit_on_signal_in_progress) /* if we are terminating on sighup, */
505 quit(); /* printing the "exiting" messages will fail */
506 var object driverfun = Symbol_value(S(break_driver)); /* *BREAK-DRIVER* */
507 if (!nullp(driverfun)) {
508 pushSTACK(continuable_p ? T : NIL);
509 funcall(driverfun,1); /* call with CONTINUABLE argument */
510 if (!continuable_p) /* not continuable? */
511 reset(1); /* -> back to the previous REPLoop */
512 } else {
513 var p_backtrace_t bt_save = back_trace;
514 var struct backtrace_t bt_here;
515 bt_here.bt_next = back_trace;
516 bt_here.bt_function = L(initial_break_driver);
517 bt_here.bt_stack = STACK STACKop -1;
518 bt_here.bt_num_arg = -1;
519 back_trace = &bt_here;
520 /* Default-Driver: (CLEAR-INPUT *DEBUG-IO*), since whatever has been
521 typed so far, was not typed in anticipation of this error */
522 Symbol_value(S(terminal_read_stream)) = unbound;
523 Symbol_value(S(terminal_read_open_object)) = unbound;
524 clear_input(var_stream(S(debug_io),strmflags_rd_ch_B|strmflags_wr_ch_B));
525 /* SYS::*BREAK-COUNT* increase: */
526 dynamic_bind(S(break_count),fixnum_inc(Symbol_value(S(break_count)),1));
527 if (!posfixnump(Symbol_value(S(break_count)))) /* should be Fixnum >=0 */
528 Symbol_value(S(break_count)) = Fixnum_0; /* oops - fix it! */
529 { /* bind *STANDARD-INPUT* and *STANDARD-OUTPUT* to *DEBUG-IO* */
530 var object stream =
531 var_stream(S(debug_io),strmflags_rd_ch_B|strmflags_wr_ch_B);
532 dynamic_bind(S(standard_input),stream);
533 dynamic_bind(S(standard_output),stream);
534 }
535 dynamic_bind(S(print_escape),T); /* bind *PRINT-ESCAPE* to T */
536 dynamic_bind(S(print_readably),NIL); /* bind *PRINT-READABLY* to NIL */
537 { /* make prompt:
538 (format nil "~S. Break> " SYS::*BREAK-COUNT*)
539 ==
540 (with-output-to-string (s)
541 (prin1 SYS::*BREAK-COUNT* s) (write-string ". Break> " s))
542 ==
543 (let ((s (make-string-output-stream)))
544 (prin1 SYS::*BREAK-COUNT* s) (write-string ". Break> " s)
545 (get-output-stream-string s)) */
546 pushSTACK(make_string_output_stream());
547 prin1(&STACK_0,Symbol_value(S(break_count)));
548 write_sstring(&STACK_0,O(breakprompt_string));
549 STACK_0 = get_output_stream_string(&STACK_0);
550 }
551 { /* make driver-frame: */
552 var gcv_object_t* top_of_frame = STACK; /* pointer over frame */
553 var sp_jmp_buf returner; /* return point */
554 finish_entry_frame(DRIVER,returner,,;);
555 /* re-entry point is here */
556 while (1) {
557 /* (SYS::READ-EVAL-PRINT Prompt) */
558 pushSTACK(STACK_(0+2)); /* Prompt "nnn. Break> " */
559 funcall(L(read_eval_print),1);
560 if (eq(value1,T)) /* EOF -> finish loop */
561 break;
562 }
563 if (!continuable_p) { /* not continuable? */
564 back_trace = bt_save;
565 unwind(); reset(1); /* -> back to the previous REPLoop */
566 }
567 skipSTACK(1+2); /* dissolve driver frame, forget prompt */
568 dynamic_unbind(S(print_readably));
569 dynamic_unbind(S(print_escape));
570 dynamic_unbind(S(standard_output));
571 dynamic_unbind(S(standard_input));
572 dynamic_unbind(S(break_count));
573 }
574 back_trace = bt_save;
575 }
576 }
577
578 LISPFUNN(initial_break_driver,1)
579 {
580 break_driver(!nullp(popSTACK()));
581 VALUES1(NIL);
582 }
583
584 LISPFUNN(load,1)
585 /* (LOAD filename), more primitive version than in CLTL p. 426
586 method:
587 (defun load (filename)
588 (let ((stream (open filename))
589 (end-of-file "EOF")) ; nonrecurring object
590 (loop
591 (let ((obj (read stream nil end-of-file)))
592 (when (eql obj end-of-file) (return))
593 (if (compiled-function-p obj) (funcall obj) (eval obj))))
594 (close stream)
595 t)) */
596 {
597 funcall(L(open),1); /* (OPEN filename) */
598 pushSTACK(value1); /* save stream */
599 while (1) {
600 var object obj = stream_read(&STACK_0,NIL,NIL); /* read object */
601 if (eq(obj,eof_value)) /* EOF -> done */
602 break;
603 if (closurep(obj)) {
604 funcall(obj,0); /* call closure (probably compiled closure) */
605 } else {
606 eval_noenv(obj); /* evaluate other form */
607 }
608 }
609 builtin_stream_close(&STACK_0,0); /* close stream */
610 skipSTACK(1); VALUES1(T);
611 }
612
613 /* -----------------------------------------------------------------------
614 Auxiliary functions for debugger and stepper
615
616 The following functions climb around in the stack, but will never
617 trespass a driver-frame or the upper end of the stack.
618 Valid "stackpointers" are in this context pointers to stack elements or
619 frames, if there is neither the end of stack nor a driver-frame.
620 Modus 1: all stack items
621 Modus 2: frames
622 Modus 3: lexical frames: frame-info has FRAME_BIT = 1 and
623 (SKIP2_BIT = 1 or ENTRYPOINT_BIT = 0 or BLOCKGO_BIT = 1)
624 Modus 4: EVAL- and APPLY-frames: frame-info = [TRAPPED_]EVAL/APPLY_FRAME_INFO
625 Modus 5: APPLY-frames: frame-info = [TRAPPED_]APPLY_FRAME_INFO
626
627 Macro: tests, if FRAME has reached stack end. */
628 #define stack_upend_p() \
629 ( (gcv_object_t*)STACK_start cmpSTACKop FRAME \
630 || (framecode(FRAME_(0)) == DRIVER_frame_info) /* driver-frame = stack end */ \
631 || ((framepointerp(Symbol_value(S(frame_limit_up)))) \
632 && (uTheFramepointer(Symbol_value(S(frame_limit_up))) cmpSTACKop FRAME) /* FRAME > *frame-limit-up* ? */))
633 #define stack_downend_p() \
634 ( FRAME cmpSTACKop STACK \
635 || (framecode(FRAME_(0)) == DRIVER_frame_info) /* driver-frame = stack end */ \
636 || ((framepointerp(Symbol_value(S(frame_limit_down)))) \
637 && (FRAME cmpSTACKop uTheFramepointer(Symbol_value(S(frame_limit_down)))) /* FRAME < *frame-limit-down* ? */))
638
639 /* Macro: Tests, if FRAME points to a frame.
640 first approximation:
641 #define frame_p() (!( (as_oint(FRAME_(0)) & wbit(frame_bit_o)) ==0))
642 in second approximation, considering the frames with Skip2-bit: */
643 #define frame_p() framep(FRAME)
framep(gcv_object_t * FRAME)644 local bool framep (gcv_object_t* FRAME)
645 {
646 /* a normal lisp object is not a frame: */
647 if ((as_oint(FRAME_(0)) & wbit(frame_bit_o)) ==0)
648 return false;
649 /* if a frame starts at FRAME_(-1) without Skip2-bit,
650 then FRAME_(0) is part of this frame, which means,
651 it is not itself the start of a frame: */
652 if ( (!(FRAME==STACK)) /* do not trespass the STACK borders! */
653 && (framecode(FRAME_(-1)) < skip2_limit_t)
654 && framep(FRAME STACKop -1))
655 return false;
656 return true; /* else, a frame starts here. */
657 }
658
659 /* Macro: decreases FRAME down to the next frame. */
660 #define next_frame_down() do { FRAME skipSTACKop -1; } while (!frame_p())
661
662 /* Macro: Tests, if the frame at FRAME is a lexical frame. */
663 #ifdef entrypoint_bit_t
664 #define lexical_frame_p() \
665 ( (framecode(FRAME_(0)) >= skip2_limit_t) \
666 || ( (as_oint(FRAME_(0)) & wbit(entrypoint_bit_o)) ==0) \
667 || blockgo_frame_p(framecode(FRAME_(0))) \
668 )
669 #else
670 #define lexical_frame_p() \
671 (/* (framecode(FRAME_(0)) >= skip2_limit_t) \
672 || */ (framecode(FRAME_(0)) >= entrypoint_limit_t) \
673 || blockgo_frame_p(framecode(FRAME_(0))) \
674 )
675 #endif
blockgo_frame_p(fcint frame_info)676 local bool blockgo_frame_p(fcint frame_info)
677 {
678 switch (frame_info) {
679 case IBLOCK_frame_info:
680 case ITAGBODY_frame_info:
681 case NESTED_IBLOCK_frame_info:
682 case NESTED_ITAGBODY_frame_info:
683 case CBLOCK_CTAGBODY_frame_info:
684 return true;
685 default:
686 return false;
687 }
688 }
689
690 /* Macro: Tests, if the frame at FRAME is an EVAL/APPLY frame. */
691 #define evalapply_frame_p() \
692 ((framecode(FRAME_(0)) & ~(bit(eval_bit_t)|bit(trapped_bit_t))) == \
693 ((EVAL_frame_info|APPLY_frame_info) & ~(bit(eval_bit_t)|bit(trapped_bit_t))))
694
695 /* Macro: Tests, if the frame at FRAME is an APPLY frame. */
696 #define apply_frame_p() \
697 ((framecode(FRAME_(0)) & ~bit(trapped_bit_t)) == (APPLY_frame_info & ~bit(trapped_bit_t)))
698
699 /* UP: jumps up one stackitem */
frame_up_1(gcv_object_t * stackptr)700 local gcv_object_t* frame_up_1 (gcv_object_t* stackptr)
701 {
702 var gcv_object_t* FRAME = stackptr;
703 if (frame_p())
704 FRAME = topofframe(FRAME_(0)); /* Pointer to top of frame */
705 else
706 FRAME skipSTACKop 1; /* pointer to next object */
707 return (stack_upend_p() ? stackptr : FRAME);
708 }
709
710 /* UP: jumpts down one stackitem */
frame_down_1(gcv_object_t * stackptr)711 local gcv_object_t* frame_down_1 (gcv_object_t* stackptr)
712 {
713 var gcv_object_t* FRAME = stackptr;
714 next_frame_down(); /* search next frame below */
715 if (!(topofframe(FRAME_(0)) == stackptr)) /* not directly below stackptr? */
716 FRAME = stackptr STACKop -1;
717 return (stack_downend_p() ? stackptr : FRAME);
718 }
719
720 /* UP: jumps up to frame after next frame */
frame_up_2(gcv_object_t * stackptr)721 local gcv_object_t* frame_up_2 (gcv_object_t* stackptr)
722 {
723 var gcv_object_t* FRAME = stackptr;
724 if (frame_p())
725 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
726 else
727 FRAME skipSTACKop 1; /* pointer to next object */
728 while (1) {
729 if (stack_upend_p())
730 return stackptr;
731 if (as_oint(FRAME_(0)) & wbit(frame_bit_o))
732 return FRAME;
733 FRAME skipSTACKop 1;
734 }
735 }
736
737 /* UP: jumps down to frame after next frame */
frame_down_2(gcv_object_t * stackptr)738 local gcv_object_t* frame_down_2 (gcv_object_t* stackptr)
739 {
740 var gcv_object_t* FRAME = stackptr;
741 next_frame_down(); /* search next frame below */
742 return (stack_downend_p() ? stackptr : FRAME);
743 }
744
745 /* UP: jumps to next higher lexical frame */
frame_up_3(gcv_object_t * stackptr)746 local gcv_object_t* frame_up_3 (gcv_object_t* stackptr)
747 {
748 var gcv_object_t* FRAME = stackptr;
749 if (frame_p())
750 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
751 else
752 FRAME skipSTACKop 1; /* pointer to next object */
753 while (1) {
754 if (stack_upend_p())
755 return stackptr;
756 if (frame_p()) {
757 if (lexical_frame_p())
758 return FRAME;
759 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
760 } else {
761 FRAME skipSTACKop 1;
762 }
763 }
764 }
765
766 /* UP: jumps to next lower lexical frame */
frame_down_3(gcv_object_t * stackptr)767 local gcv_object_t* frame_down_3 (gcv_object_t* stackptr)
768 {
769 var gcv_object_t* FRAME = stackptr;
770 while (1) {
771 next_frame_down(); /* search next frame below */
772 if (stack_downend_p())
773 return stackptr;
774 if (lexical_frame_p())
775 break;
776 }
777 return FRAME;
778 }
779
780 /* UP: jumps to next higher EVAL/APPLY-frame */
frame_up_4(gcv_object_t * stackptr)781 local gcv_object_t* frame_up_4 (gcv_object_t* stackptr)
782 {
783 var gcv_object_t* FRAME = stackptr;
784 if (frame_p())
785 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
786 else
787 FRAME skipSTACKop 1; /* pointer to next object */
788 while (1) {
789 if (stack_upend_p())
790 return stackptr;
791 if (frame_p()) {
792 if (evalapply_frame_p())
793 return FRAME;
794 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
795 } else {
796 FRAME skipSTACKop 1;
797 }
798 }
799 }
800
801 /* UP: jumpt to next lower EVAL/APPLY-frame */
frame_down_4(gcv_object_t * stackptr)802 local gcv_object_t* frame_down_4 (gcv_object_t* stackptr)
803 {
804 var gcv_object_t* FRAME = stackptr;
805 while (1) {
806 next_frame_down(); /* search next frame below */
807 if (stack_downend_p())
808 return stackptr;
809 if (evalapply_frame_p())
810 break;
811 }
812 return FRAME;
813 }
814
815 /* UP: jumps to next higher APPLY-frame */
frame_up_5(gcv_object_t * stackptr)816 local gcv_object_t* frame_up_5 (gcv_object_t* stackptr)
817 {
818 var gcv_object_t* FRAME = stackptr;
819 if (frame_p())
820 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
821 else
822 FRAME skipSTACKop 1; /* pointer to next object */
823 while (1) {
824 if (stack_upend_p())
825 return stackptr;
826 if (frame_p()) {
827 if (apply_frame_p())
828 return FRAME;
829 FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
830 } else {
831 FRAME skipSTACKop 1;
832 }
833 }
834 }
835
836 /* UP: jumps to next lower APPLY-frame */
frame_down_5(gcv_object_t * stackptr)837 local gcv_object_t* frame_down_5 (gcv_object_t* stackptr)
838 {
839 var gcv_object_t* FRAME = stackptr;
840 while (1) {
841 next_frame_down(); /* search next frame below */
842 if (stack_downend_p())
843 return stackptr;
844 if (apply_frame_p())
845 break;
846 }
847 return FRAME;
848 }
849
850 /* type of a pointer to a climb-up resp. climb-down routine: */
851 typedef gcv_object_t* (*climb_fun_t) (gcv_object_t* stackptr);
852
853 local const climb_fun_t frame_up_table[] =
854 { &frame_up_1, &frame_up_2, &frame_up_3, &frame_up_4, &frame_up_5, };
855 local const climb_fun_t frame_down_table[] =
856 { &frame_down_1, &frame_down_2, &frame_down_3, &frame_down_4, &frame_down_5, };
857
858 /* UP: checks and decodes the mode-argument.
859 test_mode_arg(table)
860 > STACK_0: mode
861 > table: table of routines for climbing up resp. climbing down
862 < result: routine for climbing up resp. climbing down
863 increases STACK by 1 */
test_mode_arg(const climb_fun_t * table)864 local climb_fun_t test_mode_arg (const climb_fun_t* table) {
865 var object arg = popSTACK();
866 var uintV mode;
867 if ( !(posfixnump(arg)
868 && ((mode = posfixnum_to_V(arg)) > 0)
869 && (mode<=5))) {
870 pushSTACK(arg); /* TYPE-ERROR slot DATUM */
871 pushSTACK(O(type_climb_mode)); /* TYPE-ERROR slot EXPECTED-TYPE */
872 pushSTACK(arg);
873 pushSTACK(TheSubr(subr_self)->name);
874 error(type_error,GETTEXT("~S: bad frame climbing mode ~S"));
875 }
876 return table[mode-1];
877 }
878
879 /* UP: checks a frame-pointer-argument.
880 test_framepointer_arg()
881 > STACK_0: Lisp object, should be a frame-pointer
882 < result: frame-pointer
883 increases STACK by 1 */
test_framepointer_arg(void)884 local gcv_object_t* test_framepointer_arg (void)
885 {
886 var object arg = popSTACK();
887 if (!framepointerp(arg)) {
888 pushSTACK(arg); /* TYPE-ERROR slot DATUM */
889 pushSTACK(S(frame_pointer)); /* TYPE-ERROR slot EXPECTED-TYPE */
890 pushSTACK(arg);
891 pushSTACK(TheSubr(subr_self)->name);
892 error(type_error,GETTEXT("~S: ~S is not a stack pointer"));
893 }
894 return uTheFramepointer(arg);
895 }
896
897 /* climb n times or as far as possible, according to table
898 > STACK_0: mode
899 > STACK_1: frame pointer
900 > STACK_2: indicator, how far to climb
901 < value1: new frame pointer
902 removes 3 elements from STACK
903 can trigger GC*/
climb_stack(const climb_fun_t * table)904 local maygc Values climb_stack (const climb_fun_t* table) {
905 climb_fun_t climber = test_mode_arg(table);
906 gcv_object_t* stackptr = test_framepointer_arg();
907 object repeat_arg = popSTACK();
908 if (uint32_p(repeat_arg)) {
909 uint32 count = I_to_uint32(repeat_arg);
910 while (count--) stackptr = (*climber)(stackptr);
911 } else while (1) { /* climb as far as possible: */
912 gcv_object_t* next_stackptr = (*climber)(stackptr);
913 if (next_stackptr == stackptr)
914 break;
915 stackptr = next_stackptr;
916 }
917 VALUES1(make_framepointer(stackptr));
918 }
919
920 LISPFUNN(frame_up,3)
921 { /* (SYS::FRAME-UP n framepointer mode)
922 returns the frame-pointer increased by n or the top one. */
923 climb_stack(frame_up_table);
924 }
925
926 LISPFUNN(frame_down,3)
927 { /* (SYS::FRAME-DOWN n framepointer mode)
928 returns the frame-pointer decreased by n or the bottom one. */
929 climb_stack(frame_down_table);
930 }
931
932 LISPFUNN(the_frame,0)
933 { /* (SYS::THE-FRAME) returns the current stackpointer as frame-pointer. */
934 var gcv_object_t* stackptr = STACK;
935 stackptr = frame_up_2(stackptr); /* up to the next higher frame */
936 VALUES1(make_framepointer(stackptr));
937 }
938
939 /* UP: activates the same lexical environment, that was active at
940 framepointer STACK_0.
941 same_env_as();
942 increases STACK by 1, constructs an ENV5-Frame on top of the STACK */
same_env_as(void)943 local void same_env_as (void)
944 {
945 var gcv_object_t* FRAME = test_framepointer_arg();
946 /* 5 Environments still "empty": */
947 var object found_var_env = nullobj;
948 var object found_fun_env = nullobj;
949 var object found_block_env = nullobj;
950 var object found_go_env = nullobj;
951 var object found_decl_env = nullobj;
952 /* and fill: */
953 while (1) {
954 /* search at FRAME downwards for ENV-frames: */
955 while (1) {
956 FRAME skipSTACKop -1;
957 if (FRAME==STACK) /* done? */
958 goto end;
959 if ( frame_p()
960 && (framecode(FRAME_(0)) >= skip2_limit_t)
961 && (!( (as_oint(FRAME_(0)) & wbit(envbind_bit_o)) ==0)))
962 break;
963 }
964 /* found next ENV-frame.
965 its contents fills the empty components of env: */
966 switch (framecode(FRAME_(0)) & envbind_case_mask_t) {
967 case (ENV1V_frame_info & envbind_case_mask_t): /* 1 VAR_ENV */
968 if (eq(found_var_env,nullobj)) { found_var_env = FRAME_(1); }
969 break;
970 case (ENV1F_frame_info & envbind_case_mask_t): /* 1 FUN_ENV */
971 if (eq(found_fun_env,nullobj)) { found_fun_env = FRAME_(1); }
972 break;
973 case (ENV1B_frame_info & envbind_case_mask_t): /* 1 BLOCK_ENV */
974 if (eq(found_block_env,nullobj)) { found_block_env = FRAME_(1); }
975 break;
976 case (ENV1G_frame_info & envbind_case_mask_t): /* 1 GO_ENV */
977 if (eq(found_go_env,nullobj)) { found_go_env = FRAME_(1); }
978 break;
979 case (ENV1D_frame_info & envbind_case_mask_t): /* 1 DECL_ENV */
980 if (eq(found_decl_env,nullobj)) { found_decl_env = FRAME_(1); }
981 break;
982 case (ENV2VD_frame_info & envbind_case_mask_t): /* 1 VAR_ENV and 1 DECL_ENV */
983 if (eq(found_var_env,nullobj)) { found_var_env = FRAME_(1); }
984 if (eq(found_decl_env,nullobj)) { found_decl_env = FRAME_(2); }
985 break;
986 case (ENV5_frame_info & envbind_case_mask_t): /* all 5 environments */
987 if (eq(found_var_env,nullobj)) { found_var_env = FRAME_(1); }
988 if (eq(found_fun_env,nullobj)) { found_fun_env = FRAME_(2); }
989 if (eq(found_block_env,nullobj)) { found_block_env = FRAME_(3); }
990 if (eq(found_go_env,nullobj)) { found_go_env = FRAME_(4); }
991 if (eq(found_decl_env,nullobj)) { found_decl_env = FRAME_(5); }
992 break;
993 default: NOTREACHED;
994 }
995 /* if each single environment of env is filled (/=nullobj),
996 the environment is done: */
997 if ( (!eq(found_var_env,nullobj))
998 && (!eq(found_fun_env,nullobj))
999 && (!eq(found_block_env,nullobj))
1000 && (!eq(found_go_env,nullobj))
1001 && (!eq(found_decl_env,nullobj)))
1002 goto done;
1003 }
1004 end: /* end of stack is reached. */
1005 /* fetch the remaining environment-components from the current environment: */
1006 if (eq(found_var_env,nullobj)) { found_var_env = aktenv.var_env; }
1007 if (eq(found_fun_env,nullobj)) { found_fun_env = aktenv.fun_env; }
1008 if (eq(found_block_env,nullobj)) { found_block_env = aktenv.block_env; }
1009 if (eq(found_go_env,nullobj)) { found_go_env = aktenv.go_env; }
1010 if (eq(found_decl_env,nullobj)) { found_decl_env = aktenv.decl_env; }
1011 done:
1012 /* construct environment-frame: */
1013 make_ENV5_frame();
1014 /* set current environments: */
1015 aktenv.var_env = found_var_env ;
1016 aktenv.fun_env = found_fun_env ;
1017 aktenv.block_env = found_block_env;
1018 aktenv.go_env = found_go_env ;
1019 aktenv.decl_env = found_decl_env ;
1020 }
1021
1022 LISPFUNN(same_env_as,2)
1023 { /* (SYS::SAME-ENV-AS framepointer fun) activates the same lexical
1024 environment, that was active at framepointer, and then calls fun. */
1025 var object fun = popSTACK();
1026 same_env_as(); /* activate environment of framepointer */
1027 funcall(fun,0); /* call fun */
1028 unwind(); /* unwind environment-frame */
1029 }
1030
1031 LISPFUNN(eval_at,2)
1032 { /* (SYS::EVAL-AT framepointer form) activates the same lexical
1033 environment, that was active at framepointer, and evaluates the form. */
1034 var object form = popSTACK();
1035 same_env_as(); /* activate environment of framepointer */
1036 eval(form); /* evaluate form */
1037 unwind(); /* unwind environment-frame */
1038 }
1039
1040 LISPFUNN(eval_frame_p,1)
1041 { /* (SYS::EVAL-FRAME-P framepointer)
1042 indicates, if framepointer points to an EVAL/APPLY-frame. */
1043 var gcv_object_t* FRAME = test_framepointer_arg();
1044 VALUES_IF(evalapply_frame_p());
1045 }
1046
1047 LISPFUNN(driver_frame_p,1)
1048 { /* (SYS::DRIVER-FRAME-P framepointer)
1049 indicates, if framepointer points to a driver-frame. */
1050 var gcv_object_t* FRAME = test_framepointer_arg();
1051 VALUES_IF(framecode(FRAME_(0)) == DRIVER_frame_info);
1052 }
1053
1054 /* error-message, if there is no EVAL/APPLY-frame-pointer.
1055 error_evalframe(obj);
1056 > obj: not an EVAL/APPLY-frame-pointer */
error_evalframe(object obj)1057 local _Noreturn void error_evalframe (object obj) {
1058 pushSTACK(obj);
1059 pushSTACK(TheSubr(subr_self)->name);
1060 error(error_condition,GETTEXT("~S: ~S is not a pointer to an EVAL/APPLY frame"));
1061 }
1062
1063 LISPFUNN(trap_eval_frame,2)
1064 { /* (SYS::TRAP-EVAL-FRAME framepointer flag) switches the breakpoint at
1065 the specified EVAL/APPLY-frame on and off according to flag. */
1066 var object flag = popSTACK();
1067 var object frame = popSTACK();
1068 if (!framepointerp(frame))
1069 error_evalframe(frame);
1070 var gcv_object_t* FRAME = uTheFramepointer(frame);
1071 if (!evalapply_frame_p())
1072 error_evalframe(frame);
1073 /* FRAME points to the EVAL/APPLY-frame. */
1074 if (!nullp(flag)) {
1075 /* switch on breakpoint */
1076 *(oint*)(&FRAME_(0)) |= wbit(trapped_bit_o);
1077 } else {
1078 /* switch off breakpoint */
1079 *(oint*)(&FRAME_(0)) &= ~wbit(trapped_bit_o);
1080 }
1081 VALUES1(frame);
1082 }
1083
1084 LISPFUNN(redo_eval_frame,1)
1085 { /* (SYS::REDO-EVAL-FRAME framepointer) unwinds up to the specified
1086 EVAL/APPLY-frame and restarts to execute it. */
1087 var object frame = popSTACK();
1088 if (!framepointerp(frame))
1089 error_evalframe(frame);
1090 var gcv_object_t* FRAME = uTheFramepointer(frame);
1091 if (!evalapply_frame_p())
1092 error_evalframe(frame);
1093 /* FRAME points to the EVAL/APPLY-frame. */
1094 VALUES0;
1095 /* unwind everything up to the EVAL/APPLY-frame, then jump there */
1096 unwind_upto(FRAME);
1097 }
1098
1099 LISPFUNN(return_from_eval_frame,2)
1100 { /* (SYS::RETURN-FROM-EVAL-FRAME framepointer form)
1101 unwind up to the specified EVAL/APPLY-frame and return as its values
1102 all values of the evaluation of the specified form. */
1103 var object form = popSTACK();
1104 var object frame = popSTACK();
1105 if (!framepointerp(frame))
1106 error_evalframe(frame);
1107 var gcv_object_t* FRAME = uTheFramepointer(frame);
1108 if (!evalapply_frame_p())
1109 error_evalframe(frame);
1110 /* FRAME points to the EVAL/APPLY-frame. */
1111 VALUES1(form);
1112 /* unwind everything up to the EVAL/APPLY-frame, jump there */
1113 unwind_upto(FRAME);
1114 }
1115
1116 /* -----------------------------------------------------------------------
1117 Debug aux
1118
1119 Returns the top-of-frame of a back_trace element. */
top_of_back_trace_frame(const struct backtrace_t * bt)1120 global gcv_object_t* top_of_back_trace_frame (const struct backtrace_t *bt) {
1121 var gcv_object_t* stack = bt->bt_stack;
1122 var object fun = bt->bt_function;
1123 if (fsubrp(fun)) { /* FSUBR */
1124 var uintW numreq;
1125 var uintW numopt;
1126 var uintW body_flag;
1127 switch ((uintW)posfixnum_to_V(TheFsubr(fun)->argtype)) {
1128 case fsubr_argtype_1_0_nobody: numreq = 1; numopt = 0; body_flag=0; break;
1129 case fsubr_argtype_2_0_nobody: numreq = 2; numopt = 0; body_flag=0; break;
1130 case fsubr_argtype_1_1_nobody: numreq = 1; numopt = 1; body_flag=0; break;
1131 case fsubr_argtype_2_1_nobody: numreq = 2; numopt = 1; body_flag=0; break;
1132 case fsubr_argtype_0_body: numreq = 0; numopt = 0; body_flag = 1; break;
1133 case fsubr_argtype_1_body: numreq = 1; numopt = 0; body_flag = 1; break;
1134 case fsubr_argtype_2_body: numreq = 2; numopt = 0; body_flag = 1; break;
1135 default: NOTREACHED;
1136 }
1137 return stack STACKop (numreq + numopt + body_flag);
1138 }
1139 if (subrp(fun)) /* SUBR */
1140 return stack STACKop (TheSubr(fun)->req_count + TheSubr(fun)->opt_count
1141 + TheSubr(fun)->key_count);
1142 if (closurep(fun)) {
1143 var object codevec = TheClosure(fun)->clos_codevec;
1144 if (simple_bit_vector_p(Atype_8Bit,codevec)) { /* Compiled Closure */
1145 return stack STACKop (TheCodevec(codevec)->ccv_numreq
1146 + TheCodevec(codevec)->ccv_numopt
1147 + (TheCodevec(codevec)->ccv_flags & bit(0) ? 1 : 0)
1148 + (TheCodevec(codevec)->ccv_flags & bit(7)
1149 ? TheCodevec(codevec)->ccv_numkey : 0));
1150 } else /* Interpreted Closure */
1151 return stack;
1152 }
1153 /* Only SUBRs and functions occur as bt_function. */
1154 NOTREACHED;
1155 }
1156
1157 /* print one backtrace object
1158 > stream_ : lisp stream where the object is printed
1159 > bt : the backtrace object to print
1160 > index : the backtrace depth
1161 can trigger GC */
print_back_trace(const gcv_object_t * stream_,const struct backtrace_t * bt,uintL index)1162 local maygc void print_back_trace (const gcv_object_t* stream_,
1163 const struct backtrace_t *bt, uintL index) {
1164 write_ascii_char(stream_,'<');
1165 prin1(stream_,fixnum(index));
1166 write_ascii_char(stream_,'/');
1167 prin1(stream_,fixnum(STACK_item_count(bt->bt_stack,
1168 (gcv_object_t*)STACK_start)));
1169 write_ascii_char(stream_,'>');
1170 write_ascii_char(stream_,' ');
1171 prin1(stream_,bt->bt_function);
1172 if (bt->bt_num_arg >= 0) {
1173 write_ascii_char(stream_,' ');
1174 prin1(stream_,fixnum(bt->bt_num_arg));
1175 }
1176 }
1177 /* print several backtrace objects, up to FRAME
1178 > stream_ : lisp stream where the object is printed
1179 < FRAME : stack pointer - the limit for printing the stack
1180 > bt : the first backtrace object to print
1181 > index : the backtrace depth
1182 < bt : the next backtrace depth to be printed
1183 < index : the next backtrace depth
1184 can trigger GC */
print_bt_to_frame(const gcv_object_t * stream_,const gcv_object_t * FRAME,p_backtrace_t * bt_,uintL * index)1185 local maygc void print_bt_to_frame (const gcv_object_t* stream_,
1186 const gcv_object_t* FRAME,
1187 p_backtrace_t *bt_,
1188 uintL *index) {
1189 while (bt_beyond_stack_p(*bt_,FRAME)) {
1190 print_back_trace(stream_,*bt_,++(*index));
1191 terpri(stream_);
1192 *bt_ = (*bt_)->bt_next;
1193 }
1194 }
1195
1196 /* UP: prints the stackitem FRAME_(0) in detail to the stream
1197 and returns the next higher stackptr.
1198 print_stackitem(&stream,FRAME)
1199 can trigger GC */
print_stackitem(const gcv_object_t * stream_,gcv_object_t * FRAME)1200 local maygc gcv_object_t* print_stackitem (const gcv_object_t* stream_,
1201 gcv_object_t* FRAME)
1202 {
1203 if (!frame_p()) { /* no frame, normal LISP-object */
1204 write_sstring(stream_,O(showstack_string_lisp_obj)); /* "- " */
1205 var object obj = FRAME_(0);
1206 #if !defined(NO_symbolflags)
1207 switch (typecode(obj)) { /* poss. remove symbol-flags */
1208 case_symbolflagged: obj = symbol_without_flags(obj);
1209 default: break;
1210 }
1211 #endif
1212 prin1(stream_,obj); /* print LISP-object */
1213 return FRAME STACKop 1;
1214 } else { /* met frame */
1215 write_ascii_char(stream_,'[');
1216 prin1(stream_,fixnum(STACK_item_count(FRAME,(gcv_object_t*)STACK_start)));
1217 write_ascii_char(stream_,']');
1218 write_ascii_char(stream_,' ');
1219 var gcv_object_t* FRAME_top = topofframe(FRAME_(0)); /* top of frame */
1220 switch (framecode(FRAME_(0))) { /* according to frametype */
1221 case TRAPPED_APPLY_frame_info: {
1222 write_sstring(stream_,CLSTEXT("APPLY frame with breakpoint for call "));
1223 } goto APPLY_frame;
1224 case APPLY_frame_info: {
1225 write_sstring(stream_,CLSTEXT("APPLY frame for call "));
1226 APPLY_frame:
1227 /* print function name and arguments: */
1228 write_ascii_char(stream_,'('); /* print '(' */
1229 prin1(stream_,TheIclosure(FRAME_(frame_closure))->clos_name); /* print name */
1230 {
1231 var gcv_object_t* argptr = FRAME_top;
1232 var uintL count = STACK_item_count(FRAME STACKop frame_args,FRAME_top);
1233 dotimesL(count,count, {
1234 write_ascii_char(stream_,' '); /* print ' ' */
1235 write_ascii_char(stream_,'\''); /* print "'" */
1236 prin1(stream_,NEXT(argptr)); /* print next argument */
1237 });
1238 }
1239 write_ascii_char(stream_,')'); /* print ')' */
1240 } break;
1241 case TRAPPED_EVAL_frame_info: {
1242 write_sstring(stream_,CLSTEXT("EVAL frame with breakpoint for form "));
1243 } goto EVAL_frame;
1244 case EVAL_frame_info: {
1245 write_sstring(stream_,CLSTEXT("EVAL frame for form "));
1246 EVAL_frame:
1247 prin1(stream_,FRAME_(frame_form)); /* print form */
1248 } break;
1249 case DYNBIND_frame_info: { /* dynamic variable binding frames: */
1250 write_sstring(stream_,CLSTEXT("frame binding variables (~ = dynamically):"));
1251 /* print bindings: */
1252 FRAME skipSTACKop 1;
1253 while (FRAME != FRAME_top) {
1254 /* print binding of Symbol FRAME_(0) to value FRAME_(1): */
1255 write_sstring(stream_,O(showstack_string_bindung)); /* " | " */
1256 write_ascii_char(stream_,'~'); /* print '~' */
1257 write_ascii_char(stream_,' '); /* print ' ' */
1258 prin1(stream_,FRAME_(0)); /* print symbol */
1259 write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1260 prin1(stream_,FRAME_(1)); /* print value */
1261 FRAME skipSTACKop 2;
1262 }
1263 } break;
1264 #ifdef HAVE_SAVED_REGISTERS
1265 case CALLBACK_frame_info: { /* callback-register-frames: */
1266 write_sstring(stream_,CLSTEXT("CALLBACK frame"));
1267 } break;
1268 #endif
1269 /* variable- and function binding frames: */
1270 case VAR_frame_info: {
1271 write_sstring(stream_,CLSTEXT("frame binding variables "));
1272 #ifdef NO_symbolflags
1273 prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1274 write_sstring(stream_,CLSTEXT(" binds (~ = dynamically):"));
1275 pushSTACK(FRAME_(frame_next_env)); /* save next environment */
1276 /* print bindings: */
1277 FRAME skipSTACKop frame_bindings;
1278 while (FRAME != FRAME_top) {
1279 if (as_oint(FRAME_(varframe_binding_mark)) & wbit(active_bit_o)) {
1280 /* print binding of symbol FRAME_(1) to value FRAME_(2): */
1281 write_sstring(stream_,O(showstack_string_bindung)); /* " | " */
1282 if (as_oint(FRAME_(varframe_binding_mark)) & wbit(dynam_bit_o))
1283 /* dynamic binding? */
1284 write_ascii_char(stream_,'~'); /* yes -> print '~' */
1285 write_ascii_char(stream_,' '); /* print ' ' */
1286 /* print symbol: */
1287 prin1(stream_,symbol_without_flags(FRAME_(varframe_binding_sym)));
1288 write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1289 prin1(stream_,FRAME_(varframe_binding_value)); /* print value */
1290 }
1291 FRAME skipSTACKop varframe_binding_size;
1292 }
1293 goto VARFUN_frame_next;
1294 #else
1295 goto VARFUN_frame;
1296 #endif
1297 }
1298 case FUN_frame_info: {
1299 write_sstring(stream_,CLSTEXT("frame binding functions "));
1300 goto VARFUN_frame;
1301 VARFUN_frame: {
1302 prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1303 write_sstring(stream_,CLSTEXT(" binds (~ = dynamically):"));
1304 pushSTACK(FRAME_(frame_next_env)); /* save next environment */
1305 /* print bindings: */
1306 FRAME skipSTACKop frame_bindings;
1307 while (FRAME != FRAME_top) {
1308 if (as_oint(FRAME_(0)) & wbit(active_bit_o)) {
1309 /* print binding of symbol FRAME_(0) to value FRAME_(1): */
1310 write_sstring(stream_,O(showstack_string_bindung)); /* " | " */
1311 if (as_oint(FRAME_(0)) & wbit(dynam_bit_o)) /* bindings dynamic? */
1312 write_ascii_char(stream_,'~'); /* yes -> print '~' */
1313 write_ascii_char(stream_,' '); /* print ' ' */
1314 prin1(stream_,symbol_without_flags(FRAME_(0))); /* print symbol */
1315 write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1316 prin1(stream_,FRAME_(1)); /* print value */
1317 }
1318 FRAME skipSTACKop 2;
1319 }}
1320 VARFUN_frame_next:
1321 /* print next environment: */
1322 terpri(stream_);
1323 write_sstring(stream_,CLSTEXT(" Next environment: "));
1324 {
1325 var object env = popSTACK(); /* next environment */
1326 if (!simple_vector_p(env)) {
1327 prin1(stream_,env);
1328 } else {
1329 /* next environment is a vector of length 2n+1 */
1330 do {
1331 pushSTACK(env);
1332 var uintL count = floor(Svector_length(env),2); /* = n = number of bindings */
1333 var uintL index = 0;
1334 dotimesL(count,count, {
1335 write_sstring(stream_,O(showstack_string_bindung)); /* " | " */
1336 prin1(stream_,TheSvector(STACK_0)->data[index++]); /* print symbol */
1337 write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1338 prin1(stream_,TheSvector(STACK_0)->data[index++]); /* print symbol */
1339 });
1340 env = TheSvector(popSTACK())->data[index]; /* last vector-element */
1341 } while (simple_vector_p(env));
1342 }
1343 }
1344 } break;
1345 /* compiled block/tagbody-frames: */
1346 case CBLOCK_CTAGBODY_frame_info: {
1347 if (simple_vector_p(Car(FRAME_(frame_ctag)))) {
1348 /* compiled tagbody-frames: */
1349 write_sstring(stream_,CLSTEXT("compiled tagbody frame for "));
1350 prin1(stream_,Car(FRAME_(frame_ctag))); /* tag-vector */
1351 } else {
1352 /* compiled block-frames: */
1353 write_sstring(stream_,CLSTEXT("compiled block frame for "));
1354 prin1(stream_,Car(FRAME_(frame_ctag))); /* blockname */
1355 }
1356 } break;
1357 /* interpreted block-frames: */
1358 case IBLOCK_frame_info: {
1359 write_sstring(stream_,CLSTEXT("block frame "));
1360 } goto IBLOCK_frame;
1361 case NESTED_IBLOCK_frame_info: {
1362 write_sstring(stream_,CLSTEXT("nested block frame "));
1363 } goto IBLOCK_frame;
1364 IBLOCK_frame: {
1365 pushSTACK(FRAME_(frame_next_env));
1366 prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1367 write_sstring(stream_,CLSTEXT(" for "));
1368 prin1(stream_,FRAME_(frame_name)); /* blockname */
1369 } goto NEXT_ENV;
1370 /* interpreted tagbody-frames: */
1371 case ITAGBODY_frame_info: {
1372 write_sstring(stream_,CLSTEXT("tagbody frame "));
1373 } goto ITAGBODY_frame;
1374 case NESTED_ITAGBODY_frame_info: {
1375 write_sstring(stream_,CLSTEXT("nested tagbody frame "));
1376 } goto ITAGBODY_frame;
1377 ITAGBODY_frame: {
1378 pushSTACK(FRAME_(frame_next_env));
1379 prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1380 write_sstring(stream_,CLSTEXT(" for"));
1381 /* print tags/bodys: */
1382 FRAME skipSTACKop frame_bindings;
1383 while (FRAME != FRAME_top) {
1384 /* print binding of tag FRAME_(0) to body FRAME_(1): */
1385 write_sstring(stream_,O(showstack_string_bindung)); /* " | " */
1386 prin1(stream_,FRAME_(0)); /* print tag */
1387 write_sstring(stream_,O(showstack_string_zuordtag)); /* " --> " */
1388 prin1(stream_,FRAME_(1)); /* print body */
1389 FRAME skipSTACKop 2;
1390 }
1391 } goto NEXT_ENV;
1392 NEXT_ENV: { /* printing of a block- or tagbody-environments STACK_0 */
1393 terpri(stream_);
1394 write_sstring(stream_,CLSTEXT(" Next environment: "));
1395 var object env = popSTACK();
1396 if (!consp(env)) {
1397 prin1(stream_,env);
1398 } else { /* next environment is an Alist */
1399 do {
1400 pushSTACK(Cdr(env));
1401 env = Car(env);
1402 if (atomp(env)) {
1403 pushSTACK(S(show_stack));
1404 error(error_condition,
1405 GETTEXT("~S: environment is not an association list"));
1406 }
1407 pushSTACK(Cdr(env));
1408 pushSTACK(Car(env));
1409 write_sstring(stream_,O(showstack_string_bindung)); /* " | " */
1410 prin1(stream_,popSTACK());
1411 write_sstring(stream_,O(showstack_string_zuordtag)); /* " --> " */
1412 prin1(stream_,popSTACK());
1413 env = popSTACK();
1414 } while (consp(env));
1415 }
1416 } break;
1417 case CATCH_frame_info: { /* catch-frames: */
1418 write_sstring(stream_,CLSTEXT("catch frame for tag "));
1419 prin1(stream_,FRAME_(frame_tag)); /* tag */
1420 } break;
1421 case HANDLER_frame_info: { /* handler-frames: */
1422 write_sstring(stream_,CLSTEXT("handler frame for conditions"));
1423 var uintL m2 = Svector_length(Car(FRAME_(frame_handlers))); /* 2*m */
1424 var uintL i = 0;
1425 do {
1426 write_ascii_char(stream_,' '); /* print ' ' */
1427 prin1(stream_,TheSvector(Car(FRAME_(frame_handlers)))->data[i]); /* print type i */
1428 i += 2;
1429 } while (i < m2);
1430 } break;
1431 case UNWIND_PROTECT_frame_info: { /* unwind-protect-frames: */
1432 write_sstring(stream_,CLSTEXT("unwind-protect frame"));
1433 } break;
1434 case DRIVER_frame_info: { /* driver-frames: */
1435 terpri(stream_); /* blank line */
1436 write_sstring(stream_,CLSTEXT("driver frame"));
1437 } break;
1438 /* environment-frames: */
1439 case ENV1V_frame_info: {
1440 write_sstring(stream_,CLSTEXT("frame binding environments"));
1441 write_sstring(stream_,O(showstack_string_VENV_frame)); /* " VAR_ENV <--> " */
1442 prin1(stream_,FRAME_(1));
1443 } break;
1444 case ENV1F_frame_info: {
1445 write_sstring(stream_,CLSTEXT("frame binding environments"));
1446 write_sstring(stream_,O(showstack_string_FENV_frame)); /* " FUN_ENV <--> " */
1447 prin1(stream_,FRAME_(1));
1448 } break;
1449 case ENV1B_frame_info: {
1450 write_sstring(stream_,CLSTEXT("frame binding environments"));
1451 write_sstring(stream_,O(showstack_string_BENV_frame)); /* " BLOCK_ENV <--> " */
1452 prin1(stream_,FRAME_(1));
1453 } break;
1454 case ENV1G_frame_info: {
1455 write_sstring(stream_,CLSTEXT("frame binding environments"));
1456 write_sstring(stream_,O(showstack_string_GENV_frame)); /* " GO_ENV <--> " */
1457 prin1(stream_,FRAME_(1));
1458 } break;
1459 case ENV1D_frame_info: {
1460 write_sstring(stream_,CLSTEXT("frame binding environments"));
1461 write_sstring(stream_,O(showstack_string_DENV_frame)); /* " DECL_ENV <--> " */
1462 prin1(stream_,FRAME_(1));
1463 } break;
1464 case ENV2VD_frame_info: {
1465 write_sstring(stream_,CLSTEXT("frame binding environments"));
1466 write_sstring(stream_,O(showstack_string_VENV_frame)); /* " VAR_ENV <--> " */
1467 prin1(stream_,FRAME_(1));
1468 write_sstring(stream_,O(showstack_string_DENV_frame)); /* " DECL_ENV <--> " */
1469 prin1(stream_,FRAME_(2));
1470 } break;
1471 case ENV5_frame_info: {
1472 write_sstring(stream_,CLSTEXT("frame binding environments"));
1473 write_sstring(stream_,O(showstack_string_VENV_frame)); /* " VAR_ENV <--> " */
1474 prin1(stream_,FRAME_(1));
1475 write_sstring(stream_,O(showstack_string_FENV_frame)); /* " FUN_ENV <--> " */
1476 prin1(stream_,FRAME_(2));
1477 write_sstring(stream_,O(showstack_string_BENV_frame)); /* " BLOCK_ENV <--> " */
1478 prin1(stream_,FRAME_(3));
1479 write_sstring(stream_,O(showstack_string_GENV_frame)); /* " GO_ENV <--> " */
1480 prin1(stream_,FRAME_(4));
1481 write_sstring(stream_,O(showstack_string_DENV_frame)); /* " DECL_ENV <--> " */
1482 prin1(stream_,FRAME_(5));
1483 } break;
1484 default:
1485 pushSTACK(S(show_stack));
1486 error(serious_condition,GETTEXT("~S: unknown frame type"));
1487 }
1488 return FRAME_top; /* pointer top of frame */
1489 }
1490 }
1491
1492 LISPFUNN(describe_frame,2)
1493 { /* (SYS::DESCRIBE-FRAME stream framepointer) prints in detail the
1494 stackitem, that the pointer points to. */
1495 var gcv_object_t* FRAME = test_framepointer_arg(); /* pointer in the stack */
1496 STACK_0 = check_stream(STACK_0);
1497 fresh_line(&STACK_0);
1498 {
1499 var uintL count = 0;
1500 var p_backtrace_t bt = back_trace;
1501 unwind_back_trace(bt,FRAME STACKop -1);
1502 print_bt_to_frame(&STACK_0,FRAME,&bt,&count);
1503 }
1504 print_stackitem(&STACK_0,FRAME); /* print stack-item */
1505 elastic_newline(&STACK_0);
1506 skipSTACK(1); VALUES0; /* no values */
1507 }
1508
1509 /* UP: print the stack (up to frame_limit frames, if that is non-0)
1510 frame by frame (moving using frame_up_x) or all stack items if that is NULL.
1511 starting with start_frame or STACK if that is NULL
1512 In debugger, use 'print show_stack(0,0,0)'.
1513 can trigger GC */
show_stack(climb_fun_t frame_up_x,uintL frame_limit,gcv_object_t * start_frame)1514 local inline maygc uintL show_stack (climb_fun_t frame_up_x, uintL frame_limit,
1515 gcv_object_t* start_frame)
1516 { /* run along the stack upwards */
1517 var gcv_object_t* FRAME = (start_frame == NULL ? STACK : start_frame);
1518 pushSTACK(var_stream(S(standard_output),strmflags_wr_ch_B));
1519 var gcv_object_t* stream_ = &STACK_0;
1520 var uintL count = 0;
1521 var p_backtrace_t bt = back_trace;
1522 while (!((gcv_object_t*)STACK_start == FRAME)
1523 && (frame_limit==0 || count<frame_limit)) {
1524 fresh_line(stream_);
1525 print_bt_to_frame(stream_,FRAME,&bt,&count);
1526 FRAME = print_stackitem(stream_,FRAME);
1527 elastic_newline(stream_);
1528 if (frame_up_x != NULL) {
1529 var gcv_object_t* next_frame = (*frame_up_x)(FRAME);
1530 if (next_frame == FRAME) break;
1531 FRAME = next_frame;
1532 }
1533 }
1534 skipSTACK(1); /* drop *STANDARD-OUTPUT* */
1535 return count;
1536 }
1537
1538 LISPFUN(show_stack,seclass_default,0,3,norest,nokey,0,NIL)
1539 { /* (SHOW-STACK mode limit start-frame) print the stack contents. */
1540 var gcv_object_t* start_frame = (missingp(STACK_0) ? (skipSTACK(1), &STACK_1)
1541 : test_framepointer_arg());
1542 var uintL frame_limit = (missingp(STACK_0) ? (skipSTACK(1), 0) :
1543 uint32_p(STACK_0) ? I_to_uint32(popSTACK())
1544 : (error_uint32(popSTACK()), 0));
1545 var climb_fun_t frame_up_x = (missingp(STACK_0)
1546 ? (skipSTACK(1), (climb_fun_t) NULL)
1547 : test_mode_arg(&frame_up_table[0]));
1548 VALUES1(UL_to_I(show_stack(frame_up_x,frame_limit,start_frame)));
1549 }
1550
1551 /* For debugging: From within gdb, type: call gdb_show_stack().
1552 Equivalent to (ext:show-stack) from the Lisp prompt. */
gdb_show_stack(void)1553 global void gdb_show_stack (void) {
1554 pushSTACK(unbound); pushSTACK(unbound); pushSTACK(unbound); C_show_stack();
1555 }
1556
1557 /* Fore debugging: From within gdb, type: call gdb_disassemble_closure(obj).
1558 Equivalent to (sys::disassemble-closures obj *standard-output*). */
gdb_disassemble_closure(object obj)1559 global void gdb_disassemble_closure (object obj) {
1560 pushSTACK(obj); pushSTACK(Symbol_value(S(standard_output)));
1561 funcall(S(disassemble_closures),2);
1562 pushSTACK(Symbol_value(S(standard_output))); terpri(&STACK_0); skipSTACK(1);
1563 }
1564
1565 LISPFUNN(crash,0)
1566 { /* (SYSTEM::CRASH) jumps to the debugger sitting in the background. */
1567 abort();
1568 VALUES0; /* no values */
1569 }
1570
1571 LISPFUNN(proom,0)
1572 { /* (SYSTEM::%ROOM), returns 6 values:
1573 - room occupied by LISP-objects (bytes)
1574 - room free for LISP-objects (bytes)
1575 - room statically occupied by LISP-objects (bytes)
1576 - GC count
1577 - total space freed by GC (bytes)
1578 - total time spent in GC (internal time units)
1579 do it in more detail at SPVW_PAGES?? */
1580 pushSTACK(uintM_to_I(used_space()));
1581 pushSTACK(uintM_to_I(free_space()));
1582 pushSTACK(uintM_to_I(static_space()));
1583 pushSTACK(UL_to_I(gc_count));
1584 #ifdef intQsize
1585 pushSTACK(UQ_to_I(gc_space));
1586 #else
1587 pushSTACK(UL2_to_I(gc_space.hi,gc_space.lo));
1588 #endif
1589 pushSTACK(internal_time_to_I(&gc_time));
1590 STACK_to_mv(6);
1591 }
1592
1593 LISPFUN(gc,seclass_default,0,1,norest,nokey,0,NIL)
1594 { /* execute a GC and return the same values as %ROOM
1595 with an argument, invalidate JITC objects */
1596 var object arg = popSTACK();
1597 PERFORM_GC(gar_col(missingp(arg) ? 0 : 1),true); /* execute GC */
1598 C_proom();
1599 }
1600
1601 /* rewrite read-form, in collaboration with the terminal-stream?? */
1602