1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Introduce version_t struct. Will be needed for code invalidation.

This commit is contained in:
Maxime Chevalier-Boisvert 2021-01-12 14:56:43 -05:00 committed by Alan Wu
parent a251059070
commit 3a74011ff8
7 changed files with 187 additions and 172 deletions

View file

@ -14,7 +14,7 @@
#include "ujit_asm.h"
// Compute the number of bits needed to encode a signed value
size_t sig_imm_size(int64_t imm)
uint32_t sig_imm_size(int64_t imm)
{
// Compute the smallest size this immediate fits in
if (imm >= -128 && imm <= 127)
@ -28,7 +28,7 @@ size_t sig_imm_size(int64_t imm)
}
// Compute the number of bits needed to encode an unsigned value
size_t unsig_imm_size(uint64_t imm)
uint32_t unsig_imm_size(uint64_t imm)
{
// Compute the smallest size this immediate fits in
if (imm <= 255)
@ -41,7 +41,7 @@ size_t unsig_imm_size(uint64_t imm)
return 64;
}
x86opnd_t mem_opnd(size_t num_bits, x86opnd_t base_reg, int32_t disp)
x86opnd_t mem_opnd(uint32_t num_bits, x86opnd_t base_reg, int32_t disp)
{
bool is_iprel = base_reg.as.reg.reg_type == REG_IP;
@ -54,7 +54,7 @@ x86opnd_t mem_opnd(size_t num_bits, x86opnd_t base_reg, int32_t disp)
return opnd;
}
x86opnd_t resize_opnd(x86opnd_t opnd, size_t num_bits)
x86opnd_t resize_opnd(x86opnd_t opnd, uint32_t num_bits)
{
assert (num_bits % 8 == 0);
x86opnd_t sub = opnd;
@ -85,7 +85,7 @@ x86opnd_t const_ptr_opnd(const void *ptr)
}
// Allocate a block of executable memory
uint8_t* alloc_exec_mem(size_t mem_size)
uint8_t* alloc_exec_mem(uint32_t mem_size)
{
#ifndef _WIN32
// Map the memory as executable
@ -112,7 +112,7 @@ uint8_t* alloc_exec_mem(size_t mem_size)
}
// Initialize a code block object
void cb_init(codeblock_t* cb, uint8_t* mem_block, size_t mem_size)
void cb_init(codeblock_t* cb, uint8_t* mem_block, uint32_t mem_size)
{
cb->mem_block = mem_block;
cb->mem_size = mem_size;
@ -122,30 +122,30 @@ void cb_init(codeblock_t* cb, uint8_t* mem_block, size_t mem_size)
}
// Align the current write position to a multiple of bytes
void cb_align_pos(codeblock_t* cb, size_t multiple)
void cb_align_pos(codeblock_t* cb, uint32_t multiple)
{
// Compute the pointer modulo the given alignment boundary
uint8_t* ptr = &cb->mem_block[cb->write_pos];
size_t rem = ((size_t)ptr) % multiple;
uint32_t rem = ((uint32_t)ptr) % multiple;
// If the pointer is already aligned, stop
if (rem != 0)
return;
// Pad the pointer by the necessary amount to align it
size_t pad = multiple - rem;
uint32_t pad = multiple - rem;
cb->write_pos += pad;
}
// Set the current write position
void cb_set_pos(codeblock_t* cb, size_t pos)
void cb_set_pos(codeblock_t* cb, uint32_t pos)
{
assert (pos < cb->mem_size);
cb->write_pos = pos;
}
// Get a direct pointer into the executable memory block
uint8_t* cb_get_ptr(codeblock_t* cb, size_t index)
uint8_t* cb_get_ptr(codeblock_t* cb, uint32_t index)
{
assert (index < cb->mem_size);
return &cb->mem_block[index];
@ -160,12 +160,12 @@ void cb_write_byte(codeblock_t* cb, uint8_t byte)
}
// Write multiple bytes starting from the current position
void cb_write_bytes(codeblock_t* cb, size_t num_bytes, ...)
void cb_write_bytes(codeblock_t* cb, uint32_t num_bytes, ...)
{
va_list va;
va_start(va, num_bytes);
for (size_t i = 0; i < num_bytes; ++i)
for (uint32_t i = 0; i < num_bytes; ++i)
{
uint8_t byte = va_arg(va, int);
cb_write_byte(cb, byte);
@ -175,7 +175,7 @@ void cb_write_bytes(codeblock_t* cb, size_t num_bytes, ...)
}
// Write a signed integer over a given number of bits at the current position
void cb_write_int(codeblock_t* cb, uint64_t val, size_t num_bits)
void cb_write_int(codeblock_t* cb, uint64_t val, uint32_t num_bits)
{
assert (num_bits > 0);
assert (num_bits % 8 == 0);
@ -210,10 +210,10 @@ void cb_write_int(codeblock_t* cb, uint64_t val, size_t num_bits)
default:
{
// Compute the size in bytes
size_t num_bytes = num_bits / 8;
uint32_t num_bytes = num_bits / 8;
// Write out the bytes
for (size_t i = 0; i < num_bytes; ++i)
for (uint32_t i = 0; i < num_bytes; ++i)
{
uint8_t byte_val = (uint8_t)(val & 0xFF);
cb_write_byte(cb, byte_val);
@ -224,7 +224,7 @@ void cb_write_int(codeblock_t* cb, uint64_t val, size_t num_bits)
}
// Allocate a new label with a given name
size_t cb_new_label(codeblock_t* cb, const char* name)
uint32_t cb_new_label(codeblock_t* cb, const char* name)
{
//if (hasASM)
// writeString(to!string(label) ~ ":");
@ -232,7 +232,7 @@ size_t cb_new_label(codeblock_t* cb, const char* name)
assert (cb->num_labels < MAX_LABELS);
// Allocate the new label
size_t label_idx = cb->num_labels++;
uint32_t label_idx = cb->num_labels++;
// This label doesn't have an address yet
cb->label_addrs[label_idx] = 0;
@ -242,14 +242,14 @@ size_t cb_new_label(codeblock_t* cb, const char* name)
}
// Write a label at the current address
void cb_write_label(codeblock_t* cb, size_t label_idx)
void cb_write_label(codeblock_t* cb, uint32_t label_idx)
{
assert (label_idx < MAX_LABELS);
cb->label_addrs[label_idx] = cb->write_pos;
}
// Add a label reference at the current write position
void cb_label_ref(codeblock_t* cb, size_t label_idx)
void cb_label_ref(codeblock_t* cb, uint32_t label_idx)
{
assert (label_idx < MAX_LABELS);
assert (cb->num_refs < MAX_LABEL_REFS);
@ -262,17 +262,17 @@ void cb_label_ref(codeblock_t* cb, size_t label_idx)
// Link internal label references
void cb_link_labels(codeblock_t* cb)
{
size_t orig_pos = cb->write_pos;
uint32_t orig_pos = cb->write_pos;
// For each label reference
for (size_t i = 0; i < cb->num_refs; ++i)
for (uint32_t i = 0; i < cb->num_refs; ++i)
{
size_t ref_pos = cb->label_refs[i].pos;
size_t label_idx = cb->label_refs[i].label_idx;
uint32_t ref_pos = cb->label_refs[i].pos;
uint32_t label_idx = cb->label_refs[i].label_idx;
assert (ref_pos < cb->mem_size);
assert (label_idx < MAX_LABELS);
size_t label_addr = cb->label_addrs[label_idx];
uint32_t label_addr = cb->label_addrs[label_idx];
assert (label_addr < cb->mem_size);
// Compute the offset from the reference's end to the label
@ -327,7 +327,7 @@ bool sib_needed(x86opnd_t opnd)
}
// Compute the size of the displacement field needed for a memory operand
size_t disp_size(x86opnd_t opnd)
uint32_t disp_size(x86opnd_t opnd)
{
assert (opnd.type == OPND_MEM);
@ -340,7 +340,7 @@ size_t disp_size(x86opnd_t opnd)
// Compute the required displacement size
if (opnd.as.mem.disp != 0)
{
size_t num_bits = sig_imm_size(opnd.as.mem.disp);
uint32_t num_bits = sig_imm_size(opnd.as.mem.disp);
assert (num_bits <= 32 && "displacement does not fit in 32 bits");
// x86 can only encode 8-bit and 32-bit displacements
@ -400,7 +400,7 @@ void cb_write_rm(
x86opnd_t r_opnd,
x86opnd_t rm_opnd,
uint8_t opExt,
size_t op_len,
uint32_t op_len,
...)
{
assert (op_len > 0 && op_len <= 3);
@ -455,7 +455,7 @@ void cb_write_rm(
// Write the opcode bytes to the code block
va_list va;
va_start(va, op_len);
for (size_t i = 0; i < op_len; ++i)
for (uint32_t i = 0; i < op_len; ++i)
{
uint8_t byte = va_arg(va, int);
cb_write_byte(cb, byte);
@ -479,7 +479,7 @@ void cb_write_rm(
}
else
{
size_t dsize = disp_size(rm_opnd);
uint32_t dsize = disp_size(rm_opnd);
if (dsize == 0 || rm_opnd.as.mem.is_iprel)
mod = 0;
else if (dsize == 8)
@ -547,7 +547,7 @@ void cb_write_rm(
// Add the displacement
if (rm_opnd.type == OPND_MEM)
{
size_t dsize = disp_size(rm_opnd);
uint32_t dsize = disp_size(rm_opnd);
if (dsize > 0)
cb_write_int(cb, rm_opnd.as.mem.disp, dsize);
}
@ -566,7 +566,7 @@ void write_rm_unary(
//cb.writeASM(mnem, opnd);
// Check the size of opnd0
size_t opndSize;
uint32_t opndSize;
if (opnd.type == OPND_REG || opnd.type == OPND_MEM)
opndSize = opnd.num_bits;
else
@ -608,7 +608,7 @@ void cb_write_rm_multi(
*/
// Check the size of opnd0
size_t opndSize = opnd0.num_bits;
uint32_t opndSize = opnd0.num_bits;
// Check the size of opnd1
if (opnd1.type == OPND_REG || opnd1.type == OPND_MEM)
@ -696,7 +696,7 @@ void cb_write_shift(
//cb.writeASM(mnem, opnd0, opnd1);
// Check the size of opnd0
size_t opndSize;
uint32_t opndSize;
if (opnd0.type == OPND_REG || opnd0.type == OPND_MEM)
opndSize = opnd0.num_bits;
else
@ -733,7 +733,7 @@ void cb_write_shift(
// Encode a relative jump to a label (direct or conditional)
// Note: this always encodes a 32-bit offset
void cb_write_jcc(codeblock_t* cb, const char* mnem, uint8_t op0, uint8_t op1, size_t label_idx)
void cb_write_jcc(codeblock_t* cb, const char* mnem, uint8_t op0, uint8_t op1, uint32_t label_idx)
{
//cb.writeASM(mnem, label);
@ -857,7 +857,7 @@ void call_ptr(codeblock_t* cb, x86opnd_t scratch_reg, uint8_t* dst_ptr)
}
/// call - Call to label with 32-bit offset
void call_label(codeblock_t* cb, size_t label_idx)
void call_label(codeblock_t* cb, uint32_t label_idx)
{
//cb.writeASM("call", label);
@ -1049,37 +1049,37 @@ void imul(CodeBlock cb, X86Opnd opnd0, X86Opnd opnd1, X86Opnd opnd2)
*/
/// jcc - relative jumps to a label
void ja (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "ja" , 0x0F, 0x87, label_idx); }
void jae (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jae" , 0x0F, 0x83, label_idx); }
void jb (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jb" , 0x0F, 0x82, label_idx); }
void jbe (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jbe" , 0x0F, 0x86, label_idx); }
void jc (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jc" , 0x0F, 0x82, label_idx); }
void je (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "je" , 0x0F, 0x84, label_idx); }
void jg (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jg" , 0x0F, 0x8F, label_idx); }
void jge (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jge" , 0x0F, 0x8D, label_idx); }
void jl (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jl" , 0x0F, 0x8C, label_idx); }
void jle (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jle" , 0x0F, 0x8E, label_idx); }
void jna (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jna" , 0x0F, 0x86, label_idx); }
void jnae(codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnae", 0x0F, 0x82, label_idx); }
void jnb (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnb" , 0x0F, 0x83, label_idx); }
void jnbe(codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnbe", 0x0F, 0x87, label_idx); }
void jnc (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnc" , 0x0F, 0x83, label_idx); }
void jne (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jne" , 0x0F, 0x85, label_idx); }
void jng (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jng" , 0x0F, 0x8E, label_idx); }
void jnge(codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnge", 0x0F, 0x8C, label_idx); }
void jnl (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnl" , 0x0F, 0x8D, label_idx); }
void jnle(codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnle", 0x0F, 0x8F, label_idx); }
void jno (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jno" , 0x0F, 0x81, label_idx); }
void jnp (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnp" , 0x0F, 0x8b, label_idx); }
void jns (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jns" , 0x0F, 0x89, label_idx); }
void jnz (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jnz" , 0x0F, 0x85, label_idx); }
void jo (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jo" , 0x0F, 0x80, label_idx); }
void jp (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jp" , 0x0F, 0x8A, label_idx); }
void jpe (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jpe" , 0x0F, 0x8A, label_idx); }
void jpo (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jpo" , 0x0F, 0x8B, label_idx); }
void js (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "js" , 0x0F, 0x88, label_idx); }
void jz (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jz" , 0x0F, 0x84, label_idx); }
void jmp (codeblock_t* cb, size_t label_idx) { cb_write_jcc(cb, "jmp" , 0xFF, 0xE9, label_idx); }
void ja (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "ja" , 0x0F, 0x87, label_idx); }
void jae (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jae" , 0x0F, 0x83, label_idx); }
void jb (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jb" , 0x0F, 0x82, label_idx); }
void jbe (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jbe" , 0x0F, 0x86, label_idx); }
void jc (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jc" , 0x0F, 0x82, label_idx); }
void je (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "je" , 0x0F, 0x84, label_idx); }
void jg (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jg" , 0x0F, 0x8F, label_idx); }
void jge (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jge" , 0x0F, 0x8D, label_idx); }
void jl (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jl" , 0x0F, 0x8C, label_idx); }
void jle (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jle" , 0x0F, 0x8E, label_idx); }
void jna (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jna" , 0x0F, 0x86, label_idx); }
void jnae(codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnae", 0x0F, 0x82, label_idx); }
void jnb (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnb" , 0x0F, 0x83, label_idx); }
void jnbe(codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnbe", 0x0F, 0x87, label_idx); }
void jnc (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnc" , 0x0F, 0x83, label_idx); }
void jne (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jne" , 0x0F, 0x85, label_idx); }
void jng (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jng" , 0x0F, 0x8E, label_idx); }
void jnge(codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnge", 0x0F, 0x8C, label_idx); }
void jnl (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnl" , 0x0F, 0x8D, label_idx); }
void jnle(codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnle", 0x0F, 0x8F, label_idx); }
void jno (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jno" , 0x0F, 0x81, label_idx); }
void jnp (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnp" , 0x0F, 0x8b, label_idx); }
void jns (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jns" , 0x0F, 0x89, label_idx); }
void jnz (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jnz" , 0x0F, 0x85, label_idx); }
void jo (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jo" , 0x0F, 0x80, label_idx); }
void jp (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jp" , 0x0F, 0x8A, label_idx); }
void jpe (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jpe" , 0x0F, 0x8A, label_idx); }
void jpo (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jpo" , 0x0F, 0x8B, label_idx); }
void js (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "js" , 0x0F, 0x88, label_idx); }
void jz (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jz" , 0x0F, 0x84, label_idx); }
void jmp (codeblock_t* cb, uint32_t label_idx) { cb_write_jcc(cb, "jmp" , 0xFF, 0xE9, label_idx); }
/// jcc - relative jumps to a pointer (32-bit offset)
void ja_ptr (codeblock_t* cb, uint8_t* ptr) { cb_write_jcc_ptr(cb, "ja" , 0x0F, 0x87, ptr); }
@ -1233,13 +1233,13 @@ void movzx(codeblock_t* cb, x86opnd_t dst, x86opnd_t src)
{
cb.writeASM("movzx", dst, src);
size_t dstSize;
uint32_t dstSize;
if (dst.isReg)
dstSize = dst.reg.size;
else
assert (false, "movzx dst must be a register");
size_t srcSize;
uint32_t srcSize;
if (src.isReg)
srcSize = src.reg.size;
else if (src.isMem)
@ -1281,7 +1281,7 @@ void neg(codeblock_t* cb, x86opnd_t opnd)
}
// nop - Noop, one or multiple bytes long
void nop(codeblock_t* cb, size_t length)
void nop(codeblock_t* cb, uint32_t length)
{
switch (length)
{
@ -1335,7 +1335,7 @@ void nop(codeblock_t* cb, size_t length)
default:
{
size_t written = 0;
uint32_t written = 0;
while (written + 9 <= length)
{
nop(cb, 9);

View file

@ -15,10 +15,10 @@
typedef struct LabelRef
{
// Position in the code block where the label reference exists
size_t pos;
uint32_t pos;
// Label which this refers to
size_t label_idx;
uint32_t label_idx;
} labelref_t;
@ -29,13 +29,13 @@ typedef struct CodeBlock
uint8_t* mem_block;
// Memory block size
size_t mem_size;
uint32_t mem_size;
/// Current writing position
size_t write_pos;
uint32_t write_pos;
// Table of registered label addresses
size_t label_addrs[MAX_LABELS];
uint32_t label_addrs[MAX_LABELS];
// Table of registered label names
// Note that these should be constant strings only
@ -45,10 +45,10 @@ typedef struct CodeBlock
labelref_t label_refs[MAX_LABEL_REFS];
// Number of labels registeered
size_t num_labels;
uint32_t num_labels;
// Number of references to labels
size_t num_refs;
uint32_t num_refs;
// TODO: system for disassembly/comment strings, indexed by position
@ -214,7 +214,7 @@ static const x86opnd_t R15B = { OPND_REG, 8, .as.reg = { REG_GP, 15 }};
#define C_ARG_REGS ( (x86opnd_t[]){ RDI, RSI, RDX, RCX, R8, R9 } )
// Memory operand with base register and displacement/offset
x86opnd_t mem_opnd(size_t num_bits, x86opnd_t base_reg, int32_t disp);
x86opnd_t mem_opnd(uint32_t num_bits, x86opnd_t base_reg, int32_t disp);
// Immediate number operand
x86opnd_t imm_opnd(int64_t val);
@ -238,24 +238,24 @@ x86opnd_t const_ptr_opnd(const void *ptr);
)
// Code block methods
uint8_t* alloc_exec_mem(size_t mem_size);
void cb_init(codeblock_t* cb, uint8_t* mem_block, size_t mem_size);
void cb_align_pos(codeblock_t* cb, size_t multiple);
void cb_set_pos(codeblock_t* cb, size_t pos);
uint8_t* cb_get_ptr(codeblock_t* cb, size_t index);
uint8_t* alloc_exec_mem(uint32_t mem_size);
void cb_init(codeblock_t* cb, uint8_t* mem_block, uint32_t mem_size);
void cb_align_pos(codeblock_t* cb, uint32_t multiple);
void cb_set_pos(codeblock_t* cb, uint32_t pos);
uint8_t* cb_get_ptr(codeblock_t* cb, uint32_t index);
void cb_write_byte(codeblock_t* cb, uint8_t byte);
void cb_write_bytes(codeblock_t* cb, size_t num_bytes, ...);
void cb_write_int(codeblock_t* cb, uint64_t val, size_t num_bits);
size_t cb_new_label(codeblock_t* cb, const char* name);
void cb_write_label(codeblock_t* cb, size_t label_idx);
void cb_label_ref(codeblock_t* cb, size_t label_idx);
void cb_write_bytes(codeblock_t* cb, uint32_t num_bytes, ...);
void cb_write_int(codeblock_t* cb, uint64_t val, uint32_t num_bits);
uint32_t cb_new_label(codeblock_t* cb, const char* name);
void cb_write_label(codeblock_t* cb, uint32_t label_idx);
void cb_label_ref(codeblock_t* cb, uint32_t label_idx);
void cb_link_labels(codeblock_t* cb);
// Encode individual instructions into a code block
void add(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
void and(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
void call_ptr(codeblock_t* cb, x86opnd_t scratch_reg, uint8_t* dst_ptr);
void call_label(codeblock_t* cb, size_t label_idx);
void call_label(codeblock_t* cb, uint32_t label_idx);
void call(codeblock_t* cb, x86opnd_t opnd);
void cmova(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
void cmovae(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
@ -291,36 +291,36 @@ void cmp(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
void cdq(codeblock_t* cb);
void cqo(codeblock_t* cb);
void int3(codeblock_t* cb);
void ja(codeblock_t* cb, size_t label_idx);
void jae(codeblock_t* cb, size_t label_idx);
void jb(codeblock_t* cb, size_t label_idx);
void jbe(codeblock_t* cb, size_t label_idx);
void jc(codeblock_t* cb, size_t label_idx);
void je(codeblock_t* cb, size_t label_idx);
void jg(codeblock_t* cb, size_t label_idx);
void jge(codeblock_t* cb, size_t label_idx);
void jl(codeblock_t* cb, size_t label_idx);
void jle(codeblock_t* cb, size_t label_idx);
void jna(codeblock_t* cb, size_t label_idx);
void jnae(codeblock_t* cb, size_t label_idx);
void jnb(codeblock_t* cb, size_t label_idx);
void jnbe(codeblock_t* cb, size_t label_idx);
void jnc(codeblock_t* cb, size_t label_idx);
void jne(codeblock_t* cb, size_t label_idx);
void jng(codeblock_t* cb, size_t label_idx);
void jnge(codeblock_t* cb, size_t label_idx);
// void jnl(codeblock_t* cb, size_t label_idx); // this conflicts with jnl(3)
void jnle(codeblock_t* cb, size_t label_idx);
void jno(codeblock_t* cb, size_t label_idx);
void jnp(codeblock_t* cb, size_t label_idx);
void jns(codeblock_t* cb, size_t label_idx);
void jnz(codeblock_t* cb, size_t label_idx);
void jo(codeblock_t* cb, size_t label_idx);
void jp(codeblock_t* cb, size_t label_idx);
void jpe(codeblock_t* cb, size_t label_idx);
void jpo(codeblock_t* cb, size_t label_idx);
void js(codeblock_t* cb, size_t label_idx);
void jz(codeblock_t* cb, size_t label_idx);
void ja(codeblock_t* cb, uint32_t label_idx);
void jae(codeblock_t* cb, uint32_t label_idx);
void jb(codeblock_t* cb, uint32_t label_idx);
void jbe(codeblock_t* cb, uint32_t label_idx);
void jc(codeblock_t* cb, uint32_t label_idx);
void je(codeblock_t* cb, uint32_t label_idx);
void jg(codeblock_t* cb, uint32_t label_idx);
void jge(codeblock_t* cb, uint32_t label_idx);
void jl(codeblock_t* cb, uint32_t label_idx);
void jle(codeblock_t* cb, uint32_t label_idx);
void jna(codeblock_t* cb, uint32_t label_idx);
void jnae(codeblock_t* cb, uint32_t label_idx);
void jnb(codeblock_t* cb, uint32_t label_idx);
void jnbe(codeblock_t* cb, uint32_t label_idx);
void jnc(codeblock_t* cb, uint32_t label_idx);
void jne(codeblock_t* cb, uint32_t label_idx);
void jng(codeblock_t* cb, uint32_t label_idx);
void jnge(codeblock_t* cb, uint32_t label_idx);
// void jnl(codeblock_t* cb, uint32_t label_idx); // this conflicts with jnl(3)
void jnle(codeblock_t* cb, uint32_t label_idx);
void jno(codeblock_t* cb, uint32_t label_idx);
void jnp(codeblock_t* cb, uint32_t label_idx);
void jns(codeblock_t* cb, uint32_t label_idx);
void jnz(codeblock_t* cb, uint32_t label_idx);
void jo(codeblock_t* cb, uint32_t label_idx);
void jp(codeblock_t* cb, uint32_t label_idx);
void jpe(codeblock_t* cb, uint32_t label_idx);
void jpo(codeblock_t* cb, uint32_t label_idx);
void js(codeblock_t* cb, uint32_t label_idx);
void jz(codeblock_t* cb, uint32_t label_idx);
void ja_ptr(codeblock_t* cb, uint8_t* ptr);
void jae_ptr(codeblock_t* cb, uint8_t* ptr);
void jb_ptr(codeblock_t* cb, uint8_t* ptr);
@ -351,7 +351,7 @@ void jpe_ptr(codeblock_t* cb, uint8_t* ptr);
void jpo_ptr(codeblock_t* cb, uint8_t* ptr);
void js_ptr(codeblock_t* cb, uint8_t* ptr);
void jz_ptr(codeblock_t* cb, uint8_t* ptr);
void jmp(codeblock_t* cb, size_t label_idx);
void jmp(codeblock_t* cb, uint32_t label_idx);
void jmp_ptr(codeblock_t* cb, uint8_t* ptr);
void jmp_rm(codeblock_t* cb, x86opnd_t opnd);
void jmp32(codeblock_t* cb, int32_t offset);
@ -359,7 +359,7 @@ void lea(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
void mov(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
void movsx(codeblock_t* cb, x86opnd_t dst, x86opnd_t src);
void neg(codeblock_t* cb, x86opnd_t opnd);
void nop(codeblock_t* cb, size_t length);
void nop(codeblock_t* cb, uint32_t length);
void not(codeblock_t* cb, x86opnd_t opnd);
void or(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1);
void pop(codeblock_t* cb, x86opnd_t reg);

View file

@ -7,7 +7,7 @@
// Print the bytes in a code block
void print_bytes(codeblock_t* cb)
{
for (size_t i = 0; i < cb->write_pos; ++i)
for (uint32_t i = 0; i < cb->write_pos; ++i)
{
printf("%02X", (int)cb->mem_block[i]);
}
@ -26,7 +26,7 @@ void check_bytes(codeblock_t* cb, const char* bytes)
if (cb->write_pos != num_bytes)
{
fprintf(stderr, "incorrect encoding length, expected %ld, got %ld\n",
fprintf(stderr, "incorrect encoding length, expected %ld, got %d\n",
num_bytes,
cb->write_pos
);
@ -35,7 +35,7 @@ void check_bytes(codeblock_t* cb, const char* bytes)
exit(-1);
}
for (size_t i = 0; i < num_bytes; ++i)
for (uint32_t i = 0; i < num_bytes; ++i)
{
char byte_str[] = {0, 0, 0, 0};
strncpy(byte_str, bytes + (2 * i), 2);
@ -46,7 +46,7 @@ void check_bytes(codeblock_t* cb, const char* bytes)
if (cb_byte != byte)
{
fprintf(stderr, "incorrect encoding at position %ld, expected %02X, got %02X\n",
fprintf(stderr, "incorrect encoding at position %d, expected %02X, got %02X\n",
i,
(int)byte,
(int)cb_byte
@ -92,7 +92,7 @@ void run_tests()
// call
{
cb_set_pos(cb, 0);
size_t fn_label = cb_new_label(cb, "foo");
uint32_t fn_label = cb_new_label(cb, "foo");
call_label(cb, fn_label);
cb_link_labels(cb);
check_bytes(cb, "E8FBFFFFFF");
@ -131,14 +131,14 @@ void run_tests()
// jcc
{
cb_set_pos(cb, 0);
size_t loop_label = cb_new_label(cb, "loop");
uint32_t loop_label = cb_new_label(cb, "loop");
jge(cb, loop_label);
cb_link_labels(cb);
check_bytes(cb, "0F8DFAFFFFFF");
}
{
cb_set_pos(cb, 0);
size_t loop_label = cb_new_label(cb, "loop");
uint32_t loop_label = cb_new_label(cb, "loop");
jo(cb, loop_label);
cb_link_labels(cb);
check_bytes(cb, "0F80FAFFFFFF");

View file

@ -154,7 +154,7 @@ uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx)
/*
Compile a sequence of bytecode instructions starting at `insn_idx`.
*/
uint8_t *
void
ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_t* num_instrs)
{
assert (cb != NULL);
@ -170,16 +170,14 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_
rb_bug("out of executable memory (outlined block)");
}
// Get a pointer to the current write position in the code block
uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
// Last operation that was successfully compiled
opdesc_t* p_last_op = NULL;
// Initialize JIT state object
jitstate_t jit = { 0 };
jit.iseq = iseq;
jit.start_idx = insn_idx;
jitstate_t jit = {
iseq,
insn_idx
};
// For each instruction to compile
for (;;) {
@ -236,8 +234,6 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_
pc += insn_len(opcode);
}
}
return code_ptr;
}
static bool
@ -1055,7 +1051,7 @@ void
ujit_init_codegen(void)
{
// Initialize the code blocks
size_t mem_size = 128 * 1024 * 1024;
uint32_t mem_size = 128 * 1024 * 1024;
uint8_t* mem_block = alloc_exec_mem(mem_size);
cb = &block;
cb_init(cb, mem_block, mem_size/2);

View file

@ -15,7 +15,7 @@ typedef struct JITState
const rb_iseq_t *iseq;
// Index in the iseq of the opcode we are replacing
uint32_t start_idx;
const uint32_t start_idx;
// Index of the current instruction being compiled
uint32_t insn_idx;
@ -42,7 +42,7 @@ typedef struct OpDesc
uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx);
uint8_t *ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_t* num_instrs);
void ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_t* num_instrs);
void ujit_init_codegen(void);

View file

@ -70,12 +70,12 @@ ctx_stack_opnd(ctx_t* ctx, int32_t idx)
}
// Retrieve a basic block version for an (iseq, idx) tuple
uint8_t* find_block_version(blockid_t block, const ctx_t* ctx)
version_t* find_block_version(blockid_t block, const ctx_t* ctx)
{
// If there exists a version for this block id
st_data_t st_version;
if (rb_st_lookup(version_tbl, (st_data_t)&block, &st_version)) {
return (uint8_t*)st_version;
return (version_t*)st_version;
}
//
@ -86,23 +86,24 @@ uint8_t* find_block_version(blockid_t block, const ctx_t* ctx)
}
// Compile a new block version immediately
uint8_t* gen_block_version(blockid_t blockid, const ctx_t* ctx)
version_t* gen_block_version(blockid_t blockid, const ctx_t* ctx)
{
// Copy the context object to avoid modifying it
// Allocate a version object
version_t* p_version = malloc(sizeof(version_t));
memcpy(&p_version->blockid, &blockid, sizeof(blockid_t));
memcpy(&p_version->ctx, ctx, sizeof(ctx_t));
// Compile the block version
ctx_t ctx_copy = *ctx;
uint32_t num_instrs = 0;
uint8_t* p_block = ujit_compile_block(blockid.iseq, blockid.idx, &ctx_copy, &num_instrs);
// Need to allocate the blockid on the heap
// to store it in the hash table
blockid_t* p_blockid = (blockid_t*)malloc(sizeof(blockid_t));
memcpy(p_blockid, &blockid, sizeof(blockid_t));
p_version->start_pos = cb->write_pos;
ujit_compile_block(blockid.iseq, blockid.idx, &ctx_copy, &num_instrs);
p_version->end_pos = cb->write_pos;
// Keep track of the new block version
st_insert(version_tbl, (st_data_t)p_blockid, (st_data_t)p_block);
st_insert(version_tbl, (st_data_t)&p_version->blockid, (st_data_t)p_version);
return p_block;
return p_version;
}
// Called by the generated code when a branch stub is executed
@ -132,31 +133,29 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx)
}
// Try to find a compiled version of this block
uint8_t* block_ptr = find_block_version(target, target_ctx);
version_t* p_version = find_block_version(target, target_ctx);
// If this block hasn't yet been compiled
if (!block_ptr)
if (!p_version)
{
//fprintf(stderr, "compiling block\n");
block_ptr = gen_block_version(target, target_ctx);
p_version = gen_block_version(target, target_ctx);
}
// Update the branch target address
branch->dst_addrs[target_idx] = block_ptr;
//fprintf(stderr, "rewrite branch at %d\n", branch->start_pos);
uint8_t* dst_addr = cb_get_ptr(cb, p_version->start_pos);
branch->dst_addrs[target_idx] = dst_addr;
// Rewrite the branch with the new jump target address
assert (branch->dst_addrs[0] != NULL);
assert (branch->dst_addrs[1] != NULL);
size_t cur_pos = cb->write_pos;
uint32_t cur_pos = cb->write_pos;
cb_set_pos(cb, branch->start_pos);
branch->gen_fn(cb, branch->dst_addrs[0], branch->dst_addrs[1], branch->shape);
assert (cb->write_pos <= branch->end_pos);
cb_set_pos(cb, cur_pos);
// Return a pointer to the compiled block version
return block_ptr;
return dst_addr;
}
// Get a version or stub corresponding to a branch target
@ -169,10 +168,12 @@ uint8_t* get_branch_target(
uint32_t target_idx
)
{
uint8_t* block_code = find_block_version(target, ctx);
version_t* p_version = find_block_version(target, ctx);
if (block_code)
return block_code;
if (p_version)
{
return cb_get_ptr(cb, p_version->start_pos);
}
// Generate an outlined stub that will call
// branch_stub_hit(uint32_t branch_idx, uint32_t target_idx)
@ -216,12 +217,10 @@ void gen_branch(
uint8_t* dst_addr0 = get_branch_target(target0, ctx0, ocb, num_branches, 0);
uint8_t* dst_addr1 = get_branch_target(target1, ctx1, ocb, num_branches, 1);
uint32_t start_pos = (uint32_t)cb->write_pos;
// Call the branch generation function
uint32_t start_pos = cb->write_pos;
gen_fn(cb, dst_addr0, dst_addr1, SHAPE_DEFAULT);
uint32_t end_pos = (uint32_t)cb->write_pos;
uint32_t end_pos = cb->write_pos;
// Register this branch entry
branch_t branch_entry = {

View file

@ -45,6 +45,26 @@ typedef struct BlockId
// Null block id constant
static const blockid_t BLOCKID_NULL = { 0, 0 };
// Basic block version
typedef struct BlockVersion
{
// Basic block this is a version of
blockid_t blockid;
// Context at the start of the block
ctx_t ctx;
// Positions where the generated code starts and ends
uint32_t start_pos;
uint32_t end_pos;
// TODO
// TODO: list of incoming branches, branch entries
// TODO
// incoming;
} version_t;
/// Branch code shape enumeration
enum uint8_t
{
@ -90,8 +110,8 @@ x86opnd_t ctx_stack_push(ctx_t* ctx, size_t n);
x86opnd_t ctx_stack_pop(ctx_t* ctx, size_t n);
x86opnd_t ctx_stack_opnd(ctx_t* ctx, int32_t idx);
uint8_t* find_block_version(blockid_t block, const ctx_t* ctx);
uint8_t* gen_block_version(blockid_t block, const ctx_t* ctx);
version_t* find_block_version(blockid_t block, const ctx_t* ctx);
version_t* gen_block_version(blockid_t block, const ctx_t* ctx);
void gen_branch(
const ctx_t* src_ctx,