Working X86 JIT compilation/execution

This commit is contained in:
Simon Robertshaw 2013-01-30 18:11:06 +00:00
parent c4e5e82fec
commit ca7c0d777b
6 changed files with 142 additions and 48 deletions

View File

@ -958,7 +958,8 @@ int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
machine->CSPush(i); machine->CSPush(i);
machine->CSPush(x); machine->CSPush(x);
machine->CSPush(y); machine->CSPush(y);
machine->Call(0); //machine->Call(0);
machine->CallCompiled(0);
/*vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type]; /*vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];

View File

@ -417,13 +417,13 @@ namespace pim
void VirtualMachine::Compile() void VirtualMachine::Compile()
{ {
Native * native = new X86Native(); Native * native = new X86Native();
std::vector<unsigned char> executableCode = native->Compile(rom, romSize); std::vector<unsigned char> executableCode = native->Compile(sim, rom, romSize);
Client::Ref().WriteFile(executableCode, "code.x"); Client::Ref().WriteFile(executableCode, "code.x");
unsigned char * romAddress = new unsigned char[executableCode.size()+8]; unsigned char * romAddress = new unsigned char[executableCode.size()+8];
std::fill(romAddress, romAddress+executableCode.size()+8, 0x90); //Fill with NOP for debugging std::fill(romAddress, romAddress+executableCode.size()+8, 0x90); //Fill with NOP for debugging
std::copy(executableCode.begin(), executableCode.end(), romAddress+4); std::copy(executableCode.begin(), executableCode.end(), romAddress+4);
nativeRom = (intptr_t)romAddress;
delete native; delete native;
} }
@ -435,12 +435,15 @@ namespace pim
void VirtualMachine::CallCompiled(int entryPoint) void VirtualMachine::CallCompiled(int entryPoint)
{ {
void (*nativeFunction)(int, int, int) = (void(*)(int, int, int))nativeRom;
int arg3 = CSPop().Integer;
int arg2 = CSPop().Integer;
int arg1 = CSPop().Integer;
nativeFunction(arg1, arg2, arg3);
} }
void VirtualMachine::Call(std::string entryPoint) void VirtualMachine::Call(std::string entryPoint)
{ {
} }
void VirtualMachine::Call(int entryPoint) void VirtualMachine::Call(int entryPoint)

View File

@ -59,6 +59,8 @@ namespace pim
int romSize; int romSize;
int romMask; int romMask;
intptr_t nativeRom;
unsigned char * compiledRom; unsigned char * compiledRom;
int compiledRomSize; int compiledRomSize;

View File

@ -6,6 +6,6 @@ namespace pim
{ {
public: public:
Native() {} Native() {}
virtual std::vector<unsigned char> Compile(Instruction * rom, int romSize) {} virtual std::vector<unsigned char> Compile(Simulation * sim, Instruction * rom, int romSize) {}
}; };
} }

View File

@ -1,22 +1,32 @@
#include "Opcodes.h" #include "Opcodes.h"
#include "X86Native.h" #include "X86Native.h"
#include "simulation/Simulation.h"
namespace pim namespace pim
{ {
std::vector<unsigned char> X86Native::Compile(Instruction * rom, int romSize) std::vector<unsigned char> X86Native::Compile(Simulation * sim, Instruction * rom, int romSize)
{ {
#if defined(X86) && !defined(_64BIT) #if defined(X86) && !defined(_64BIT)
int programCounter = 0; int programCounter = 0;
nativeRom.clear(); nativeRom.clear();
unsigned char * esi = new unsigned char[1024*1024];//malloc(1024*1024);
esi += 512;
//int * esi = malloc(1024*1024);
emit("BE"); //mov esi, machineStack
emit((intptr_t)esi);
emit("81 C4"); //add esp, 4
emit(4);
while(programCounter < romSize) while(programCounter < romSize)
{ {
Word argument = rom[programCounter].Parameter; Word argument = rom[programCounter].Parameter;
virtualToNative[programCounter] = nativeRom.size();
switch(rom[programCounter].Opcode) switch(rom[programCounter].Opcode)
{ {
case Opcode::Load: case Opcode::Load:
emit("83 EE 04"); //sub esi, 4 emit("83 EE 04"); //sub esi, 4
//Load value at base stack + offset into eax //Load value at base stack + offset into eax
emit("8B 85"); //mov eax, [ebp+offset] //emit("8B 85"); //mov eax, [ebp+offset]
emit("8B 84 24"); //mov eax, [esp+offset]
emit((int) (argument.Integer)); emit((int) (argument.Integer));
//Store value in eax onto top of program stack //Store value in eax onto top of program stack
emit("89 06"); //mov [esi], eax emit("89 06"); //mov [esi], eax
@ -25,7 +35,8 @@ namespace pim
//Load value on top of the program stack into eax //Load value on top of the program stack into eax
emit("8B 06"); //mov eax, [esi] emit("8B 06"); //mov eax, [esi]
//Load value in eax into memory //Load value in eax into memory
emit("89 85"); //mov [ebp+offset], eax //emit("89 85"); //mov [ebp+offset], eax
emit("89 84 24"); //mov [esp+offset], eax
emit((int) (argument.Integer)); emit((int) (argument.Integer));
emit("83 C6 04"); //add esi, 4 emit("83 C6 04"); //add esi, 4
break; break;
@ -35,8 +46,13 @@ namespace pim
emit((int) (argument.Integer)); emit((int) (argument.Integer));
break; break;
case Opcode::Increment: case Opcode::Increment:
emit("81 06"); //add [esi], dword ptr constant if(argument.Integer > 0) {
emit((int) (argument.Integer)); emit("81 06"); //add [esi], dword ptr constant
emit((int) (argument.Integer));
} else {
emit("81 2E"); //sub [esi], dword ptr constant
emit((int) (-argument.Integer));
}
break; break;
case Opcode::Discard: case Opcode::Discard:
emit("83 C6 04"); //add esi, 4 emit("83 C6 04"); //add esi, 4
@ -83,6 +99,7 @@ namespace pim
emit("F7 1E"); //neg [esi] emit("F7 1E"); //neg [esi]
break; break;
case Opcode::Create: case Opcode::Create:
emitCall((intptr_t)sim, (intptr_t)((void*)&Simulation::create_part));
//temp1 = PSPop(); //temp1 = PSPop();
//temp2 = PSPop(); //temp2 = PSPop();
//temp3 = PSPop(); //temp3 = PSPop();
@ -103,20 +120,29 @@ namespace pim
//} //}
//PSPush(temp>>8); //PSPush(temp>>8);
{ {
int propertyOffset = argument.Integer; intptr_t partsArray = (intptr_t)sim->pmap;
int partsArray = 0;
emit("8B 06"); //mov eax, [esi] emit("8B 06"); //mov eax, [esi]
//mov ecx, [esi+4] emit("8B 4E 04"); //mov ecx, [esi+4]
//and eax, 348 emit("81 F9"); //cmp ecx, XRES
//and ecx, 612 emit((int)XRES);
emit("7D 22"); //|--< //jge 34
//imul eax, 612, eax emit("74 20"); //|--< //jz 32
emit("8B 46 04"); //add eax, ecx emit("3D"); //| //cmp eax, YRES
emit("8B 81"); //mov eax, [eax*4+pmap] emit((int)YRES); //|
//sar eax, 8 emit("7D 19"); //|--< //jge 25
emit("89 06"); //mov [esi+4], eax #Copy eax onto stack emit("74 17"); //|--< //jz 23
emit("83 C6 08"); //add esi, 4 //|
emit("69 C0"); //| //imul eax, 612
emit((int)XRES); //|
emit("01 C8"); //| //add eax, ecx
emit("8B 04 85"); //| //mov eax, [eax*4+pmap]
emit((int)partsArray); //|
emit("C1 F8 08"); //| //sar eax, 8
emit("89 46 04"); //| //mov [esi+4], eax #Copy eax onto stack
emit("EB 07"); //| |-< //jmp +7
emit("C7 46 04 FF FF FF FF"); //L-+-> //mov [esi+4], -1
emit("83 C6 04"); // L-> //add esi, 4
} }
break; break;
case Opcode::Position: case Opcode::Position:
@ -129,6 +155,34 @@ namespace pim
//} //}
//PSPush((int)sim->parts[temp1.Integer].x); //PSPush((int)sim->parts[temp1.Integer].x);
//PSPush((int)sim->parts[temp1.Integer].y); //PSPush((int)sim->parts[temp1.Integer].y);
{
intptr_t partsArray = (intptr_t)sim->parts;
emit("8B 06"); //mov eax, [esi] #Load index from stack
emit("3D"); //cmp eax, NPART
emit((int)NPART);
emit("7D 23"); //|--< //jge 31
emit("74 21"); //|--< //jz 29
//|
emit("C1 E0 03"); //| //sal eax, 3 #Shift index left (multiply by 8)
emit("8D 14 C5 00 00 00 00"); //| //lea edx, [eax*8] #Mutiply by 8 again and copy into edx //Size of 56 is represented by (1*(8^2))-(1*8)
emit("89 D1"); //| //mov ecx, edx
emit("29 C1"); //| //sub ecx, eax #Subtract index*8^2 by index*8 to get the index*56
//emit("8B 81"); //| //mov eax, [ecx+xOffset+partsArray] #Copy value at index+baseAddress+propertyOffset into eax
emit("D9 81"); //| //fld [ecx+xOffset+partsArray]
emit(partsArray+offsetof(Particle, x));
emit("DB 1E"); //| //fistp [esi]
//emit("89 06"); //| //mov [esi], eax #Copy eax onto stack
//emit("89 81"); //| //mov eax, [ecx+yOffset+partsArray] #Copy value at index+baseAddress+propertyOffset into eax
emit("D9 81"); //| //fld [ecx+xOffset+partsArray]
emit(partsArray+offsetof(Particle, y));
emit("DB 5E FC"); //| //fistp [esi-4], eax #Copy eax onto stack
//emit("89 46 FC"); //| //mov [esi-4], eax #Copy eax onto stack
emit("EB 0D"); //| |-< //jmp +13
emit("C7 06 FF FF FF FF"); //L-+-> //mov [esi], -1
emit("C7 46 FC FF FF FF FF"); // | //mov [esi-4] -1
emit("83 EE 04"); // L-> //sub esi, 4
}
break; break;
case Opcode::Kill: case Opcode::Kill:
//sim->kill_part(PSPop().Integer); //sim->kill_part(PSPop().Integer);
@ -136,11 +190,11 @@ namespace pim
break; break;
case Opcode::LoadProperty: case Opcode::LoadProperty:
{ {
int propertyOffset = argument.Integer; intptr_t propertyOffset = argument.Integer;
int partsArray = 0; intptr_t partsArray = (intptr_t)sim->parts;
emit("8B 06"); //mov eax, [esi] #Load index from stack emit("8B 06"); //mov eax, [esi] #Load index from stack
emit("C1 E0 03"); //sal eax, 3 #Shift index left (multiply by 8) emit("C1 E0 03"); //sal eax, 3 #Shift index left (multiply by 8)
emit("8D 14 C5"); //lea edx, [eax*8] #Mutiply by 8 again and copy into edx //Size of 56 is represented by (1*(8^2))-(1*8) emit("8D 14 C5 00 00 00 00"); //lea edx, [eax*8] #Mutiply by 8 again and copy into edx //Size of 56 is represented by (1*(8^2))-(1*8)
emit("89 D1"); //mov ecx, edx emit("89 D1"); //mov ecx, edx
emit("29 C1"); //sub ecx, eax #Subtract index*8^2 by index*8 to get the index*56 emit("29 C1"); //sub ecx, eax #Subtract index*8^2 by index*8 to get the index*56
emit("8B 81"); //mov eax, [ecx+propertyOffset+partsArray] #Copy value at index+baseAddress+propertyOffset into eax emit("8B 81"); //mov eax, [ecx+propertyOffset+partsArray] #Copy value at index+baseAddress+propertyOffset into eax
@ -150,11 +204,11 @@ namespace pim
break; break;
case Opcode::StoreProperty: case Opcode::StoreProperty:
{ {
int propertyOffset = argument.Integer; intptr_t propertyOffset = argument.Integer;
int partsArray = 0; intptr_t partsArray = (intptr_t)sim->parts;
emit("8B 06"); //mov eax, [esi] emit("8B 06"); //mov eax, [esi]
emit("C1 E0 03"); //sal eax, 3 emit("C1 E0 03"); //sal eax, 3
emit("8D 14 C5"); //lea edx, [eax*8] emit("8D 14 C5 00 00 00 00"); //lea edx, [eax*8]
emit("89 D1"); //mov ecx, edx emit("89 D1"); //mov ecx, edx
emit("29 C1"); //sub ecx, eax emit("29 C1"); //sub ecx, eax
emit("8B 46 04"); //mov eax, [esi+4] emit("8B 46 04"); //mov eax, [esi+4]
@ -167,52 +221,53 @@ namespace pim
emit("83 C6 08"); //add esi, 8 emit("83 C6 08"); //add esi, 8
emit("8B 46 FC"); //mov eax, [esi-4] emit("8B 46 FC"); //mov eax, [esi-4]
emit("3B 46 F8"); //cmp eax, [esi-8] emit("3B 46 F8"); //cmp eax, [esi-8]
emit("75 08"); //jne 8 emit("75 05"); //jne 8
emit("E9 01"); //jmp [0x12345678] emit("E9"); //jmp [0x12345678]
emit((int)0); emitPlaceholder(argument.Integer);
break; break;
case Opcode::JumpNotEqual: case Opcode::JumpNotEqual:
emit("83 C6 04"); //add esi, 8 emit("83 C6 04"); //add esi, 8
emit("8B 46 FC"); //mov eax, [esi-4] emit("8B 46 FC"); //mov eax, [esi-4]
emit("3B 46 F8"); //cmp eax, [esi-8] emit("3B 46 F8"); //cmp eax, [esi-8]
emit("74 08"); //je 8 emit("74 05"); //je 8
emit("E9 01"); //jmp [0x12345678] emit("E9"); //jmp [0x12345678]
emit((int)0); emitPlaceholder(argument.Integer);
break; break;
case Opcode::JumpGreater: case Opcode::JumpGreater:
emit("83 C6 08"); //add esi 8 emit("83 C6 08"); //add esi 8
emit("8B 46 FC"); //mov eax, [esi-4] emit("8B 46 FC"); //mov eax, [esi-4]
emit("3B 46 F8"); //cmp eax, [esi-8] emit("3B 46 F8"); //cmp eax, [esi-8]
emit("7E 08"); //jng 8 emit("7E 05"); //jng 8
emit("E9 01"); //jmp [0x12345678] emit("E9"); //jmp [0x12345678]
emit((int)0); emitPlaceholder(argument.Integer);
break; break;
case Opcode::JumpGreaterEqual: case Opcode::JumpGreaterEqual:
emit("83 C6 08"); //add esi 8 emit("83 C6 08"); //add esi 8
emit("8B 46 FC"); //mov eax, [esi-4] emit("8B 46 FC"); //mov eax, [esi-4]
emit("3B 46 F8"); //cmp eax, [esi-8] emit("3B 46 F8"); //cmp eax, [esi-8]
emit("7C 08"); //jnge +6 emit("7C 05"); //jnge +6
emit("E9 01"); //jmp [0x12345678] emit("E9"); //jmp [0x12345678]
emit((int)0); emitPlaceholder(argument.Integer);
break; break;
case Opcode::JumpLess: case Opcode::JumpLess:
emit("83 C6 08"); //add esi 8 emit("83 C6 08"); //add esi 8
emit("8B 46 FC"); //mov eax, [esi-4] emit("8B 46 FC"); //mov eax, [esi-4]
emit("3B 46 F8"); //cmp eax, [esi-8] emit("3B 46 F8"); //cmp eax, [esi-8]
emit("7D 08"); //jnl +6 emit("7D 05"); //jnl +6
emit("E9 01"); //jmp [0x12345678] emit("E9"); //jmp [0x12345678]
emit((int)0); emitPlaceholder(argument.Integer);
break; break;
case Opcode::JumpLessEqual: case Opcode::JumpLessEqual:
emit("83 C6 08"); //add esi 8 emit("83 C6 08"); //add esi 8
emit("8B 46 FC"); //mov eax, [esi-4] emit("8B 46 FC"); //mov eax, [esi-4]
emit("3B 46 F8"); //cmp eax, [esi-8] emit("3B 46 F8"); //cmp eax, [esi-8]
emit("7F 08"); //jnle +6 emit("7F 08"); //jnle +6
emit("E9 01"); //jmp [0x12345678] emit("E9"); //jmp [0x12345678]
emit((int)0); emitPlaceholder(argument.Integer);
break; break;
case Opcode::Jump: case Opcode::Jump:
//programCounter = argument.Integer-1; emit("E9"); //jmp [0x12345678]
emitPlaceholder(argument.Integer);
break; break;
case Opcode::Return: case Opcode::Return:
emit("81 C7"); //add edi, constant emit("81 C7"); //add edi, constant
@ -226,11 +281,39 @@ namespace pim
//std::cout << programStack << std::endl; //std::cout << programStack << std::endl;
programCounter++; programCounter++;
} }
emit("81 EC"); //sub esp, 4
emit(4);
emit("C9"); //leave
emit("C3"); //ret
for(std::map<int, int>::iterator iter = placeholders.begin(), end = placeholders.end(); iter != end; ++iter)
{
std::pair<int, int> placeholder = *iter;
int newNativeAddress = virtualToNative[placeholder.second]-placeholder.first-4;
nativeRom[placeholder.first] = newNativeAddress & 0xFF;
nativeRom[placeholder.first+1] = (newNativeAddress >> 8) & 0xFF;
nativeRom[placeholder.first+2] = (newNativeAddress >> 16) & 0xFF;
nativeRom[placeholder.first+3] = (newNativeAddress >> 24) & 0xFF;
}
//std::cout << "CS: " << callStack << " PS: " << programStack << std::endl; //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
return nativeRom; return nativeRom;
#endif #endif
} }
void X86Native::emitPlaceholder(int virtualAddress)
{
placeholders[nativeRom.size()] = virtualAddress;
emit((int)0);
}
void X86Native::emitCall(intptr_t objectPtr, intptr_t functionAddress)
{
emit("B9"); //mov ecx, instancePointer
emit((int) objectPtr);
emit("A1"); //mov eax, functionAddress
emit((int)functionAddress);
emit("FF D0"); //call eax
}
void X86Native::emit(std::string opcode) void X86Native::emit(std::string opcode)
{ {
unsigned char c1, c2; unsigned char c1, c2;

View File

@ -1,4 +1,5 @@
#include <vector> #include <vector>
#include <map>
#include "Native.h" #include "Native.h"
namespace pim namespace pim
@ -7,11 +8,15 @@ namespace pim
{ {
public: public:
X86Native() : Native(), nativeRom() {} X86Native() : Native(), nativeRom() {}
virtual std::vector<unsigned char> Compile(Instruction * rom, int romSize); virtual std::vector<unsigned char> Compile(Simulation * sim, Instruction * rom, int romSize);
private: private:
void emit(std::string opcode); void emit(std::string opcode);
void emit(int constant); void emit(int constant);
void emitCall(intptr_t objectPtr, intptr_t functionAddress);
void emitPlaceholder(int virtualAddress);
unsigned char hex(char c); unsigned char hex(char c);
std::vector<unsigned char> nativeRom; std::vector<unsigned char> nativeRom;
std::map<int, int> virtualToNative;
std::map<int, int> placeholders;
}; };
} }