mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-12-23 06:40:03 +00:00
minor refactoring, OP_INVOKE performance boost
This commit is contained in:
parent
71d3a8e1c4
commit
9ebae876f6
@ -1,15 +1,29 @@
|
||||
class test
|
||||
function __init(self, x)
|
||||
self.x = x
|
||||
self.setArg(x)
|
||||
end
|
||||
|
||||
function print(self)
|
||||
print(self.x)
|
||||
function fact(self)
|
||||
var total = 1
|
||||
|
||||
return self.x
|
||||
for (var i = self.x; i > 0; i = i - 1) do
|
||||
total = total * i;
|
||||
end
|
||||
|
||||
return total
|
||||
end
|
||||
|
||||
function setArg(self, x)
|
||||
self.x = x
|
||||
end
|
||||
end
|
||||
|
||||
var t = test("hello")
|
||||
var t = test(1)
|
||||
|
||||
print(t.print())
|
||||
for (var x = 1; x < 1000; x = x + 1) do
|
||||
for (var i = 1; i < 100; i = i + 1) do
|
||||
t.setArg(i)
|
||||
|
||||
print(t.fact())
|
||||
end
|
||||
end
|
@ -32,6 +32,7 @@ CValue cosmoB_dsetMeta(CState *state, int nargs, CValue *args) {
|
||||
|
||||
return cosmoV_newNil(); // nothing
|
||||
}
|
||||
|
||||
CValue cosmoB_dgetMeta(CState *state, int nargs, CValue *args) {
|
||||
if (nargs != 1) {
|
||||
cosmoV_error(state, "Expected 1 parameter, got %d!", nargs);
|
||||
|
@ -114,6 +114,8 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
||||
return simpleInstruction("OP_GETOBJECT", offset);
|
||||
case OP_SETOBJECT:
|
||||
return simpleInstruction("OP_SETOBJECT", offset);
|
||||
case OP_INVOKE:
|
||||
return shortOperandInstruction("OP_INVOKE", chunk, offset);
|
||||
case OP_ADD:
|
||||
return simpleInstruction("OP_ADD", offset);
|
||||
case OP_SUB:
|
||||
|
@ -95,7 +95,8 @@ bool cosmoO_equal(CObj* obj1, CObj* obj2) {
|
||||
CObjObject *cosmoO_newObject(CState *state) {
|
||||
CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT);
|
||||
obj->meta = state->metaObj;
|
||||
cosmoV_pushValue(state, cosmoV_newObj(obj)); // so out GC can keep track of it
|
||||
obj->user = NULL; // reserved for C API
|
||||
cosmoV_pushValue(state, cosmoV_newObj(obj)); // so our GC can keep track of it
|
||||
cosmoT_initTable(state, &obj->tbl, ARRAY_START);
|
||||
cosmoV_pop(state);
|
||||
|
||||
|
@ -13,8 +13,8 @@ typedef enum {
|
||||
COBJ_OBJECT,
|
||||
COBJ_FUNCTION,
|
||||
COBJ_CFUNCTION,
|
||||
COBJ_METHOD,
|
||||
// internal use
|
||||
COBJ_METHOD,
|
||||
COBJ_CLOSURE,
|
||||
COBJ_UPVALUE,
|
||||
} CObjType;
|
||||
@ -39,6 +39,7 @@ typedef struct CObjString {
|
||||
typedef struct CObjObject {
|
||||
CommonHeader; // "is a" CObj
|
||||
CTable tbl;
|
||||
void *user; // userdata (NULL by default)
|
||||
struct CObjObject *meta; // metaobject, describes the behavior of the object
|
||||
} CObjObject;
|
||||
|
||||
|
@ -32,7 +32,7 @@ typedef enum {
|
||||
OP_NEWOBJECT,
|
||||
OP_GETOBJECT,
|
||||
OP_SETOBJECT,
|
||||
OP_NEWCLASS,
|
||||
OP_INVOKE,
|
||||
|
||||
// ARITHMETIC
|
||||
OP_ADD,
|
||||
|
22
src/cparse.c
22
src/cparse.c
@ -153,8 +153,6 @@ static void advance(CParseState *pstate) {
|
||||
pstate->previous = pstate->current;
|
||||
pstate->current = cosmoL_scanToken(pstate->lex);
|
||||
|
||||
//printf("got %d [%.*s]\n", pstate->current.type, pstate->current.length, pstate->current.start);
|
||||
|
||||
if (pstate->current.type == TOKEN_ERROR) {
|
||||
// go ahead and consume the rest of the errors so it doesn't cascade
|
||||
CToken temp;
|
||||
@ -586,6 +584,11 @@ static void dot(CParseState *pstate, bool canAssign) {
|
||||
expression(pstate);
|
||||
writeu8(pstate, OP_SETOBJECT);
|
||||
valuePopped(pstate, 2); // pops key, value & object
|
||||
} else if (match(pstate, TOKEN_LEFT_PAREN)) { // it's an invoked call
|
||||
uint8_t args = parseArguments(pstate);
|
||||
writeu8(pstate, OP_INVOKE);
|
||||
writeu8(pstate, args);
|
||||
valuePopped(pstate, args); // pops the function & the object but pushes a result
|
||||
} else {
|
||||
writeu8(pstate, OP_GETOBJECT);
|
||||
// pops key & object but also pushes the field so total popped is 1
|
||||
@ -815,22 +818,7 @@ static void varDeclaration(CParseState *pstate, bool forceLocal) {
|
||||
expression(pstate);
|
||||
} while (match(pstate, TOKEN_COMMA));
|
||||
|
||||
if (pstate->compiler->pushedValues < pstate->compiler->savedPushed) {
|
||||
writeu8(pstate, OP_NIL); // didn't get expected result
|
||||
valuePushed(pstate, 1);
|
||||
}
|
||||
|
||||
valuePushed(pstate, 1);
|
||||
} else if (match(pstate, TOKEN_COMMA)) {
|
||||
valuePopped(pstate, 1); // we are expecting a value
|
||||
varDeclaration(pstate, forceLocal);
|
||||
|
||||
if (pstate->compiler->pushedValues < pstate->compiler->savedPushed) {
|
||||
writeu8(pstate, OP_NIL); // didn't get expected result
|
||||
valuePushed(pstate, 1);
|
||||
}
|
||||
|
||||
valuePushed(pstate, 1); // we already popped, & when we call defineVariable it'll pop, so go ahead and fix it here
|
||||
} else {
|
||||
writeu8(pstate, OP_NIL);
|
||||
valuePushed(pstate, 1);
|
||||
|
@ -7,8 +7,7 @@ typedef enum {
|
||||
COSMO_TNIL,
|
||||
COSMO_TBOOLEAN,
|
||||
COSMO_TNUMBER,
|
||||
COSMO_TOBJ,
|
||||
COSMO_TUSERDATA
|
||||
COSMO_TOBJ
|
||||
} CosmoType;
|
||||
|
||||
typedef double cosmo_Number;
|
||||
@ -21,7 +20,6 @@ typedef struct CValue {
|
||||
union {
|
||||
cosmo_Number num;
|
||||
bool b; // boolean
|
||||
void *ptr; // userdata
|
||||
CObj *obj;
|
||||
} val;
|
||||
} CValue;
|
||||
|
92
src/cvm.c
92
src/cvm.c
@ -87,10 +87,11 @@ void pushCallFrame(CState *state, CObjClosure *closure, int args) {
|
||||
frame->closure = closure;
|
||||
}
|
||||
|
||||
void popCallFrame(CState *state) {
|
||||
// offset is the offset of the callframe base we set the state->top back too (useful for passing values in the stack as arguments, like methods)
|
||||
void popCallFrame(CState *state, int offset) {
|
||||
closeUpvalues(state, state->callFrame[state->frameCount - 1].base); // close any upvalue still open
|
||||
|
||||
state->top = state->callFrame[state->frameCount - 1].base; // resets the stack
|
||||
state->top = state->callFrame[state->frameCount - 1].base + offset; // resets the stack
|
||||
state->frameCount--;
|
||||
}
|
||||
|
||||
@ -112,7 +113,18 @@ typedef enum {
|
||||
CALL_CFUNCTION
|
||||
} preCallResult;
|
||||
|
||||
bool call(CState *state, CObjClosure *closure, int args) {
|
||||
static inline void callCFunction(CState *state, CosmoCFunction cfunc, int args, int offset) {
|
||||
StkPtr savedBase = cosmoV_getTop(state, args);
|
||||
|
||||
cosmoM_freezeGC(state); // we don't want a GC event during c api because we don't actually trust the user to know how to evade the GC
|
||||
CValue res = cfunc(state, args, savedBase + 1);
|
||||
cosmoM_unfreezeGC(state);
|
||||
|
||||
state->top = savedBase + offset;
|
||||
cosmoV_pushValue(state, res);
|
||||
}
|
||||
|
||||
bool call(CState *state, CObjClosure *closure, int args, int offset) {
|
||||
// missmatched args, thats an obvious user error, so error.
|
||||
if (args != closure->function->args) {
|
||||
cosmoV_error(state, "Expected %d parameters for %s, got %d!", closure->function->args, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, args);
|
||||
@ -130,7 +142,7 @@ bool call(CState *state, CObjClosure *closure, int args) {
|
||||
CValue* result = cosmoV_getTop(state, 0);
|
||||
|
||||
// pop the callframe and return result :)
|
||||
popCallFrame(state);
|
||||
popCallFrame(state, offset);
|
||||
|
||||
// push the return value back onto the stack
|
||||
cosmoV_pushValue(state, *result);
|
||||
@ -139,36 +151,10 @@ bool call(CState *state, CObjClosure *closure, int args) {
|
||||
|
||||
bool callMethod(CState* state, CObjMethod *method, int args) {
|
||||
if (method->isCFunc) {
|
||||
StkPtr savedBase = state->top - args - 1;
|
||||
|
||||
cosmoM_freezeGC(state);
|
||||
CValue res = method->cfunc->cfunc(state, args+1, savedBase);
|
||||
cosmoM_unfreezeGC(state);
|
||||
|
||||
state->top = savedBase;
|
||||
cosmoV_pushValue(state, res);
|
||||
callCFunction(state, method->cfunc->cfunc, args+1, 1);
|
||||
} else {
|
||||
CObjClosure *closure = method->closure;
|
||||
|
||||
StkPtr val = state->top - args - 1;
|
||||
|
||||
if (args+1 != closure->function->args) {
|
||||
cosmoV_error(state, "Expected %d parameters for %s, got %d!", closure->function->args, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, args+1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// load function into callframe
|
||||
pushCallFrame(state, closure, closure->function->args);
|
||||
|
||||
// execute
|
||||
if (!cosmoV_execute(state))
|
||||
return false;
|
||||
CValue* result = state->top - 1;
|
||||
|
||||
// pop the callframe and return result
|
||||
popCallFrame(state);
|
||||
state->top++;
|
||||
cosmoV_pushValue(state, *result); // and push return value
|
||||
call(state, closure, args+1, 1); // offset = 1 so our stack is properly reset
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -186,7 +172,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
switch (val->val.obj->type) {
|
||||
case COBJ_CLOSURE: {
|
||||
CObjClosure *closure = (CObjClosure*)(val->val.obj);
|
||||
if (!call(state, closure, args)) {
|
||||
if (!call(state, closure, args, 0)) {
|
||||
return COSMOVM_RUNTIME_ERR;
|
||||
}
|
||||
break;
|
||||
@ -223,14 +209,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
case COBJ_CFUNCTION: {
|
||||
// it's a C function, so call it
|
||||
CosmoCFunction cfunc = ((CObjCFunction*)(val->val.obj))->cfunc;
|
||||
CValue *savedBase = state->top - args;
|
||||
|
||||
cosmoM_freezeGC(state); // we don't want a GC event during c api because we don't actually trust the user to know how to evade the GC
|
||||
CValue res = cfunc(state, args, savedBase);
|
||||
cosmoM_unfreezeGC(state);
|
||||
|
||||
state->top = savedBase - 1;
|
||||
cosmoV_pushValue(state, res);
|
||||
callCFunction(state, cfunc, args, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -446,6 +425,37 @@ bool cosmoV_execute(CState *state) {
|
||||
cosmoV_setTop(state, 3);
|
||||
break;
|
||||
}
|
||||
case OP_INVOKE: {
|
||||
uint8_t args = READBYTE();
|
||||
StkPtr key = cosmoV_getTop(state, args); // grabs key from stack
|
||||
StkPtr temp = cosmoV_getTop(state, args+1); // grabs object from stack
|
||||
|
||||
// sanity check
|
||||
if (!(temp->type == COSMO_TOBJ) || !(temp->val.obj->type == COBJ_OBJECT)) {
|
||||
cosmoV_error(state, "Couldn't get from non-object!");
|
||||
break;
|
||||
}
|
||||
|
||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
||||
CValue val; // to hold our value
|
||||
|
||||
cosmoO_getObject(state, object, *key, &val);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// moves return value & resets stack (key now points to the stack location of our return value)
|
||||
*temp = *key;
|
||||
state->top = key;
|
||||
break;
|
||||
}
|
||||
case OP_ADD: { // pop 2 values off the stack & try to add them together
|
||||
BINARYOP(cosmoV_newNumber, +);
|
||||
break;
|
||||
|
@ -15,7 +15,7 @@ class test
|
||||
end
|
||||
|
||||
var obj = test("Hello world")
|
||||
for (var i = 1; i <= 10; i=i+1) do
|
||||
for (var i = 1; i <= 1; i=i+1) do
|
||||
obj.print(i)
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user