Chapter 19. Compiled Programs
19.1. RSUBR (the TYPE)
RSUBRs ("relocatable subroutines") are machine-language programs
written to run in the MDL environment. They are usually produced by
the MDL assembler (often from output produced by the compiler)
although this is not necessary. All RSUBRs have two components: the
"reference vector" and the "code vector". In some cases the code
vector is in pure storage. There is also a set of "fixups" associated
with every RSUBR, although it may not be available in the running
MDL.
19.2. The Reference Vector
An RSUBR is basically a VECTOR that has been CHTYPEd to TYPE
RSUBR via the SUBR RSUBR (see below). This ex-VECTOR is the
reference vector. The first three elements of the reference vector
have predefined meanings:
- The first element is of
TYPECODEorPCODEand is the impure or pure code vector respectively. - The second element is an
ATOMand specifies the name of theRSUBR. - The third element is of
TYPEDECLand declares the type/structure of theRSUBR's arguments and result.
The rest of the elements of the reference vector are objects in
garbage-collected storage that the RSUBR needs to reference and any
impure slots that the RSUBR needs to use.
When the RSUBR is running, one of the PDP-10 accumulators (with
symbolic name R) is always pointing to the reference vector, to
permit rapid access to the various elements.
19.3. RSUBR Linking
RSUBRs can call any APPLICABLE object, all in a uniform manner. In
general, a call to an F/SUBR is linked up at assembly/compile time so
that the calling instruction (UUO) points directly at the code in the
interpreter for the F/SUBR. However, the locations of most other
APPLICABLEs are not known at assembly/compile time. Therefore, the
calling UUO is set up to point at a slot in the reference vector (by
indexing off accumulator R). This slot initially contains the ATOM
whose G/LVAL is the called object. The calling mechanism (UUO handler)
causes control to be transferred to the called object and, depending
on the state of the RSUBR-link flag, the ATOM will be replaced by
its G/LVAL. (If the call is of the "quick" variety, the called RSUBR
or RSUBR-ENTRY will be CHTYPEd to a QUICK-RSUBR or
QUICK-ENTRY, respectively, before replacement.) Regardless of the
RSUBR-link flag's state, calls to FUNCTIONs are never permanently
linked. A call to a non-Subroutine generates an extra FRAME, whose
FUNCT is the dummy ATOM CALLER.
RSUBRs are linked together for faster execution, but linking may not
be desirable if the RSUBRs are being debugged, and various revisions
are being re-loaded. A linked call will forever after go to the same
code, regardless of the current G/LVAL of the called ATOM. Thus,
while testing RSUBRs, you may want to disable linking, by calling
the RSUBR-LINK SUBR with a FALSE argument. Calling it with a
non-FALSE argument enables linking thereafter. It returns the
previous state of the link flag, either T or #FALSE (). Calling it
with no argument returns the current state.
19.4. Pure and Impure Code
The first element of an RSUBR is the code vector, of TYPE CODE
or PCODE. TYPE CODE is of PRIMTYPE UVECTOR, and the UTYPE
should be of PRIMTYPE WORD. The code vector is simply a block of
words that are the instructions which comprise the RSUBR. Since the
code vector is stored just like a standard UVECTOR, it will be moved
around by the garbage collector. Therefore, all RSUBR code is
required to be location-insensitive. The compiler guarantees the
location-insensitivity of its output. The assembler helps to make the
code location-insensitive by defining all labels as offsets relative
to the beginning of the code vector and causing instructions that
refer to labels to index automatically off the PDP-10 accumulator
symbolically named M. M, like R, is set up by the UUO handler,
but it points to the code vector instead of the reference vector. The
code vector of an RSUBR can be frozen (using the FREEZE SUBR) to
prevent it from moving during debugging by DDT in the superior
operating-system process.
If the first element of an RSUBR is of TYPE PCODE ("pure code"),
the code vector of the RSUBR is pure and sharable. TYPE PCODE is
of PRIMTYPE WORD. The left half of the word specifies an offset
into an internal table of pure RSUBRs, and the right half specifies
an offset into the block of code where this RSUBR starts. The
PCODE prints out as:
%<PCODE name:string offset:fix>
where name names the entry in the user's pure-RSUBR table, and
offset is the offset. (Obviously, PCODE is also the name of a
SUBR, which generates a pure code vector.) Pure RSUBRs may also
move around, but only by being included in MDL's page map at different
places. Once again M can be used exactly as before to do
location-independent address referencing. Individual pure code vectors
can be "unmapped" (marked as being not in primary storage but in their
original pure-code disk files) if the space in storage allocated for
pure code is exhausted. An unmapped RSUBR is mapped in again
whenever needed. All pure RSUBRs are unmapped before a SAVE file
is written, so that the code is not duplicated on disk. A purified
RSUBR must use RGLOC ("relative GLOC") instead of GLOC. RGLOC
produces objects of TYPE LOCR instead of LOCD.
19.5. TYPE-C and TYPE-W
In order to handle user NEWTYPEs reasonably, the internal TYPE
codes for them have to be able to be different from one MDL run to
another. Therefore, references to the TYPE codes must be in the
reference vector rather than the code vector. To help handle this
problem, two TYPEs exist, TYPE-C ("type code") and TYPE-W ("type
word"), both of PRIMTYPE WORD. They print as:
%<TYPE-C type primtype:atom>
%<TYPE-W type primtype:atom>
The SUBR TYPE-C produces an internal TYPE code for the type,
and TYPE-W produces a prototype "TYPE word" (appendix 1) for an
object of that TYPE. The primtype argument is optional, included
only as a check against the call to NEWTYPE. TYPE-W can also take
a third argument, of PRIMTYPE WORD, whose right half is included
in the generated "TYPE word". If type is not a valid TYPE, a
NEWTYPE is automatically done.
To be complete, a similar SUBR and TYPE should be mentioned here.
<PRIMTYPE-C type>
produces an internal "storage allocation code" (appendix 1) for the
type. The value is of TYPE PRIMTYPE-C, PRIMTYPE WORD. In
almost all cases the SUBR TYPEPRIM gives just as much information,
except in the case of TEMPLATEs: all TYPEs of TEMPLATEs have the
same TYPEPRIM, but they all have different PRIMTYPE-Cs.
19.6. RSUBR (the SUBR)
<RSUBR [code name decl ref ref ...]>
CHTYPEs its argument to an RSUBR, after checking it for legality.
RSUBR is rarely called other than in the MDL Assembler (Lebling,
1979). It can be used if changes must be made to an RSUBR that are
prohibited by MDL's built-in safety mechanisms. For example, if the
GVAL of name is an RSUBR:
<SET FIXIT <CHTYPE ,name VECTOR>>$
[...]
...(changes to .FIXIT)...
<SETG name <RSUBR .FIXIT>>$
#RSUBR [...]
19.7. RSUBR-ENTRY
RSUBRs can have multiple entry points. An RSUBR-ENTRY can be
applied to arguments exactly like an RSUBR.
<RSUBR-ENTRY [rsubr-or-atom name:atom decl] offset:fix>
returns the VECTOR argument CHTYPEd to an RSUBR-ENTRY into the
rsubr at the specified offset. If the RSUBR-ENTRY is to have a
DECL (RSUBR style), it should come as shown.
<ENTRY-LOC rsubr-entry>
("entry location") returns the offset into the RSUBR of this
entry.
19.8. RSUBRs in Files
There are three kinds of files that can contain RSUBRs, identified
by second names BINARY, NBIN and FBIN. There is nothing magic
about these names, but they are used by convention.
A BINARY file is a completely ASCII file containing complete impure
RSUBRs in character representation. Even a code vector appears as
#CODE followed by a UVECTOR of PRIMTYPE WORDs. BINARY files
are generally slow to load, because of all the parsing that must be
done.
An NBIN file contains a mixture of ASCII characters and binary code.
The start of a binary portion is signalled to READ by the character
control-C, so naive readers of an NBIN file under ITS may
incorrectly assume that it ends before any binary code appears. An
NBIN file cannot be edited with a text editor. An RSUBR is written
in NBIN format by being PRINTed on a "PRINTB" CHANNEL. The
RSUBRs in NBIN files are not purified either.
An FBIN file is actually part of a triad of files. The FBIN
file(s) itself is the impure part of a collection of purified
RSUBRs. It is simply ASCII and can be edited at will. (Exception: in
the ITS and Tops-20 versions, the first object in the file should not
be removed or changed in any way, lest a "grim reaper" program for
FBIN files think that the other files in the triad are obsolete and
delete them.) The pure code itself resides (in the ITS and Tops-20
versions) in a special large file that contains all currently-used
pure code, or (in the Tenex version) in a file in a special disk
directory with first name the same as the name argument to PCODE
for the RSUBR. The pure-code file is page-mapped directly into MDL
storage in read-only mode. It can be unmapped when the pure storage
must be reclaimed, and it can be mapped at a different storage address
when pure storage must be compacted. There is also a "fixup" file (see
below) or portion of a file associated with the FBIN to round out
the triad.
An initial MDL can have pure RSUBRs in it that were "loaded" during
the initialization procedure. The files are not page-mapped in until
they are actually needed. The "loading" has other side effects, such
as the creation of OBLISTs (chapter 15). Exactly what is pre-loaded
is outside the scope of this document.
19.9. Fixups
The purpose of "fixups" is to correct references in the RSUBR to
parts of the interpreter that change from one release of MDL to the
next. The reason the fixups contain a release number is so that they
can be completely ignored when an RSUBR is loaded into the same
release of MDL as that from which it was last written out.
There are three forms of fixups, corresponding to the three kinds of
RSUBR files. ASCII RSUBRs, found in BINARY files, have ASCII
fixups. The fixups are contained in a LIST that has the following
format:
(MDL-release:fix
name:atom value:fix (use:fix use:fix ...)
name:atom value:fix (use:fix use:fix ...)
...)
The fixups in NBIN files and the fixup files associated with FBIN
files are in a fast internal format that looks like a UVECTOR of
PRIMTYPE WORDs.
Fixups are usually discarded after they are used during the loading
procedure. However, if, while reading a BINARY or NBIN file the
ATOM KEEP-FIXUPS!- has a non-FALSE LVAL, the fixups will be
kept, via an association between the RSUBR and the ATOM RSUBR.
It should be noted that, besides correcting the code, the fixups
themselves are corrected when KEEP-FIXUPS is bound and true. Also,
the assembler and compiler make the same association when they first
create an RSUBR, so that it can be written out with its fixups.
In the case of pure RSUBRs (FBIN files), things are a little
different. If a pure-code file exists for this release of MDL, it is
used immediately, and the fixups are completely ignored. If a
pure-code file for this release doesn't exist, the fixup file is used
to create a new copy of the file from an old one, and also a new
version of the fixup file is created to go with the new pure-code
file. This all goes on automatically behind the user's back.