/* begincopyright
  Copyright (c) 1988 Xerox Corporation. All rights reserved.
  Use and copying of this software and preparation of derivative works based
  upon this software are permitted. Any distribution of this software or
  derivative works must comply with all applicable United States export
  control laws. This software is made available AS IS, and Xerox Corporation
  makes no warranty about the software, its performance or its conformity to
  any specification. Any person obtaining a copy of this software is requested
  to send their name and post office or electronic mail address to:
    PCR Coordinator
    Xerox PARC
    3333 Coyote Hill Rd.
    Palo Alto, CA 94304
  endcopyright */

/*
 * IncrementalLoadPrivate.h
 *
 * Private data structures and procedures used by Incremental Loader
 *   and by object file readers.
 *
 * Demers, January 23, 1990 2:48:16 pm PST
 */

#ifndef ←XR←INCREMENTAL←LOAD←PRIVATE←
#define ←XR←INCREMENTAL←LOAD←PRIVATE← 1

#ifndef ←XR←INCREMENTAL←LOAD←
#include "xr/IncrementalLoad.h"
#endif

#ifndef ←XR←PZONE←
#include "xr/PZone.h"
#endif

#ifndef ←XR←THREADS←
#include "xr/Threads.h"
#endif

#ifndef ←XR←UIO←
#include "xr/UIO.h"
#endif

/*
 * debugging stuff ...
 */

#define XR←IL←ASSERT 1

#if defined(XR←IL←ASSERT)
    extern void XR←Panic(/* char *msg */);
#   define XR←ILAssert(p,m) { if(!(p)) XR←Panic((m)); }
#else
#   define XR←ILAssert(p,m) {}
#endif



/*
 * Setup proc -- called prior to forking VPs and IOPs
 */

extern void
XR←SetupIncrementalLoader();


/* ??? should be part of GC interface ??? */

typedef void (*XR←GCRootCallback)(/*
    XR←Seg seg,
    XR←Pointer data
*/);

typedef void (*XR←GCRootEnumerator)(/*
    XR←GCRootCallback rootCallback,
    XR←Pointer rootCallbackData,
    XR←Pointer rootEnumeratorData
*/);

/* ??? end of GC stuff ??? */

/*
 * Private initialization state ...
 */

typedef enum {
    ilis←initial = 0,
    ilis←allocated = 1,
    ilis←internalizing = 2,
    ilis←internalized = 3,
    ilis←last = 0x7fffffff
} XR←ILInitializationState;


/*
 * Registration data
 */


typedef enum XR←ILOpRep {
    ilOpNone = 0,
    ilOpInternalize = 1,	/* internalize boot file symbols */
    ilOpLoad = 2,		/* load a file */
    ilOpCommit = 3,		/* commit load */
    ilOpAbort = 4,		/* abort load */
    ilOpError = 0x7fffffff	/* (32 bits) */
} XR←ILOp;


typedef void (*XR←ILReaderProc)(/*struct XR←ILSymTabRep *ilst*/);
/*
    expects ilst->ilst←opArg, ilst->ilst←ilfteArg
    sets ilst->ilst←result
*/


typedef struct XR←ILRegistrationRep {
    /* link in registration list */
        struct XR←ILRegistrationRep * ilr←next;
    /* object file reader proc (see below) */
        XR←ILReaderProc ilr←proc;
        XR←Pointer ilr←data;
    /* magic numbers this proc can interpret */
        int ilr←nMagics;
        unsigned ilr←magics[/* ilr←nMagics */ 1];
} * XR←ILRegistration;

#define XR←ILRegistrationBytes(nm) \
	( sizeof(struct XR←ILRegistrationRep) + ((nm)-1) * sizeof(unsigned) )


/*
 * IL file table entry
 *
 * Allocated in ILSymTab ilst←zone.
 */

