简体   繁体   English

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

[英]How to simulate the call stack with parameters and local variables in JavaScript with 1 global memory array?

I have been stuck on this for a few days.我已经坚持了几天。 Basically I can sum it up into asking, how do you simulate this function like it were written in assembly (or machine code even, something using only 1 memory array) , but doing everything in JavaScript?基本上我可以总结为问,你如何模拟这个函数,就像它是用汇编编写的(甚至是机器代码,只使用 1 个内存数组的东西) ,但在 JavaScript 中做所有事情?

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
}

So my attempt at it is something along these lines:所以我的尝试是这样的:

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]
}

How do I properly add the push and pop operations using only this memory array and make this look right?如何仅使用此内存阵列正确添加推送和弹出操作并使其看起来正确? Also, I hardcoded all the memory addresses, how do I properly make them relative?另外,我对所有内存地址进行了硬编码,如何正确地使它们相对?

You need a stack pointer, either as a separate global (like a CPU with registers separate from memory), or just pick a memory location for this special use.您需要一个堆栈指针,或者作为一个单独的全局变量(比如一个寄存器与内存分开的 CPU),或者只是为这个特殊用途选择一个内存位置。 Like @bergi explained in answer to your earlier question, you need to do things like memory[tos++] to push things on the stack, instead of assuming that the starting value of the stack pointer is 0 by hard-coding stores to memory[0] .@bergi解释在回答你刚才的问题,你需要做这样的事情memory[tos++]推栈上的东西,而不是假设堆栈指针的初始值是0通过硬编码卖场memory[0]

(In many ISAs, including x86, the stack pointer starts at the highest address in a region, and pushing stuff on the stack subtracts from the stack pointer. So it grows down). (在包括 x86 在内的许多 ISA 中,堆栈指针从区域中的最高地址开始,将堆栈上的内容压入堆栈会从堆栈指针中减去。因此它会向下增长)。

You're already using memory[100] as a return-value register instead of letting JavaScript return a value.您已经在使用memory[100]作为返回值寄存器,而不是让 JavaScript 返回值。 Use memory[99] as a stack pointer if you want, so you might have something like mem[ --mem[99] ] = val_to_push .如果需要,可以使用memory[99]作为堆栈指针,因此您可能有类似mem[ --mem[99] ] = val_to_push It's obviously much more readable if you use a separate variable that you can call sp , or state.sp if you want to define a state object with memory and some scalar registers including a sp stack pointer.如果你使用一个单独的变量,你可以调用sp ,或者state.sp如果你想定义一个带有内存一些标量寄存器(包括sp堆栈指针)的状态对象,它显然更具可读性。


Real calling conventions return in registers, not memory;真正的调用约定在寄存器中返回,而不是在内存中; using a retval register "in memory" is an unnecessary complication.在“内存中”使用 retval 寄存器是不必要的复杂化。 It's still CPU-like if you let JS functions return values via the JS mechanism, and consider that a register.如果让 JS 函数通过 JS 机制返回值,并将其视为寄存器,它仍然是 CPU 类的。 As long as you limit it to simple numbers.只要您将其限制为简单数字即可。

Since you get to make up the details of your machine, you could use JS local variables as scratch registers, and allow functions to have as many as they want.由于您可以编写机器的详细信息,您可以使用 JS 局部变量作为临时寄存器,并允许函数拥有任意数量的函数。

So programming for this machine is somewhat like LLVM-IR where you just use as many "registers" as you want and LLVM takes care of where to actually store them.因此,为这台机器编程有点像 LLVM-IR,您只需使用任意数量的“寄存器”,而 LLVM 负责实际存储它们的位置。 But not really;但并非如此; your code wouldn't "compile" to spill excess registers to the stack, it really does have as many registers as you care to use.您的代码不会“编译”以将多余的寄存器溢出到堆栈中,它确实具有您想使用的尽可能多的寄存器。

To treat them as registers and not let it degenerate into pure JS that doesn't use memory[] , you could still require arg passing to happen via memory (ie a stack-args calling convention), and pretend that a function call destroyed the values of all local variables.要将它们视为寄存器而不是让它退化为不使用memory[]纯 JS,您仍然可以要求通过内存进行 arg传递(即堆栈参数调用约定),并假装函数调用破坏了所有局部变量的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM