mirror of
				https://github.com/CPunch/Cosmo.git
				synced 2025-10-31 04:50:12 +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, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user