Go to the first, previous, next, last section, table of contents.

Message dispatching

This section explains how messages can be dispatched, i.e. how the implementation of a method can be invoked, given the message.

A method is translated by the compiler to a C function with essentially the same arguments as the method, with two mandatory additions and some additions depending on the return type of the method. For the method

(boolean, Any) next

defined for the instance tom.Enumerator, the C function implementing this is

i_tom_Enumerator__or__next (tom_object self, selector cmd,
                            tom_object *ret1)

As can be seen, the first element of the tuple return type is the type returned by the implementation C function. Such a function always has two `implicit' first arguments: self being the object receiving the message, and cmd being the message sent. Following these two are the `normal' arguments to the method, which are none in this case. Finally, any of the remaining return values are to be returned in the pointer arguments supplied after the normal arguments. In the example, a pointer for returning the second tuple element is provided.

A message is dispatched by invoking the method implementation for the given (self, cmd) pair. The lookup of the implementation, i.e. the pointer to the C function, can be done in three different ways:

Call the function trt_lookup with the receiver and the selector to be invoked (i.e. the values to be passed for self and cmd). trt_lookup returns a function pointer to the method implementation. Invoke that function with the arguments.
A direct lookup is equivalent to inlining the trt_lookup function. This is a rather unwise way of invoking a method as it considerably increases code size.
When using trt_send to dispatch a message, the function trt_send is invoked with all the arguments to be passed to the method implementation. trt_send will perform the lookup and jump directly to the implementation.

These different dispatching mechanisms can be selected by an option to otmc. They are described here for explanatory purposes; never implement any of these directly in your C code; the next section explains how to do that portably.

Sending is the preferred way of dispatching messages, though possibly not present on all TOM implementations as it involves an assembly language routine. Also note that there are dependencies of the applicability of some dispatching mechanisms. For example, it is impossible to use sending on dynamically loaded code on hppa-hpux machines. This is not a TOM feature but due to the interspace stubs needed by the hpux shared library interspace calls, added to the fact that a callee stores the return program counter in the stack frame of the caller.

When doing profiling on a TOM program, all code should really use the lookup way of dispatching instead of sending to dispatch. Otherwise, all methods will be reported to only invoke trt_send, and trt_send will be reported as the culprit which invoked every method and thus effectively void the use of the call graph.

Go to the first, previous, next, last section, table of contents.