堆栈的写时复制

Copy-on-write for stacks

如何在大数后缀计算中实现堆栈管理的写时复制技术?

我想针对以下操作优化我的系统:

duplicate top of stack
swap the two top elements
copy the second element on stack to the top
rotate the stack making the third element on top
apply n-ary operations on the stack 

一个典型的操作从栈顶获取一些参数并留下一些结果。

我的堆栈实现为一个数组,其中数据从低内存增长到高内存,指针从高内存增长到低内存。

正如我所见,问题不在于写时复制技术本身,而在于内存管理和垃圾收集。

在 Forth 中,我们不能有运算符重载,并且应该为每个 class 数字有一组明确独立的操作。那么我们有两个选择:

    1. 一组对 bigint 对象(它们的处理程序)的操作,具有手动内存管理,类似于对文件、动态内存缓冲区或其他对象的操作。
    1. 一整套操作,包括独立堆栈,如浮点数操作,具有自动内存管理。

请注意,选项 (2) 在幕后包含 (1)。

引用计数

在选项 (2) 中实现自动内存管理的一种方法是使用专用堆栈(或可能两个堆栈)和引用计数。堆栈包含对对象(缓冲区)的引用。更改数据的操作(如 b::1+)应该复制缓冲区并在计数器大于 1 时用新的引用替换引用(否则可以在该位置更改数据)。

将项目(引用)放入堆栈应增加其计数器,从堆栈中移除应减少其计数器。当计数器变为 0 时,应释放缓冲区。

b::dupb::over等操作增加计数器。 b::swap 不改变任何计数器。 b::drop 减少计数器(如果计数器为 0 则释放缓冲区)。

将一个项目从堆栈移到 bigint 变量中不应更改结果中的计数器。但是应该减少变量先前值的计数器(如果有的话)。

如果命名变量和常量不够用(例如,拥有用户定义的数组),您可能需要在 API 中引入指针(一种匿名变量)或 bigint 对象的处理程序.

不可变对象

实现选项 (2) 的另一种方法是使用不可变对象和垃圾回收循环。在这种方法中我们不需要计算引用,但需要维护外部指针(包括变量)的列表。

可以在 Peter Sovietov 的 s-expressions 实现中找到此类垃圾收集的一个简单示例:Функциональное программирование на языке Форт ("Functional programming in Forth language" in Russian, but it can be easy translated using Google Translate)。