我所说的无栈虚拟机是指在堆上维护自己的堆栈,而不是使用系统的“C堆栈”的实现。这有很多优点,比如可以实现连续性和可序列化状态,但在涉及C绑定时也有一些缺点,特别是涉及到C-VM-C回调(或VM-C-VM)的情况。
问题是这些缺点具体是什么?是否能给出一个真实问题的好例子?
问题是这些缺点具体是什么?是否能给出一个真实问题的好例子?
听起来你已经熟悉一些缺点和优点了。
其他一些优点: a) 即使底层实现没有任何支持,也可以支持适当的尾调用优化 b) 更容易构建类似于语言级别的“堆栈跟踪” c) 更容易添加适当的续体,正如你所指出的
最近我用C#写了一个简单的“Scheme”解释器,最初使用了.NET堆栈。然后我重新编写了它以使用显式堆栈——也许以下内容会对你有所帮助:
第一个版本使用了隐式的.NET运行时堆栈...
最初,它只是一个类层次结构,不同的形式(Lambda、Let等)是以下接口的实现:
// A "form" is an expression that can be evaluted with
// respect to an environment
// e.g.
// "(* x 3)"
// "x"
// "3"
public interface IForm
{
object Evaluate(IEnvironment environment);
}
IEnvironment看起来就像你期望的那样:
/// <summary>
/// Fundamental interface for resolving "symbols" subject to scoping.
/// </summary>
public interface IEnvironment
{
object Lookup(string name);
IEnvironment Extend(string name, object value);
}
为了将“内建函数”添加到我的Scheme解释器中,我最初的接口如下:
/// <summary>
/// A function is either a builtin function (i.e. implemented directly in CSharp)
/// or something that's been created by the Lambda form.
/// </summary>
public interface IFunction
{
object Invoke(object[] args);
}
/// <summary>
/// A function that wishes to use the thread state to
/// evaluate its arguments. The function should either:
/// a) Push tasks on to threadState.Pending which, when evaluated, will
/// result in the result being placed on to threadState.Results
/// b) Push its result directly on to threadState.Results
/// </summary>
public interface IStackFunction
{
void Evaluate(IThreadState threadState, object[] args);
}
现在IForm已经更新为:
public interface IForm
{
void Evaluate(IEnvironment environment, IThreadState s);
}
在这里,IThreadState的含义如下:
/// <summary>
/// The state of the interpreter.
/// The implementation of a task which takes some arguments,
/// call them "x" and "y", and which returns an argument "z",
/// should follow the following protocol:
/// a) Call "PopResult" to get x and y
/// b) Either
/// i) push "z" directly onto IThreadState using PushResult OR
/// ii) push a "task" on to the stack which will result in "z" being
/// pushed on to the result stack.
///
/// Note that ii) is "recursive" in its definition - that is, a task
/// that is pushed on to the task stack may in turn push other tasks
/// on the task stack which, when evaluated,
/// ... ultimately will end up pushing the result via PushResult.
/// </summary>
public interface IThreadState
{
void PushTask(ITask task);
object PopResult();
void PushResult(object result);
}
ITask 是什么:
public interface ITask
{
void Execute(IThreadState s);
}
ThreadState threadState = new ThreadState();
threadState.PushTask(null);
threadState.PushTask(new EvaluateForm(f, environment));
ITask next = null;
while ((next = threadState.PopTask()) != null)
next.Execute(threadState);
return threadState.PopResult(); // Get what EvaluateForm evaluated to