From 78e21a0f2861106fb814643247b27012e0433dac Mon Sep 17 00:00:00 2001 From: CPunch Date: Sun, 7 Feb 2021 14:32:39 -0600 Subject: [PATCH] refactored cosmoV_set & cosmoV_get, renamed COSMO_TOBJ->COSMO_TREF also changed print() to print raw primitives instead of generating a needlessly. helped performance immensely in scripts like `examples/increment.cosmo` --- src/cbaselib.c | 10 +++++-- src/cmem.c | 4 +-- src/cobj.h | 2 +- src/ctable.c | 2 +- src/cvalue.c | 10 +++---- src/cvalue.h | 10 +++---- src/cvm.c | 76 +++++++++++++++++++++++++++++++++++++------------- src/cvm.h | 16 +++++++++-- 8 files changed, 92 insertions(+), 38 deletions(-) diff --git a/src/cbaselib.c b/src/cbaselib.c index ef41d25..facdac6 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -10,8 +10,12 @@ int cosmoB_print(CState *state, int nargs, CValue *args) { for (int i = 0; i < nargs; i++) { - CObjString *str = cosmoV_toString(state, args[i]); - printf("%s", cosmoO_readCString(str)); + if (IS_REF(args[i])) { // if its a CObj*, generate the CObjString + CObjString *str = cosmoV_toString(state, args[i]); + printf("%s", cosmoO_readCString(str)); + } else { // else, thats pretty expensive for primitives, just print the raw value + printValue(args[i]); + } } printf("\n"); @@ -173,7 +177,7 @@ int cosmoB_oisChild(CState *state, int nargs, CValue *args) { return 0; } - if (!IS_OBJ(args[0]) || !IS_OBJECT(args[1])) { + if (!IS_REF(args[0]) || !IS_OBJECT(args[1])) { cosmoV_typeError(state, "object.ischild()", ", ", "%s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1])); return 0; } diff --git a/src/cmem.c b/src/cmem.c index a56452f..9770022 100644 --- a/src/cmem.c +++ b/src/cmem.c @@ -71,7 +71,7 @@ void tableRemoveWhite(CState *state, CTable *tbl) { int cap = tbl->capacityMask + 1; for (int i = 0; i < cap; i++) { CTableEntry *entry = &tbl->table[i]; - if (IS_OBJ(entry->key) && !(cosmoV_readRef(entry->key))->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table + if (IS_REF(entry->key) && !(cosmoV_readRef(entry->key))->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table cosmoT_remove(state, tbl, entry->key); } } @@ -174,7 +174,7 @@ void markObject(CState *state, CObj *obj) { } void markValue(CState *state, CValue val) { - if (IS_OBJ(val)) + if (IS_REF(val)) markObject(state, cosmoV_readRef(val)); } diff --git a/src/cobj.h b/src/cobj.h index daaf0db..6a77a6f 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -130,7 +130,7 @@ typedef struct CObjUpval { #define cosmoO_readCString(x) ((CObjString*)x)->str static inline bool isObjType(CValue val, CObjType type) { - return IS_OBJ(val) && cosmoV_readRef(val)->type == type; + return IS_REF(val) && cosmoV_readRef(val)->type == type; } // just protects against macro expansion diff --git a/src/ctable.c b/src/ctable.c index cbce9e3..333deed 100644 --- a/src/ctable.c +++ b/src/ctable.c @@ -66,7 +66,7 @@ uint32_t getObjectHash(CObj *obj) { uint32_t getValueHash(CValue *val) { switch (GET_TYPE(*val)) { - case COSMO_TOBJ: + case COSMO_TREF: return getObjectHash(cosmoV_readRef(*val)); case COSMO_TNUMBER: { uint32_t buf[sizeof(cosmo_Number)/sizeof(uint32_t)]; diff --git a/src/cvalue.c b/src/cvalue.c index 6b0ab5c..ee58775 100644 --- a/src/cvalue.c +++ b/src/cvalue.c @@ -27,7 +27,7 @@ bool cosmoV_equal(CValue valA, CValue valB) { switch (GET_TYPE(valA)) { case COSMO_TBOOLEAN: return cosmoV_readBoolean(valA) == cosmoV_readBoolean(valB); case COSMO_TNUMBER: return cosmoV_readNumber(valA) == cosmoV_readNumber(valB); - case COSMO_TOBJ: return cosmoO_equal(cosmoV_readRef(valA), cosmoV_readRef(valB)); + case COSMO_TREF: return cosmoO_equal(cosmoV_readRef(valA), cosmoV_readRef(valB)); case COSMO_TNIL: return true; default: return false; @@ -44,7 +44,7 @@ CObjString *cosmoV_toString(CState *state, CValue val) { case COSMO_TBOOLEAN: { return cosmoV_readBoolean(val) ? cosmoO_copyString(state, "true", 4) : cosmoO_copyString(state, "false", 5); } - case COSMO_TOBJ: { + case COSMO_TREF: { return cosmoO_toString(state, cosmoV_readRef(val)); } case COSMO_TNIL: { @@ -63,7 +63,7 @@ cosmo_Number cosmoV_toNumber(CState *state, CValue val) { case COSMO_TBOOLEAN: { return cosmoV_readBoolean(val) ? 1 : 0; } - case COSMO_TOBJ: { + case COSMO_TREF: { return cosmoO_toNumber(state, cosmoV_readRef(val)); } case COSMO_TNIL: // fall through @@ -77,7 +77,7 @@ const char *cosmoV_typeStr(CValue val) { case COSMO_TNIL: return ""; case COSMO_TBOOLEAN: return ""; case COSMO_TNUMBER: return ""; - case COSMO_TOBJ: return cosmoO_typeStr(cosmoV_readRef(val)); + case COSMO_TREF: return cosmoO_typeStr(cosmoV_readRef(val)); default: return ""; @@ -92,7 +92,7 @@ void printValue(CValue val) { case COSMO_TBOOLEAN: printf(cosmoV_readBoolean(val) ? "true" : "false"); break; - case COSMO_TOBJ: { + case COSMO_TREF: { printObject(cosmoV_readRef(val)); break; } diff --git a/src/cvalue.h b/src/cvalue.h index 7f9afbd..94e0790 100644 --- a/src/cvalue.h +++ b/src/cvalue.h @@ -6,7 +6,7 @@ typedef enum { COSMO_TNUMBER, // number has to be 0 because NaN box COSMO_TBOOLEAN, - COSMO_TOBJ, + COSMO_TREF, COSMO_TNIL, } CosmoType; @@ -47,7 +47,7 @@ typedef union CValue { #define SIG_MASK (MASK_QUIETNAN | MASK_TYPE) #define BOOL_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TBOOLEAN) << 48)) -#define OBJ_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TOBJ) << 48)) +#define OBJ_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TREF) << 48)) #define NIL_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TNIL) << 48)) #define cosmoV_newNumber(x) ((CValue){.num = x}) @@ -62,7 +62,7 @@ typedef union CValue { #define IS_NUMBER(x) (((x).data & MASK_QUIETNAN) != MASK_QUIETNAN) #define IS_BOOLEAN(x) (((x).data & SIG_MASK) == BOOL_SIG) #define IS_NIL(x) (((x).data & SIG_MASK) == NIL_SIG) -#define IS_OBJ(x) (((x).data & SIG_MASK) == OBJ_SIG) +#define IS_REF(x) (((x).data & SIG_MASK) == OBJ_SIG) #else /* @@ -83,7 +83,7 @@ typedef struct CValue { #define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = (x)}}) #define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = (x)}}) -#define cosmoV_newRef(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)(x)}}) +#define cosmoV_newRef(x) ((CValue){COSMO_TREF, {.obj = (CObj*)(x)}}) #define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}}) // read CValues @@ -97,7 +97,7 @@ typedef struct CValue { #define IS_NUMBER(x) (GET_TYPE(x) == COSMO_TNUMBER) #define IS_BOOLEAN(x) (GET_TYPE(x) == COSMO_TBOOLEAN) #define IS_NIL(x) (GET_TYPE(x) == COSMO_TNIL) -#define IS_OBJ(x) (GET_TYPE(x) == COSMO_TOBJ) +#define IS_REF(x) (GET_TYPE(x) == COSMO_TREF) #endif diff --git a/src/cvm.c b/src/cvm.c index 91dbd4a..e58074c 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -306,7 +306,7 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset) printf("(%d args)\n", args); #endif - if (!IS_OBJ(func)) { + if (!IS_REF(func)) { cosmoV_error(state, "Cannot call non-callable type %s!", cosmoV_typeStr(func)); return false; } @@ -449,7 +449,7 @@ COSMO_API void cosmoV_makeTable(CState *state, int pairs) { cosmoV_pushRef(state, (CObj*)newObj); } -COSMO_API bool cosmoV_get(CState *state, CObj *_obj, CValue key, CValue *val) { +bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val) { CObjObject *object = cosmoO_grabProto(_obj); // no proto to get from @@ -472,7 +472,7 @@ COSMO_API bool cosmoV_get(CState *state, CObj *_obj, CValue key, CValue *val) { return false; } -COSMO_API bool cosmoV_set(CState *state, CObj *_obj, CValue key, CValue val) { +bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val) { CObjObject *object = cosmoO_grabProto(_obj); // no proto to set to @@ -486,8 +486,46 @@ COSMO_API bool cosmoV_set(CState *state, CObj *_obj, CValue key, CValue val) { return true; } +COSMO_API bool cosmoV_get(CState *state) { + CValue val; + StkPtr obj = cosmoV_getTop(state, 1); // object was pushed first + StkPtr key = cosmoV_getTop(state, 0); // then the key + + if (!IS_REF(*obj)) { + cosmoV_error(state, "Couldn't get field from type %s!", cosmoV_typeStr(*obj)); + return false; + } + + if (!cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val)) + return false; + + // pop the obj & key, push the value + cosmoV_setTop(state, 2); + cosmoV_pushValue(state, val); + return true; +} + +// yes, this would technically make it possible to set fields of types other than . go crazy +COSMO_API bool cosmoV_set(CState *state) { + StkPtr obj = cosmoV_getTop(state, 2); // object was pushed first + StkPtr key = cosmoV_getTop(state, 1); // then the key + StkPtr val = cosmoV_getTop(state, 0); // and finally the value + + if (!IS_REF(*obj)) { + cosmoV_error(state, "Couldn't set field on type %s!", cosmoV_typeStr(*obj)); + return false; + } + + if (!cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val)) + return false; + + // pop the obj, key & value + cosmoV_setTop(state, 3); + return true; +} + COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val) { - if (!cosmoV_get(state, obj, key, val)) + if (!cosmoV_rawget(state, obj, key, val)) return false; // if the result is callable, wrap it in an method @@ -701,7 +739,7 @@ int cosmoV_execute(CState *state) { StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table // sanity check - if (!IS_OBJ(*temp)) { + if (!IS_REF(*temp)) { cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp)); return -1; } @@ -733,7 +771,7 @@ int cosmoV_execute(CState *state) { StkPtr temp = cosmoV_getTop(state, 2); // table is after the key // sanity check - if (!IS_OBJ(*temp)) { + if (!IS_REF(*temp)) { cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp)); return -1; } @@ -769,8 +807,8 @@ int cosmoV_execute(CState *state) { uint16_t ident = READUINT(); // use for the key // sanity check - if (IS_OBJ(*temp)) { - if (!cosmoV_set(state, cosmoV_readRef(*temp), constants[ident], *value)) + if (IS_REF(*temp)) { + if (!cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value)) return -1; } else { CObjString *field = cosmoV_toString(state, constants[ident]); @@ -788,8 +826,8 @@ int cosmoV_execute(CState *state) { uint16_t ident = READUINT(); // use for the key // sanity check - if (IS_OBJ(*temp)) { - if (!cosmoV_get(state, cosmoV_readRef(*temp), constants[ident], &val)) + if (IS_REF(*temp)) { + if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val)) return -1; } else { CObjString *field = cosmoV_toString(state, constants[ident]); @@ -807,7 +845,7 @@ int cosmoV_execute(CState *state) { uint16_t ident = READUINT(); // use for the key // this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead of just cosmoV_get - if (IS_OBJ(*temp)) { + if (IS_REF(*temp)) { if (!cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val)) return -1; } else { @@ -828,9 +866,9 @@ int cosmoV_execute(CState *state) { CValue val; // to hold our value // sanity check - if (IS_OBJ(*temp)) { + if (IS_REF(*temp)) { // get the field from the object - if (!cosmoV_get(state, cosmoV_readRef(*temp), constants[ident], &val)) + if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val)) return -1; // now invoke the method! @@ -845,7 +883,7 @@ int cosmoV_execute(CState *state) { case OP_ITER: { StkPtr temp = cosmoV_getTop(state, 0); // should be the object/table - if (!IS_OBJ(*temp)) { + if (!IS_REF(*temp)) { cosmoV_error(state, "Couldn't iterate over non-iterator type %s!", cosmoV_typeStr(*temp)); return -1; } @@ -968,7 +1006,7 @@ int cosmoV_execute(CState *state) { case OP_COUNT: { StkPtr temp = cosmoV_getTop(state, 0); - if (!IS_OBJ(*temp)) { + if (!IS_REF(*temp)) { cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp)); return -1; } @@ -1038,7 +1076,7 @@ int cosmoV_execute(CState *state) { StkPtr temp = cosmoV_getTop(state, 1); // object should be above the key StkPtr key = cosmoV_getTop(state, 0); // grabs key - if (!IS_OBJ(*temp)) { + if (!IS_REF(*temp)) { cosmoV_error(state, "Couldn't index non-indexable type %s!", cosmoV_typeStr(*temp)); return -1; } @@ -1089,11 +1127,11 @@ int cosmoV_execute(CState *state) { CValue ident = constants[indx]; // grabs identifier // sanity check - if (IS_OBJ(*temp)) { + if (IS_REF(*temp)) { CObj *obj = cosmoV_readRef(*temp); CValue val; - if (!cosmoV_get(state, obj, ident, &val)) + if (!cosmoV_rawget(state, obj, ident, &val)) return -1; // pop the object off the stack @@ -1102,7 +1140,7 @@ int cosmoV_execute(CState *state) { // check that it's a number value if (IS_NUMBER(val)) { cosmoV_pushValue(state, val); // pushes old value onto the stack :) - if (!cosmoV_set(state, obj, ident, cosmoV_newNumber(cosmoV_readNumber(val) + inc))) + if (!cosmoV_rawset(state, obj, ident, cosmoV_newNumber(cosmoV_readNumber(val) + inc))) return -1; } else { cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); diff --git a/src/cvm.h b/src/cvm.h index 35b9a16..430153d 100644 --- a/src/cvm.h +++ b/src/cvm.h @@ -40,8 +40,20 @@ COSMO_API bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjO */ COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *name); -COSMO_API bool cosmoV_get(CState *state, CObj *obj, CValue key, CValue *val); -COSMO_API bool cosmoV_set(CState *state, CObj *obj, CValue key, CValue val); +/* + expects object to be pushed, then the key. + + if returns false an error was thrown, if returns true the value was pushed onto the stack and the object and key were popped +*/ +COSMO_API bool cosmoV_get(CState *state); + +/* + expects object to be pushed, then the key, and finally the new value. + + if returns false an error was thrown, if returns true the value was set and the object key, and value were popped +*/ +COSMO_API bool cosmoV_set(CState *state); + // wraps the closure into a CObjMethod, so the function is called as an invoked method COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);