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;
 }