diff --git a/VaninVM/CodeHeader.h b/VaninVM/CodeHeader.h index 8e00649..76e2427 100644 --- a/VaninVM/CodeHeader.h +++ b/VaninVM/CodeHeader.h @@ -3,11 +3,11 @@ #pragma pack(push, 1) struct { - char signature[4]; + char signature[2]; int version; int count_const; int size_const; -}First_Header; +}Const_Header; struct { diff --git a/VaninVM/Context.c b/VaninVM/Context.c index b798f11..ff65c06 100644 --- a/VaninVM/Context.c +++ b/VaninVM/Context.c @@ -30,4 +30,22 @@ context* pop_context() c_node* last = node_last; node_last = node_last->prev; return last->obj; +} + +//Find Context in Context Stack. +context* find_context(int id) +{ + context* result = NULL; + c_node* current = node_last; + while (current != NULL || current->prev != NULL) + { + if (current->obj->id == id) + { + result = current->obj; + break; + } + else + current = current->prev; + } + return result; } \ No newline at end of file diff --git a/VaninVM/Context.h b/VaninVM/Context.h index d0208e3..f0eedec 100644 --- a/VaninVM/Context.h +++ b/VaninVM/Context.h @@ -23,5 +23,6 @@ context* create_context(int function, func** hash,char** code); void push_context(context*); context* pop_context(); void remove_context(context*); +context* find_context(int id); #endif \ No newline at end of file diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c index 43b898c..90c54e2 100644 --- a/VaninVM/IOcode.c +++ b/VaninVM/IOcode.c @@ -2,6 +2,8 @@ #include "CodeHeader.h" #include +int version = 0100; + int read_bytecode(FILE* stream, func*** hash) { int i; @@ -39,21 +41,33 @@ int read_constant(FILE* stream, int* count, char*** index) int i, j; char* buffer; - fread_s(&First_Header, sizeof(First_Header), sizeof(First_Header), 1, stream); //Reading first part of header - *(count) = First_Header.count_const; + fread_s(&Const_Header, sizeof(Const_Header), sizeof(Const_Header), 1, stream); //Reading first part of header + if (Const_Header.signature[0]==Const_Header.signature[1]== 0xBA) + { + printf("%s", "Wrong file-format"); + return 1; + } - buffer = (char*)malloc(First_Header.size_const+1); + if (Const_Header.version != version) + { + printf("%s", "Unsupported bytecode format"); + return 1; + } + + *(count) = Const_Header.count_const; + + buffer = (char*)malloc(Const_Header.size_const+1); buffer[0]=0; - *(index) = (char**)malloc(sizeof(char**)*First_Header.count_const); + *(index) = (char**)malloc(sizeof(char**)*Const_Header.count_const); - fread_s(buffer+1, First_Header.size_const, sizeof(char), First_Header.size_const, stream); //Reading constant values + fread_s(buffer+1, Const_Header.size_const, sizeof(char), Const_Header.size_const, stream); //Reading constant values j=0; (*(index))[j++]=buffer; - for (i = 0; iConst_Header.count_const) break; if (buffer[i] == 0) diff --git a/VaninVM/LocalVars.c b/VaninVM/LocalVars.c new file mode 100644 index 0000000..fbaab2c --- /dev/null +++ b/VaninVM/LocalVars.c @@ -0,0 +1,38 @@ +#include +#include "LocalVars.h" + +long long getlocal_int(context* cont, int id) +{ + long long result; + result = ((long long*)(cont->locals))[id]; + return result; +} + +double getlocal_double(context* cont, int id) +{ + double result; + result = ((double*)(cont->locals))[id]; + return result; +} + +int getlocal_string(context* cont, int id) +{ + long long result; + result = ((long long*)(cont->locals))[id]; + return (int)result; +} + +void putlocal_int(long long* num, context* cont, int id) +{ + memcpy(((long long*)cont->locals)+id, num, sizeof(long long)); +} + +void putlocal_double(double* num, context* cont, int id) +{ + memcpy(((double*)cont->locals)+id, num, sizeof(double)); +} + +void putlocal_string(int* str, context* cont, int id) +{ + memcpy(((long long*)cont->locals)+id, (long long*)str, sizeof(long long)); +} diff --git a/VaninVM/LocalVars.h b/VaninVM/LocalVars.h new file mode 100644 index 0000000..efb873d --- /dev/null +++ b/VaninVM/LocalVars.h @@ -0,0 +1,12 @@ +#ifndef LOCALVARS_H +#define LOCALVARS_H +#include "Context.h" + +long long getlocal_int(context*, int); +double getlocal_double(context*, int); +int getlocal_string(context*, int); + +void putlocal_int(long long*, context*, int); +void putlocal_double(double*, context*, int); +void putlocal_string(int*, context*, int); +#endif \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c index cb96402..c476d4e 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -1,11 +1,16 @@ -#include "IOcode.h" -#include "TOS.h" #include "OpCode.h" + +#include "IOcode.h" #include "CodeHeader.h" + +#include "TOS.h" #include "Context.h" #include "ReturnStack.h" +#include "LocalVars.h" +long long cmp_int(long long* a, long long* b); +double cmp_double(double* a, double* b); int main(int argc, char** argv) { @@ -15,7 +20,7 @@ int main(int argc, char** argv) //ExecutionProcess Variables double d1, d2; long long i1, i2; - short s1; + short s1, s2; char* code; int ip, startfunc; @@ -30,209 +35,580 @@ int main(int argc, char** argv) //Running Variable int exec_status = 1; - fopen_s(&input, "bytecode", "rb"); + + if (argc<2) + { + printf("%s", "File is not specified"); + return 1; + } + + fopen_s(&input, argv[1], "rb"); //const_pull - read_constant(input, &const_count, &const_index); + if (read_constant(input, &const_count, &const_index) != 0) + return 1; //code_pull startfunc = read_bytecode(input, &phash_table); fclose(input); - + initTOS(); initRStack(); ip = 0; current_context = create_context(startfunc, phash_table, &code); + node_last = NULL; while (exec_status) { switch (code[ip]) { - case INVALID: - //DO(INVALID, "Invalid instruction.", 1) - ip++; break; - case DLOAD: - //DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) - d1 = *((double*)(code+(++ip))); + case INVALID: + //DO(INVALID, "Invalid instruction.", 1) + ip++; break; + case DLOAD: + //DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) + d1 = *((double*)(code+(++ip))); + push_double(d1); + ip+=8; break; + case ILOAD: + //DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) + i1 = *((long long*)(code+(++ip))); + push_int(i1); + ip+=8; break; + case SLOAD: + s1 = *((short*)(code+(++ip))); + push_int((long long)(const_index[s1])); + ip+=2; break; + case DLOAD0: + // DO(DLOAD0, "Load double 0 on TOS.", 1) + push_double(0); + ip++; break; + case ILOAD0: + //DO(ILOAD0, "Load int 0 on TOS.", 1) + push_int(0); + ip++; break; + case SLOAD0: + //DO(SLOAD0, "Load empty string on TOS.", 1) + push_int((long long)(const_index[0])); + ip++; break; + case DLOAD1: + //DO(DLOAD1, "Load double 1 on TOS.", 1) + push_double(1); + ip++; break; + case ILOAD1: + //DO(ILOAD1, "Load int 1 on TOS.", 1) + push_int(1); + ip++; break; + case DLOADM1: + //DO(DLOADM1, "Load double -1 on TOS.", 1) + push_double(-1); + ip++; break; + case ILOADM1: + //DO(ILOADM1, "Load int -1 on TOS.", 1) + push_int(-1); + ip++; break; + case DADD: + //DO(DADD, "Add 2 doubles on TOS, push value back.", 1) + d1 = pop_double(); + d2 = pop_double(); + d1 += d2; + push_double(d1); + ip++; break; + case IADD: + //DO(IADD, "Add 2 ints on TOS, push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 += i2; + push_int(i1); + ip++; break; + case DSUB: + //DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) + d1 = pop_double(); + d2 = pop_double(); + d2 -= d1; + push_double(d2); + ip++; break; + case ISUB: + //DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i2 -= i1; + push_int(i2); + ip++; break; + case DMUL: + //DO(DMUL, "Multiply 2 doubles on TOS, push value back.", 1) + d1 = pop_double(); + d2 = pop_double(); + d1 *= d2; + push_double(d1); + ip++; break; + case IMUL: + //DO(IMUL, "Multiply 2 ints on TOS, push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 *= i2; + push_int(i1); + ip++; break; + case DDIV: + //DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1) + d1 = pop_double(); + d2 = pop_double(); + d1 = d1/d2; + push_double(d1); + ip++; break; + case IDIV: + //DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 = i1/i2; + push_int(i1); + ip++; break; + case IMOD: + //DO(IMOD, "Modulo operation on 2 ints on TOS (upper to lower), push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 = i1 % i2; + push_int(i1); + ip++; break; + case DNEG: + //DO(DNEG, "Negate double on TOS.", 1) + d1 = pop_double(); + d1 = -d1; + push_double(d1); + ip++; break; + case INEG: + //DO(INEG, "Negate int on TOS.", 1) + i1 = pop_int(); + i1 = - i1; + push_int(i1); + ip++; break; + case IAOR: + //DO(IAOR, "Arithmetic OR of 2 ints on TOS, push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 = i1 | i2; + push_int(i1); + ip++; break; + case IAAND: + //DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 = i1 & i2; + push_int(i1); + ip++; break; + case IAXOR: + //DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i1 = i1 ^ i2; + push_int(i1); + ip++; break; + case IPRINT: + //DO(IPRINT, "Pop and print integer TOS.", 1) + i1 = pop_int(); + printf("%llu", i1); + ip++; break; + case DPRINT: + //DO(DPRINT, "Pop and print double TOS.", 1) + d1 = pop_double(); + printf("%f", d1); + ip++; break; + case SPRINT: + //DO(SPRINT, "Pop and print string TOS.", 1) + i1 = pop_int(); + printf("%s", (char*)i1); + ip++; break; + case I2D: + //DO(I2D, "Convert int on TOS to double.", 1) + i1 = pop_int(); + d1 = (double)i1; + push_double(d1); + ip++; break; + case D2I: + //DO(D2I, "Convert double on TOS to int.", 1) + d1 = pop_double(); + i1 = (int)d1; + push_int(i1); + ip++; break; + case S2I: + //DO(S2I, "Convert string on TOS to int.", 1) + ip++; break; + case SWAP: + //DO(SWAP, "Swap 2 topmost values.", 1) + i1 = pop_int(); + i2 = pop_int(); + push_int(i1); + push_int(i2); + ip++; break; + case POP: + //DO(POP, "Remove topmost value.", 1) + TOS--; + ip++; break; + case LOADDVAR0: + //DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) + d1 = getlocal_double(current_context, 0); + push_double(d1); + ip++;break; + case LOADDVAR1: + //DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) + d1 = getlocal_double(current_context, 1); + push_double(d1); + ip++;break; + case LOADDVAR2: + //DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) + d1 = getlocal_double(current_context, 2); + push_double(d1); + ip++;break; + case LOADDVAR3: + //DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) + d1 = getlocal_double(current_context, 3); + push_double(d1); + ip++; break; + case LOADIVAR0: + //DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) + i1 = getlocal_int(current_context, 0); + push_int(i1); + ip++; break; + case LOADIVAR1: + //DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) + i1 = getlocal_int(current_context, 1); + push_int(i1); + ip++; break; + case LOADIVAR2: + //DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) + i1 = getlocal_int(current_context, 2); + push_int(i1); + ip++; break; + case LOADIVAR3: + //DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) + i1 = getlocal_int(current_context, 3); + push_int(i1); + ip++; break; + case LOADSVAR0: + //DO(LOADSVAR0, "Load string from variable 0, push on TOS.", 1) + i1 = (long long)getlocal_string(current_context, 0); + push_int(i1); + ip++; break; + case LOADSVAR1: + //DO(LOADSVAR1, "Load string from variable 1, push on TOS.", 1) + i1 = (long long)getlocal_string(current_context, 1); + push_int(i1); + ip++; break; + case LOADSVAR2: + //DO(LOADSVAR2, "Load string from variable 2, push on TOS.", 1) + i1 = (long long)getlocal_string(current_context, 2); + push_int(i1); + ip++; break; + case LOADSVAR3: + //DO(LOADSVAR3, "Load string from variable 3, push on TOS.", 1) + i1 = (long long)getlocal_string(current_context, 3); + push_int(i1); + ip++; break; + case STOREDVAR0: + //DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 0); + ip++; break; + case STOREDVAR1: + //DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 1); + ip++; break; + case STOREDVAR2: + //DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 2); + ip++; break; + case STOREDVAR3: + //DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 3); + ip++; break; + case STOREIVAR0: + //DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 0); + ip++; break; + case STOREIVAR1: + //DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 1); + ip++; break; + case STOREIVAR2: + //DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 2); + ip++; break; + case STOREIVAR3: + //DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 3); + ip++; break; + case STORESVAR0: + //DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 0); + ip++; break; + case STORESVAR1: + //DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 1); + ip++; break; + case STORESVAR2: + //DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 2); + ip++; break; + case STORESVAR3: + //DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 3); + ip++; break; + case LOADDVAR: + //DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) + s1 = *((short*)(code+(++ip))); + d1 = getlocal_double(current_context, s1); + push_double(d1); + ip+=2; break; + case LOADIVAR: + //DO(LOADIVAR, "Load int from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) + s1 = *((short*)(code+(++ip))); + i1 = getlocal_int(current_context, s1); + push_int(i1); + ip+=2; break; + case LOADSVAR: + //DO(LOADSVAR, "Load string from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) + s1 = *((short*)(code+(++ip))); + i1 = (long long)getlocal_string(current_context, s1); + push_int(i1); + ip+=2; break; + case STOREDVAR: + //DO(STOREDVAR, "Pop TOS and store to double variable, whose 2-byte id is inlined to insn stream.", 3) + s1 = *((short*)(code+(++ip))); + d1 = pop_double(); + putlocal_double(&d1, current_context, s1); + ip+=2; break; + case STOREIVAR: + //DO(STOREIVAR, "Pop TOS and store to int variable, whose 2-byte id is inlined to insn stream.", 3) + s1 = *((short*)(code+(++ip))); + i1 = pop_int(); + putlocal_int(&i1, current_context, s1); + ip+=2; break; + case STORESVAR: + //DO(STORESVAR, "Pop TOS and store to string variable, whose 2-byte id is inlined to insn stream.", 3) + s1 = *((short*)(code+(++ip))); + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, s1); + ip+=2; break; + case LOADCTXDVAR: + //DO(LOADCTXDVAR, "Load double from variable, whose 2-byte context and 2-byte id inlined to insn stream, push on TOS.", 5) + s1 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + if (find_context(s1) != NULL) + { + d1 = getlocal_double(find_context(s1), s2); push_double(d1); - ip+=8; break; - case ILOAD: - //DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) - i1 = *((long long*)(code+(++ip))); + } + else + { + printf("%s", "Context Not Found"); + exec_status = 0; + } + ip+=2; break; + case LOADCTXIVAR: + //DO(LOADCTXIVAR, "Load int from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) + s1 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + if (find_context(s1) != NULL) + { + i1 = getlocal_int(find_context(s1), s2); push_int(i1); - ip+=8; break; - case SLOAD: - s1 = *((short*)(code+(++ip))); - push_int((long long)(const_index[s1])); - ip+=2; break; - case DLOAD0: - // DO(DLOAD0, "Load double 0 on TOS.", 1) - push_double(0); - ip++; break; - case ILOAD0: - //DO(ILOAD0, "Load int 0 on TOS.", 1) - push_int(0); - ip++; break; - case DLOAD1: - //DO(DLOAD1, "Load double 1 on TOS.", 1) - push_double(1); - ip++; break; - case ILOAD1: - //DO(ILOAD1, "Load int 1 on TOS.", 1) - push_int(1); - ip++; break; - case DLOADM1: - //DO(DLOADM1, "Load double -1 on TOS.", 1) - push_double(-1); - ip++; break; - case ILOADM1: - //DO(ILOADM1, "Load int -1 on TOS.", 1) - push_int(-1); - ip++; break; - case DADD: - //DO(DADD, "Add 2 doubles on TOS, push value back.", 1) - d1 = pop_double(); - d2 = pop_double(); - d1 += d2; - push_double(d1); - ip++; break; - case IADD: - //DO(IADD, "Add 2 ints on TOS, push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 += i2; - push_int(i1); - ip++; break; - case DSUB: - //DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) - d1 = pop_double(); - d2 = pop_double(); - d1 -= d2; - push_double(d1); - ip++; break; - case ISUB: - //DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 -= i2; - push_int(i1); - ip++; break; - case DMUL: - //DO(DMUL, "Multiply 2 doubles on TOS, push value back.", 1) - d1 = pop_double(); - d2 = pop_double(); - d1 *= d2; - push_double(d1); - ip++; break; - case IMUL: - //DO(IMUL, "Multiply 2 ints on TOS, push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 *= i2; - push_int(i1); - ip++; break; - case DDIV: - //DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1) - d1 = pop_double(); - d2 = pop_double(); - d1 /= d2; - push_double(d1); - ip++; break; - case IDIV: - //DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 /= i2; - push_int(i1); - ip++; break; - case IMOD: - //DO(IMOD, "Modulo operation on 2 ints on TOS (upper to lower), push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 %= i2; - push_int(i1); - ip++; break; - case DNEG: - //DO(DNEG, "Negate double on TOS.", 1) - d1 = pop_double(); - d1 = -d1; - push_double(d1); - ip++; break; - case INEG: - //DO(INEG, "Negate int on TOS.", 1) - i1 = pop_int(); - i1 = - i1; - push_int(i1); - ip++; break; - case IAOR: - //DO(IAOR, "Arithmetic OR of 2 ints on TOS, push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 = i1 | i2; - push_int(i1); - ip++; break; - case IAAND: - //DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1) - ip++; break; - case IAXOR: - //DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) - case IPRINT: - //DO(IPRINT, "Pop and print integer TOS.", 1) - i1 = pop_int(); - printf("%d", i1); - ip++; break; - case DPRINT: - //DO(DPRINT, "Pop and print double TOS.", 1) - d1 = pop_double(); - printf("%f", d1); - ip++; break; - case SPRINT: - //DO(SPRINT, "Pop and print string TOS.", 1) - i1 = pop_int(); - printf("%s", (char*)i1); - ip++; break; - case I2D: - //DO(I2D, "Convert int on TOS to double.", 1) - i1 = pop_int(); - d1 = (double)i1; - push_double(d1); - ip++; break; - case D2I: - //DO(D2I, "Convert double on TOS to int.", 1) - d1 = pop_double(); - i1 = (int)d1; - push_int(i1); - ip++; break; - case SWAP: - //DO(SWAP, "Swap 2 topmost values.", 1) - i1 = pop_int(); - i2 = pop_int(); - push_int(i1); - push_int(i2); - ip++; break; - case POP: - //DO(POP, "Remove topmost value.", 1) - TOS--; - ip++; break; - case STOP: - //DO(STOP, "Stop execution.", 1) - exec_status = 0; - break; - case CALL: - s1 = *((short*)(code+(++ip))); - ip+=2; push_ret(ip); - push_context(current_context); - current_context = create_context(s1, phash_table, &code); - ip = 0; break; - case RETURN: - remove_context(current_context); - current_context = pop_context(); - code = phash_table[current_context->id]->code; - ip = pop_ret(); break; - + } + else + { + printf("%s", "Context Not Found"); + exec_status = 0; + } + ip+=2; break; + case LOADCTXSVAR: + //DO(LOADCTXSVAR, "Load string from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) + s1 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + if (find_context(s1) != NULL) + { + i1 = (long long)getlocal_string(find_context(s1), s2); + push_double(i1); + } + else + { + printf("%s", "Context Not Found"); + exec_status = 0; + } + ip+=2; break; + case STORECTXDVAR: + //DO(STORECTXDVAR, "Pop TOS and store to double variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) + s1 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + d1 = pop_double(); + if (find_context(s1) != NULL) + { + putlocal_double(&d1, find_context(s1), s2); + } + else + { + printf("%s", "Context Not Found"); + exec_status = 0; + } + ip+=2; break; + case STORECTXIVAR: + //DO(STORECTXIVAR, "Pop TOS and store to int variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) + s1 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + i1 = pop_int(); + if (find_context(s1) != NULL) + { + putlocal_int(&i1, find_context(s1), s2); + } + else + { + printf("%s", "Context Not Found"); + exec_status = 0; + } + ip+=2; break; + case STORECTXSVAR: + //DO(STORECTXSVAR, "Pop TOS and store to string variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) + s1 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + i1 = pop_int(); + if (find_context(s1) != NULL) + { + putlocal_string((int*)&d1, find_context(s1), s2); + } + else + { + printf("%s", "Context Not Found"); + exec_status = 0; + } + ip+=2; break; + case DCMP: + //DO(DCMP, "Compare 2 topmost doubles, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) + d1 = TOS[tp-1]; + d2 = TOS[tp-2]; + push_double(cmp_double(&d1, &d2)); + ip++; break; + case ICMP: + //DO(ICMP, "Compare 2 topmost ints, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) + i1 = get_int(tp-1); + i2 = get_int(tp-2); + push_int(cmp_int(&i1, &i2)); + ip++; break; + case JA: + //DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip += (2+s1); break; + case IFICMPNE: + // DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 != i2) + ip += s1; + break; + case IFICMPE: + //DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 == i2) + ip += s1; + break; + case IFICMPG: + //DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 > i2) + ip += s1; + break; + case IFICMPGE: + //DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 >= i2) + ip += s1; + break; + case IFICMPL: + //DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 < i2) + ip += s1; + break; + case IFICMPLE: + //DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 <= i2) + ip += s1; + break; + case DUMP: + //DO(DUMP, "Dump value on TOS, without removing it.", 1) + i1 = get_int(tp-1); + d1 = TOS[tp-1]; + printf("TOS: Double:%e Integer:%llu Hex:%#08llx", d1, i1, i1); + ip++; break; + case STOP: + //DO(STOP, "Stop execution.", 1) + exec_status = 0; + break; + case CALL: + //DO(CALL, "Call function, next two bytes - unsigned function id.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; push_ret(ip); + push_context(current_context); + current_context = create_context(s1, phash_table, &code); + ip = 0; break; + case RETURN: + //DO(RETURN, "Return to call location", 1) + remove_context(current_context); + current_context = pop_context(); + code = phash_table[current_context->id]->code; + ip = pop_ret(); break; + case BREAK: + //DO(BREAK, "Breakpoint for the debugger.", 1) + getchar(); + ip++; break; } } remove_context(current_context); - getchar(); + return 0; +} + +double cmp_double(long long* a, long long* b) +{ + if (*a == *b) return 0; + else if (*a > *b) return 1; + else return -1; +} +long long cmp_int(long long* a, long long* b) +{ + if (*a == *b) return 0; + else if (*a > *b) return 1; + else return -1; } \ No newline at end of file diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h index af9e9da..c13bbc4 100644 --- a/VaninVM/OpCode.h +++ b/VaninVM/OpCode.h @@ -8,6 +8,7 @@ enum opcode SLOAD, DLOAD0, ILOAD0, + SLOAD0, DLOAD1, ILOAD1, DLOADM1, @@ -31,10 +32,58 @@ enum opcode SPRINT, I2D, D2I, + S2I, SWAP, POP, + LOADDVAR0, + LOADDVAR1, + LOADDVAR2, + LOADDVAR3, + LOADIVAR0, + LOADIVAR1, + LOADIVAR2, + LOADIVAR3, + LOADSVAR0, + LOADSVAR1, + LOADSVAR2, + LOADSVAR3, + STOREDVAR0, + STOREDVAR1, + STOREDVAR2, + STOREDVAR3, + STOREIVAR0, + STOREIVAR1, + STOREIVAR2, + STOREIVAR3, + STORESVAR0, + STORESVAR1, + STORESVAR2, + STORESVAR3, + LOADDVAR, + LOADIVAR, + LOADSVAR, + STOREDVAR, + STOREIVAR, + STORESVAR, + LOADCTXDVAR, + LOADCTXIVAR, + LOADCTXSVAR, + STORECTXDVAR, + STORECTXIVAR, + STORECTXSVAR, + DCMP, + ICMP, + JA, + IFICMPNE, + IFICMPE, + IFICMPG, + IFICMPGE, + IFICMPL, + IFICMPLE, + DUMP, STOP, CALL, - RETURN + RETURN, + BREAK }; #endif \ No newline at end of file diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c index 25f398b..973fc12 100644 --- a/VaninVM/TOS.c +++ b/VaninVM/TOS.c @@ -15,6 +15,13 @@ long long pop_int() return number.num_i; } +long long get_int(int id) +{ + tos_num number; + number.num_d = TOS[id]; + return number.num_i; +} + void push_double(double num) { TOS[tp++] = num; diff --git a/VaninVM/TOS.h b/VaninVM/TOS.h index 68a909c..93572dc 100644 --- a/VaninVM/TOS.h +++ b/VaninVM/TOS.h @@ -13,6 +13,7 @@ int initTOS(); void push_int(long long); void push_double(double); long long pop_int(); +long long get_int(int); double pop_double(); #endif \ No newline at end of file diff --git a/VaninVM/opc.txt b/VaninVM/opc.txt index eea5921..2bc9db8 100644 --- a/VaninVM/opc.txt +++ b/VaninVM/opc.txt @@ -1,11 +1,11 @@ #define FOR_BYTECODES(DO) \ - -DO(INVALID, "Invalid instruction.", 1) \ + ?-DO(INVALID, "Invalid instruction.", 1) \ +DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) \ +DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) \ +DO(SLOAD, "Load string reference on TOS, next two bytes - constant id.", 3) \ +DO(DLOAD0, "Load double 0 on TOS.", 1) \ +DO(ILOAD0, "Load int 0 on TOS.", 1) \ - DO(SLOAD0, "Load empty string on TOS.", 1) \ + +DO(SLOAD0, "Load empty string on TOS.", 1) \ +DO(DLOAD1, "Load double 1 on TOS.", 1) \ +DO(ILOAD1, "Load int 1 on TOS.", 1) \ +DO(DLOADM1, "Load double -1 on TOS.", 1) \ @@ -26,60 +26,60 @@ +DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) \ +DO(IPRINT, "Pop and print integer TOS.", 1) \ +DO(DPRINT, "Pop and print double TOS.", 1) \ - DO(SPRINT, "Pop and print string TOS.", 1) \ + +DO(SPRINT, "Pop and print string TOS.", 1) \ +DO(I2D, "Convert int on TOS to double.", 1) \ +DO(D2I, "Convert double on TOS to int.", 1) \ - DO(S2I, "Convert string on TOS to int.", 1) \ + +DO(S2I, "Convert string on TOS to int.", 1) \ +DO(SWAP, "Swap 2 topmost values.", 1) \ +DO(POP, "Remove topmost value.", 1) \ - DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) \ - DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) \ - DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) \ - DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) \ - DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) \ - DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) \ - DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) \ - DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) \ - DO(LOADSVAR0, "Load string from variable 0, push on TOS.", 1) \ - DO(LOADSVAR1, "Load string from variable 1, push on TOS.", 1) \ - DO(LOADSVAR2, "Load string from variable 2, push on TOS.", 1) \ - DO(LOADSVAR3, "Load string from variable 3, push on TOS.", 1) \ - DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) \ - DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) \ - DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) \ - DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) \ - DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) \ - DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) \ - DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) \ - DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) \ - DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) \ - DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1) \ - DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1) \ - DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1) \ - DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) \ - DO(LOADIVAR, "Load int from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \ - DO(LOADSVAR, "Load string from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \ - DO(STOREDVAR, "Pop TOS and store to double variable, whose 2-byte id is inlined to insn stream.", 3) \ - DO(STOREIVAR, "Pop TOS and store to int variable, whose 2-byte id is inlined to insn stream.", 3) \ - DO(STORESVAR, "Pop TOS and store to string variable, whose 2-byte id is inlined to insn stream.", 3) \ - DO(LOADCTXDVAR, "Load double from variable, whose 2-byte context and 2-byte id inlined to insn stream, push on TOS.", 5) \ - DO(LOADCTXIVAR, "Load int from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \ - DO(LOADCTXSVAR, "Load string from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \ - DO(STORECTXDVAR, "Pop TOS and store to double variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ - DO(STORECTXIVAR, "Pop TOS and store to int variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ - DO(STORECTXSVAR, "Pop TOS and store to string variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ - DO(DCMP, "Compare 2 topmost doubles, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \ - DO(ICMP, "Compare 2 topmost ints, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \ - DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) \ - DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) \ - DO(DUMP, "Dump value on TOS, without removing it.", 1) \ + +DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) \ + +DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) \ + +DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) \ + +DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) \ + +DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) \ + +DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) \ + +DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) \ + +DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) \ + +DO(LOADSVAR0, "Load string from variable 0, push on TOS.", 1) \ + +DO(LOADSVAR1, "Load string from variable 1, push on TOS.", 1) \ + +DO(LOADSVAR2, "Load string from variable 2, push on TOS.", 1) \ + +DO(LOADSVAR3, "Load string from variable 3, push on TOS.", 1) \ + +DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) \ + +DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) \ + +DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) \ + +DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) \ + +DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) \ + +DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) \ + +DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) \ + +DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) \ + +DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) \ + +DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1) \ + +DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1) \ + +DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1) \ + +DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) \ + +DO(LOADIVAR, "Load int from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \ + +DO(LOADSVAR, "Load string from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \ + +DO(STOREDVAR, "Pop TOS and store to double variable, whose 2-byte id is inlined to insn stream.", 3) \ + +DO(STOREIVAR, "Pop TOS and store to int variable, whose 2-byte id is inlined to insn stream.", 3) \ + +DO(STORESVAR, "Pop TOS and store to string variable, whose 2-byte id is inlined to insn stream.", 3) \ + +DO(LOADCTXDVAR, "Load double from variable, whose 2-byte context and 2-byte id inlined to insn stream, push on TOS.", 5) \ + +DO(LOADCTXIVAR, "Load int from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \ + +DO(LOADCTXSVAR, "Load string from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \ + +DO(STORECTXDVAR, "Pop TOS and store to double variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ + +DO(STORECTXIVAR, "Pop TOS and store to int variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ + +DO(STORECTXSVAR, "Pop TOS and store to string variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \ + ?+DO(DCMP, "Compare 2 topmost doubles, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \ + ?+DO(ICMP, "Compare 2 topmost ints, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \ + +DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) \ + +DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) \ + +DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) \ + +DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) \ + +DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) \ + +DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) \ + +DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) \ + +DO(DUMP, "Dump value on TOS, without removing it.", 1) \ +DO(STOP, "Stop execution.", 1) \ - DO(CALL, "Call function, next two bytes - unsigned function id.", 3) \ - DO(CALLNATIVE, "Call native function, next two bytes - id of the native function.", 3) \ - DO(RETURN, "Return to call location", 1) \ - DO(BREAK, "Breakpoint for the debugger.", 1) \ No newline at end of file + +DO(CALL, "Call function, next two bytes - unsigned function id.", 3) \ + ?DO(CALLNATIVE, "Call native function, next two bytes - id of the native function.", 3) \ + +DO(RETURN, "Return to call location", 1) \ + ?+DO(BREAK, "Breakpoint for the debugger.", 1) \ No newline at end of file