mirror of
https://github.com/copy/v86.git
synced 2025-12-31 04:23:15 +00:00
Partial custom implementation for arithmethic instructions with read-memory
This commit is contained in:
parent
9de2b926a7
commit
cfb9cd8abe
3 changed files with 234 additions and 42 deletions
|
|
@ -16,6 +16,46 @@ const sf = 1 << 7;
|
|||
|
||||
// os: the instruction behaves differently depending on the operand size
|
||||
const encodings = [
|
||||
{ opcode: 0x00, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x01, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x02, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x03, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x08, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x09, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x0A, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x0B, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x10, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x11, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x12, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x13, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x18, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x19, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x1A, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x1B, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x20, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x21, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x22, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x23, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x28, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x29, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x2A, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x2B, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x30, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x31, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x32, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x33, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x38, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x39, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x3A, nonfaulting: 1, custom: 1, e: 1, },
|
||||
{ opcode: 0x3B, nonfaulting: 1, custom: 1, os: 1, e: 1, },
|
||||
|
||||
{ opcode: 0x06, os: 1, skip: 1, },
|
||||
{ opcode: 0x07, os: 1, skip: 1, block_boundary: 1, }, // pop es: block_boundary since it uses non-raising cpu exceptions
|
||||
{ opcode: 0x0E, os: 1, skip: 1, },
|
||||
|
|
@ -786,10 +826,6 @@ const encodings = [
|
|||
for(let i = 0; i < 8; i++)
|
||||
{
|
||||
encodings.push.apply(encodings, [
|
||||
{ opcode: 0x00 | i << 3, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x01 | i << 3, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x02 | i << 3, nonfaulting: 1, e: 1, },
|
||||
{ opcode: 0x03 | i << 3, nonfaulting: 1, os: 1, e: 1, },
|
||||
{ opcode: 0x04 | i << 3, nonfaulting: 1, eax: 1, imm8: 1, },
|
||||
{ opcode: 0x05 | i << 3, nonfaulting: 1, os: 1, eax: 1, imm1632: 1, },
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,12 @@ pub fn gen_call_fn2(builder: &mut WasmBuilder, name: &str) {
|
|||
builder.instruction_body.call_fn(fn_idx);
|
||||
}
|
||||
|
||||
pub fn gen_call_fn2_ret(builder: &mut WasmBuilder, name: &str) {
|
||||
// generates: fn( _, _ ) where _ must be left on the stack before calling this, and fn returns a value
|
||||
let fn_idx = builder.get_fn_idx(name, module_init::FN2_RET_TYPE_INDEX);
|
||||
builder.instruction_body.call_fn(fn_idx);
|
||||
}
|
||||
|
||||
pub fn gen_fn3_const(ctx: &mut JitContext, name: &str, arg0: u32, arg1: u32, arg2: u32) {
|
||||
let builder = &mut ctx.builder;
|
||||
let fn_idx = builder.get_fn_idx(name, module_init::FN3_TYPE_INDEX);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,191 @@ fn pop32_reg_jit(ctx: &mut JitContext, reg: u32) {
|
|||
ctx.builder.instruction_body.store_aligned_i32(0);
|
||||
}
|
||||
|
||||
macro_rules! define_instruction_read8(
|
||||
($fn:expr, $name_mem:ident, $name_reg:ident) => (
|
||||
pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read8(ctx);
|
||||
codegen::gen_get_reg8(ctx.builder, r);
|
||||
codegen::gen_call_fn2(ctx.builder, $fn)
|
||||
}
|
||||
|
||||
pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg8(ctx.builder, r1);
|
||||
codegen::gen_get_reg8(ctx.builder, r2);
|
||||
codegen::gen_call_fn2(ctx.builder, $fn)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! define_instruction_read16(
|
||||
($fn:expr, $name_mem:ident, $name_reg:ident) => (
|
||||
pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read16(ctx);
|
||||
codegen::gen_get_reg16(ctx.builder, r);
|
||||
codegen::gen_call_fn2(ctx.builder, $fn)
|
||||
}
|
||||
|
||||
pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg16(ctx.builder, r1);
|
||||
codegen::gen_get_reg16(ctx.builder, r2);
|
||||
codegen::gen_call_fn2(ctx.builder, $fn)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! define_instruction_read32(
|
||||
($fn:expr, $name_mem:ident, $name_reg:ident) => (
|
||||
pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read32(ctx);
|
||||
codegen::gen_get_reg32(ctx.builder, r);
|
||||
codegen::gen_call_fn2(ctx.builder, $fn)
|
||||
}
|
||||
|
||||
pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg32(ctx.builder, r1);
|
||||
codegen::gen_get_reg32(ctx.builder, r2);
|
||||
codegen::gen_call_fn2(ctx.builder, $fn)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! define_instruction_write_reg8(
|
||||
($fn:expr, $name_mem:ident, $name_reg:ident) => (
|
||||
pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
ctx.builder.instruction_body.const_i32(global_pointers::get_reg8_offset(r) as i32);
|
||||
codegen::gen_get_reg8(ctx.builder, r);
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read8(ctx);
|
||||
codegen::gen_call_fn2_ret(ctx.builder, $fn);
|
||||
ctx.builder.instruction_body.store_u8(0);
|
||||
}
|
||||
|
||||
pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
ctx.builder.instruction_body.const_i32(global_pointers::get_reg8_offset(r2) as i32);
|
||||
codegen::gen_get_reg8(ctx.builder, r2);
|
||||
codegen::gen_get_reg8(ctx.builder, r1);
|
||||
codegen::gen_call_fn2_ret(ctx.builder, $fn);
|
||||
ctx.builder.instruction_body.store_u8(0);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! define_instruction_write_reg16(
|
||||
($fn:expr, $name_mem:ident, $name_reg:ident) => (
|
||||
pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
ctx.builder.instruction_body.const_i32(global_pointers::get_reg16_offset(r) as i32);
|
||||
codegen::gen_get_reg16(ctx.builder, r);
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read16(ctx);
|
||||
codegen::gen_call_fn2_ret(ctx.builder, $fn);
|
||||
ctx.builder.instruction_body.store_aligned_u16(0);
|
||||
}
|
||||
|
||||
pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
ctx.builder.instruction_body.const_i32(global_pointers::get_reg16_offset(r2) as i32);
|
||||
codegen::gen_get_reg16(ctx.builder, r2);
|
||||
codegen::gen_get_reg16(ctx.builder, r1);
|
||||
codegen::gen_call_fn2_ret(ctx.builder, $fn);
|
||||
ctx.builder.instruction_body.store_aligned_u16(0);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! define_instruction_write_reg32(
|
||||
($fn:expr, $name_mem:ident, $name_reg:ident) => (
|
||||
pub fn $name_mem(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
ctx.builder.instruction_body.const_i32(global_pointers::get_reg32_offset(r) as i32);
|
||||
codegen::gen_get_reg32(ctx.builder, r);
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read32(ctx);
|
||||
codegen::gen_call_fn2_ret(ctx.builder, $fn);
|
||||
ctx.builder.instruction_body.store_aligned_i32(0);
|
||||
}
|
||||
|
||||
pub fn $name_reg(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
ctx.builder.instruction_body.const_i32(global_pointers::get_reg32_offset(r2) as i32);
|
||||
codegen::gen_get_reg32(ctx.builder, r2);
|
||||
codegen::gen_get_reg32(ctx.builder, r1);
|
||||
codegen::gen_call_fn2_ret(ctx.builder, $fn);
|
||||
ctx.builder.instruction_body.store_aligned_i32(0);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
define_instruction_write_reg8!("add8", instr_02_mem_jit, instr_02_reg_jit);
|
||||
define_instruction_write_reg16!("add16", instr16_03_mem_jit, instr16_03_reg_jit);
|
||||
define_instruction_write_reg32!("add32", instr32_03_mem_jit, instr32_03_reg_jit);
|
||||
|
||||
define_instruction_write_reg8!("or8", instr_0A_mem_jit, instr_0A_reg_jit);
|
||||
define_instruction_write_reg16!("or16", instr16_0B_mem_jit, instr16_0B_reg_jit);
|
||||
define_instruction_write_reg32!("or32", instr32_0B_mem_jit, instr32_0B_reg_jit);
|
||||
|
||||
define_instruction_write_reg8!("adc8", instr_12_mem_jit, instr_12_reg_jit);
|
||||
define_instruction_write_reg16!("adc16", instr16_13_mem_jit, instr16_13_reg_jit);
|
||||
define_instruction_write_reg32!("adc32", instr32_13_mem_jit, instr32_13_reg_jit);
|
||||
|
||||
define_instruction_write_reg8!("sbb8", instr_1A_mem_jit, instr_1A_reg_jit);
|
||||
define_instruction_write_reg16!("sbb16", instr16_1B_mem_jit, instr16_1B_reg_jit);
|
||||
define_instruction_write_reg32!("sbb32", instr32_1B_mem_jit, instr32_1B_reg_jit);
|
||||
|
||||
define_instruction_write_reg8!("and8", instr_22_mem_jit, instr_22_reg_jit);
|
||||
define_instruction_write_reg16!("and16", instr16_23_mem_jit, instr16_23_reg_jit);
|
||||
define_instruction_write_reg32!("and32", instr32_23_mem_jit, instr32_23_reg_jit);
|
||||
|
||||
define_instruction_write_reg8!("sub8", instr_2A_mem_jit, instr_2A_reg_jit);
|
||||
define_instruction_write_reg16!("sub16", instr16_2B_mem_jit, instr16_2B_reg_jit);
|
||||
define_instruction_write_reg32!("sub32", instr32_2B_mem_jit, instr32_2B_reg_jit);
|
||||
|
||||
define_instruction_write_reg8!("xor8", instr_32_mem_jit, instr_32_reg_jit);
|
||||
define_instruction_write_reg16!("xor16", instr16_33_mem_jit, instr16_33_reg_jit);
|
||||
define_instruction_write_reg32!("xor32", instr32_33_mem_jit, instr32_33_reg_jit);
|
||||
|
||||
define_instruction_read8!("cmp8", instr_38_mem_jit, instr_38_reg_jit);
|
||||
define_instruction_read16!("cmp16", instr16_39_mem_jit, instr16_39_reg_jit);
|
||||
define_instruction_read32!("cmp32", instr32_39_mem_jit, instr32_39_reg_jit);
|
||||
|
||||
pub fn instr_3A_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_get_reg8(ctx.builder, r);
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read8(ctx);
|
||||
codegen::gen_call_fn2(ctx.builder, "cmp8")
|
||||
}
|
||||
|
||||
pub fn instr_3A_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg8(ctx.builder, r2);
|
||||
codegen::gen_get_reg8(ctx.builder, r1);
|
||||
codegen::gen_call_fn2(ctx.builder, "cmp8")
|
||||
}
|
||||
|
||||
pub fn instr16_3B_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_get_reg16(ctx.builder, r);
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read16(ctx);
|
||||
codegen::gen_call_fn2(ctx.builder, "cmp16")
|
||||
}
|
||||
|
||||
pub fn instr16_3B_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg16(ctx.builder, r2);
|
||||
codegen::gen_get_reg16(ctx.builder, r1);
|
||||
codegen::gen_call_fn2(ctx.builder, "cmp16")
|
||||
}
|
||||
|
||||
pub fn instr32_3B_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_get_reg32(ctx.builder, r);
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read32(ctx);
|
||||
codegen::gen_call_fn2(ctx.builder, "cmp32")
|
||||
}
|
||||
|
||||
pub fn instr32_3B_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg32(ctx.builder, r2);
|
||||
codegen::gen_get_reg32(ctx.builder, r1);
|
||||
codegen::gen_call_fn2(ctx.builder, "cmp32")
|
||||
}
|
||||
|
||||
pub fn instr16_50_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, AX); }
|
||||
pub fn instr32_50_jit(ctx: &mut JitContext) { push32_reg_jit(ctx, EAX); }
|
||||
pub fn instr16_51_jit(ctx: &mut JitContext) { push16_reg_jit(ctx, CX); }
|
||||
|
|
@ -230,44 +415,9 @@ pub fn instr32_7E_jit(_ctx: &mut JitContext, _imm: u32) {}
|
|||
pub fn instr16_7F_jit(_ctx: &mut JitContext, _imm: u32) {}
|
||||
pub fn instr32_7F_jit(_ctx: &mut JitContext, _imm: u32) {}
|
||||
|
||||
pub fn instr_84_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read8(ctx);
|
||||
codegen::gen_get_reg8(ctx.builder, r);
|
||||
codegen::gen_call_fn2(ctx.builder, "test8")
|
||||
}
|
||||
|
||||
pub fn instr_84_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg8(ctx.builder, r1);
|
||||
codegen::gen_get_reg8(ctx.builder, r2);
|
||||
codegen::gen_call_fn2(ctx.builder, "test8")
|
||||
}
|
||||
|
||||
pub fn instr16_85_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read16(ctx);
|
||||
codegen::gen_get_reg16(ctx.builder, r);
|
||||
codegen::gen_call_fn2(ctx.builder, "test16")
|
||||
}
|
||||
|
||||
pub fn instr16_85_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg16(ctx.builder, r1);
|
||||
codegen::gen_get_reg16(ctx.builder, r2);
|
||||
codegen::gen_call_fn2(ctx.builder, "test16")
|
||||
}
|
||||
|
||||
pub fn instr32_85_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
codegen::gen_safe_read32(ctx);
|
||||
codegen::gen_get_reg32(ctx.builder, r);
|
||||
codegen::gen_call_fn2(ctx.builder, "test32")
|
||||
}
|
||||
|
||||
pub fn instr32_85_reg_jit(ctx: &mut JitContext, r1: u32, r2: u32) {
|
||||
codegen::gen_get_reg32(ctx.builder, r1);
|
||||
codegen::gen_get_reg32(ctx.builder, r2);
|
||||
codegen::gen_call_fn2(ctx.builder, "test32")
|
||||
}
|
||||
define_instruction_read8!("test8", instr_84_mem_jit, instr_84_reg_jit);
|
||||
define_instruction_read16!("test16", instr16_85_mem_jit, instr16_85_reg_jit);
|
||||
define_instruction_read32!("test32", instr32_85_mem_jit, instr32_85_reg_jit);
|
||||
|
||||
pub fn instr_88_mem_jit(ctx: &mut JitContext, modrm_byte: u8, r: u32) {
|
||||
codegen::gen_modrm_resolve(ctx, modrm_byte);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue