Subject: Re: bug#4287: reducing emacs size by more frequent garbage-collect calls in loadup.el

From: Dan Nicolaescu <[email-masked]>
Date: Mon, 31 Aug 2009 17:57:54 -0700 (PDT)

Stefan Monnier <[email-masked]> writes:

  > >> >> Can you show the patch?
  > >> > Sure:
  > >> Sorry, too ugly to be worth the few bytes (especially since these are
  > >> bytes you'll be using anyway as soon as you start Emacs).
  > > How about another suggested method that is not ugly: a load-and-gc
  > > function?
  > 
  > Could be.  The devil is in the details, so without the patch it's hard
  > to judge.

Here's one.
The function name can be adjusted to be more specific if needed, and the
fmakunbound call is not necessarily needed...

--- loadup.el.~1.180.~	2009-08-20 23:31:53.000000000 -0700
+++ loadup.el	2009-08-31 17:55:33.000000000 -0700
@@ -56,31 +56,35 @@
 (set-buffer "*scratch*")
 (setq buffer-undo-list t)
 
-(load "emacs-lisp/byte-run")
-(load "emacs-lisp/backquote")
-(load "subr")
+(defun load-and-gc (file &optional noerror nomessage nosuffix must-suffix)
+  (load file noerror nomessage nosuffix must-suffix)
+  (garbage-collect))
+
+(load-and-gc "emacs-lisp/byte-run")
+(load-and-gc "emacs-lisp/backquote")
+(load-and-gc "subr")
 
 ;; We specify .el in case someone compiled version.el by mistake.
-(load "version.el")
+(load-and-gc "version.el")
 
-(load "widget")
-(load "custom")
-(load "emacs-lisp/map-ynp")
-(load "cus-start")
-(load "international/mule")
-(load "international/mule-conf.el") ;Don't get confused if someone compiled this by mistake.
-(load "env")
-(load "format")
-(load "bindings")
+(load-and-gc "widget")
+(load-and-gc "custom")
+(load-and-gc "emacs-lisp/map-ynp")
+(load-and-gc "cus-start")
+(load-and-gc "international/mule")
+(load-and-gc "international/mule-conf.el") ;Don't get confused if someone compiled this by mistake.
+(load-and-gc "env")
+(load-and-gc "format")
+(load-and-gc "bindings")
 (setq load-source-file-function 'load-with-code-conversion)
-(load "files")
+(load-and-gc "files")
 
-(load "cus-face")
-(load "faces")  ; after here, `defface' may be used.
-(load "minibuffer")
+(load-and-gc "cus-face")
+(load-and-gc "faces")  ; after here, `defface' may be used.
+(load-and-gc "minibuffer")
 
-(load "button")
-(load "startup")
+(load-and-gc "button")
+(load-and-gc "startup")
 
 (message "Lists of integers (garbage collection statistics) are normal output")
 (message "while building Emacs; they do not indicate a problem.")
@@ -88,139 +92,139 @@
 
 (condition-case nil
     ;; Don't get confused if someone compiled this by mistake.
-    (load "loaddefs.el")
+    (load-and-gc "loaddefs.el")
   ;; In case loaddefs hasn't been generated yet.
-  (file-error (load "ldefs-boot.el")))
+  (file-error (load-and-gc "ldefs-boot.el")))
 
 (message "%s" (garbage-collect))
-(load "abbrev")         ;lisp-mode.el and simple.el use define-abbrev-table.
-(load "simple")
+(load-and-gc "abbrev")         ;lisp-mode.el and simple.el use define-abbrev-table.
+(load-and-gc "simple")
 
-(load "help")
+(load-and-gc "help")
 
-(load "jka-cmpr-hook")
-(load "epa-hook")
+(load-and-gc "jka-cmpr-hook")
+(load-and-gc "epa-hook")
 ;; Any Emacs Lisp source file (*.el) loaded here after can contain
 ;; multilingual text.
-(load "international/mule-cmds")
-(load "case-table")
-(load "international/characters")
-(load "composite")
+(load-and-gc "international/mule-cmds")
+(load-and-gc "case-table")
+(load-and-gc "international/characters")
+(load-and-gc "composite")
 ;; This file doesn't exist when building Emacs from CVS.  It is
 ;; generated just after temacs is build.
-(load "international/charprop.el" t)
+(load-and-gc "international/charprop.el" t)
 
 ;; Load language-specific files.
-(load "language/chinese")
-(load "language/cyrillic")
-(load "language/indian")
-(load "language/sinhala")
-(load "language/english")
-(load "language/ethiopic")
-(load "language/european")
-(load "language/czech")
-(load "language/slovak")
-(load "language/romanian")
-(load "language/greek")
-(load "language/hebrew")
-(load "language/japanese")
-(load "language/korean")
-(load "language/lao")
-(load "language/tai-viet")
-(load "language/thai")
-(load "language/tibetan")
-(load "language/vietnamese")
-(load "language/misc-lang")
-(load "language/utf-8-lang")
-(load "language/georgian")
-(load "language/khmer")
-(load "language/burmese")
-(load "language/cham")
-
-(load "indent")
-(load "window")
-(load "frame")
-(load "term/tty-colors")
-(load "font-core")
+(load-and-gc "language/chinese")
+(load-and-gc "language/cyrillic")
+(load-and-gc "language/indian")
+(load-and-gc "language/sinhala")
+(load-and-gc "language/english")
+(load-and-gc "language/ethiopic")
+(load-and-gc "language/european")
+(load-and-gc "language/czech")
+(load-and-gc "language/slovak")
+(load-and-gc "language/romanian")
+(load-and-gc "language/greek")
+(load-and-gc "language/hebrew")
+(load-and-gc "language/japanese")
+(load-and-gc "language/korean")
+(load-and-gc "language/lao")
+(load-and-gc "language/tai-viet")
+(load-and-gc "language/thai")
+(load-and-gc "language/tibetan")
+(load-and-gc "language/vietnamese")
+(load-and-gc "language/misc-lang")
+(load-and-gc "language/utf-8-lang")
+(load-and-gc "language/georgian")
+(load-and-gc "language/khmer")
+(load-and-gc "language/burmese")
+(load-and-gc "language/cham")
+
+(load-and-gc "indent")
+(load-and-gc "window")
+(load-and-gc "frame")
+(load-and-gc "term/tty-colors")
+(load-and-gc "font-core")
 ;; facemenu must be loaded before font-lock, because `facemenu-keymap'
 ;; needs to be defined when font-lock is loaded.
-(load "facemenu")
-(load "emacs-lisp/syntax")
-(load "font-lock")
-(load "jit-lock")
+(load-and-gc "facemenu")
+(load-and-gc "emacs-lisp/syntax")
+(load-and-gc "font-lock")
+(load-and-gc "jit-lock")
 
 (if (fboundp 'track-mouse)
     (progn
-      (load "mouse")
+      (load-and-gc "mouse")
       (and (boundp 'x-toolkit-scroll-bars)
-	   (load "scroll-bar"))
-      (load "select")))
-(load "emacs-lisp/timer")
-(load "isearch")
-(load "rfn-eshadow")
+	   (load-and-gc "scroll-bar"))
+      (load-and-gc "select")))
+(load-and-gc "emacs-lisp/timer")
+(load-and-gc "isearch")
+(load-and-gc "rfn-eshadow")
 
 (message "%s" (garbage-collect))
-(load "menu-bar")
-(load "paths.el")  ;Don't get confused if someone compiled paths by mistake.
-(load "emacs-lisp/lisp")
-(load "textmodes/page")
-(load "register")
-(load "textmodes/paragraphs")
-(load "emacs-lisp/lisp-mode")
-(load "textmodes/text-mode")
-(load "textmodes/fill")
+(load-and-gc "menu-bar")
+(load-and-gc "paths.el")  ;Don't get confused if someone compiled paths by mistake.
+(load-and-gc "emacs-lisp/lisp")
+(load-and-gc "textmodes/page")
+(load-and-gc "register")
+(load-and-gc "textmodes/paragraphs")
+(load-and-gc "emacs-lisp/lisp-mode")
+(load-and-gc "textmodes/text-mode")
+(load-and-gc "textmodes/fill")
 (message "%s" (garbage-collect))
 
-(load "replace")
-(load "buff-menu")
+(load-and-gc "replace")
+(load-and-gc "buff-menu")
 
 (if (fboundp 'x-create-frame)
     (progn
-      (load "fringe")
-      (load "image")
-      (load "international/fontset")
-      (load "dnd")
-      (load "mwheel")
-      (load "tool-bar")))
+      (load-and-gc "fringe")
+      (load-and-gc "image")
+      (load-and-gc "international/fontset")
+      (load-and-gc "dnd")
+      (load-and-gc "mwheel")
+      (load-and-gc "tool-bar")))
 (if (featurep 'x)
     (progn
-      (load "x-dnd")
-      (load "term/common-win")
-      (load "term/x-win")))
+      (load-and-gc "x-dnd")
+      (load-and-gc "term/common-win")
+      (load-and-gc "term/x-win")))
 
 (message "%s" (garbage-collect))
 
 (if (eq system-type 'windows-nt)
     (progn
-      (load "w32-vars")
-      (load "term/common-win")
-      (load "term/w32-win")
-      (load "ls-lisp")
-      (load "disp-table")
-      (load "dos-w32")
-      (load "w32-fns")))
+      (load-and-gc "w32-vars")
+      (load-and-gc "term/common-win")
+      (load-and-gc "term/w32-win")
+      (load-and-gc "ls-lisp")
+      (load-and-gc "disp-table")
+      (load-and-gc "dos-w32")
+      (load-and-gc "w32-fns")))
 (if (eq system-type 'ms-dos)
     (progn
-      (load "dos-w32")
-      (load "dos-fns")
-      (load "dos-vars")
+      (load-and-gc "dos-w32")
+      (load-and-gc "dos-fns")
+      (load-and-gc "dos-vars")
       ;; Don't load term/common-win: it isn't appropriate for the `pc'
       ;; ``window system'', which generally behaves like a terminal.
-      (load "term/pc-win")
-      (load "ls-lisp")
-      (load "disp-table"))) ; needed to setup ibm-pc char set, see internal.el
+      (load-and-gc "term/pc-win")
+      (load-and-gc "ls-lisp")
+      (load-and-gc "disp-table"))) ; needed to setup ibm-pc char set, see internal.el
 (if (featurep 'ns)
     (progn
-      (load "emacs-lisp/easymenu")  ;; for platform-related menu adjustments
-      (load "term/ns-win")))
+      (load-and-gc "emacs-lisp/easymenu")  ;; for platform-related menu adjustments
+      (load-and-gc "term/ns-win")))
 (if (fboundp 'atan)	; preload some constants and
     (progn		; floating pt. functions if we have float support.
-      (load "emacs-lisp/float-sup")))
+      (load-and-gc "emacs-lisp/float-sup")))
 (message "%s" (garbage-collect))
 
-(load "vc-hooks")
-(load "ediff-hook")
-(if (fboundp 'x-show-tip) (load "tooltip"))
+(load-and-gc "vc-hooks")
+(load-and-gc "ediff-hook")
+(if (fboundp 'x-show-tip) (load-and-gc "tooltip"))
 
 (message "%s" (garbage-collect))
 
@@ -283,9 +287,12 @@
 ;;;Note: You can cause additional libraries to be preloaded
 ;;;by writing a site-init.el that loads them.
 ;;;See also "site-load" above.
-(load "site-init" t)
+(load-and-gc "site-init" t)
 (setq current-load-list nil)
 
+;; Unbound the function, we don't need it elsewhere.
+(fmakunbound 'load-and-gc)
+
 ;; Write the value of load-history into fns-VERSION.el,
 ;; then clear out load-history.
 ;; (if (or (equal (nth 3 command-line-args) "dump")