Therefore, SPIN provides the externalized reference utility. Externalized references are a means of associating an integer value with a Modula-3 pointer. This integer value can then be passed to and from user-level applications without violating any language restrictions.
Externalized reference associations usually occur on a per-application basis, but one can be instantiated by any kernel entity.
Currently, each Space.T is instantiated with externalized reference facilities. Spaces are statically linked extensions which support user-level address spaces.
When externalizing a reference, clients may specify an index into the mapping table. If that table entry is in use, the old reference will be overwritten. If the client does not specify an index, an unused index is automatically chosen.
Access to capabilities stored in an externalized reference table is controlled by the entity which holds the table. For instance, with the current Space.T implementation, holding a capability to the Space.T also allows access to the externalized reference table through methods provided by the Space.i3 interface.
An in-kernel reference can be externalized many times. Ideally, to keep the size of the table manageable and efficient, a reference should not appear twice in the same table. That is, when externalizing a reference, it should first be determined that an existing Word.T externalized reference cannot be used.
An efficient way to perform this check would be a reverse table lookup. The Modula-3 Table generic does not provide a reverse lookup method. Therefore, a reverse table can be maintained for each externalalized reference table. However, the reverse table evaluates hash functions on REFANY types. If the Modula-3 garbage collector then moves the referent and updates the REFANY, the hash function would evaluate differently. Modula-3 strongrefs and weakrefs are used to defeat this problem.
IMPORT Foo, ExternalRef;
...
PROCEDURE ExampleOfExternalization(myExternTable: ExternalRef.T; ...) ...
VAR
fooref: REF Foo.T := NEW(REF Foo.T);
extref: Word.T;
...
BEGIN
...
extref := ExternalRef.Externalize(myExternTable, fooref);
...
END ExampleOfExternalization;
Similarly, Internalize() returns a REFANY which can be narrowed into the appropriate type:
IMPORT Foo, ExternalRef;
...
PROCEDURE ExampleOfInternalization(myExternTable: ExternalRef.T;
extref: Word.T;
... ) ...
VAR
fooref: REF Foo.T;
...
BEGIN
...
fooref := NARROW(ExternalRef.Interalize(myExternTable, extref), REF Foo.T);
...
END ExampleOfInteralization;
ddion@cs.washington.edu