From acf652595c7df69adab683a5a9b29e3881cc42be Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Thu, 13 Sep 2012 10:14:08 +0100 Subject: [PATCH] Some progress on JIT - no syscalls yet --- src/virtualmachine/Exceptions.h | 24 ++- src/virtualmachine/JustInTime.cpp | 263 ++++++++++++++++++++++++-- src/virtualmachine/Syscalls.cpp | 4 +- src/virtualmachine/VirtualMachine.cpp | 7 +- src/virtualmachine/VirtualMachine.h | 26 ++- 5 files changed, 298 insertions(+), 26 deletions(-) diff --git a/src/virtualmachine/Exceptions.h b/src/virtualmachine/Exceptions.h index 2dca4614e..fbc434176 100644 --- a/src/virtualmachine/Exceptions.h +++ b/src/virtualmachine/Exceptions.h @@ -7,11 +7,16 @@ namespace vm { class RuntimeException: public std::exception { + char * error; public: - RuntimeException() {} + RuntimeException() : error(NULL) {} + RuntimeException(char * message) : error(strdup(message)) {} const char * what() const throw() { - return "VirtualMachine runtime exception"; + if(error) + return error; + else + return "VirtualMachine runtime exception"; } ~RuntimeException() throw() {}; }; @@ -56,6 +61,21 @@ namespace vm ~AccessViolationException() throw() {}; }; + class JITException: public RuntimeException + { + char * _what; + public: + JITException(const char * what2) + { + _what = strdup(what2); + } + const char * what() const throw() + { + return _what; + } + ~JITException() throw() {}; + }; + class OutOfMemoryException: public RuntimeException { public: diff --git a/src/virtualmachine/JustInTime.cpp b/src/virtualmachine/JustInTime.cpp index 930689282..9929d81d7 100644 --- a/src/virtualmachine/JustInTime.cpp +++ b/src/virtualmachine/JustInTime.cpp @@ -1,5 +1,12 @@ +#ifdef VMJIT + +#include #include "VirtualMachine.h" +#ifdef WIN32 +#include "Windows.h" +#endif + namespace vm { #define OP(n) OP##n @@ -9,24 +16,34 @@ namespace vm ebx scratch ecx scratch (required for shifts) edx scratch (required for divisions) - esi program stack - edi opstack + esi RP + edi DP */ // TTimo: initialised the statics, this fixes a crash when entering a compiled VM - static unsigned char *buf = NULL; - static unsigned char *jused = NULL; - static int compiledOfs = 0; - static int pc = 0; + static unsigned char *buf = NULL; + static unsigned char *jused = NULL; + static int compiledOfs = 0; + static int pc = 0; - static int callMask = 0; // bk001213 - init + //static int callMask = 0; // bk001213 - init + static int eDP; + static int eRP; + static int instruction, pass; + static int lastConst = 0; + static int oc0, oc1, pop0, pop1; - static int instruction, pass; - static int lastConst = 0; - static int oc0, oc1, pop0, pop1; + static int eRamMask = 0; + static int eRomMask = 0; + static int * eInstructionPointers = NULL; - static int *instructionPointers = NULL; + static int eSyscallNum; + static void * eRam = NULL; + static VirtualMachine * eVM = NULL; + + static int callFromCompiledPtr = (int)VirtualMachine::callFromCompiled; + static int callSyscallPtr = (int)VirtualMachine::callSyscall; typedef enum { @@ -38,7 +55,201 @@ namespace vm static ELastCommand LastCommand; - void VirtualMachine::Compile() + void VirtualMachine::callSyscall() + { + //throw RuntimeException("Turd"); + + /*VirtualMachine * savedVM; + int * callOpStack2; + + savedVM = eVM; + callOpStack2 = (int*)eOpStack; + + // save the stack to allow recursive VM entry + eVM->DP = eDP - 4; + *(int *)((byte *)eVM->ram + eDP + 4) = eSyscallNum; + //VM_LogSyscalls( (int *)((byte *)currentVM->dataBase + programStack + 4) ); + *(callOpStack2+1) = eVM->syscall( *(int *)((unsigned char *)eVM->ram + eDP + 4) ); + + eVM = savedVM;*/ + } + + void VirtualMachine::callFromCompiled() + { + /*__asm__("doAsmCall: \n\t" \ + " movl (%%edi),%%eax \n\t" \ + " subl $4,%%edi \n\t" \ + " orl %%eax,%%eax \n\t" \ + " jl systemCall \n\t" \ + " shll $2,%%eax \n\t" \ + " addl %3,%%eax \n\t" \ + " call *(%%eax) \n\t" \ + " movl (%%edi),%%eax \n\t" \ + " andl %5, %%eax \n\t" \ + " jmp doret \n\t" \ + "systemCall: \n\t" \ + " negl %%eax \n\t" \ + " decl %%eax \n\t" \ + " movl %%eax,%0 \n\t" \ + " movl %%esi,%1 \n\t" \ + " movl %%edi,%2 \n\t" \ + " pushl %%ecx \n\t" \ + " pushl %%esi \n\t" \ + " pushl %%edi \n\t" \ + " call *%4 \n\t" \ + " popl %%edi \n\t" \ + " popl %%esi \n\t" \ + " popl %%ecx \n\t" \ + " addl $4,%%edi \n\t" \ + "doret: \n\t" \ + " ret \n\t" \ + : "=rm" (eSyscallNum), "=rm" (eDP), "=rm" (eOpStack) \ + : "rm" (eInstructionPointers), "r" (callSyscall), "m" (eRomMask) \ + : "ax", "di", "si", "cx" \ + );*/ + //" call *%4 \n\t" + + //" negl %%eax \n\t" + // " decl %%eax \n\t" + __asm__ volatile ("doAsmCall: \n\t" \ + " movl (%%edi),%%eax \n\t" \ + " subl $4,%%edi \n\t" \ + " orl %%eax,%%eax \n\t" \ + " jl systemCall \n\t" \ + " shll $2,%%eax \n\t" \ + " addl %3,%%eax \n\t" \ + " call *(%%eax) \n\t" \ + " movl (%%edi),%%eax \n\t" \ + " andl %5, %%eax \n\t" \ + " ret \n\t" \ + "systemCall: \n\t" \ + " movl %%eax,%0 \n\t" \ + " movl %%esi,%1 \n\t" \ + " movl %%edi,%2 \n\t" \ + " pushl %%ecx \n\t" \ + " pushl %%esi \n\t" \ + " pushl %%edi \n\t" \ + : "=rm" (eSyscallNum), "=rm" (eRP), "=rm" (eDP) \ + : "rm" (eInstructionPointers), "r" (callSyscall), "m" (eRomMask) \ + : "ax", "di", "si", "cx" \ + ); + //printf("Syscall: %d\n", eSyscallNum); + //throw RuntimeException("Turd"); + + eVM->DP = eDP-((int)eRam); + eVM->syscall(eSyscallNum); + eDP = eVM->DP+((int)eRam)-4; + + //" addl $4,%edi \n\t" + // " ret \n\t" + __asm__ volatile ("popl %edi \n\t" \ + " popl %esi \n\t" \ + " popl %ecx \n\t" \ + "doret: \n\t" \ + ); + } + + int VirtualMachine::CallCompiled(int address) + { + //int stack[1024]; + //int stack[100]; + int programStack; + int stackOnEntry; + unsigned char * image; + void * entryPoint; + int * oldInstructionPointers; + void * oldDataStack; + + oldDataStack = eRam; + oldInstructionPointers = eInstructionPointers; + + eVM = this; + eInstructionPointers = instructionPointers; + + eRomMask = romMask; + eRamMask = ramMask; + + // we might be called recursively, so this might not be the very top + eDP = ((int)ram)+DP; + stackOnEntry = DP; + + // set up the stack frame + image = (unsigned char *)ram;//vm->dataBase; + + eDP -= 48; + + //*(int *)&image[ programStack + 44] = args[9]; + //*(int *)&image[ programStack + 40] = args[8]; + //*(int *)&image[ programStack + 36] = args[7]; + //*(int *)&image[ programStack + 32] = args[6]; + //*(int *)&image[ programStack + 28] = args[5]; + //*(int *)&image[ programStack + 24] = args[4]; + //*(int *)&image[ programStack + 20] = args[3]; + //*(int *)&image[ programStack + 16] = args[2]; + //*(int *)&image[ programStack + 12] = args[1]; + //*(int *)&image[ programStack + 8 ] = args[0]; + //*(int *)&image[ programStack + 4 ] = 0; // return stack + //*(int *)&image[ programStack ] = -1; // will terminate the loop on return + + // off we go into generated code... + entryPoint = compiledRom;//0;//vm->codeBase; + eRam = ram+dataStack; + + #if defined(_MSC_VER) + __asm { + pushad + mov esi, DP; + mov edi, opStack + call entryPoint + mov DP, esi + mov opStack, edi + popad + } + #else + { + static int memDP; + static int memRP; + static void *memEntryPoint; + + memDP = DP+((int)ram); + memRP = RP; + memEntryPoint = entryPoint; + + __asm__(" pushal \r\n" \ + " movl %0,%%esi \r\n" \ + " movl %1,%%edi \r\n" \ + " call *%2 \r\n" \ + " movl %%esi,%0 \r\n" \ + " movl %%edi,%1 \r\n" \ + " popal \r\n" \ + : "=m" (memRP), "=m" (memDP) \ + : "m" (memEntryPoint), "0" (memRP), "1" (memDP) \ + : "si", "di" \ + ); + + DP = memDP-((int)ram); + RP = memRP; + } + #endif + + if ( eRam != ram+dataStack ) { + throw RuntimeException("opStack corrupted in compiled code"); + } + if ( DP != stackOnEntry+4 ) { + printf("DP: %d, stackOnEntry: %d\n", DP, stackOnEntry); + throw RuntimeException("programStack corrupted in compiled code"); + } + + DP = stackOnEntry; + + // in case we were recursively called by another vm + eInstructionPointers = oldInstructionPointers; + eRam = oldDataStack; + + return 0;//*(int *)eOpStack; + } + + bool VirtualMachine::Compile() { Instruction op; int maxLength; @@ -50,6 +261,7 @@ namespace vm maxLength = romSize * 8; buf = new unsigned char[maxLength]; jused = new unsigned char[romSize + 2]; + instructionPointers = new int[romSize]; std::fill(jused, jused+romSize+2, 0); for(pass=0; pass<2; pass++) { @@ -90,6 +302,7 @@ namespace vm emitInstruction( "CC" ); // int 3 break; case OP(ENTER): + //emitInstruction( "CC" ); // int 3 emitInstruction( "81 EE" ); // sub esi, 0x12345678 emit4( constant4() ); break; @@ -216,12 +429,11 @@ namespace vm emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP(CALL): - emitInstruction( "C7 86" ); // mov dword ptr [esi+ram],0x12345678 - emit4( (int)ram ); - emit4( pc ); - emitInstruction( "FF 15" ); // call asmCallPtr - //emit4( (int)&asmCallPtr ); - emit4(0); + emitInstruction("C7 86"); // mov dword ptr [esi+ram],0x12345678 + emit4((int)ram); + emit4(pc); + emitInstruction("FF 15"); // call callFromCompiled + emit4((int)&callFromCompiledPtr); break; case OP(PUSH): emitAddEDI4(); @@ -729,6 +941,11 @@ namespace vm //Com_Memcpy( codeBase, buf, compiledOfs ); + compiledRom = new char[compiledOfs]; + std::copy(buf, buf+compiledOfs, compiledRom); + compiledRomSize = compiledOfs; + compiledRomMask = compiledOfs; + delete[] buf; delete[] jused; @@ -736,9 +953,12 @@ namespace vm // offset all the instruction pointers for the new location for ( i = 0 ; i < /*header->instructionCount*/ romSize ; i++ ) { - instructionPointers[i] += (int)codeBase; + instructionPointers[i] += (int)rom; } +#ifdef WIN32 + VirtualProtect(compiledRom, compiledRomSize, PAGE_EXECUTE, NULL); +#endif #if 0 // ndef _WIN32 // Must make the newly generated code executable { @@ -755,6 +975,7 @@ namespace vm Com_Error( ERR_FATAL, "mprotect failed to change PROT_EXEC" ); } #endif + return true; } @@ -918,4 +1139,6 @@ namespace vm } #undef OP -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/virtualmachine/Syscalls.cpp b/src/virtualmachine/Syscalls.cpp index bc88fb24e..b9f921155 100644 --- a/src/virtualmachine/Syscalls.cpp +++ b/src/virtualmachine/Syscalls.cpp @@ -61,7 +61,9 @@ namespace vm TRAPDEF(partCreate) { - Push(sim->create_part(ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4)); + //Push(sim->create_part(ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4)); + printf("create_part(%d, %d, %d, %d)\n", ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4); + Push(0); } TRAPDEF(partChangeType) diff --git a/src/virtualmachine/VirtualMachine.cpp b/src/virtualmachine/VirtualMachine.cpp index dfff84e78..9de822dbf 100644 --- a/src/virtualmachine/VirtualMachine.cpp +++ b/src/virtualmachine/VirtualMachine.cpp @@ -186,8 +186,9 @@ namespace vm /* set up stack. */ { int stacksize = 0x10000; - returnStack = ramSize; dataStack = ramSize - (stacksize / 2); + //returnStack = ramSize; + returnStack = dataStack+4; RP = returnStack; DP = dataStack; } @@ -195,6 +196,8 @@ namespace vm /* set up PC for return-to-termination. */ PC = romSize + 1; + ramMask = ramSize; + return 1; } @@ -203,7 +206,7 @@ namespace vm PC = romSize+1; } - int VirtualMachine::Call(int address) + int VirtualMachine::CallInterpreted(int address) { word w; int i, argCount = 0; diff --git a/src/virtualmachine/VirtualMachine.h b/src/virtualmachine/VirtualMachine.h index ab75e9601..287e9aaec 100644 --- a/src/virtualmachine/VirtualMachine.h +++ b/src/virtualmachine/VirtualMachine.h @@ -66,6 +66,8 @@ namespace vm class VirtualMachine { + int * instructionPointers; + bool bigEndian; /* host is big-endian (requires byte-swapping). */ /* Memory spaces. */ @@ -76,10 +78,16 @@ namespace vm /* Read-Only Memory (code). */ Instruction * rom; int romSize; + int romMask; + + char * compiledRom; + int compiledRomSize; + int compiledRomMask; /* Random-Access Memory (data). */ ram_t *ram; int ramSize; + int ramMask; int dataStack; int returnStack; @@ -113,7 +121,21 @@ namespace vm int readInt(FILE *qvmfile); int opcodeParameterSize(int opcode); int syscall(int programCounter); + + //Used by the JIT + int constant4(); + int constant1(); + void emit1(int v); + void emit4(int v); + void emitInstruction(const char *string); + void emitCommand(int command); + void emitAddEDI4(); + void emitMovEAXEDI(); + bool emitMovEBXEDI(int andit); + static int hex(int c); public: + static void callFromCompiled(); + static void callSyscall(); Simulation * sim; Renderer * ren; @@ -124,9 +146,11 @@ public: VirtualMachine(int hunkMbytes); virtual ~VirtualMachine(); + bool Compile(); int LoadProgram(char * filename); int Run(); - int Call(int address); + int CallInterpreted(int address); + int CallCompiled(int address); void End(); void Marshal(int address, word element) {