mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-22 15:30:06 +00:00
minor refactoring, OP_INVOKE performance boost
This commit is contained in:
parent
71d3a8e1c4
commit
9ebae876f6
@ -1,15 +1,29 @@
|
|||||||
class test
|
class test
|
||||||
function __init(self, x)
|
function __init(self, x)
|
||||||
|
self.setArg(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function fact(self)
|
||||||
|
var total = 1
|
||||||
|
|
||||||
|
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
|
self.x = x
|
||||||
end
|
end
|
||||||
|
|
||||||
function print(self)
|
|
||||||
print(self.x)
|
|
||||||
|
|
||||||
return self.x
|
|
||||||
end
|
|
||||||
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
|
return cosmoV_newNil(); // nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
CValue cosmoB_dgetMeta(CState *state, int nargs, CValue *args) {
|
CValue cosmoB_dgetMeta(CState *state, int nargs, CValue *args) {
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "Expected 1 parameter, got %d!", nargs);
|
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);
|
return simpleInstruction("OP_GETOBJECT", offset);
|
||||||
case OP_SETOBJECT:
|
case OP_SETOBJECT:
|
||||||
return simpleInstruction("OP_SETOBJECT", offset);
|
return simpleInstruction("OP_SETOBJECT", offset);
|
||||||
|
case OP_INVOKE:
|
||||||
|
return shortOperandInstruction("OP_INVOKE", chunk, offset);
|
||||||
case OP_ADD:
|
case OP_ADD:
|
||||||
return simpleInstruction("OP_ADD", offset);
|
return simpleInstruction("OP_ADD", offset);
|
||||||
case OP_SUB:
|
case OP_SUB:
|
||||||
|
@ -95,7 +95,8 @@ bool cosmoO_equal(CObj* obj1, CObj* obj2) {
|
|||||||
CObjObject *cosmoO_newObject(CState *state) {
|
CObjObject *cosmoO_newObject(CState *state) {
|
||||||
CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT);
|
CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT);
|
||||||
obj->meta = state->metaObj;
|
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);
|
cosmoT_initTable(state, &obj->tbl, ARRAY_START);
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ typedef enum {
|
|||||||
COBJ_OBJECT,
|
COBJ_OBJECT,
|
||||||
COBJ_FUNCTION,
|
COBJ_FUNCTION,
|
||||||
COBJ_CFUNCTION,
|
COBJ_CFUNCTION,
|
||||||
COBJ_METHOD,
|
|
||||||
// internal use
|
// internal use
|
||||||
|
COBJ_METHOD,
|
||||||
COBJ_CLOSURE,
|
COBJ_CLOSURE,
|
||||||
COBJ_UPVALUE,
|
COBJ_UPVALUE,
|
||||||
} CObjType;
|
} CObjType;
|
||||||
@ -39,6 +39,7 @@ typedef struct CObjString {
|
|||||||
typedef struct CObjObject {
|
typedef struct CObjObject {
|
||||||
CommonHeader; // "is a" CObj
|
CommonHeader; // "is a" CObj
|
||||||
CTable tbl;
|
CTable tbl;
|
||||||
|
void *user; // userdata (NULL by default)
|
||||||
struct CObjObject *meta; // metaobject, describes the behavior of the object
|
struct CObjObject *meta; // metaobject, describes the behavior of the object
|
||||||
} CObjObject;
|
} CObjObject;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ typedef enum {
|
|||||||
OP_NEWOBJECT,
|
OP_NEWOBJECT,
|
||||||
OP_GETOBJECT,
|
OP_GETOBJECT,
|
||||||
OP_SETOBJECT,
|
OP_SETOBJECT,
|
||||||
OP_NEWCLASS,
|
OP_INVOKE,
|
||||||
|
|
||||||
// ARITHMETIC
|
// ARITHMETIC
|
||||||
OP_ADD,
|
OP_ADD,
|
||||||
|
22
src/cparse.c
22
src/cparse.c
@ -153,8 +153,6 @@ static void advance(CParseState *pstate) {
|
|||||||
pstate->previous = pstate->current;
|
pstate->previous = pstate->current;
|
||||||
pstate->current = cosmoL_scanToken(pstate->lex);
|
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) {
|
if (pstate->current.type == TOKEN_ERROR) {
|
||||||
// go ahead and consume the rest of the errors so it doesn't cascade
|
// go ahead and consume the rest of the errors so it doesn't cascade
|
||||||
CToken temp;
|
CToken temp;
|
||||||
@ -586,6 +584,11 @@ static void dot(CParseState *pstate, bool canAssign) {
|
|||||||
expression(pstate);
|
expression(pstate);
|
||||||
writeu8(pstate, OP_SETOBJECT);
|
writeu8(pstate, OP_SETOBJECT);
|
||||||
valuePopped(pstate, 2); // pops key, value & object
|
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 {
|
} else {
|
||||||
writeu8(pstate, OP_GETOBJECT);
|
writeu8(pstate, OP_GETOBJECT);
|
||||||
// pops key & object but also pushes the field so total popped is 1
|
// 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);
|
expression(pstate);
|
||||||
} while (match(pstate, TOKEN_COMMA));
|
} 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);
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
writeu8(pstate, OP_NIL);
|
writeu8(pstate, OP_NIL);
|
||||||
valuePushed(pstate, 1);
|
valuePushed(pstate, 1);
|
||||||
|
@ -7,8 +7,7 @@ typedef enum {
|
|||||||
COSMO_TNIL,
|
COSMO_TNIL,
|
||||||
COSMO_TBOOLEAN,
|
COSMO_TBOOLEAN,
|
||||||
COSMO_TNUMBER,
|
COSMO_TNUMBER,
|
||||||
COSMO_TOBJ,
|
COSMO_TOBJ
|
||||||
COSMO_TUSERDATA
|
|
||||||
} CosmoType;
|
} CosmoType;
|
||||||
|
|
||||||
typedef double cosmo_Number;
|
typedef double cosmo_Number;
|
||||||
@ -21,7 +20,6 @@ typedef struct CValue {
|
|||||||
union {
|
union {
|
||||||
cosmo_Number num;
|
cosmo_Number num;
|
||||||
bool b; // boolean
|
bool b; // boolean
|
||||||
void *ptr; // userdata
|
|
||||||
CObj *obj;
|
CObj *obj;
|
||||||
} val;
|
} val;
|
||||||
} CValue;
|
} CValue;
|
||||||
|
92
src/cvm.c
92
src/cvm.c
@ -87,10 +87,11 @@ void pushCallFrame(CState *state, CObjClosure *closure, int args) {
|
|||||||
frame->closure = closure;
|
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
|
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--;
|
state->frameCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +113,18 @@ typedef enum {
|
|||||||
CALL_CFUNCTION
|
CALL_CFUNCTION
|
||||||
} preCallResult;
|
} 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.
|
// missmatched args, thats an obvious user error, so error.
|
||||||
if (args != closure->function->args) {
|
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);
|
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);
|
CValue* result = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
// pop the callframe and return result :)
|
// pop the callframe and return result :)
|
||||||
popCallFrame(state);
|
popCallFrame(state, offset);
|
||||||
|
|
||||||
// push the return value back onto the stack
|
// push the return value back onto the stack
|
||||||
cosmoV_pushValue(state, *result);
|
cosmoV_pushValue(state, *result);
|
||||||
@ -139,36 +151,10 @@ bool call(CState *state, CObjClosure *closure, int args) {
|
|||||||
|
|
||||||
bool callMethod(CState* state, CObjMethod *method, int args) {
|
bool callMethod(CState* state, CObjMethod *method, int args) {
|
||||||
if (method->isCFunc) {
|
if (method->isCFunc) {
|
||||||
StkPtr savedBase = state->top - args - 1;
|
callCFunction(state, method->cfunc->cfunc, args+1, 1);
|
||||||
|
|
||||||
cosmoM_freezeGC(state);
|
|
||||||
CValue res = method->cfunc->cfunc(state, args+1, savedBase);
|
|
||||||
cosmoM_unfreezeGC(state);
|
|
||||||
|
|
||||||
state->top = savedBase;
|
|
||||||
cosmoV_pushValue(state, res);
|
|
||||||
} else {
|
} else {
|
||||||
CObjClosure *closure = method->closure;
|
CObjClosure *closure = method->closure;
|
||||||
|
call(state, closure, args+1, 1); // offset = 1 so our stack is properly reset
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -186,7 +172,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
|||||||
switch (val->val.obj->type) {
|
switch (val->val.obj->type) {
|
||||||
case COBJ_CLOSURE: {
|
case COBJ_CLOSURE: {
|
||||||
CObjClosure *closure = (CObjClosure*)(val->val.obj);
|
CObjClosure *closure = (CObjClosure*)(val->val.obj);
|
||||||
if (!call(state, closure, args)) {
|
if (!call(state, closure, args, 0)) {
|
||||||
return COSMOVM_RUNTIME_ERR;
|
return COSMOVM_RUNTIME_ERR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -223,14 +209,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
|||||||
case COBJ_CFUNCTION: {
|
case COBJ_CFUNCTION: {
|
||||||
// it's a C function, so call it
|
// it's a C function, so call it
|
||||||
CosmoCFunction cfunc = ((CObjCFunction*)(val->val.obj))->cfunc;
|
CosmoCFunction cfunc = ((CObjCFunction*)(val->val.obj))->cfunc;
|
||||||
CValue *savedBase = state->top - args;
|
callCFunction(state, cfunc, args, 0);
|
||||||
|
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -446,6 +425,37 @@ bool cosmoV_execute(CState *state) {
|
|||||||
cosmoV_setTop(state, 3);
|
cosmoV_setTop(state, 3);
|
||||||
break;
|
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
|
case OP_ADD: { // pop 2 values off the stack & try to add them together
|
||||||
BINARYOP(cosmoV_newNumber, +);
|
BINARYOP(cosmoV_newNumber, +);
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,7 @@ class test
|
|||||||
end
|
end
|
||||||
|
|
||||||
var obj = test("Hello world")
|
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)
|
obj.print(i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user