The SpecialObj interface defines the network object runtime {\it 
   special object}.  This object provides methods for maintenance 
   of the per-space agent export table (see NetObj.i3) as well as 
   methods to support object marshalling and garbage collection.  
   There is one such concrete object per address space instance.  
   In addition, there are potentially many special object surrogates 
   used to invoke corresponding methods in different address spaces. 
   
INTERFACEASpecialObj ; IMPORT NetObj, Fingerprint, SpaceID, StubLib, Transport, Thread, WireRep; TYPE FpTower = REF ARRAY OF Fingerprint.T;
Fingerprint is a hashed representation of a Modula-3 type. 
   Every network object type can be represented by such a hash. The 
   hash function must yield uniform results across all network object 
   clients.  An FpTower is an ordered list of Fingerprint which 
   represents the type hierarchy for a single network object.  Each list 
   is ordered from subtype to supertype.  The fingerprint of the common
   supertype NetObj.T is omitted, but implied. 
VersionList = ARRAY OF StubLib.StubProtocol;A
VersionList is an array of StubLib.StubProtocol.  For any given
   surrogate type, there may be multiple stub instances corresponding to
   compilations under different stub compilers.  Similarly, an object
   owner may support dispatchers for several stub protocol version.
   Items of the type FpTower are always accompanied by a VersionList.
   The general scheme for attributing stub versions to the elements of a
   FpTower is as follows:
       let fp be a FpTower;
       let ver be a set of pairs
               (StubLib.StubProtocol,INTEGER);
       for any element ver(v,n):
           version v stubs exist for fp[i] where n <= i
   We adopt a more restrictive scheme where ver is simply an
   array of StubLib.StubProtocol.  This corresponds exactly to
   the general form where n is always zero.
   The effect of this is that the stub versions appearing in ver
   apply to all the elements of fp.  However, stub versions that don't
   exist for fp[0] will not appear in the representation.
   For example, if a server has stubs for (A, v1) and (AB, v2), then
   then v1 stubs will not be accessible for AB objects.
   For a version list ver, if ver[i] = StubLib.NullStubProtocol, then
   ver[j] = StubLib.NullStubProtocol where j >= i.
EventID = ARRAY [0..1] OF StubLib.Int32; (* lsw..msw *)An
EventID is a monotonically increasing value which identifies 
   events communicated between a client's garbage collector and the 
   object owners for which that client hold surrogates.  This value 
   serves to serialize calls which otherwise might arrive and be 
   processed asynchronously. 
CleanElem = RECORD wrep: WireRep.T; id: EventID; END; CleanBatch = ARRAY OF CleanElem;A
CleanBatch is a list of wire representations which refer to
   network objects to be marked clean.  It is used only in the
   ST.clean: call below.  Each wrep is tagged with an EventID
   to logically serialize calls to dirty and clean according to
   the order in which they were generated. 
   
CONST DefaultBatchLen = 50;
TYPE
  ST = NetObj.T OBJECT METHODS
    get(name: TEXT) : NetObj.T
      RAISES {NetObj.Error, Thread.Alerted};
    put(name: TEXT; obj: NetObj.T)
      RAISES {NetObj.Error, Thread.Alerted};
    getAdr(sp: SpaceID.T): NetObj.Address
      RAISES {NetObj.Error, Thread.Alerted};
    dirty(
      wrep: WireRep.T; eventID: EventID;
      VAR (*OUT*) vers: VersionList;
      loc: Transport.Location := NIL): FpTower
      RAISES {NetObj.Error, Thread.Alerted};
    clean(
      READONLY batch: CleanBatch; strong: BOOLEAN := FALSE;
      loc: Transport.Location := NIL)
      RAISES {NetObj.Error, Thread.Alerted};
  END;
 The special object ST for each address space instance implements
   an agent table describing a set of exported objects.  The get
   method performs a table lookup and returns the object registered
   under name, or NIL is there isn't one.  The put method
   registers obj in the table under name, overwriting any existing
   entry.
   Each address space contains a table holding a NetObj.Address 
   for itself and for every other address space for which it has any
   surrogates.  getAdr performs a lookup in this table and returns
   the result.  This is used by the object unmarshalling code to
   construct a Transport.Location to the object owner if no such
   location exists.
   
   The dirty method is used to inform the object owner of the 
   existence of a surrogate with wire representation wrep at the 
   address space whose local garbage collector is identified by 
   loc.  The caller must tag each call with a unique and 
   monotonically increasing eventID.  Dirty calls must possess a 
   more recent eventID than the most recent one attributed to wrep 
   and loc by the object owner.  Otherwise the call is considered 
   out-of-date and is ignored.  The loc argument is always defaulted 
   during surrogate invocations and is supplied by the server stub 
   during concrete method invocation.  loc is required so that the 
   liveness of the surrogate's address space can be monitored.
   The dirty call uses the out parameter vers to return a subset of
   the stub protocol versions supported by the object owner for the
   object class of wrep.  If the result array is too small, the owner
   will choose which elements to omit.  If the result array is too large,
   empty slots will be filled with the value StubLib.NullStubProtocol.
   
   The clean method notifies an object owner that a surrogate for
   wrep no longer exists at loc.  The batch argument is an
   array of [wrep, eventID] tuples.  As with dirty, each
   wrep, is tagged with an eventID, and this eventID must be
   the most recent id received by the owner for wrep and loc. 
   The loc argument is always defaulted during surrogate invocations
   and is supplied by the server stub during concrete method invocation.
   If clean fails due to communication problems, it must be retried
   with strong = TRUE until it is determined that such attempts will
   never succeed, for instance because it is determined that the communication
   problem is permanent.
 
TYPE Surrogate <: ST;
 Surrogate is the type of surrogate special objects. 
PROCEDURE New(loc: Transport.Location) : ST;
 New returns a surrogate for the concrete special object at the
   target address space of loc. 
END SpecialObj.