/* c-globals-tbl.c
*
* COPYRIGHT (c) 1992 by AT&T Bell Laboratories.
*
* This implements a registry of global C symbols that may be referenced
* in the ML heap (e.g., references to C functions).
*/
#include "ml-base.h"
#include "tags.h"
#include "ml-values.h"
#include "c-globals-tbl.h"
#define MAKE_EXTERN(index) MAKE_DESC(index, DTAG_extern)
#define HASH_STRING(name, res) { \
const char *__cp = (name); \
int __hash = 0, __n; \
for (; *__cp; __cp++) { \
__n = (128*__hash) + (unsigned)*__cp; \
__hash = __n - (8388593 * (__n / 8388593)); \
} \
(res) = __hash; \
}
typedef struct item { /* An item in the Symbol/Addr tables */
ml_val_t addr; /* The address of the external reference */
const char *name; /* The name of the reference */
int stringHash; /* The hash sum of the name */
struct item *nextSymb; /* The next item the SymbolTable bucket */
struct item *nextAddr; /* The next item the AddrTable bucket */
} item_t;
typedef struct item_ref { /* an item in an export table */
item_t *item;
int index;
struct item_ref *next;
} item_ref_t;
struct export_table { /* A table of C symbols mapping strings to items, */
/* which is used when loading a heap image. */
item_ref_t **table;
int tableSize;
int numItems;
item_t **itemMap; /* A map from item #s to items */
int itemMapSize;
};
/* hash key to index */
#define STRHASH_INDEX(h, sz) ((h) & ((sz)-1))
#define ADDRHASH_INDEX(a, sz) (((Word_t)(a) >> 3) & ((sz)-1))
PVT item_t **SymbolTable = NIL(item_t **); /* Maps names to items */
PVT item_t **AddrTable = NIL(item_t **); /* Maps addresses to items */
PVT int TableSize = 0; /* The size of the tables; always */
/* power of 2. */
PVT int NumSymbols = 0; /* The number of entries in the tables */
/* local routines */
PVT void GrowTable (export_table_t *tbl);
/* RecordCSymbol:
*
* Enter a global C symbol into the tables.
*/
void RecordCSymbol (const char *name, ml_val_t addr)
{
int n, i, hash;
item_t *item, *p;
ASSERT ((((Word_t)addr & ~TAG_boxed) & TAG_desc) == 0);
if (TableSize == NumSymbols) {
/* double the table size */
int newTblSz = (TableSize ? 2*TableSize : 64);
item_t **newSTbl = NEW_VEC(item_t *, newTblSz);
item_t **newATbl = NEW_VEC(item_t *, newTblSz);
memset ((char *)newSTbl, 0, sizeof(item_t *) * newTblSz);
memset ((char *)newATbl, 0, sizeof(item_t *) * newTblSz);
for (i = 0; i < TableSize; i++) {
for (p = SymbolTable[i]; p != NIL(item_t *); ) {
item = p;
p = p->nextSymb;
n = STRHASH_INDEX(item->stringHash, newTblSz);
item->nextSymb = newSTbl[n];
newSTbl[n] = item;
}
for (p = AddrTable[i]; p != NIL(item_t *); ) {
item = p;
p = p->nextAddr;
n = ADDRHASH_INDEX(item->addr, newTblSz);
item->nextAddr = newATbl[n];
newATbl[n] = item;
}
}
if (SymbolTable != NIL(item_t **)) {
FREE (SymbolTable);
FREE (AddrTable);
}
SymbolTable = newSTbl;
AddrTable = newATbl;
TableSize = newTblSz;
}
/* compute the string hash function */
HASH_STRING(name, hash);
/* Allocate the item */
item = NEW_OBJ(item_t);
item->name = name;
item->stringHash = hash;
item->addr = addr;
/* insert the item into the symbol table. */
n = STRHASH_INDEX(hash, TableSize);
for (p = SymbolTable[n]; p != NIL(item_t *); p = p->nextSymb) {
if ((p->stringHash == hash) && (strcmp(name, p->name) == 0)) {
if (p->addr != addr)
Die ("global C symbol \"%s\" defined twice", name);
else {
FREE (item);
return;
}
}
}
item->nextSymb = SymbolTable[n];
SymbolTable[n] = item;
/* insert the item into the addr table. */
n = ADDRHASH_INDEX(addr, TableSize);
for (p = AddrTable[n]; p != NIL(item_t *); p = p->nextAddr) {
if (p->addr == addr) {
if ((p->stringHash != hash) || (strcmp(name, p->name) != 0))
Die ("address %#x defined twice: \"%s\" and \"%s\"",
addr, p->name, name);
else {
FREE (item);
return;
}
}
}
item->nextAddr = AddrTable[n];
AddrTable[n] = item;
NumSymbols++;
} /* end of RecordCSymbol */
/* AddrToCSymbol:
*
* Return the name of the C symbol that labels the given address
* (or NIL).
*/
const char *AddrToCSymbol (ml_val_t addr)
{
item_t *q;
/* Find the symbol in the AddrTable */
for (q = AddrTable[ADDRHASH_INDEX(addr, TableSize)];
q != NIL(item_t *);
q = q->nextAddr)
{
if (q->addr == addr)
return q->name;
}
return NIL(const char *);
} /* end of AddrToCSymbol */
/* NewExportTbl:
*/
export_table_t *NewExportTbl ()
{
export_table_t *tbl;
tbl = NEW_OBJ(export_table_t);
tbl->table = NIL(item_ref_t **);
tbl->tableSize = 0;
tbl->numItems = 0;
tbl->itemMap = NIL(item_t **);
tbl->itemMapSize = 0;
return tbl;
} /* end of NewExportTbl */
/* ExportCSymbol:
*
* Add an external address to an export table, returning its external reference
* descriptor.
*/
ml_val_t ExportCSymbol (export_table_t *tbl, ml_val_t addr)
{
Addr_t a = PTR_MLtoADDR(addr);
item_ref_t *p;
item_t *q;
int h, index;
/*SayDebug("ExportCSymbol: addr = %#x, ", addr);*/
if (tbl->numItems >= tbl->tableSize)
GrowTable (tbl);
/* First check to see if addr is already in tbl */
h = ADDRHASH_INDEX(a, tbl->tableSize);
for (p = tbl->table[h]; p != NIL(item_ref_t *); p = p->next) {
if (p->item->addr == addr) {
/*SayDebug("old name = \"%s\", index = %d\n", p->item->name, p->index);*/
return MAKE_EXTERN(p->index);
}
}
/* Find the symbol in the AddrTable */
for (q = AddrTable[ADDRHASH_INDEX(a, TableSize)]; q != NIL(item_t *); q = q->nextAddr) {
if (q->addr == addr)
break;
}
if (q == NIL(item_t *)) {
Error("external address %#x not registered\n", addr);
return ML_unit;
}
/* Insert the index into the address to index map. */
/*SayDebug("new name = \"%s\", index = %d\n", q->name, tbl->numItems);*/
index = tbl->numItems++;
if (tbl->itemMapSize <= index) {
int newSz = ((tbl->itemMapSize == 0) ? 64 : 2*tbl->itemMapSize);
item_t **newMap = NEW_VEC(item_t *, newSz);
int i;
for (i = 0; i < tbl->itemMapSize; i++)
newMap[i] = tbl->itemMap[i];
if (tbl->itemMap != NIL(item_t **))
FREE (tbl->itemMap);
tbl->itemMap = newMap;
tbl->itemMapSize = newSz;
}
tbl->itemMap[index] = q;
/* Insert the address into the export table */
p = NEW_OBJ(item_ref_t);
p->item = q;
p->index = index;
p->next = tbl->table[h];
tbl->table[h] = p;
return MAKE_EXTERN(index);
} /* end of ExportCSymbol */
/* AddrOfCSymbol:
*
* Given an external reference, return its address.
*/
ml_val_t AddrOfCSymbol (export_table_t *tbl, ml_val_t xref)
{
int index;
index = GET_LEN(xref);
/*SayDebug("AddrOfCSymbol: %#x: %d --> %#x\n", xref, index, tbl->itemMap[index]->addr);*/
if (index >= tbl->numItems)
Die ("bad external object index %d", index);
else
return tbl->itemMap[index]->addr;
} /* end of AddrOfCSymbol */
/* ExportedSymbols:
*/
void ExportedSymbols (export_table_t *tbl, int *numSymbs, export_item_t **symbs)
{
int i, n = tbl->numItems;
item_t **p;
export_item_t *ep;
*numSymbs = n;
*symbs = ep = NEW_VEC(export_item_t, n);
for (p = tbl->itemMap, i = 0; i < n; i++) {
*ep = (*p)->name;
p++; ep++;
}
} /* end of ExportedSymbols */
/* FreeExportTbl:
*
* Free the storage used by a import/export table.
*/
void FreeExportTbl (export_table_t *tbl)
{
int i;
item_ref_t *p, *q;
for (i = 0; i < tbl->tableSize; i++) {
for (p = tbl->table[i]; p != NIL(item_ref_t *); ) {
q = p->next;
FREE (p);
p = q;
}
}
if (tbl->itemMap != NIL(item_t **))
FREE (tbl->itemMap);
FREE (tbl);
} /* end of FreeExportTbl */
/* ImportCSymbol:
*/
ml_val_t ImportCSymbol (const char *name)
{
int hash, index;
item_t *p;
HASH_STRING(name, hash);
/* insert the item into the symbol table. */
index = STRHASH_INDEX(hash, TableSize);
for (p = SymbolTable[index]; p != NIL(item_t *); p = p->nextSymb) {
if ((p->stringHash == hash) && (strcmp(name, p->name) == 0)) {
return (p->addr);
}
}
return ML_unit;
} /* end of ImportCSymbol */
/* ExportTableSz:
*
* Return the number of bytes required to represent the strings in an exported
* symbols table.
*/
Addr_t ExportTableSz (export_table_t *tbl)
{
int i;
Addr_t nbytes;
for (nbytes = 0, i = 0; i < tbl->numItems; i++) {
nbytes += (strlen(tbl->itemMap[i]->name) + 1);
}
nbytes = ROUNDUP(nbytes, WORD_SZB);
return nbytes;
} /* end of ExportTableSz */
/* GrowTable:
*/
PVT void GrowTable (export_table_t *tbl)
{
int newTblSz = (tbl->tableSize ? 2 * tbl->tableSize : 32);
item_ref_t **newTbl = NEW_VEC(item_ref_t *, newTblSz);
int i, n;
item_ref_t *p, *q;
memset ((char *)newTbl, 0, newTblSz * sizeof(item_ref_t *));
for (i = 0; i < tbl->tableSize; i++) {
for (p = tbl->table[i]; p != NIL(item_ref_t *); ) {
q = p;
p = p->next;
n = ADDRHASH_INDEX(q->item->addr, newTblSz);
q->next = newTbl[n];
newTbl[n] = q;
}
}
if (tbl->table != NIL(item_ref_t **)) FREE (tbl->table);
tbl->table = newTbl;
tbl->tableSize = newTblSz;
} /* end of GrowTable */
syntax highlighted by Code2HTML, v. 0.9.1