#include #include #include #include "instruktion.c" #include "stack.c" #include "program.c" #include "codeReader.c" #include "debugMenu.c" #include "bigint.h" #include "record.c" #include "SDA.c" // Debug int debug = 0; // Purge Flag int purgeFlag = false; // Heap Size int argVheapSizeKiB = 8192; // Program struct program program; // SDA struct sda sda; // Stack struct stack stack; #define SIZE 10000 //Register struct stack reg; unsigned fp; void version(void) { printf("Ninja Virtual Machine version %i (compiled %s, %s)\n", 0, __DATE__, __TIME__); } void help(void) { printf("Usage: ./njvm [options] \n\t--debug\tstart virtual machine in debug mode\n\t--version\tshow version and exit\n\t--help\t\tshow this help and exit\n"); } void execute(struct program program) { int bp = -1; int i; char charInput; StackSlot tempSlot; ObjRef tempObj; ObjRef tempObj2; int tempInt; for (i = 0; i < *program.size; ++i) { // if (debug == 1 || bp == i) debugMenu(fp, stack, &debug, i, &bp); if (debug == 1) printf("(%i)", i); switch (program.program[i] >> 24) { case HALT: if (debug == 1) printf("halt\n"); goto end; case PUSHC: if (debug == 1) printf("pushc: %i\n", IMMEDIATE(program.program[i])); bigFromInt(SIGN_EXTEND(IMMEDIATE(program.program[i]))); push(stack, stackSlotWithObjRef(bip.res)); break; case ADD: if (debug == 1) printf("add: %i + %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigAdd(); push(stack, stackSlotWithObjRef(bip.res)); break; case SUB: if (debug == 1) printf("sub: %i - %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigSub(); push(stack, stackSlotWithObjRef(bip.res)); break; case MUL: if (debug == 1) printf("mul: %i * %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigMul(); push(stack, stackSlotWithObjRef(bip.res)); break; case DIV: if (debug == 1) printf("div: %i / %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigDiv(); push(stack, stackSlotWithObjRef(bip.res)); break; case MOD: if (debug == 1) printf("mod: %i %% %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigDiv(); push(stack, stackSlotWithObjRef(bip.rem)); break; case RDINT: if (debug == 1) printf("rdint\n"); bigRead(stdin); push(stack, stackSlotWithObjRef(bip.res)); if (debug == 1) printf("pushed %i\n", peek(stack, 1)); break; case WRINT: if (debug == 1) printf("wrint: %i\n", peek(stack, 1)); bip.op1 = pop(stack).u.objRef; bigPrint(stdout); break; case RDCHR: if (debug == 1) printf("rdchr\n"); scanf("%c", &charInput); bigFromInt(charInput); push(stack, stackSlotWithObjRef(bip.res)); if (debug == 1) printf("pushed %c\n", charInput); break; case WRCHR: if (debug == 1) printf("wrchr: %c\n", peek(stack, 1)); bip.op1 = pop(stack).u.objRef; printf("%c", bigToInt()); break; case PUSHG: if (debug == 1) printf("pushg: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); push(stack, stackSlotWithObjRef(getSDA(SIGN_EXTEND(IMMEDIATE(program.program[i])), sda))); break; case POPG: if (debug == 1) printf("popg: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); setSDA(SIGN_EXTEND(IMMEDIATE(program.program[i])), pop(stack).u.objRef, sda); break; case ASF: if (debug == 1) printf("asf: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); push(stack, stackSlotWitchNumber(fp)); fp = *stack.current; *stack.current = *stack.current + SIGN_EXTEND(IMMEDIATE(program.program[i])); break; case RSF: if (debug == 1) printf("rsf: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); *stack.current = fp; if (debug == 1) printf("pop: %i\n", peek(stack, 1)); tempSlot = pop(stack); fp = tempSlot.u.number; break; case POPL: if (debug == 1) printf("popl: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); stack.stack[fp + SIGN_EXTEND(IMMEDIATE(program.program[i]))] = pop(stack); break; case PUSHL: if (debug == 1) printf("pushl: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); push(stack, stack.stack[fp + SIGN_EXTEND(IMMEDIATE(program.program[i]))]); break; case NE: if (debug == 1) printf("ne: %i != %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigFromInt(bigCmp() != 0); push(stack, stackSlotWithObjRef(bip.res)); break; case EQ: if (debug == 1) printf("eq: %i == %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigFromInt(bigCmp() == 0); push(stack, stackSlotWithObjRef(bip.res)); break; case LT: if (debug == 1) printf("lt: %i < %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigFromInt(bigCmp() < 0); push(stack, stackSlotWithObjRef(bip.res)); break; case LE: if (debug == 1) printf("le: %i <= %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigFromInt(bigCmp() <= 0); push(stack, stackSlotWithObjRef(bip.res)); break; case GT: if (debug == 1) printf("gt: %i > %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigFromInt(bigCmp() > 0); push(stack, stackSlotWithObjRef(bip.res)); break; case GE: if (debug == 1) printf("ge: %i >= %i\n", peek(stack, 2), peek(stack, 1)); bip.op2 = pop(stack).u.objRef; bip.op1 = pop(stack).u.objRef; bigFromInt(bigCmp() >= 0); push(stack, stackSlotWithObjRef(bip.res)); break; case BRF: if (debug == 1) printf("brf: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); if (debug == 1) printf("pop: %i\n", peek(stack, 1)); bip.op1 = pop(stack).u.objRef; int b = bigToInt(); if (b == false) { i = SIGN_EXTEND(IMMEDIATE(program.program[i])) - 1; if (debug == 1) printf("new i: %i\n", i); } else if (b != true) { printf("Error: brf: %i\n", b); exit(EXIT_FAILURE); } break; case BRT: if (debug == 1) printf("brt: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); if (debug == 1) printf("pop: %i\n", peek(stack, 1)); bip.op1 = pop(stack).u.objRef; b = bigToInt(); if (b == true) { i = SIGN_EXTEND(IMMEDIATE(program.program[i])) - 1; if (debug == 1) printf("new i: %i\n", i); } else if (b != false) { printf("Error: brt: %i\n", b); exit(EXIT_FAILURE); } break; case JMP: if (debug == 1) printf("jmp: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); i = SIGN_EXTEND(IMMEDIATE(program.program[i])) - 1; if (debug == 1) printf("new i: %i\n", i); break; case CALL: if (debug == 1) printf("call: %i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); push(stack, stackSlotWitchNumber(i)); if (debug == 1) printf("push: %i\n", i + 1); i = SIGN_EXTEND(IMMEDIATE(program.program[i])) - 1; if (debug == 1) printf("new i: %i\n", i); break; case RET: if (debug == 1) printf("ret\n"); if (debug == 1) printf("pop: %i\n", peek(stack, 1)); i = getIntValfromStackSlot(pop(stack)); if (debug == 1) printf("new i: %i\n", i); break; case DROP: if (debug == 1) printf("drop\n"); *stack.current = *stack.current - SIGN_EXTEND(IMMEDIATE(program.program[i])); break; case DUP: if (debug == 1) printf("dup\n"); tempObj = pop(stack).u.objRef; push(stack, stackSlotWithObjRef(tempObj)); push(stack, stackSlotWithObjRef(tempObj)); break; case POPR: if (debug == 1) printf("popr\n"); push(reg, pop(stack)); break; case PUSHR: if (debug == 1) printf("pushr\n"); push(stack, pop(reg)); break; case NEW: if (debug == 1) printf("new\t%i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); push(stack, stackSlotWithObjRef(newRecord(SIGN_EXTEND(IMMEDIATE(program.program[i]))))); break; case GETF: if (debug == 1) printf("getf\n"); tempObj = pop(stack).u.objRef; push(stack, stackSlotWithObjRef(getField(tempObj, SIGN_EXTEND(IMMEDIATE(program.program[i]))))); break; case PUTF: if (debug == 1) printf("putf\t%i\n", SIGN_EXTEND(IMMEDIATE(program.program[i]))); tempObj = pop(stack).u.objRef; tempObj2 = pop(stack).u.objRef; setField(tempObj2, SIGN_EXTEND(IMMEDIATE(program.program[i])), tempObj); break; case NEWA: if (debug == 1) printf("newa\n"); bip.op1 = pop(stack).u.objRef; push(stack, stackSlotWithObjRef(newRecord(bigToInt()))); break; case GETFA: if (debug == 1) printf("getfa\n"); bip.op1 = pop(stack).u.objRef; tempInt = bigToInt(); tempObj = pop(stack).u.objRef; push(stack, stackSlotWithObjRef(getField(tempObj, bigToInt()))); break; case PUTFA: if (debug == 1) printf("putfa\n"); tempObj = pop(stack).u.objRef; // Value tempObj2 = pop(stack).u.objRef; // Index bip.op1 = tempObj2; tempInt = bigToInt(); setField(pop(stack).u.objRef, tempInt, tempObj); break; case GETSZ: if (debug == 1) printf("getsz\n"); tempObj = pop(stack).u.objRef; if (IS_PRIMITIVE(tempObj)) bigFromInt(-1); else bigFromInt(GET_ELEMENT_COUNT(tempObj)); push(stack, stackSlotWithObjRef(bip.res)); break; case PUSHN: if (debug == 1) printf("pushn\n"); push(stack, stackSlotWithObjRef(NULL)); break; case REFEQ: if (debug == 1) printf("refeq\n"); if (pop(stack).u.objRef == pop(stack).u.objRef) bigFromInt(true); else bigFromInt(false); push(stack, stackSlotWithObjRef(bip.res)); break; case REFNE: if (debug == 1) printf("refeq\n"); if (pop(stack).u.objRef != pop(stack).u.objRef) bigFromInt(true); else bigFromInt(false); push(stack, stackSlotWithObjRef(bip.res)); break; } } end: return; } void tests(void) { } /* * Garbage Collection */ ObjRef *heap; int heapSizeKiB; char *memTargetPtr; char *freeHeapPtr; char *halfHeapPtr; int gcCount = 0; #define MSB (1 << (8 * sizeof(unsigned int) - 1)) #define IS_PRIMITIVE(objRef) (((objRef)->size & MSB) == 0) #define GET_SIZE(objRef)((objRef)->size& ~MSB) #define GET_REFS(objRef)((ObjRef *)((objRef)->data)) ObjRef copyObjectToFreeMem(ObjRef orig) { int size; if (IS_PRIMITIVE(orig)) { size = GET_SIZE(orig); } else { size = sizeof(void *) + sizeof(unsigned int) + sizeof(bool) + GET_SIZE(orig) * sizeof(ObjRef *); } memcpy(freeHeapPtr, orig, size); ObjRef oldPtr = (ObjRef) freeHeapPtr; freeHeapPtr += size; return oldPtr; } ObjRef relocate(ObjRef orig) { ObjRef copy; if (orig == NULL) { copy = NULL; } else { if (orig->brokenHeart == 1) { copy = orig->forwardPointer; } else { copy = copyObjectToFreeMem(orig); orig->brokenHeart = true; orig->forwardPointer = copy; } } return copy; } void scan(void) { char *scanPtr = memTargetPtr; while (scanPtr < freeHeapPtr) { ObjRef scanOr = (ObjRef) scanPtr; if (!IS_PRIMITIVE(scanOr)) { for (int i = 0; i < GET_SIZE(scanOr); i++) { GET_REFS(scanOr)[i] = relocate(GET_REFS(scanOr)[i]); } scanPtr += sizeof(bool) + (GET_SIZE(scanOr) * sizeof(ObjRef *)) + sizeof(unsigned int) + sizeof(void *); } else { scanPtr += GET_SIZE(scanOr); } } } void swap() { if (memTargetPtr == (char *) heap) { freeHeapPtr = halfHeapPtr; memTargetPtr = halfHeapPtr; halfHeapPtr = ((char *) heap) + (heapSizeKiB * 1024); } else { freeHeapPtr = ((char *) heap); memTargetPtr = ((char *) heap); halfHeapPtr = ((char *) heap) + ((heapSizeKiB * 1024) / 2); } } void garbageCollector() { char *memToPurgePtr = halfHeapPtr - ((heapSizeKiB * 1024) / 2); swap(); for (int i = 0; i < *stack.size; i++) { if (stack.stack[i].isObjRef) { stack.stack[i].u.objRef = relocate(stack.stack[i].u.objRef); } } for (int i = 0; i < *sda.size; i++) { sda.sda[i] = relocate(sda.sda[i]); } scan(); if (purgeFlag) { memset(memToPurgePtr, 0, heapSizeKiB * 1024 / 2); } gcCount++; } ObjRef alloc(unsigned int objectSize) { if (freeHeapPtr + objectSize > halfHeapPtr) { garbageCollector(); if (freeHeapPtr + objectSize > halfHeapPtr) { fprintf(stderr, "Heap is full\n"); exit(1); } } ObjRef or; or = (ObjRef) freeHeapPtr; freeHeapPtr = freeHeapPtr + objectSize; return or; } void heapAllocator(int n) { heapSizeKiB = n; if ((heap = malloc(n * 1024)) == NULL) { perror("malloc"); exit(1); } memTargetPtr = (char *) heap; freeHeapPtr = memTargetPtr; halfHeapPtr = (memTargetPtr + (n * 1024) / 2); } /* * Main */ int main(int argc, char *argv[]) { // Init the Heap //initHeap(1000); // Initialize the Stack int size = SIZE; int current = 0; stack.size = &size; stack.current = ¤t; stack.stack = malloc(SIZE * 1024); if (stack.stack == NULL) { perror("malloc"); } // Initialize the registery int rSize = 100000; int rCurrent = 0; StackSlot r[100000]; reg.size = &rSize; reg.current = &rCurrent; reg.stack = r; // Initialize ProgrammSpeicher int psize = 100000; int saveProgram = 0; unsigned int p[100000]; program.size = &psize; program.program = p; program.saveProgram = &saveProgram; int run = 0; int sizeSDA; if (argc > 1) { for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "--debug") == 0) { debug = 1; } else if (strcmp(argv[i], "--version") == 0) { version(); return 0; } else if (strcmp(argv[i], "--help") == 0) { help(); return 0; } else if (strcmp(argv[i], "--stack") == 0) { i++; size = atoi(argv[i]); } else if (strcmp(argv[i], "--heap") == 0) { i++; argVheapSizeKiB = atoi(argv[i]); } else if (strcmp(argv[i], "--gcpurge") == 0) { purgeFlag = true; } else { sizeSDA = fromFile(argv[i], program); run = 1; } } heapAllocator(argVheapSizeKiB); // Init the sda ObjRef s[sizeSDA]; sda.size = &sizeSDA; sda.sda = s; } if (debug) { tests(); } if (run) { printf("Ninja Virtual Machine started\n"); ObjRef s[sizeSDA]; sda.size = &sizeSDA; sda.sda = s; if (debug == 1) printProgram(program); execute(program); printf("Ninja Virtual Machine stopped\n"); } else { printf("Error: no code file specified\n"); return 1; } }