diff options
| author | Stefan Monnier | 2011-03-05 23:48:17 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2011-03-05 23:48:17 -0500 |
| commit | e2abe5a13dffb08d6371b6a611bc39c3a9ac2bc6 (patch) | |
| tree | b9fb87041279f75ba8b6b304e0765bf412377af6 | |
| parent | d032d5e7dfabfae60f3304da02c97cd1e189b9a2 (diff) | |
| download | emacs-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/ChangeLog | 17 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 3 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 87 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cconv.el | 11 | ||||
| -rw-r--r-- | lisp/emacs-lisp/macroexp.el | 9 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 23 | ||||
| -rw-r--r-- | lisp/help-fns.el | 26 | ||||
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/alloc.c | 13 | ||||
| -rw-r--r-- | src/bytecode.c | 71 |
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 @@ | |||
| 1 | 2011-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 | |||
| 1 | 2011-03-01 Stefan Monnier <monnier@iro.umontreal.ca> | 18 | 2011-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 | |||
| 78 | like `(,a . ,(pred (< a))) or, with more checks: | 78 | like `(,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. |
| 83 | If DOCSTRING already has a usage info, then just return it unchanged. | 85 | If DOCSTRING already has a usage info, then just return it unchanged. |
| 84 | The usage info is built from ARGLIST. DOCSTRING can be nil. | 86 | The usage info is built from ARGLIST. DOCSTRING can be nil. |
| 85 | ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"." | 87 | ARGLIST 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 @@ | |||
| 1 | 2011-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 | |||
| 1 | 2011-03-01 Stefan Monnier <monnier@iro.umontreal.ca> | 7 | 2011-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 | ||
| 2946 | DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0, | 2946 | DEFUN ("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. |
| 2948 | The arguments should be the arglist, bytecode-string, constant vector, | 2948 | The arguments should be the ARGLIST, bytecode-string BYTE-CODE, constant |
| 2949 | stack size, (optional) doc string, and (optional) interactive spec. | 2949 | vector CONSTANTS, maximum stack size DEPTH, (optional) DOCSTRING, |
| 2950 | and (optional) INTERACTIVE-SPEC. | ||
| 2950 | The first four arguments are required; at most six have any | 2951 | The first four arguments are required; at most six have any |
| 2951 | significance. | 2952 | significance. |
| 2953 | The ARGLIST can be either like the one of `lambda', in which case the arguments | ||
| 2954 | will be dynamically bound before executing the byte code, or it can be an | ||
| 2955 | integer of the form NNNNNNNRMMMMMMM where the 7bit MMMMMMM specifies the | ||
| 2956 | minimum number of arguments, the 7-bit NNNNNNN specifies the maximum number | ||
| 2957 | of arguments (ignoring &rest) and the R bit specifies whether there is a &rest | ||
| 2958 | argument to catch the left-over arguments. If such an integer is used, the | ||
| 2959 | arguments will not be dynamically bound but will be instead pushed on the | ||
| 2960 | stack before executing the byte-code. | ||
| 2952 | usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS) */) | 2961 | usage: (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) |