1 ;;; find-gc.el --- detect functions that call the garbage collector
3 ;; Copyright (C) 1992 Free Software Foundation, Inc.
8 ;; This file is part of XEmacs.
10 ;; XEmacs is free software; you can redistribute it and/or modify it
11 ;; under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; XEmacs is distributed in the hope that it will be useful, but
16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ;; General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with XEmacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
25 ;;; Synched up with: FSF 19.30.
27 ;;; #### before this is really usable, it should be rewritten to call
28 ;;; Makefile to compile the files.
32 ;;; Produce in unsafe-list the set of all functions that may invoke GC.
33 ;;; This expects the Emacs sources to live in emacs-source-directory.
34 ;;; It creates a temporary working directory /tmp/esrc.
38 (defvar unsafe-list nil)
39 (defvar subrs-used nil)
40 (defvar subrs-called nil)
42 ;; Set this to point to your XEmacs source directory.
43 (defvar emacs-source-directory "/usr/src/xemacs/xemacs-20/src")
45 ;;; Functions on this list are safe, even if they appear to be able
46 ;;; to call the target.
48 (defvar noreturn-list '(signal_error error Fthrow wrong_type_argument))
50 ;;; Try to load generated source-files
51 (load-library (concat emacs-source-directory "/../lisp/source-files.el"))
53 (defvar source-files nil
54 "Set this to the source files you want to check.")
58 (defun find-gc-unsafe ()
60 (trace-call-tree t nil)
62 (set-buffer (get-buffer-create "*gc-tmp*"))
64 (find-unsafe-funcs 'Fgarbage_collect)
65 (setq unsafe-list (sort unsafe-list 'find-gc-sort-p))
66 (insert (format "%s\n" unsafe-list))
67 (setq unsafe-list nil)
68 (find-unsafe-funcs 'garbage_collect_1)
69 (setq unsafe-list (sort unsafe-list 'find-gc-sort-p))
70 (insert (format "%s\n" unsafe-list))
71 (goto-char (point-min))
72 (while (search-forward ") (" nil t)
77 (defun find-gc-sort-p (x y)
78 (string-lessp (car x) (car y)))
80 ;;; This does a depth-first search to find all functions that can
81 ;;; ultimately call the function "target". The result is an a-list
82 ;;; in unsafe-list; the cars are the unsafe functions, and the cdrs
83 ;;; are (one of) the unsafe functions that these functions directly
86 (defun find-unsafe-funcs (target)
87 (setq unsafe-list (list (list target)))
88 (trace-unsafe target))
90 (defun trace-unsafe (func)
91 (let ((used (assq func subrs-used)))
93 (error "No subrs-used for %s" (car unsafe-list)))
94 (while (setq used (cdr used))
95 (or (assq (car used) unsafe-list)
96 (memq (car used) noreturn-list)
98 (setq unsafe-list (cons (cons (car used) func) unsafe-list))
99 (trace-unsafe (car used)))))))
102 ;;; This produces an a-list of functions in subrs-called. The cdr of
103 ;;; each entry is a list of functions which the function in car calls.
105 (defun trace-call-tree (&optional make-all delete-after)
107 (setq subrs-called nil)
108 (let ((case-fold-search nil)
110 ;; Stage one, make rtl files with make
113 "sh" nil nil nil "-c"
114 (format "cd %s; make dortl" emacs-source-directory file))
115 (dolist (file source-files)
116 (princ (format "Compiling %s...\n" file))
118 "sh" nil nil nil "-c"
119 (format "cd %s; make %s.rtl" emacs-source-directory file))))
120 (set-buffer (get-buffer-create "*Trace Call Tree*"))
121 ;; Stage two, process them
122 (dolist (file source-files)
124 (insert-file-contents (concat emacs-source-directory "/" file ".rtl"))
125 (while (re-search-forward ";; Function \\|(call_insn " nil t)
126 (if (= (char-after (- (point) 3)) ?o)
128 (looking-at "[a-zA-Z0-9_]+")
129 (setq name (intern (buffer-substring (match-beginning 0)
131 (princ (format "%s : %s\n" file name))
132 (setq entry (list name)
133 subrs-called (cons entry subrs-called)))
134 (if (looking-at ".*\n?.*\"\\([A-Za-z0-9_]+\\)\"")
136 (setq name (intern (buffer-substring (match-beginning 1)
138 (or (memq name (cdr entry))
139 (setcdr entry (cons name (cdr entry)))))))))
141 (dolist (file source-files)
142 (delete-file (concat emacs-source-directory "/" file ".rtl"))))
146 ;;; This produces an inverted a-list in subrs-used. The cdr of each
147 ;;; entry is a list of functions that call the function in car.
149 (defun trace-use-tree ()
150 (setq subrs-used (mapcar 'list (mapcar 'car subrs-called)))
151 (let ((ptr subrs-called)
155 (while (setq p2 (cdr p2))
156 (if (setq found (assq (car p2) subrs-used))
157 (setcdr found (cons (car (car ptr)) (cdr found)))))
158 (setq ptr (cdr ptr)))))
160 ;;; find-gc.el ends here