From mboxrd@z Thu Jan 1 00:00:00 1970 From: Scott Christley To: egcs@cygnus.com Subject: GCC/ObjC enhancements, comments requested Date: Sat, 07 Feb 1998 18:11:00 -0000 Message-id: X-SW-Source: 1998-02/msg00274.html PORTABLE DYNAMIC INVOCATION Enhance GCC so that it can correctly perform dynamic invocation of C functions, more properly the call instruction for the processor, on any GCC supported platform. Currently GCC attempts to provide this capability through the builtin_apply family of functions. However, the current implementation is insufficient because it does not take the return/argument types and the architecture specific stack/register loading into account. This capability is essential to the portability and feasibility of ObjC for any GCC supported platform. This document details enhancements to be made to the GCC compiler and the ObjC runtime library. Implementation details are provided if possible otherwise the interface for the functionality is provided. There are two parts; the first part consists of modifications to the GCC backend to correct the deficiencies of the current implementation, and the second part consists of additional ObjC classes added to the ObjC runtime library which provide an object-oriented interface to the GCC compiler backend implementation. GCC backend support As stated before, the current implementation in the GCC backend is deficient. What needs to be determined is exactly how much functionality is to be provided versus functionality that can be delegated to front-end languages or users. In order to properly perform a dynamic call instruction this information must be known: * type information for the arguments and return value. * allocation information for loading the stack and register with argument and return values. * A memory address where the call instruction is to transfer execution. The type information cannot be known by the GCC backend a-priori, so the user is required to supply this information; likewise, the memory address must also be supplied by the user. The allocation information can be constructed based upon the type information for the arguments and return value, but calls which have the identical type information will also have the same allocation information, so its possible to calculate this information once and cache it so that subsequent calls just retrieve the information from the cache. At this point in time, the GCC backend will not provide caching capability; instead, user (front-end languages) must provide this if so desired. So the proposal is to add three builtin functions. This function is given a type string and pointers to two buffers where it will store its output. The function will traverse through the type string and for each argument store a 0 (zero), if the argument is passed in a register, or a 1 (one), if the argument is passed on the stack, into buffer; if the argument is passed on the stack then the stack size will be stored into sizes. The type string uses the encoding characters as defined by the ObjC runtime library; the first character representing the return value with the additional characters representing the arguments. void builtin_allocation(char *types, int *buffer, int *sizes); This function is given a type string and returns the type information in internal GCC format. tree builtin_convert_type(char *types); This function is similar to the existing builtin_apply function except that it has two additional argument; one which contains type information, in internal GCC format, for the arguments and return value, and the other which is a two element array that points to register/stack allocation information. static rtx builtin_perform (rtx function, rtx arguments, rtx argsize, tree types, int *allocation[2]); ObjC Runtime Library Support The ObjC runtime library will provide an interface to the GCC backend implementation through a set of ObjC classes. The initial design of these classes was taken from the OpenStep specification, but they have been significantly modified to provide invocation of normal C functions as well as ObjC methods. Class Hierarchy Object Invocation MethodInvocation InvocationSignature MethodSignature An Invocation is a call instruction, like a C function, rendered static. An Invocation contains all the elements of a call instruction: a call pointer, arguments, and the return value. Each of these elements can be set directly, and the return value is set automatically when the Invocation is dispatched. An Invocation can be repeatedly dispatched; its arguments can be modified between dispatch for varying results; even its call pointer can be changed to another with the same invocation signature (argument and return types). This makes it useful for repeating messages with many arguments and variations; rather than retyping a slightly different expression for each message, you modify the Invocation as needed each time before dispatching it to a new target. @interface Invocation + (Invocation *)invocationWithSignature:(InvocationSignature *)signature; - (void *)callPointer; - (void)getArgument:(void *)buffer atIndex:(int)index; - (void)getReturnValue:(void *)buffer; - (void)invoke; - (InvocationSignature *)signature; - (void)setArgument:(void *)buffer atIndex:(int)index; - (void)setCallPointer:(void *)pointer; - (void)setReturnValue:(void *)buffer; @end A MethodInvocation is a subclass of Invocation which is specifically for ObjC methods. A MethodInvocation requires a selector to be specified versus a call pointer, and a target object which will receive the ObjC method invocation. Like Invocation, a MethodInvocation can be repeatedly dispatched; allowing its arguments, target object, and selector to changed; the selector can only be changed to one with the same MethodSignature. @interface MethodInvocation + (MethodInvocation *)methodInvocationWithSignature:(MethodSignature *)signature; - (void)getArgument:(void *)buffer atIndex:(int)index; - (void)getReturnValue:(void *)buffer; - (void)invoke; - (void)invokeWithTarget:(id)anObject; - (MethodSignature *)signature; - (SEL)selector; - (void)setArgument:(void *)buffer atIndex:(int)index; - (void)setReturnValue:(void *)buffer; - (void)setSelector:(SEL)selector; - (void)setTarget:(id)anObject; - (id)target; @end An InvocationSignature records type information for the arguments and return value of an invocation. It is then used to create an Invocation, which can be assigned values for the call pointer and the arguments, An InvocationSignature presents its argument types by index with the getArgumentTypeAtIndex: method. In addition to the argument types, an invocationSignature offers the total number of arguments with numberOfArguments, the total stack frame length occupied by all arguments with frameLength (this varies with hardware architecture), and the length and type of the return value with methodReturnLength and methodReturnType. @interface InvocationSignature -(const char *)getArgumentTypeAtIndex:(unsignedint)index; - (unsigned int)frameLength; - (unsigned int)returnLength; - (char *)returnType; - (unsigned int)numberOfArguments @end A MethodSignature records type information for the arguments and return value of an ObjC method. It's used to forward messages that the receiving object doesn't respond tomost notably in the case of distributed objects. A MethodSignature is typically created using Object's methodSignatureForSelector: instance method. It's then used to create an Invocation, which is passed as the argument to a forwardInvocation: message to send the invocation on to whatever other object can handle the message. In the default case, Object invokes doesNotRecognizeSelector:, which generates an error. For distributed objects, the Invocation is encoded using the information in the MethodSignature and sent to the real object represented by the receiver of the message. A MethodSignature presents two additional hidden arguments for every ObjC method, self and _cmd, which are at indices 0 and 1 respectively. The arguments normally specified in a invocation follow these. Applications using distributed objects can determine if the method is asynchronous with the isOneway method. @interface MethodSignature -(const char *)getArgumentTypeAtIndex:(unsignedint)index; - (unsigned int)frameLength; - (BOOL)isOneway - (unsigned int)returnLength; - (char *)returnType; - (unsigned int)numberOfArguments @end To support the signature/invocation classes within the ObjC runtime library, a number of methods are added to the root class, Object. @interface Object - (MethodSignature *)methodSignatureForSelector:(SEL)selector; - (void)forwardInvocation:(MethodInvocation *)invocation; @end