Eclipse OMR - JitBuilder Demo1(Simple)

https://github.com/eclipse/omr/blob/master/jitbuilder/release/src/Simple.hpp

https://github.com/eclipse/omr/blob/master/jitbuilder/release/src/Simple.cpp

上面两个文件是Eclipse OMR的JitBuilder自带的demo中的一个,也是最简单的一个示例。

这里例子实现了这功能:用代码动态定义一个函数increment,这个函数的用途:参数是一个32位的整数,返回值是该参数值加1。int32 increment(int32)。因为这个是demo,所以整数加法越界的问题并没有处理。increment(2017)返回2018。

int increment(int value) {
  return value + 1;
}

上面是用C语言写的同样功能,我们在用JitBuilder实现之前,先思考一下我们写这个函数的步骤:

1、定义函数名称:increment

2、定义函数的参数名称(value)和参数类型(int)

3、定义函数返回值类型(int)

4、实现函数体代码

在JitBuilder中也是遵循这三个步骤,我们下面仔细地看看Demo代码。

先看头文件:https://github.com/eclipse/omr/blob/master/jitbuilder/release/src/Simple.hpp

class SimpleMethod : public TR::MethodBuilder
{
  public:
    SimpleMethod(TR::TypeDictionary *);
    virtual bool buildIL();
};

这是核心代码,功能简明扼要:定义自己的class:SimpleMethod,其父类是TR::MethodBuilder,实现SimpleMethod的构造函数,override TR::MethodBuilder的方法buildIL(准确地讲buildIL方法是更上层的父类定义的)。

接着看cpp文件:https://github.com/eclipse/omr/blob/master/jitbuilder/release/src/Simple.cpp

cpp文件中代码稍微多一点,我们先看SimpleMethod的构造函数

SimpleMethod::SimpleMethod(TR::TypeDictionary *d)
   : MethodBuilder(d)
{
   DefineLine(LINETOSTR(__LINE__));
   DefineFile(__FILE__);

   DefineName("increment");
   DefineParameter("value", Int32);
   DefineReturnType(Int32);
}

1、用DefineName定义了要实现的函数名称:increment

2、用DefineParameter定义了函数increment的参数名称value和类型Int32

3、用DefineReturnType定义了函数返回值Int32

这三步就对应我们写下了如下C代码

int increment(int value) 
{

}

接下来当然是要实现函数体的具体代码,这是在buildIL里面实现的,先看代码

bool SimpleMethod::buildIL()
{
   Return(
      Add(
         Load("value"),
         ConstInt32(1)));

   return true;
}

凭猜测,这是类似下面的C代码

return value + 1;

buildIL中的IL是Intermediate Language的缩写,即中间语言。因为OMR本身不会和高级语言对应,所以就定义了自己的语言(IL)来表达语义。学过编译原理的都明白这是写编译器必须的套路。

OMR的IL的全称是:Testarossa's Intermediate Language

更多的文档见:https://github.com/eclipse/omr/tree/master/doc/compiler/il

因为IL涉及到的知识点还是相当多,这个留在以后的博客里面仔细讲解。

一个基本的观点先记住:IL是基于Tree结构的,准确地讲是DAG(无环有向图)

回到我们的increment函数的buildIL中

Return(
      Add(
         Load("value"),
         ConstInt32(1)));

这就是用C++代码按IL的风格写出的代码,特别要注意的是用缩进表达了Tree里面的层次结构,这是写IL的时候特定的惯用法。

小结一下上述步骤:

1、定义自己的class,从TR::MethodBuilder继承。

2、在自定义的class的构造函数中定义函数名称、参数名称和类型和返回值类型

3、override buildIL,用IL实现函数的具体功能

实现了increment函数,下面就看看如何使用了。

int main(int argc, char *argv[])
{
   // 我把原来代码中关于错误处理的代码全部删除了
   // 所以下面的代码是为了便于入门理解用

   // 第1步:调用initializeJit()初始化JIT编译器
   initializeJit();

   // 第2步:初始化自定义的class,这里是SimpleMethod
   TR::TypeDictionary types;
   SimpleMethod method(&types);
   
   // 第3步:即时编译代码
   uint8_t *entry = 0;
   int32_t rc = compileMethodBuilder(&method, &entry);

   // 第4步:用函数指针获得编译后的代码地址
   typedef int32_t (SimpleMethodFunction)(int32_t);
   SimpleMethodFunction *increment = (SimpleMethodFunction *) entry;

   // 第5步:用函数指针调用函数
   int32_t v = 10;
   cout << "increment(" << v << ") == " << increment(v) << "\n";
   
   // 第6步:卸载JIT编译器,释放内存
   shutdownJit();
}

上面6步就是使用JIT编译器的基本套路。

看完这个之后,你就可以动手改动改动这个demo的代码,比如实现一个 int add(int a, int b)。

猜你喜欢

转载自my.oschina.net/u/134395/blog/1580711
今日推荐