首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >语言实现如何实现本机扩展类实例化?

语言实现如何实现本机扩展类实例化?
EN

Software Engineering用户
提问于 2020-04-11 17:42:36
回答 2查看 107关注 0票数 3

我正在用C编写语言解释器,我目前正在实现一个系统,允许用C语言为解释器编写扩展模块。

这些模块像普通模块一样加载到代码文件中,但在幕后它们是用C编写的动态加载库。这是一种类似于Python解释器中的方法。

在C代码中(无论是在主解释器中还是在扩展模块中),当前实例化类的方法如下:

代码语言:javascript
复制
ObjectInstance* instance = vm_instantiate_class(class_object, arguments);

vm_instantiate_class负责分配新实例,如果存在则调用其类的初始化器方法,以及一些更多的簿记。

代码语言:javascript
复制
ObjectInstance* vm_instantiate_class(ObjectClass* klass, ValueArray args) {
    // Allocate instance
    ObjectInstance* instance = object_instance_new(klass);

    // This goes to the instance's class, gets the requested attribute, and if it's a method,
    // the method is wrapped with a BoundMethod so it remembers it's associated instance when it's called
    ObjectBoundMethod* init_method = (ObjectBoundMethod*) object_load_attribute((Object*) instance, "@init");

    // Invoke the initializer on the instance
    vm_call_bound_method(init_method, args);

    instance->is_initialized = true;
    return instance;
}

这对于创建实例非常有用,无论是在主解释器循环中调用用户代码时,还是从C扩展调用它。

但是,在考虑如何实例化本机类时,我陷入了两难境地。

当前,扩展中的本机类实现如下所示。我们定义了一个“继承”ObjectInstance的结构:

代码语言:javascript
复制
typedef struct {
    ObjectInstance base;
    // ... other native fields
    int x;
    int y;
} ObjectInstanceMyClass;

如上面所示,当object_instance_newvm_instantiate_class调用时,它会检查类对象是本机类还是用户类。如果是本机内存,类对象将说明实际需要为实例分配多少内存(例如sizeof(ObjectInstanceMyClass))。如果是用户类,则分配sizeof(ObjectInstance)

这允许用户代码可以看到本机实例,就像任何其他实例一样--但是它实际上可以在内部携带本机数据,在通过语言公开的数据类型之外。

在我正在编写的扩展中,有一个本机类包装了本机OS资源--假设有一个文件句柄。在扩展本身中,我希望能够像实例化常规类一样优雅地实例化它:

代码语言:javascript
复制
ValueArray args = make_value_array();
value_array_write(args, <a native C file handle>);
ObjectInstanceFile* file_object = (ObjectInstanceFile*) vm_instantiate_class(file_class, args);

但是,我不能这样做,因为在我的语言中,<a native C file handle>不是合法类型的,因此不能写入ValueArray

我能想到的一个解决办法是:

代码语言:javascript
复制
// Use vm_instantiate_class to create an instance, and do actual initialization
// ad-hoc in the outside code.

ValueArray args = make_value_array(); // Empty args
ObjectInstance* instance = vm_instantiate_class(file_class, args);
ObjectInstanceFile* file_object = (ObjectInstanceFile*) instance;
file_object->handle = <a native C file handle>; // Initialize the field

这种方法是可行的,但它并不优雅。

我希望能够在包装本机资源的类上调用vm_instantiate_class (在语言级别上没有等效资源),并且使它能够工作,而不必在调用之后对实例进行进一步修补。

这种事情是如何在语言实现中普遍实现的呢?具体来说,我想了解CPython实现,但否则任何语言实现示例都可以。

EN

回答 2

Software Engineering用户

发布于 2020-04-17 21:41:44

我不确定CPython,但是Lua解释器(和亲属)所做的解决方案是有一个与void * +方法相对应的对象类型(Lua调用这个用户数据)。Lua没有构造函数,所以它们所需要的只是一个有效返回包装器的make_userdata(void *, methods)函数。通过在argsvm_instantiate_class中传递这样的用户数据(它甚至不需要支持方法,它实际上只是指针的包装器),这可以很容易地适应您的情况。

另一方面,您有构造函数(@init)。为什么不在构造函数中打开句柄呢?然后,它可以设置自己的方式,它想要。所有东西都被很好地封装,而且,作为一个额外的好处,对象实际上是可以从用户代码中实例化的,这在当前系统中似乎不是这样的。

票数 1
EN

Software Engineering用户

发布于 2020-04-18 06:53:56

滑翔GObject的源代码中寻找灵感(来自GTK)。阅读有关ObjVLisp模型的论文。

RefPerSys中,我们面临着同样的问题,这也与垃圾收集垃圾收集密切相关。

假设您的目标平台具有相同大小的所有指针(指向数据的指针和指向函数的指针),具有单一的平面虚拟地址空间冯·诺依曼 (而不是哈佛大学)体系结构。在2020年,大多数操作系统和处理器(但不是全部)都是如此: Linux/x86-64、Windows/x86-64、Android/ARM等等.

然后,您可以将任何指针(不安全地)从void*或向转换。因此,您的file_object->handle将是(例如)一个适当地从/到一个void*转换的FILE*。你会得到有标记的工会

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/408676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档