跳转到内容

鹦鹉虚拟机/PMC 系统

来自维基教科书,开放世界中的开放书籍

我们已经讨论过 PMCs——在鹦鹉虚拟机/多态容器 (PMCs)章节中——包括如何使用 PMC 编译器定义新的 PMC 类型,以及如何在 PIR 程序中使用它们。本章将更详细地介绍 PMCs 在 Parrot 中的实际使用方式,包括 PMCs 的内存管理、变形 PMCs 以及与 PMCs 的交互。

PMC 系统概述

[编辑 | 编辑源代码]

PMC 数据结构看似简单,并且被设计成足够可扩展,以供通用数据和功能使用。以下是 PMC 结构和相关的 PMC_EXT 结构的定义

struct PMC {
    Parrot_UInt     flags;
    VTABLE         *vtable;
    DPOINTER       *data;
    struct PMC_EXT *pmc_ext;
};

typedef struct PMC_EXT {
    DPOINTER *data;
    PMC *_metadata;
    struct _Sync *_synchronize;
    PMC *_next_for_GC;
} PMC_EXT;

从这些定义中我们可以看到,PMC 实际上非常小。关于 PMC 的大部分信息,包括它所有不同的方法和 VTABLE 接口都存储在 ->vtable 指针中。VTABLE 结构是一个非常大的结构,包含所有不同 VTABLE 接口的函数指针。

PMC 数据

[编辑 | 编辑源代码]

每个 PMC 类型还包含一个指向特定于该 PMC 的数据结构的指针。这些数据结构是根据 PMC 的继承层次结构及其定义的所有属性来定义的。例如,这个 PMC 定义

pmclass MyPmc {
    ATTR INTVAL a;
    ATTR FLOATVAL b;
    ATTR STRING *c;
    ATTR PMC *d;

    ...
}

将转换为这个 C 数据结构定义

typedef struct Parrot_MyPmc_attributes {
    INTVAL a;
    FLOATVAL b;
    STRING *c;
    PMC *d;
} Parrot_MyPmc_attributes;

这个结构应该包含在 ->data 指针中,应该始终使用 PMC_data 宏访问它。这样,如果 PMC 结构定义最终发生了变化,所有正确使用宏的代码都将自动更新,因为宏也会更新。以下是一个使用这些属性的初始化 VTABLE 的示例

VTABLE void init () {
    Parrot_MyPmc_attributes *p = mem_allocate_typed(Parrot_MyPmc_attributes);
    p->a = 0;
    p->b = 0.0
    p->c = NULL;
    p->d = PMCNULL;
    PMC_data(SELF) = p;
}

还有一个宏使用单词 PARROT 和 PMC 的全大写字母名称来检索数据结构,并正确地进行类型转换(因此你的编译器不会对使用未类型转换的指针发出警告)

Parrot_MyPmc_attributes *attr = PARROT_MYPMC(SELF);



C 不是一种基于类的(或“面向对象”的)语言,但 OO 编程方法的许多教训已被改编用于 Parrot 的代码库。PMCs、STRINGs 和一些其他数据类型是基于“PObj”的定义,也称为“Buffer”

typedef struct Buffer {
    Parrot_UInt flags;
} Buffer;

请注意,Buffer 中的前两个条目与 PMC 中的是一样的?所有以这两个数据项开始的对象都被称为“PObject 同构”。简而言之,我们说所有 pobject 同构都只是“PObjects”,并且有许多类型的 PObjects。例如,内存管理系统可以测试所有 pobjects 的标志以确定内存对象是什么类型的 PObject。

PMC 可以选择包含一个 PMC_EXT 结构,它添加了额外的功能。PMC_EXT 允许一个 PMC 在多个线程之间或多个 Parrot 解释器之间共享,而不会引入数据竞争。PMC_EXT 还允许一个 PMC 包含一个元数据哈希(属性值对),这些元数据通常作为属性添加到 PIR 中。

PObject 标志

[编辑 | 编辑源代码]

PMC 管理

[编辑 | 编辑源代码]

PMCs 从两个特殊的池中分配,一个 PMC 池和一个常量 PMC 池。常量 PMCs 被认为是不可变且永久存在的,因此它们从不被修改,也不被垃圾收集器收集。STRINGS 在字符串池或常量字符串池中分配。相同的关系适用,常量字符串从不被修改,也不被收集。PMC_EXT 结构目前不受内存管理子系统的管理。但是,由于 PMC_EXT 与 PMCs 之间是一对一的关系,我们总是知道当它的 PMC 被释放时可以释放它。

就垃圾收集而言,PMCs 是 Parrot 中唯一的一种聚合数据类型。STRINGS 不包含指向垃圾收集器感兴趣的其他数据项的指针。堆栈块,在某些结构中内部使用,是 PObjs 也是聚合,但由收集器单独标记,并且不直接作为聚合处理。

VTables 代表对所有类型 PMCs 的标准接口。对于每个 PMC,有一系列可以执行(或尝试)的标准操作。并非所有 PMCs 都支持所有 Vtable 操作

VTable 类型

[编辑 | 编辑源代码]

VTables 是复杂的数据项,除了包含大量的函数指针之外,还包含一些数据项来支持 PMCs。其中一个数据项是一个类 PMC,一个代表特定 PMC 类的 PMC。另一个数据项是一个枚举,它区分所有 PMC 类。


上一个 鹦鹉虚拟机 下一个
运行核心 内存和垃圾收集
华夏公益教科书