aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2011-03-05 23:48:17 -0500
committerStefan Monnier2011-03-05 23:48:17 -0500
commite2abe5a13dffb08d6371b6a611bc39c3a9ac2bc6 (patch)
treeb9fb87041279f75ba8b6b304e0765bf412377af6
parentd032d5e7dfabfae60f3304da02c97cd1e189b9a2 (diff)
downloademacs-e2abe5a13dffb08d6371b6a611bc39c3a9ac2bc6.tar.gz
emacs-e2abe5a13dffb08d6371b6a611bc39c3a9ac2bc6.zip
Fix pcase memoizing; change lexbound byte-code marker.
* src/bytecode.c (exec_byte_code): Remove old lexical binding slot handling and replace it with the a integer args-desc handling. * eval.c (funcall_lambda): Adjust arglist test accordingly. * lisp/emacs-lisp/bytecomp.el (byte-compile-arglist-signature): Handle integer arglist descriptor. (byte-compile-make-args-desc): Make integer arglist descriptor. (byte-compile-lambda): Use integer arglist descriptor to mark lexical byte-coded functions instead of an extra slot. * lisp/help-fns.el (help-add-fundoc-usage): Don't add a dummy doc. (help-split-fundoc): Return a nil doc if there was no actual doc. (help-function-arglist): Generate an arglist from an integer arg-desc. * lisp/emacs-lisp/pcase.el (pcase--memoize): Rename from pcase-memoize; Make only the key weak. (pcase): Change the key used in the memoization table, so it does not always get GC'd away. * lisp/emacs-lisp/macroexp.el (macroexpand-all-1): Slight change to the pcase pattern to generate slightly better code.
-rw-r--r--lisp/ChangeLog17
-rw-r--r--lisp/emacs-lisp/byte-opt.el3
-rw-r--r--lisp/emacs-lisp/bytecomp.el87
-rw-r--r--lisp/emacs-lisp/cconv.el11
-rw-r--r--lisp/emacs-lisp/macroexp.el9
-rw-r--r--lisp/emacs-lisp/pcase.el23
-rw-r--r--lisp/help-fns.el26
-rw-r--r--src/ChangeLog6
-rw-r--r--src/alloc.c13
-rw-r--r--src/bytecode.c71
10 files changed, 188 insertions, 78 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 10f57c2b96a..70604238117 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,20 @@
12011-03-06 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * emacs-lisp/bytecomp.el (byte-compile-arglist-signature):
4 Handle integer arglist descriptor.
5 (byte-compile-make-args-desc): Make integer arglist descriptor.
6 (byte-compile-lambda): Use integer arglist descriptor to mark lexical
7 byte-coded functions instead of an extra slot.
8 * help-fns.el (help-add-fundoc-usage): Don't add a dummy doc.
9 (help-split-fundoc): Return a nil doc if there was no actual doc.
10 (help-function-arglist): Generate an arglist from an integer arg-desc.
11 * emacs-lisp/pcase.el (pcase--memoize): Rename from pcase-memoize;
12 Make only the key weak.
13 (pcase): Change the key used in the memoization table, so it does not
14 always get GC'd away.
15 * emacs-lisp/macroexp.el (macroexpand-all-1): Slight change to the
16 pcase pattern to generate slightly better code.
17
12011-03-01 Stefan Monnier <monnier@iro.umontreal.ca> 182011-03-01 Stefan Monnier <monnier@iro.umontreal.ca>
2 19
3 * emacs-lisp/cconv.el (cconv-liftwhen): Increase threshold. 20 * emacs-lisp/cconv.el (cconv-liftwhen): Increase threshold.
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index d86cb729081..6d6eb68535e 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -2009,8 +2009,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
2009 (setq lap0 (car rest) 2009 (setq lap0 (car rest)
2010 lap1 (nth 1 rest)) 2010 lap1 (nth 1 rest))
2011 (if (memq (car lap0) byte-constref-ops) 2011 (if (memq (car lap0) byte-constref-ops)
2012 (if (or (eq (car lap0) 'byte-constant) 2012 (if (memq (car lap0) '(byte-constant byte-constant2))
2013 (eq (car lap0) 'byte-constant2))
2014 (unless (memq (cdr lap0) byte-compile-constants) 2013 (unless (memq (cdr lap0) byte-compile-constants)
2015 (setq byte-compile-constants (cons (cdr lap0) 2014 (setq byte-compile-constants (cons (cdr lap0)
2016 byte-compile-constants))) 2015 byte-compile-constants)))
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 3575b10e1f1..297655a235a 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -33,6 +33,9 @@
33 33
34;;; Code: 34;;; Code:
35 35
36;; FIXME: Use lexical-binding and get rid of the atrocious "bytecomp-"
37;; variable prefix.
38
36;; ======================================================================== 39;; ========================================================================
37;; Entry points: 40;; Entry points:
38;; byte-recompile-directory, byte-compile-file, 41;; byte-recompile-directory, byte-compile-file,
@@ -1180,22 +1183,28 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'."
1180 (t fn))))))) 1183 (t fn)))))))
1181 1184
1182(defun byte-compile-arglist-signature (arglist) 1185(defun byte-compile-arglist-signature (arglist)
1183 (let ((args 0) 1186 (if (integerp arglist)
1184 opts 1187 ;; New style byte-code arglist.
1185 restp) 1188 (cons (logand arglist 127) ;Mandatory.
1186 (while arglist 1189 (if (zerop (logand arglist 128)) ;No &rest.
1187 (cond ((eq (car arglist) '&optional) 1190 (lsh arglist -8))) ;Nonrest.
1188 (or opts (setq opts 0))) 1191 ;; Old style byte-code, or interpreted function.
1189 ((eq (car arglist) '&rest) 1192 (let ((args 0)
1190 (if (cdr arglist) 1193 opts
1191 (setq restp t 1194 restp)
1192 arglist nil))) 1195 (while arglist
1193 (t 1196 (cond ((eq (car arglist) '&optional)
1194 (if opts 1197 (or opts (setq opts 0)))
1195 (setq opts (1+ opts)) 1198 ((eq (car arglist) '&rest)
1199 (if (cdr arglist)
1200 (setq restp t
1201 arglist nil)))
1202 (t
1203 (if opts
1204 (setq opts (1+ opts))
1196 (setq args (1+ args))))) 1205 (setq args (1+ args)))))
1197 (setq arglist (cdr arglist))) 1206 (setq arglist (cdr arglist)))
1198 (cons args (if restp nil (if opts (+ args opts) args))))) 1207 (cons args (if restp nil (if opts (+ args opts) args))))))
1199 1208
1200 1209
1201(defun byte-compile-arglist-signatures-congruent-p (old new) 1210(defun byte-compile-arglist-signatures-congruent-p (old new)
@@ -2645,6 +2654,26 @@ If FORM is a lambda or a macro, byte-compile it as a function."
2645 ;; Return the new lexical environment 2654 ;; Return the new lexical environment
2646 lexenv)))) 2655 lexenv))))
2647 2656
2657(defun byte-compile-make-args-desc (arglist)
2658 (let ((mandatory 0)
2659 nonrest (rest 0))
2660 (while (and arglist (not (memq (car arglist) '(&optional &rest))))
2661 (setq mandatory (1+ mandatory))
2662 (setq arglist (cdr arglist)))
2663 (setq nonrest mandatory)
2664 (when (eq (car arglist) '&optional)
2665 (setq arglist (cdr arglist))
2666 (while (and arglist (not (eq (car arglist) '&rest)))
2667 (setq nonrest (1+ nonrest))
2668 (setq arglist (cdr arglist))))
2669 (when arglist
2670 (setq rest 1))
2671 (if (> mandatory 127)
2672 (byte-compile-report-error "Too many (>127) mandatory arguments")
2673 (logior mandatory
2674 (lsh nonrest 8)
2675 (lsh rest 7)))))
2676
2648;; Byte-compile a lambda-expression and return a valid function. 2677;; Byte-compile a lambda-expression and return a valid function.
2649;; The value is usually a compiled function but may be the original 2678;; The value is usually a compiled function but may be the original
2650;; lambda-expression. 2679;; lambda-expression.
@@ -2716,18 +2745,22 @@ If FORM is a lambda or a macro, byte-compile it as a function."
2716 ;; Build the actual byte-coded function. 2745 ;; Build the actual byte-coded function.
2717 (if (eq 'byte-code (car-safe compiled)) 2746 (if (eq 'byte-code (car-safe compiled))
2718 (apply 'make-byte-code 2747 (apply 'make-byte-code
2719 (append (list bytecomp-arglist) 2748 (if lexical-binding
2720 ;; byte-string, constants-vector, stack depth 2749 (byte-compile-make-args-desc bytecomp-arglist)
2721 (cdr compiled) 2750 bytecomp-arglist)
2722 ;; optionally, the doc string. 2751 (append
2723 (if (or bytecomp-doc bytecomp-int 2752 ;; byte-string, constants-vector, stack depth
2724 lexical-binding) 2753 (cdr compiled)
2725 (list bytecomp-doc)) 2754 ;; optionally, the doc string.
2726 ;; optionally, the interactive spec. 2755 (cond (lexical-binding
2727 (if (or bytecomp-int lexical-binding) 2756 (require 'help-fns)
2728 (list (nth 1 bytecomp-int))) 2757 (list (help-add-fundoc-usage
2729 (if lexical-binding 2758 bytecomp-doc bytecomp-arglist)))
2730 '(t)))) 2759 ((or bytecomp-doc bytecomp-int)
2760 (list bytecomp-doc)))
2761 ;; optionally, the interactive spec.
2762 (if bytecomp-int
2763 (list (nth 1 bytecomp-int)))))
2731 (setq compiled 2764 (setq compiled
2732 (nconc (if bytecomp-int (list bytecomp-int)) 2765 (nconc (if bytecomp-int (list bytecomp-int))
2733 (cond ((eq (car-safe compiled) 'progn) (cdr compiled)) 2766 (cond ((eq (car-safe compiled) 'progn) (cdr compiled))
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index 7855193fa3f..5501c13ee4f 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -66,22 +66,21 @@
66;;; Code: 66;;; Code:
67 67
68;; TODO: 68;; TODO:
69;; - byte-optimize-form should be applied before cconv.
70;; - maybe unify byte-optimize and compiler-macros.
69;; - canonize code in macro-expand so we don't have to handle (let (var) body) 71;; - canonize code in macro-expand so we don't have to handle (let (var) body)
70;; and other oddities. 72;; and other oddities.
71;; - Change new byte-code representation, so it directly gives the
72;; number of mandatory and optional arguments as well as whether or
73;; not there's a &rest arg.
74;; - clean up cconv-closure-convert-rec, especially the `let' binding part. 73;; - clean up cconv-closure-convert-rec, especially the `let' binding part.
75;; - new byte codes for unwind-protect, catch, and condition-case so that 74;; - new byte codes for unwind-protect, catch, and condition-case so that
76;; closures aren't needed at all. 75;; closures aren't needed at all.
77;; - a reference to a var that is known statically to always hold a constant 76;; - a reference to a var that is known statically to always hold a constant
78;; should be turned into a byte-constant rather than a byte-stack-ref. 77;; should be turned into a byte-constant rather than a byte-stack-ref.
79;; Hmm... right, that's called constant propagation and could be done here 78;; Hmm... right, that's called constant propagation and could be done here,
80;; But when that constant is a function, we have to be careful to make sure 79;; but when that constant is a function, we have to be careful to make sure
81;; the bytecomp only compiles it once. 80;; the bytecomp only compiles it once.
82;; - Since we know here when a variable is not mutated, we could pass that 81;; - Since we know here when a variable is not mutated, we could pass that
83;; info to the byte-compiler, e.g. by using a new `immutable-let'. 82;; info to the byte-compiler, e.g. by using a new `immutable-let'.
84;; - add tail-calls to bytecode.c and the bytecompiler. 83;; - add tail-calls to bytecode.c and the byte compiler.
85 84
86;; (defmacro dlet (binders &rest body) 85;; (defmacro dlet (binders &rest body)
87;; ;; Works in both lexical and non-lexical mode. 86;; ;; Works in both lexical and non-lexical mode.
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index 4377797cba8..168a430577d 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -176,10 +176,11 @@ Assumes the caller has bound `macroexpand-all-environment'."
176 (macroexpand-all-forms args))))) 176 (macroexpand-all-forms args)))))
177 ;; Macro expand compiler macros. 177 ;; Macro expand compiler macros.
178 ;; FIXME: Don't depend on CL. 178 ;; FIXME: Don't depend on CL.
179 (`(,(and (pred symbolp) fun 179 (`(,(pred (lambda (fun)
180 (guard (and (eq (get fun 'byte-compile) 180 (and (symbolp fun)
181 'cl-byte-compile-compiler-macro) 181 (eq (get fun 'byte-compile)
182 (functionp 'compiler-macroexpand)))) 182 'cl-byte-compile-compiler-macro)
183 (functionp 'compiler-macroexpand))))
183 . ,_) 184 . ,_)
184 (let ((newform (compiler-macroexpand form))) 185 (let ((newform (compiler-macroexpand form)))
185 (if (eq form newform) 186 (if (eq form newform)
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 89bbff980c4..2300ebf721a 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -42,7 +42,7 @@
42;; is in a loop, the repeated macro-expansion becomes terribly costly, so we 42;; is in a loop, the repeated macro-expansion becomes terribly costly, so we
43;; memoize previous macro expansions to try and avoid recomputing them 43;; memoize previous macro expansions to try and avoid recomputing them
44;; over and over again. 44;; over and over again.
45(defconst pcase-memoize (make-hash-table :weakness t :test 'equal)) 45(defconst pcase--memoize (make-hash-table :weakness 'key :test 'eq))
46 46
47(defconst pcase--dontcare-upats '(t _ dontcare)) 47(defconst pcase--dontcare-upats '(t _ dontcare))
48 48
@@ -78,10 +78,21 @@ E.g. you can match pairs where the cdr is larger than the car with a pattern
78like `(,a . ,(pred (< a))) or, with more checks: 78like `(,a . ,(pred (< a))) or, with more checks:
79`(,(and a (pred numberp)) . ,(and (pred numberp) (pred (< a))))" 79`(,(and a (pred numberp)) . ,(and (pred numberp) (pred (< a))))"
80 (declare (indent 1) (debug case)) ;FIXME: edebug `guard' and vars. 80 (declare (indent 1) (debug case)) ;FIXME: edebug `guard' and vars.
81 (or (gethash (cons exp cases) pcase-memoize) 81 ;; We want to use a weak hash table as a cache, but the key will unavoidably
82 (puthash (cons exp cases) 82 ;; be based on `exp' and `cases', yet `cases' is a fresh new list each time
83 (pcase--expand exp cases) 83 ;; we're called so it'll be immediately GC'd. So we use (car cases) as key
84 pcase-memoize))) 84 ;; which does come straight from the source code and should hence not be GC'd
85 ;; so easily.
86 (let ((data (gethash (car cases) pcase--memoize)))
87 ;; data = (EXP CASES . EXPANSION)
88 (if (and (equal exp (car data)) (equal cases (cadr data)))
89 ;; We have the right expansion.
90 (cddr data)
91 (when data
92 (message "pcase-memoize: equal first branch, yet different"))
93 (let ((expansion (pcase--expand exp cases)))
94 (puthash (car cases) (cons exp (cons cases expansion)) pcase--memoize)
95 expansion))))
85 96
86;;;###autoload 97;;;###autoload
87(defmacro pcase-let* (bindings &rest body) 98(defmacro pcase-let* (bindings &rest body)
@@ -135,6 +146,8 @@ of the form (UPAT EXP)."
135 (and (symbolp upat) (not (memq upat pcase--dontcare-upats)))) 146 (and (symbolp upat) (not (memq upat pcase--dontcare-upats))))
136 147
137(defun pcase--expand (exp cases) 148(defun pcase--expand (exp cases)
149 ;; (message "pid=%S (pcase--expand %S ...hash=%S)"
150 ;; (emacs-pid) exp (sxhash cases))
138 (let* ((defs (if (symbolp exp) '() 151 (let* ((defs (if (symbolp exp) '()
139 (let ((sym (make-symbol "x"))) 152 (let ((sym (make-symbol "x")))
140 (prog1 `((,sym ,exp)) (setq exp sym))))) 153 (prog1 `((,sym ,exp)) (setq exp sym)))))
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 87fb6a02bd3..58df45bc33c 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -76,15 +76,18 @@ DEF is the function whose usage we're looking for in DOCSTRING."
76 ;; Replace `fn' with the actual function name. 76 ;; Replace `fn' with the actual function name.
77 (if (consp def) "anonymous" def) 77 (if (consp def) "anonymous" def)
78 (match-string 1 docstring)) 78 (match-string 1 docstring))
79 (substring docstring 0 (match-beginning 0))))) 79 (unless (zerop (match-beginning 0))
80 (substring docstring 0 (match-beginning 0))))))
80 81
82;; FIXME: Move to subr.el?
81(defun help-add-fundoc-usage (docstring arglist) 83(defun help-add-fundoc-usage (docstring arglist)
82 "Add the usage info to DOCSTRING. 84 "Add the usage info to DOCSTRING.
83If DOCSTRING already has a usage info, then just return it unchanged. 85If DOCSTRING already has a usage info, then just return it unchanged.
84The usage info is built from ARGLIST. DOCSTRING can be nil. 86The usage info is built from ARGLIST. DOCSTRING can be nil.
85ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"." 87ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"."
86 (unless (stringp docstring) (setq docstring "Not documented")) 88 (unless (stringp docstring) (setq docstring ""))
87 (if (or (string-match "\n\n(fn\\(\\( .*\\)?)\\)\\'" docstring) (eq arglist t)) 89 (if (or (string-match "\n\n(fn\\(\\( .*\\)?)\\)\\'" docstring)
90 (eq arglist t))
88 docstring 91 docstring
89 (concat docstring 92 (concat docstring
90 (if (string-match "\n?\n\\'" docstring) 93 (if (string-match "\n?\n\\'" docstring)
@@ -95,6 +98,7 @@ ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"."
95 (concat "(fn" (match-string 1 arglist) ")") 98 (concat "(fn" (match-string 1 arglist) ")")
96 (format "%S" (help-make-usage 'fn arglist)))))) 99 (format "%S" (help-make-usage 'fn arglist))))))
97 100
101;; FIXME: Move to subr.el?
98(defun help-function-arglist (def) 102(defun help-function-arglist (def)
99 ;; Handle symbols aliased to other symbols. 103 ;; Handle symbols aliased to other symbols.
100 (if (and (symbolp def) (fboundp def)) (setq def (indirect-function def))) 104 (if (and (symbolp def) (fboundp def)) (setq def (indirect-function def)))
@@ -103,12 +107,28 @@ ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"."
103 ;; and do the same for interpreted closures 107 ;; and do the same for interpreted closures
104 (if (eq (car-safe def) 'closure) (setq def (cddr def))) 108 (if (eq (car-safe def) 'closure) (setq def (cddr def)))
105 (cond 109 (cond
110 ((and (byte-code-function-p def) (integerp (aref def 0)))
111 (let* ((args-desc (aref def 0))
112 (max (lsh args-desc -8))
113 (min (logand args-desc 127))
114 (rest (logand args-desc 128))
115 (arglist ()))
116 (dotimes (i min)
117 (push (intern (concat "arg" (number-to-string (1+ i)))) arglist))
118 (when (> max min)
119 (push '&optional arglist)
120 (dotimes (i (- max min))
121 (push (intern (concat "arg" (number-to-string (+ 1 i min))))
122 arglist)))
123 (unless (zerop rest) (push '&rest arglist) (push 'rest arglist))
124 (nreverse arglist)))
106 ((byte-code-function-p def) (aref def 0)) 125 ((byte-code-function-p def) (aref def 0))
107 ((eq (car-safe def) 'lambda) (nth 1 def)) 126 ((eq (car-safe def) 'lambda) (nth 1 def))
108 ((and (eq (car-safe def) 'autoload) (not (eq (nth 4 def) 'keymap))) 127 ((and (eq (car-safe def) 'autoload) (not (eq (nth 4 def) 'keymap)))
109 "[Arg list not available until function definition is loaded.]") 128 "[Arg list not available until function definition is loaded.]")
110 (t t))) 129 (t t)))
111 130
131;; FIXME: Move to subr.el?
112(defun help-make-usage (function arglist) 132(defun help-make-usage (function arglist)
113 (cons (if (symbolp function) function 'anonymous) 133 (cons (if (symbolp function) function 'anonymous)
114 (mapcar (lambda (arg) 134 (mapcar (lambda (arg)
diff --git a/src/ChangeLog b/src/ChangeLog
index c638e1fa4b5..e8b3c57fbd0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
12011-03-06 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * bytecode.c (exec_byte_code): Remove old lexical binding slot handling
4 and replace it with the a integer args-desc handling.
5 * eval.c (funcall_lambda): Adjust arglist test accordingly.
6
12011-03-01 Stefan Monnier <monnier@iro.umontreal.ca> 72011-03-01 Stefan Monnier <monnier@iro.umontreal.ca>
2 8
3 * callint.c (quotify_arg): Simplify the logic. 9 * callint.c (quotify_arg): Simplify the logic.
diff --git a/src/alloc.c b/src/alloc.c
index 0b7db7ec627..c7fd8747f74 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2945,10 +2945,19 @@ usage: (vector &rest OBJECTS) */)
2945 2945
2946DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0, 2946DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0,
2947 doc: /* Create a byte-code object with specified arguments as elements. 2947 doc: /* Create a byte-code object with specified arguments as elements.
2948The arguments should be the arglist, bytecode-string, constant vector, 2948The arguments should be the ARGLIST, bytecode-string BYTE-CODE, constant
2949stack size, (optional) doc string, and (optional) interactive spec. 2949vector CONSTANTS, maximum stack size DEPTH, (optional) DOCSTRING,
2950and (optional) INTERACTIVE-SPEC.
2950The first four arguments are required; at most six have any 2951The first four arguments are required; at most six have any
2951significance. 2952significance.
2953The ARGLIST can be either like the one of `lambda', in which case the arguments
2954will be dynamically bound before executing the byte code, or it can be an
2955integer of the form NNNNNNNRMMMMMMM where the 7bit MMMMMMM specifies the
2956minimum number of arguments, the 7-bit NNNNNNN specifies the maximum number
2957of arguments (ignoring &rest) and the R bit specifies whether there is a &rest
2958argument to catch the left-over arguments. If such an integer is used, the
2959arguments will not be dynamically bound but will be instead pushed on the
2960stack before executing the byte-code.
2952usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS) */) 2961usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS) */)
2953 (register int nargs, Lisp_Object *args) 2962 (register int nargs, Lisp_Object *args)
2954{ 2963{
diff --git a/src/bytecode.c b/src/bytecode.c
index 9693a5a9196..dbab02886e2 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -502,37 +502,50 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
502 stacke = stack.bottom - 1 + XFASTINT (maxdepth); 502 stacke = stack.bottom - 1 + XFASTINT (maxdepth);
503#endif 503#endif
504 504
505 if (! NILP (args_template)) 505 if (INTEGERP (args_template))
506 /* We should push some arguments on the stack. */
507 { 506 {
508 Lisp_Object at; 507 int at = XINT (args_template);
509 int pushed = 0, optional = 0; 508 int rest = at & 128;
510 509 int mandatory = at & 127;
511 for (at = args_template; CONSP (at); at = XCDR (at)) 510 int nonrest = at >> 8;
512 if (EQ (XCAR (at), Qand_optional)) 511 eassert (mandatory <= nonrest);
513 optional = 1; 512 if (nargs <= nonrest)
514 else if (EQ (XCAR (at), Qand_rest)) 513 {
515 { 514 int i;
516 PUSH (pushed < nargs 515 for (i = 0 ; i < nargs; i++, args++)
517 ? Flist (nargs - pushed, args) 516 PUSH (*args);
518 : Qnil); 517 if (nargs < mandatory)
519 pushed = nargs; 518 /* Too few arguments. */
520 at = Qnil; 519 Fsignal (Qwrong_number_of_arguments,
521 break; 520 Fcons (Fcons (make_number (mandatory),
522 } 521 rest ? Qand_rest : make_number (nonrest)),
523 else if (pushed < nargs) 522 Fcons (make_number (nargs), Qnil)));
524 { 523 else
525 PUSH (*args++); 524 {
526 pushed++; 525 for (; i < nonrest; i++)
527 } 526 PUSH (Qnil);
528 else if (optional) 527 if (rest)
529 PUSH (Qnil); 528 PUSH (Qnil);
530 else 529 }
531 break; 530 }
532 531 else if (rest)
533 if (pushed != nargs || !NILP (at)) 532 {
533 int i;
534 for (i = 0 ; i < nonrest; i++, args++)
535 PUSH (*args);
536 PUSH (Flist (nargs - nonrest, args));
537 }
538 else
539 /* Too many arguments. */
534 Fsignal (Qwrong_number_of_arguments, 540 Fsignal (Qwrong_number_of_arguments,
535 Fcons (args_template, Fcons (make_number (nargs), Qnil))); 541 Fcons (Fcons (make_number (mandatory),
542 make_number (nonrest)),
543 Fcons (make_number (nargs), Qnil)));
544 }
545 else if (! NILP (args_template))
546 /* We should push some arguments on the stack. */
547 {
548 error ("Unknown args template!");
536 } 549 }
537 550
538 while (1) 551 while (1)