假设你有一个只有 4 个寄存器 A、B、C 和 D 的虚拟机。编译器如何用有限的空间存储如此多的变量?
是否有多种方法可以做到这一点,或者是否有一种可靠的方法可以实现这一点?这个奇特的科学术语是什么?它被认为是一个复杂的问题吗?
compiler-construction register-allocation cpu-registers vm-implementation
我已经用 Java 创建了一个原型 VM(因为它是我最熟悉的语言),并且我尝试以字节码格式存储指令。我想知道如何在字节码中存储值,因为byte只能是 0 到 255。
举个例子:
push 4752
Run Code Online (Sandbox Code Playgroud)
Push 的操作码值为 0。但是我如何存储 4752?它不适合单个字节。我可以将值存储在 4 个字节中,因此允许它们是 32 位整数,但随后我必须决定是加载操作码(1 个字节)还是一个值(4 个字节)。目前,我将程序作为整数数组传递,VM 循环遍历该数组并执行操作码。如果操作码需要一个值,它会从数组中获取该值,然后增加程序计数器以跳过该值,以便它不会被执行。
我试图弄清楚像 JVM 这样的虚拟机是如何做到这一点的,但我无法找到答案。
我正在VM中实现一个简单的JIT编译器,我正在为了好玩而写作(主要是为了更多地了解语言设计)而且我得到了一些奇怪的行为,也许有人可以告诉我为什么.
首先,我为C和C++定义了一个JIT"原型":
#ifdef __cplusplus
typedef void* (*_JIT_METHOD) (...);
#else
typedef (*_JIT_METHOD) ();
#endif
Run Code Online (Sandbox Code Playgroud)
我有一个compile()函数,可以将东西编译成ASM并将其粘贴到内存中:
void* compile (void* something)
{
// grab some memory
unsigned char* buffer = (unsigned char*) malloc (1024);
// xor eax, eax
// inc eax
// inc eax
// inc eax
// ret -> eax should be 3
/* WORKS!
buffer[0] = 0x67;
buffer[1] = 0x31;
buffer[2] = 0xC0;
buffer[3] = 0x67;
buffer[4] = 0x40;
buffer[5] = 0x67;
buffer[6] = 0x40;
buffer[7] = 0x67;
buffer[8] …Run Code Online (Sandbox Code Playgroud) 如果我有一个在我的模块中的几个地方调用的函数,虚拟机是否仅在第一次执行函数时将其编译为本机代码,而不是在其他调用中使用兑现代码?(比如.NET jit编译器)
JVM有两条指令:( bipush操作数值应介于Byte.MIN_VALUE和之间Byte.MAX_VALUE.)和sipush(操作数值应介于Short.MIN_VALUE和之间Short.MAX_VALUE).相应地,MethodVisitorASM中提供API来操作这两个指令:
public void visitIntInsn(int opcode, int operand)
Run Code Online (Sandbox Code Playgroud)
因此,如何访问ASM中的其他非字节(短)基元?例如,原语long,double,int,boolean,和float数据?这看起来很奇怪,这些数据被封装为Long,Double,Integer.
在我正在编写的虚拟机中,我希望能够以类似于以下伪代码的方式调度命令.
add: reg[memory[pc+1]] = reg[memory[pc+1]] + reg[memory[pc+2]]; pc += 2; goto done;
sub: reg[memory[pc+1]] = reg[memory[pc+1]] - reg[memory[pc+2]]; pc += 2; goto done;
cmp: /* Would take more space than simply x = x + y; */ goto done;
for(int pc = 0; memory[pc] != END; pc++) {
goto currentPositionInMemorySomehow + (memory[pc] * lengthOfInstruction);
done:
}
Run Code Online (Sandbox Code Playgroud)
其中memory是包含字节码的数组,pc是程序计数器.但要做到这一点,我们要求跳转到的每个位置在下一个块之前具有完全相同的指令数.除非有一个很棒的平台无关的汇编代码,否则不能选择下载到汇编代码,这样就可以使用相同的代码并编译到Linux,Mac和Windows.无论每个处理器都坐在上面.任何和所有的帮助将不胜感激.
最近,我研究虚拟机如何加载静态变量,但是我遇到的问题如下:
public class Example{
static{
num = 3;
System.out.print(num);
}
public static int num;
}
Run Code Online (Sandbox Code Playgroud)
编译器报告错误.我认为num有记忆区和价值.为什么我不能访问num变量?
在我理解的32位处理器中,每条指令都是32位.那么,对于汇编中的MOV指令,如何仅将32位用于操作码加参数?因此对于:
MOV register, [address]
Run Code Online (Sandbox Code Playgroud)
地址本身不占用32位吗?那么这不会占用整个指令吗?也许我错了,但我正在尝试用C/C++实现一个VM.救命?