diff --git a/lightening.h b/lightening.h index 43ef7b82b..437ba1872 100644 --- a/lightening.h +++ b/lightening.h @@ -78,7 +78,6 @@ typedef struct jit_reloc { uint8_t kind; uint8_t inst_start_offset; - uint16_t flags; uint32_t offset; } jit_reloc_t; diff --git a/lightening/lightening.c b/lightening/lightening.c index 1a135590d..faba86bdb 100644 --- a/lightening/lightening.c +++ b/lightening/lightening.c @@ -124,11 +124,6 @@ struct jit_state void (*free)(void*); }; -enum jit_reloc_flags -{ - JIT_RELOC_CAN_SHORTEN = 1<<0 -}; - #define ASSERT(x) do { if (!(x)) abort(); } while (0) #if defined(__GNUC__) # define UNLIKELY(exprn) __builtin_expect(exprn, 0) @@ -139,7 +134,8 @@ enum jit_reloc_flags static jit_bool_t jit_get_cpu(void); static jit_bool_t jit_init(jit_state_t *); static void jit_flush(void *fptr, void *tptr); -static void jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc); +static void jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc, + jit_pointer_t addr); jit_bool_t init_jit(void) @@ -283,13 +279,12 @@ static inline void emit_u64(jit_state_t *_jit, uint64_t u64) { static inline jit_reloc_t jit_reloc (jit_state_t *_jit, enum jit_reloc_kind kind, - uint8_t inst_start_offset, uint16_t flags) + uint8_t inst_start_offset) { jit_reloc_t ret; ret.kind = kind; ret.inst_start_offset = inst_start_offset; - ret.flags = 0; ret.offset = _jit->pc.uc - _jit->start; switch (kind) @@ -331,6 +326,7 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr) if (_jit->overflow) return; union jit_pc loc; + uint8_t *end; loc.uc = _jit->start + reloc.offset; ptrdiff_t diff; @@ -341,38 +337,37 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr) *loc.ui = (uintptr_t)addr; else *loc.ul = (uintptr_t)addr; - if (loc.uc + sizeof(diff) == _jit->pc.uc && - (reloc.flags & JIT_RELOC_CAN_SHORTEN)) - jit_try_shorten (_jit, reloc); + end = loc.uc + sizeof(diff); break; case JIT_RELOC_REL8: diff = ((uint8_t*)addr) - (loc.uc + 1); ASSERT (INT8_MIN <= diff && diff <= INT8_MAX); *loc.uc = diff; + end = loc.uc + 1; break; case JIT_RELOC_REL16: diff = ((uint8_t*)addr) - (loc.uc + 2); ASSERT (INT16_MIN <= diff && diff <= INT16_MAX); *loc.us = diff; - if ((loc.uc + 1) == _jit->pc.uc && (reloc.flags & JIT_RELOC_CAN_SHORTEN)) - jit_try_shorten (_jit, reloc); + end = loc.uc + 2; break; case JIT_RELOC_REL32: diff = ((uint8_t*)addr) - (loc.uc + 4); ASSERT (INT32_MIN <= diff && diff <= INT32_MAX); *loc.ui = diff; - if ((loc.ui + 1) == _jit->pc.ui && (reloc.flags & JIT_RELOC_CAN_SHORTEN)) - jit_try_shorten (_jit, reloc); + end = loc.uc + 4; break; case JIT_RELOC_REL64: diff = ((uint8_t*)addr) - (loc.uc + 8); *loc.ul = diff; - if ((loc.ul + 1) == _jit->pc.ul && (reloc.flags & JIT_RELOC_CAN_SHORTEN)) - jit_try_shorten (_jit, reloc); + end = loc.uc + 8; break; default: abort (); } + + if (end == _jit->pc.uc) + jit_try_shorten (_jit, reloc, addr); } #if defined(__i386__) || defined(__x86_64__) diff --git a/lightening/x86-cpu.c b/lightening/x86-cpu.c index 7b1639335..aa9d68a68 100644 --- a/lightening/x86-cpu.c +++ b/lightening/x86-cpu.c @@ -403,7 +403,7 @@ mov_addr(jit_state_t *_jit, int32_t r0) rex(_jit, 0, WIDE, _NOREG, _NOREG, r0); ic(_jit, 0xb8 | r7(r0)); ptrdiff_t inst_start = _jit->pc.uc - pc_start; - return jit_reloc(_jit, JIT_RELOC_ABSOLUTE, inst_start, 0); + return jit_reloc(_jit, JIT_RELOC_ABSOLUTE, inst_start); } static void @@ -659,15 +659,6 @@ testi(jit_state_t *_jit, int32_t r0, jit_word_t i0) ii(_jit, i0); } -static void -cc(jit_state_t *_jit, int32_t code, int32_t r0) -{ - rex(_jit, 0, 0, _NOREG, _NOREG, r0); - ic(_jit, 0x0f); - ic(_jit, 0x90 | code); - mrm(_jit, 0x03, 0x00, r7(r0)); -} - static void negr(jit_state_t *_jit, int32_t r0, int32_t r1) { @@ -1465,69 +1456,6 @@ xori(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0) } } -static void -cr(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1, int32_t r2) -{ - if (reg8_p(r0)) { - jit_bool_t same = r0 == r1 || r0 == r2; - if (!same) - ixorr(_jit, r0, r0); - icmpr(_jit, r1, r2); - if (same) - imovi(_jit, r0, 0); - cc(_jit, code, r0); - } else { - jit_gpr_t reg = get_temp_gpr(_jit); - ixorr(_jit, jit_gpr_regno(reg), jit_gpr_regno(reg)); - icmpr(_jit, r1, r2); - cc(_jit, code, jit_gpr_regno(reg)); - movr(_jit, r0, jit_gpr_regno(reg)); - unget_temp_gpr(_jit); - } -} - -static void -ci(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1, jit_word_t i0) -{ - if (reg8_p(r0)) { - jit_bool_t same = r0 == r1; - if (!same) - ixorr(_jit, r0, r0); - icmpi(_jit, r1, i0); - if (same) - imovi(_jit, r0, 0); - cc(_jit, code, r0); - } else { - jit_gpr_t reg = get_temp_gpr(_jit); - ixorr(_jit, jit_gpr_regno(reg), jit_gpr_regno(reg)); - icmpi(_jit, r1, i0); - cc(_jit, code, jit_gpr_regno(reg)); - movr(_jit, r0, jit_gpr_regno(reg)); - unget_temp_gpr(_jit); - } -} - -static void -ci0(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1) -{ - if (reg8_p(r0)) { - jit_bool_t same = r0 == r1; - if (!same) - ixorr(_jit, r0, r0); - testr(_jit, r1, r1); - if (same) - imovi(_jit, r0, 0); - cc(_jit, code, r0); - } else { - jit_gpr_t reg = get_temp_gpr(_jit); - ixorr(_jit, jit_gpr_regno(reg), jit_gpr_regno(reg)); - testr(_jit, r1, r1); - cc(_jit, code, jit_gpr_regno(reg)); - movr(_jit, r0, jit_gpr_regno(reg)); - unget_temp_gpr(_jit); - } -} - static void extr_c(jit_state_t *_jit, int32_t r0, int32_t r1) { @@ -2255,7 +2183,7 @@ static jit_reloc_t jccs(jit_state_t *_jit, int32_t code) { ic(_jit, 0x70 | code); - return jit_reloc(_jit, JIT_RELOC_REL8, 1, 0); + return jit_reloc(_jit, JIT_RELOC_REL8, 1); } static jit_reloc_t @@ -2263,7 +2191,26 @@ jcc(jit_state_t *_jit, int32_t code) { ic(_jit, 0x0f); ic(_jit, 0x80 | code); - return jit_reloc(_jit, JIT_RELOC_REL32, 2, 0); + return jit_reloc(_jit, JIT_RELOC_REL32, 2); +} + +static void +jcci(jit_state_t *_jit, int32_t code, jit_word_t i0) +{ + ptrdiff_t rel8 = i0 - (_jit->pc.w + 1 + 1); + ptrdiff_t rel32 = i0 - (_jit->pc.w + 2 + 4); + if (INT8_MIN <= rel8 && rel8 <= INT8_MAX) + { + ic(_jit, 0x70 | code); + ic(_jit, rel8); + } + else + { + ASSERT(INT32_MIN <= rel32 && rel32 <= INT32_MAX); + ic(_jit, 0x0f); + ic(_jit, 0x80 | code); + ii(_jit, rel32); + } } #define DEFINE_JUMPS(cc, CC, code) \ @@ -2666,8 +2613,14 @@ jmpr(jit_state_t *_jit, int32_t r0) static void jmpi(jit_state_t *_jit, jit_word_t i0) { + ptrdiff_t rel8 = i0 - (_jit->pc.w + 1 + 1); ptrdiff_t rel32 = i0 - (_jit->pc.w + 1 + 4); - if (INT32_MIN <= rel32 && rel32 <= INT32_MAX) + if (INT8_MIN <= rel8 && rel8 <= INT8_MAX) + { + ic(_jit, 0xeb); + ic(_jit, rel8); + } + else if (INT32_MIN <= rel32 && rel32 <= INT32_MAX) { ic(_jit, 0xe9); ii(_jit, rel32); @@ -2685,14 +2638,7 @@ static jit_reloc_t jmp(jit_state_t *_jit) { ic(_jit, 0xe9); - return jit_reloc(_jit, JIT_RELOC_REL32, 1, 0); -} - -static jit_reloc_t -jmpsi(jit_state_t *_jit) -{ - ic(_jit, 0xeb); - return jit_reloc(_jit, JIT_RELOC_REL8, 1, 0); + return jit_reloc(_jit, JIT_RELOC_REL32, 1); } static void diff --git a/lightening/x86.c b/lightening/x86.c index a0afd02aa..4031bb1ca 100644 --- a/lightening/x86.c +++ b/lightening/x86.c @@ -351,6 +351,42 @@ jit_flush(void *fptr, void *tptr) } static void -jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc) +jit_try_shorten(jit_state_t *_jit, jit_reloc_t reloc, jit_pointer_t addr) { + uint8_t *loc = _jit->start + reloc.offset; + uint8_t *start = loc - reloc.inst_start_offset; + jit_imm_t i0 = (jit_imm_t)addr; + + switch (reloc.kind) + { + case JIT_RELOC_ABSOLUTE: { + _jit->pc.uc = start; + ASSERT((loc[-1] & ~7) == 0xb8); // MOVI + int32_t r0 = loc[-1] & 7; + if (start != loc - 1) { + ASSERT(start == loc - 2); + r0 |= (loc[-2] & 1) << 3; + } + return movi(_jit, r0, i0); + } + case JIT_RELOC_REL8: + ASSERT((loc[-1] & ~0xf) == 0x70 || loc[-1] == 0xeb); // JCCSI or JMPSI + /* Nothing useful to do. */ + return; + case JIT_RELOC_REL16: + /* We don't emit these. */ + abort (); + case JIT_RELOC_REL32: + _jit->pc.uc = start; + if (start[0] == 0xe9) { // JMP + return jmpi(_jit, i0); + } + ASSERT(start[0] == 0x0f); // JCC + return jcci(_jit, start[1] & ~0x80, i0); + case JIT_RELOC_REL64: + /* We don't emit these. */ + abort (); + default: + abort (); + } }