;-*- Mode:LISP; Package:EH; Readtable:ZL; Base:8 -*- ;;>> missing handlers for: ; cons-in-inappropriate-region ; attempt-to-extend-fixed-area ; attempt-to-close-over-a-memory-location ; new-nonexistent-instance-variable (defflavor trap () () :abstract-flavor (:included-flavors condition) ;;>> this is really a defflavor bug ;;>> --- it should notice the method-combinations from included flavors ;;>> FIX! (:method-combination (:case :base-flavor-last :proceed :proceed-asking-user :document-proceed-type :proceed-ucode-with-args)) (:documentation "Error signalled by the microcode")) (defmethod (trap :default :ucode-proceed-types) ()) (defflavor random-trap () (trap format-condition-mixin error)) (defflavor random-dangerous-trap () (random-trap dangerous-condition)) (defmethod (trap :print-error-message-prefix) (sg brief stream &aux tem flag) (if brief (princ ">>TRAP: " stream) (let (trap-micro-pc ete saved-micro-pcs) (setf (list* trap-micro-pc ete 'a 'a saved-micro-pcs) (symeval-in-stack-group '*ucode-error-status* sg)) (format stream ">>TRAP ~A ~A" trap-micro-pc ete) (dolist (pc saved-micro-pcs) (when (setq tem (assq (1- (%pointer pc)) calls-sub-list)) (or flag (format stream " ->")) (setq flag t) (format stream " ~A " (cdr tem)))) ;show whole stack if active function is micro-compiled ;we need something like this, but it needs to be smarter about errors ; (if (fboundp 'compiler:show-micro-stack) ; (compiler:show-micro-stack stream sg)) (terpri)))) ;;; Conventions for the error handler routines: how to add new ones. ;;; ;;; Each place in the microcode where TRAP can be called is followed by ;;; an ERROR-TABLE pseudo-op. This should appear at the PC which is ;;; going to be TRAP's return address. An example is ;;; (ERROR-TABLE ARGTYP FIXNUM M-T 0) ;;; (for example). The CDR of this list is the ETE. So, the FIRST element ;;; is the name of the error, and the SECOND is the first "argument" to that ;;; error's associated routines. ;;; ;;; All ETEs should be a list whose car is a symbol. ;;; That symbol should be defined in a DEF-UCODE-ERROR in this file. ;;; Within the DEF-UCODE-ERROR, the variable ETE can be used to ;;; refer to the entire ETE list. (defmacro def-ucode-error (trap-name condition-flavor &body init-options) (let ((condition-flavor (if (consp condition-flavor) (car condition-flavor) condition-flavor)) (condition-names (cdr-safe condition-flavor))) `(defun (:property ,trap-name make-ucode-error-function) (ignore sg ete) (declare (function-parent ,trap-name def-ucode-error)) sg ete (make-instance ',condition-flavor ,@(if (consp condition-flavor) `(:condition-names ',condition-names)) ,@init-options)))) (defun make-ucode-error (error-name sg ete) (let ((error-fctn (get error-name 'make-ucode-error-function))) (if (null error-fctn) (ferror "A ~s trap was received from the microcode, which does not have a make-ucode-error-function associated with it!" error-name) (funcall error-fctn error-name sg ete)))) (defmacro def-ucode-format-error (error-name &body format-args) (declare (arglist error-name error-flavor format-string &body format-args)) `(def-ucode-error ,error-name random-trap :format-string ,(car format-args) :format-args (list . ,(cdr format-args)))) (defun sg-proceed-micro-pc (sg tags) "Restart SG from an error in the microcode, at micro-pc determined by TAG. TAG may be the name of an (ERROR-TABLE RESTART tag) in the microcode source. If TAG is NIL, restart at the pc where the error happened. If a PROCEED routine doesn't call SG-PROCEED-MICRO-PC, then control will be returned from the micro-routine that got the error." (setq tags (if (consp tags) tags (list tags))) ;yes, consp not cl:listp ;; Operates by pushing the specified PC onto the saved microstack, ;; since resuming the stack group will do a POPJ. (dolist (tag tags) (let ((pc (if tag (cdr (assq tag restart-list)) (1+ (sg-trap-micro-pc sg))))) (when (null pc) (bad-hacker tag " no such restart!") (throw 'quit nil)) ;; Since the micro stack is saved backwards, the top of the stack is buried ;; where it is hard to get at. (let ((rp (sg-regular-pdl sg)) (sp (sg-special-pdl sg)) (spp (sg-special-pdl-pointer sg)) (frame (sg-ap sg))) (or (zerop (rp-micro-stack-saved rp frame)) ;Shuffle up stack to make room (do ((flag 0)) ((not (zerop flag))) (setf (aref sp (1+ spp)) (aref sp spp)) (%p-dpb 0 %%specpdl-block-start-flag (locf (aref sp (1+ spp)))) (setq flag (%p-ldb %%specpdl-block-start-flag (locf (aref sp spp)))) (setq spp (1- spp)))) (setf (aref sp (setq spp (1+ spp))) pc) (%p-dpb 1 %%specpdl-block-start-flag (locf (aref sp spp))) (setf (sg-special-pdl-pointer sg) (1+ (sg-special-pdl-pointer sg))) (setf (rp-micro-stack-saved rp frame) 1) (setf (rp-attention rp frame) 1))))) (defun sg-data-type (sg register) (%p-data-type (sg-locate sg register))) (defun sg-pointer-careful (sg register) (let* ((location (sg-locate sg register))) (cond ((%p-contents-safe-p location) (contents location)) ((%p-pointerp location) (%p-contents-as-locative location)) (t (%p-pointer location))))) (def-ucode-error argtyp arg-type-error :type-specifier (description-type-spec (second ete)) :arg-location-in-sg (third ete) :arg-pointer (sg-pointer-careful sg (third ete)) :arg-data-type (sg-data-type sg (third ete)) ;; arg-number is T if it was the only arg :arg-number (fourth ete) :restart-tag (fifth ete) :function (or (sixth ete) (and (eq (fifth ete) 'array-decode-n-error-restart) (not (memq (sg-erring-function sg) '(aref aset aloc))) (aref (sg-regular-pdl sg) (sg-ipmark sg))) (sg-erring-function sg))) (defflavor arg-type-error (function arg-number arg-pointer arg-data-type arg-location-in-sg restart-tag) (trap wrong-type-value) :gettable-instance-variables :initable-instance-variables) (defmethod (arg-type-error :after :init) (ignore) (setq place (and arg-number (neq arg-number 't) function (fboundp function) (nth arg-number (arglist function))))) (defmethod (arg-type-error :arg-name) () (send self :place)) (defmethod (arg-type-error :arg-number) () (and arg-number (if (eq arg-number 't) 0 arg-number))) ;; this is what wrong-type-value conditions expect (defmethod (arg-type-error :value) () (%make-pointer arg-data-type arg-pointer)) ;; I don't know what this is used by. (defmethod (arg-type-error :old-value) () (%make-pointer arg-data-type arg-pointer)) (defmethod (arg-type-error :report) (stream) (format:output stream (format t "~:[Some~*~*~;The~:[ ~:R~;~*~]~] argument to ~S, " arg-number (eq arg-number t) (and (numberp arg-number) (1+ arg-number)) function) (if (null arg-data-type) (format t "whose value has not been preserved") (unless (condition-case () (prin1 (%make-pointer arg-data-type arg-pointer)) (:no-error t) (error nil)) (printing-random-object (nil *standard-output*) (format t "~A #o~O" (nth arg-data-type q-data-types) (%pointer arg-pointer))))) (format t (if (arrayp function) ", was an invalid array subscript.~%Use " ", was of the wrong type.~%The function expected ")) (princ description) ".")) ;;; Translate symbols appearing in ARGTYP entries into type specs. ;;; Those that do not appear in the alist are left unchanged. ;;; SYMBOL-OR-LOCATIVE is translated because that's as good as defining it. ;;; The others are translated because they are global and we don't want ;;; to define any global type specs that aren't documented. (defvar *description-type-specs* '((plusp (non-complex-number (0))) (nonnegative-fixnum (fixnum 0)) (positive-fixnum (fixnum (0))) (area si::area) ;(nil null) (non-nil (not null)) (symbol-or-locative (or symbol locative)) (art-q-array (array t)))) (defun description-type-spec (desc) (if (symbolp desc) (or (cadr (assq desc *description-type-specs*)) desc) `(or . ,(mapcar #'description-type-spec desc)))) ;;; Define, as type specs, all the symbols that appear in ARGTYP entries. ;;; Specify pretty names for those for which the default is not pretty. ;;; For some, we must define new predicates to make them work in TYPEP. (deftype fixnum-field () '(satisfies fixnum-byte-spec-p)) (defun fixnum-byte-spec-p (x) (and (fixnump x) (< (byte-size x) %%q-pointer))) (defprop fixnum-field "a byte spec for a field that fits in a fixnum" si::type-name) (deftype art-q-list-array () '(and array (satisfies art-q-list-array-p))) (defun art-q-list-array-p (array) (eq (array-type array) 'art-q-list)) (defprop art-q-list-array "an ART-Q-LIST array" si::type-name) (deftype non-displaced-array () '(and array (not (satisfies array-displaced-p)))) (defprop non-displaced-array "a non-displaced array" si::type-name) (deftype reasonable-size-array () '(and array (satisfies array-size-reasonable-p))) (defun array-size-reasonable-p (array) (declare (ignore array)) t) ; I wonder what uses this... (deftype numeric-array () '(and array (not (array t)))) (defprop numeric-array "an array which cannot contain arbitrary lisp data." si::type-name) ;(deftype fixnum-greater-than-0 () '(and fixnum (integer 1))) ;(deftype fixnum-greater-than-1 () '(and fixnum (integer 2))) ;(deftype q-array () '(array t)) ;(deftype byte-array () '(and array (not (array t)))) ;(deftype art-4b-array () '(array (mod 16.))) ;(defprop art-4b-array "an ART-4B array" si::type-name) ;(deftype art-16b-array () '(array (unsigned-byte 16.))) ;(defprop art-16b-array "an ART-16B array" si::type-name) (defmethod (arg-type-error :ucode-proceed-types) () (if restart-tag '(:argument-value))) (defmethod (arg-type-error :case :proceed-asking-user :argument-value) (continuation read-object-function) "Use a different argument. You type an expression for the new value." (funcall continuation :argument-value (funcall read-object-function :eval-read "Form to evaluate and use as replacement argument: "))) (defmethod (arg-type-error :case :proceed-ucode-with-args :argument-value) (sg value-to-proceed-with &rest ignore) ;avoid using value as arg because its an instance var. (sg-store value-to-proceed-with sg arg-location-in-sg) (sg-proceed-micro-pc sg (and (neq restart-tag 'fall-through) restart-tag))) ;>> This seems pretty bogoid. Don't have to ucode with me now, though. (def-ucode-error flonum-no-good (arg-type-error wrong-type-argument) ;huh? (wrong-type-argument..) :description 'integer :arg-location-in-sg nil :arg-pointer nil :arg-data-type nil :arg-number nil :restart-tag nil :function (sg-erring-function sg)) ;;; FIXNUM-OVERFLOW ;;; First arg is M-T to show that that is where the value should ;;; get stored. Maybe it will someday be other things, too. ;;; Second is either PUSH or NOPUSH. ;;; Recover by storing a new value in the place where the ;;; value would have been stored if it hadn't overflowed. ;;; This is M-T, and also the regpdl if the second arg is PUSH. ;;; Force return from the microroutine executing at the time. ; not used 5-Jan-86 ;(def-ucode-error fixnum-overflow fixnum-overflow-error ; :function (sg-erring-function sg) ; :operands (list (sg-contents sg (second ete))) ; :number (sg-contents sg (second ete)) ; :location-in-sg (second ete) ; :push-new-value-flag ; (progn (or (memq (third ete) '(push nopush)) ; (bad-hacker ete "Bad ETE, must be PUSH or NOPUSH.")) ; (third ete))) ;(defflavor fixnum-overflow (function location-in-sg push-new-value-flag number) ; (trap arithmetic-error) ; :gettable-instance-variables :initable-instance-variables) ;(defmethod (fixnum-overflow :report) (stream) ; (format stream "~S got a fixnum overflow." function)) ;(defmethod (fixnum-overflow :ucode-proceed-types) () ; '(:new-value)) ;(defmethod (fixnum-overflow :case :proceed-asking-user :new-value) ; (continuation read-object-function &aux num) ; "Return a value specified by you. You type an expression for the new value." ; (setq num (funcall read-object-function :eval-read ; "Form to evaluate to get fixnum to return instead: ")) ; (check-type num fixnum) ; (funcall continuation :new-value num)) ;(defmethod (fixnum-overflow :case :proceed-ucode-with-args :new-value) (sg value &rest ignore) ; (sg-fixnum-store value sg location-in-sg) ; (and (eq push-new-value-flag 'push) ; (sg-regpdl-push sg value))) (defflavor floating-point-exception (small-float-p function) (trap arithmetic-error) :initable-instance-variables :gettable-instance-variables :abstract-flavor) (defmethod (floating-point-exception :operation) () (function-name function)) ; :operands, :non-trap-result ;;; FLOATING-EXPONENT-UNDERFLOW ;;; Arg is SFL or FLO (def-ucode-error floating-exponent-underflow floating-exponent-underflow :small-float-p (eq (second ete) 'sfl) :function (sg-erring-function sg)) (defflavor floating-exponent-underflow () (floating-point-exception) :gettable-instance-variables :initable-instance-variables) (defmethod (floating-exponent-underflow :report) (stream) (format stream "~S produced a result too small in magnitude to be a ~:[~;short~] float." function small-float-p)) ; Should have :new-value proceed type (defmethod (floating-exponent-underflow :ucode-proceed-types) () '(:use-zero)) (defmethod (floating-exponent-underflow :case :proceed-asking-user :use-zero) (continuation read-object-function) "Use 0.0 as the result." (when (funcall read-object-function '(:fquery :list-choices nil :fresh-line nil) "Proceed using 0.0~:[s~;f~]0 as the value instead? " (not small-float-p)) (funcall continuation :use-zero))) (defmethod (floating-exponent-underflow :case :proceed-ucode-with-args :use-zero) (sg &rest ignore) (sg-proceed-micro-pc sg nil)) ;;; FLOATING-EXPONENT-OVERFLOW ;;; Result is to be placed in M-T and pushed on the pdl. ;;; Arg is SFL or FLO ;;; In the case of SFL the pdl has already been pushed. (def-ucode-error floating-exponent-overflow floating-exponent-overflow :small-float-p (eq (second ete) 'sfl) :function (sg-erring-function sg)) (defflavor floating-exponent-overflow () (floating-point-exception) :gettable-instance-variables :initable-instance-variables) (defmethod (floating-exponent-overflow :report) (stream) (format stream "~S produced a result too large in magnitude to be a ~:[~;short~] float." function small-float-p)) (defmethod (floating-exponent-overflow :ucode-proceed-types) () '(:new-value)) (defmethod (floating-exponent-overflow :case :proceed-asking-user :new-value) (continuation read-object-function &aux num) "Use a float specified by you as the result." (do-forever (setq num (funcall read-object-function :eval-read (if small-float-p "Form evaluating to short-float to return instead: " "Form evaluating to float to return instead: "))) (cond ((and small-float-p (small-floatp num)) (return nil)) ((floatp num) (return nil))) (format t "Please use a ~:[~;short~] float.~%" small-float-p)) (funcall continuation :new-value num)) (defmethod (floating-exponent-overflow :case :proceed-ucode-with-args :new-value) (sg value &rest ignore) (sg-store value sg 'm-t) (and small-float-p (sg-regpdl-pop sg)) (sg-regpdl-push value sg)) ;;; DIVIDE-BY-ZERO ;;; You cannot recover. ;;; The second element of the ETE can be the location of the dividend. (defun (:property divide-by-zero make-ucode-error-function) (ignore sg ete) (declare (ignore ete)) (if (eq (sg-erring-function sg) '^) (make-instance 'illegal-expt-trap :base 'unknown :exponent (sg-contents sg 'pp)) (apply #'make-instance 'divide-by-zero :function (sg-erring-function sg) ;(if (second ete) `(:dividend ,(sg-contents sg (second ete)))) () ))) (defflavor divide-by-zero (function) (trap arithmetic-error) :initable-instance-variables :gettable-instance-variables) (defmethod (divide-by-zero :report) (stream) (format stream "There was an attempt to divide a number by zero in ~S." function)) (defflavor illegal-expt-trap () (trap illegal-expt)) (defflavor bad-array-mixin (array) () :abstract-flavor (:required-flavors error) :gettable-instance-variables :initable-instance-variables (:method-combination (:case :base-flavor-last :proceed :proceed-asking-user :document-proceed-type ;>> This is a kludge. It should only be on trap, ;>> but some compile-flavor-methods lossage is getting in my ;>> way on this cold-load. Excise it when convenient. :proceed-ucode-with-args))) (defmethod (bad-array-mixin :case :proceed-asking-user :new-array) (continuation read-object-function) "Use a different array. You type an expression for the array to use." (funcall continuation :new-array (funcall read-object-function :eval-read "Form to eval to get array to use instead: "))) (defflavor bad-array-trap (array-location-in-sg (restart-tag nil) function) (bad-array-mixin trap error) :initable-instance-variables :gettable-instance-variables) (defmethod (bad-array-trap :ucode-proceed-types) () (if restart-tag '(:new-array))) (defmethod (bad-array-trap :case :proceed-ucode-with-args :new-array) (sg -array-) (sg-store -array- sg array-location-in-sg) (sg-proceed-micro-pc sg restart-tag)) ;;; ARRAY-NUMBER-DIMENSIONS ;;; First arg is no longer used. ;;; Second arg is how many dimensions we want (as a constant), or NIL if variable number. ;;; Third arg is the array ;;; Fourth arg is restart tag. ;;; Fourth arg is QARYR if this is array called as function. (def-ucode-error array-number-dimensions (array-number-dimensions-error array-wrong-number-of-dimensions) :array (sg-contents sg (fourth ete)) :array-location-in-sg (fourth ete) :subscripts-given (array-number-dimensions-subscript-list sg ete) :restart-tag (fifth ete)) (defun array-number-dimensions-subscript-list (sg ete) (let* ((rp (sg-regular-pdl sg))) (if (not (fixnump (third ete))) ;; This is AREF, ALOC, ASET or array called as function. (do ((p (sg-regular-pdl-pointer sg) (1- p)) subscripts (c (sg-fixnum-contents sg 'm-r) (1- c))) (( c 0) subscripts) (push (aref rp p) subscripts)) ;; (THIRD ETE) tells us whether the error was from ARRAY-DECODE-1, -2 or -3. (case (third ete) (1 (list (sg-fixnum-contents sg 'm-q))) (2 (list (sg-contents sg 'm-j) (sg-contents sg 'm-q))) (3 (list (sg-contents sg 'm-i) (sg-contents sg 'm-j) (sg-contents sg 'm-q))))))) (defflavor array-number-dimensions-error (subscripts-given) (bad-array-trap) :initable-instance-variables :gettable-instance-variables) (defmethod (array-number-dimensions-error :number-of-subscripts-expected) () (array-rank array)) (defmethod (array-number-dimensions-error :number-of-subscripts-given) () (length subscripts-given)) (defmethod (array-number-dimensions-error :report) (stream) (format stream ;; Was this array applied or aref'ed? (if (eq restart-tag 'qaryr) "The ~D-dimensional array ~S was erroneously applied to ~D argument~:P ~S." "The ~D-dimensional array ~S was given ~D subscript~:P: ~S.") (array-rank array) array (length subscripts-given) subscripts-given)) ;;; NUMBER-ARRAY-NOT-ALLOWED ;;; First arg is where to find the array. ;;; Second arg is restart tag for new array. (def-ucode-error number-array-not-allowed number-array-not-allowed :array (sg-contents sg (second ete)) :array-location-in-sg (second ete) :restart-tag (third ete) :referencing-function (sg-erring-function sg)) (defflavor number-array-not-allowed (referencing-function) (bad-array-trap) :initable-instance-variables :gettable-instance-variables) (defmethod (number-array-not-allowed :report) (stream) (format stream "The array ~S, which was given to ~S, is not allowed to be a number array." array referencing-function)) ;;; INDIVIDUAL-SUBSCRIPT-OOB ;;; First arg is location of array ;;; second arg is dimension number. ;;; We assume that the current frame's args are the array and the subscripts, ;;; and find the actual losing subscript that way. ; not used 5-Jan-86 ;(def-ucode-error individual-subscript-oob (subscript-error subscript-out-of-bounds) ; :function (sg-erring-function sg) ; :object (sg-contents sg (second ete)) ; :subscripts-given (subscript-oob-subscript-list sg ete) ; :dimension-number (sg-contents sg (third ete)) ; :restart-tag (fourth ete)) ;;; SUBSCRIPT-OOB ;;; First arg is how many we gave. ;;; Second is the legal limit. ;;; Third optional arg is a restart tag. ;;; It can also be a list of restart tags. Then their addresses are pushed sequentially. ;;; This is used to get the effect of making the microcode restart by calling ;;; a subroutine which will return to the point of the error. ;;; Fourth optional arg is where the array is. ;;; Fifth is either T if indices are on the stack, ;;; or 1 if this is AR-1-FORCE or such like and there is only one index (first arg says where) ;;; or missing if this is AR-1, AR-2, AR-3 and the array's rank should be ;;; used to decide where the args are. (def-ucode-error subscript-oob (subscript-error subscript-out-of-bounds) :function (sg-erring-function sg) :index-location-in-sg (second ete) :subscript-used (sg-fixnum-contents sg (second ete)) :subscripts-given (subscript-oob-subscript-list sg ete) :subscript-limit (sg-fixnum-contents sg (third ete)) :restart-tag (fourth ete) :object (if (fifth ete) (sg-contents sg (fifth ete)))) (defun subscript-oob-subscript-list (sg ete) (let* ((object (if (fifth ete) (sg-contents sg (fifth ete)))) (frame (sg-ipmark sg)) (rp (sg-regular-pdl sg)) (fn (rp-function-word rp frame))) (if (locativep object) ;for reasons having to do with array-caching, ; the ucode changes the data-type to DTP-LOCATIVE ; for displaced or indirect arrays. (setq object (%make-pointer dtp-array-pointer object))) (if (and (arrayp object) (neq (sixth ete) 1)) (if (sixth ete) ;; This is AREF, ALOC, ASET or array called as function. (do ((p (sg-regular-pdl-pointer sg) (1- p)) subscripts (limit (+ frame (cond ((eq fn #'aset) 2) ((typep fn 'array) 0) (t 1))))) ((= p limit) subscripts) (push (aref rp p) subscripts)) ;; It is AX-1, AX-2 or AX-3. Since we are past the point of getting ;; a wrong-number-dimensions error, we can tell which by the rank of the array. ;; The ETE cannot distinguish since the errors come from the same spot. ; (if array-index-order (let ((rank (array-rank object))) (case rank (1 (list (sg-fixnum-contents sg (second ete)))) (2 (list (sg-contents sg 'm-j) (- (sg-fixnum-contents sg (second ete)) (* (array-dimension object 1) (sg-contents sg 'm-j))))) (3 (list (sg-contents sg 'm-i) (sg-contents sg 'm-j) (- (sg-fixnum-contents sg (second ete)) (* (array-dimension object 2) (+ (sg-contents sg 'm-j) (* (array-dimension object 1) (sg-contents sg 'm-i))))))))) ; (let ((rank (array-rank object))) ; (case rank ; (1 (list (sg-fixnum-contents sg (second ete)))) ; (2 (list (- (sg-fixnum-contents sg (second ete)) ; (* (array-dimension object 0) ; (sg-contents sg 'm-j))) ; (sg-contents sg 'm-j))) ; (3 (list (- (sg-fixnum-contents sg (second ete)) ; (* (array-dimension object 0) ; (+ (sg-contents sg 'm-j) ; (* (array-dimension object 1) ; (sg-contents sg 'm-i))))) ; (sg-contents sg 'm-j) ; (sg-contents sg 'm-i)))))) ) ;; If object is not known or not an array, or if AX-1-FORCE. (list (sg-fixnum-contents sg (second ete)))))) (defflavor subscript-error (function subscripts-given subscript-used index-location-in-sg subscript-limit restart-tag object (dimension-number nil)) (trap error) :gettable-instance-variables :initable-instance-variables) (defmethod (subscript-error :report) (stream) (cond (dimension-number (format stream "The subscript for dimension ~D was ~S, which is out of range for ~S." dimension-number (nth dimension-number subscripts-given) object)) (object (if (locativep object) ;see comment above. (setq object (%make-pointer dtp-array-pointer object))) (if (= (length subscripts-given) 1) (format stream "The subscript ~S for ~S was out of range in ~S." subscript-used object function) (format stream "The subscripts ~S for ~S were out of range in ~S." subscripts-given object function))) ((< subscript-used 0) (format stream "The index, ~S, was negative in ~S." subscript-used function)) (t (format stream "The index, ~S, was beyond the length, ~S, in ~S." subscript-used subscript-limit function)))) (defmethod (subscript-error :ucode-proceed-types) () '(:new-subscript)) (defmethod (subscript-error :case :proceed-asking-user :new-subscript) (continuation read-object-function) "Use different subscripts. You type expressions for them." (if (or (not (arrayp object)) ( (length subscripts-given) (array-rank object))) (let (num) (do-forever (setq num (funcall read-object-function :eval-read "Form evaluating to index to use instead: ")) (if (and (integerp num) (< -1 num subscript-limit)) (return (values))) (format t "Please use a positive fixnum less than ~D.~%" subscript-limit)) (funcall continuation :new-subscript num)) (do ((i 0 (1+ i)) subscripts) ((= i (length subscripts-given)) (apply continuation :new-subscript (nreverse subscripts))) (push (funcall read-object-function :eval-read " Subscript ~D: " i) subscripts)))) (defmethod (subscript-error :case :proceed-ucode-with-args :new-subscript) (sg &rest subscripts) (if dimension-number ;; For error in ARRAY-ROW-MAJOR-INDEX, ;; store back all the subscripts into the frame. ;; We will restart the function to examine them. (do ((tail subscripts (cdr tail)) (i 0 (1+ i))) ((= i (length subscripts-given))) (setf (aref (sg-regular-pdl sg) (+ (sg-ap sg) i 2)) (car tail))) ;; Errors based on the cumulative index: store the updated cumulative index. (sg-fixnum-store ; (if array-index-order (do ((i 0 (1+ i)) (index 0) (rest subscripts (cdr rest))) ((null rest) index) (setq index (* index (array-dimension object i))) (incf index (car rest))) ; (do ((i (array-rank object) (1- i)) ; (index 0) ; (rest (reverse subscripts) (cdr rest))) ; ((null rest) index) ; (setq index (* index (array-dimension object (1- i)))) ; (incf index (car rest)))) sg index-location-in-sg)) (if (consp restart-tag) (dolist (tag restart-tag) (sg-proceed-micro-pc sg tag)) (sg-proceed-micro-pc sg restart-tag))) ;;; First arg is where to find array, second is where to find dimension number. ;>> this is inadequate -- needs bad-array-mixin stuff (def-ucode-format-error bad-array-dimension-number "The dimension number ~S is out of range for ~S." (sg-fixnum-contents sg (third ete)) (sg-contents sg (second ete))) ;;; BAD-ARRAY-TYPE ;;; First arg is where array header is. Note that it may well have a data type of DTP-TRAP. ;;; You cannot recover. (def-ucode-format-error bad-array-type "The array type, ~S, was invalid in ~S." (ldb %%array-type-field (%p-pointer (sg-locate sg (second ete)))) (sg-erring-function sg)) ;;; ARRAY-HAS-NO-LEADER ;;; First arg is where array pointer is. ;;; Second arg is restart tag for new array. (def-ucode-error array-has-no-leader array-has-no-leader :array (sg-contents sg (second ete)) :array-location-in-sg (second ete) :restart-tag (third ete) :function (sg-erring-function sg)) (defflavor array-has-no-leader (function) (bad-array-trap) :initable-instance-variables) (defmethod (array-has-no-leader :report) (stream) (format stream "The array given to ~S, ~S, has no leader." function array)) ;;; FILL-POINTER-NOT-FIXNUM ;;; First arg is where array pointer is. ;;; Second arg is restart tag for new array. (def-ucode-error fill-pointer-not-fixnum bad-array-trap :array (sg-contents sg (second ete)) :array-location-in-sg (second ete) :restart-tag (third ete) :format-string :format-args (list (sg-erring-function sg) (sg-contents sg (second ete)))) (defflavor fill-pointer-not-fixnum (function) (bad-array-trap) :initable-instance-variables) (defmethod (fill-pointer-not-fixnum :report) (stream) (format stream "The fill-pointer of the array given to ~S, ~S, is not a fixnum." function array)) ;;;; More random losses. ;;; IALLB-TOO-SMALL ; not used 5-Jan-86 ;; First arg is how many we asked for. ;(def-ucode-format-error iallb-too-small ; "There was a request to allocate ~S cells." ; (sg-fixnum-contents sg (second ete))) ; ;(def-ucode-format-error cons-zero-size ; "There was an attempt to allocate zero storage by ~S." ; (sg-erring-function sg)) ;>> this is a bit of a crock. Differs from real invalid-function in that instead of ;>> calling out to apply-lambda with the losing function, it errs when pushing the ;>> "function" on the pdl (def-ucode-error number-called-as-function invalid-function-trap :function (sg-contents sg (second ete))) (defflavor invalid-function-trap () (invalid-function trap)) (defmethod (invalid-function-trap :ucode-proceed-types) () '(:new-function)) (defmethod (invalid-function-trap :case :proceed-ucode-with-args :new-function) (sg new-function) (sg-store new-function sg 'm-a) (sg-proceed-micro-pc sg nil)) ;;; WRONG-SG-STATE ;;; Arg is where sg is. ;;; You cannot recover. ;>> (def-ucode-error wrong-sg-state (error wrong-stack-group-state) :format-string "The state of the stack group, ~S, given to ~S, was invalid.~%" :format-args (list (sg-contents sg (second ete)) (sg-erring-function sg))) ;;; SG-RETURN-UNSAFE ;;; No args, since the frob is in the previous-stack-group of the current one. ;;; You cannot recover. (def-ucode-format-error sg-return-unsafe "An /"unsafe/" stack group attempted to ~S." 'stack-group-return) ;;; TV-ERASE-OFF-SCREEN ;;; No arg. (def-ucode-format-error tv-erase-off-screen ;draw-off-end-of-screen "An attempt was made to do graphics past the end of the screen.") ;;; THROW-TAG-NOT-SEEN ;; This comes from throw-trap: below ;;>> See dj:mly;throw-trap (defflavor throw-tag-not-seen (tag value count action) (trap error) :gettable-instance-variables :initable-instance-variables) (defmethod (throw-tag-not-seen :values) () (list value)) (defmethod (throw-tag-not-seen :report) (stream) (format stream "There was no pending ~S for the tag ~S." 'catch tag)) (defmethod (throw-tag-not-seen :after :print-error-message) (sg brief stream) (declare (ignore sg)) (unless brief (format stream "The value being thrown was ~S." value) (and (or count action) (format stream "~&While in a *UNWIND-STACK with remaining count of ~D and action ~S." count action)))) (defmethod (throw-tag-not-seen :ucode-proceed-types) () '(:new-tag)) (defmethod (throw-tag-not-seen :case :proceed-asking-user :new-tag) (continuation read-object-function) "Throw to another tag. You type an expression for it." (funcall continuation :new-tag (funcall read-object-function :eval-read "Form evaluating to tag to use instead: "))) (defmethod (throw-tag-not-seen :case :proceed-ucode-with-args :new-tag) (sg new-tag) (sg-store new-tag sg 'm-a) (sg-proceed-micro-pc sg ())) ;;; MVR-BAD-NUMBER ;;; Where the # is. ; not used 5-Jan-86 ;(def-ucode-format-error mvr-bad-number ; "The function attempted to return ~D. values." ; (sg-fixnum-contents sg (second ete))) (def-ucode-format-error zero-args-to-select-method "~S was applied to no arguments." (sg-contents sg (second ete))) (defflavor select-method-not-found () (trap unclaimed-message)) (def-ucode-error selected-method-not-found select-method-not-found :object (sg-contents sg (second ete)) :message (sg-contents sg (third ete)) :arguments (cdr (sg-accumulated-arguments sg))) (defun sg-accumulated-arguments (sg) (do ((idx (1+ (sg-ipmark sg)) (1+ idx)) (limit (sg-regular-pdl-pointer sg)) (rp (sg-regular-pdl sg)) args) ((> idx limit) (nreverse args)) (push (aref rp idx) args))) (def-ucode-format-error select-method-garbage-in-select-method-list "The weird object ~S was found in a select-method alist." (sg-contents sg (second ete))) (def-ucode-format-error select-method-bad-subroutine-call "A bad /"subroutine call/" was found inside ~S." (sg-contents sg (second ete))) (def-ucode-format-error no-mapping-table "Flavor ~S is not a component of SELF's flavor, ~S, on a call to a function which assumes SELF is a ~S." (si:fef-flavor-name (aref (sg-regular-pdl sg) (sg-ap sg))) (type-of (symeval-in-stack-group 'self sg)) (si:fef-flavor-name (aref (sg-regular-pdl sg) (sg-ap sg)))) (def-ucode-format-error no-mapping-table-1 "SYS:SELF-MAPPING-TABLE is NIL in a combined method.") (def-ucode-format-error self-not-instance "A method is referring to an instance variable, but SELF is ~S, not an instance." (symeval-in-stack-group 'self sg)) ;;; Signaled by LOCATE-IN-INSTANCE (def-ucode-format-error instance-lacks-instance-variable "There is no instance variable ~S in ~S." (sg-contents sg (second ete)) (sg-contents sg (third ete))) ;This is no longer called. ; Instead, new-nonexistent-instance-variable is the guy. ; Unfortunately, that is not handled. (def-ucode-format-error nonexistent-instance-variable "Compiled code referred to instance variable ~S, no longer present in flavor ~S." ; was ... (si:flavor-decode-self-ref-pointer (%p-pointer (sg-saved-vma sg))) (si:flavor-decode-self-ref-pointer (si:fef-flavor-name (aref (sg-regular-pdl sg) (sg-ap sg))) (sg-regpdl-pop sg)) (si:fef-flavor-name (aref (sg-regular-pdl sg) (sg-ap sg)))) (def-ucode-format-error micro-code-entry-out-of-range "MISC-instruction ~S is not an implemented instruction." (sg-fixnum-contents sg (second ete))) (def-ucode-format-error bignum-not-big-enough-dpb "There is an internal error in bignums; please report this bug.") (def-ucode-format-error bad-internal-memory-selector-arg "~S is not valid as the first argument to %WRITE-INTERNAL-PROCESSOR-MEMORIES." (sg-fixnum-contents sg (second ete))) (def-ucode-format-error bitblt-destination-too-small "The destination of a BITBLT was too small.") (def-ucode-format-error bitblt-array-fractional-word-width "An array passed to BITBLT has an invalid width. The width, times the number of bits per pixel, must be a multiple of 32.") (defflavor write-in-read-only (address) (trap error) :gettable-instance-variables :initable-instance-variables) (defmethod (write-in-read-only :report) (stream &aux name) (format stream " There was an attempt to write into #o~O, which is a read-only address.~ ~% #o~O is in area #~D, ~S" address address (%area-number address) (setq name (area-name (%area-number address)))) (if (eq name 'macro-compiled-program) (format stream "~% Compiled-in LISTS and STRINGS are consed in the MACRO-COMPILED-PROGRAM area,~ ~% and attempts to modify them are often the source of this error."))) (def-ucode-error write-in-read-only write-in-read-only :address (sg-contents sg (second ete))) (def-ucode-error turd-alert (turd-alert-error draw-on-unprepared-sheet) :sheet (sg-contents sg (second ete))) (defflavor turd-alert-error (sheet) (trap error) :gettable-instance-variables :initable-instance-variables) (defmethod (turd-alert-error :report) (stream) (format stream "There was an attempt to draw on the sheet ~S without preparing it first.~%" sheet)) (defmethod (turd-alert-error :ucode-proceed-types) () '(:no-action)) (defmethod (turd-alert-error :case :proceed-asking-user :no-action) (continuation ignore) "Proceed, perhaps writing garbage on the screen." (funcall continuation :no-action)) (defmethod (turd-alert-error :case :proceed-ucode-with-args :no-action) (sg &rest ignore) (sg-proceed-micro-pc sg nil)) (def-ucode-format-error physical-address-not-in-sys-conf "The nubus physical address #x~16r is not part of the system configuration structure." (sg-contents sg (second ete))) (def-ucode-format-error virtual-address-not-in-sys-conf "The virtual address ~o is not part of the system configuration structure." (sg-fixnum-contents sg (second ete))) ;;;; General Machine Lossages. ;;; PDL-OVERFLOW ;;; Arg is either SPECIAL or REGULAR (def-ucode-error pdl-overflow pdl-overflow :pdl-name (cdr (assq (second ete) '((regular . :regular) (special . :special))))) (defflavor pdl-overflow (pdl-name) (trap debugger-condition) :gettable-instance-variables :initable-instance-variables) (defmethod (pdl-overflow :report) (stream) (format stream "The ~A push-down list has overflown." (cadr (assq pdl-name '((:regular "regular") (:special "special")))))) (defmethod (pdl-overflow :ucode-proceed-types) () '(:grow-pdl)) (defmethod (pdl-overflow :case :proceed-asking-user :grow-pdl) (continuation ignore) "Make the stack larger and proceed." (funcall continuation :grow-pdl)) (defmethod (pdl-overflow :case :proceed-ucode-with-args :grow-pdl) (sg &rest ignore) (format t "Continuing with more pdl.~%") (sg-maybe-grow-pdls sg t nil nil t) ;Make very sure that there is enough room (sg-proceed-micro-pc sg nil)) ;Then continue after ucode check for room ;;; ILLEGAL-INSTRUCTION ;;; No args. (defflavor illegal-instruction (compiled-function pc) (trap error) :initable-instance-variables :gettable-instance-variables) (defmethod (illegal-instruction :report) (stream) (if pc (format stream "Illegal instruction #o~O at pc ~D in ~S (~S)" (fef-instruction compiled-function pc) pc compiled-function (string-trim '(#/space #/newline #/tab) (with-output-to-string (*standard-output*) (compiler:disassemble-instruction compiled-function pc)))) (write-string "There was an attempt to execute an invalid instruction." stream))) (defun (:property illegal-instruction make-ucode-error-function) (ignore sg ignore) (let ((fef (aref (sg-regular-pdl sg) (sg-ap sg))) (pc (1- (rp-exit-pc (sg-regular-pdl sg) (sg-ap sg))))) (make-instance 'illegal-instruction :compiled-function fef :pc (if (and (compiled-function-p fef) (< (floor pc 2) (%structure-total-size fef))) pc nil)))) ; M-1 contains nubus physical address ; M-2 contains the data (on a write) ; M-A has cycle code: ; 1 = %nubus-read ; 2 = %nubus-read-byte ; 3 = %nubus-write ; 4 = %nubus-write-byte ; M-B has low 16 bits of memory status register ; (M-A, M-B have 0 in their data-types) ; No ucode generates this 5-Jan-86. What's the story (defun (:property nubus-error make-ucode-error-function) (ignore sg ignore) (let ((phys-adr (sg-contents sg 'M-1)) (data (sg-contents sg 'M-2)) (cycle-type (cdr (assq (sg-fixnum-contents sg 'M-A) '((1 . :read) (2 . :read-byte) (3 . :write) (4 . :write-byte))))) (memory-status-reg (sg-fixnum-contents sg 'M-B)) cycle-status) (setq cycle-status (cond ((ldb-test (byte 1 14.) memory-status-reg) :nubus-timeout) ((ldb-test (byte 1 15.) memory-status-reg) :parity-error) ((= (ldb (byte 2 6) memory-status-reg) 1) :parity-error) ((= (ldb (byte 2 6) memory-status-reg) 2) :nubus-timeout) (t nil))) (make-instance 'nubus-error :physical-address phys-adr :data data :cycle-type cycle-type :cycle-status cycle-status))) (defflavor nubus-error (physical-address data cycle-type cycle-status) (trap error) :gettable-instance-variables :initable-instance-variables) (defmethod (nubus-error :report) (stream) (format stream "Nubus error type ~a while trying to do ~a of #x~x." cycle-status cycle-type physical-address) (if (memq cycle-type '(:write :write-byte)) (format stream " The data was #x~x" data))) (defmethod (nubus-error :ucode-proceed-types) () (cond ((memq cycle-type '(:write :write-byte)) '(:try-again :dont-write)) (t '(:try-again :return-0)))) (defmethod (nubus-error :case :proceed-asking-user :try-again) (continuation ignore) "Try again." (funcall continuation :try-again)) (defmethod (nubus-error :case :proceed-asking-user :dont-write) (continuation ignore) "Proceed skipping the write operation." (funcall continuation :dont-write)) (defmethod (nubus-error :case :proceed-asking-user :return-0) (continuation ignore) "Proceed returning 0 from the read operation." (funcall continuation :return-0)) (defmethod (nubus-error :case :proceed-ucode-with-args :dont-write) (sg &rest ignore) (sg-proceed-micro-pc sg nil)) (defmethod (nubus-error :case :proceed-ucode-with-args :return-0) (sg &rest ignore) (sg-store 0 sg 'M-T) (sg-proceed-micro-pc sg nil)) ;some day... (defmethod (nubus-error :case :proceed-ucode-with-args :try-again) (sg &rest ignore) (sg-store 0 sg 'M-T) (sg-proceed-micro-pc sg nil) ) ;;; BAD-CDR-CODE ;;; Arg is where loser is. (def-ucode-format-error bad-cdr-code "A bad cdr-code was found in memory (at address ~O)." (sg-fixnum-contents sg (second ete))) ;Can't use Lisp print since will err again ;;; DATA-TYPE-SCREWUP ;;; This happens when some internal data structure contains wrong data type. arg is name. ;;; As it happens, all the names either start with a vowel or do if pronounced as letters ;;; Not continuable (def-ucode-format-error data-type-screwup "A bad data-type was found in the internal guts of an ~A." (second ete)) ;;; STACK-FRAME-TOO-LARGE (def-ucode-format-error stack-frame-too-large "Attempt to make a stack frame larger than 256. words.") ;;; AREA-OVERFLOW ;;; arg is register containing area# ; This "feature" punted 851802 ;(def-ucode-format-error area-overflow ; "Allocation in the /"~A/" area exceeded the maximum of ~D. words." ; (area-name (sg-fixnum-contents sg (second ete))) ; (area-maximum-size (sg-fixnum-contents sg (second ete)))) ;;; VIRTUAL-MEMORY-OVERFLOW (def-ucode-error virtual-memory-overflow random-dangerous-trap :format-string "You've used up all available virtual memory!~% This can happen even if you have the garbage collector on. Perhaps increasing the frequency or volatility of GC flips will help in the future. (Try GC:GC-ON with an argument of 2 or 3)") ;;; RCONS-FIXED ; Not used 5-Jan-86 ;(def-ucode-error rcons-fixed (error cons-in-fixed-area) ; :property-list `(:area ,(area-name (sg-contents sg 'm-s))) ; :format-string "There was an attempt to allocate storage in the fixed area ~S." ; :format-args (list (area-name (sg-contents sg 'm-s)))) ;;; REGION-TABLE-OVERFLOW (def-ucode-error region-table-overflow random-dangerous-trap :format-string "Unable to create a new region because the region tables are full.") ;;; RPLACD-WRONG-REPRESENTATION-TYPE ;;; arg is first argument to RPLACD ; not used 5-Jan-86 ;(def-ucode-format-error rplacd-wrong-representation-type ; "Attempt to RPLACD a list which is embedded in a structure and therefore ;cannot be RPLACD'ed. The list is ~S." ; (sg-contents sg (second ete))) ;;;; Special cases. ;;; MAR-BREAK ;;; This code won't work if write-data is a DTP-NULL because of trap out of MAKUNBOUND (defun mar-break-decode (sg ete) (let ((direction (cdr (assq (second ete) '((write . :write) (read . :read))))) object-data-type object-pointer value-data-type value-pointer value object offset value-has-dtp-null ) ;first get the MD (setq value-data-type (sg-regpdl-pop sg)) (setq value-pointer (sg-regpdl-pop sg)) ;then the VMA (setq object-data-type (sg-regpdl-pop sg)) (setq object-pointer (sg-regpdl-pop sg)) (cond ((eq direction :write) (cond ((si:%data-type-safe-p value-data-type) (setq value (%make-pointer value-data-type value-pointer))) ((= value-data-type dtp-null) (setq value (%make-pointer dtp-locative value-pointer)) (setq value-has-dtp-null t)) (t (ferror "bad MD in mar break")))) (t (setq value-data-type (%p-data-type object-pointer)) (setq value-pointer (%p-pointer object-pointer)) (cond ((= value-data-type dtp-null) (setq value-has-dtp-null t)) ((not (si:%data-type-safe-p value-data-type)) (ferror "VMA points to bad data in MAR read trap")))) ) (setq object (%find-structure-header object-pointer)) (setq offset (%pointer-difference object-pointer object)) (values direction value object offset value-has-dtp-null))) (defun (:property mar-break make-ucode-error-function) (ignore sg ete) (multiple-value-bind (dir val obj off dtp-null-flag) (mar-break-decode sg ete) (make-instance 'mar-break :direction dir :value val :object obj :offset off :value-has-dtp-null dtp-null-flag))) (defflavor mar-break (direction value object offset value-has-dtp-null) (trap debugging-condition) :gettable-instance-variables :initable-instance-variables) (defmethod (mar-break :report) (stream) (if (eq direction ':write) (format stream "The MAR has gone off because of an attempt to write ~S into offset ~O in ~S." (if (null value-has-dtp-null) value "void") offset object) (format stream "The MAR has gone off because of an attempt to read from offset ~O in ~S." offset object))) (defmethod (mar-break :ucode-proceed-types) () (cond ((eq direction ':write) '(:no-action :proceed-no-write)) (t '(:no-action)))) (defmethod (mar-break :case :proceed-asking-user :no-action) (continuation ignore) "Proceed." (funcall continuation :no-action)) (defmethod (mar-break :case :proceed-asking-user :proceed-no-write) (continuation ignore) "Proceed, not changing the cell contents." (funcall continuation :proceed-no-write)) (defmethod (mar-break :case :proceed-ucode-with-args :no-action) (sg &rest ignore) ;; By simply returning without calling SG-PROCEED-MICRO-PC, the PGF-R will return (sg-funcall sg #'(lambda (vma md) ;Simulate the write (let ((%mar-high -2) (%mar-low -1)) ;Disable MAR (rplaca vma md))) (%make-pointer-offset dtp-locative object offset) value)) (defmethod (mar-break :case :proceed-ucode-with-args :proceed-no-write) (&rest ignore) ;; By simply returning without calling SG-PROCEED-MICRO-PC, the PGF-R will return ) ;;;; TRANS-TRAP (defun %p-contents-eq (p x) (and (neq (%p-data-type p) dtp-null) (eq (car p) x))) ;;; Given the address on which a trans-trap occurred, determine where the contents ;;; of that address is stored now, and if it is a null pointer, what cell of which ;;; symbol was unbound. The "symbol" can actually be a function-spec. (defun trans-trap-decode (sg) (declare (values original-address current-address cell-type symbol)) (let (original-address current-address cell-type symbol contents pp rp) (setq pp (sg-regular-pdl-pointer sg)) (setq rp (sg-regular-pdl sg)) (cond ((assq 'trans-trap-restart-new restart-list) ;hack! (setq original-address (%make-pointer dtp-locative (aref rp (- pp 3))))) (t (setq original-address (sg-saved-vma sg)))) (setq current-address (cell-location-in-stack-group original-address sg)) (setq cell-type nil) ;NIL means not a null pointer (when (= (aref rp pp) dtp-null) (setq cell-type ':closure) ;Jumping to conclusions, default to this (setq contents (%make-pointer dtp-locative (aref rp (1- pp))) symbol (%find-structure-header contents)) (cond ((symbolp symbol) (case (%pointer-difference original-address symbol) (1 (setq cell-type ':value)) (2 (setq cell-type ':function)) (t (if (fboundp 'si:identify-locative-to-index-cell-array) (let ((type (si:identify-locative-to-index-cell-array original-address))) (if type (setq cell-type type))))))) ((and (consp symbol) (= (%p-data-type symbol) dtp-list) (%p-contents-eq (car symbol) ':method)) (setq cell-type ':function symbol (si::meth-function-spec symbol))) (t (setq cell-type nil)))) (values original-address current-address cell-type symbol))) (defun (:property trans-trap make-ucode-error-function) (ignore sg ete) (declare (ignore ete)) (without-interrupts (multiple-value-bind (original-address current-address cell-type symbol) (trans-trap-decode sg) (setq current-address (%make-pointer dtp-locative current-address)) (make-instance (case cell-type ((:value :closure) 'unbound-variable) (:function 'undefined-function) (t 'cell-contents-error)) :address original-address :current-address current-address :cell-type cell-type :symbol symbol :data-type (aref (sg-regular-pdl sg) (sg-regular-pdl-pointer sg)) :pointer (aref (sg-regular-pdl sg) (1- (sg-regular-pdl-pointer sg))) :containing-structure (%find-structure-header original-address) :condition-names (case cell-type (:value '(unbound-symbol)) (:closure (typecase (%find-structure-header original-address) (instance '(unbound-instance-variable)) (list '(unbound-closure-variable)) (t '(bad-data-type-in-memory)))) (:function `(undefined-function)) (t '(bad-data-type-in-memory))))))) (defflavor cell-contents-error (address current-address cell-type symbol containing-structure data-type pointer) (trap error) :gettable-instance-variables :initable-instance-variables) (defmethod (cell-contents-error :current-address) () (%pointer current-address)) (defflavor unbound-variable () (cell-contents-error)) (defmethod (unbound-variable :variable-name) () symbol) (defmethod (unbound-variable :instance) () (and (typep containing-structure 'instance) containing-structure)) (defflavor undefined-function () (cell-contents-error)) (defmethod (undefined-function :function-name) () symbol) (defmethod (cell-contents-error :report) (stream &aux contents-changed verb) (setq contents-changed (or ( (%p-data-type current-address) data-type) ( (%p-pointer current-address) pointer))) (setq verb (if contents-changed "was" "is")) (case cell-type (:value (format stream "The variable ~S ~A unbound." symbol verb)) (:function (format stream "The function ~S ~A undefined." symbol verb)) (:closure (if (typep containing-structure 'instance) (format stream "The instance variable ~S ~A unbound in ~S." symbol verb containing-structure) (format stream "The variable ~S ~A unbound (in a closure value-cell)." symbol verb))) (otherwise (format stream "The word #<~S ~S> was read from location ~O ~@[(in ~A)~]." (q-data-types data-type) pointer (%pointer address) (let ((area (%area-number address))) (and area (area-name area))))))) (defmethod (cell-contents-error :after :print-error-message) (sg brief stream &aux prop contents-changed) (unless brief (setq contents-changed (or ( (%p-data-type current-address) data-type) ( (%p-pointer current-address) pointer))) (case cell-type (:value (if contents-changed (cell-contents-error-print-new-contents-1 stream "It now has the value" current-address))) (:function (if contents-changed (cell-contents-error-print-new-contents-1 stream "It now has the definition" current-address)) (and (symbolp symbol) (get symbol 'compiler::qintcmp) (let ((fn (rp-function-word (sg-regular-pdl sg) (sg-out-to-interesting-active sg *error-locus-frame*)))) (format stream "Note: ~S is supported as a function only when used in compiled code.~%" symbol) (if (consp fn) (format stream "You may have evaluated the definition of ~S, which is now not compiled.~%" (function-name fn))))) (and (symbolp symbol) (setq prop (getl symbol '(expr fexpr macro subr fsubr lsubr autoload))) (format stream "Note: the symbol has a ~S property, ~ so this may be a Maclisp compatibility problem.~%" (car prop)))) (:closure (if contents-changed (cell-contents-error-print-new-contents-1 stream "It now has the value" current-address))) (otherwise (if contents-changed (cell-contents-error-print-new-contents-1 stream "The cell now contains" current-address)))))) (defun cell-contents-error-print-new-contents-1 (stream cell-description address) (if (%p-contents-safe-p address) (format stream "~A ~S.~%" cell-description (%p-contents-offset address 0)) (format stream "~A #<~S ~S>.~%" cell-description (q-data-types (%p-data-type address)) (%p-pointer address)))) ;;; Some people would rather not spend the time for this feature, so let them turn it off (defconst enable-trans-trap-dwim t "Non-NIL means look spontaneously in other packages on undefined function or variable error.") ;;; If problem is symbol in wrong package, offer some dwimoid assistance. (defmethod (cell-contents-error :debugger-command-loop) (sg &optional (error-object self)) (catch 'quit (and enable-trans-trap-dwim (catch-error-restart ((sys:abort error) "Return to debugger command loop.") (let ((*error-sg* sg)) (send error-object :proceed-asking-user :package-dwim 'proceed-error-sg 'read-object))))) nil) (defmethod (cell-contents-error :case :proceed-asking-user :package-dwim) (continuation ignore &aux cell new-val) "Look for symbols with the same name but in different packages." (and (symbolp symbol) (setq cell (assq cell-type '((:value boundp symeval) (:function fdefinedp fdefinition)))) (car (setq new-val (sg-funcall *error-sg* 'cell-contents-error-dwimify symbol cell terminal-io))) (funcall continuation :new-value (cadr new-val)))) ;;; CELL is a list (symbolic-name dwimify-definition-type value-extractor) (defun cell-contents-error-dwimify (sym cell *query-io*) (declare (return-list success-p new-value new-symbol)) (let ((dwim-value (dwimify-package-0 sym (second cell)))) (send *query-io* :fresh-line) (and dwim-value (values t (funcall (third cell) dwim-value) dwim-value)))) (defmethod (cell-contents-error :user-proceed-types) (proceed-types) (remq ':new-value proceed-types)) (defmethod (cell-contents-error :case :proceed-asking-user :no-action) (continuation read-object-function) "Proceed, using current contents if legal, or reading replacement value." (if (not (%p-contents-safe-p current-address)) ;; Location still contains garbage, get a replacement value. (send self :proceed-asking-user :new-value continuation read-object-function) (funcall continuation :no-action))) (defmethod (cell-contents-error :case :proceed-asking-user :new-value) (continuation read-object-function) "Use the value of an expression you type." (let ((prompt "Form to evaluate and use instead of cell's contents:~%")) (case cell-type (:value (setq prompt (format nil "Form to evaluate and use instead of ~S's value:~%" symbol))) (:function (setq prompt (format nil "Form to evaluate and use instead of ~S's function definition:~%" symbol)))) (funcall continuation :new-value (funcall read-object-function :eval-read prompt)))) (defmethod (cell-contents-error :case :proceed-asking-user :store-new-value) (continuation read-object-function) "Use the value of an expression you type, and store that value." (let ((value (funcall read-object-function :eval-read (or (case cell-type (:value (format nil "Form to evaluate and SETQ ~S to: " symbol)) (:function (format nil "Form to evaluate and FSET ~S to: " symbol))) "Form to evaluate and store back: ")))) (funcall continuation :store-new-value value))) (defmethod (cell-contents-error :ucode-proceed-types) () (if (memq cell-type '(:value :function)) '(:no-action :new-value :store-new-value :package-dwim) '(:no-action :new-value :store-new-value))) (defmethod (cell-contents-error :case :proceed-ucode-with-args :store-new-value) (sg value) (%p-store-contents current-address value) (sg-regpdl-push value sg) (sg-proceed-micro-pc sg 'trans-trap-restart)) (defmethod (cell-contents-error :case :proceed-ucode-with-args :new-value) (sg value) (sg-regpdl-push value sg) (sg-proceed-micro-pc sg 'trans-trap-restart)) ;;; This has to exist, but it's not intended to ever be used, ;;; so do the same thing as :NO-ACTION if it ever does get used. (defmethod (cell-contents-error :case :proceed-ucode-with-args :package-dwim) (sg) (sg-regpdl-push 0 sg) ;; Transfer the current contents to what MD will be got from. (%blt-typed current-address (sg-locate sg 'pp) 1 0) (sg-proceed-micro-pc sg 'trans-trap-restart)) (defmethod (cell-contents-error :case :proceed-ucode-with-args :no-action) (sg) (sg-regpdl-push 0 sg) ;; Transfer the current contents to what MD will be got from. (%blt-typed current-address (sg-locate sg 'pp) 1 0) (sg-proceed-micro-pc sg 'trans-trap-restart)) ;;;; FUNCTION-ENTRY ;;; Special case. ;;; The ucode kindly leaves the M-ERROR-SUBSTATUS pushed onto the ;;; regular pdl so that we can find it. ;;; The meanings of %%M-ESUBS-BAD-QUOTED-ARG, %%M-ESUBS-BAD-EVALED-ARG ;;; and %%M-ESUBS-BAD-QUOTE-STATUS are not clear, as they are not used ;;; by the microcode. (defflavor function-entry-error-trap () (trap function-entry-error) :abstract-flavor) (defun function-entry-error-trap (sg) (loop with error-code = (aref (sg-regular-pdl sg) (sg-regular-pdl-pointer sg)) for symbol in '(%%m-esubs-too-few-args %%m-esubs-too-many-args %%m-esubs-bad-dt) for flag in '(too-few-arguments-trap too-many-arguments-trap function-entry-error-trap) when (ldb-test (symbol-value symbol) error-code) return flag)) (defun (:property function-entry make-ucode-error-function) (ignore sg ignore) (make-instance (function-entry-error-trap sg) :function (aref (sg-regular-pdl sg) (sg-ap sg)) :argument-list (cdr (get-frame-function-and-args sg (sg-ap sg))) :nargs (rp-number-args-supplied (sg-regular-pdl sg) (sg-ap sg)))) (defmethod (function-entry-error-trap :default :report) (stream) (format stream "Function ~S called with an argument of bad data type." (function-name function))) (defmethod (function-entry-error-trap :ucode-proceed-types) () '(:fewer-arguments :additional-arguments :new-argument-list)) (defflavor too-many-arguments-trap () (too-many-arguments function-entry-error-trap)) (defflavor too-few-arguments-trap () (too-few-arguments function-entry-error-trap)) (defmethod (too-few-arguments-trap :ucode-proceed-types) () '(:additional-arguments :fewer-arguments :new-argument-list)) (defmethod (function-entry-error-trap :case :proceed-ucode-with-args :fewer-arguments) (sg n) (send self :proceed-ucode-with-args :new-argument-list sg (firstn n argument-list))) (defmethod (function-entry-error-trap :case :proceed-ucode-with-args :additional-arguments) (sg args) (send self :proceed-ucode-with-args :new-argument-list sg (append argument-list (copy-list args)))) ;; Copied from LAD: RELEASE-3.DEBUGGER; TRAP.LISP#28 on 2-Oct-86 06:00:49 (defmethod (function-entry-error-trap :case :proceed-ucode-with-args :new-argument-list) (sg arguments &aux (form (cons function arguments))) (let* ((frame (sg-ap sg)) (*error-locus-frame* (sg-ap sg)) (*current-frame* (sg-ap sg)) (*innermost-visible-frame* (sg-ap sg))) ;; If we haven't quit before getting here, he wants to proceed and FORM is set up (sg-unwind-to-frame-and-reinvoke sg frame form) (leaving-error-handler) (without-interrupts (if *error-handler-running* (wipe-current-stack-group-and-resume sg) (stack-group-resume sg nil))))) (defflavor dont-clear-input-ucode-breakpoint () (trap debugging-condition)) (defmethod (dont-clear-input-ucode-breakpoint :maybe-clear-input) (stream) (declare (ignore stream)) ;; Don't clear input nil) (defmethod (dont-clear-input-ucode-breakpoint :print-error-message-prefix) (sg brief stream) (declare (ignore sg brief)) (princ ">> " stream)) (defmethod (dont-clear-input-ucode-breakpoint :ucode-proceed-types) () '(:no-action)) (defmethod (dont-clear-input-ucode-breakpoint :case :proceed-ucode-with-args :no-action) (sg &rest ignore) (sg-proceed-micro-pc sg nil)) (defmethod (dont-clear-input-ucode-breakpoint :case :proceed-asking-user :no-action) (continuation ignore) "Proceed." (format t " Continue from break.~%") (funcall continuation :no-action)) ;>> BOGUS (defsignal trace-breakpoint step-break () "Used by (TRACE (FOO ERROR))") ;>> DEFICIENT (def-ucode-error breakpoint step-break :format-string "Breakpoint") ;>> (defvar *step-break-instance*) (defun (:property step-break make-ucode-error-function) (ignore ignore ignore) (if (variable-boundp *step-break-instance*) *step-break-instance* (setq *step-break-instance* (make-instance 'step-break)))) (defflavor step-break () (dont-clear-input-ucode-breakpoint)) (defmethod (step-break :ucode-proceed-types) () '(:no-action)) ;added 12/4/86 by RG. Enables proceed from :ERROR option in trace. (defmethod (step-break :user-proceed-types) (proceed-types) (if (memq :no-action proceed-types) proceed-types (cons :no-action proceed-types))) (defmethod (step-break :inhibit-backtrace) () t) (defmethod (step-break :inhibit-proceed-prompt) () t) (defmethod (step-break :print-error-message) (sg brief stream) (declare (ignore brief)) (let ((rp (sg-regular-pdl sg))) (format stream ">> Step break at pc ~D in ~S" (rp-exit-pc rp *error-locus-frame*) (rp-function-word rp *error-locus-frame*)))) (def-ucode-error call-trap call-trap :function (rp-function-word (sg-regular-pdl sg) (sg-ipmark sg)) :catch-value (aref (sg-regular-pdl sg) (+ (sg-ipmark sg) 2))) (defflavor call-trap (function catch-value) (dont-clear-input-ucode-breakpoint) :gettable-instance-variables :initable-instance-variables) (defun (:property call-trap enter-error-handler) (sg ignore) (let ((*innermost-visible-frame* (sg-ipmark sg))) ;Make frame being entered visible. ;; Trap on exit from this frame -- unless it is a CATCH. ;; In that case, it is redundant to trap again, ;; and suspected of causing bugs. (unless (eq (rp-function-word (sg-regular-pdl sg) (sg-ipmark sg)) #'*catch) (setf (rp-trap-on-exit (sg-regular-pdl sg) *innermost-visible-frame*) 1) (setf (rp-attention (sg-regular-pdl sg) *innermost-visible-frame*) 1)))) (defmethod (call-trap :around :find-current-frame) (cont mt args sg) (let ((ipmark (fourth (symeval-in-stack-group '*ucode-error-status* sg)))) (multiple-value-bind (nil nil innermost-frame innermost-visible-p) (lexpr-funcall-with-mapping-table cont mt args) (values ipmark ipmark innermost-frame innermost-visible-p)))) (defmethod (call-trap :report) (stream) (if (neq function #'*catch) (format stream "Break on entry to function ~S." (function-name function)) (format stream "Break on call to CATCH (about to do normal exit from CATCH frame); ~ value is ~S." catch-value))) (defmethod (call-trap :inhibit-proceed-prompt) () t) (def-ucode-error exit-trap exit-trap :function (rp-function-word (sg-regular-pdl sg) (sg-ap sg)) :values (sg-frame-value-list sg (sg-ap sg))) (defflavor exit-trap (function values) (dont-clear-input-ucode-breakpoint) :gettable-instance-variables :initable-instance-variables) (defun (:property exit-trap enter-error-handler) (sg ignore) ;; Don't catch this trap again if user tries to return, etc. (setf (rp-trap-on-exit (sg-regular-pdl sg) (sg-ap sg)) 0) (let ((*innermost-visible-frame* (sg-ap sg))) ;; Add our last value onto list of all multiple values returned ;; so the user sees them all in the same place. (sg-return-additional-value sg *innermost-visible-frame* (sg-ac-t sg)))) (defmethod (exit-trap :around :find-current-frame) (cont mt args sg) (let ((ap (third (symeval-in-stack-group '*ucode-error-status* sg)))) (multiple-value-bind (nil nil innermost-frame innermost-visible-p) (lexpr-funcall-with-mapping-table cont mt args) (values ap ap innermost-frame innermost-visible-p)))) (defmethod (exit-trap :report) (stream) (format stream "Break on exit from ~S." (function-name function))) (defmethod (exit-trap :after :print-error-message) (sg brief stream) (declare (ignore sg brief)) (if (null values) (format stream " No values being returned.~%") (format stream " Values being returned are:") (let ((*print-length* error-message-prinlength) (*print-level* error-message-prinlevel)) (dolist (val values) (format stream "~% ~S" val))) (terpri))) (defmethod (exit-trap :inhibit-proceed-prompt) () t) (defmethod (exit-trap :case :proceed-ucode-with-args :no-action) (sg &rest ignore) ;; Un-return the last returned value and put it in M-T to be returned over. ;; This is a no-op if we are not feeding multiple values ;; since the value just comes from M-T in that case. (setf (sg-ac-t sg) (sg-discard-last-value sg (sg-ap sg))) (sg-proceed-micro-pc sg nil)) ;;; THROW-TRAP is used for both exit trap and tag not seen, starting in UCADR 260. ;;; If M-E contains NIL, the tag was not seen. (defun (:property throw-trap make-ucode-error-function) (ignore sg ignore) (cond ((sg-contents sg 'm-e) ;; If tag was found, it must be trap-on-exit. (make-instance 'throw-exit-trap :function (function-name (car (%p-contents-as-locative (locf (sg-ac-d sg))))))) (t ;; Otherwise tag was not found. (make-instance 'throw-tag-not-seen :tag (sg-ac-a sg) :value (sg-ac-t sg) :count (sg-ac-b sg) :action (sg-ac-c sg))))) (defun (:property throw-trap enter-error-handler) (sg ignore) (if (sg-contents sg 'm-e) ;; Do this only for trap-on-exit, not for tag not seen. (let ((cur-frame (- (%pointer-difference (%p-contents-as-locative (locf (sg-ac-d sg))) (sg-regular-pdl sg)) 2))) (setf (rp-trap-on-exit (sg-regular-pdl sg) cur-frame) 0)))) (defflavor throw-exit-trap (function) (dont-clear-input-ucode-breakpoint) :gettable-instance-variables :initable-instance-variables) (defmethod (throw-exit-trap :around :find-current-frame) (cont mt args ignore) (multiple-value-bind (x y z) (around-method-continue cont mt args) (values x y z t))) (defmethod (throw-exit-trap :report) (stream) (format stream "Break on throw through marked call to ~S." function)) ;;; List problems with currently-loaded error table (defun list-problems () (let ((unhandled-traps ()) (missing-restart-tags ()) (argtyp-unknown-types ()) (orphaned-traps ()) (tem)) (dolist (ete error-table) (or (get (setq tem (second ete)) 'make-ucode-error-function) (pushnew tem unhandled-traps :test #'eq)) (if (eq tem 'argtyp) (let ((type (third ete))) (if (symbolp type) (setq type (ncons type))) (when (dolist (type type) (or (type-defined-p type) (assq type *description-type-specs*) (return t))) (pushnew (third ete) argtyp-unknown-types)))) (and (setq tem (assq tem ;Anything that calls SG-PROCEED-MICRO-PC '((argtyp . 5) (subscript-oob . 4)))) (setq tem (nth (cdr tem) ete)) (progn (if (consp tem) (setq tem (cadr tem))) t) (neq tem 'fall-through) (not (assq tem restart-list)) (pushnew tem missing-restart-tags :test #'eq))) (do-symbols (sym 'eh) (and (get sym 'make-ucode-error-function) (not (find sym error-table :key #'second)) (push sym orphaned-traps))) (if (not (null unhandled-traps)) (format t "~&Traps without handler: ~S" unhandled-traps)) (if (not (null orphaned-traps)) (format t "~&Trap handlers defined, but no ucode for: ~S" orphaned-traps)) (if (not (null missing-restart-tags)) (format t "~&Missing RESTART tags: ~S" missing-restart-tags)) (if (not (null argtyp-unknown-types)) (format t "~&ARGTYP types not defined for TYPEP: ~S" argtyp-unknown-types)) (if (or unhandled-traps orphaned-traps missing-restart-tags argtyp-unknown-types) t nil))) (defun type-defined-p (type) (let ((type1 (if (consp type) (car type) type))) (and (symbolp type1) (or (getl type1 '(si::type-predicate si::type-expander si::type-alias-for si::flavor si::defstruct-description #|si::defstruct-named-p|#)) (rassq type si::type-of-alist) (rassq type si::typep-one-arg-alist) #|(and (fboundp 'class-symbolp) (class-symbolp type1))|# )))) (compile-flavor-methods trap random-trap random-dangerous-trap arg-type-error ;fixnum-overflow floating-point-exception floating-exponent-overflow floating-exponent-underflow divide-by-zero bad-array-mixin bad-array-trap array-number-dimensions-error number-array-not-allowed subscript-error array-has-no-leader fill-pointer-not-fixnum invalid-function-trap throw-tag-not-seen select-method-not-found turd-alert-error write-in-read-only pdl-overflow illegal-instruction illegal-expt-trap nubus-error mar-break cell-contents-error unbound-variable undefined-function function-entry-error-trap too-many-arguments-trap too-few-arguments-trap dont-clear-input-ucode-breakpoint step-break call-trap exit-trap throw-exit-trap )