summaryrefslogtreecommitdiff
path: root/libguile/lightening/lightening/lightening.c
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/lightening/lightening/lightening.c')
-rw-r--r--libguile/lightening/lightening/lightening.c519
1 files changed, 422 insertions, 97 deletions
diff --git a/libguile/lightening/lightening/lightening.c b/libguile/lightening/lightening/lightening.c
index 0973d8a69..572976f40 100644
--- a/libguile/lightening/lightening/lightening.c
+++ b/libguile/lightening/lightening/lightening.c
@@ -29,14 +29,16 @@
#include "../lightening.h"
+#define ASSERT(x) do { if (!(x)) abort(); } while (0)
+
#if defined(__GNUC__)
# define maybe_unused __attribute__ ((unused))
+# define UNLIKELY(exprn) __builtin_expect(exprn, 0)
#else
# define maybe_unused /**/
+# define UNLIKELY(exprn) exprn
#endif
-#define _NOREG 0xffff
-
union jit_pc
{
uint8_t *uc;
@@ -47,6 +49,23 @@ union jit_pc
uintptr_t uw;
};
+#ifdef JIT_NEEDS_LITERAL_POOL
+struct jit_literal_pool_entry
+{
+ jit_reloc_t reloc;
+ int64_t value;
+};
+
+struct jit_literal_pool
+{
+ uint32_t deadline;
+ uint32_t size;
+ uint32_t byte_size;
+ uint32_t capacity;
+ struct jit_literal_pool_entry entries[];
+};
+#endif // JIT_NEEDS_LITERAL_POOL
+
struct jit_state
{
union jit_pc pc;
@@ -57,25 +76,50 @@ struct jit_state
uint8_t temp_fpr_saved;
uint8_t overflow;
int frame_size; // Used to know when to align stack.
+#ifdef JIT_NEEDS_LITERAL_POOL
+ struct jit_literal_pool *pool;
+#endif
void* (*alloc)(size_t);
void (*free)(void*);
};
-#define ASSERT(x) do { if (!(x)) abort(); } while (0)
-#if defined(__GNUC__)
-# define UNLIKELY(exprn) __builtin_expect(exprn, 0)
-#else
-# define UNLIKELY(exprn) exprn
-#endif
-
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,
jit_pointer_t addr);
+static void* bless_function_pointer(void *ptr);
struct abi_arg_iterator;
+#ifdef JIT_NEEDS_LITERAL_POOL
+static struct jit_literal_pool* alloc_literal_pool(jit_state_t *_jit,
+ size_t capacity);
+static void clear_literal_pool(struct jit_literal_pool *pool);
+static void grow_literal_pool(jit_state_t *_jit);
+static void add_literal_pool_entry(jit_state_t *_jit,
+ struct jit_literal_pool_entry entry,
+ ptrdiff_t max_offset);
+static void add_pending_literal(jit_state_t *_jit, jit_reloc_t src,
+ ptrdiff_t max_offset_bits);
+static void remove_pending_literal(jit_state_t *_jit, jit_reloc_t src);
+static void patch_pending_literal(jit_state_t *_jit, jit_reloc_t src,
+ uint64_t value);
+enum guard_pool { GUARD_NEEDED, NO_GUARD_NEEDED };
+static void emit_literal_pool(jit_state_t *_jit, enum guard_pool guard);
+
+static int32_t read_jmp_offset(uint32_t *loc);
+static int offset_in_jmp_range(ptrdiff_t offset);
+static void patch_jmp_offset(uint32_t *loc, ptrdiff_t offset);
+static int32_t read_jcc_offset(uint32_t *loc);
+static int offset_in_jcc_range(ptrdiff_t offset);
+static void patch_jcc_offset(uint32_t *loc, ptrdiff_t offset);
+static void patch_veneer(uint32_t *loc, jit_pointer_t addr);
+static int32_t read_load_from_pool_offset(uint32_t *loc);
+#endif
+
+static jit_bool_t is_fpr_arg(enum jit_operand_abi arg);
+static jit_bool_t is_gpr_arg(enum jit_operand_abi arg);
static void reset_abi_arg_iterator(struct abi_arg_iterator *iter, size_t argc,
const jit_operand_t *args);
static void next_abi_arg(struct abi_arg_iterator *iter,
@@ -102,16 +146,26 @@ jit_new_state(void* (*alloc_fn)(size_t), void (*free_fn)(void*))
_jit->free = free_fn;
if (!jit_init (_jit)) {
+#ifdef JIT_NEEDS_LITERAL_POOL
+ free_fn (_jit->pool);
+#endif
free_fn (_jit);
return NULL;
}
+#ifdef JIT_NEEDS_LITERAL_POOL
+ _jit->pool = alloc_literal_pool(_jit, 0);
+#endif
+
return _jit;
}
void
jit_destroy_state(jit_state_t *_jit)
{
+#ifdef JIT_NEEDS_LITERAL_POOL
+ _jit->free (_jit->pool);
+#endif
_jit->free (_jit);
}
@@ -131,6 +185,9 @@ jit_begin(jit_state_t *_jit, uint8_t* buf, size_t length)
_jit->limit = buf + length;
_jit->overflow = 0;
_jit->frame_size = 0;
+#ifdef JIT_NEEDS_LITERAL_POOL
+ clear_literal_pool(_jit->pool);
+#endif
}
jit_bool_t
@@ -147,30 +204,43 @@ jit_reset(jit_state_t *_jit)
_jit->pc.uc = _jit->start = _jit->limit = NULL;
_jit->overflow = 0;
_jit->frame_size = 0;
+#ifdef JIT_NEEDS_LITERAL_POOL
+ clear_literal_pool(_jit->pool);
+#endif
}
void*
jit_end(jit_state_t *_jit, size_t *length)
{
- uint8_t *code = _jit->start;
+#ifdef JIT_NEEDS_LITERAL_POOL
+ if (_jit->pool->size)
+ emit_literal_pool(_jit, NO_GUARD_NEEDED);
+#endif
+
+ if (_jit->overflow)
+ return NULL;
+
+ uint8_t *start = _jit->start;
uint8_t *end = _jit->pc.uc;
- ASSERT (code);
- ASSERT (code <= end);
+ ASSERT (start);
+ ASSERT (start <= end);
ASSERT (end <= _jit->limit);
- ASSERT (!_jit->overflow);
- jit_flush (code, end);
+ jit_flush (start, end);
if (length) {
- *length = end - code;
+ *length = end - start;
}
_jit->pc.uc = _jit->start = _jit->limit = NULL;
_jit->overflow = 0;
_jit->frame_size = 0;
+#ifdef JIT_NEEDS_LITERAL_POOL
+ clear_literal_pool(_jit->pool);
+#endif
- return code;
+ return bless_function_pointer(start);
}
static int
@@ -179,14 +249,46 @@ is_power_of_two (unsigned x)
return x && !(x & (x-1));
}
-void
-jit_align(jit_state_t *_jit, unsigned align)
+static jit_gpr_t
+get_temp_gpr(jit_state_t *_jit)
{
- ASSERT (is_power_of_two (align));
- uintptr_t here = _jit->pc.w;
- uintptr_t there = (here + align - 1) & ~(align - 1);
- if (there - here)
- jit_nop(_jit, there - here);
+ switch(_jit->temp_gpr_saved++)
+ {
+ case 0:
+ return JIT_TMP0;
+#ifdef JIT_TMP1
+ case 1:
+ return JIT_TMP1;
+#endif
+ default:
+ abort();
+ }
+}
+
+static jit_fpr_t
+get_temp_fpr(jit_state_t *_jit)
+{
+ switch(_jit->temp_fpr_saved++)
+ {
+ case 0:
+ return JIT_FTMP;
+ default:
+ abort();
+ }
+}
+
+static void
+unget_temp_fpr(jit_state_t *_jit)
+{
+ ASSERT(_jit->temp_fpr_saved);
+ _jit->temp_fpr_saved--;
+}
+
+static void
+unget_temp_gpr(jit_state_t *_jit)
+{
+ ASSERT(_jit->temp_gpr_saved);
+ _jit->temp_gpr_saved--;
}
static inline void emit_u8(jit_state_t *_jit, uint8_t u8) {
@@ -210,6 +312,10 @@ static inline void emit_u32(jit_state_t *_jit, uint32_t u32) {
_jit->overflow = 1;
} else {
*_jit->pc.ui++ = u32;
+#ifdef JIT_NEEDS_LITERAL_POOL
+ if (UNLIKELY(_jit->pc.uc >= _jit->start + _jit->pool->deadline))
+ emit_literal_pool(_jit, GUARD_NEEDED);
+#endif
}
}
@@ -223,38 +329,21 @@ 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)
+ uint8_t inst_start_offset, uint8_t *loc, uint8_t *pc_base,
+ uint8_t rsh)
{
jit_reloc_t ret;
+ ASSERT(rsh < __WORDSIZE);
+ ASSERT(pc_base >= (loc - inst_start_offset));
+ ASSERT(pc_base - (loc - inst_start_offset) < 256);
+
ret.kind = kind;
ret.inst_start_offset = inst_start_offset;
- ret.offset = _jit->pc.uc - _jit->start;
+ ret.pc_base_offset = pc_base - (loc - inst_start_offset);
+ ret.rsh = rsh;
+ ret.offset = loc - _jit->start;
- switch (kind)
- {
- case JIT_RELOC_ABSOLUTE:
- if (sizeof(intptr_t) == 4)
- emit_u32 (_jit, 0);
- else
- emit_u64 (_jit, 0);
- break;
- case JIT_RELOC_REL8:
- emit_u8 (_jit, 0);
- break;
- case JIT_RELOC_REL16:
- emit_u16 (_jit, 0);
- break;
- case JIT_RELOC_REL32:
- emit_u32 (_jit, 0);
- break;
- case JIT_RELOC_REL64:
- emit_u64 (_jit, 0);
- break;
- default:
- abort ();
- }
-
return ret;
}
@@ -272,7 +361,10 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
union jit_pc loc;
uint8_t *end;
loc.uc = _jit->start + reloc.offset;
- ptrdiff_t diff;
+ uint8_t *pc_base = loc.uc - reloc.inst_start_offset + reloc.pc_base_offset;
+ ptrdiff_t diff = (uint8_t*)addr - pc_base;
+ ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0);
+ diff >>= reloc.rsh;
switch (reloc.kind)
{
@@ -284,25 +376,68 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
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;
end = loc.uc + 2;
break;
+#ifdef JIT_NEEDS_LITERAL_POOL
+ case JIT_RELOC_JMP_WITH_VENEER: {
+ int32_t voff = read_jmp_offset(loc.ui);
+ uint8_t *target = pc_base + (voff << reloc.rsh);
+ if (target == loc.uc) {
+ // PC still in range to reify direct branch.
+ if (offset_in_jmp_range(diff)) {
+ // Target also in range: reify direct branch.
+ patch_jmp_offset(loc.ui, diff);
+ remove_pending_literal(_jit, reloc);
+ } else {
+ // Target out of range; branch to veneer.
+ patch_pending_literal(_jit, reloc, (uintptr_t) addr);
+ }
+ } else {
+ // Already emitted a veneer. In this case, patch the veneer
+ // directly.
+ patch_veneer((uint32_t *) target, addr);
+ }
+ return;
+ }
+ case JIT_RELOC_JCC_WITH_VENEER: {
+ int32_t voff = read_jcc_offset(loc.ui);
+ uint8_t *target = pc_base + (voff << reloc.rsh);
+ if (target == loc.uc) {
+ if (offset_in_jcc_range(diff)) {
+ patch_jcc_offset(loc.ui, diff);
+ remove_pending_literal(_jit, reloc);
+ } else {
+ patch_pending_literal(_jit, reloc, (uintptr_t) addr);
+ }
+ } else {
+ patch_veneer((uint32_t *) target, addr);
+ }
+ return;
+ }
+ case JIT_RELOC_LOAD_FROM_POOL: {
+ int32_t voff = read_load_from_pool_offset(loc.ui);
+ uint8_t *target = pc_base + (voff << reloc.rsh);
+ if (target == loc.uc) {
+ patch_pending_literal(_jit, reloc, (uintptr_t) addr);
+ } else {
+ *(uintptr_t *) target = (uintptr_t) addr;
+ }
+ return;
+ }
+#endif
case JIT_RELOC_REL32:
- diff = ((uint8_t*)addr) - (loc.uc + 4);
ASSERT (INT32_MIN <= diff && diff <= INT32_MAX);
*loc.ui = diff;
end = loc.uc + 4;
break;
case JIT_RELOC_REL64:
- diff = ((uint8_t*)addr) - (loc.uc + 8);
*loc.ul = diff;
end = loc.uc + 8;
break;
@@ -403,6 +538,45 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr)
FOR_EACH_INSTRUCTION(IMPL_INSTRUCTION)
#undef IMPL_INSTRUCTION
+void
+jit_align(jit_state_t *_jit, unsigned align)
+{
+ ASSERT (is_power_of_two (align));
+ uintptr_t here = _jit->pc.w;
+ uintptr_t there = (here + align - 1) & ~(align - 1);
+ if (there - here)
+ nop(_jit, there - here);
+}
+
+static jit_bool_t
+is_fpr_arg(enum jit_operand_abi arg)
+{
+ switch (arg)
+ {
+ case JIT_OPERAND_ABI_UINT8:
+ case JIT_OPERAND_ABI_INT8:
+ case JIT_OPERAND_ABI_UINT16:
+ case JIT_OPERAND_ABI_INT16:
+ case JIT_OPERAND_ABI_UINT32:
+ case JIT_OPERAND_ABI_INT32:
+ case JIT_OPERAND_ABI_UINT64:
+ case JIT_OPERAND_ABI_INT64:
+ case JIT_OPERAND_ABI_POINTER:
+ return 0;
+ case JIT_OPERAND_ABI_FLOAT:
+ case JIT_OPERAND_ABI_DOUBLE:
+ return 1;
+ default:
+ abort();
+ }
+}
+
+static jit_bool_t
+is_gpr_arg(enum jit_operand_abi arg)
+{
+ return !is_fpr_arg(arg);
+}
+
static void
abi_imm_to_gpr(jit_state_t *_jit, enum jit_operand_abi abi, jit_gpr_t dst,
intptr_t imm)
@@ -570,10 +744,10 @@ abi_mem_to_mem(jit_state_t *_jit, enum jit_operand_abi abi, jit_gpr_t base,
abi_gpr_to_mem(_jit, abi, base, offset, tmp);
unget_temp_gpr(_jit);
} else {
- jit_fpr_t tmp = get_temp_xpr(_jit);
+ jit_fpr_t tmp = get_temp_fpr(_jit);
abi_mem_to_fpr(_jit, abi, tmp, src_base, src_offset);
abi_fpr_to_mem(_jit, abi, base, offset, tmp);
- unget_temp_xpr(_jit);
+ unget_temp_fpr(_jit);
}
}
@@ -609,7 +783,11 @@ move_operand(jit_state_t *_jit, jit_operand_t dst, jit_operand_t src)
src.loc.mem.offset);
case MOVE_FPR_TO_FPR:
- return jit_movr_d(_jit, dst.loc.fpr, src.loc.fpr);
+ ASSERT(src.abi == dst.abi);
+ if (src.abi == JIT_OPERAND_ABI_DOUBLE)
+ return jit_movr_d(_jit, dst.loc.fpr, src.loc.fpr);
+ else
+ return jit_movr_f(_jit, dst.loc.fpr, src.loc.fpr);
case MOVE_MEM_TO_FPR:
return abi_mem_to_fpr(_jit, src.abi, dst.loc.fpr, src.loc.mem.base,
@@ -704,7 +882,7 @@ move_one(jit_state_t *_jit, jit_operand_t *dst, jit_operand_t *src,
jit_operand_t tmp;
if (is_fpr_arg (src[j].kind)) {
tmp_fpr = 1;
- tmp = jit_operand_fpr(src[j].abi, get_temp_xpr(_jit));
+ tmp = jit_operand_fpr(src[j].abi, get_temp_fpr(_jit));
} else {
tmp_gpr = 1;
/* Preserve addend, if any, from source operand, to be applied
@@ -729,7 +907,7 @@ move_one(jit_state_t *_jit, jit_operand_t *dst, jit_operand_t *src,
if (tmp_gpr)
unget_temp_gpr(_jit);
else if (tmp_fpr)
- unget_temp_xpr(_jit);
+ unget_temp_fpr(_jit);
}
static void
@@ -849,10 +1027,11 @@ jit_shrink_stack(jit_state_t *_jit, size_t diff)
_jit->frame_size -= diff;
}
-static const jit_gpr_t V[] = {
-#ifdef JIT_VTMP
- JIT_VTMP ,
-#endif
+static const jit_gpr_t platform_callee_save_gprs[] = {
+ JIT_PLATFORM_CALLEE_SAVE_GPRS
+};
+
+static const jit_gpr_t user_callee_save_gprs[] = {
JIT_V0, JIT_V1, JIT_V2
#ifdef JIT_V3
, JIT_V3
@@ -869,12 +1048,15 @@ static const jit_gpr_t V[] = {
#ifdef JIT_V7
, JIT_V7
#endif
+#ifdef JIT_V8
+ , JIT_V8
+#endif
+#ifdef JIT_V9
+ , JIT_V9
+#endif
};
-static const jit_fpr_t VF[] = {
-#ifdef JIT_VFTMP
- JIT_VFTMP ,
-#endif
+static const jit_fpr_t user_callee_save_fprs[] = {
#ifdef JIT_VF0
JIT_VF0
#endif
@@ -901,55 +1083,54 @@ static const jit_fpr_t VF[] = {
#endif
};
-static const size_t v_count = sizeof(V) / sizeof(V[0]);
-static const size_t vf_count = sizeof(VF) / sizeof(VF[0]);
+#define ARRAY_SIZE(X) (sizeof (X)/sizeof ((X)[0]))
+static const size_t pv_count = ARRAY_SIZE(platform_callee_save_gprs);
+static const size_t v_count = ARRAY_SIZE(user_callee_save_gprs);
+static const size_t vf_count = ARRAY_SIZE(user_callee_save_fprs);
size_t
jit_enter_jit_abi(jit_state_t *_jit, size_t v, size_t vf, size_t frame_size)
{
-#ifdef JIT_VTMP
- v++;
-#endif
-#ifdef JIT_VFTMP
- vf++;
-#endif
-
ASSERT(v <= v_count);
ASSERT(vf <= vf_count);
ASSERT(_jit->frame_size == 0);
_jit->frame_size = jit_initial_frame_size();
- /* Save values of callee-save registers. */
- for (size_t i = 0; i < v; i++)
- jit_pushr (_jit, V[i]);
- for (size_t i = 0; i < vf; i++)
- jit_pushr_d (_jit, VF[i]);
+ size_t reserved =
+ jit_align_stack(_jit, (pv_count + v) * (__WORDSIZE / 8) + vf * 8);
+
+ size_t offset = 0;
+ for (size_t i = 0; i < vf; i++, offset += 8)
+ jit_stxi_d(_jit, offset, JIT_SP, user_callee_save_fprs[i]);
+ for (size_t i = 0; i < v; i++, offset += __WORDSIZE / 8)
+ jit_stxi(_jit, offset, JIT_SP, user_callee_save_gprs[i]);
+ for (size_t i = 0; i < pv_count; i++, offset += __WORDSIZE / 8)
+ jit_stxi(_jit, offset, JIT_SP, platform_callee_save_gprs[i]);
+ ASSERT(offset <= reserved);
- return jit_align_stack(_jit, frame_size);
+ return reserved;
}
void
jit_leave_jit_abi(jit_state_t *_jit, size_t v, size_t vf, size_t frame_size)
{
-#ifdef JIT_VTMP
- v++;
-#endif
-#ifdef JIT_VFTMP
- vf++;
-#endif
-
- jit_shrink_stack(_jit, frame_size);
+ ASSERT(v <= v_count);
+ ASSERT(vf <= vf_count);
+ ASSERT((pv_count + v) * (__WORDSIZE / 8) + vf * 8 <= frame_size);
- /* Restore callee-save registers. */
- for (size_t i = 0; i < vf; i++)
- jit_popr_d (_jit, VF[vf - i - 1]);
+ size_t offset = 0;
+ for (size_t i = 0; i < vf; i++, offset += 8)
+ jit_ldxi_d(_jit, user_callee_save_fprs[i], JIT_SP, offset);
+ for (size_t i = 0; i < v; i++, offset += __WORDSIZE / 8)
+ jit_ldxi(_jit, user_callee_save_gprs[i], JIT_SP, offset);
+ for (size_t i = 0; i < pv_count; i++, offset += __WORDSIZE / 8)
+ jit_ldxi(_jit, platform_callee_save_gprs[i], JIT_SP, offset);
+ ASSERT(offset <= frame_size);
- for (size_t i = 0; i < v; i++)
- jit_popr (_jit, V[v - i - 1]);
+ jit_shrink_stack(_jit, frame_size);
}
-
// Precondition: stack is already aligned.
static size_t
prepare_call_args(jit_state_t *_jit, size_t argc, jit_operand_t args[])
@@ -969,7 +1150,7 @@ prepare_call_args(jit_state_t *_jit, size_t argc, jit_operand_t args[])
for (size_t i = 0; i < argc; i++) {
switch(args[i].kind) {
case JIT_OPERAND_KIND_GPR:
- if (jit_same_gprs (args[i].loc.mem.base, JIT_SP))
+ if (jit_same_gprs (args[i].loc.gpr.gpr, JIT_SP))
args[i].loc.gpr.addend += stack_size;
break;
case JIT_OPERAND_KIND_MEM:
@@ -1029,3 +1210,147 @@ jit_load_args(jit_state_t *_jit, size_t argc, jit_operand_t args[])
jit_locate_args(_jit, argc, src);
jit_move_operands(_jit, args, src, argc);
}
+
+#ifdef JIT_NEEDS_LITERAL_POOL
+#define INITIAL_LITERAL_POOL_CAPACITY 12
+static struct jit_literal_pool*
+alloc_literal_pool(jit_state_t *_jit, size_t capacity)
+{
+ if (capacity == 0) capacity = INITIAL_LITERAL_POOL_CAPACITY;
+
+ struct jit_literal_pool *ret =
+ _jit->alloc (sizeof (struct jit_literal_pool) +
+ sizeof (struct jit_literal_pool_entry) * capacity);
+ ASSERT (ret);
+ ret->deadline = -1;
+ ret->size = 0;
+ ret->capacity = capacity;
+ return ret;
+}
+
+static void
+clear_literal_pool(struct jit_literal_pool *pool)
+{
+ pool->deadline = -1;
+ pool->size = 0;
+}
+
+static void
+grow_literal_pool(jit_state_t *_jit)
+{
+ struct jit_literal_pool *new_pool =
+ alloc_literal_pool(_jit, _jit->pool->capacity * 2);
+
+ for (size_t i = 0; i < _jit->pool->size; i++)
+ new_pool->entries[new_pool->size++] = _jit->pool->entries[i];
+ new_pool->deadline = _jit->pool->deadline;
+
+ _jit->free (_jit->pool);
+ _jit->pool = new_pool;
+}
+
+static void
+add_literal_pool_entry(jit_state_t *_jit, struct jit_literal_pool_entry entry,
+ ptrdiff_t max_offset)
+{
+ if (_jit->pool->size == _jit->pool->capacity)
+ grow_literal_pool (_jit);
+
+ max_offset <<= entry.reloc.rsh;
+ ptrdiff_t deadline =
+ _jit->pc.uc - _jit->start + max_offset - _jit->pool->byte_size;
+ if (_jit->pool->size == 0)
+ // Assume that we might need a uint32_t for alignment, and another
+ // to branch over the table.
+ _jit->pool->deadline = deadline - 2 * sizeof(uint32_t);
+ else if (deadline < _jit->pool->deadline)
+ _jit->pool->deadline = deadline;
+
+ // Assume that each entry takes a max of 16 bytes.
+ _jit->pool->byte_size += 16;
+
+ _jit->pool->entries[_jit->pool->size++] = entry;
+}
+
+static void
+add_pending_literal(jit_state_t *_jit, jit_reloc_t src,
+ ptrdiff_t max_offset_bits)
+{
+ struct jit_literal_pool_entry entry = { src, 0 };
+ add_literal_pool_entry(_jit, entry,
+ (1 << (max_offset_bits + src.rsh)) - 1);
+}
+
+static void
+remove_pending_literal(jit_state_t *_jit, jit_reloc_t src)
+{
+ for (size_t i = _jit->pool->size; i--; ) {
+ if (_jit->pool->entries[i].reloc.offset == src.offset) {
+ for (size_t j = i + 1; j < _jit->pool->size; j++)
+ _jit->pool->entries[j-1] = _jit->pool->entries[j];
+ _jit->pool->size--;
+ return;
+ }
+ }
+ abort();
+}
+
+static void
+patch_pending_literal(jit_state_t *_jit, jit_reloc_t src, uint64_t value)
+{
+ for (size_t i = _jit->pool->size; i--; ) {
+ if (_jit->pool->entries[i].reloc.offset == src.offset) {
+ ASSERT(_jit->pool->entries[i].value == 0);
+ _jit->pool->entries[i].value = value;
+ return;
+ }
+ }
+ abort();
+}
+
+static void
+emit_literal_pool(jit_state_t *_jit, enum guard_pool guard)
+{
+ _jit->pool->deadline = -1;
+
+ if (!_jit->pool->size)
+ return;
+
+ jit_reloc_t skip;
+ if (guard == GUARD_NEEDED)
+ skip = jit_jmp(_jit);
+
+ // FIXME: Could de-duplicate constants.
+ for (size_t i = 0; i < _jit->pool->size; i++) {
+ jit_align(_jit, 8);
+ struct jit_literal_pool_entry *entry = &_jit->pool->entries[i];
+ uint8_t *loc = _jit->start + entry->reloc.offset;
+ uint8_t *pc_base =
+ loc - entry->reloc.inst_start_offset + entry->reloc.pc_base_offset;
+ ptrdiff_t diff = _jit->pc.uc - pc_base;
+ diff >>= entry->reloc.rsh;
+
+ switch (entry->reloc.kind) {
+ case JIT_RELOC_JMP_WITH_VENEER:
+ patch_jmp_offset((uint32_t*) loc, diff);
+ emit_veneer(_jit, (void*) (uintptr_t) entry->value);
+ break;
+ case JIT_RELOC_JCC_WITH_VENEER:
+ patch_jcc_offset((uint32_t*) loc, diff);
+ emit_veneer(_jit, (void*) (uintptr_t) entry->value);
+ break;
+ case JIT_RELOC_LOAD_FROM_POOL:
+ patch_load_from_pool_offset((uint32_t*) loc, diff);
+ emit_u64(_jit, entry->value);
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (guard == GUARD_NEEDED)
+ jit_patch_here(_jit, skip);
+
+ clear_literal_pool(_jit->pool);
+}
+#endif