我应该如何使用自定义编译器管理内存?

时间:2011-10-31 16:50:02

标签: java compiler-construction

我正在为Java中的8位处理器创建一个模拟器。它的架构非常简单,只需一个4字节寄存器和256字节主存储器。我已经实现了“硬件”堆栈,因此处理器支持PUSHPOPGET。堆栈从最后一个存储器单元向后填充,因此“正常”存储器使用应该从单元0开始。您不必保留存储器,程序默认情况下可以使用完整的256字节。

我也在为这个处理器创建一个编译器,它是用我发明的一种简单语言编译的。目前,定义的每个变量(我只是支持一个8位整数类型)被分配给一个存储单元,从0开始增加。所以我最多有256个(如果堆栈是空的)变量。目前,我不想改变这一点。

我的下一个目标是添加使用无参数过程而无返回类型的功能。在自动返回之前,应释放函数中声明的变量。那么我应该在哪里存储变量?我会在开头的变量和内存末尾的“硬件”堆栈之间创建一个“软件”堆栈。我首先有想法使用硬件堆栈,但我想将它用于调用和返回方法本身。有没有比创建第二个“软件”堆栈更好的解决方案?

3 个答案:

答案 0 :(得分:2)

当您调用它时,每个函数都应在堆栈上创建激活帧/调用堆栈,其中包括返回地址的空间,任何参数以及在函数内创建的任何局部变量。至少,您的情境中的激活帧应包含调用代码的返回地址。发挥作用的额外数据取决于您的函数是否接受参数,和/或它是否创建了函数本地的任何变量。您的堆栈可能如下所示:

+------------------+
|  Return address  |
+------------------+
|   Parameter 0    |
+------------------+
|       ...        |
+------------------+
|   Parameter N    |
+------------------+
|   Local Var 0    |
+------------------+
|       ...        |
+------------------+
|   Local Var N    |   <--- Top of Stack
+------------------+

由于您已经在堆栈中使用主内存,因此激活帧也将存在。我假设您的处理器有一个指向堆栈顶部的堆栈指针?

可以创建两个堆栈但是你需要决定放置这个堆栈的位置以及应该消耗多少内存。您想将一半主内存用于硬件堆栈而另一半用于软件堆栈吗?这也意味着您要限制可以进行的嵌套调用(甚至是递归)调用的数量。相反,您可以使用另一种方法来节省内存使用量。执行此操作的方法是在调用函数后将参数包含在函数中(汇编器必须执行此操作):

+--------------+
|   JMP FUNC   | Call the function
+--------------+
|  Parameter 0 | <--- return address points here
+--------------+
|     ...      |
+--------------+
|  Parameter N |
+--------------+
| (other code) | <--- after function call, return address should be fixed to point here
+--------------+

这意味着您必须在函数内部做更多工作才能加载参数。如果你还记得,返回地址是堆栈上的第一个值。您可以加载此值,然后将该值索引以加载参数。加载参数后,您需要调整返回地址的值,使其指向在已定义的参数之后启动的代码。

答案 1 :(得分:1)

保持两个堆栈肯定会很好,但是你仍然坚持决定放置两个堆栈的位置。硬件应该从255开始,软件在127吗?这样可以将有效内存空间减少一半,并且还可以将递归深度减半,因为您最多只有127个插槽可以放入函数调用。

交错堆栈 - 硬件在255,软件在254,每个后续值跳跃2个点解决了内存范围的损失,但是当堆栈变得不平衡时,你仍然在浪费内存(10个排队的硬件)堆栈插槽,使用了20个软件插槽=浪费了10个插槽),并且还将堆栈寻址空间减少了一半

答案 2 :(得分:1)

可能有几种有效的解决方案。您可以在“硬件”堆栈中使用调用/返回数据分配变量,或者您可以为“内存”实现类似堆栈的方案,以便“内存顶部”在调用时存储并在返回时弹出。毫无疑问,有2或3个其他方案。

要考虑的是如何处理“本地”与“全球”数据。您可能需要添加新的“本地寻址”操作码或某种基址寄存器方案。

您可能想要检查旧版Burroughs machines中的完成方式。