From 29629245a4f764aae6f6f7559c72f943d688e4f5 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 24 Mar 2020 12:50:14 +0100 Subject: [PATCH] Use new hashmap implementation for symbols --- include/asm/asm.h | 1 - include/asm/symbol.h | 8 +- src/asm/output.c | 174 +++++++++++++------------------------------ src/asm/symbol.c | 151 +++++++++++++++---------------------- 4 files changed, 115 insertions(+), 219 deletions(-) diff --git a/include/asm/asm.h b/include/asm/asm.h index 5f1bc4ef..867e3345 100644 --- a/include/asm/asm.h +++ b/include/asm/asm.h @@ -34,7 +34,6 @@ extern uint32_t unionStart[MAXUNIONS]; extern uint32_t unionSize[MAXUNIONS]; extern char tzCurrentFileName[_MAX_PATH + 1]; extern struct Section *pCurrentSection; -extern struct sSymbol *tHashedSymbols[HASHSIZE]; extern struct sSymbol *pPCSymbol; extern bool oDontExpandStrings; diff --git a/include/asm/symbol.h b/include/asm/symbol.h index d3cfb89a..2720d073 100644 --- a/include/asm/symbol.h +++ b/include/asm/symbol.h @@ -34,9 +34,7 @@ struct sSymbol { enum SymbolType type; bool isExported; /* Whether the symbol is to be exported */ bool isBuiltin; /* Whether the symbol is a built-in */ - bool isReferenced; /* Whether the symbol is referenced in a RPN expr */ struct sSymbol *pScope; - struct sSymbol *pNext; struct Section *pSection; int32_t nValue; uint32_t ulMacroSize; @@ -44,6 +42,9 @@ struct sSymbol { int32_t (*Callback)(struct sSymbol const *self); char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */ uint32_t nFileLine; /* Line where the symbol was defined. */ + + uint32_t ID; /* ID of the symbol in the object file (-1 if none) */ + struct sSymbol *next; /* Next object to output in the object file */ }; static inline bool sym_IsDefined(struct sSymbol const *sym) @@ -87,8 +88,9 @@ static inline char *sym_GetStringValue(struct sSymbol const *sym) return sym->pMacro; } +void sym_ForEach(void (*func)(struct sSymbol *, void *), void *arg); + int32_t sym_GetValue(struct sSymbol const *sym); -uint32_t sym_CalcHash(const char *s); void sym_SetExportAll(bool set); struct sSymbol *sym_AddLocalReloc(char const *tzSym); struct sSymbol *sym_AddReloc(char const *tzSym); diff --git a/src/asm/output.c b/src/asm/output.c index 449d95f4..e0eb1f0d 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -40,13 +40,6 @@ struct Patch { struct Patch *pNext; }; -struct PatchSymbol { - uint32_t ID; - struct sSymbol const *pSymbol; - struct PatchSymbol *pNext; - struct PatchSymbol *pBucketNext; /* next symbol in hash table bucket */ -}; - struct Assertion { struct Patch *patch; struct Section *section; @@ -54,29 +47,17 @@ struct Assertion { struct Assertion *next; }; -struct PatchSymbol *tHashedPatchSymbols[HASHSIZE]; -struct Section *pSectionList, *pCurrentSection; -struct PatchSymbol *pPatchSymbols; -struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols; -struct Assertion *assertions = NULL; char *tzObjectname; -/* - * Count the number of symbols used in this object - */ -static uint32_t countsymbols(void) -{ - struct PatchSymbol *pSym; - uint32_t count = 0; +/* TODO: shouldn't `pCurrentSection` be somewhere else? */ +struct Section *pSectionList, *pCurrentSection; - pSym = pPatchSymbols; - while (pSym) { - count++; - pSym = pSym->pNext; - } +/* Linked list of symbols to put in the object file */ +static struct sSymbol *objectSymbols = NULL; +static struct sSymbol **objectSymbolsTail = &objectSymbols; +static uint32_t nbSymbols = 0; /* Length of the above list */ - return count; -} +static struct Assertion *assertions = NULL; /* * Count the number of sections used in this object @@ -236,10 +217,8 @@ static void writesymbol(struct sSymbol const *pSym, FILE *f) break; case SYMTYPE_EXPORT: offset = pSym->nValue; - if (pSym->type != SYM_LABEL) - sectid = -1; - else - sectid = getsectid(pSym->pSection); + sectid = pSym->type == SYM_LABEL ? getsectid(pSym->pSection) + : -1; break; } @@ -256,58 +235,18 @@ static void writesymbol(struct sSymbol const *pSym, FILE *f) } /* - * Add a symbol to the object + * Returns a symbol's ID within the object file + * If the symbol does not have one, one is assigned by registering the symbol */ -static uint32_t nextID; - -static uint32_t addsymbol(struct sSymbol const *pSym) +static uint32_t getSymbolID(struct sSymbol *sym) { - struct PatchSymbol *pPSym, **ppPSym; - uint32_t hash; + if (sym->ID == -1) { + sym->ID = nbSymbols++; - hash = sym_CalcHash(pSym->tzName); - ppPSym = &(tHashedPatchSymbols[hash]); - - while ((*ppPSym) != NULL) { - if (pSym == (*ppPSym)->pSymbol) - return (*ppPSym)->ID; - ppPSym = &((*ppPSym)->pBucketNext); - } - - pPSym = malloc(sizeof(struct PatchSymbol)); - *ppPSym = pPSym; - - if (pPSym == NULL) - fatalerror("No memory for patchsymbol"); - - pPSym->pNext = NULL; - pPSym->pBucketNext = NULL; - pPSym->pSymbol = pSym; - pPSym->ID = nextID++; - - *ppPatchSymbolsTail = pPSym; - ppPatchSymbolsTail = &(pPSym->pNext); - - return pPSym->ID; -} - -/* - * Add all exported symbols to the object - */ -static void addexports(void) -{ - int32_t i; - - for (i = 0; i < HASHSIZE; i++) { - struct sSymbol *pSym; - - pSym = tHashedSymbols[i]; - while (pSym) { - if (pSym->isExported) - addsymbol(pSym); - pSym = pSym->pNext; - } + *objectSymbolsTail = sym; + objectSymbolsTail = &sym->next; } + return sym->ID; } static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn, @@ -330,63 +269,46 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn, break; case RPN_SYM: { - uint32_t symptr = 0; - - while ((tzSym[symptr++] = popbyte()) != 0) + for (unsigned int i = -1; (tzSym[++i] = popbyte()); ) ; + struct sSymbol *sym = sym_FindSymbol(tzSym); + uint32_t value; - struct sSymbol const *sym = sym_FindSymbol(tzSym); - - if (!sym) { - break; // TODO: wtf? - } else if (sym_IsConstant(sym)) { - uint32_t value; - - value = sym_GetConstantValue(tzSym); + if (sym_IsConstant(sym)) { writebyte(RPN_CONST); - writebyte(value & 0xFF); - writebyte(value >> 8); - writebyte(value >> 16); - writebyte(value >> 24); + value = sym_GetConstantValue(tzSym); } else { - symptr = addsymbol(sym); writebyte(RPN_SYM); - writebyte(symptr & 0xFF); - writebyte(symptr >> 8); - writebyte(symptr >> 16); - writebyte(symptr >> 24); + value = getSymbolID(sym); } + writebyte(value & 0xFF); + writebyte(value >> 8); + writebyte(value >> 16); + writebyte(value >> 24); break; } case RPN_BANK_SYM: { - struct sSymbol *sym; - uint32_t symptr = 0; - - while ((tzSym[symptr++] = popbyte()) != 0) + for (unsigned int i = -1; (tzSym[++i] = popbyte()); ) ; + struct sSymbol *sym = sym_FindSymbol(tzSym); + uint32_t value = getSymbolID(sym); - sym = sym_FindSymbol(tzSym); - if (sym == NULL) - break; - - symptr = addsymbol(sym); writebyte(RPN_BANK_SYM); - writebyte(symptr & 0xFF); - writebyte(symptr >> 8); - writebyte(symptr >> 16); - writebyte(symptr >> 24); + writebyte(value & 0xFF); + writebyte(value >> 8); + writebyte(value >> 16); + writebyte(value >> 24); break; } case RPN_BANK_SECT: { - uint16_t b; + uint8_t b; writebyte(RPN_BANK_SECT); - do { b = popbyte(); - writebyte(b & 0xFF); + writebyte(b); } while (b != 0); break; } @@ -471,32 +393,40 @@ static void writeassert(struct Assertion *assert, FILE *f) fputstring(assert->message, f); } +static void registerExportedSymbol(struct sSymbol *symbol, void *arg) +{ + (void)arg; + if (symbol->isExported && symbol->ID == -1) { + *objectSymbolsTail = symbol; + objectSymbolsTail = &symbol->next; + nbSymbols++; + } +} + /* * Write an objectfile */ void out_WriteObject(void) { FILE *f; - struct PatchSymbol *pSym; struct Section *pSect; struct Assertion *assert = assertions; - addexports(); - f = fopen(tzObjectname, "wb"); if (!f) err(1, "Couldn't write file '%s'", tzObjectname); + /* Also write exported symbols that weren't written above */ + sym_ForEach(registerExportedSymbol, NULL); + fprintf(f, RGBDS_OBJECT_VERSION_STRING, RGBDS_OBJECT_VERSION_NUMBER); fputlong(RGBDS_OBJECT_REV, f); - fputlong(countsymbols(), f); + fputlong(nbSymbols, f); fputlong(countsections(), f); - pSym = pPatchSymbols; - while (pSym) { - writesymbol(pSym->pSymbol, f); - pSym = pSym->pNext; + for (struct sSymbol const *sym = objectSymbols; sym; sym = sym->next) { + writesymbol(sym, f); } pSect = pSectionList; diff --git a/src/asm/symbol.c b/src/asm/symbol.c index abe9a6c1..6b18ed3e 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -28,10 +29,12 @@ #include "extern/err.h" +#include "hashmap.h" #include "helpers.h" #include "version.h" -struct sSymbol *tHashedSymbols[HASHSIZE]; +HashMap symbols; + static struct sSymbol *pScope; /* Current section symbol scope */ struct sSymbol *pPCSymbol; static struct sSymbol *p_NARGSymbol; @@ -48,6 +51,26 @@ static char SavedMINUTE[3]; static char SavedSECOND[3]; static bool exportall; +struct ForEachArgs { + void (*func)(struct sSymbol *, void *); + void *arg; +}; + +static void forEachWrapper(void *_symbol, void *_argWrapper) +{ + struct ForEachArgs *argWrapper = _argWrapper; + struct sSymbol *symbol = _symbol; + + argWrapper->func(symbol, argWrapper->arg); +} + +void sym_ForEach(void (*func)(struct sSymbol *, void *), void *arg) +{ + struct ForEachArgs argWrapper = { .func = func, .arg = arg }; + + hash_ForEach(symbols, forEachWrapper, &argWrapper); +} + static int32_t Callback_NARG(struct sSymbol const *self) { (void)self; @@ -79,14 +102,6 @@ int32_t sym_GetValue(struct sSymbol const *sym) return sym->nValue; } -/* - * Calculate the hash value for a symbol name - */ -uint32_t sym_CalcHash(const char *s) -{ - return calchash(s) % HASHSIZE; -} - /* * Update a symbol's definition filename and line */ @@ -105,36 +120,28 @@ static void updateSymbolFilename(struct sSymbol *nsym) */ static struct sSymbol *createsymbol(char const *s) { - struct sSymbol **ppsym; - uint32_t hash; + struct sSymbol *symbol = malloc(sizeof(*symbol)); - hash = sym_CalcHash(s); - ppsym = &(tHashedSymbols[hash]); + if (!symbol) + fatalerror("Failed to create symbol: %s", strerror(errno)); - while ((*ppsym) != NULL) - ppsym = &((*ppsym)->pNext); - - (*ppsym) = malloc(sizeof(struct sSymbol)); - - if ((*ppsym) == NULL) { - fatalerror("No memory for symbol"); - return NULL; - } - - if (snprintf((*ppsym)->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN) + if (snprintf(symbol->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN) warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s); - (*ppsym)->isExported = false; - (*ppsym)->isBuiltin = false; - (*ppsym)->isReferenced = false; - (*ppsym)->pScope = NULL; - (*ppsym)->pNext = NULL; - (*ppsym)->pSection = NULL; - (*ppsym)->nValue = 0; - (*ppsym)->pMacro = NULL; - (*ppsym)->Callback = NULL; - updateSymbolFilename(*ppsym); - return *ppsym; + hash_AddElement(symbols, symbol->tzName, symbol); + + symbol->isExported = false; + symbol->isBuiltin = false; + symbol->pScope = NULL; + symbol->pSection = NULL; + symbol->nValue = 0; /* TODO: is this necessary? */ + symbol->pMacro = NULL; + symbol->Callback = NULL; + + symbol->ID = -1; + symbol->next = NULL; + updateSymbolFilename(symbol); + return symbol; } /* @@ -153,12 +160,10 @@ static void fullSymbolName(char *output, size_t outputSize, } /* - * Find the pointer to a symbol by name and scope + * Find a symbol by name and scope */ -static struct sSymbol **findpsymbol(char const *s, struct sSymbol const *scope) +static struct sSymbol *findsymbol(char const *s, struct sSymbol const *scope) { - struct sSymbol **ppsym; - int32_t hash; char fullname[MAXSYMLEN + 1]; if (s[0] == '.' && scope) { @@ -168,32 +173,11 @@ static struct sSymbol **findpsymbol(char const *s, struct sSymbol const *scope) char const *separator = strchr(s, '.'); - if (separator) { - if (strchr(separator + 1, '.')) - fatalerror("'%s' is a nonsensical reference to a nested local symbol", - s); - } + if (separator && strchr(separator + 1, '.')) + fatalerror("'%s' is a nonsensical reference to a nested local symbol", + s); - hash = sym_CalcHash(s); - ppsym = &(tHashedSymbols[hash]); - - while ((*ppsym) != NULL) { - if ((strcmp(s, (*ppsym)->tzName) == 0)) - return ppsym; - - ppsym = &((*ppsym)->pNext); - } - return NULL; -} - -/* - * Find a symbol by name and scope - */ -static struct sSymbol *findsymbol(char const *s, struct sSymbol const *scope) -{ - struct sSymbol **ppsym = findpsymbol(s, scope); - - return ppsym ? *ppsym : NULL; + return hash_GetElement(symbols, s); } /* @@ -213,7 +197,7 @@ struct sSymbol *sym_FindSymbol(char const *tzName) static inline bool isReferenced(struct sSymbol const *sym) { - return sym->isReferenced; + return sym->ID != -1; } /* @@ -221,33 +205,20 @@ static inline bool isReferenced(struct sSymbol const *sym) */ void sym_Purge(char const *tzName) { - struct sSymbol **ppSym; - struct sSymbol *pscope; + struct sSymbol *scope = tzName[0] == '.' ? pScope : NULL; + struct sSymbol *symbol = findsymbol(tzName, scope); - if (*tzName == '.') - pscope = pScope; - else - pscope = NULL; - - ppSym = findpsymbol(tzName, pscope); - - if (!ppSym) { + if (!symbol) { yyerror("'%s' not defined", tzName); - } else if ((*ppSym)->isBuiltin) { + } else if (symbol->isBuiltin) { yyerror("Built-in symbol '%s' cannot be purged", tzName); - } else if (isReferenced(*ppSym)) { + } else if (isReferenced(symbol)) { yyerror("Symbol \"%s\" is referenced and thus cannot be purged", tzName); } else { - struct sSymbol *pSym; - - pSym = *ppSym; - *ppSym = pSym->pNext; - - if (pSym->pMacro) - free(pSym->pMacro); - - free(pSym); + hash_RemoveElement(symbols, tzName); + free(symbol->pMacro); + free(symbol); } } @@ -503,10 +474,8 @@ void sym_Export(char const *tzSym) struct sSymbol *nsym = sym_FindSymbol(tzSym); /* If the symbol doesn't exist, create a ref that can be purged */ - if (!nsym) { + if (!nsym) nsym = sym_Ref(tzSym); - nsym->isReferenced = false; - } nsym->isExported = true; } @@ -554,7 +523,6 @@ struct sSymbol *sym_Ref(char const *tzSym) nsym = createsymbol(tzSym); nsym->type = SYM_REF; } - nsym->isReferenced = true; return nsym; } @@ -583,9 +551,6 @@ static inline char const *removeLeadingZeros(char const *ptr) */ void sym_Init(void) { - for (int32_t i = 0; i < HASHSIZE; i++) - tHashedSymbols[i] = NULL; - pPCSymbol = sym_AddReloc("@"); pPCSymbol->Callback = CallbackPC; pPCSymbol->isBuiltin = true;