Я разрабатываю язык сценариев, который компилируется для собственной виртуальной машины, простой, который содержит инструкции для работы с такими данными, как points , vector , float и т. д. Ячейка памяти представлена следующим образом:
struct memory_cell
{
u32 id;
u8 type;
union
{
u8 b; /* boolean */
double f; /* float */
struct { double x, y, z; } v; /* vector */
struct { double r, g, b; } c; /* color */
struct { double r, g, b; } cw; /* color weight */
struct { double x, y, z; } p; /* point variable */
struct { u16 length; memory_cell **cells; } l; /* list variable */
};
};
Инструкции являются общими и могут работать со многими различными операндами. Например
ADD dest, src1, src2
может работать с поплавками, векторами, точками, цветами, устанавливая правильный тип назначения в соответствии с операндами.
Основной цикл выполнения просто проверяет код операции инструкции (которая представляет собой структуру, содержащую объединения для определения любого вида инструкции) и выполняет ее. Я использовал упрощенный подход, при котором у меня нет регистров, а просто большой массив ячеек памяти.
Мне было интересно, может ли JIT помочь мне в достижении лучших результатов или нет, и как этого добиться.
Как я уже сказал, лучшая реализация, достигнутая на данный момент, выглядит примерно так:
void VirtualMachine::executeInstruction(instr i)
{
u8 opcode = (i.opcode[0] & (u8)0xFC) >> 2;
if (opcode >= 1 && opcode <= 17) /* RTL instruction */
{
memory_cell *dest;
memory_cell *src1;
memory_cell *src2;
/* fetching destination */
switch (i.opcode[0] & 0x03)
{
/* skip fetching for optimization */
case 0: { break; }
case MEM_CELL: { dest = memory[stack_pointer+i.rtl.dest.cell]; break; }
case ARRAY_VAL: { dest = memory[stack_pointer+i.rtl.dest.cell]->l.cells[i.rtl.dest.index]; break; }
case ARRAY_CELL: { dest = memory[stack_pointer+i.rtl.dest.cell]->l.cells[(int)i.rtl.dest.value]; break; }
}
/* omitted code */
switch (opcode)
{
case ADD:
{
if (src1->type == M_VECTOR && src2->type == M_VECTOR)
{
dest->type = M_VECTOR;
dest->v.x = src1->v.x + src2->v.x;
dest->v.y = src1->v.y + src2->v.y;
dest->v.z = src1->v.z + src2->v.z;
}
/* omitted code */
Легко / удобно попробовать jit-компиляцию? Но я действительно не знаю, с чего начать, поэтому спрашиваю несколько советов.
Кроме того, есть ли другие советы, которые я должен учитывать при разработке?
Эта виртуальная машина должна быть достаточно быстрой, чтобы вычислять шейдеры для трассировщика лучей, но я, по-видимому, не проводил никаких тестов.