From aaed92424fc0172902de82b023bee4fa83c2db00 Mon Sep 17 00:00:00 2001 From: CPunch Date: Tue, 17 Nov 2020 15:07:56 -0600 Subject: [PATCH] CObjMethod refactor --- examples/stress.cosmo | 18 ++++++++++++++++++ src/cmem.c | 2 +- src/cobj.c | 13 ++++--------- src/cobj.h | 6 +----- src/cvm.c | 37 ++++++++++++++++--------------------- 5 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 examples/stress.cosmo diff --git a/examples/stress.cosmo b/examples/stress.cosmo new file mode 100644 index 0000000..a93f952 --- /dev/null +++ b/examples/stress.cosmo @@ -0,0 +1,18 @@ +class Test + function __init(self, x) + self.x = x + end + + function print(self) + print(self.x) + end +end + +-- stressing the GC +local i = 0 +while true do + var x = Test("Hello world " .. i) + x.print() + + i = i + 1 +end \ No newline at end of file diff --git a/src/cmem.c b/src/cmem.c index 3e0e032..1225cd2 100644 --- a/src/cmem.c +++ b/src/cmem.c @@ -111,7 +111,7 @@ void blackenObject(CState *state, CObj *obj) { } case COBJ_METHOD: { CObjMethod *method = (CObjMethod*)obj; - markObject(state, (CObj*)method->closure); + markValue(state, method->func); markObject(state, (CObj*)method->obj); break; } diff --git a/src/cobj.c b/src/cobj.c index 5ae385f..e9bbf0d 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -123,17 +123,15 @@ CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func) { CObjMethod *cosmoO_newCMethod(CState *state, CObjCFunction *func, CObjObject *obj) { CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD); - method->cfunc = func; + method->func = cosmoV_newObj(func); method->obj = obj; - method->isCFunc = true; return method; } CObjMethod *cosmoO_newMethod(CState *state, CObjClosure *func, CObjObject *obj) { CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD); - method->closure = func; + method->func = cosmoV_newObj(func); method->obj = obj; - method->isCFunc = false; return method; } @@ -297,11 +295,8 @@ void printObject(CObj *o) { } case COBJ_METHOD: { CObjMethod *method = (CObjMethod*)o; - if (method->closure->function->name != NULL) { - printf(" %p : %.*s", method->obj, method->closure->function->name->length, method->closure->function->name->str); - } else { - printf(" %p : %s", method->obj, UNNAMEDCHUNK); - } + printf(" %p : ", method->obj); + printValue(method->func); break; } case COBJ_CLOSURE: { diff --git a/src/cobj.h b/src/cobj.h index 5d0a1a1..484cb3d 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -71,11 +71,7 @@ typedef struct CObjClosure { typedef struct CObjMethod { CommonHeader; // "is a " CObj CObjObject *obj; // obj this method is bound too - union { - CObjClosure *closure; - CObjCFunction *cfunc; - }; - bool isCFunc; + CValue func; } CObjMethod; typedef struct CObjUpval { diff --git a/src/cvm.c b/src/cvm.c index 221b3dc..c5f66a2 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -149,12 +149,17 @@ bool call(CState *state, CObjClosure *closure, int args, int offset) { return true; } -bool callMethod(CState* state, CObjMethod *method, int args) { - if (method->isCFunc) { - callCFunction(state, method->cfunc->cfunc, args+1, 1); +bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args) { + // first, set the first argument to the object + StkPtr temp = cosmoV_getTop(state, args); + *temp = cosmoV_newObj(obj); + + if (IS_CFUNCTION(func)) { + callCFunction(state, cosmoV_readCFunction(func), args+1, 1); + } else if (IS_CLOSURE(func)) { + call(state, cosmoV_readClosure(func), args+1, 1); // offset = 1 so our stack is properly reset } else { - CObjClosure *closure = method->closure; - call(state, closure, args+1, 1); // offset = 1 so our stack is properly reset + cosmoV_error(state, "Cannot call non-function value!"); } return true; @@ -179,30 +184,27 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) { } case COBJ_METHOD: { CObjMethod *method = (CObjMethod*)val->val.obj; - *val = cosmoV_newObj(method->obj); // sets the object on the stack so the function can reference it in it's first argument - callMethod(state, method, args); + invokeMethod(state, method->obj, method->func, args); break; } case COBJ_OBJECT: { CObjObject *protoObj = (CObjObject*)val->val.obj; CObjObject *newObj = cosmoO_newObject(state); newObj->proto = protoObj; - *val = cosmoV_newObj(newObj); CValue ret; // check if they defined an initalizer - if (cosmoV_getObject(state, protoObj, cosmoV_newObj(state->iStrings[ISTRING_INIT]), &ret) && IS_METHOD(ret)) { - callMethod(state, cosmoV_readMethod(ret), args); - cosmoV_pop(state); + if (cosmoO_getIString(state, protoObj, ISTRING_INIT, &ret)) { + invokeMethod(state, newObj, ret, args); } else { // no default initalizer if (args != 0) { cosmoV_error(state, "Expected 0 parameters, got %d!", args); return COSMOVM_RUNTIME_ERR; } - state->top--; } + cosmoV_pop(state); // pops the return value, it's unused cosmoV_pushValue(state, cosmoV_newObj(newObj)); break; } @@ -443,15 +445,8 @@ bool cosmoV_execute(CState *state) { cosmoO_getObject(state, object, *key, &val); // we use cosmoO_getObject instead of the cosmoV_getObject wrapper so we get the raw value from the object instead of the CObjMethod wrapper - // now set the key stack location to the object, and call it! - *key = *temp; - if (IS_CLOSURE(val)) { - call(state, cosmoV_readClosure(val), args+1, 1); - } else if (IS_CFUNCTION(val)) { - callCFunction(state, cosmoV_readCFunction(val), args+1, 1); - } else { - cosmoV_error(state, "Cannot call non-function value! got %d", val.val.obj->type); - } + // now invoke the method! + invokeMethod(state, object, val, args); // moves return value & resets stack (key now points to the stack location of our return value) *temp = *key;