From 3a74011ff8e5b9b4bf07ef72d249d08b8c13c57e Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert Date: Tue, 12 Jan 2021 14:56:43 -0500 Subject: [PATCH] Introduce version_t struct. Will be needed for code invalidation. --- ujit_asm.c | 142 +++++++++++++++++++++++------------------------ ujit_asm.h | 102 +++++++++++++++++----------------- ujit_asm_tests.c | 14 ++--- ujit_codegen.c | 16 ++---- ujit_codegen.h | 4 +- ujit_core.c | 57 ++++++++++--------- ujit_core.h | 24 +++++++- 7 files changed, 187 insertions(+), 172 deletions(-) diff --git a/ujit_asm.c b/ujit_asm.c index 4fb0cc764a..231e83b5c8 100644 --- a/ujit_asm.c +++ b/ujit_asm.c @@ -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); diff --git a/ujit_asm.h b/ujit_asm.h index 43b3665486..278919bfdb 100644 --- a/ujit_asm.h +++ b/ujit_asm.h @@ -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); diff --git a/ujit_asm_tests.c b/ujit_asm_tests.c index 8f2fbdfcbf..2d5cfc7716 100644 --- a/ujit_asm_tests.c +++ b/ujit_asm_tests.c @@ -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"); diff --git a/ujit_codegen.c b/ujit_codegen.c index 980e3e6673..8ba71bf37f 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -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 = █ cb_init(cb, mem_block, mem_size/2); diff --git a/ujit_codegen.h b/ujit_codegen.h index 0a845571eb..413ecb35ac 100644 --- a/ujit_codegen.h +++ b/ujit_codegen.h @@ -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); diff --git a/ujit_core.c b/ujit_core.c index e3086c4fba..c3166d0f09 100644 --- a/ujit_core.c +++ b/ujit_core.c @@ -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 = { diff --git a/ujit_core.h b/ujit_core.h index 9ff3a5af2f..4c80bbc5d4 100644 --- a/ujit_core.h +++ b/ujit_core.h @@ -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,