typedef struct XR←ILFileTabEntryRep {
    /* public part ... */
        struct XR←ILFileEntryRep ilfte←ilfe;
    /* reader responsible for this file */
        XR←ILRegistration ilfte←ilr;
        XR←Pointer ilfte←readerPrivateState;
    /* PZone revert data for commit points ... */
        char * ilfte←revertCookie;
        char * ilfte←revertCookiePtrFree;
    /* GC root enumeration data */
        XR←GCRootEnumerator ilfte←gcRootEnumerator;
        XR←Pointer ilfte←gcRootEnumeratorData;
    /* -> next-most-recently-allocated ilfte ... */
        struct XR←ILFileTabEntryRep * ilfte←prev;
} * XR←ILFileTabEntry;


/*
 * Relocation item
 *
 * Allocated in ILSymTab ilst←zonePerCommit; could be pointer-free if desired.
 *
 * A list of these hangs from each undefined symbol; they are processed
 *   and removed after the symbol's value has been determined.
 *
 * This is good enough for SPARC, VAX, 68K machines.
 * We may need to extend it for other architectures.
 */

typedef struct XR←ILRelocItemRep {
    /* forward pointer */
       struct XR←ILRelocItemRep * ilri←next;
    /* proc to be called with symbol's val when determined ...	*/
    /* (parameters 'addr', 'type', 'addend' are	not interpreted	*/
    /* by this package, just passed along.) 			*/
        void (*ilri←proc)(/*
            char *addr,
            unsigned type,
            long addend,
            unsigned val
        */);
        char *ilri←addr;
        unsigned ilri←type;
        long ilri←addend;
} * XR←ILRelocItem;


/*
 * Symbol table entry
 *
 * Allocated in ILSymTab ilst←zonePtrFree.
 */

typedef struct XR←ILSymTabEntryRep {
    /* public data */
        struct XR←ILSymEntryRep ilste←ilse;
        XR←ILRelocItem ilste←ilri;
    /* hash table structure (case-insensitive index by name) */
        unsigned ilste←hash;
        struct XR←ILSymTabEntryRep *ilste←symNext;
    /* skip list structure (index by value) */
        unsigned ilste←height;
        struct XR←ILSymTabEntryRep *ilste←valNext[/* height */ 1];
} * XR←ILSymTabEntry;

#define XR←ILSymTabEntryBytes(height) \
	( sizeof(struct XR←ILSymTabEntryRep) \
		+ ((height)-1) * sizeof(struct XR←ILSymTabEntryRep *) )

/*
 * Symbol table
 */

#define XR←MAX←IL←FILE←DATA 16


typedef struct XR←ILSymTabRep {
    /* lock */
        struct XR←MLRep ilst←ml;
        struct XR←CVRep ilst←avail;
        bool ilst←locked;
    /* state of initialization */
        XR←ILInitializationState ilst←initializationState;
    /* zones */
        XR←PZone ilst←zonePerFile; /* freed after each file is loaded */
        XR←PZone ilst←zonePerCommit; /* freed after each commit */
        XR←PZone ilst←zone; /* not freed, but reverted on abort */
        XR←PZone ilst←zonePtrFree; /* not freed, but reverted on abort */
    /* registration data */
        XR←ILRegistration ilst←registrations;
    /* file table */
        unsigned ilst←seqNum;
        XR←ILFileTabEntry ilst←ilfte;
    /* state of current incremental load */
        /* result code for most recent operation */
            XR←ILError ilst←result;
        /* new symbols (loaded but but not yet committed) */
            XR←ILSymTabEntry ilst←newSymsHd;
            XR←ILSymTabEntry ilst←newSymsTl;
            unsigned ilst←numUndefined;
            XR←ILSymTabEntry ilst←undefinedSymsHdCache;
        /* readSymbolsOnly is TRUE forinternalizing PCR itself */
            bool ilst←readSymbolsOnly;
        /* cached callbacks used during incremental load */
            XR←ILContinueAction (*ilst←activeRefProc)(/*
                char *sym,
                XR←ILSymEntry ilseOld,
                void *clientData
            */);
            char *ilst←activeRefClientData;
            XR←ILContinueAction (*ilst←activeDefProc)(/*
                XR←ILSymEntry ilseNew,
                XR←ILSymEntry ilseOld,
                void *clientData
            */);
            char *ilst←activeDefClientData;
            XR←ILContinueAction (*ilst←activeCommonProc)(/*
                char *sym,
                unsigned size,
                XR←ILSymEntry ilse,
                void *clientData
            */);
            char *ilst←activeCommonClientData;
            void (*ilst←activePatchSizeProc)(/*
                XR←ILFileEntry ilfe,
                void *clientData
            */);
            char *ilst←activePatchSizeClientData;
        /* fildes and reader-proc-specific data */
            XR←Fildes ilst←fd;
            XR←Pointer ilst←readerProcData;
            XR←ILOp ilst←opArg;
            XR←ILFileTabEntry ilst←ilfteArg;
            unsigned ilst←fileData[XR←MAX←IL←FILE←DATA];
    /* symbol hash table */
        unsigned ilst←numEntries;
        unsigned ilst←numHdrs;	/* must be power of 2 */
        XR←ILSymTabEntry * ilst←hdrs;
    /* value skip list */
        XR←ILSymTabEntry ilst←left;
        unsigned ilst←maxHeight;
    /* file for file-and-commons information for transform←symtab */
    /* ??? THIS OUGHT TO BE PROVIDED MORE GENERALLY ELSEWHERE ??? */
        char *ilst←infoFileName;
        XR←Fildes ilst←infoFile;
} * XR←ILSymTab;


