}
}
+/*
+ * Reset value on restart.
+ */
+static void
+reset_value(jit_value_t value)
+{
+ value->reg = -1;
+ value->in_register = 0;
+ value->in_global_register = 0;
+ value->in_frame = 0;
+}
+
+/*
+ * Clean up the compilation state on restart.
+ */
+static void
+cleanup_on_restart(jit_gencode_t gen, jit_function_t func)
+{
+ jit_block_t block;
+ jit_insn_iter_t iter;
+ jit_insn_t insn;
+
+#ifdef _JIT_COMPILE_DEBUG
+ printf("\n*** Restart compilation ***\n\n");
+#endif
+
+ block = 0;
+ while((block = jit_block_next(func, block)) != 0)
+ {
+ /* Clear the block addresses and fixup lists */
+ block->address = 0;
+ block->fixup_list = 0;
+ block->fixup_absolute_list = 0;
+
+ /* Reset values referred to by block instructions */
+ jit_insn_iter_init(&iter, block);
+ while((insn = jit_insn_iter_next(&iter)) != 0)
+ {
+ if(insn->dest && (insn->flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
+ {
+ reset_value(insn->dest);
+ }
+ if(insn->value1 && (insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
+ {
+ reset_value(insn->value1);
+ }
+ if(insn->value2 && (insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
+ {
+ reset_value(insn->value2);
+ }
+ }
+ }
+
+ /* Reset values referred to by builder */
+ if(func->builder->setjmp_value)
+ {
+ reset_value(func->builder->setjmp_value);
+ }
+ if(func->builder->parent_frame)
+ {
+ reset_value(func->builder->parent_frame);
+ }
+
+ /* Reset the "touched" registers mask. The first time compilation
+ might have followed wrong code paths and thus allocated wrong
+ registers. */
+ if(func->builder->has_tail_call)
+ {
+ /* For functions with tail calls _jit_regs_alloc_global()
+ does not allocate any global registers. The "permanent"
+ mask has all global registers set to prevent their use. */
+ gen->touched = jit_regused_init;
+ }
+ else
+ {
+ gen->touched = gen->permanent;
+ }
+}
+
/*
* Compile a function and return its entry point.
*/
/* End the function's output process */
result = _jit_cache_end_method(&(gen.posn));
- /* If we need to restart on a different cache page, then clear
- the block addresses and fixup lists */
+ /* If we need to restart on a different cache page, then clean up
+ the compilation state */
if(result == JIT_CACHE_END_RESTART)
{
- block = 0;
- while((block = jit_block_next(func, block)) != 0)
- {
- block->address = 0;
- block->fixup_list = 0;
- block->fixup_absolute_list = 0;
- }
+ cleanup_on_restart(&gen, func);
}
}
while(result == JIT_CACHE_END_RESTART);
#define CLOBBER_OTHER_REG 4
#ifdef JIT_REG_DEBUG
+#include <stdlib.h>
+
static void dump_regs(jit_gencode_t gen, const char *name)
{
int reg, index;
return 0;
}
+/*
+ * Exchange the content of two value descriptors.
+ */
static void
swap_values(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
{
return 0;
}
+/*
+ * Check if the register contains any values either dead or alive
+ * that may need to be evicted from it.
+ */
+static int
+is_register_occupied(jit_gencode_t gen, _jit_regs_t *regs, int reg)
+{
+ if(reg < 0)
+ {
+ return 0;
+ }
+
+ /* Assume that a global register is always alive unless it is to be
+ computed right away. */
+ if(jit_reg_is_used(gen->permanent, reg))
+ {
+ if(!regs->ternary
+ && regs->descs[0].value
+ && regs->descs[0].value->has_global_register
+ && regs->descs[0].value->global_reg == reg)
+ {
+ return 0;
+ }
+ return 1;
+ }
+
+ if(gen->contents[reg].is_long_end)
+ {
+ reg = get_long_pair_start(reg);
+ }
+ if(gen->contents[reg].num_values)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* Determine the effect of using a register for a value. This includes the
* following:
}
flags = CLOBBER_NONE;
- if(is_register_alive(gen, regs, reg))
+ if(is_register_occupied(gen, regs, reg))
{
flags |= CLOBBER_REG;
}
- if(is_register_alive(gen, regs, other_reg))
+ if(is_register_occupied(gen, regs, other_reg))
{
flags |= CLOBBER_OTHER_REG;
}
}
}
- if(is_register_alive(gen, regs, reg))
+ if(is_register_occupied(gen, regs, reg))
{
flags |= CLOBBER_REG;
}
- if(is_register_alive(gen, regs, other_reg))
+ if(is_register_occupied(gen, regs, other_reg))
{
flags |= CLOBBER_OTHER_REG;
}
still_in_frame = 0;
}
+#ifdef JIT_REG_DEBUG
+ if(gen->contents[reg].num_values == JIT_MAX_REG_VALUES)
+ {
+ printf("*** Too many values for one register! ***\n");
+ abort();
+ }
+#endif
+
gen->contents[reg].values[gen->contents[reg].num_values] = value;
++(gen->contents[reg].num_values);
gen->contents[reg].age = gen->current_age;
printf("spill_clobbered_register(reg = %d)\n", reg);
#endif
- /* Find the other register in a long pair */
- if(gen->contents[reg].is_long_start)
- {
- other_reg = OTHER_REG(reg);
- }
- else if(gen->contents[reg].is_long_end)
- {
- other_reg = reg;
- reg = get_long_pair_start(reg);
- }
- else
- {
- other_reg = -1;
- }
-
- /* Spill register contents in two passes. First free values that
- do not reqiure spilling then spill those that do. This approach
- is only useful in case a stack register contains both kinds of
- values and the last value is one that does not require spilling.
- This way we may save one free instruction. */
+#ifdef JIT_REG_STACK
+ /* For a stack register spill it in two passes. First drop values that
+ reqiure neither spilling nor a generation of the free instruction.
+ Then lazily exchange the register with the top and spill or free it
+ as necessary. This approach might save a exch/free instructions in
+ certain cases. */
if(IS_STACK_REG(reg))
{
for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
{
+ if(gen->contents[reg].num_values == 1)
+ {
+ break;
+ }
+
value = gen->contents[reg].values[index];
usage = value_usage(regs, value);
- if((usage & VALUE_INPUT) == 0
- && ((usage & VALUE_DEAD) != 0 || value->in_frame))
+ if((usage & VALUE_INPUT) != 0)
{
- free_value(gen, value, reg, other_reg, 0);
+ continue;
+ }
+ if((usage & VALUE_DEAD) != 0 || value->in_frame)
+ {
+ unbind_value(gen, value, reg, -1);
}
}
- }
- for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
- {
- value = gen->contents[reg].values[index];
- usage = value_usage(regs, value);
- if((usage & VALUE_DEAD) == 0)
+ for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
{
- if((usage & VALUE_INPUT) == 0)
+ int top;
+
+ value = gen->contents[reg].values[index];
+ usage = value_usage(regs, value);
+ if((usage & VALUE_INPUT) != 0)
{
- save_value(gen, value, reg, other_reg, 1);
+ if((usage & VALUE_DEAD) != 0 || value->in_frame)
+ {
+ continue;
+ }
+
+ top = gen->reg_stack_top - 1;
+ if(reg != top)
+ {
+ exch_stack_top(gen, reg, 0);
+ reg = top;
+ }
+
+ save_value(gen, value, reg, -1, 0);
}
else
{
- save_value(gen, value, reg, other_reg, 0);
+ top = gen->reg_stack_top - 1;
+ if(reg != top)
+ {
+ exch_stack_top(gen, reg, 0);
+ reg = top;
+ }
+
+ if((usage & VALUE_DEAD) != 0 || value->in_frame)
+ {
+ free_value(gen, value, reg, -1, 0);
+ }
+ else
+ {
+ save_value(gen, value, reg, -1, 1);
+ }
}
}
+ }
+ else
+#endif
+ {
+ /* Find the other register in a long pair */
+ if(gen->contents[reg].is_long_start)
+ {
+ other_reg = OTHER_REG(reg);
+ }
+ else if(gen->contents[reg].is_long_end)
+ {
+ other_reg = reg;
+ reg = get_long_pair_start(reg);
+ }
else
{
- if((usage & VALUE_INPUT) == 0)
+ other_reg = -1;
+ }
+
+ for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+ {
+ value = gen->contents[reg].values[index];
+ usage = value_usage(regs, value);
+ if((usage & VALUE_DEAD) == 0)
+ {
+ if((usage & VALUE_INPUT) == 0)
+ {
+ save_value(gen, value, reg, other_reg, 1);
+ }
+ else
+ {
+ save_value(gen, value, reg, other_reg, 0);
+ }
+ }
+ else
{
- free_value(gen, value, reg, other_reg, 0);
+ if((usage & VALUE_INPUT) == 0)
+ {
+ free_value(gen, value, reg, other_reg, 0);
+ }
}
}
}
}
#endif
-static void
-abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
-{
- _jit_regdesc_t *desc;
- int reg, other_reg;
-
-#ifdef JIT_REG_DEBUG
- printf("abort_input_value(%d)\n", index);
-#endif
-
- desc = ®s->descs[index];
- if(!desc->value || desc->duplicate)
- {
- return;
- }
-
- if(desc->load && desc->value->in_register)
- {
- reg = desc->value->reg;
- if(gen->contents[reg].is_long_start)
- {
- other_reg = OTHER_REG(reg);
- }
- else
- {
- other_reg = -1;
- }
- unbind_value(gen, desc->value, reg, other_reg);
-#ifdef JIT_REG_STACK
- if(IS_STACK_REG(reg))
- {
- --(gen->reg_stack_top);
- }
-#endif
- }
-}
-
#ifdef JIT_REG_STACK
static void
pop_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
if(IS_STACK_REG(reg))
{
int top = gen->reg_stack_top - 1;
-
/* spill top registers if there are any that needs to be */
- for(; top > reg && jit_reg_is_used(regs->clobber, top); top--)
+ for(; top >= reg && jit_reg_is_used(regs->clobber, top); top--)
{
spill_clobbered_register(gen, regs, top);
/* If an input value is on the top then it stays there
- and the top does not change. */
+ and the top position does not change. */
if(gen->contents[top].num_values > 0)
{
break;
}
}
- /* If the top register was not spilled then exchange it with
- the current register. */
if(top > reg)
{
- exch_stack_top(gen, reg, 0);
- }
- /* Finally spill the register */
- if(top >= JIT_REG_STACK_START)
- {
- spill_clobbered_register(gen, regs, top);
+ spill_clobbered_register(gen, regs, reg);
}
}
else
#endif
}
-void
-_jit_regs_abort(jit_gencode_t gen, _jit_regs_t *regs)
-{
- abort_input_value(gen, regs, 2);
- abort_input_value(gen, regs, 1);
- if(regs->ternary)
- {
- abort_input_value(gen, regs, 0);
- }
-}
-
unsigned char *
_jit_regs_inst_ptr(jit_gencode_t gen, int space)
{
unsigned char *
_jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space)
{
- unsigned char *inst;
-
if(!_jit_regs_assign(gen, regs))
{
return 0;
return 0;
}
- inst = _jit_regs_inst_ptr(gen, space);
- if(!inst)
- {
- _jit_regs_abort(gen, regs);
- }
-
- return inst;
+ return _jit_regs_inst_ptr(gen, space);
}
void