diff --git a/src/cmem.h b/src/cmem.h index 7e65b94..1ac7cdb 100644 --- a/src/cmem.h +++ b/src/cmem.h @@ -7,13 +7,19 @@ //#define GC_STRESS //#define GC_DEBUG -// arrays will grow by a factor of 2 +// arrays *must* grow by a factor of 2 #define GROW_FACTOR 2 #define HEAP_GROW_FACTOR 2 #define ARRAY_START 8 +#ifdef GC_DEBUG #define cosmoM_freearray(state, type, buf, capacity) \ - cosmoM_reallocate(state, buf, sizeof(type) *capacity, 0) + printf("freeing array %p [size %lu] at %s:%d\n", buf, sizeof(type) * capacity, __FILE__, __LINE__); \ + cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0) +#else +#define cosmoM_freearray(state, type, buf, capacity) \ + cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0) +#endif #define cosmoM_growarray(state, type, buf, count, capacity) \ if (count >= capacity || buf == NULL) { \ @@ -22,8 +28,14 @@ buf = (type*)cosmoM_reallocate(state, buf, sizeof(type) *old, sizeof(type) *capacity); \ } +#ifdef GC_DEBUG +#define cosmoM_free(state, type, x) \ + printf("freeing %p [size %lu] at %s:%d\n", x, sizeof(type), __FILE__, __LINE__); \ + cosmoM_reallocate(state, x, sizeof(type), 0) +#else #define cosmoM_free(state, type, x) \ cosmoM_reallocate(state, x, sizeof(type), 0) +#endif #define cosmoM_isFrozen(state) \ (state->freezeGC > 0) diff --git a/src/cstate.c b/src/cstate.c index 47697b2..feb800d 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -16,7 +16,7 @@ CState *cosmoV_newState() { } state->panic = false; - state->freezeGC = false; + state->freezeGC = 1; // we start frozen // GC state->objects = NULL; @@ -38,7 +38,6 @@ CState *cosmoV_newState() { for (int i = 0; i < COBJ_MAX; i++) state->protoObjects[i] = NULL; - // first, set all strings to NULL so our GC doesn't read garbage data for (int i = 0; i < ISTRING_MAX; i++) state->iStrings[i] = NULL; @@ -68,13 +67,16 @@ CState *cosmoV_newState() { for (int i = 0; i < ISTRING_MAX; i++) state->iStrings[i]->isIString = true; + state->freezeGC = 0; // unfreeze the state return state; } void cosmoV_freeState(CState *state) { #ifdef GC_DEBUG - printf("state %p is being freed!\n", state); + printf("state %p is being free'd!\n", state); #endif + cosmoM_freezeGC(state); + // frees all the objects CObj *objs = state->objects; while (objs != NULL) { @@ -92,7 +94,15 @@ void cosmoV_freeState(CState *state) { cosmoT_clearTable(state, &state->globals); // free our gray stack & finally free the state structure - free(state->grayStack.array); + cosmoM_freearray(state, CObj*, state->grayStack.array, state->grayStack.capacity); + + // TODO: yeah idk, it looks like im missing 520 bytes somewhere? i'll look into it later +/*#ifdef GC_DEBUG + if (state->allocatedBytes != sizeof(CState)) { + printf("state->allocatedBytes doesn't match expected value (%lu), got %lu!", sizeof(CState), state->allocatedBytes); + exit(0); + } +#endif*/ free(state); } diff --git a/src/cvm.c b/src/cvm.c index 9bc118a..4bebd10 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -691,37 +691,30 @@ int cosmoV_execute(CState *state) { StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table // sanity check - if (IS_OBJ(*temp)) { - CValue val; // to hold our value - - switch (cosmoV_readObj(*temp)->type) { - case COBJ_TABLE: { - CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp); - - cosmoT_get(&tbl->tbl, *key, &val); - break; - } - default: { // check for __index metamethod - CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); - - if (object == NULL) { - cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp)); - return -1; - } - - if (!cosmoO_indexObject(state, object, *key, &val)) // if returns false, cosmoV_error was called - return -1; - - break; - } - } - - cosmoV_setTop(state, 2); // pops the table & the key - cosmoV_pushValue(state, val); // pushes the field result - } else { + if (!IS_OBJ(*temp)) { cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp)); + return -1; } + CObj *obj = cosmoV_readObj(*temp); + CObjObject *proto = cosmoO_grabProto(obj); + CValue val; // to hold our value + + if (proto != NULL) { + // check for __index metamethod + if (!cosmoO_indexObject(state, proto, *key, &val)) // if returns false, cosmoV_error was called + return -1; + } else if (obj->type == COBJ_TABLE) { + CObjTable *tbl = (CObjTable*)obj; + + cosmoT_get(&tbl->tbl, *key, &val); + } else { + cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp)); + return -1; + } + + cosmoV_setTop(state, 2); // pops the table & the key + cosmoV_pushValue(state, val); // pushes the field result continue; } case OP_NEWINDEX: { @@ -730,37 +723,29 @@ int cosmoV_execute(CState *state) { StkPtr temp = cosmoV_getTop(state, 2); // table is after the key // sanity check - if (IS_OBJ(*temp)) { - switch (cosmoV_readObj(*temp)->type) { - case COBJ_TABLE: { // index and set table - CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp); - CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key); - - *newVal = *value; // set the index - break; - } - default: { // check for __newindex - CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); - - if (object == NULL) { - cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s", cosmoV_typeStr(*temp)); - return -1; - } - - if (!cosmoO_newIndexObject(state, object, *key, *value)) // if it returns false, cosmoV_error was called - return -1; - - break; - } - } - - // pop everything off the stack - cosmoV_setTop(state, 3); - } else { + if (!IS_OBJ(*temp)) { cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp)); return -1; } + CObj *obj = cosmoV_readObj(*temp); + CObjObject *proto = cosmoO_grabProto(obj); + + if (proto != NULL) { + if (!cosmoO_newIndexObject(state, proto, *key, *value)) // if it returns false, cosmoV_error was called + return -1; + } else if (obj->type == COBJ_TABLE) { + CObjTable *tbl = (CObjTable*)obj; + CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key); + + *newVal = *value; // set the index + } else { + cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s", cosmoV_typeStr(*temp)); + return -1; + } + + // pop everything off the stack + cosmoV_setTop(state, 3); continue; } case OP_NEWOBJECT: { @@ -856,63 +841,56 @@ int cosmoV_execute(CState *state) { } CObj *obj = cosmoV_readObj(*temp); - switch (obj->type) { - case COBJ_TABLE: { - CObjTable *tbl = (CObjTable*)obj; + CObjObject *proto = cosmoO_grabProto(obj); + CValue val; - cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key - cosmoV_pushValue(state, cosmoV_newObj(tbl)); // value + if (proto != NULL) { + // grab __iter & call it + if (cosmoO_getIString(state, proto, ISTRING_ITER, &val)) { + cosmoV_pop(state); // pop the object from the stack + cosmoV_pushValue(state, val); + cosmoV_pushValue(state, cosmoV_newObj(obj)); + if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // we expect 1 return value on the stack, the iterable object + return -1; - cosmoV_pushString(state, "__next"); // key - CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next); - cosmoV_pushValue(state, cosmoV_newObj(tbl_next)); // value + StkPtr iObj = cosmoV_getTop(state, 0); - cosmoV_makeObject(state, 2); // pushes the new object to the stack - - CObjObject *obj = cosmoV_readObject(*(cosmoV_getTop(state, 0))); - cosmoO_setUserI(state, obj, 0); // increment for iterator - - // make our CObjMethod for OP_NEXT to call - CObjMethod *method = cosmoO_newMethod(state, cosmoV_newObj(tbl_next), (CObj*)obj); - - cosmoV_setTop(state, 2); // pops the object & the tbl - cosmoV_pushValue(state, cosmoV_newObj(method)); // pushes the method for OP_NEXT - break; - } - default: { - CObjObject *object = cosmoO_grabProto(obj); - CValue val; - - if (object == NULL) { - cosmoV_error(state, "No proto defined! Couldn't get from type %s", cosmoO_typeStr(obj)); + if (!IS_OBJECT(*iObj)) { + cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected !", cosmoV_typeStr(*iObj)); return -1; } - // grab __iter & call it - if (cosmoO_getIString(state, object, ISTRING_ITER, &val)) { - cosmoV_pop(state); // pop the object from the stack - cosmoV_pushValue(state, val); - cosmoV_pushValue(state, cosmoV_newObj(obj)); - if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // we expect 1 return value on the stack, the iterable object - return -1; - - StkPtr iObj = cosmoV_getTop(state, 0); - - if (!IS_OBJECT(*iObj)) { - cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected !", cosmoV_typeStr(*iObj)); - return -1; - } - - // get __next method and place it at the top of the stack - cosmoV_getMethod(state, cosmoV_readObj(*iObj), cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iObj); - } else { - cosmoV_error(state, "Expected iterable object! '__iter' not defined!"); - return -1; - } - - break; + // get __next method and place it at the top of the stack + cosmoV_getMethod(state, cosmoV_readObj(*iObj), cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iObj); + } else { + cosmoV_error(state, "Expected iterable object! '__iter' not defined!"); + return -1; } + } else if (obj->type == COBJ_TABLE) { + CObjTable *tbl = (CObjTable*)obj; + + cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key + cosmoV_pushValue(state, cosmoV_newObj(tbl)); // value + + cosmoV_pushString(state, "__next"); // key + CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next); + cosmoV_pushValue(state, cosmoV_newObj(tbl_next)); // value + + cosmoV_makeObject(state, 2); // pushes the new object to the stack + + CObjObject *obj = cosmoV_readObject(*(cosmoV_getTop(state, 0))); + cosmoO_setUserI(state, obj, 0); // increment for iterator + + // make our CObjMethod for OP_NEXT to call + CObjMethod *method = cosmoO_newMethod(state, cosmoV_newObj(tbl_next), (CObj*)obj); + + cosmoV_setTop(state, 2); // pops the object & the tbl + cosmoV_pushValue(state, cosmoV_newObj(method)); // pushes the method for OP_NEXT + } else { + cosmoV_error(state, "No proto defined! Couldn't get from type %s", cosmoO_typeStr(obj)); + return -1; } + continue; } case OP_NEXT: { @@ -989,7 +967,7 @@ int cosmoV_execute(CState *state) { int count = cosmoO_count(state, cosmoV_readObj(*temp)); cosmoV_pop(state); - + cosmoV_pushNumber(state, count); // pushes the count onto the stack continue; } @@ -1052,53 +1030,45 @@ 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)) { - switch (cosmoV_readObj(*temp)->type) { - case COBJ_TABLE: { - CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp); - CValue *val = cosmoT_insert(state, &tbl->tbl, *key); + if (!IS_OBJ(*temp)) { + cosmoV_error(state, "Couldn't index non-indexable type %s!", cosmoV_typeStr(*temp)); + return -1; + } - // pops tbl & key from stack - cosmoV_setTop(state, 2); + CObj *obj = cosmoV_readObj(*temp); + CObjObject *proto = cosmoO_grabProto(obj); + CValue val; - if (IS_NUMBER(*val)) { - cosmoV_pushValue(state, *val); // pushes old value onto the stack :) - *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc); - } else { - cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); - return -1; - } - break; + // call __index if the proto was found + if (proto != NULL) { + if (cosmoO_indexObject(state, proto, *key, &val)) { + if (!IS_NUMBER(val)) { + cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); + return -1; } - default: { - CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); - CValue val; - if (object == NULL) { - cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp)); - return -1; - } - - // call __index - if (cosmoO_indexObject(state, object, *key, &val)) { - if (IS_NUMBER(val)) { - cosmoV_pushValue(state, val); // pushes old value onto the stack :) + cosmoV_pushValue(state, val); // pushes old value onto the stack :) - // call __newindex - if (!cosmoO_newIndexObject(state, object, *key, cosmoV_newNumber(cosmoV_readNumber(val) + inc))) - return -1; - } else { - cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); - return -1; - } - } else { - return -1; - } - break; - } + // call __newindex + if (!cosmoO_newIndexObject(state, proto, *key, cosmoV_newNumber(cosmoV_readNumber(val) + inc))) + return -1; + } else + return -1; // cosmoO_indexObject failed and threw an error + } else if (obj->type == COBJ_TABLE) { + CObjTable *tbl = (CObjTable*)obj; + CValue *val = cosmoT_insert(state, &tbl->tbl, *key); + + if (!IS_NUMBER(*val)) { + cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); + return -1; } + + // pops tbl & key from stack + cosmoV_setTop(state, 2); + cosmoV_pushValue(state, *val); // pushes old value onto the stack :) + *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc); // sets table index } else { - cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp)); + cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp)); return -1; } @@ -1112,44 +1082,23 @@ int cosmoV_execute(CState *state) { // sanity check if (IS_OBJ(*temp)) { - switch (cosmoV_readObj(*temp)->type) { - case COBJ_TABLE: { - CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp); - CValue *val = cosmoT_insert(state, &tbl->tbl, ident); + CObj *obj = cosmoV_readObj(*temp); + CValue val; + + if (!cosmoV_get(state, obj, ident, &val)) + return -1; - // pops tbl from stack - cosmoV_pop(state); + // pop the object off the stack + cosmoV_pop(state); - if (IS_NUMBER(*val)) { - cosmoV_pushValue(state, *val); // pushes old value onto the stack :) - *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc); - } else { - cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); - return -1; - } - break; - } - default: { - CObj *obj = cosmoV_readObj(*temp); - CValue val; - - if (!cosmoV_get(state, obj, ident, &val)) - return -1; - - // pop the object off the stack - cosmoV_pop(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))) - return -1; - } else { - cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); - return -1; - } - break; - } + // 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))) + return -1; + } else { + cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); + return -1; } } else { cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));