Change `function` so that when evaluating #'(lambda ...)
we return an object of type `interpreted-function` rather than
a list starting with one of `lambda` or `closure`.
The new type reuses the existing PVEC_CLOSURE (nee PVEC_COMPILED)
tag and tries to align the corresponding elements:
- the arglist, the docstring, and the interactive-form go in the
same slots as for byte-code functions.
- the body of the function goes in the slot used for the bytecode string.
- the lexical context goes in the slot used for the constants of
bytecoded functions.
The first point above means that `help-function-arglist`,
`documentation`, and `interactive-form`s don't need to
distinguish interpreted and bytecode functions any more.
Main benefits of the change:
- We can now reliably distinguish a list from a function value.
- `cl-defmethod` can dispatch on `interactive-function` and `closure`.
Dispatch on `function` also works now for interpreted functions but still
won't work for functions represented as lists or as symbols, of course.
- Function values are now self-evaluating. That was alrready the case
when byte-compiled, but not when interpreted since
(eval '(closure ...)) signals a void-function error.
That also avoids false-positive warnings about "don't quote your lambdas"
when doing things like `(mapcar ',func ...)`.
* src/eval.c (Fmake_interpreted_closure): New function.
(Ffunction): Use it and change calling convention of
`Vinternal_make_interpreted_closure_function`.
(FUNCTIONP, Fcommandp, eval_sub, funcall_general, funcall_lambda)
(Ffunc_arity, lambda_arity): Simplify.
(funcall_lambda): Adjust to new representation.
(syms_of_eval): `defsubr` the new function. Remove definition of `Qclosure`.
* lisp/emacs-lisp/cconv.el (cconv-make-interpreted-closure):
Change calling convention and use `make-interpreted-closure`.
* src/data.c (Fcl_type_of): Distinguish `byte-code-function`s from
`interpreted-function`s.
(Fclosurep, finterpreted_function_p): New functions.
(Fbyte_code_function_p): Don't be confused by `interpreted-function`s.
(Finteractive_form, Fcommand_modes): Simplify.
(syms_of_data): Define new type symbols and `defsubr` the two
new functions.
* lisp/emacs-lisp/cl-print.el (cl-print-object) <interpreted-function>:
New method.
* lisp/emacs-lisp/oclosure.el (oclosure): Refine the parent
to be `closure`.
(oclosure--fix-type, oclosure-type): Simplify.
(oclosure--copy, oclosure--get, oclosure--set): Adjust to
new representation.
* src/callint.c (Fcall_interactively): Adjust to new representation.
* src/lread.c (bytecode_from_rev_list):
* lisp/simple.el (function-documentation):
* lisp/help.el (help-function-arglist): Remove the old `closure` case
and adjust the byte-code case so it handles `interpreted-function`s.
* lisp/emacs-lisp/cl-preloaded.el (closure): New type.
(byte-code-function): Add it as a parent.
(interpreted-function): Adjust parent (the type itself was already
added earlier by accident).
* lisp/emacs-lisp/bytecomp.el (byte-compile--reify-function): Adjust to
new representation.
(byte-compile): Use `interpreted-function-p`.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand): Adjust to
new representation.
(side-effect-free-fns): Add `interpreted-function-p` and `closurep`.
* src/profiler.c (trace_hash, ffunction_equal): Simplify.
* lisp/profiler.el (profiler-function-equal): Simplify.
* lisp/emacs-lisp/nadvice.el (advice--interactive-form-1):
Use `interpreted-function-p`; adjust to new representation; and take
advantage of the fact that function values are now self-evaluating.
* lisp/emacs-lisp/lisp-mode.el (closure):
Remove `lisp-indent-function` property.
* lisp/emacs-lisp/disass.el (disassemble-internal): Adjust to
new representation.
* lisp/emacs-lisp/edebug.el (edebug--strip-instrumentation):
Use `interpreted-function-p`.
* lisp/emacs-lisp/comp-common.el (comp-known-type-specifiers):
Add `closurep` and `interpreted-function-p`.
* test/lisp/help-fns-tests.el (help-fns-test-lisp-defun): Adjust to
more precise type info in `describe-function`.
* test/lisp/erc/resources/erc-d/erc-d-tests.el (erc-d--render-entries):
Use `interpreted-function-p`.
* test/lisp/emacs-lisp/macroexp-resources/vk.el (vk-f4, vk-f5):
Don't hardcode function values.
* doc/lispref/functions.texi (Anonymous Functions): Don't suggest that
function values are lists. Reword "self-quoting" to reflect the
fact that #' doesn't return the exact same object. Update examples
with the new shape of the return value.
* doc/lispref/variables.texi (Lexical Binding):
* doc/lispref/lists.texi (Rearrangement):
* doc/lispref/control.texi (Handling Errors): Update examples to reflect
new representation of function values.
It's a general-purpose polymorphic ordering function, like `<` but
for any two values of the same type.
* src/data.c (syms_of_data): Add the `type-mismatch` error.
(bits_word_to_host_endian): Move...
* src/lisp.h (bits_word_to_host_endian): ...here, and declare inline.
* src/fns.c (Fstring_lessp): Extract the bulk of this function to...
(string_cmp): ...this 3-way comparison function, for use elsewhere.
(bool_vector_cmp, value_cmp, Fvaluelt): New.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns, pure-fns):
Add `value<`, which is pure and side-effect-free.
* test/src/fns-tests.el (fns-value<-ordered, fns-value<-unordered)
(fns-value<-type-mismatch, fns-value<-symbol-with-pos)
(fns-value<-circle, ert-deftest fns-value<-bool-vector): New tests.
* doc/lispref/sequences.texi (Sequence Functions):
* doc/lispref/numbers.texi (Comparison of Numbers):
* doc/lispref/strings.texi (Text Comparison):
Document the new value< function.
* etc/NEWS: Announce.
Eliminate a case that matches very rarely and where the default
handling works just as well anyway.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker): Remove
redundant case.
We shouldn't be warning inside the optimiser in the first place.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form):
Remove byte-compile-form-stack manipulation.
(byte-optimize-form-code-walker): Move malformed function warning
from here...
* lisp/emacs-lisp/cconv.el: ...to here.
This fixes bug#67483.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form): Push and
pop FORM onto/off byte-compile-form-stack so that warning
messages get a position near to the erroneous source.
The compiler didn't cancel aliasing if the aliased variable was
modified in a variable binding in the same `let` that created
the alias. For example,
(let ((x A))
(let ((y x)
(z (setq x B)))
y))
would incorrectly substitute y->x in the body form despite x being
already modified at that point, which normally should have cancelled
the aliasing.
Bug reported by Alan Mackenzie.
* lisp/emacs-lisp/byte-opt.el (byte-optimize--aliased-vars):
Now an alist that also contains the aliases; update the doc string.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
* lisp/emacs-lisp/byte-opt.el (byte-optimize-let-form):
Detect aliasing early for `let`-bound variables as well.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test cases.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns)
(side-effect-and-error-free-fns)
(byte-compile-side-effect-and-error-free-ops)
(byte-compile-side-effect-free-ops):
Demote `equal` and `equal-including-properties` from error-free to
merely side-effect-free since they may in fact signal error on
circularity.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-equal, byte-optimize-eq):
Optimise (eq X X) -> t where X is a variable; idem for eql and equal.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test case.
* lisp/emacs-lisp/byte-opt.el (byte-after-unwind-ops):
Cease sinking `eq` past `unwind`, because that optimised away the
let-binding in
(let ((symbols-with-pos-enabled nil))
(eq x y))
and `eq` is currently sensitive to `symbols-with-pos-enabled`.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp--eq-symbols-with-pos-enabled): New test.
* lisp/emacs-lisp/byte-opt.el (byte-opt--nary-comparison):
Fix a typo causing miscompilation of code such as (OP X),
where OP is <, >, <=, >= or =.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-tests--test-cases): Add test case.
Reported by Richard Copley.
While at it, rework the code so as not to rely on an
intermediate rewriting of (funcall (lambda ..) ...)
to ((lambda ..) ...) since that forms is deprecated.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-funcall): Unfold lambdas
instead of turning them into the deprecated ((lambda ..) ..).
(byte-optimize-form-code-walker): Don't unfold ((lambda ..) ..) any more.
(byte-compile-inline-expand): Revert to non-optimized call if the unfolding
can't be optimized.
* lisp/emacs-lisp/bytecomp.el (byte-compile-form): Don't unfold
((lambda ..) ..) any more.
* lisp/emacs-lisp/cl-macs.el (cl--slet): Remove workaround.
* lisp/emacs-lisp/disass.el (disassemble): Make sure the code is
compiled with its own `lexical-binding` value.
* lisp/emacs-lisp/macroexp.el (macroexp--unfold-lambda): Make it work
both for ((lambda ..) ..) and for (funcall #'(lambda ..) ..).
Be careful not to move dynbound vars from `lambda` to `let`.
(macroexp--expand-all): Unfold (funcall #'(lambda ..) ..) instead of
turning it into ((lambda ..) ..). Don't unfold ((lambda ..) ..) any more.
Previously (+ X 0) was reduced to (+ X) which became (* X 1) in
codegen, but this is wrong for X = -0.0 and also slightly slower.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-plus): Don't reduce an
addition to (+ X) by eliminating zeros; retain one 0 argument.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test case.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Optimise closed-over values in closure creation like any other, which
can lead to stack variables being eliminated.
* lisp/emacs-lisp/byte-opt.el (byte-optimize--substitutable-p):
Allow quoted lists and conses, and vector literals, to be substituted
from lexical variables. This can eliminate variable bindings and
create new constant folding opportunities.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
((closure ...) ...) is a malformed function call; treat it as such.
Better malformed function warning location.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-funcall): Don't convert
(funcall '(lambda ...) ...) -> ((lambda ...) ...)
because that would inline what is essentially an `eval` of a
function using dynamic binding rules into lexbound code.
Since the last cdr of a non-terminal argument to `nconc` is
overwritten no matter its value:
(nconc (cons 1 2) nil) => (1)
a terminating nil arg cannot just be eliminated unconditionally.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-nconc):
Only eliminate a terminal nil arg to `nconc` if preceded by
a nonempty proper list. Right now we only bother to prove this
for `(list ...)`, so that
(nconc (list 1 2 3) nil) -> (list 1 2 3)
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-tests--test-cases): Add test cases.
Add the transforms:
(nconc) -> nil
(nconc X) -> X
and for arguments to `nconc`:
nil -> <elided>
(list X...) (list Y...) -> (list X... Y...)
(list X) Y -> (cons X Y)
* lisp/emacs-lisp/byte-opt.el (byte-optimize-nconc): New.
(byte-optimize-append): Fix minor flaws and generalise.
Move the warning about unused return values from calls to
side-effect-free functions from the source-level optimiser to the code
generator, where it can be unified with the special-purpose warning
about unused values from `mapcar`. This change also cures spurious
duplicate warnings about the same code, makes the warnings amenable to
suppression through `with-suppressed-warnings`, and now warns about
some unused values that weren't caught before.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Move warning away from here.
* lisp/emacs-lisp/byte-run.el (with-suppressed-warnings):
* lisp/emacs-lisp/bytecomp.el (byte-compile-warnings):
Doc string updates.
(byte-compile-form): Put the new warnings here.
(byte-compile-normal-call): Move mapcar warning away from here.
* lisp/emacs-lisp/bytecomp.el (byte-compile-ignore):
Compile args to `ignore` for value to avoid unused-value warnings, and
then discard the generated values immediately thereafter. Mostly this
does not affect the generated code but in rare cases it might result
in slightly worse code.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-test--with-suppressed-warnings): Adapt test.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Accept (stack-set 1) as equivalent to (discardN-preserve-tos 1) in a
rule previously overlooked. This is usually beneficial in code size
and almost always shortens dynamic paths.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Use the current for-effect mode when optimising the body form,
instead of always optimising it for value.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Add `format-message` and `substring-no-properties`.
* lisp/subr.el (number-sequence, copy-tree, looking-at-p)
(string-match-p, string-trim-right, string-lines):
Declare side-effect-free.
(syntax-class, version-list-<, version-list-=, version-list-<=)
(version-list-not-zero): Declare pure and side-effect-free.
(ensure-list): Declare side-effect-free and error-free.
(string-equal-ignore-case): Remove `pure` declaration.
We may want it to be pure but right now it's not.
This way we don't need to set these properties on aliases at all;
it was always easy to forget doing so.
* lisp/emacs-lisp/byte-opt.el (byte-opt--fget): New function.
(byte-optimize-form-code-walker, byte-optimize-form): Use it.
(side-effect-free-fns, side-effect-and-error-free-fns, pure-fns):
Remove aliases from lists, leaving only built-in functions.
Some Lisp functions still had their `side-effect-free` and `pure`
properties declared in byte-opt.el; do it at their definition instead.
The lists in byte-opt.el now only contain functions implemented in C
and function aliases.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns)
(side-effect-and-error-free-fns, pure-fns):
Remove functions whose properties are now declared elsewhere
and some obsolete entries.
* lisp/custom.el (custom-variable-p):
* lisp/emacs-lisp/lisp.el (buffer-end):
* lisp/emacs-lisp/regexp-opt.el (regexp-opt):
* lisp/env.el (getenv):
* lisp/simple.el (count-lines, mark, string-empty-p, lax-plist-get):
* lisp/subr.el (ignore, always, zerop, fixnump, bignump, lsh, last)
(eventp, mouse-movement-p, log10, memory-limit, string-greaterp)
(interactive-p):
* lisp/window.el (get-lru-window, get-largest-window, (window-edges)
(window-body-edges, window-pixel-edges, window-body-pixel-edges)
(window-absolute-pixel-edges, window-absolute-body-pixel-edges)
(one-window-p):
Declare functions `side-effect-free` and/or `pure` as appropriate.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Fix a flaw in the
dup (varset|varbind|stack-set) discard -> (varset|varbind|stack-set)
rule: don't match stack-set(1) which is dealt with elsewhere, and
generalise to discard(N).
Hoisting stack reduction ops allows them to coalesce and/or cancel out
pushing ops, and for useful operations to sink and combine, such as
not + goto-if-[not-]nil.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Add the rule
UNARY discardN-preserve-tos --> discardN-preserve-tos UNARY
where UNARY pops and pushes one value.
Generalise the rule
const discardN-preserve-tos --> discardN const
to any 0-ary op, not just const: varref, point, etc.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Make the improvements:
- Add the rule
stack-ref(X) discardN-preserve-tos(Y)
--> discard(Y) stack-ref(X-Y), X≥Y
discard(X) discardN-preserve-tos(Y-X-1), X<Y
with the usual equivalences:
stack-set(1) = discardN-preserve-tos(1)
stack-ref(0) = dup
discard(0) = discardN-preserve-tos(0) = no-op
This rule hoists stack reduction to where it is more likely to be
exploited further, may reduce the op size through smaller
immediates, and sometimes removes either or both operations
outright.
The rule is inhibited by an immediately following `return` op
because other rules will produce better code in that case.
- Add the rule
(discardN-preserve-tos|dup) OP return --> OP return
where OP is a unary operation such as `not` or `car`.
- Generalise a previous rule to
NOEFFECT PRODUCER return --> PRODUCER return
where PRODUCER is now any op that pushes a value without looking at
the stack: const, varref, point etc.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-concat):
Flatten nested forms; concat is associative. This reduces the number
of calls and may coalesce adjacent constant strings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-constant-args): Simplify.
(byte-optimize--constant-symbol-p): Speed up.
(byteopt--eval-const): New.
(byte-optimize-member, byte-optimize-concat, byte-optimize-append):
Use byteopt--eval-const instead of eval which is much slower.
* lisp/emacs-lisp/byte-opt.el (byte-after-unbind-ops):
Add discardN and discardN-preserve-tos, both of which
commute with unbind. This enables subsequent optimisations.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Remove code forcing forward motion after applying certain
transformations; these were only there to keep output identical across
refactorings.
This is a refactoring step: there is no change in how the optimiser
works.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Instead of re-using local variables through mutation, bind them at
point of use. This ensures that there is no value leakage by mistake
and actually reduces the static size of the bytecode of this function
somewhat.
The lousy variable names (tmp, tmp2 etc) are retained but
can at least now be changed into something more descriptive.