Initial Commit
[packages] / xemacs-packages / xemacs-devel / find-gc.el
1 ;;; find-gc.el --- detect functions that call the garbage collector
2
3 ;; Copyright (C) 1992 Free Software Foundation, Inc.
4
5 ;; Maintainer: FSF
6 ;; Keywords: maint
7
8 ;; This file is part of XEmacs.
9
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)
13 ;; any later version.
14
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.
19
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.
24
25 ;;; Synched up with: FSF 19.30.
26
27 ;;; #### before this is really usable, it should be rewritten to call
28 ;;; Makefile to compile the files.
29
30 ;;; Commentary:
31
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.
35
36 ;;; Code:
37
38 (defvar unsafe-list nil)
39 (defvar subrs-used nil)
40 (defvar subrs-called nil)
41
42 ;; Set this to point to your XEmacs source directory.
43 (defvar emacs-source-directory "/usr/src/xemacs/xemacs-20/src")
44
45 ;;; Functions on this list are safe, even if they appear to be able
46 ;;; to call the target.
47
48 (defvar noreturn-list '(signal_error error Fthrow wrong_type_argument))
49
50 ;;; Try to load generated source-files
51 (load-library (concat emacs-source-directory "/../lisp/source-files.el"))
52
53 (defvar source-files nil
54   "Set this to the source files you want to check.")
55
56 ;;;
57
58 (defun find-gc-unsafe ()
59   (setq subrs-used nil)
60   (trace-call-tree t nil)
61   (trace-use-tree)
62   (set-buffer (get-buffer-create "*gc-tmp*"))
63   (erase-buffer)
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)
73     (replace-match ")
74  (" nil t))
75   )
76
77 (defun find-gc-sort-p (x y)
78   (string-lessp (car x) (car y)))
79
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
84 ;;; call.
85
86 (defun find-unsafe-funcs (target)
87   (setq unsafe-list (list (list target)))
88   (trace-unsafe target))
89
90 (defun trace-unsafe (func)
91   (let ((used (assq func subrs-used)))
92     (or 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)
97           (progn
98             (setq unsafe-list (cons (cons (car used) func) unsafe-list))
99             (trace-unsafe (car used)))))))
100
101
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.
104
105 (defun trace-call-tree (&optional make-all delete-after)
106   (save-excursion
107     (setq subrs-called nil)
108     (let ((case-fold-search nil)
109           name entry file)
110       ;; Stage one, make rtl files with make
111       (if make-all
112           (call-process 
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))
117           (call-process 
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)
123         (erase-buffer)
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)
127               (progn
128                 (looking-at "[a-zA-Z0-9_]+")
129                 (setq name (intern (buffer-substring (match-beginning 0)
130                                                      (match-end 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_]+\\)\"")
135                 (progn
136                   (setq name (intern (buffer-substring (match-beginning 1)
137                                                        (match-end 1))))
138                   (or (memq name (cdr entry))
139                       (setcdr entry (cons name (cdr entry)))))))))
140       (when delete-after
141         (dolist (file source-files)
142           (delete-file (concat emacs-source-directory "/" file ".rtl"))))
143             )))
144
145
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.
148
149 (defun trace-use-tree ()
150   (setq subrs-used (mapcar 'list (mapcar 'car subrs-called)))
151   (let ((ptr subrs-called)
152         p2 found)
153     (while ptr
154       (setq p2 (car ptr))
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)))))
159
160 ;;; find-gc.el ends here