extern XR←ILSymTab XR←ilSymTab;

/*
 * Registration proc
 */
    
extern int
XR←RegisterIncrementalLoadProc(/*
    XR←ILReaderProc proc,
    XR←Pointer data,
    int nMagics,
    unsigned *magics
*/);
/*
    Register an incremental loading proc.
    Return 0 (success), -errno (failure).
    The magic numbers `*magics' are copied, so the args may be volatile.
    The `data' value is stored in ilst->ilst←readerProcData before `proc'
      is called.

    The `proc' is complicated, and embodies all the file-format-specific
      behavior.  It is called once with `op' = load, and once more with
      `op' = commit or `op' = abort.  The commit operations are invoked
      in the order in which the files were loaded; the abort operations are
      invoked in reverse order.

    All this ought to be documented here, but isn't yet ... For an example,
      see IncrementalLoadADotOut.c.
*/


/*
 * An IncrementalLoading package that might be included as part of the
 *   boot file should export the following procedure:
 */

extern void XR←run←IncrementalLoadDEFAULT();
/*
    Called by this package to initialize default incremental loader.
    It should call XR←RegisterIncrementalLoadProc.
*/

/*
 *
 * Utilities for use by registered object file reader procs ...
 *
 * In most (but not all) cases, error results are stored in ilst->ilst←result,
 *   and are as described in IncrementalLoad.h.
 */

extern XR←ILError
XR←ILMakeError(/*
    bool fatal,
    int code,
    char * msg
*/);

extern XR←ILError
XR←ILMakeNoMemError(/*
*/);


#define XR←ILSetError(ilst,fatal,code,msg) \
	(ilst)->ilst←result = XR←ILMakeError((fatal),(code),(msg))
/*
    Set error indication in *ilst.
    The characters of *msg are copied.
*/

#define XR←ILCheckAlloc(p) \
	if( ((XR←Pointer)(p)) == NIL ) return( XR←ILMakeNoMemError() )


#define XR←ILCheckAlloc2(ilst,p) \
	if( ((XR←Pointer)(p)) == NIL ) { \
		(ilst)->ilst←result = XR←ILMakeNoMemError(); \
		return; }
/*
    Check if result of an allocation is NIL, return error if so.
*/


extern void
XR←ILGetOpenFile(/*
    XR←ILSymTab ilst
*/);
/*
    Check that the descriptor in ilst->ilst←fd is open (>= 0).
    If necessary, open the file named in ilst->ilst←ilfteActive.
    If this fails, set ilst->ilst←result appropriately.
*/

