0.6.8.5: fixed bug 1, and made clearer/cleaner debugger restarts
authorWilliam Harold Newman <william.newman@airmail.net>
Wed, 1 Nov 2000 19:37:48 +0000 (19:37 +0000)
committerWilliam Harold Newman <william.newman@airmail.net>
Wed, 1 Nov 2000 19:37:48 +0000 (19:37 +0000)
13 files changed:
BUGS
NEWS
doc/beyond-ansi.sgml
src/code/alien-type.lisp
src/code/cold-init.lisp
src/code/debug.lisp
src/code/fop.lisp
src/code/late-target-error.lisp
src/code/loop.lisp
src/code/pp-backq.lisp
src/code/save.lisp
src/code/toplevel.lisp
version.lisp-expr

diff --git a/BUGS b/BUGS
index 411b75c..ca875a7 100644 (file)
--- a/BUGS
+++ b/BUGS
@@ -24,11 +24,16 @@ but instead
 
 KNOWN BUGS RELATED TO THE IR1 INTERPRETER
 
-At some point, the pure interpreter (aka the "IR1 interpreter") will
-probably go away (replaced by constructs like
+(Note: At some point, the pure interpreter (aka the "IR1 interpreter")
+will probably go away (replaced by constructs like
   (DEFUN EVAL (X) (FUNCALL (COMPILE NIL (LAMBDA ..)))))
 and at that time these bugs should go away automatically. Until then,
 they'll probably remain, since they're not considered urgent.
+After the IR1 interpreter goes away is also the preferred time
+to start systematically exterminating cases where debugging
+functionality (backtrace, breakpoint, etc.) breaks down, since
+getting rid of the IR1 interpreter will reduce the number of
+special cases we need to support.)
 
 IR1-1:
   The FUNCTION special operator doesn't check properly whether its
@@ -44,18 +49,13 @@ IR1-2:
        T
 
 
-OTHER KNOWN BUGS:
+KNOWN BUGS OF NO SPECIAL CLASS:
 
-(There is also some information on bugs in the manual page and in the
-TODO file. Eventually more such information may move here.)
-
-1:
-  Failure in initialization files is not handled gracefully -- it's 
-  a throw to TOP-LEVEL-CATCHER, which is not caught until we enter
-  TOPLEVEL-REPL. Code should be added to catch such THROWs even when
-  we're not in TOPLEVEL-REPL and do *something* with them (probably
-  complaining about an error outside TOPLEVEL-REPL, perhaps printing
-  a BACKTRACE, then terminating execution of SBCL).
+(Note:
+  * There is also some information on bugs in the manual page and
+    in the TODO file. Eventually more such information may move here.
+  * The gaps in the number sequence belong to old bugs which were
+    eliminated.)
 
 2:
   DEFSTRUCT should almost certainly overwrite the old LAYOUT information
diff --git a/NEWS b/NEWS
index 7b202e3..fb26354 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -536,6 +536,15 @@ changes in sbcl-0.6.9 relative to sbcl-0.6.8:
   into everyone's system when I do a "cvs update".) When no
   customize-target-features.lisp file exists, the target *FEATURES* list
   should be constructed the same way as before.
+* The QUIT debugger command is gone, since it did something
+  rather different than the SB-EXT:QUIT command, and since it never
+  worked properly outside the main toplevel read/eval/print loop.
+  Invoking the new TOPLEVEL restart provides the same functionality.
+* The GO debugger command is also gone, since you can just invoke
+  the CONTINUE restart directly instead.
+* The TOP debugger command is also gone, since it's redundant with 
+  'f 0', and since it interfered with abbreviations for the TOPLEVEL
+  restart.
 ?? signal handling reliability
 ?? fixed some bugs mentioned in the man page:
   ?? DEFUN-vs.-DECLAIM
index eb789f0..a3d7eea 100644 (file)
@@ -160,6 +160,14 @@ is also supported.</para>
 
 <para>The debugger supports a number of options. Its documentation is
 accessed by typing <userinput>help</> at the debugger prompt.</para>
