1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | --- ./opcode_vm.c 2018-05-16 14:01:57.457011799 +0800 +++ ./opcode_vm_v2.c 2018-05-17 02:41:24.989543622 +0800 @@ -25,7 +25,6 @@ #include <sys/mman.h> - #ifdef _NOJIT static inline int IAdd(int inp1, int inp2) { puts("Non-JIT version iadd."); @@ -38,6 +37,9 @@ #else +#define MAXCODECACHE_NUM 256 +void *CodeCachePool[MAXCODECACHE_NUM] = {NULL}; + // Nope, I'm not gonna write an assembler. // Just pretend we _magically_get assembly pieces we need. const unsigned char _add[] = \ @@ -45,10 +47,9 @@ const unsigned char _sub[] = \ "\x55\x48\x89\xe5\x89\x7d\xfc\x89\x75\xf8\x8b\x45\xfc\x2b\x45\xf8\x5d\xc3\x00"; -#define MAXCODECAHE_SIZE 4096 -void* AllocExeMem(size_t size) { +void* AllocTB(size_t size) { void* memPtr = mmap(0, size, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (memPtr == (void*)-1) { perror("mmap() failed."); @@ -57,7 +58,53 @@ return memPtr; } -void *CodeCachePool; +int SetTBExecutable(void* m, size_t sz) { + return mprotect(m, sz, PROT_READ | PROT_EXEC); + } + +static inline unsigned long CPHash(const unsigned char* cpiece) { + // djb2 hash function, credit to : + // http://www.cse.yorku.ca/~oz/hash.html + unsigned long hash = 5381; + int c; + while (c = *cpiece++) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + + +static inline void* GenTB(const unsigned char* cpiece, unsigned long k , size_t sz) { + unsigned char* tb = AllocTB(sz); + memcpy(tb, cpiece, sz); + CodeCachePool[k] = tb; + SetTBExecutable(tb, sz); + return tb; +} + + +static inline void* CheckCollision(const unsigned char* cpiece, unsigned long k, size_t sz) { + void *desiredTB; + if(CodeCachePool[k] == NULL) { + // This is caused by collision, probe for open slot. + // Very unlikely to happen. + puts("wtf"); + desiredTB = GenTB(cpiece, k, sz); + } + else { + desiredTB = strcmp(CodeCachePool[k], cpiece) == 0 ? + // Collision occured if strcmp returns non 0 + CodeCachePool[k] : + CheckCollision(cpiece, (k+1)%MAXCODECACHE_NUM, sz) ; + } + return desiredTB; +} + +// Find out whether the code piece is already in translation block +static inline void* TBFind(const unsigned char* cpiece, size_t sz) { + unsigned long key = (CPHash(cpiece)%MAXCODECACHE_NUM); + return CodeCachePool[key] ? CheckCollision(cpiece, key, sz) : GenTB(cpiece, key, sz) ; +} + int (*IAdd)(int, int); int (*ISub)(int, int); @@ -77,7 +124,7 @@ **/ const unsigned char BytecodeStream[] = \ -"\x01\x02\x03\x02\x05\x04\x00\x00\x00\xff"; +"\x01\x02\x03\x02\x05\x04\x01\x0a\x0a\x02\x0c\x02\x00\x00\x00\xff"; int runVM(const unsigned char* bstream) { @@ -90,14 +137,13 @@ return 0; case 0x01: #ifndef _NOJIT - // emit code to code cache. - memcpy(CodeCachePool, _add, sizeof(_add)); + IAdd = TBFind(_add, sizeof(_add)); #endif printf("iadd: %d\n", IAdd((int)insn[1], (int)insn[2])); break; case 0x02: #ifndef _NOJIT - memcpy(CodeCachePool, _sub, sizeof(_sub)); + ISub = TBFind(_sub, sizeof(_sub)); #endif printf("isub: %d\n", ISub((int)insn[1], (int)insn[2])); break; @@ -112,13 +158,8 @@ int main(int ac, char* av[]) { int ret = -1; - #ifndef _NOJIT - CodeCachePool = AllocExeMem(MAXCODECAHE_SIZE); - IAdd = CodeCachePool; - ISub= CodeCachePool; - #endif ret = runVM(BytecodeStream); - if(ret == 0) { perror("VM exited successfully."); } - else { perror("Unexpected error occured."); } + if(ret == 0) { puts("VM exited successfully."); } + else { puts("Unexpected error occured."); } return 0; } |
Direct link: https://paste.plurk.com/show/2636452