1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 04:10:18 +02:00
guile/module/oop/goops/compile.scm
Andy Wingo e177058bc4 don't re-enter the compiler during method dispatch
* libguile/goops.c (scm_make): In the pre-inst `make', default
  `procedure' to #f, and read a `make-procedure' instead of
  `compile-env'.

* libguile/goops.h (scm_si_make_procedure): This instead of
  scm_si_compile_env.

* module/oop/goops.scm (make-method): Remove this unused function. Users
  should use (make <method> ...) directly.
  (method): Capture `make-procedure' instead of `procedure' in the case
  that the body calls a next-method. Allows for the kind of
  "recompilation" that we were using before, but with closures instead of
  re-entering the compiler. Type-specific compilation is still
  interesting, but probably should be implemented in another way.
  (initialize): Default #:procedure to #f, and
  s/compile-env/make-procedure/.

* module/oop/goops/compile.scm (code-table-lookup): Just return the
  cmethod, not the entry -- since the entry is now just (append types
  cmethod).
  (compile-make-procedure): New procedure, returns a form that, when
  evaluated/compiled, will yield a procedure of one argument, the
  next-method. When called with a next-method, the procedure returns an
  actual method implementation. compile-make-procedure returns #f if the
  body doesn't call next-method.
  (compile-method): Unify to always return procedures. Much cleaner and
  *much* faster in the compiled case. In the interpreted case, there
  might be a slight slowdown, but if there is one it should be slight.

* module/oop/goops/dispatch.scm (method-cache-install!): Adapt to removal
  of compute-entry-with-cmethod.
2009-02-13 23:30:20 +01:00

108 lines
4.1 KiB
Scheme
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;; Copyright (C) 1999, 2001, 2006 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 2.1 of the License, or (at your option) any later version.
;;;;
;;;; This library 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
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;;;;
;; There are circularities here; you can't import (oop goops compile)
;; before (oop goops). So when compiling, make sure that things are
;; kosher.
(eval-case ((compile-toplevel) (resolve-module '(oop goops))))
(define-module (oop goops compile)
:use-module (oop goops)
:use-module (oop goops util)
:export (compute-cmethod compile-make-procedure)
:no-backtrace
)
;;;
;;; Method entries
;;;
(define code-table-lookup
(letrec ((check-entry (lambda (entry types)
(if (null? types)
(and (not (struct? (car entry)))
entry)
(and (eq? (car entry) (car types))
(check-entry (cdr entry) (cdr types)))))))
(lambda (code-table types)
(cond ((null? code-table) #f)
((check-entry (car code-table) types))
(else (code-table-lookup (cdr code-table) types))))))
(define (compute-cmethod methods types)
(or (code-table-lookup (slot-ref (car methods) 'code-table) types)
(let* ((method (car methods))
(cmethod (compile-method methods types))
(entry (append types cmethod)))
(slot-set! method 'code-table
(cons entry (slot-ref method 'code-table)))
cmethod)))
;;;
;;; Compiling next methods into method bodies
;;;
;;; So, for the reader: there basic idea is that, given that the
;;; semantics of `next-method' depend on the concrete types being
;;; dispatched, why not compile a specific procedure to handle each type
;;; combination that we see at runtime. There are two compilation
;;; strategies implemented: one for the memoizer, and one for the VM
;;; compiler.
;;;
;;; In theory we can do much better than a bytecode compilation, because
;;; we know the *exact* types of the arguments. It's ideal for native
;;; compilation. A task for the future.
;;;
;;; I think this whole generic application mess would benefit from a
;;; strict MOP.
;;; Temporary solution---return #f if x doesn't refer to `next-method'.
(define (next-method? x)
(and (pair? x)
(or (eq? (car x) 'next-method)
(next-method? (car x))
(next-method? (cdr x)))))
;; Called by the `method' macro in goops.scm.
(define (compile-make-procedure formals specializers body)
(and (next-method? body)
(let ((next-method-sym (gensym " next-method"))
(args-sym (gensym)))
`(lambda (,next-method-sym)
(lambda ,formals
(let ((next-method (lambda ,args-sym
(if (null? ,args-sym)
,(if (list? formals)
`(,next-method-sym ,@formals)
`(apply
,next-method-sym
,@(improper->proper formals)))
(apply ,next-method-sym ,args-sym)))))
,@(if (null? body)
'((begin))
body)))))))
(define (compile-method methods types)
(let ((make-procedure (slot-ref (car methods) 'make-procedure)))
(if make-procedure
(make-procedure
(if (null? methods)
(lambda args
(no-next-method (method-generic-function (car methods)) args))
(compute-cmethod (cdr methods) types)))
(method-procedure (car methods)))))