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)。