繁体   English   中英

如何从 VM 调用本机函数?

[英]How to call native functions from a VM?

本机是指用 C++ 或 C 编写的

我正在制作一种基于 Java 的编程语言,因为它有一个 VM 和一个字节码编译器语言。

实现语言的特性,例如for循环、变量、算术等等,对我来说不是问题; 但是,执行像 Java 这样的本机函数可以。

我需要本机函数,以便使用我的语言编写的程序能够创建窗口、与硬件和操作系统交互,以及做任何不是简单数学的事情。

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

由于我的 VM 是用 C++ 实现的,我知道我可以在编译时拥有它#include我的本机函数的 hpp 文件,然后它可以动态加载dll的或so的,但是,这似乎并不真正喜欢一个很好的解决方案,因为每次您希望它能够执行另一个本机功能时都必须重新编译 VM。

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

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

您如何确定该签名应该是什么取决于您的上下文。 您可以根据参数类型推断出广泛的调用。 JNA从显式 Java 接口、方法声明或动态调用参数推断本机调用签名。

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

我还没有看到讨论过的一个主题是如何将新语言 VM 函数调用中的参数传递给 C++ 堆栈,以及如何将 C++ 函数的返回值传递回你的 VM。

假设您想让 pow(3) 函数在您的新语言中可用。 提醒一下, pow() 签名是

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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM