The task of a stub compiler is to translate an interface definition into presentation conversion routines. These routines are required to translate data values from a machine-internal format into a format suitable for network transmission at the sender (marshalling, and to do the reverse conversion at the receiver (unmarshalling).
An interface definition contains declarations of the data types that an application exchanges over a network. Type definitions consist of primitive types (e.g. integer, real, string ) and composed types (e.g. struct, array, union). Consequently, the presentation conversion code generated by a stub compiler contains two types of code, namely code dealing with converting primitive types, and code dealing with converting composite types.
The code dealing with primitive types handles format conversions such as translating between ASCII and EBCDIC character sets, byteswapping for integers or floating point format conversion. These conversions are done by specialized algorithms.Optimizations are specific to the particular algorithm, and not treated in this paper.
The paper focuses on optimizing the code for converting composite types, referred to as control code. This code has two purposes, linearisation and realignment. Linearisation is required for data structures stored in non-contiguous memory sections, such as dynamically allocated tree structures. Realignment is required for components of a record or a struct type. Different CPUs may use different conventions for positioning these fields in main memory.
The control code of presentation conversion routines can be implemented using three alternative implementation techniques: interpreted code, procedure-driven code (also referred to as compiled code) and inlined code.
With interpreted code, the stub compiler translates a composite type into a set of commands, one for each component. To convert a particular data value, these commands are interpreted by a generic routine. The advantage of using interpretation is compact. The disadvantage is slow execution speed. In our measurements, throughput of interpreted routines was as low as 3.1 Mbit/s.
With procedure-driven code, the stub compiler translates each type declaration into a procedure. This procedure contains procedure calls for converting the components of the composite type, interspersed by control code that depends on the type constructor. Since procedure driven code eliminates interpretation overhead, it is faster. We measured speed-up factors between 1.6 to 5.7 when replacing interpreted code by procedure-driven code. However, procedure-driven code can significantly increase the code size. Our measurements show a size increase by a factor of 4 to 7 when changing from interpreted code to procedure-driven code.
With inlined code, the stub compiler replaces the procedure calls in procedure-driven code with the body of the procedure that is called. Inlining leads to another improvement in execution speed, but also to a very large increase in code size. Extending the techniques developed in this paper to also handle inlining is relatively straightforward. Inlining is thus not further treated in this paper, and the reader is referred to (Hoschka, 1995) for the details of a solution.