mirror of
https://github.com/CPunch/Cosmo.git
synced 2025-05-04 17:00:07 +00:00
Compare commits
2 Commits
861607d6a8
...
dcf6a09dae
Author | SHA1 | Date | |
---|---|---|---|
dcf6a09dae | |||
e0faa14b35 |
16
src/cdebug.c
16
src/cdebug.c
@ -9,53 +9,53 @@ void printIndent(int indent)
|
|||||||
printf("\t");
|
printf("\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
int simpleInstruction(const char *name, int offset)
|
static int simpleInstruction(const char *name, int offset)
|
||||||
{
|
{
|
||||||
printf("%s", name);
|
printf("%s", name);
|
||||||
return offset + 1; // consume opcode
|
return offset + 1; // consume opcode
|
||||||
}
|
}
|
||||||
|
|
||||||
int u8OperandInstruction(const char *name, CChunk *chunk, int offset)
|
static int u8OperandInstruction(const char *name, CChunk *chunk, int offset)
|
||||||
{
|
{
|
||||||
printf("%-16s [%03d]", name, readu8Chunk(chunk, offset + 1));
|
printf("%-16s [%03d]", name, readu8Chunk(chunk, offset + 1));
|
||||||
return offset + 2;
|
return offset + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int u16OperandInstruction(const char *name, CChunk *chunk, int offset)
|
static int u16OperandInstruction(const char *name, CChunk *chunk, int offset)
|
||||||
{
|
{
|
||||||
printf("%-16s [%05d]", name, readu16Chunk(chunk, offset + 1));
|
printf("%-16s [%05d]", name, readu16Chunk(chunk, offset + 1));
|
||||||
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
|
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
int JumpInstruction(const char *name, CChunk *chunk, int offset, int dir)
|
static int JumpInstruction(const char *name, CChunk *chunk, int offset, int dir)
|
||||||
{
|
{
|
||||||
int jmp = ((int)readu16Chunk(chunk, offset + 1)) * dir;
|
int jmp = ((int)readu16Chunk(chunk, offset + 1)) * dir;
|
||||||
printf("%-16s [%05d] - jumps to %04d", name, jmp, offset + 3 + jmp);
|
printf("%-16s [%05d] - jumps to %04d", name, jmp, offset + 3 + jmp);
|
||||||
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
|
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
int u8u8OperandInstruction(const char *name, CChunk *chunk, int offset)
|
static int u8u8OperandInstruction(const char *name, CChunk *chunk, int offset)
|
||||||
{
|
{
|
||||||
printf("%-16s [%03d] [%03d]", name, readu8Chunk(chunk, offset + 1),
|
printf("%-16s [%03d] [%03d]", name, readu8Chunk(chunk, offset + 1),
|
||||||
readu8Chunk(chunk, offset + 2));
|
readu8Chunk(chunk, offset + 2));
|
||||||
return offset + 3; // op + u8 + u8
|
return offset + 3; // op + u8 + u8
|
||||||
}
|
}
|
||||||
|
|
||||||
int u8u16OperandInstruction(const char *name, CChunk *chunk, int offset)
|
static int u8u16OperandInstruction(const char *name, CChunk *chunk, int offset)
|
||||||
{
|
{
|
||||||
printf("%-16s [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1),
|
printf("%-16s [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1),
|
||||||
readu16Chunk(chunk, offset + 2));
|
readu16Chunk(chunk, offset + 2));
|
||||||
return offset + 4; // op + u8 + u16
|
return offset + 4; // op + u8 + u16
|
||||||
}
|
}
|
||||||
|
|
||||||
int u8u8u16OperandInstruction(const char *name, CChunk *chunk, int offset)
|
static int u8u8u16OperandInstruction(const char *name, CChunk *chunk, int offset)
|
||||||
{
|
{
|
||||||
printf("%-16s [%03d] [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1),
|
printf("%-16s [%03d] [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1),
|
||||||
readu8Chunk(chunk, offset + 2), readu16Chunk(chunk, offset + 3));
|
readu8Chunk(chunk, offset + 2), readu16Chunk(chunk, offset + 3));
|
||||||
return offset + 5; // op + u8 + u8 + u16
|
return offset + 5; // op + u8 + u8 + u16
|
||||||
}
|
}
|
||||||
|
|
||||||
int constInstruction(const char *name, CChunk *chunk, int offset)
|
static int constInstruction(const char *name, CChunk *chunk, int offset)
|
||||||
{
|
{
|
||||||
int index = readu16Chunk(chunk, offset + 1);
|
int index = readu16Chunk(chunk, offset + 1);
|
||||||
printf("%-16s [%05d] - ", name, index);
|
printf("%-16s [%05d] - ", name, index);
|
||||||
|
16
src/clex.c
16
src/clex.c
@ -150,7 +150,7 @@ static bool match(CLexState *state, char expected)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char peek(CLexState *state)
|
static char peek(CLexState *state)
|
||||||
{
|
{
|
||||||
return *state->currentChar;
|
return *state->currentChar;
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ static char peekNext(CLexState *state)
|
|||||||
return state->currentChar[1];
|
return state->currentChar[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
char next(CLexState *state)
|
static char next(CLexState *state)
|
||||||
{
|
{
|
||||||
if (isEnd(state))
|
if (isEnd(state))
|
||||||
return '\0'; // return a null terminator
|
return '\0'; // return a null terminator
|
||||||
@ -171,12 +171,12 @@ char next(CLexState *state)
|
|||||||
return state->currentChar[-1];
|
return state->currentChar[-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isHex(char c)
|
static bool isHex(char c)
|
||||||
{
|
{
|
||||||
return isNumerical(c) || ('A' <= c && 'F' >= c) || ('a' <= c && 'f' >= c);
|
return isNumerical(c) || ('A' <= c && 'F' >= c) || ('a' <= c && 'f' >= c);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTokenType identifierType(CLexState *state)
|
static CTokenType identifierType(CLexState *state)
|
||||||
{
|
{
|
||||||
int length = state->currentChar - state->startChar;
|
int length = state->currentChar - state->startChar;
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ CTokenType identifierType(CLexState *state)
|
|||||||
return TOKEN_IDENTIFIER;
|
return TOKEN_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void skipWhitespace(CLexState *state)
|
static void skipWhitespace(CLexState *state)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
char c = peek(state);
|
char c = peek(state);
|
||||||
@ -235,7 +235,7 @@ void skipWhitespace(CLexState *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CToken parseString(CLexState *state)
|
static CToken parseString(CLexState *state)
|
||||||
{
|
{
|
||||||
makeBuffer(state); // buffer mode
|
makeBuffer(state); // buffer mode
|
||||||
while (peek(state) != '"' && !isEnd(state)) {
|
while (peek(state) != '"' && !isEnd(state)) {
|
||||||
@ -341,7 +341,7 @@ CToken parseString(CLexState *state)
|
|||||||
return makeToken(state, TOKEN_STRING);
|
return makeToken(state, TOKEN_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
CToken parseNumber(CLexState *state)
|
static CToken parseNumber(CLexState *state)
|
||||||
{
|
{
|
||||||
switch (peek(state)) {
|
switch (peek(state)) {
|
||||||
case 'x': // hexadecimal number
|
case 'x': // hexadecimal number
|
||||||
@ -380,7 +380,7 @@ CToken parseNumber(CLexState *state)
|
|||||||
return makeToken(state, TOKEN_NUMBER);
|
return makeToken(state, TOKEN_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
CToken parseIdentifier(CLexState *state)
|
static CToken parseIdentifier(CLexState *state)
|
||||||
{
|
{
|
||||||
// read literal
|
// read literal
|
||||||
while ((isAlpha(peek(state)) || isNumerical(peek(state))) && !isEnd(state))
|
while ((isAlpha(peek(state)) || isNumerical(peek(state))) && !isEnd(state))
|
||||||
|
@ -93,7 +93,7 @@ typedef struct
|
|||||||
char *currentChar;
|
char *currentChar;
|
||||||
char *startChar;
|
char *startChar;
|
||||||
char *buffer; // if non-NULL & bufCount > 0, token->start & token->length will be set to buffer
|
char *buffer; // if non-NULL & bufCount > 0, token->start & token->length will be set to buffer
|
||||||
// & bufCount respectively
|
// & bufCount respectively. used exclusively for string literals
|
||||||
size_t bufCount;
|
size_t bufCount;
|
||||||
size_t bufCap;
|
size_t bufCap;
|
||||||
int line; // current line
|
int line; // current line
|
||||||
|
24
src/cmem.c
24
src/cmem.c
@ -51,10 +51,10 @@ COSMO_API bool cosmoM_checkGarbage(CState *state, size_t needed)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void markObject(CState *state, CObj *obj);
|
static void markObject(CState *state, CObj *obj);
|
||||||
void markValue(CState *state, CValue val);
|
static void markValue(CState *state, CValue val);
|
||||||
|
|
||||||
void markTable(CState *state, CTable *tbl)
|
static void markTable(CState *state, CTable *tbl)
|
||||||
{
|
{
|
||||||
if (tbl->table == NULL) // table is still being initialized
|
if (tbl->table == NULL) // table is still being initialized
|
||||||
return;
|
return;
|
||||||
@ -68,7 +68,7 @@ void markTable(CState *state, CTable *tbl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// frees white members from the table
|
// frees white members from the table
|
||||||
void tableRemoveWhite(CState *state, CTable *tbl)
|
static void tableRemoveWhite(CState *state, CTable *tbl)
|
||||||
{
|
{
|
||||||
if (tbl->table == NULL) // table is still being initialized
|
if (tbl->table == NULL) // table is still being initialized
|
||||||
return;
|
return;
|
||||||
@ -86,7 +86,7 @@ void tableRemoveWhite(CState *state, CTable *tbl)
|
|||||||
cosmoT_checkShrink(state, tbl); // recovers the memory we're no longer using
|
cosmoT_checkShrink(state, tbl); // recovers the memory we're no longer using
|
||||||
}
|
}
|
||||||
|
|
||||||
void markArray(CState *state, CValueArray *array)
|
static void markArray(CState *state, CValueArray *array)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < array->count; i++) {
|
for (size_t i = 0; i < array->count; i++) {
|
||||||
markValue(state, array->values[i]);
|
markValue(state, array->values[i]);
|
||||||
@ -95,7 +95,7 @@ void markArray(CState *state, CValueArray *array)
|
|||||||
|
|
||||||
// mark all references associated with the object
|
// mark all references associated with the object
|
||||||
// black = keep, white = discard
|
// black = keep, white = discard
|
||||||
void blackenObject(CState *state, CObj *obj)
|
static void blackenObject(CState *state, CObj *obj)
|
||||||
{
|
{
|
||||||
markObject(state, (CObj *)obj->proto);
|
markObject(state, (CObj *)obj->proto);
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
@ -161,7 +161,7 @@ void blackenObject(CState *state, CObj *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void markObject(CState *state, CObj *obj)
|
static void markObject(CState *state, CObj *obj)
|
||||||
{
|
{
|
||||||
if (obj == NULL || obj->isMarked) // skip if NULL or already marked
|
if (obj == NULL || obj->isMarked) // skip if NULL or already marked
|
||||||
return;
|
return;
|
||||||
@ -185,14 +185,14 @@ void markObject(CState *state, CObj *obj)
|
|||||||
state->grayStack.array[state->grayStack.count++] = obj;
|
state->grayStack.array[state->grayStack.count++] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void markValue(CState *state, CValue val)
|
static void markValue(CState *state, CValue val)
|
||||||
{
|
{
|
||||||
if (IS_REF(val))
|
if (IS_REF(val))
|
||||||
markObject(state, cosmoV_readRef(val));
|
markObject(state, cosmoV_readRef(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace our gray references
|
// trace our gray references
|
||||||
void traceGrays(CState *state)
|
static void traceGrays(CState *state)
|
||||||
{
|
{
|
||||||
while (state->grayStack.count > 0) {
|
while (state->grayStack.count > 0) {
|
||||||
CObj *obj = state->grayStack.array[--state->grayStack.count];
|
CObj *obj = state->grayStack.array[--state->grayStack.count];
|
||||||
@ -200,7 +200,7 @@ void traceGrays(CState *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sweep(CState *state)
|
static void sweep(CState *state)
|
||||||
{
|
{
|
||||||
CObj *prev = NULL;
|
CObj *prev = NULL;
|
||||||
CObj *object = state->objects;
|
CObj *object = state->objects;
|
||||||
@ -224,7 +224,7 @@ void sweep(CState *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void markUserRoots(CState *state)
|
static void markUserRoots(CState *state)
|
||||||
{
|
{
|
||||||
CObj *root = state->userRoots;
|
CObj *root = state->userRoots;
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ void markUserRoots(CState *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void markRoots(CState *state)
|
static void markRoots(CState *state)
|
||||||
{
|
{
|
||||||
// mark all values on the stack
|
// mark all values on the stack
|
||||||
for (StkPtr value = state->stack; value < state->top; value++) {
|
for (StkPtr value = state->stack; value < state->top; value++) {
|
||||||
|
@ -67,6 +67,7 @@ COSMO_API void cosmoM_collectGarbage(CState *state);
|
|||||||
COSMO_API void cosmoM_updateThreshhold(CState *state);
|
COSMO_API void cosmoM_updateThreshhold(CState *state);
|
||||||
|
|
||||||
// lets the VM know you are holding a reference to a CObj and to not free it
|
// lets the VM know you are holding a reference to a CObj and to not free it
|
||||||
|
// NOTE: prefer to use the stack when possible
|
||||||
COSMO_API void cosmoM_addRoot(CState *state, CObj *newRoot);
|
COSMO_API void cosmoM_addRoot(CState *state, CObj *newRoot);
|
||||||
|
|
||||||
// lets the VM know this root is no longer held in a reference and is able to be freed
|
// lets the VM know this root is no longer held in a reference and is able to be freed
|
||||||
|
@ -64,7 +64,7 @@ typedef enum
|
|||||||
OP_FALSE,
|
OP_FALSE,
|
||||||
OP_NIL,
|
OP_NIL,
|
||||||
|
|
||||||
OP_RETURN
|
OP_RETURN,
|
||||||
} COPCODE; // there can be a max of 256 instructions
|
} COPCODE; // there can be a max of 256 instructions
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
10
src/cosmo.h
10
src/cosmo.h
@ -14,7 +14,15 @@
|
|||||||
performance, however this will produce undefined behavior as you reach the stack limit (and may
|
performance, however this will produce undefined behavior as you reach the stack limit (and may
|
||||||
cause a seg fault!). It is recommended to keep this enabled.
|
cause a seg fault!). It is recommended to keep this enabled.
|
||||||
*/
|
*/
|
||||||
#define SAFE_STACK
|
// #define SAFE_STACK
|
||||||
|
|
||||||
|
/*
|
||||||
|
NAN_BOXXED:
|
||||||
|
if undefined, the interpreter will use a tagged union to store values. This is the default.
|
||||||
|
Note that even though the sizeof(CValue) is 8 bytes for NAN_BOXXED (as opposed to 16 bytes for
|
||||||
|
the tagged union) no performance benefits were measured. I recommend keeping this undefined for
|
||||||
|
now.
|
||||||
|
*/
|
||||||
// #define NAN_BOXXED
|
// #define NAN_BOXXED
|
||||||
|
|
||||||
// forward declare *most* stuff so our headers are cleaner
|
// forward declare *most* stuff so our headers are cleaner
|
||||||
|
13
src/ctable.c
13
src/ctable.c
@ -11,7 +11,7 @@
|
|||||||
#define MIN_TABLE_CAPACITY ARRAY_START
|
#define MIN_TABLE_CAPACITY ARRAY_START
|
||||||
|
|
||||||
// bit-twiddling hacks, gets the next power of 2
|
// bit-twiddling hacks, gets the next power of 2
|
||||||
unsigned int nextPow2(unsigned int x)
|
static unsigned int nextPow2(unsigned int x)
|
||||||
{
|
{
|
||||||
if (x <= ARRAY_START - 1)
|
if (x <= ARRAY_START - 1)
|
||||||
return ARRAY_START; // sanity check
|
return ARRAY_START; // sanity check
|
||||||
@ -46,13 +46,14 @@ void cosmoT_initTable(CState *state, CTable *tbl, int startCap)
|
|||||||
|
|
||||||
void cosmoT_addTable(CState *state, CTable *from, CTable *to)
|
void cosmoT_addTable(CState *state, CTable *from, CTable *to)
|
||||||
{
|
{
|
||||||
|
CTableEntry *entry;
|
||||||
int cap = from->capacityMask + 1;
|
int cap = from->capacityMask + 1;
|
||||||
|
|
||||||
for (int i = 0; i < cap; i++) {
|
for (int i = 0; i < cap; i++) {
|
||||||
CTableEntry *entry = &from->table[i];
|
entry = &from->table[i];
|
||||||
|
|
||||||
if (!(IS_NIL(entry->key))) {
|
if (!(IS_NIL(entry->key))) {
|
||||||
CValue *newVal = cosmoT_insert(state, to, entry->key);
|
*cosmoT_insert(state, to, entry->key) = entry->val;
|
||||||
*newVal = entry->val;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,7 +63,7 @@ void cosmoT_clearTable(CState *state, CTable *tbl)
|
|||||||
cosmoM_freearray(state, CTableEntry, tbl->table, (tbl->capacityMask + 1));
|
cosmoM_freearray(state, CTableEntry, tbl->table, (tbl->capacityMask + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getObjectHash(CObj *obj)
|
static uint32_t getObjectHash(CObj *obj)
|
||||||
{
|
{
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case COBJ_STRING:
|
case COBJ_STRING:
|
||||||
@ -72,7 +73,7 @@ uint32_t getObjectHash(CObj *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getValueHash(CValue *val)
|
static uint32_t getValueHash(CValue *val)
|
||||||
{
|
{
|
||||||
switch (GET_TYPE(*val)) {
|
switch (GET_TYPE(*val)) {
|
||||||
case COSMO_TREF:
|
case COSMO_TREF:
|
||||||
|
391
src/cvm.c
391
src/cvm.c
@ -672,15 +672,62 @@ int _tbl__next(CState *state, int nargs, CValue *args)
|
|||||||
return -1; \
|
return -1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t READBYTE(CCallFrame *frame)
|
||||||
|
{
|
||||||
|
return *frame->pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t READUINT(CCallFrame *frame)
|
||||||
|
{
|
||||||
|
frame->pc += 2;
|
||||||
|
return *(uint16_t *)(&frame->pc[-2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VM_JUMPTABLE
|
||||||
|
# define DISPATCH goto *cosmoV_dispatchTable[READBYTE(frame)]
|
||||||
|
# define CASE(op) \
|
||||||
|
DISPATCH; \
|
||||||
|
JMP_##op
|
||||||
|
# define JMPLABEL(op) &&JMP_##op
|
||||||
|
# define SWITCH \
|
||||||
|
static void *cosmoV_dispatchTable[] = { \
|
||||||
|
JMPLABEL(OP_LOADCONST), JMPLABEL(OP_SETGLOBAL), JMPLABEL(OP_GETGLOBAL), \
|
||||||
|
JMPLABEL(OP_SETLOCAL), JMPLABEL(OP_GETLOCAL), JMPLABEL(OP_GETUPVAL), \
|
||||||
|
JMPLABEL(OP_SETUPVAL), JMPLABEL(OP_PEJMP), JMPLABEL(OP_EJMP), \
|
||||||
|
JMPLABEL(OP_JMP), JMPLABEL(OP_JMPBACK), JMPLABEL(OP_POP), \
|
||||||
|
JMPLABEL(OP_CALL), JMPLABEL(OP_CLOSURE), JMPLABEL(OP_CLOSE), \
|
||||||
|
JMPLABEL(OP_NEWTABLE), JMPLABEL(OP_NEWARRAY), JMPLABEL(OP_INDEX), \
|
||||||
|
JMPLABEL(OP_NEWINDEX), JMPLABEL(OP_NEWOBJECT), JMPLABEL(OP_SETOBJECT), \
|
||||||
|
JMPLABEL(OP_GETOBJECT), JMPLABEL(OP_GETMETHOD), JMPLABEL(OP_INVOKE), \
|
||||||
|
JMPLABEL(OP_ITER), JMPLABEL(OP_NEXT), JMPLABEL(OP_ADD), \
|
||||||
|
JMPLABEL(OP_SUB), JMPLABEL(OP_MULT), JMPLABEL(OP_DIV), \
|
||||||
|
JMPLABEL(OP_MOD), JMPLABEL(OP_POW), JMPLABEL(OP_NOT), \
|
||||||
|
JMPLABEL(OP_NEGATE), JMPLABEL(OP_COUNT), JMPLABEL(OP_CONCAT), \
|
||||||
|
JMPLABEL(OP_INCLOCAL), JMPLABEL(OP_INCGLOBAL), JMPLABEL(OP_INCUPVAL), \
|
||||||
|
JMPLABEL(OP_INCINDEX), JMPLABEL(OP_INCOBJECT), JMPLABEL(OP_EQUAL), \
|
||||||
|
JMPLABEL(OP_LESS), JMPLABEL(OP_GREATER), JMPLABEL(OP_LESS_EQUAL), \
|
||||||
|
JMPLABEL(OP_GREATER_EQUAL), JMPLABEL(OP_TRUE), JMPLABEL(OP_FALSE), \
|
||||||
|
JMPLABEL(OP_NIL), JMPLABEL(OP_RETURN), \
|
||||||
|
}; \
|
||||||
|
DISPATCH;
|
||||||
|
# define DEFAULT DISPATCH /* no-op */
|
||||||
|
#else
|
||||||
|
# define CASE(op) \
|
||||||
|
continue; \
|
||||||
|
case op
|
||||||
|
# define SWITCH switch (READBYTE(frame))
|
||||||
|
# define DEFAULT \
|
||||||
|
default: \
|
||||||
|
CERROR("unknown opcode!"); \
|
||||||
|
exit(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
// returns -1 if panic
|
// returns -1 if panic
|
||||||
int cosmoV_execute(CState *state)
|
int cosmoV_execute(CState *state)
|
||||||
{
|
{
|
||||||
CCallFrame *frame = &state->callFrame[state->frameCount - 1]; // grabs the current frame
|
CCallFrame *frame = &state->callFrame[state->frameCount - 1]; // grabs the current frame
|
||||||
CValue *constants = frame->closure->function->chunk.constants.values; // cache the pointer :)
|
CValue *constants = frame->closure->function->chunk.constants.values; // cache the pointer :)
|
||||||
|
|
||||||
#define READBYTE() *frame->pc++
|
|
||||||
#define READUINT() (frame->pc += 2, *(uint16_t *)(&frame->pc[-2]))
|
|
||||||
|
|
||||||
while (!state->panic) {
|
while (!state->panic) {
|
||||||
#ifdef VM_DEBUG
|
#ifdef VM_DEBUG
|
||||||
cosmoV_printStack(state);
|
cosmoV_printStack(state);
|
||||||
@ -688,95 +735,98 @@ int cosmoV_execute(CState *state)
|
|||||||
frame->pc - frame->closure->function->chunk.buf, state->frameCount - 1);
|
frame->pc - frame->closure->function->chunk.buf, state->frameCount - 1);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
switch (READBYTE()) {
|
SWITCH
|
||||||
case OP_LOADCONST: { // push const[uint] to stack
|
{
|
||||||
uint16_t indx = READUINT();
|
CASE(OP_LOADCONST) :
|
||||||
|
{ // push const[uint] to stack
|
||||||
|
uint16_t indx = READUINT(frame);
|
||||||
cosmoV_pushValue(state, constants[indx]);
|
cosmoV_pushValue(state, constants[indx]);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_SETGLOBAL: {
|
CASE(OP_SETGLOBAL) :
|
||||||
uint16_t indx = READUINT();
|
{
|
||||||
|
uint16_t indx = READUINT(frame);
|
||||||
CValue ident = constants[indx]; // grabs identifier
|
CValue ident = constants[indx]; // grabs identifier
|
||||||
CValue *val = cosmoT_insert(state, &state->globals->tbl, ident);
|
CValue *val = cosmoT_insert(state, &state->globals->tbl, ident);
|
||||||
*val = *cosmoV_pop(state); // sets the value in the hash table
|
*val = *cosmoV_pop(state); // sets the value in the hash table
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_GETGLOBAL: {
|
CASE(OP_GETGLOBAL) :
|
||||||
uint16_t indx = READUINT();
|
{
|
||||||
|
uint16_t indx = READUINT(frame);
|
||||||
CValue ident = constants[indx]; // grabs identifier
|
CValue ident = constants[indx]; // grabs identifier
|
||||||
CValue val; // to hold our value
|
CValue val; // to hold our value
|
||||||
cosmoT_get(state, &state->globals->tbl, ident, &val);
|
cosmoT_get(state, &state->globals->tbl, ident, &val);
|
||||||
cosmoV_pushValue(state, val); // pushes the value to the stack
|
cosmoV_pushValue(state, val); // pushes the value to the stack
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_SETLOCAL: {
|
CASE(OP_SETLOCAL) :
|
||||||
uint8_t indx = READBYTE();
|
{
|
||||||
|
uint8_t indx = READBYTE(frame);
|
||||||
// set base to top of stack & pop
|
// set base to top of stack & pop
|
||||||
frame->base[indx] = *cosmoV_pop(state);
|
frame->base[indx] = *cosmoV_pop(state);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_GETLOCAL: {
|
CASE(OP_GETLOCAL) :
|
||||||
uint8_t indx = READBYTE();
|
{
|
||||||
|
uint8_t indx = READBYTE(frame);
|
||||||
cosmoV_pushValue(state, frame->base[indx]);
|
cosmoV_pushValue(state, frame->base[indx]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case OP_GETUPVAL: {
|
CASE(OP_GETUPVAL) :
|
||||||
uint8_t indx = READBYTE();
|
{
|
||||||
|
uint8_t indx = READBYTE(frame);
|
||||||
cosmoV_pushValue(state, *frame->closure->upvalues[indx]->val);
|
cosmoV_pushValue(state, *frame->closure->upvalues[indx]->val);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_SETUPVAL: {
|
CASE(OP_SETUPVAL) :
|
||||||
uint8_t indx = READBYTE();
|
{
|
||||||
|
uint8_t indx = READBYTE(frame);
|
||||||
*frame->closure->upvalues[indx]->val = *cosmoV_pop(state);
|
*frame->closure->upvalues[indx]->val = *cosmoV_pop(state);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_PEJMP: { // pop equality jump
|
CASE(OP_PEJMP) :
|
||||||
uint16_t offset = READUINT();
|
{ // pop equality jump
|
||||||
|
uint16_t offset = READUINT(frame);
|
||||||
|
|
||||||
if (isFalsey(cosmoV_pop(state))) { // pop, if the condition is false, jump!
|
if (isFalsey(cosmoV_pop(state))) { // pop, if the condition is false, jump!
|
||||||
frame->pc += offset;
|
frame->pc += offset;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_EJMP: { // equality jump
|
CASE(OP_EJMP) :
|
||||||
uint16_t offset = READUINT();
|
{ // equality jump
|
||||||
|
uint16_t offset = READUINT(frame);
|
||||||
|
|
||||||
if (isFalsey(cosmoV_getTop(state, 0))) { // if the condition is false, jump!
|
if (isFalsey(cosmoV_getTop(state, 0))) { // if the condition is false, jump!
|
||||||
frame->pc += offset;
|
frame->pc += offset;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_JMP: { // jump
|
CASE(OP_JMP) :
|
||||||
uint16_t offset = READUINT();
|
{ // jump
|
||||||
|
uint16_t offset = READUINT(frame);
|
||||||
frame->pc += offset;
|
frame->pc += offset;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_JMPBACK: {
|
CASE(OP_JMPBACK) :
|
||||||
uint16_t offset = READUINT();
|
{
|
||||||
|
uint16_t offset = READUINT(frame);
|
||||||
frame->pc -= offset;
|
frame->pc -= offset;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_POP: { // pops value off the stack
|
CASE(OP_POP) :
|
||||||
cosmoV_setTop(state, READBYTE());
|
{ // pops value off the stack
|
||||||
continue;
|
cosmoV_setTop(state, READBYTE(frame));
|
||||||
}
|
}
|
||||||
case OP_CALL: {
|
CASE(OP_CALL) :
|
||||||
uint8_t args = READBYTE();
|
{
|
||||||
uint8_t nres = READBYTE();
|
uint8_t args = READBYTE(frame);
|
||||||
|
uint8_t nres = READBYTE(frame);
|
||||||
if (cosmoV_call(state, args, nres) != COSMOVM_OK) {
|
if (cosmoV_call(state, args, nres) != COSMOVM_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_CLOSURE: {
|
CASE(OP_CLOSURE) :
|
||||||
uint16_t index = READUINT();
|
{
|
||||||
|
uint16_t index = READUINT(frame);
|
||||||
CObjFunction *func = cosmoV_readFunction(constants[index]);
|
CObjFunction *func = cosmoV_readFunction(constants[index]);
|
||||||
CObjClosure *closure = cosmoO_newClosure(state, func);
|
CObjClosure *closure = cosmoO_newClosure(state, func);
|
||||||
cosmoV_pushRef(state, (CObj *)closure);
|
cosmoV_pushRef(state, (CObj *)closure);
|
||||||
|
|
||||||
for (int i = 0; i < closure->upvalueCount; i++) {
|
for (int i = 0; i < closure->upvalueCount; i++) {
|
||||||
uint8_t encoding = READBYTE();
|
uint8_t encoding = READBYTE(frame);
|
||||||
uint8_t index = READBYTE();
|
uint8_t index = READBYTE(frame);
|
||||||
if (encoding == OP_GETUPVAL) {
|
if (encoding == OP_GETUPVAL) {
|
||||||
// capture upvalue from current frame's closure
|
// capture upvalue from current frame's closure
|
||||||
closure->upvalues[i] = frame->closure->upvalues[index];
|
closure->upvalues[i] = frame->closure->upvalues[index];
|
||||||
@ -785,21 +835,20 @@ int cosmoV_execute(CState *state)
|
|||||||
closure->upvalues[i] = captureUpvalue(state, frame->base + index);
|
closure->upvalues[i] = captureUpvalue(state, frame->base + index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_CLOSE: {
|
CASE(OP_CLOSE) :
|
||||||
|
{
|
||||||
closeUpvalues(state, state->top - 1);
|
closeUpvalues(state, state->top - 1);
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NEWTABLE: {
|
CASE(OP_NEWTABLE) :
|
||||||
uint16_t pairs = READUINT();
|
{
|
||||||
|
uint16_t pairs = READUINT(frame);
|
||||||
cosmoV_makeTable(state, pairs);
|
cosmoV_makeTable(state, pairs);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NEWARRAY: {
|
CASE(OP_NEWARRAY) :
|
||||||
uint16_t pairs = READUINT();
|
{
|
||||||
|
uint16_t pairs = READUINT(frame);
|
||||||
StkPtr val;
|
StkPtr val;
|
||||||
CObjTable *newObj = cosmoO_newTable(state);
|
CObjTable *newObj = cosmoO_newTable(state);
|
||||||
cosmoV_pushRef(state, (CObj *)newObj); // so our GC doesn't free our new table
|
cosmoV_pushRef(state, (CObj *)newObj); // so our GC doesn't free our new table
|
||||||
@ -816,9 +865,9 @@ int cosmoV_execute(CState *state)
|
|||||||
// once done, pop everything off the stack + push new table
|
// once done, pop everything off the stack + push new table
|
||||||
cosmoV_setTop(state, pairs + 1); // + 1 for our table
|
cosmoV_setTop(state, pairs + 1); // + 1 for our table
|
||||||
cosmoV_pushRef(state, (CObj *)newObj);
|
cosmoV_pushRef(state, (CObj *)newObj);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INDEX: {
|
CASE(OP_INDEX) :
|
||||||
|
{
|
||||||
StkPtr key = cosmoV_getTop(state, 0); // key should be the top of the stack
|
StkPtr key = cosmoV_getTop(state, 0); // key should be the top of the stack
|
||||||
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table
|
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table
|
||||||
|
|
||||||
@ -849,9 +898,9 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
cosmoV_setTop(state, 2); // pops the table & the key
|
cosmoV_setTop(state, 2); // pops the table & the key
|
||||||
cosmoV_pushValue(state, val); // pushes the field result
|
cosmoV_pushValue(state, val); // pushes the field result
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NEWINDEX: {
|
CASE(OP_NEWINDEX) :
|
||||||
|
{
|
||||||
StkPtr value = cosmoV_getTop(state, 0); // value is at the top of the stack
|
StkPtr value = cosmoV_getTop(state, 0); // value is at the top of the stack
|
||||||
StkPtr key = cosmoV_getTop(state, 1);
|
StkPtr key = cosmoV_getTop(state, 1);
|
||||||
StkPtr temp = cosmoV_getTop(state, 2); // table is after the key
|
StkPtr temp = cosmoV_getTop(state, 2); // table is after the key
|
||||||
@ -866,7 +915,8 @@ int cosmoV_execute(CState *state)
|
|||||||
CObjObject *proto = cosmoO_grabProto(obj);
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
|
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
if (!cosmoO_newIndexObject(state, proto, *key,
|
if (!cosmoO_newIndexObject(
|
||||||
|
state, proto, *key,
|
||||||
*value)) // if it returns false, cosmoV_error was called
|
*value)) // if it returns false, cosmoV_error was called
|
||||||
return -1;
|
return -1;
|
||||||
} else if (obj->type == COBJ_TABLE) {
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
@ -882,17 +932,17 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
// pop everything off the stack
|
// pop everything off the stack
|
||||||
cosmoV_setTop(state, 3);
|
cosmoV_setTop(state, 3);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NEWOBJECT: {
|
CASE(OP_NEWOBJECT) :
|
||||||
uint16_t pairs = READUINT();
|
{
|
||||||
|
uint16_t pairs = READUINT(frame);
|
||||||
cosmoV_makeObject(state, pairs);
|
cosmoV_makeObject(state, pairs);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_SETOBJECT: {
|
CASE(OP_SETOBJECT) :
|
||||||
|
{
|
||||||
StkPtr value = cosmoV_getTop(state, 0); // value is at the top of the stack
|
StkPtr value = cosmoV_getTop(state, 0); // value is at the top of the stack
|
||||||
StkPtr temp = cosmoV_getTop(state, 1); // object is after the value
|
StkPtr temp = cosmoV_getTop(state, 1); // object is after the value
|
||||||
uint16_t ident = READUINT(); // use for the key
|
uint16_t ident = READUINT(frame); // use for the key
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
@ -907,12 +957,12 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
// pop everything off the stack
|
// pop everything off the stack
|
||||||
cosmoV_setTop(state, 2);
|
cosmoV_setTop(state, 2);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_GETOBJECT: {
|
CASE(OP_GETOBJECT) :
|
||||||
|
{
|
||||||
CValue val; // to hold our value
|
CValue val; // to hold our value
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
||||||
uint16_t ident = READUINT(); // use for the key
|
uint16_t ident = READUINT(frame); // use for the key
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
@ -927,15 +977,15 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
cosmoV_setTop(state, 1); // pops the object
|
cosmoV_setTop(state, 1); // pops the object
|
||||||
cosmoV_pushValue(state, val); // pushes the field result
|
cosmoV_pushValue(state, val); // pushes the field result
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_GETMETHOD: {
|
CASE(OP_GETMETHOD) :
|
||||||
|
{
|
||||||
CValue val; // to hold our value
|
CValue val; // to hold our value
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
||||||
uint16_t ident = READUINT(); // use for the key
|
uint16_t ident = READUINT(frame); // use for the key
|
||||||
|
|
||||||
// this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead of
|
// this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead
|
||||||
// just cosmoV_get
|
// of just cosmoV_get
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
if (!cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val))
|
if (!cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val))
|
||||||
return -1;
|
return -1;
|
||||||
@ -948,12 +998,12 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
cosmoV_setTop(state, 1); // pops the object
|
cosmoV_setTop(state, 1); // pops the object
|
||||||
cosmoV_pushValue(state, val); // pushes the field result
|
cosmoV_pushValue(state, val); // pushes the field result
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INVOKE: {
|
CASE(OP_INVOKE) :
|
||||||
uint8_t args = READBYTE();
|
{
|
||||||
uint8_t nres = READBYTE();
|
uint8_t args = READBYTE(frame);
|
||||||
uint16_t ident = READUINT();
|
uint8_t nres = READBYTE(frame);
|
||||||
|
uint16_t ident = READUINT(frame);
|
||||||
StkPtr temp = cosmoV_getTop(state, args); // grabs object from stack
|
StkPtr temp = cosmoV_getTop(state, args); // grabs object from stack
|
||||||
CValue val; // to hold our value
|
CValue val; // to hold our value
|
||||||
|
|
||||||
@ -969,10 +1019,9 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_ITER: {
|
CASE(OP_ITER) :
|
||||||
|
{
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // should be the object/table
|
StkPtr temp = cosmoV_getTop(state, 0); // should be the object/table
|
||||||
|
|
||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
@ -992,15 +1041,16 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
cosmoV_pushRef(state, (CObj *)obj);
|
cosmoV_pushRef(state, (CObj *)obj);
|
||||||
if (cosmoV_call(state, 1, 1) !=
|
if (cosmoV_call(state, 1, 1) !=
|
||||||
COSMOVM_OK) // we expect 1 return value on the stack, the iterable object
|
COSMOVM_OK) // we expect 1 return value on the stack, the iterable
|
||||||
|
// object
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
StkPtr iObj = cosmoV_getTop(state, 0);
|
StkPtr iObj = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
if (!IS_OBJECT(*iObj)) {
|
if (!IS_OBJECT(*iObj)) {
|
||||||
cosmoV_error(
|
cosmoV_error(state,
|
||||||
state,
|
"Expected iterable object! '__iter' returned %s, expected "
|
||||||
"Expected iterable object! '__iter' returned %s, expected <object>!",
|
"<object>!",
|
||||||
cosmoV_typeStr(*iObj));
|
cosmoV_typeStr(*iObj));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1022,11 +1072,13 @@ int cosmoV_execute(CState *state)
|
|||||||
CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next);
|
CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next);
|
||||||
cosmoV_pushRef(state, (CObj *)tbl_next); // value
|
cosmoV_pushRef(state, (CObj *)tbl_next); // value
|
||||||
|
|
||||||
CObjObject *obj = cosmoV_makeObject(state, 2); // pushes the new object to the stack
|
CObjObject *obj =
|
||||||
|
cosmoV_makeObject(state, 2); // pushes the new object to the stack
|
||||||
cosmoO_setUserI(obj, 0); // increment for iterator
|
cosmoO_setUserI(obj, 0); // increment for iterator
|
||||||
|
|
||||||
// make our CObjMethod for OP_NEXT to call
|
// make our CObjMethod for OP_NEXT to call
|
||||||
CObjMethod *method = cosmoO_newMethod(state, cosmoV_newRef(tbl_next), (CObj *)obj);
|
CObjMethod *method =
|
||||||
|
cosmoO_newMethod(state, cosmoV_newRef(tbl_next), (CObj *)obj);
|
||||||
|
|
||||||
cosmoV_setTop(state, 2); // pops the object & the tbl
|
cosmoV_setTop(state, 2); // pops the object & the tbl
|
||||||
cosmoV_pushRef(state, (CObj *)method); // pushes the method for OP_NEXT
|
cosmoV_pushRef(state, (CObj *)method); // pushes the method for OP_NEXT
|
||||||
@ -1035,12 +1087,11 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoO_typeStr(obj));
|
cosmoO_typeStr(obj));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NEXT: {
|
CASE(OP_NEXT) :
|
||||||
uint8_t nresults = READBYTE();
|
{
|
||||||
uint16_t jump = READUINT();
|
uint8_t nresults = READBYTE(frame);
|
||||||
|
uint16_t jump = READUINT(frame);
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // we don't actually pop this off the stack
|
StkPtr temp = cosmoV_getTop(state, 0); // we don't actually pop this off the stack
|
||||||
|
|
||||||
if (!IS_METHOD(*temp)) {
|
if (!IS_METHOD(*temp)) {
|
||||||
@ -1058,25 +1109,29 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_setTop(state, nresults); // pop the return values
|
cosmoV_setTop(state, nresults); // pop the return values
|
||||||
frame->pc += jump;
|
frame->pc += jump;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
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
|
||||||
NUMBEROP(cosmoV_newNumber, +);
|
NUMBEROP(cosmoV_newNumber, +);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_SUB: { // pop 2 values off the stack & try to subtracts them
|
CASE(OP_SUB) :
|
||||||
NUMBEROP(cosmoV_newNumber, -)
|
{
|
||||||
continue;
|
// pop 2 values off the stack & try to subtracts them
|
||||||
|
NUMBEROP(cosmoV_newNumber, -);
|
||||||
}
|
}
|
||||||
case OP_MULT: { // pop 2 values off the stack & try to multiplies them together
|
CASE(OP_MULT) :
|
||||||
NUMBEROP(cosmoV_newNumber, *)
|
{
|
||||||
continue;
|
// pop 2 values off the stack & try to multiplies them together
|
||||||
|
NUMBEROP(cosmoV_newNumber, *);
|
||||||
}
|
}
|
||||||
case OP_DIV: { // pop 2 values off the stack & try to divides them
|
CASE(OP_DIV) :
|
||||||
NUMBEROP(cosmoV_newNumber, /)
|
{
|
||||||
continue;
|
// pop 2 values off the stack & try to divides them
|
||||||
|
NUMBEROP(cosmoV_newNumber, /);
|
||||||
}
|
}
|
||||||
case OP_MOD: {
|
CASE(OP_MOD) :
|
||||||
|
{
|
||||||
StkPtr valA = cosmoV_getTop(state, 1);
|
StkPtr valA = cosmoV_getTop(state, 1);
|
||||||
StkPtr valB = cosmoV_getTop(state, 0);
|
StkPtr valB = cosmoV_getTop(state, 0);
|
||||||
if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) {
|
if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) {
|
||||||
@ -1088,9 +1143,9 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_typeStr(*valB));
|
cosmoV_typeStr(*valB));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_POW: {
|
CASE(OP_POW) :
|
||||||
|
{
|
||||||
StkPtr valA = cosmoV_getTop(state, 1);
|
StkPtr valA = cosmoV_getTop(state, 1);
|
||||||
StkPtr valB = cosmoV_getTop(state, 0);
|
StkPtr valB = cosmoV_getTop(state, 0);
|
||||||
if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) {
|
if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) {
|
||||||
@ -1102,13 +1157,13 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_typeStr(*valB));
|
cosmoV_typeStr(*valB));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NOT: {
|
CASE(OP_NOT) :
|
||||||
|
{
|
||||||
cosmoV_pushBoolean(state, isFalsey(cosmoV_pop(state)));
|
cosmoV_pushBoolean(state, isFalsey(cosmoV_pop(state)));
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_NEGATE: { // pop 1 value off the stack & try to negate
|
CASE(OP_NEGATE) :
|
||||||
|
{ // pop 1 value off the stack & try to negate
|
||||||
StkPtr val = cosmoV_getTop(state, 0);
|
StkPtr val = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
if (IS_NUMBER(*val)) {
|
if (IS_NUMBER(*val)) {
|
||||||
@ -1118,9 +1173,9 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_COUNT: {
|
CASE(OP_COUNT) :
|
||||||
|
{
|
||||||
StkPtr temp = cosmoV_getTop(state, 0);
|
StkPtr temp = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
@ -1132,16 +1187,16 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
|
|
||||||
cosmoV_pushNumber(state, count); // pushes the count onto the stack
|
cosmoV_pushNumber(state, count); // pushes the count onto the stack
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_CONCAT: {
|
CASE(OP_CONCAT) :
|
||||||
uint8_t vals = READBYTE();
|
{
|
||||||
|
uint8_t vals = READBYTE(frame);
|
||||||
cosmoV_concat(state, vals);
|
cosmoV_concat(state, vals);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INCLOCAL: { // this leaves the value on the stack
|
CASE(OP_INCLOCAL) :
|
||||||
int8_t inc = READBYTE() - 128; // amount we're incrementing by
|
{ // this leaves the value on the stack
|
||||||
uint8_t indx = READBYTE();
|
int8_t inc = READBYTE(frame) - 128; // amount we're incrementing by
|
||||||
|
uint8_t indx = READBYTE(frame);
|
||||||
StkPtr val = &frame->base[indx];
|
StkPtr val = &frame->base[indx];
|
||||||
|
|
||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
@ -1152,12 +1207,11 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INCGLOBAL: {
|
CASE(OP_INCGLOBAL) :
|
||||||
int8_t inc = READBYTE() - 128; // amount we're incrementing by
|
{
|
||||||
uint16_t indx = READUINT();
|
int8_t inc = READBYTE(frame) - 128; // amount we're incrementing by
|
||||||
|
uint16_t indx = READUINT(frame);
|
||||||
CValue ident = constants[indx]; // grabs identifier
|
CValue ident = constants[indx]; // grabs identifier
|
||||||
CValue *val = cosmoT_insert(state, &state->globals->tbl, ident);
|
CValue *val = cosmoT_insert(state, &state->globals->tbl, ident);
|
||||||
|
|
||||||
@ -1169,12 +1223,11 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INCUPVAL: {
|
CASE(OP_INCUPVAL) :
|
||||||
int8_t inc = READBYTE() - 128; // amount we're incrementing by
|
{
|
||||||
uint8_t indx = READBYTE();
|
int8_t inc = READBYTE(frame) - 128; // amount we're incrementing by
|
||||||
|
uint8_t indx = READBYTE(frame);
|
||||||
CValue *val = frame->closure->upvalues[indx]->val;
|
CValue *val = frame->closure->upvalues[indx]->val;
|
||||||
|
|
||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
@ -1185,16 +1238,16 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INCINDEX: {
|
CASE(OP_INCINDEX) :
|
||||||
int8_t inc = READBYTE() - 128; // amount we're incrementing by
|
{
|
||||||
|
int8_t inc = READBYTE(frame) - 128; // amount we're incrementing by
|
||||||
StkPtr temp = cosmoV_getTop(state, 1); // object should be above the key
|
StkPtr temp = cosmoV_getTop(state, 1); // object should be above the key
|
||||||
StkPtr key = cosmoV_getTop(state, 0); // grabs key
|
StkPtr key = cosmoV_getTop(state, 0); // grabs key
|
||||||
|
|
||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
cosmoV_error(state, "Couldn't index non-indexable type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't index non-indexable type %s!",
|
||||||
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1236,12 +1289,11 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_INCOBJECT: {
|
CASE(OP_INCOBJECT) :
|
||||||
int8_t inc = READBYTE() - 128; // amount we're incrementing by
|
{
|
||||||
uint16_t indx = READUINT();
|
int8_t inc = READBYTE(frame) - 128; // amount we're incrementing by
|
||||||
|
uint16_t indx = READUINT(frame);
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // object should be at the top of the stack
|
StkPtr temp = cosmoV_getTop(state, 0); // object should be at the top of the stack
|
||||||
CValue ident = constants[indx]; // grabs identifier
|
CValue ident = constants[indx]; // grabs identifier
|
||||||
|
|
||||||
@ -1270,57 +1322,42 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_EQUAL: {
|
CASE(OP_EQUAL) :
|
||||||
|
{
|
||||||
// pop vals
|
// pop vals
|
||||||
StkPtr valB = cosmoV_pop(state);
|
StkPtr valB = cosmoV_pop(state);
|
||||||
StkPtr valA = cosmoV_pop(state);
|
StkPtr valA = cosmoV_pop(state);
|
||||||
|
|
||||||
// compare & push
|
// compare & push
|
||||||
cosmoV_pushBoolean(state, cosmoV_equal(state, *valA, *valB));
|
cosmoV_pushBoolean(state, cosmoV_equal(state, *valA, *valB));
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case OP_GREATER: {
|
CASE(OP_GREATER) :
|
||||||
NUMBEROP(cosmoV_newBoolean, >)
|
{
|
||||||
continue;
|
NUMBEROP(cosmoV_newBoolean, >);
|
||||||
}
|
}
|
||||||
case OP_LESS: {
|
CASE(OP_LESS) :
|
||||||
NUMBEROP(cosmoV_newBoolean, <)
|
{
|
||||||
continue;
|
NUMBEROP(cosmoV_newBoolean, <);
|
||||||
}
|
}
|
||||||
case OP_GREATER_EQUAL: {
|
CASE(OP_GREATER_EQUAL) :
|
||||||
NUMBEROP(cosmoV_newBoolean, >=)
|
{
|
||||||
continue;
|
NUMBEROP(cosmoV_newBoolean, >=);
|
||||||
}
|
}
|
||||||
case OP_LESS_EQUAL: {
|
CASE(OP_LESS_EQUAL)
|
||||||
NUMBEROP(cosmoV_newBoolean, <=)
|
: {NUMBEROP(cosmoV_newBoolean, <=)} CASE(OP_TRUE) : cosmoV_pushBoolean(state, true);
|
||||||
continue;
|
CASE(OP_FALSE) : cosmoV_pushBoolean(state, false);
|
||||||
}
|
CASE(OP_NIL) : cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
case OP_TRUE:
|
CASE(OP_RETURN) :
|
||||||
cosmoV_pushBoolean(state, true);
|
{
|
||||||
continue;
|
uint8_t res = READBYTE(frame);
|
||||||
case OP_FALSE:
|
|
||||||
cosmoV_pushBoolean(state, false);
|
|
||||||
continue;
|
|
||||||
case OP_NIL:
|
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
|
||||||
continue;
|
|
||||||
case OP_RETURN: {
|
|
||||||
uint8_t res = READBYTE();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
default:
|
DEFAULT;
|
||||||
CERROR("unknown opcode!");
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef READBYTE
|
// we'll only reach this if state->panic is true
|
||||||
#undef READUINT
|
|
||||||
|
|
||||||
// we'll only reach this is state->panic is true
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
src/cvm.h
13
src/cvm.h
@ -8,6 +8,19 @@
|
|||||||
|
|
||||||
// #define VM_DEBUG
|
// #define VM_DEBUG
|
||||||
|
|
||||||
|
/*
|
||||||
|
if we're using GNUC or clang, we can use computed gotos which speeds up
|
||||||
|
cosmoV_execute by about 20% from benchmarking. of course, if you know
|
||||||
|
your compiler supports computed gotos, you can define VM_JUMPTABLE
|
||||||
|
|
||||||
|
BTW: be weary of maliciously crafted cosmo dumps!! it's very easy to crash
|
||||||
|
cosmo with this enabled and reading invalid opcodes due to us just using the
|
||||||
|
opcode as an index into the jump table
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
# define VM_JUMPTABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
COSMOVM_OK,
|
COSMOVM_OK,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user