2012-12-02 55 views
1

通过原生我的意思是写在C++或C如何从VM调用本地函数?

我正在做基于一种编程语言爪哇,因为它有一个虚拟机,并字节码编译的语言。

实现语言的功能,如for循环,变量,算术等对我来说不是问题;不过,执行像Java这样的本地函数可以。

我需要本地函数,以便使用我的语言编写的程序可以创建窗口,与硬件和操作系统进行交互,并执行几乎不是简单的数学操作。

我听说过JNI,它绝对看起来像我想要的东西,但是,我不知道如何实现这样的东西。

正如我的虚拟机是用C++实现的,我知道我可以拥有它我的本地函数#include HPP文件在编译时间,然后它可以动态加载dll的或so的,然而,这并未“这似乎是一个很好的解决方案,因为每当你希望它能够执行另一个本地函数时,你都必须重新编译虚拟机。

问题归结为:C++程序(VM)如何动态(在运行时按字节码指示)更精确地加载C++函数库,然后执行那些函数而不用它们在一些头文件中预先声明?

+1

请问你提供一些代码样本你想要什么? –

+0

在Windows上,您使用LoadLibrary()和GetProcAddress()。 Linux具有不同名称的等同功能。这些无助于您了解参数和返回值的数量和类型。 –

+0

@BhavikAmbani当然,只要几个小时回家。 – corazza

回答

1

看看libffi。它提供方法来调用给定函数地址和调用签名的任何函数。

如何确定签名应该取决于您的上下文。您可以根据参数类型推断大范围的调用。 JNA推断来自显式Java接口,方法声明或动态调用参数的本地调用签名。

超越简单函数调用来处理构造函数,内存管理和对象方法调度比较复杂,但仍基于相同的基本原则。

+0

这绝对看起来像我需要的东西。然而,我并不确定我该如何在一些动态加载的共享对象('dlopen()')中获得指向某个函数的指针。我知道名称,参数数量,参数类型和函数本身的返回类型,因为这是用我的语言描述的,但我不知道如何获得指向本地函数的指针。如果我知道本地函数将被称为'X',我可以得到一个指向它的指针吗? – corazza

+0

'dlsym()'查找给定名称的符号。通常,导出的符号是可以调用的函数或用于数据访问的全局变量的地址。 – technomage

+0

现在我已经有了'dlopen()'和'dlsym()',LibFFI的实际需求在哪里? – corazza

0

我没有见过的一个话题是如何将新语言VM函数调用的参数传递给C++堆栈,以及如何将C++函数的返回值传递回虚拟机。

假设你想让你的新语言提供pow(3)函数。 作为提醒,战俘()签名是

double pow (double base, double power) 

最简单的方法是这样的

void 
language::pow(VM * pVM) 
{ 
    double arg2 = pVM->PopDouble(); 
    double arg1 = pVM->PopDouble(); 
    double result = pow(arg1, arg2); 
    pVM->PushDouble(result); 
} 

但是,这听起来并不像你所追求的。结合dlopen()的&的dlsym()得到你像

void 
language::pow(VM * pVM) 
{ 
    double arg2 = pVM->PopDouble(); 
    double arg1 = pVM->PopDouble(); 
    void *handle = dlopen("libm", RTLD_LAZY); 
    if (!handle) { /*...return; ...*/ } 
    typedef double (* pfPow) (double, double); 
    pfPow pPow = (pfPow) dlsym(handle, "pow"); 
    if (!pPow) { /*...return; ...*/ } 
    double result = (* pPow)(arg1, arg2); 
    pVM->PushDouble(result); 
} 

但是,这更是雪上加霜。您仍然需要每个C++函数的存根函数,您希望您的语言能够访问它。

这听起来像你希望你的语言有类似

double result = eval_double("libm", "pow", arg1, arg2); 

我不知道如何实现,在C++。 Varags支持获取任何类型的C++参数。但是没有推送任意类型的C++参数的API。