2012-03-07 129 views
-1

我想用C/C++构建一个快速的JIT。它应该将我的字节码转换为IA32。是的,我知道libjit和类似的,但我相信他们并不简单。我认为我已经找到了更快捷的方式来构建指令,但我错了 - 传统的开关/外壳方法比我的快两倍。我的方法是复制一个块,然后填写一个模板。我知道现代编译器上的switch/case会创建一个跳转表,所以我没有跳转表的实现。简单的字节码翻译器

我已经使用了一个包含循环到基准的代码[]的内容的50mb文件。 我的配置是:i7,8gb ram,使用VS2010编译。

这里是我的代码:

#include <stdio.h> 
#include <stdlib.h> 
#include <memory.h> 
#include <time.h> 

//unsigned char code[] = {1,2,3,4,4}; 

void mycopy(unsigned char* to, unsigned char* from, int size) { 
    int i = 0; 
    while(i < size) { 
     /*if (i < size-3) { 
      if (*(unsigned int*) &from[i] == 0xFFFFFFFF) { 
       *(unsigned int*) &to[i] = 0xC3C3C3C3; 
       i += 4; 
       continue; 
      } 
     }*/ 

     to[i] = from[i]; 
     i++; 
    } 
} 

void translateA(unsigned char* code, unsigned char* output, int size) { 

    unsigned char A[] = { 3, 1, 1, 1 }; // { size, <bytes...> } 
    unsigned char B[] = { 2, 2, 2 }; 
    unsigned char C[] = { 8, 3, 3, 3, 3, 0xFF, 0xFF, 0xFF, 0xFF }; 
    unsigned char D[] = { 1, 4 }; 

    void* templat[] = { &A, &B, &C, &D }; 

    int i = 0; 
    int total = 0; 
    while(i < size) { 
     int op_index = (int) code[i] - 1; 
     unsigned char* instr_buffer = (unsigned char*) templat[op_index]; 
     int size = (int) instr_buffer[0]; 
     instr_buffer++; 
     mycopy(output+total, instr_buffer,size); 
     total += size; 
     i++; 
    } 
} 




void translateB(unsigned char* code, unsigned char* output, int size) { 
    for(int i = 0; i < size; i++) { 
     switch(code[i]) { 
      case 1: 
       output[0] = 1; 
       output[1] = 1; 
       output[2] = 1; 
       output += 3; 
       break; 
      case 2: 
       output[0] = 2; 
       output[1] = 2; 
       output += 2; 
       break; 
      case 3: 
       output[0] = 3; 
       output[1] = 3; 
       output[2] = 3; 
       output[3] = 3; 
       output[4] = 0xC3; 
       output[5] = 0xC3; 
       output[6] = 0xC3; 
       output[7] = 0xC3;    
       output += 8;    
       break; 
      case 4: 
       output[0] = 4; 
       output++; 
       break; 
     } 
    } 
} 

int main(int argc, char* argv[]) { 
    // load the 'code' to an array 
    FILE* f = fopen("testops.bin", "r+"); 

    fseek(f, 0, SEEK_END); 
    long fsize = ftell(f); 
    fseek(f, 0, SEEK_SET); 

    unsigned char* code = (unsigned char*) malloc(fsize); 
    fread(code, fsize, 1, f); 
    fclose(f); 

    unsigned char* output = (unsigned char*) malloc(fsize*10); 
    memset(output, 0x7A, fsize*10); 

    // benchmark it 
    time_t start = clock(); 

    // Replace with translateB. It's ~2x faster 
    translateA(code, output, fsize); 

    printf("\nelapsed %fs\n\n", (float) (clock()-start)/1000); 

    printf("OUTPUT: "); 
    for(int i=0;i<1024;i++) { 
     if (output[i] == 0x7A) break; 
     printf("%X", output[i]); 
    } 

    printf("\n"); 

    system("PAUSE"); 
    return 0; 
} 

编辑:我的问题是,为什么拨码开关的速度更快?有什么我做错了吗?

+3

你的问题是什么? – orlp 2012-03-07 19:49:11

+0

我的问题是为什么切换代码更快? – blez 2012-03-07 20:08:11

+0

我编辑了我的问题。 – blez 2012-03-07 20:31:23

回答

0

建立然后反汇编你的程序,你会得到你的回应。

由于编译器优化,开关盒更高效,因为它会按照您所说的创建跳转表。

你的方法使得更多的地址查找,并且每个字节码有一个更多的函数调用和循环。

此外,为什么你使用while作为你知道循环次数的循环? 编译器可能会对for循环进行其他优化。

而对于4个开关,我不确定你的编译器是否会创建一个跳转表,所以真实的例子可能会更快。