+<!-- FIXME:
+     A true debugger section in the manual would be good. Start
+     with CMU CL's debugger section, but remember:
+       * no QUIT command (TOPLEVEL restart instead)
+       * no GO command (CONTINUE restart instead)
+       * Limitations of the x86 port of the debugger should be 
+         documented or fixed where possible.
+       * Discuss TRACE and its unification with PROFILE. -->
 
 <para>Documentation for <function>inspect</> is accessed by typing
 <userinput>help</> at the <function>inspect</> prompt.</para>
index add7d74..0a28be1 100644 (file)
                           (alien-type-type-alien-type type2))
          t))
 
-;;; KLUDGE: This DEFINE-SUPERCLASSES gets executed much later than the others
-;;; (toplevel form time instead of cold load init time) because ALIEN-VALUE
-;;; itself is a structure which isn't defined until fairly late.
+;;; KLUDGE: This DEFINE-SUPERCLASSES gets executed much later than the
+;;; others (toplevel form time instead of cold load init time) because
+;;; ALIEN-VALUE itself is a structure which isn't defined until fairly
+;;; late.
 ;;;
 ;;; FIXME: I'm somewhat tempted to just punt ALIEN from the type system.
 ;;; It's sufficiently unlike the others that it's a bit of a pain, and
index 6ac2dd8..3f24bb5 100644 (file)
   (terpri)
   (/show0 "going into toplevel loop")
   (handling-end-of-the-world 
-    (toplevel)))
+    (toplevel-init)))
 
 (defun quit (&key recklessly-p
                  (unix-code 0 unix-code-p)
index 422b573..0a6cb5c 100644 (file)
   "*PRINT-LENGTH* for the debugger")
 
 (defvar *debug-readtable*
-  ;; KLUDGE: This can't be initialized in a cold toplevel form, because the
-  ;; *STANDARD-READTABLE* isn't initialized until after cold toplevel forms
-  ;; have run. So instead we initialize it immediately after
-  ;; *STANDARD-READTABLE*. -- WHN 20000205
+  ;; KLUDGE: This can't be initialized in a cold toplevel form,
+  ;; because the *STANDARD-READTABLE* isn't initialized until after
+  ;; cold toplevel forms have run. So instead we initialize it
+  ;; immediately after *STANDARD-READTABLE*. -- WHN 20000205
   nil
   #!+sb-doc
   "*READTABLE* for the debugger")
@@ -68,23 +68,19 @@ The debugger rebinds various special variables for controlling i/o, sometimes
   to defaults (much like WITH-STANDARD-IO-SYNTAX does) and sometimes to 
   its own special values, e.g. SB-DEBUG:*DEBUG-PRINT-LEVEL*.
 Debug commands do not affect * and friends, but evaluation in the debug loop
-  do affect these variables.
+  does affect these variables.
 SB-DEBUG:*FLUSH-DEBUG-ERRORS* controls whether errors at the debug prompt
   drop you into deeper into the debugger.
 
 Getting in and out of the debugger:
-  Q        throws to top level.
-  GO       calls CONTINUE which tries to proceed with the restart 'CONTINUE.
   RESTART  invokes restart numbered as shown (prompt if not given).
   ERROR    prints the error condition and restart cases.
-
   The name of any restart, or its number, is a valid command, and is the same
     as using RESTART to invoke that restart.
 
 Changing frames:
-  U     up frame     D  down frame
-  T     top frame    B  bottom frame
-  F n   frame n
+  U      up frame     D    down frame
+  B  bottom frame     F n  frame n (n=0 for top frame)
 
 Inspecting frames:
   BACKTRACE [n]  shows n frames going down the stack.
@@ -93,8 +89,8 @@ Inspecting frames:
   SOURCE [n]     displays frame's source form with n levels of enclosing forms.
 
 Breakpoints and steps:
-  LIST-LOCATIONS [{function | :c}]   List the locations for breakpoints.
-                                     Specify :c for the current frame.
+  LIST-LOCATIONS [{function | :C}]   List the locations for breakpoints.
+                                     Specify :C for the current frame.
     Abbreviation: LL
   LIST-BREAKPOINTS                   List the active breakpoints.
     Abbreviations: LB, LBP
@@ -722,7 +718,9 @@ Function and macro commands:
            ;; WITH-SIMPLE-RESTART.
            (let ((level *debug-command-level*)
                  (restart-commands (make-restart-commands)))
-             (with-simple-restart (abort "Return to debug level ~D." level)
+             (with-simple-restart (abort
+                                  "Reduce debugger level (to debug level ~D)."
+                                   level)
                (funcall *debug-prompt*)
                (let ((input (sb!int:get-stream-command *debug-io*)))
                  (cond (input
@@ -1051,12 +1049,15 @@ Function and macro commands:
 
 (def-debug-command-alias "D" "DOWN")
 
-(def-debug-command "TOP" ()
-  (do ((prev *current-frame* lead)
-       (lead (sb!di:frame-up *current-frame*) (sb!di:frame-up lead)))
-      ((null lead)
-       (setf *current-frame* prev)
-       (print-frame-call prev))))
+;;; CMU CL had this command, but SBCL doesn't, since
+;;; it's redundant with "FRAME 0", and it interferes with abbreviations
+;;; for the TOPLEVEL restart.
+;;;(def-debug-command "TOP" ()
+;;;  (do ((prev *current-frame* lead)
+;;;       (lead (sb!di:frame-up *current-frame*) (sb!di:frame-up lead)))
+;;;      ((null lead)
+;;;       (setf *current-frame* prev)
+;;;       (print-frame-call prev))))
 
 (def-debug-command "BOTTOM" ()
   (do ((prev *current-frame* lead)
@@ -1091,12 +1092,20 @@ Function and macro commands:
 \f
 ;;;; commands for entering and leaving the debugger
 
-(def-debug-command "QUIT" ()
-  (throw 'sb!impl::top-level-catcher nil))
+;;; CMU CL supported this QUIT debug command, but SBCL provides this
+;;; functionality with a restart instead. (The QUIT debug command was
+;;; removed because it's confusing to have "quit" mean two different
+;;; things in the system, "restart the top level REPL" in the debugger
+;;; and "terminate the Lisp system" as the SB-EXT:QUIT function.)
+;;;
+;;;(def-debug-command "QUIT" ()
+;;;  (throw 'sb!impl::top-level-catcher nil))
 
-(def-debug-command "GO" ()
-  (continue *debug-condition*)
-  (error "There is no restart named CONTINUE."))
+;;; CMU CL supported this GO debug command, but SBCL doesn't -- just
+;;; type the CONTINUE restart name.
+;;;(def-debug-command "GO" ()
+;;;  (continue *debug-condition*)
+;;;  (error "There is no restart named CONTINUE."))
 
 (def-debug-command "RESTART" ()
   (let ((num (read-if-available :prompt)))
@@ -1312,9 +1321,10 @@ Function and macro commands:
   (continue *debug-condition*)
   (error "couldn't continue"))
 
-;;; List possible breakpoint locations, which ones are active, and where GO
-;;; will continue. Set *POSSIBLE-BREAKPOINTS* to the code-locations which can
-;;; then be used by sbreakpoint.
+;;; List possible breakpoint locations, which ones are active, and
+;;; where the CONTINUE restart will transfer control. Set
+;;; *POSSIBLE-BREAKPOINTS* to the code-locations which can then be
+;;; used by sbreakpoint.
 (def-debug-command "LIST-LOCATIONS" ()
   (let ((df (read-if-available *default-breakpoint-debug-function*)))
     (cond ((consp df)
index a28857f..c5791ed 100644 (file)
     (sb!vm:sanctify-for-execution component)
     component))
 
-;;; This a no-op except in cold load. (In ordinary warm load, everything
-;;; involved with function definition can be handled nicely by ordinary
-;;; toplevel code.)
+;;; This a no-op except in cold load. (In ordinary warm load,
+;;; everything involved with function definition can be handled nicely
+;;; by ordinary toplevel code.)
 (define-fop (fop-fset 74 nil)
   (pop-stack)
   (pop-stack))
index 795a5a8..a636049 100644 (file)
   "Transfer control to a restart named ABORT, signalling a CONTROL-ERROR if
    none exists."
   (invoke-restart (find-restart 'abort condition))
-  ;; ABORT signals an error in case there was a restart named abort that did
+  ;; ABORT signals an error in case there was a restart named ABORT that did
   ;; not transfer control dynamically. This could happen with RESTART-BIND.
   (error 'abort-failure))
 
index b1ef79a..1e9dbc6 100644 (file)
@@ -913,16 +913,16 @@ a LET-like macro, and a SETQ-like macro, which perform LOOP-style destructuring.
                            (loop-lookup-keyword keyword
                                                 (loop-universe-keywords
                                                  *loop-universe*)))
-                     ;; It's a "miscellaneous" toplevel LOOP keyword (do,
-                     ;; collect, named, etc.)
+                     ;; It's a "miscellaneous" toplevel LOOP keyword (DO,
+                     ;; COLLECT, NAMED, etc.)
                      (apply (symbol-function (first tem)) (rest tem)))
                     ((setq tem
                            (loop-lookup-keyword keyword
                                                 (loop-universe-iteration-keywords *loop-universe*)))
                      (loop-hack-iteration tem))
                     ((loop-tmember keyword '(and else))
-                     ;; Alternative is to ignore it, ie let it go around to
-                     ;; the next keyword...
+                     ;; The alternative is to ignore it, i.e. let it go
+                     ;; around to the next keyword...
                      (loop-error "secondary clause misplaced at top level in LOOP macro: ~S ~S ~S ..."
                                  keyword
                                  (car *loop-source-code*)
index bbc1e85..b1d5cc4 100644 (file)
@@ -83,7 +83,7 @@
 ;;; This is called by !PPRINT-COLD-INIT, fairly late, because
 ;;; SET-PPRINT-DISPATCH doesn't work until the compiler works.
 ;;;
-;;; FIXME: It might be cleaner to just make these toplevel forms and
+;;; FIXME: It might be cleaner to just make these be toplevel forms and
 ;;; enforce the delay by putting this file late in the build sequence.
 (defun !backq-pp-cold-init ()
   (set-pprint-dispatch '(cons (eql backq-list)) #'pprint-backquote)
index 326b8ba..7f0abb0 100644 (file)
@@ -39,7 +39,7 @@
 ;;; image to make a running Lisp, the memory never gets reclaimed.
 ;;; (But with the PURIFY option it seems to work OK.)
 (defun save-lisp-and-die (core-file-name &key
-                                        (toplevel #'toplevel)
+                                        (toplevel #'toplevel-init)
                                         (purify nil)
                                         (root-structures ())
                                         (environment-name "auxiliary"))
index 9ff9a7d..284f73e 100644 (file)
   (let ((caught (gensym "CAUGHT")))
     `(let ((,caught (catch '%end-of-the-world
                      (/show0 "inside CATCH '%END-OF-THE-WORLD")
-                     ,@body)))
+                     (restart-case (progn ,@body)
+                       ;; KLUDGE: I'd like to name this restart QUIT,
+                       ;; but then people would hate me, since in CMU
+                       ;; CL, even though they have essentially the
+                       ;; same QUIT function as SBCL, the "QUIT"
+                       ;; command in the debugger means to return to
+                       ;; the toplevel, not to actually call QUIT. Oh
+                       ;; well. -- WHN 2000-11-01
+                       (end-of-the-world ()
+                         :report (lambda (s)
+                                   (format s
+                                           "Terminate the current Lisp, ~
+                                            like #'~S."
+                                           'quit))
+                         (quit))))))
        (/show0 "back from CATCH '%END-OF-THE-WORLD, flushing output")
        (flush-standard-output-streams)
        (/show0 "calling UNIX-EXIT")
             (* (floor initial-offset sb!vm:word-bytes) sb!vm:word-bytes)
             0))))
 \f
-;;;; the default TOPLEVEL function
+;;;; the default toplevel function
 
 (defvar / nil
   #!+sb-doc
   #!+sb-doc
   "The top-level prompt string. This also may be a function of no arguments
    that returns a simple-string.")
-(defvar *in-top-level-catcher* nil
-  #!+sb-doc
-  "Are we within the Top-Level-Catcher? This is used by interrupt
-   handlers to see whether it is OK to throw.")
 
 (defun interactive-eval (form)
   "Evaluate FORM, returning whatever it returns and adjusting ***, **, *,
   (values))
 
 ;;; the default system top-level function
-(defun toplevel ()
+(defun toplevel-init ()
 
-  (/show0 "entering TOPLEVEL")
+  (/show0 "entering TOPLEVEL-INIT")
   
   (let ((sysinit nil)      ; value of --sysinit option
        (userinit nil)     ; value of --userinit option
        (noprogrammer nil) ; Has a --noprogammer option been seen?
        (options (rest *posix-argv*))) ; skipping program name
 
-    (/show0 "done with outer LET in TOPLEVEL")
+    (/show0 "done with outer LET in TOPLEVEL-INIT")
   
     ;; FIXME: There are lots of ways for errors to happen around here (e.g. bad
     ;; command line syntax, or READ-ERROR while trying to READ an --eval
 
     ;; Parse command line options.
     (loop while options do
-         (/show0 "at head of LOOP WHILE OPTIONS DO in TOPLEVEL")
+         (/show0 "at head of LOOP WHILE OPTIONS DO in TOPLEVEL-INIT")
          (let ((option (first options)))
            (flet ((pop-option ()
                     (if options
                               :test #'string=)
                         (error "bad toplevel option: ~S" (first options))
                         (return)))))))
-    (/show0 "done with LOOP WHILE OPTIONS DO in TOPLEVEL")
+    (/show0 "done with LOOP WHILE OPTIONS DO in TOPLEVEL-INIT")
 
     ;; Excise all the options that we processed, so that only user-level
     ;; options are left visible to user code.
     ;; lead to reasonable behavior.
 
     ;; Handle initialization files.
-    (/show0 "handling initialization files in TOPLEVEL")
+    (/show0 "handling initialization files in TOPLEVEL-INIT")
     (flet (;; If any of POSSIBLE-INIT-FILE-NAMES names a real file,
           ;; return its truename.
           (probe-init-files (&rest possible-init-file-names)
        (/show0 "loaded USERINIT-TRUENAME"))
 
       ;; Handle --eval options.
-      (/show0 "handling --eval options in TOPLEVEL")
+      (/show0 "handling --eval options in TOPLEVEL-INIT")
       (dolist (eval (reverse evals))
-       (/show0 "handling one --eval option in TOPLEVEL")
+       (/show0 "handling one --eval option in TOPLEVEL-INIT")
        (eval eval)
        (flush-standard-output-streams))
 
       ;; FIXME: When we do actually implement this, shouldn't it go
       ;; earlier in the sequence, so that its stream bindings will
       ;; affect the behavior of init files and --eval options?
-      (/show0 "handling --noprogrammer option in TOPLEVEL")
+      (/show0 "handling --noprogrammer option in TOPLEVEL-INIT")
       (when noprogrammer
        (warn "stub: --noprogrammer option unimplemented")) ; FIXME
 
-      (/show0 "falling into TOPLEVEL-REPL from TOPLEVEL")
+      (/show0 "falling into TOPLEVEL-REPL from TOPLEVEL-INIT")
       (toplevel-repl noprint))))
 
 ;;; read-eval-print loop for the default system toplevel
        (/// nil) (// nil) (/ nil)
        (eof-marker (cons :eof nil)))
     (loop
-      ;; FIXME: This seems to be the source of one of the basic debugger
-      ;; choices in
-      ;;    Restarts:
-      ;;      0: [CONTINUE] Return from BREAK.
-      ;;      1: [ABORT   ] Return to toplevel.
-      ;; (The "Return from BREAK" choice is defined in BREAK.) I'd like to add
-      ;; another choice,
-      ;;      2: [TERMINATE] Terminate the current Lisp.
-      ;; That way, a user hitting ^C could get out of Lisp without knowing
-      ;; enough about the system to run (SB-EXT:QUIT).
-      ;;
-      ;; If I understand the documentation of WITH-SIMPLE-RESTART correctly,
-      ;; it shows how to replace this WITH-SIMPLE-RESTART with a RESTART-CASE
-      ;; with two choices (ABORT and QUIT). Or perhaps ABORT should be renamed
-      ;; TOPLEVEL?
-      ;;    Restarts:
-      ;;      0: [CONTINUE ] Return from BREAK, continuing calculation
-      ;;                    as though nothing happened.
-      ;;      1: [TOPLEVEL ] Transfer control to toplevel read/eval/print
-      ;;                    loop, aborting current calculation.
-      ;;      2: [TERMINATE] Terminate the current Lisp (equivalent to
-      ;;                    executing (SB-EXT:QUIT)).
       (/show0 "at head of outer LOOP in TOPLEVEL-REPL")
-      (with-simple-restart (abort "Return to toplevel.")
-       (catch 'top-level-catcher
-         (sb!unix:unix-sigsetmask 0) ; FIXME: What is this for?
-         (let ((*in-top-level-catcher* t))
-           (/show0 "about to enter inner LOOP in TOPLEVEL-REPL")
-           (loop                       ; FIXME: Do we need this inner LOOP?
-            ;; FIXME: It seems bad to have GC behavior depend on scrubbing
-            ;; the control stack before each interactive command. Isn't
-            ;; there some way we can convince the GC to just ignore
-            ;; dead areas of the control stack, so that we don't need to
-            ;; rely on this half-measure?
-            (scrub-control-stack)
-            (unless noprint
-              (fresh-line)
-              (princ (if (functionp *prompt*)
-                         (funcall *prompt*)
-                         *prompt*))
-              (flush-standard-output-streams))
-            (let ((form (read *standard-input* nil eof-marker)))
-              (if (eq form eof-marker)
-                  (quit)
-                  (let ((results
-                         (multiple-value-list (interactive-eval form))))
-                    (unless noprint
-                      (dolist (result results)
-                        (fresh-line)
-                        (prin1 result)))))))))))))
+      ;; There should only be one TOPLEVEL restart, and it's here, so
+      ;; restarting at TOPLEVEL always bounces you all the way out here.
+      (with-simple-restart (toplevel
+                           "Restart at toplevel READ/EVAL/PRINT loop.")
+       ;; We add a new ABORT restart for every debugger level, so 
+       ;; restarting at ABORT in a nested debugger gets you out to the
+        ;; innermost enclosing debugger, and only when you're in the
+        ;; outermost, unnested debugger level does restarting at ABORT 
+       ;; get you out to here.
+        (with-simple-restart (abort
+                             "Reduce debugger level (leaving debugger).")
+         (catch 'top-level-catcher
+         (sb!unix:unix-sigsetmask 0)   ; FIXME: What is this for?
+         (/show0 "about to enter inner LOOP in TOPLEVEL-REPL")
+         (loop                         ; FIXME: Do we need this inner LOOP?
+          ;; FIXME: It seems bad to have GC behavior depend on scrubbing
+          ;; the control stack before each interactive command. Isn't
+          ;; there some way we can convince the GC to just ignore
+          ;; dead areas of the control stack, so that we don't need to
+          ;; rely on this half-measure?
+          (scrub-control-stack)
+          (unless noprint
+            (fresh-line)
+            (princ (if (functionp *prompt*)
+                       (funcall *prompt*)
+                       *prompt*))
+            (flush-standard-output-streams))
+          (let ((form (read *standard-input* nil eof-marker)))
+            (if (eq form eof-marker)
+                (quit)
+                (let ((results
+                       (multiple-value-list (interactive-eval form))))
+                  (unless noprint
+                    (dolist (result results)
+                      (fresh-line)
+                      (prin1 result)))))))))))))
 \f
 ;;; a convenient way to get into the assembly-level debugger
 (defun %halt ()
index 25f501d..f8ac268 100644 (file)
@@ -15,4 +15,4 @@
 ;;; versions, and a string like "0.6.5.12" is used for versions which
 ;;; aren't released but correspond only to CVS tags or snapshots.
 
-"0.6.8.4"
+"0.6.8.5"