javascript - 如何使用 1 个全局内存数组模拟 JavaScript 中带有参数和局部变量的调用堆栈?

标签 javascript arrays assembly memory callstack

我已经被这个问题困扰了好几天了。基本上我可以总结为这样一个问题:如何模拟这个函数就像它是用汇编语言编写的(甚至是机器代码,仅使用 1 个内存数组),但一切都在 JavaScript 中完成? p>

function start() {
  let x = doX(1, 2)
  let y = doX(3, 4)
  let z = doX(x, y)
  return z
}

function doX(a, b) {
  let x = a + b
  let y = a - b
  let z = x * y
  return z
}

所以我的尝试是这样的:

const memory = []

function start() {
  // capture push (function prologue)?
  memory[0] = 1
  memory[1] = 2
  doX()
  memory[2] = memory[100]
  memory[0] = 3
  memory[1] = 4
  doX()
  memory[0] = memory[2]
  memory[1] = memory[100]
  doX()
  // capture pop (function epilogue)?
  memory[100] = memory[100]
}

function doX() {
  // somehow allocate space "on the stack"
  // using only this memory object?
  // don't know how to do that....
  memory[10] = memory[0] + memory[1]
  memory[11] = memory[0] - memory[1]
  memory[12] = memory[10] * memory[11]
  // put it on the return register?
  memory[100] = memory[12]
}

如何仅使用此内存阵列正确添加推送和弹出操作并使其看起来正确?另外,我硬编码了所有内存地址,如何正确地使它们相对?

最佳答案

你需要一个堆栈指针,要么作为一个单独的全局指针(就像CPU的寄存器与内存分开),要么只是为这种特殊用途选择一个内存位置。喜欢@bergi explained为了回答您之前的问题,您需要执行诸如 memory[tos++] 之类的操作来将内容推送到堆栈上,而不是假设堆栈指针的起始值为 0 通过硬编码存储到内存[0]

(在许多 ISA 中,包括 x86,堆栈指针从区域中的最高地址开始,将内容压入堆栈会从堆栈指针中减去。因此它会向下增长)。

您已经使用内存[100]作为返回值寄存器,而不是让JavaScript返回值。 如果需要,可以使用memory[99]作为堆栈指针,因此您可能会得到类似mem[ --mem[99] ] = val_to_push。如果您使用可以调用 sp 的单独变量,或者如果您想定义具有内存的状态对象state.sp,那么它显然更具可读性。/em> 一些标量寄存器,包括 sp 堆栈指针。

<小时/>

真正的调用约定在寄存器中返回,而不是在内存中;在“内存中”使用 retval 寄存器是不必要的复杂化。如果让 JS 函数通过 JS 机制返回值,那么它仍然是类似 CPU 的,并认为它是一个寄存器。只要您将其限制为简单的数字即可。

既然你要构建机器的详细信息,你可以使用 JS 局部变量作为暂存寄存器,并允许函数拥有任意数量的变量。

因此,这台机器的编程有点像 LLVM-IR,您只需使用任意数量的“寄存器”,LLVM 就会负责实际存储它们的位置。但事实并非如此;您的代码不会“编译”以将多余的寄存器溢出到堆栈中,它确实具有您想要使用的尽可能多的寄存器。

为了将它们视为寄存器并且不让它退化为不使用内存[]的纯JS,您仍然可以要求arg传递通过内存进行(即堆栈参数调用约定),并假装函数调用破坏了所有局部变量的值。

关于javascript - 如何使用 1 个全局内存数组模拟 JavaScript 中带有参数和局部变量的调用堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59132919/

相关文章:

c++ - 了解数组和指针之间的关系

java - 拆分数组中的元素

javascript - Google map - 根据 map 当前的视点从位置数组中获取值

javascript - ES6 - 遍历 JSON

javascript - 导航滚动和点击 anchor 标签

assembly - 什么可能导致 RISC-V 上的 SIGILL(非法指令除外)?

assembly - 以二进制实现将 8 位数除以 3 (11) 的硬件

javascript - 替换后动画至高度 0

c++ - 在 C++ 中 reshape Matlab

将 C 语言转换为 MIPS 汇编语言