Node: Alternate Entry Points, Next: , Previous: Adjustable Arrays, Up: Debugging and Interfacing

Alternate Entry Points (ENTRY)

The GBE does not understand the general concept of alternate entry points as Fortran provides via the ENTRY statement. g77 gets around this by using an approach to compiling procedures having at least one ENTRY statement that is almost identical to the approach used by f2c. (An alternate approach could be used that would probably generate faster, but larger, code that would also be a bit easier to debug.)

Information on how g77 implements ENTRY is provided for those trying to debug such code. The choice of implementation seems unlikely to affect code (compiled in other languages) that interfaces to such code.

g77 compiles exactly one public procedure for the primary entry point of a procedure plus each ENTRY point it specifies, as usual. That is, in terms of the public interface, there is no difference between



     ENTRY Y

The difference between the above two cases lies in the code compiled for the X and Y procedures themselves, plus the fact that, for the second case, an extra internal procedure is compiled.

For every Fortran procedure with at least one ENTRY statement, g77 compiles an extra procedure named __g77_masterfun_x, where x is the name of the primary entry point (which, in the above case, using the standard compiler options, would be x_ in C).

This extra procedure is compiled as a private procedure--that is, a procedure not accessible by name to separately compiled modules. It contains all the code in the program unit, including the code for the primary entry point plus for every entry point. (The code for each public procedure is quite short, and explained later.)

The extra procedure has some other interesting characteristics.

The argument list for this procedure is invented by g77. It contains a single integer argument named __g77_which_entrypoint, passed by value (as in Fortran's %VAL() intrinsic), specifying the entry point index--0 for the primary entry point, 1 for the first entry point (the first ENTRY statement encountered), 2 for the second entry point, and so on.

It also contains, for functions returning CHARACTER and (when -ff2c is in effect) COMPLEX functions, and for functions returning different types among the ENTRY statements (e.g. REAL FUNCTION R() containing ENTRY I()), an argument named __g77_result that is expected at run time to contain a pointer to where to store the result of the entry point. For CHARACTER functions, this storage area is an array of the appropriate number of characters; for COMPLEX functions, it is the appropriate area for the return type; for multiple-return-type functions, it is a union of all the supported return types (which cannot include CHARACTER, since combining CHARACTER and non-CHARACTER return types via ENTRY in a single function is not supported by g77).

For CHARACTER functions, the __g77_result argument is followed by yet another argument named __g77_length that, at run time, specifies the caller's expected length of the returned value. Note that only CHARACTER*(*) functions and entry points actually make use of this argument, even though it is always passed by all callers of public CHARACTER functions (since the caller does not generally know whether such a function is CHARACTER*(*) or whether there are any other callers that don't have that information).

The rest of the argument list is the union of all the arguments specified for all the entry points (in their usual forms, e.g. CHARACTER arguments have extra length arguments, all appended at the end of this list). This is considered the "master list" of arguments.

The code for this procedure has, before the code for the first executable statement, code much like that for the following Fortran statement:

            GOTO (100000,100001,100002), __g77_which_entrypoint
     100000 ...code for primary entry point...
     100001 ...code immediately following first ENTRY statement...
     100002 ...code immediately following second ENTRY statement...

(Note that invalid Fortran statement labels and variable names are used in the above example to highlight the fact that it represents code generated by the g77 internals, not code to be written by the user.)

It is this code that, when the procedure is called, picks which entry point to start executing.

Getting back to the public procedures (x and Y in the original example), those procedures are fairly simple. Their interfaces are just like they would be if they were self-contained procedures (without ENTRY), of course, since that is what the callers expect. Their code consists of simply calling the private procedure, described above, with the appropriate extra arguments (the entry point index, and perhaps a pointer to a multiple-type- return variable, local to the public procedure, that contains all the supported returnable non-character types). For arguments that are not listed for a given entry point that are listed for other entry points, and therefore that are in the "master list" for the private procedure, null pointers (in C, the NULL macro) are passed. Also, for entry points that are part of a multiple-type- returning function, code is compiled after the call of the private procedure to extract from the multi-type union the appropriate result, depending on the type of the entry point in question, returning that result to the original caller.

When debugging a procedure containing alternate entry points, you can either set a break point on the public procedure itself (e.g. a break point on X or Y) or on the private procedure that contains most of the pertinent code (e.g. __g77_masterfun_x). If you do the former, you should use the debugger's command to "step into" the called procedure to get to the actual code; with the latter approach, the break point leaves you right at the actual code, skipping over the public entry point and its call to the private procedure (unless you have set a break point there as well, of course).

Further, the list of dummy arguments that is visible when the private procedure is active is going to be the expanded version of the list for whichever particular entry point is active, as explained above, and the way in which return values are handled might well be different from how they would be handled for an equivalent single-entry function.