mirrored from git://git.sv.gnu.org/emacs.git
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
bytecomp.el
4258 lines (3925 loc) · 160 KB
/
bytecomp.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; bytecomp.el --- compilation of Lisp code into byte code
;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 1998, 2000, 2001, 2002,
;; 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Author: Jamie Zawinski <jwz@lucid.com>
;; Hallvard Furuseth <hbf@ulrik.uio.no>
;; Maintainer: FSF
;; Keywords: lisp
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; The Emacs Lisp byte compiler. This crunches lisp source into a sort
;; of p-code (`lapcode') which takes up less space and can be interpreted
;; faster. [`LAP' == `Lisp Assembly Program'.]
;; The user entry points are byte-compile-file and byte-recompile-directory.
;;; Code:
;; ========================================================================
;; Entry points:
;; byte-recompile-directory, byte-compile-file,
;; batch-byte-compile, batch-byte-recompile-directory,
;; byte-compile, compile-defun,
;; display-call-tree
;; (byte-compile-buffer and byte-compile-and-load-file were turned off
;; because they are not terribly useful and get in the way of completion.)
;; This version of the byte compiler has the following improvements:
;; + optimization of compiled code:
;; - removal of unreachable code;
;; - removal of calls to side-effectless functions whose return-value
;; is unused;
;; - compile-time evaluation of safe constant forms, such as (consp nil)
;; and (ash 1 6);
;; - open-coding of literal lambdas;
;; - peephole optimization of emitted code;
;; - trivial functions are left uncompiled for speed.
;; + support for inline functions;
;; + compile-time evaluation of arbitrary expressions;
;; + compile-time warning messages for:
;; - functions being redefined with incompatible arglists;
;; - functions being redefined as macros, or vice-versa;
;; - functions or macros defined multiple times in the same file;
;; - functions being called with the incorrect number of arguments;
;; - functions being called which are not defined globally, in the
;; file, or as autoloads;
;; - assignment and reference of undeclared free variables;
;; - various syntax errors;
;; + correct compilation of nested defuns, defmacros, defvars and defsubsts;
;; + correct compilation of top-level uses of macros;
;; + the ability to generate a histogram of functions called.
;; User customization variables:
;;
;; byte-compile-verbose Whether to report the function currently being
;; compiled in the echo area;
;; byte-optimize Whether to do optimizations; this may be
;; t, nil, 'source, or 'byte;
;; byte-optimize-log Whether to report (in excruciating detail)
;; exactly which optimizations have been made.
;; This may be t, nil, 'source, or 'byte;
;; byte-compile-error-on-warn Whether to stop compilation when a warning is
;; produced;
;; byte-compile-delete-errors Whether the optimizer may delete calls or
;; variable references that are side-effect-free
;; except that they may return an error.
;; byte-compile-generate-call-tree Whether to generate a histogram of
;; function calls. This can be useful for
;; finding unused functions, as well as simple
;; performance metering.
;; byte-compile-warnings List of warnings to issue, or t. May contain
;; `free-vars' (references to variables not in the
;; current lexical scope)
;; `unresolved' (calls to unknown functions)
;; `callargs' (lambda calls with args that don't
;; match the lambda's definition)
;; `redefine' (function cell redefined from
;; a macro to a lambda or vice versa,
;; or redefined to take other args)
;; `obsolete' (obsolete variables and functions)
;; `noruntime' (calls to functions only defined
;; within `eval-when-compile')
;; `cl-warnings' (calls to CL functions)
;; `interactive-only' (calls to commands that are
;; not good to call from Lisp)
;; byte-compile-compatibility Whether the compiler should
;; generate .elc files which can be loaded into
;; generic emacs 18.
;; emacs-lisp-file-regexp Regexp for the extension of source-files;
;; see also the function byte-compile-dest-file.
;; New Features:
;;
;; o The form `defsubst' is just like `defun', except that the function
;; generated will be open-coded in compiled code which uses it. This
;; means that no function call will be generated, it will simply be
;; spliced in. Lisp functions calls are very slow, so this can be a
;; big win.
;;
;; You can generally accomplish the same thing with `defmacro', but in
;; that case, the defined procedure can't be used as an argument to
;; mapcar, etc.
;;
;; o You can also open-code one particular call to a function without
;; open-coding all calls. Use the 'inline' form to do this, like so:
;;
;; (inline (foo 1 2 3)) ;; `foo' will be open-coded
;; or...
;; (inline ;; `foo' and `baz' will be
;; (foo 1 2 3 (bar 5)) ;; open-coded, but `bar' will not.
;; (baz 0))
;;
;; o It is possible to open-code a function in the same file it is defined
;; in without having to load that file before compiling it. The
;; byte-compiler has been modified to remember function definitions in
;; the compilation environment in the same way that it remembers macro
;; definitions.
;;
;; o Forms like ((lambda ...) ...) are open-coded.
;;
;; o The form `eval-when-compile' is like progn, except that the body
;; is evaluated at compile-time. When it appears at top-level, this
;; is analogous to the Common Lisp idiom (eval-when (compile) ...).
;; When it does not appear at top-level, it is similar to the
;; Common Lisp #. reader macro (but not in interpreted code).
;;
;; o The form `eval-and-compile' is similar to eval-when-compile, but
;; the whole form is evalled both at compile-time and at run-time.
;;
;; o The command compile-defun is analogous to eval-defun.
;;
;; o If you run byte-compile-file on a filename which is visited in a
;; buffer, and that buffer is modified, you are asked whether you want
;; to save the buffer before compiling.
;;
;; o byte-compiled files now start with the string `;ELC'.
;; Some versions of `file' can be customized to recognize that.
(require 'backquote)
(or (fboundp 'defsubst)
;; This really ought to be loaded already!
(load "byte-run"))
;; The feature of compiling in a specific target Emacs version
;; has been turned off because compile time options are a bad idea.
(defmacro byte-compile-single-version () nil)
(defmacro byte-compile-version-cond (cond) cond)
;; The crud you see scattered through this file of the form
;; (or (and (boundp 'epoch::version) epoch::version)
;; (string-lessp emacs-version "19"))
;; is because the Epoch folks couldn't be bothered to follow the
;; normal emacs version numbering convention.
;; (if (byte-compile-version-cond
;; (or (and (boundp 'epoch::version) epoch::version)
;; (string-lessp emacs-version "19")))
;; (progn
;; ;; emacs-18 compatibility.
;; (defvar baud-rate (baud-rate)) ;Define baud-rate if it's undefined
;;
;; (if (byte-compile-single-version)
;; (defmacro byte-code-function-p (x) "Emacs 18 doesn't have these." nil)
;; (defun byte-code-function-p (x) "Emacs 18 doesn't have these." nil))
;;
;; (or (and (fboundp 'member)
;; ;; avoid using someone else's possibly bogus definition of this.
;; (subrp (symbol-function 'member)))
;; (defun member (elt list)
;; "like memq, but uses equal instead of eq. In v19, this is a subr."
;; (while (and list (not (equal elt (car list))))
;; (setq list (cdr list)))
;; list))))
(defgroup bytecomp nil
"Emacs Lisp byte-compiler."
:group 'lisp)
(defcustom emacs-lisp-file-regexp (if (eq system-type 'vax-vms)
"\\.EL\\(;[0-9]+\\)?$"
"\\.el$")
"*Regexp which matches Emacs Lisp source files.
You may want to redefine the function `byte-compile-dest-file'
if you change this variable."
:group 'bytecomp
:type 'regexp)
;; This enables file name handlers such as jka-compr
;; to remove parts of the file name that should not be copied
;; through to the output file name.
(defun byte-compiler-base-file-name (filename)
(let ((handler (find-file-name-handler filename
'byte-compiler-base-file-name)))
(if handler
(funcall handler 'byte-compiler-base-file-name filename)
filename)))
(or (fboundp 'byte-compile-dest-file)
;; The user may want to redefine this along with emacs-lisp-file-regexp,
;; so only define it if it is undefined.
(defun byte-compile-dest-file (filename)
"Convert an Emacs Lisp source file name to a compiled file name.
If FILENAME matches `emacs-lisp-file-regexp' (by default, files
with the extension `.el'), add `c' to it; otherwise add `.elc'."
(setq filename (byte-compiler-base-file-name filename))
(setq filename (file-name-sans-versions filename))
(cond ((eq system-type 'vax-vms)
(concat (substring filename 0 (string-match ";" filename)) "c"))
((string-match emacs-lisp-file-regexp filename)
(concat (substring filename 0 (match-beginning 0)) ".elc"))
(t (concat filename ".elc")))))
;; This can be the 'byte-compile property of any symbol.
(autoload 'byte-compile-inline-expand "byte-opt")
;; This is the entrypoint to the lapcode optimizer pass1.
(autoload 'byte-optimize-form "byte-opt")
;; This is the entrypoint to the lapcode optimizer pass2.
(autoload 'byte-optimize-lapcode "byte-opt")
(autoload 'byte-compile-unfold-lambda "byte-opt")
;; This is the entry point to the decompiler, which is used by the
;; disassembler. The disassembler just requires 'byte-compile, but
;; that doesn't define this function, so this seems to be a reasonable
;; thing to do.
(autoload 'byte-decompile-bytecode "byte-opt")
(defcustom byte-compile-verbose
(and (not noninteractive) (> baud-rate search-slow-speed))
"*Non-nil means print messages describing progress of byte-compiler."
:group 'bytecomp
:type 'boolean)
(defcustom byte-compile-compatibility nil
"*Non-nil means generate output that can run in Emacs 18.
This only means that it can run in principle, if it doesn't require
facilities that have been added more recently."
:group 'bytecomp
:type 'boolean)
;; (defvar byte-compile-generate-emacs19-bytecodes
;; (not (or (and (boundp 'epoch::version) epoch::version)
;; (string-lessp emacs-version "19")))
;; "*If this is true, then the byte-compiler will generate bytecode which
;; makes use of byte-ops which are present only in Emacs 19. Code generated
;; this way can never be run in Emacs 18, and may even cause it to crash.")
(defcustom byte-optimize t
"*Enable optimization in the byte compiler.
Possible values are:
nil - no optimization
t - all optimizations
`source' - source-level optimizations only
`byte' - code-level optimizations only"
:group 'bytecomp
:type '(choice (const :tag "none" nil)
(const :tag "all" t)
(const :tag "source-level" source)
(const :tag "byte-level" byte)))
(defcustom byte-compile-delete-errors nil
"*If non-nil, the optimizer may delete forms that may signal an error.
This includes variable references and calls to functions such as `car'."
:group 'bytecomp
:type 'boolean)
(defvar byte-compile-dynamic nil
"If non-nil, compile function bodies so they load lazily.
They are hidden in comments in the compiled file,
and each one is brought into core when the
function is called.
To enable this option, make it a file-local variable
in the source file you want it to apply to.
For example, add -*-byte-compile-dynamic: t;-*- on the first line.
When this option is true, if you load the compiled file and then move it,
the functions you loaded will not be able to run.")
;;;###autoload(put 'byte-compile-dynamic 'safe-local-variable 'booleanp)
(defvar byte-compile-disable-print-circle nil
"If non-nil, disable `print-circle' on printing a byte-compiled code.")
;;;###autoload(put 'byte-compile-disable-print-circle 'safe-local-variable 'booleanp)
(defcustom byte-compile-dynamic-docstrings t
"*If non-nil, compile doc strings for lazy access.
We bury the doc strings of functions and variables
inside comments in the file, and bring them into core only when they
are actually needed.
When this option is true, if you load the compiled file and then move it,
you won't be able to find the documentation of anything in that file.
To disable this option for a certain file, make it a file-local variable
in the source file. For example, add this to the first line:
-*-byte-compile-dynamic-docstrings:nil;-*-
You can also set the variable globally.
This option is enabled by default because it reduces Emacs memory usage."
:group 'bytecomp
:type 'boolean)
;;;###autoload(put 'byte-compile-dynamic-docstrings 'safe-local-variable 'booleanp)
(defcustom byte-optimize-log nil
"*If true, the byte-compiler will log its optimizations into *Compile-Log*.
If this is 'source, then only source-level optimizations will be logged.
If it is 'byte, then only byte-level optimizations will be logged."
:group 'bytecomp
:type '(choice (const :tag "none" nil)
(const :tag "all" t)
(const :tag "source-level" source)
(const :tag "byte-level" byte)))
(defcustom byte-compile-error-on-warn nil
"*If true, the byte-compiler reports warnings with `error'."
:group 'bytecomp
:type 'boolean)
(defconst byte-compile-warning-types
'(redefine callargs free-vars unresolved
obsolete noruntime cl-functions interactive-only)
"The list of warning types used when `byte-compile-warnings' is t.")
(defcustom byte-compile-warnings t
"*List of warnings that the byte-compiler should issue (t for all).
Elements of the list may be:
free-vars references to variables not in the current lexical scope.
unresolved calls to unknown functions.
callargs function calls with args that don't match the definition.
redefine function name redefined from a macro to ordinary function or vice
versa, or redefined to take a different number of arguments.
obsolete obsolete variables and functions.
noruntime functions that may not be defined at runtime (typically
defined only under `eval-when-compile').
cl-functions calls to runtime functions from the CL package (as
distinguished from macros and aliases).
interactive-only
commands that normally shouldn't be called from Lisp code."
:group 'bytecomp
:type `(choice (const :tag "All" t)
(set :menu-tag "Some"
(const free-vars) (const unresolved)
(const callargs) (const redefine)
(const obsolete) (const noruntime)
(const cl-functions) (const interactive-only))))
;;;###autoload(put 'byte-compile-warnings 'safe-local-variable 'byte-compile-warnings-safe-p)
;;;###autoload
(defun byte-compile-warnings-safe-p (x)
(or (booleanp x)
(and (listp x)
(equal (mapcar
(lambda (e)
(when (memq e '(free-vars unresolved
callargs redefine
obsolete noruntime
cl-functions interactive-only))
e))
x)
x))))
(defvar byte-compile-interactive-only-functions
'(beginning-of-buffer end-of-buffer replace-string replace-regexp
insert-file insert-buffer insert-file-literally)
"List of commands that are not meant to be called from Lisp.")
(defvar byte-compile-not-obsolete-var nil
"If non-nil, this is a variable that shouldn't be reported as obsolete.")
(defcustom byte-compile-generate-call-tree nil
"*Non-nil means collect call-graph information when compiling.
This records which functions were called and from where.
If the value is t, compilation displays the call graph when it finishes.
If the value is neither t nor nil, compilation asks you whether to display
the graph.
The call tree only lists functions called, not macros used. Those functions
which the byte-code interpreter knows about directly (eq, cons, etc.) are
not reported.
The call tree also lists those functions which are not known to be called
\(that is, to which no calls have been compiled). Functions which can be
invoked interactively are excluded from this list."
:group 'bytecomp
:type '(choice (const :tag "Yes" t) (const :tag "No" nil)
(other :tag "Ask" lambda)))
(defvar byte-compile-call-tree nil "Alist of functions and their call tree.
Each element looks like
\(FUNCTION CALLERS CALLS\)
where CALLERS is a list of functions that call FUNCTION, and CALLS
is a list of functions for which calls were generated while compiling
FUNCTION.")
(defcustom byte-compile-call-tree-sort 'name
"*If non-nil, sort the call tree.
The values `name', `callers', `calls', `calls+callers'
specify different fields to sort on."
:group 'bytecomp
:type '(choice (const name) (const callers) (const calls)
(const calls+callers) (const nil)))
(defvar byte-compile-debug nil)
;; (defvar byte-compile-overwrite-file t
;; "If nil, old .elc files are deleted before the new is saved, and .elc
;; files will have the same modes as the corresponding .el file. Otherwise,
;; existing .elc files will simply be overwritten, and the existing modes
;; will not be changed. If this variable is nil, then an .elc file which
;; is a symbolic link will be turned into a normal file, instead of the file
;; which the link points to being overwritten.")
(defvar byte-compile-constants nil
"List of all constants encountered during compilation of this form.")
(defvar byte-compile-variables nil
"List of all variables encountered during compilation of this form.")
(defvar byte-compile-bound-variables nil
"List of variables bound in the context of the current form.
This list lives partly on the stack.")
(defvar byte-compile-const-variables nil
"List of variables declared as constants during compilation of this file.")
(defvar byte-compile-free-references)
(defvar byte-compile-free-assignments)
(defvar byte-compiler-error-flag)
(defconst byte-compile-initial-macro-environment
'(
;; (byte-compiler-options . (lambda (&rest forms)
;; (apply 'byte-compiler-options-handler forms)))
(eval-when-compile . (lambda (&rest body)
(list 'quote
(byte-compile-eval (byte-compile-top-level
(cons 'progn body))))))
(eval-and-compile . (lambda (&rest body)
(byte-compile-eval-before-compile (cons 'progn body))
(cons 'progn body))))
"The default macro-environment passed to macroexpand by the compiler.
Placing a macro here will cause a macro to have different semantics when
expanded by the compiler as when expanded by the interpreter.")
(defvar byte-compile-macro-environment byte-compile-initial-macro-environment
"Alist of macros defined in the file being compiled.
Each element looks like (MACRONAME . DEFINITION). It is
\(MACRONAME . nil) when a macro is redefined as a function.")
(defvar byte-compile-function-environment nil
"Alist of functions defined in the file being compiled.
This is so we can inline them when necessary.
Each element looks like (FUNCTIONNAME . DEFINITION). It is
\(FUNCTIONNAME . nil) when a function is redefined as a macro.
It is \(FUNCTIONNAME . t) when all we know is that it was defined,
and we don't know the definition.")
(defvar byte-compile-unresolved-functions nil
"Alist of undefined functions to which calls have been compiled.
This variable is only significant whilst compiling an entire buffer.
Used for warnings when a function is not known to be defined or is later
defined with incorrect args.")
(defvar byte-compile-noruntime-functions nil
"Alist of functions called that may not be defined when the compiled code is run.
Used for warnings about calling a function that is defined during compilation
but won't necessarily be defined when the compiled file is loaded.")
(defvar byte-compile-tag-number 0)
(defvar byte-compile-output nil
"Alist describing contents to put in byte code string.
Each element is (INDEX . VALUE)")
(defvar byte-compile-depth 0 "Current depth of execution stack.")
(defvar byte-compile-maxdepth 0 "Maximum depth of execution stack.")
;;; The byte codes; this information is duplicated in bytecomp.c
(defvar byte-code-vector nil
"An array containing byte-code names indexed by byte-code values.")
(defvar byte-stack+-info nil
"An array with the stack adjustment for each byte-code.")
(defmacro byte-defop (opcode stack-adjust opname &optional docstring)
;; This is a speed-hack for building the byte-code-vector at compile-time.
;; We fill in the vector at macroexpand-time, and then after the last call
;; to byte-defop, we write the vector out as a constant instead of writing
;; out a bunch of calls to aset.
;; Actually, we don't fill in the vector itself, because that could make
;; it problematic to compile big changes to this compiler; we store the
;; values on its plist, and remove them later in -extrude.
(let ((v1 (or (get 'byte-code-vector 'tmp-compile-time-value)
(put 'byte-code-vector 'tmp-compile-time-value
(make-vector 256 nil))))
(v2 (or (get 'byte-stack+-info 'tmp-compile-time-value)
(put 'byte-stack+-info 'tmp-compile-time-value
(make-vector 256 nil)))))
(aset v1 opcode opname)
(aset v2 opcode stack-adjust))
(if docstring
(list 'defconst opname opcode (concat "Byte code opcode " docstring "."))
(list 'defconst opname opcode)))
(defmacro byte-extrude-byte-code-vectors ()
(prog1 (list 'setq 'byte-code-vector
(get 'byte-code-vector 'tmp-compile-time-value)
'byte-stack+-info
(get 'byte-stack+-info 'tmp-compile-time-value))
(put 'byte-code-vector 'tmp-compile-time-value nil)
(put 'byte-stack+-info 'tmp-compile-time-value nil)))
;; unused: 0-7
;; These opcodes are special in that they pack their argument into the
;; opcode word.
;;
(byte-defop 8 1 byte-varref "for variable reference")
(byte-defop 16 -1 byte-varset "for setting a variable")
(byte-defop 24 -1 byte-varbind "for binding a variable")
(byte-defop 32 0 byte-call "for calling a function")
(byte-defop 40 0 byte-unbind "for unbinding special bindings")
;; codes 8-47 are consumed by the preceding opcodes
;; unused: 48-55
(byte-defop 56 -1 byte-nth)
(byte-defop 57 0 byte-symbolp)
(byte-defop 58 0 byte-consp)
(byte-defop 59 0 byte-stringp)
(byte-defop 60 0 byte-listp)
(byte-defop 61 -1 byte-eq)
(byte-defop 62 -1 byte-memq)
(byte-defop 63 0 byte-not)
(byte-defop 64 0 byte-car)
(byte-defop 65 0 byte-cdr)
(byte-defop 66 -1 byte-cons)
(byte-defop 67 0 byte-list1)
(byte-defop 68 -1 byte-list2)
(byte-defop 69 -2 byte-list3)
(byte-defop 70 -3 byte-list4)
(byte-defop 71 0 byte-length)
(byte-defop 72 -1 byte-aref)
(byte-defop 73 -2 byte-aset)
(byte-defop 74 0 byte-symbol-value)
(byte-defop 75 0 byte-symbol-function) ; this was commented out
(byte-defop 76 -1 byte-set)
(byte-defop 77 -1 byte-fset) ; this was commented out
(byte-defop 78 -1 byte-get)
(byte-defop 79 -2 byte-substring)
(byte-defop 80 -1 byte-concat2)
(byte-defop 81 -2 byte-concat3)
(byte-defop 82 -3 byte-concat4)
(byte-defop 83 0 byte-sub1)
(byte-defop 84 0 byte-add1)
(byte-defop 85 -1 byte-eqlsign)
(byte-defop 86 -1 byte-gtr)
(byte-defop 87 -1 byte-lss)
(byte-defop 88 -1 byte-leq)
(byte-defop 89 -1 byte-geq)
(byte-defop 90 -1 byte-diff)
(byte-defop 91 0 byte-negate)
(byte-defop 92 -1 byte-plus)
(byte-defop 93 -1 byte-max)
(byte-defop 94 -1 byte-min)
(byte-defop 95 -1 byte-mult) ; v19 only
(byte-defop 96 1 byte-point)
(byte-defop 98 0 byte-goto-char)
(byte-defop 99 0 byte-insert)
(byte-defop 100 1 byte-point-max)
(byte-defop 101 1 byte-point-min)
(byte-defop 102 0 byte-char-after)
(byte-defop 103 1 byte-following-char)
(byte-defop 104 1 byte-preceding-char)
(byte-defop 105 1 byte-current-column)
(byte-defop 106 0 byte-indent-to)
(byte-defop 107 0 byte-scan-buffer-OBSOLETE) ; no longer generated as of v18
(byte-defop 108 1 byte-eolp)
(byte-defop 109 1 byte-eobp)
(byte-defop 110 1 byte-bolp)
(byte-defop 111 1 byte-bobp)
(byte-defop 112 1 byte-current-buffer)
(byte-defop 113 0 byte-set-buffer)
(byte-defop 114 0 byte-save-current-buffer
"To make a binding to record the current buffer")
(byte-defop 115 0 byte-set-mark-OBSOLETE)
(byte-defop 116 1 byte-interactive-p)
;; These ops are new to v19
(byte-defop 117 0 byte-forward-char)
(byte-defop 118 0 byte-forward-word)
(byte-defop 119 -1 byte-skip-chars-forward)
(byte-defop 120 -1 byte-skip-chars-backward)
(byte-defop 121 0 byte-forward-line)
(byte-defop 122 0 byte-char-syntax)
(byte-defop 123 -1 byte-buffer-substring)
(byte-defop 124 -1 byte-delete-region)
(byte-defop 125 -1 byte-narrow-to-region)
(byte-defop 126 1 byte-widen)
(byte-defop 127 0 byte-end-of-line)
;; unused: 128
;; These store their argument in the next two bytes
(byte-defop 129 1 byte-constant2
"for reference to a constant with vector index >= byte-constant-limit")
(byte-defop 130 0 byte-goto "for unconditional jump")
(byte-defop 131 -1 byte-goto-if-nil "to pop value and jump if it's nil")
(byte-defop 132 -1 byte-goto-if-not-nil "to pop value and jump if it's not nil")
(byte-defop 133 -1 byte-goto-if-nil-else-pop
"to examine top-of-stack, jump and don't pop it if it's nil,
otherwise pop it")
(byte-defop 134 -1 byte-goto-if-not-nil-else-pop
"to examine top-of-stack, jump and don't pop it if it's non nil,
otherwise pop it")
(byte-defop 135 -1 byte-return "to pop a value and return it from `byte-code'")
(byte-defop 136 -1 byte-discard "to discard one value from stack")
(byte-defop 137 1 byte-dup "to duplicate the top of the stack")
(byte-defop 138 0 byte-save-excursion
"to make a binding to record the buffer, point and mark")
(byte-defop 139 0 byte-save-window-excursion
"to make a binding to record entire window configuration")
(byte-defop 140 0 byte-save-restriction
"to make a binding to record the current buffer clipping restrictions")
(byte-defop 141 -1 byte-catch
"for catch. Takes, on stack, the tag and an expression for the body")
(byte-defop 142 -1 byte-unwind-protect
"for unwind-protect. Takes, on stack, an expression for the unwind-action")
;; For condition-case. Takes, on stack, the variable to bind,
;; an expression for the body, and a list of clauses.
(byte-defop 143 -2 byte-condition-case)
;; For entry to with-output-to-temp-buffer.
;; Takes, on stack, the buffer name.
;; Binds standard-output and does some other things.
;; Returns with temp buffer on the stack in place of buffer name.
(byte-defop 144 0 byte-temp-output-buffer-setup)
;; For exit from with-output-to-temp-buffer.
;; Expects the temp buffer on the stack underneath value to return.
;; Pops them both, then pushes the value back on.
;; Unbinds standard-output and makes the temp buffer visible.
(byte-defop 145 -1 byte-temp-output-buffer-show)
;; these ops are new to v19
;; To unbind back to the beginning of this frame.
;; Not used yet, but will be needed for tail-recursion elimination.
(byte-defop 146 0 byte-unbind-all)
;; these ops are new to v19
(byte-defop 147 -2 byte-set-marker)
(byte-defop 148 0 byte-match-beginning)
(byte-defop 149 0 byte-match-end)
(byte-defop 150 0 byte-upcase)
(byte-defop 151 0 byte-downcase)
(byte-defop 152 -1 byte-string=)
(byte-defop 153 -1 byte-string<)
(byte-defop 154 -1 byte-equal)
(byte-defop 155 -1 byte-nthcdr)
(byte-defop 156 -1 byte-elt)
(byte-defop 157 -1 byte-member)
(byte-defop 158 -1 byte-assq)
(byte-defop 159 0 byte-nreverse)
(byte-defop 160 -1 byte-setcar)
(byte-defop 161 -1 byte-setcdr)
(byte-defop 162 0 byte-car-safe)
(byte-defop 163 0 byte-cdr-safe)
(byte-defop 164 -1 byte-nconc)
(byte-defop 165 -1 byte-quo)
(byte-defop 166 -1 byte-rem)
(byte-defop 167 0 byte-numberp)
(byte-defop 168 0 byte-integerp)
;; unused: 169-174
(byte-defop 175 nil byte-listN)
(byte-defop 176 nil byte-concatN)
(byte-defop 177 nil byte-insertN)
;; unused: 178-191
(byte-defop 192 1 byte-constant "for reference to a constant")
;; codes 193-255 are consumed by byte-constant.
(defconst byte-constant-limit 64
"Exclusive maximum index usable in the `byte-constant' opcode.")
(defconst byte-goto-ops '(byte-goto byte-goto-if-nil byte-goto-if-not-nil
byte-goto-if-nil-else-pop
byte-goto-if-not-nil-else-pop)
"List of byte-codes whose offset is a pc.")
(defconst byte-goto-always-pop-ops '(byte-goto-if-nil byte-goto-if-not-nil))
(byte-extrude-byte-code-vectors)
;;; lapcode generator
;;
;; the byte-compiler now does source -> lapcode -> bytecode instead of
;; source -> bytecode, because it's a lot easier to make optimizations
;; on lapcode than on bytecode.
;;
;; Elements of the lapcode list are of the form (<instruction> . <parameter>)
;; where instruction is a symbol naming a byte-code instruction,
;; and parameter is an argument to that instruction, if any.
;;
;; The instruction can be the pseudo-op TAG, which means that this position
;; in the instruction stream is a target of a goto. (car PARAMETER) will be
;; the PC for this location, and the whole instruction "(TAG pc)" will be the
;; parameter for some goto op.
;;
;; If the operation is varbind, varref, varset or push-constant, then the
;; parameter is (variable/constant . index_in_constant_vector).
;;
;; First, the source code is macroexpanded and optimized in various ways.
;; Then the resultant code is compiled into lapcode. Another set of
;; optimizations are then run over the lapcode. Then the variables and
;; constants referenced by the lapcode are collected and placed in the
;; constants-vector. (This happens now so that variables referenced by dead
;; code don't consume space.) And finally, the lapcode is transformed into
;; compacted byte-code.
;;
;; A distinction is made between variables and constants because the variable-
;; referencing instructions are more sensitive to the variables being near the
;; front of the constants-vector than the constant-referencing instructions.
;; Also, this lets us notice references to free variables.
(defun byte-compile-lapcode (lap)
"Turns lapcode into bytecode. The lapcode is destroyed."
;; Lapcode modifications: changes the ID of a tag to be the tag's PC.
(let ((pc 0) ; Program counter
op off ; Operation & offset
(bytes '()) ; Put the output bytes here
(patchlist nil)) ; List of tags and goto's to patch
(while lap
(setq op (car (car lap))
off (cdr (car lap)))
(cond ((not (symbolp op))
(error "Non-symbolic opcode `%s'" op))
((eq op 'TAG)
(setcar off pc)
(setq patchlist (cons off patchlist)))
((memq op byte-goto-ops)
(setq pc (+ pc 3))
(setq bytes (cons (cons pc (cdr off))
(cons nil
(cons (symbol-value op) bytes))))
(setq patchlist (cons bytes patchlist)))
(t
(setq bytes
(cond ((cond ((consp off)
;; Variable or constant reference
(setq off (cdr off))
(eq op 'byte-constant)))
(cond ((< off byte-constant-limit)
(setq pc (1+ pc))
(cons (+ byte-constant off) bytes))
(t
(setq pc (+ 3 pc))
(cons (lsh off -8)
(cons (logand off 255)
(cons byte-constant2 bytes))))))
((<= byte-listN (symbol-value op))
(setq pc (+ 2 pc))
(cons off (cons (symbol-value op) bytes)))
((< off 6)
(setq pc (1+ pc))
(cons (+ (symbol-value op) off) bytes))
((< off 256)
(setq pc (+ 2 pc))
(cons off (cons (+ (symbol-value op) 6) bytes)))
(t
(setq pc (+ 3 pc))
(cons (lsh off -8)
(cons (logand off 255)
(cons (+ (symbol-value op) 7)
bytes))))))))
(setq lap (cdr lap)))
;;(if (not (= pc (length bytes)))
;; (error "Compiler error: pc mismatch - %s %s" pc (length bytes)))
;; Patch PC into jumps
(let (bytes)
(while patchlist
(setq bytes (car patchlist))
(cond ((atom (car bytes))) ; Tag
(t ; Absolute jump
(setq pc (car (cdr (car bytes)))) ; Pick PC from tag
(setcar (cdr bytes) (logand pc 255))
(setcar bytes (lsh pc -8))))
(setq patchlist (cdr patchlist))))
(concat (nreverse bytes))))
;;; compile-time evaluation
(defun byte-compile-eval (form)
"Eval FORM and mark the functions defined therein.
Each function's symbol gets added to `byte-compile-noruntime-functions'."
(let ((hist-orig load-history)
(hist-nil-orig current-load-list))
(prog1 (eval form)
(when (memq 'noruntime byte-compile-warnings)
(let ((hist-new load-history)
(hist-nil-new current-load-list))
;; Go through load-history, look for newly loaded files
;; and mark all the functions defined therein.
(while (and hist-new (not (eq hist-new hist-orig)))
(let ((xs (pop hist-new))
old-autoloads)
;; Make sure the file was not already loaded before.
(unless (or (assoc (car xs) hist-orig)
(equal (car xs) "cl"))
(dolist (s xs)
(cond
((symbolp s)
(unless (memq s old-autoloads)
(push s byte-compile-noruntime-functions)))
((and (consp s) (eq t (car s)))
(push (cdr s) old-autoloads))
((and (consp s) (eq 'autoload (car s)))
(push (cdr s) byte-compile-noruntime-functions)))))))
;; Go through current-load-list for the locally defined funs.
(let (old-autoloads)
(while (and hist-nil-new (not (eq hist-nil-new hist-nil-orig)))
(let ((s (pop hist-nil-new)))
(when (and (symbolp s) (not (memq s old-autoloads)))
(push s byte-compile-noruntime-functions))
(when (and (consp s) (eq t (car s)))
(push (cdr s) old-autoloads)))))))
(when (memq 'cl-functions byte-compile-warnings)
(let ((hist-new load-history)
(hist-nil-new current-load-list))
;; Go through load-history, look for newly loaded files
;; and mark all the functions defined therein.
(while (and hist-new (not (eq hist-new hist-orig)))
(let ((xs (pop hist-new))
old-autoloads)
;; Make sure the file was not already loaded before.
(when (and (equal (car xs) "cl") (not (assoc (car xs) hist-orig)))
(byte-compile-find-cl-functions)))))))))
(defun byte-compile-eval-before-compile (form)
"Evaluate FORM for `eval-and-compile'."
(let ((hist-nil-orig current-load-list))
(prog1 (eval form)
;; (eval-and-compile (require 'cl) turns off warnings for cl functions.
(let ((tem current-load-list))
(while (not (eq tem hist-nil-orig))
(when (equal (car tem) '(require . cl))
(setq byte-compile-warnings
(remq 'cl-functions byte-compile-warnings)))
(setq tem (cdr tem)))))))
;;; byte compiler messages
(defvar byte-compile-current-form nil)
(defvar byte-compile-dest-file nil)
(defvar byte-compile-current-file nil)
(defvar byte-compile-current-buffer nil)
;; Log something that isn't a warning.
(defmacro byte-compile-log (format-string &rest args)
`(and
byte-optimize
(memq byte-optimize-log '(t source))
(let ((print-escape-newlines t)
(print-level 4)
(print-length 4))
(byte-compile-log-1
(format
,format-string
,@(mapcar
(lambda (x) (if (symbolp x) (list 'prin1-to-string x) x))
args))))))
;; Log something that isn't a warning.
(defun byte-compile-log-1 (string)
(with-current-buffer "*Compile-Log*"
(let ((inhibit-read-only t))
(goto-char (point-max))
(byte-compile-warning-prefix nil nil)
(cond (noninteractive
(message " %s" string))
(t
(insert (format "%s\n" string)))))))
(defvar byte-compile-read-position nil
"Character position we began the last `read' from.")
(defvar byte-compile-last-position nil
"Last known character position in the input.")
;; copied from gnus-util.el
(defsubst byte-compile-delete-first (elt list)
(if (eq (car list) elt)
(cdr list)
(let ((total list))
(while (and (cdr list)
(not (eq (cadr list) elt)))
(setq list (cdr list)))
(when (cdr list)
(setcdr list (cddr list)))
total)))
;; The purpose of this function is to iterate through the
;; `read-symbol-positions-list'. Each time we process, say, a
;; function definition (`defun') we remove `defun' from
;; `read-symbol-positions-list', and set `byte-compile-last-position'
;; to that symbol's character position. Similarly, if we encounter a
;; variable reference, like in (1+ foo), we remove `foo' from the
;; list. If our current position is after the symbol's position, we
;; assume we've already passed that point, and look for the next
;; occurrence of the symbol.
;;
;; This function should not be called twice for the same occurrence of
;; a symbol, and it should not be called for symbols generated by the
;; byte compiler itself; because rather than just fail looking up the
;; symbol, we may find an occurrence of the symbol further ahead, and
;; then `byte-compile-last-position' as advanced too far.
;;
;; So your're probably asking yourself: Isn't this function a
;; gross hack? And the answer, of course, would be yes.
(defun byte-compile-set-symbol-position (sym &optional allow-previous)
(when byte-compile-read-position
(let (last entry)
(while (progn
(setq last byte-compile-last-position
entry (assq sym read-symbol-positions-list))
(when entry
(setq byte-compile-last-position
(+ byte-compile-read-position (cdr entry))
read-symbol-positions-list
(byte-compile-delete-first
entry read-symbol-positions-list)))
(or (and allow-previous (not (= last byte-compile-last-position)))
(> last byte-compile-last-position)))))))
(defvar byte-compile-last-warned-form nil)
(defvar byte-compile-last-logged-file nil)
;; This is used as warning-prefix for the compiler.
;; It is always called with the warnings buffer current.
(defun byte-compile-warning-prefix (level entry)
(let* ((inhibit-read-only t)
(dir default-directory)
(file (cond ((stringp byte-compile-current-file)
(format "%s:" (file-relative-name byte-compile-current-file dir)))
((bufferp byte-compile-current-file)
(format "Buffer %s:"
(buffer-name byte-compile-current-file)))
(t "")))
(pos (if (and byte-compile-current-file
(integerp byte-compile-read-position))
(with-current-buffer byte-compile-current-buffer
(format "%d:%d:"
(save-excursion
(goto-char byte-compile-last-position)
(1+ (count-lines (point-min) (point-at-bol))))
(save-excursion
(goto-char byte-compile-last-position)
(1+ (current-column)))))
""))
(form (if (eq byte-compile-current-form :end) "end of data"
(or byte-compile-current-form "toplevel form"))))
(when (or (and byte-compile-current-file
(not (equal byte-compile-current-file
byte-compile-last-logged-file)))
(and byte-compile-current-form
(not (eq byte-compile-current-form
byte-compile-last-warned-form))))
(insert (format "\nIn %s:\n" form)))
(when level
(insert (format "%s%s" file pos))))
(setq byte-compile-last-logged-file byte-compile-current-file
byte-compile-last-warned-form byte-compile-current-form)
entry)
;; This no-op function is used as the value of warning-series