From 85fb91b4ed9ddf342e2be14f6bb358733a588a19 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Fri, 8 Apr 2022 11:49:02 -0400 Subject: [PATCH] Use stripped Objects in hash.c These lack the unused .forward field, reducing table memory by ~25%. Also bump Object.number up to a long, and add a generic Object.data field. --- src/env.c | 26 ++++++++++++++++---------- src/env.h | 9 ++++++++- src/hash.c | 38 ++++++++++++++++++++++++++++++-------- src/hash.h | 2 +- src/object.c | 8 ++++---- src/object.h | 3 ++- src/pebblisp.c | 9 +++++---- 7 files changed, 66 insertions(+), 29 deletions(-) diff --git a/src/env.c b/src/env.c index 8067002..66a2d50 100644 --- a/src/env.c +++ b/src/env.c @@ -57,10 +57,10 @@ struct symFunc { #define pf(_func) buildFuncSym(_func ## Symbol, &(_func)) #endif -Object* fetch(const char* name, struct Environment* env) +struct StrippedObject* fetch(const char* name, struct Environment* env) { while (env) { - Object* object = getFromTable(&env->table, name); + struct StrippedObject* object = getFromTable(&env->table, name); if (object) { return object; } @@ -71,19 +71,23 @@ Object* fetch(const char* name, struct Environment* env) Object fetchFromEnvironment(const char* name, struct Environment* env) { - Object* object = fetch(name, env); + struct StrippedObject* object = fetch(name, env); if (object) { - return cloneObject(*object); + Object o = deStrip(*object); + return cloneObject(o); } return errorWithContext(DID_NOT_FIND_SYMBOL, name); } void addToEnv(struct Environment* env, const char* name, const Object obj) { - Object* existing = fetch(name, env); + struct StrippedObject* existing = fetch(name, env); if (existing) { - cleanObject(existing); - *existing = cloneObject(obj); + Object o = deStrip(*existing); + cleanObject(&o); + o = cloneObject(obj); + existing->type = o.type; + existing->data = o.data; return; } char* symbol = malloc(sizeof(char) * (strlen(name) + 1)); @@ -252,7 +256,8 @@ void printEnv(struct Environment* env, int printPointers) printf("Native"); } else { size_t length; - char* s = stringObj(&env->table.elements[i].object, &length); + // SAFETY: Casting to Object is fine because stringObj() doesn't touch .forward + char* s = stringObj((Object *) &env->table.elements[i].object, &length); printColored(s); if (env->table.elements[i].object.type == TYPE_STRING) { printf("\""); @@ -410,10 +415,11 @@ Object help(Object* params, int length, struct Environment* env) } } - Object* object = fetch(symbol, env); + struct StrippedObject* object = fetch(symbol, env); if (object) { size_t len = 0; - char* string = stringObj(object, &len); + // SAFETY: Casting to Object is fine because stringObj() doesn't touch .forward + char* string = stringObj((Object*) object, &len); Object text = stringFromSlice(string, len); free(string); return text; diff --git a/src/env.h b/src/env.h index c51d7af..fe01c15 100644 --- a/src/env.h +++ b/src/env.h @@ -4,9 +4,14 @@ #include "object.h" #include "hash.h" +struct StrippedObject { + Type type; + void* data; +}; + struct EnvElement { char* symbol; - Object object; + struct StrippedObject object; }; struct Environment; @@ -19,6 +24,8 @@ struct Environment { int refs; }; +Object deStrip(struct StrippedObject object); + struct Environment* global(); void setGlobal(struct Environment* env); diff --git a/src/hash.c b/src/hash.c index a1ad48c..51d8ff3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -3,6 +3,19 @@ #include +void addStripped(struct ObjectTable* table, char* name, struct StrippedObject object); + +Object deStrip(struct StrippedObject object) +{ + // Garbage .forward data may be safe here, but since usage of that data is + // currently in flux, it should take the more cautious route for now. + return (Object) { + .type = object.type, + .string = object.data, + .forward = NULL, + }; +} + struct ObjectTable buildTable(size_t capacity) { struct ObjectTable table = { @@ -21,7 +34,8 @@ void deleteTable(struct ObjectTable* table) for (int i = 0; i < table->capacity; i++) { if (table->elements[i].symbol) { free(table->elements[i].symbol); - cleanObject(&table->elements[i].object); + Object deStripped = deStrip(table->elements[i].object); + cleanObject(&deStripped); } } free(table->elements); @@ -47,7 +61,7 @@ void extendTable(struct ObjectTable* table) struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4); for (int i = 0; i < table->capacity; i++) { if (table->elements[i].symbol) { - addToTable(&newTable, table->elements[i].symbol, table->elements[i].object); + addStripped(&newTable, table->elements[i].symbol, table->elements[i].object); } } free(table->elements); @@ -55,7 +69,7 @@ void extendTable(struct ObjectTable* table) } } -Object* getFromTable(struct ObjectTable* table, const char* name) +struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name) { if (table->capacity == 0) { return NULL; @@ -106,11 +120,7 @@ static unsigned long hash(unused const char* str, struct ObjectTable* table) #endif -/// -/// \param table -/// \param name Should be a new allocation -/// \param object Should already be cloned -void addToTable(struct ObjectTable* table, char* name, Object object) +void addStripped(struct ObjectTable* table, char* name, struct StrippedObject object) { extendTable(table); size_t h = hash(name, table); @@ -121,3 +131,15 @@ void addToTable(struct ObjectTable* table, char* name, Object object) table->elements[h].object = object; table->count += 1; } + +/// +/// \param table +/// \param name Should be a new allocation +/// \param object Should already be cloned +void addToTable(struct ObjectTable* table, char* name, Object object) +{ + addStripped(table, name, (struct StrippedObject) { + .data = object.data, + .type = object.type, + }); +} diff --git a/src/hash.h b/src/hash.h index 55d4fb8..ca2f084 100644 --- a/src/hash.h +++ b/src/hash.h @@ -13,7 +13,7 @@ struct ObjectTable buildTable(size_t capacity); void addToTable(struct ObjectTable* table, char* name, Object object); -Object* getFromTable(struct ObjectTable* table, const char* name); +struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name); void deleteTable(struct ObjectTable* table); diff --git a/src/object.c b/src/object.c index 7e77123..1c9388a 100644 --- a/src/object.c +++ b/src/object.c @@ -245,7 +245,7 @@ int stringNObj(struct string* s, const Object* obj) inflate(s, 16); switch (obj->type) { case TYPE_NUMBER: - s->cursor += sprintf(s->cursor, "%d", obj->number); + s->cursor += sprintf(s->cursor, "%ld", obj->number); break; case TYPE_BOOL: s->cursor += sprintf(s->cursor, "%s", obj->number ? "T" : "F"); @@ -287,7 +287,7 @@ int stringNObj(struct string* s, const Object* obj) break; } case TYPE_FUNC: - s->cursor += sprintf(s->cursor, "F%d", obj->number); + s->cursor += sprintf(s->cursor, "F%ld", obj->number); break; case TYPE_LAMBDA: { #ifdef STANDALONE @@ -314,7 +314,7 @@ int stringNObj(struct string* s, const Object* obj) } if (!isValidType(*obj)) { - s->cursor += sprintf(s->cursor, "BAD_TYPE(%d) X%d", obj->type, obj->number); + s->cursor += sprintf(s->cursor, "BAD_TYPE(%d) X%ld", obj->type, obj->number); } return 0; @@ -422,8 +422,8 @@ void cleanObject(Object* target) if (!target->lambda->refs) { cleanObject(&target->lambda->params); cleanObject(&target->lambda->body); - free(target->lambda); free(target->lambda->params.docString); + free(target->lambda); } break; case TYPE_STRUCT: diff --git a/src/object.h b/src/object.h index d7743d6..0f21e1b 100644 --- a/src/object.h +++ b/src/object.h @@ -89,7 +89,7 @@ struct Object { Type type; union { - int number; + long number; Object* list; char* string; @@ -104,6 +104,7 @@ struct Object { #else struct Error* error; #endif + void* data; }; union { diff --git a/src/pebblisp.c b/src/pebblisp.c index d01badb..9e09e79 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -184,7 +184,7 @@ Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength, struct Environment* env) { if (!funcy) { - eprintf("HIGHLY ILLEGAL NULL FUNCY!!!\n"); + eprintf("HIGHLY ILLEGAL NULL FUNC-LIKE!!!\n"); return errorObject(BAD_TYPE); } switch (funcy->type) { @@ -193,7 +193,7 @@ Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength, case TYPE_FUNC: return listEvalFunc(funcy, passedArguments, evalLength, env); default: - eprintf("HIGHLY ILLEGAL NOT-FUNCY IN funcyEval()!!!\n"); + eprintf("HIGHLY ILLEGAL NOT-FUNC IN funcyEval()!!!\n"); return errorObject(BAD_TYPE); } } @@ -229,8 +229,9 @@ Object evalList(const Object* obj, struct Environment* env) Object* doc = NULL; Object* body = NULL; if (params) { - doc = params->forward && params->forward->forward ? params->forward : NULL; - body = doc ? params->forward->forward : params->forward; + int twoParams = params->forward && params->forward->forward; + doc = twoParams ? params->forward : NULL; + body = twoParams ? params->forward->forward : params->forward; } return constructLambda(params, doc, body, env); } else if (strcmp(first_form->string, "struct") == 0) {