编译堆栈机的局部变量

大卫·K

我正在构建一个玩具编译器,从类似C的语言到堆栈机,而我正要弄清楚该如何处理函数并阻止局部变量。抽象地思考它,看来我在频谱的相反两端有两个选择:1)为每个变量预处理和预分配堆栈空间,2)向VM添加特殊指令以遍历堆栈。

预处理和预分配每个变量的堆栈空间

这样做的好处是可以提前为我提供变量的所有地址,因此我不必非常聪明,也不必向VM添加任何额外的指令即可遍历堆栈。缺点是,这可能非常浪费,因为从不执行但声明一堆变量的条件代码将占用大量不必要的空间。例如,

a : t1 = value;
if (test) {
  b : t2; c : t3; d : t4; ...;
}

在上面的代码中,即使test始终为false,我仍将为条件分支中的所有那些变量分配空间。

向VM添加特殊说明以遍历堆栈

我可以想到的另一种方法是为每个变量声明生成代码,然后添加一些特殊的VM指令以在运行时找出这些变量的地址。这解决了浪费堆栈空间的问题,但随后增加了我可以通过某些缓存方法解决的计算开销。

那么正确的方法是什么,还有我没有想到的另一种方法更好吗?

Codenheim

堆栈机的想法是它在操作数堆栈上进行计算。这并不意味着所有内容都必须存储在堆栈中。这是一个普遍的误解。通常,您的本地变量/块作用域访问映射到注册操作。

.NET CLR和Java都具有存储和获取“本地”变量以及其他类型的变量的指令。我建议您也这样做,因为您不想为了简单的变量访问而走栈。那是非常低效的。加载/存储变量(如寄存器)应该是高效的。大多数堆栈计算机仍具有随机访问存储。

在CLR中,我们还在每个方法的开头预先分配了所有局部变量。您预分配的变量可能是显式高级变量和编译器生成的临时变量的混合。但是没有人说他们必须叠在一起。在我研究过的VM上,我们在快速访问区域(如关联数组或类似矢量的结构)中实现了它们。我建议您使用ildasm来反汇编.NET方法,并注意如何声明和处理局部变量。

例子:

 total = apples + oranges

映射到:

 ldloc 'apples'   # load a local onto stack
 ldloc 'oranges'  # load a local onto stack
 add              # add 2 operands on stack
 stloc 'total'    # store local from stack

在先前的回答中,我对基于堆栈的计算机进行了解释,并与寄存器计算机进行了比较。我希望其中包含一些有用的信息。https://stackoverflow.com/a/24301283/257090

使用简单的Dictionary或HashTable实现stfld(存储字段)和ldfld(加载字段)的原型非常简单。以后,您可以优化汇编程序或运行时,以将基于符号的基于符号的引用编译为整数引用,尤其是在不需要按名称对变量进行运行时查找的情况下。但是,对于反射API,您将需要实现其他元数据,以将数字或指针地址交叉引用回其原始名称。

PS:如果我误解了您的问题,或者您想讨论更多,请发表评论。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章