diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index f2411d44862..247e2f0900f 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -606,12 +606,9 @@ In use by the back-end." (defun comp--func-unique-in-cu-p (func) "Return t if FUNC is known to be unique in the current compilation unit." (if (symbolp func) - (cl-loop with h = (make-hash-table :test #'eq) - for f being the hash-value in (comp-ctxt-funcs-h comp-ctxt) - for name = (comp-func-name f) - when (gethash name h) - return nil - do (puthash name t h) + (cl-loop for f being the hash-value in (comp-ctxt-funcs-h comp-ctxt) + count (eq func (comp-func-name f)) into n + when (> n 1) return nil finally return t) t)) diff --git a/test/src/comp-resources/comp-test-direct-call-dup.el b/test/src/comp-resources/comp-test-direct-call-dup.el new file mode 100644 index 00000000000..09f8d843325 --- /dev/null +++ b/test/src/comp-resources/comp-test-direct-call-dup.el @@ -0,0 +1,41 @@ +;;; comp-test-direct-call-dup.el --- test direct calls with duplicate names -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Free Software Foundation, Inc. + +;; 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 of the License, 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. If not, see . + +;;; Commentary: + +;; Test that a duplicated function name only suppresses direct calls +;; to that name, not to other unique functions in the same CU. +;; See `comp--func-unique-in-cu-p'. + +;;; Code: + +;; Duplicate name -- calls to this should NOT be direct. +(defun comp-tests-dup-f (x) (1+ x)) +(defun comp-tests-dup-f (x) (+ x 2)) + +;; Unique callee. +(defun comp-tests-unique-f (x) (* x 2)) + +;; Call to unique callee -- should be a direct call. +(defun comp-tests-calls-unique-f (x) (comp-tests-unique-f x)) + +;; Call to ambiguous callee -- should NOT be a direct call. +(defun comp-tests-calls-dup-f (x) (comp-tests-dup-f x)) + +;;; comp-test-direct-call-dup.el ends here diff --git a/test/src/comp-resources/comp-test-direct-call.el b/test/src/comp-resources/comp-test-direct-call.el new file mode 100644 index 00000000000..f6717f6d60a --- /dev/null +++ b/test/src/comp-resources/comp-test-direct-call.el @@ -0,0 +1,42 @@ +;;; comp-test-direct-call.el --- compilation unit tested by comp-tests.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Free Software Foundation, Inc. + +;; 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 of the License, 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. If not, see . + +;;; Commentary: + +;; Test that anonymous lambdas in a compilation unit don't prevent +;; direct calls between named functions at speed 3. +;; See `comp--func-unique-in-cu-p'. + +;;; Code: + +(defun comp-tests-direct-call-callee-f (x) + (1+ x)) + +(defun comp-tests-direct-call-caller-f (x) + (comp-tests-direct-call-callee-f x)) + +;; Two anonymous lambdas -- these must not prevent direct calls +;; between the named functions above. +(defvar comp-tests-direct-call-list1 + (mapcar (lambda (x) (1+ x)) '(1 2 3))) + +(defvar comp-tests-direct-call-list2 + (mapcar (lambda (x) (1- x)) '(1 2 3))) + +;;; comp-test-direct-call.el ends here diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el index fad71c282af..a4186dba7ba 100644 --- a/test/src/comp-tests.el +++ b/test/src/comp-tests.el @@ -1612,4 +1612,50 @@ folded." t) (native-compile #'comp-tests-type-branch-optim-1-f))) +(defun comp-tests-has-direct-call-p (func-name) + "Return non-nil if FUNC-NAME contains a direct call instruction." + (cl-some + #'identity + (comp-tests-map-checker + func-name + (lambda (insn) + (or (comp-tests-mentioned-p 'direct-call insn) + (comp-tests-mentioned-p 'direct-callref insn)))))) + +(comp-deftest direct-call-with-lambdas () + "Check that anonymous lambdas don't prevent direct calls at speed 3. +See `comp--func-unique-in-cu-p'." + (let ((native-comp-speed 3) + (comp-post-pass-hooks + '((comp--final + (lambda (_) + (should (comp-tests-has-direct-call-p + 'comp-tests-direct-call-caller-f))))))) + (load (native-compile + (ert-resource-file "comp-test-direct-call.el"))) + (declare-function comp-tests-direct-call-caller-f nil) + (should (native-comp-function-p + (symbol-function 'comp-tests-direct-call-caller-f))) + (should (= (comp-tests-direct-call-caller-f 3) 4)))) + +(comp-deftest direct-call-with-duplicate-names () + "Check that duplicate names only block their own direct calls. +See `comp--func-unique-in-cu-p'." + (let ((native-comp-speed 3) + (comp-post-pass-hooks + '((comp--final + (lambda (_) + ;; Call to unique callee: SHOULD use direct call. + (should (comp-tests-has-direct-call-p + 'comp-tests-calls-unique-f)) + ;; Call to ambiguous callee: should NOT. + (should-not (comp-tests-has-direct-call-p + 'comp-tests-calls-dup-f))))))) + (load (native-compile + (ert-resource-file "comp-test-direct-call-dup.el"))) + (declare-function comp-tests-calls-unique-f nil) + (should (native-comp-function-p + (symbol-function 'comp-tests-calls-unique-f))) + (should (= (comp-tests-calls-unique-f 3) 6)))) + ;;; comp-tests.el ends here