(defmethod print-object ((entry method-entry) stream)
(maybe-print-unreadable-object (entry stream :type t)
- (format stream "~A:~A"
+ (format stream "~A:~A~@[ ~S~]"
(method-entry-effective-method entry)
- (sod-class-nickname (method-entry-chain-head entry)))))
+ (sod-class-nickname (method-entry-chain-head entry))
+ (method-entry-role entry))))
(defmethod compute-sod-effective-method
((message sod-message) (class sod-class))
(subclass sod-class)
(chain-head sod-class)
(chain-tail sod-class))
- (flet ((make-entry (message)
+ (flet ((make-entries (message)
(let ((method (find message
(sod-class-effective-methods subclass)
:key #'effective-method-message)))
- (make-method-entry method chain-head chain-tail))))
+ (make-method-entries method chain-head chain-tail))))
(make-instance 'vtmsgs
:class class
:subclass subclass
:chain-head chain-head
:chain-tail chain-tail
- :entries (mapcar #'make-entry
+ :entries (mapcan #'make-entries
(sod-class-messages class)))))
;;; class-pointer
(dolist (entry (vtmsgs-entries vtmsgs))
(let* ((type (method-entry-function-type entry))
(args (c-function-arguments type))
- (method (method-entry-effective-method entry))
- (message (effective-method-message method))
(in-names nil) (out-names nil) (varargsp nil) (me "me"))
(do ((args args (cdr args)))
((endp args))
- (let* ((raw-name (argument-name (car args)))
+ (let* ((raw-name (princ-to-string (argument-name (car args))))
(name (if (find raw-name
(list "_vt"
(sod-class-nickname class)
- (sod-message-name message))
+ (method-entry-slot-name entry))
:test #'string=)
(format nil "sod__a_~A" raw-name)
raw-name)))
(format stream "#if __STDC_VERSION__ >= 199901~%"))
(format stream "#define ~A(~{~A~^, ~}) ~
~A->_vt->~A.~A(~{~A~^, ~})~%"
- (message-macro-name class message)
+ (message-macro-name class entry)
(nreverse in-names)
me
(sod-class-nickname class)
- (sod-message-name message)
+ (method-entry-slot-name entry)
(nreverse out-names))
(when varargsp
(format stream "#endif~%"))))
(sequence-output (stream sequencer)
((class :vtmsgs (sod-message-class message) :slots)
(pprint-logical-block (stream nil :prefix " " :suffix ";")
- (pprint-c-type pointer-type stream (sod-message-name message)))
+ (pprint-c-type pointer-type stream (method-entry-slot-name entry)))
(terpri stream)))))
(defmethod hook-output progn ((cptr class-pointer)
(defmethod hook-output progn ((entry method-entry)
(reason (eql :c))
sequencer)
- (with-slots (method chain-head chain-tail) entry
+ (with-slots (method chain-head chain-tail role) entry
(let* ((message (effective-method-message method))
(class (effective-method-class method))
(super (sod-message-class message)))
(sequence-output (stream sequencer)
((class :vtable chain-head :vtmsgs super :slots)
(format stream " /* ~19@A = */ ~A,~%"
- (sod-message-name message)
- (method-entry-function-name method chain-head)))))))
+ (method-entry-slot-name entry)
+ (method-entry-function-name method chain-head role)))))))
;;;--------------------------------------------------------------------------
;;; Filling in the class object.
(format nil "~A__vtable_~A" class (sod-class-nickname chain-head)))
(export 'message-macro-name)
-(defun message-macro-name (class message)
- (format nil "~A_~A" class (sod-message-name message)))
+(defun message-macro-name (class entry)
+ (format nil "~A_~A" class (method-entry-slot-name entry)))
;;;----- That's all, folks --------------------------------------------------
effective method out into its own function.")
(defmethod method-entry-function-name
- ((method effective-method) (chain-head sod-class))
+ ((method effective-method) (chain-head sod-class) role)
(let* ((class (effective-method-class method))
(message (effective-method-message method))
(message-class (sod-message-class message)))
(if (or (not (slot-boundp method 'functions))
(slot-value method 'functions))
- (format nil "~A__mentry_~A__~A__chain_~A"
- class
+ (format nil "~A__mentry~@[__~(~A~)~]_~A__~A__chain_~A"
+ class role
(sod-class-nickname message-class)
(sod-message-name message)
(sod-class-nickname chain-head))
0)))
+(defmethod method-entry-slot-name ((entry method-entry))
+ (let* ((method (method-entry-effective-method entry))
+ (message (effective-method-message method))
+ (name (sod-message-name message))
+ (role (method-entry-role entry)))
+ (method-entry-slot-name-by-role entry role name)))
+
(defmethod method-entry-function-type ((entry method-entry))
(let* ((method (method-entry-effective-method entry))
(message (effective-method-message method))
- (type (sod-message-type message)))
+ (type (sod-message-type message))
+ (tail (ecase (method-entry-role entry)
+ ((nil) (sod-message-argument-tail message)))))
(c-type (fun (lisp (c-type-subtype type))
("me" (* (class (method-entry-chain-tail entry))))
- . (sod-message-argument-tail message)))))
-
-(defmethod make-method-entry ((method basic-effective-method)
- (chain-head sod-class) (chain-tail sod-class))
- (make-instance 'method-entry
- :method method
- :chain-head chain-head
- :chain-tail chain-tail))
+ . tail))))
+
+(defmethod make-method-entries ((method basic-effective-method)
+ (chain-head sod-class)
+ (chain-tail sod-class))
+ (let ((entries nil)
+ (message (effective-method-message method)))
+ (flet ((make (role)
+ (push (make-instance 'method-entry
+ :method method :role role
+ :chain-head chain-head
+ :chain-tail chain-tail)
+ entries)))
+ (make nil)
+ entries)))
(defmethod compute-method-entry-functions ((method basic-effective-method))
(emit-inst codegen (make-va-end-inst *sod-ap*)))
(finish-entry (tail)
(let* ((head (sod-class-chain-head tail))
- (name (method-entry-function-name method head))
+ (name (method-entry-function-name method head nil))
(type (c-type (fun (lisp return-type)
("me" (* (class tail)))
. entry-args))))
(chain-head :initarg :chain-head :type sod-class
:reader method-entry-chain-head)
(chain-tail :initarg :chain-tail :type sod-class
- :reader method-entry-chain-tail))
+ :reader method-entry-chain-tail)
+ (role :initarg :role :type (or :keyword null) :reader method-entry-role))
(:documentation
"An entry point into an effective method.
- Specifically, this is the entry point to the effective method METHOD
- invoked via the vtable for the chain headed by CHAIN-HEAD. The CHAIN-TAIL
- is the most specific class on this chain; this is useful because we can
- reuse the types of method entries from superclasses on non-primary chains.
+ Specifically, this is the entry point to the effective METHOD invoked via
+ the vtable for the chain headed by CHAIN-HEAD, and serving the given ROLE.
+ The CHAIN-TAIL is the most specific class on this chain; this is useful
+ because we can reuse the types of method entries from superclasses on
+ non-primary chains.
Each effective method may have several different method entries, because
an effective method can be called via vtables attached to different
job of the method entry to adjust the instance pointers correctly for the
rest of the effective method.
+ A vtable can contain more than one entry for the same message. Such
+ entries are distinguished by their roles. A message always has an entry
+ with the `nil role. No other roles are currently defined, though they may
+ be introduced by extensions.
+
The boundaries between a method entry and the effective method
is (intentionally) somewhat fuzzy. In extreme cases, the effective method
may not exist at all as a distinct entity in the output because its
content is duplicated in all of the method entry functions. This is left
up to the effective method protocol."))
-(export 'make-method-entry)
-(defgeneric make-method-entry (effective-method chain-head chain-tail)
+(export 'make-method-entries)
+(defgeneric make-method-entries (effective-method chain-head chain-tail)
(:documentation
- "Return a METHOD-ENTRY for an EFFECTIVE-METHOD called via CHAIN-HEAD.
+ "Return a list of `method-entry' objects for an EFFECTIVE-METHOD called
+ via CHAIN-HEAD.
There is no default method for this function. (Maybe when the
effective-method/method-entry output protocol has settled down I'll know
(:documentation
"Return the C function type for a method entry."))
+(export 'method-entry-slot-name)
+(defgeneric method-entry-slot-name (entry)
+ (:documentation
+ "Return the `vtmsgs' slot name for a method entry.
+
+ The default method indirects through `method-entry-slot-name-by-role'."))
+
+(defgeneric method-entry-slot-name-by-role (entry role name)
+ (:documentation "Easier implementation for `method-entry-slot-name'.")
+ (:method ((entry method-entry) (role (eql nil)) name) name))
+
(export 'effective-method-basic-argument-names)
(defgeneric effective-method-basic-argument-names (method)
(:documentation
(return-type (c-type-subtype message-type))
(raw-args (sod-message-argument-tail message))
(arguments (if (varargs-message-p message)
- (cons (make-argument *sod-ap* (c-type va-list))
+ (cons (make-argument *sod-ap*
+ (c-type va-list))
(butlast raw-args))
raw-args)))
(codegen-push codegen)
"Returns the function name of an effective method."))
(export 'method-entry-function-name)
-(defgeneric method-entry-function-name (method chain-head)
+(defgeneric method-entry-function-name (method chain-head role)
(:documentation
"Returns the function name of a method entry.
- The method entry is given as an effective method/chain-head pair, rather
- than as a method entry object because we want the function name before
- we've made the entry object."))
+ The method entry is given as an effective method/chain-head/role triple,
+ rather than as a method entry object because we want the function name
+ before we've made the entry object."))
(export 'compute-method-entry-functions)
(defgeneric compute-method-entry-functions (method)