extern void
XR←ILRead(/*
    XR←ILSymTab ilst,
    unsigned offset,
    char *buf,
    unsigned bytes,
    bool abort
*/);
/*
    Read the current file as specified.
    The fOffset field in the pcfe will be added to offset before reading.
    If this fails, set ilst->ilst←result from XR←GetErrno(), with the
      sign negative iff abort is TRUE.
*/



extern void
XR←ILAllocSegments(/*
    XR←ILSymTab ilst,
    unsigned tBytes,
    unsigned dBytes,
    unsigned bBytes
*/);
/*
    Allocate storage for text, data, bss, and patch segments.
    Fill in the address and size fields of ilst←ilfteActive.
    Note: the common segment is allocated at commit time.
*/


extern unsigned
XR←ILHashFromSym(/*
    char *sym
*/);
/*
    Hash function used by procs below ...
      case-insensitive!
*/


extern XR←ILSymTabEntry
XR←ILSetSymDefined(/*
    XR←ILSymTable ilst,
    char *sym,
    unsigned hash,
    unsigned type,
    unsigned value,
    unsigned size
*/);
/*
    Record a definition of given symbol in file currently being loaded.
    Return the symbol table entry.
    The characters of `*sym' are not copied, and symbol table entries are
      pointer-free, so *sym should be allocated in a permanent place;
      this is generally ilst←zonePtrFree.
    The size argument may be zero, meaning "unknown."
    This may call the redefinedProc associated with the active incremental
      load, which may return ilca←abort(msg).  In this case, XR←ILSetSymDefined
      returns NIL immediately.
*/


extern XR←ILSymTabEntry
XR←ILSetSymCommon(/*
    XR←ILSymTable ilst,
    char *sym,
    unsigned hash,
    unsigned size
*/);
/*
    Record a common symbol in file currently being loaded.
    Return the symbol table entry.
    The characters of `*sym' are not copied, and symbol table entries are
      pointer-free, so *sym should be allocated in a permanent place;
      this is generally ilst←zonePtrFree.
    This may call the oldCommonProc associated with the active incremental
      load, which may return ilca←useOldCommon or ilca←abort(msg).  In the
      abort case, XR←ILSetSymCommon returns NIL immediately.
*/


extern XR←ILSymTabEntry
XR←ILSetSymReferenced(/*
    XR←ILSymTable ilst,
    char *sym,
    unsigned hash,
*/);
/*
    Record an (external) reference to a given symbol from the file currently
      being loaded.
    The characters of `*sym' are not copied, and symbol table entries are
      pointer-free, so *sym should be allocated in a permanent place;
      this is generally ilst←zonePtrFree.
    Return the symbol table entry.
    This may call the undefinedProc associated with the active incremental
      load.  A result of FALSE from that proc will set ilst->ilst←result
      and return NIL immediately.
*/


extern void
XR←ILRelocate(/*
    XR←ILSymTab ilst,
    XR←ILSymTabEntry ilste,
    void (*proc)(
        char *addr,
        unsigned relocType, long addend, unsigned val
    ),
    char *addr,
    unsigned relocType,
    long addend
*/);
/*
    Process a relocation reference to an undefined external symbol described by
      ilste.
    The proc, addr, relocType and addend parameters are as in an
      XR←ILRelocItem structure; the proc will be called once when (if)
      the external symbol becomes defined.  (This may be immediately!)
    May fail and set ilst->ilst←result.
*/


extern void
XR←ILSetGCRootEnumerator(/*
    XR←ILSymTab ilst,
    XR←ILFileTabEntry ilfte,
    XR←GCRootEnumerator gcRootEnumerator,
    XR←Pointer gcRootEnumeratorData
*/);
/*
    Store the ilfte←gcRootEnumerator and ilfte←gcRootEnumeratorData fields
      carefully (so a concurrent GC doesn't get confused).

    If the reader proc doesn't call this, default root set is used.  For
      most architectures this will be entire data, bss, common segs.
*/

#endif