src/jit.c - JIT


JIT (Just In Time) compilation converts bytecode to native machine code instructions and executes the generated instruction sequence directly.

Functions ^

static void insert_fixup_targets(Interp *interpreter, char *branch, size_t limit)

Look at fixups, mark all fixup entries as branch target.

TODO: actually this is wrong: fixups belong only to one code segment. The code below doesn't check, for which segments the fixups are inserted.

static void make_branch_list(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, opcode_t *cur_op, opcode_t *code_start, opcode_t *code_end)

optimizer->map_branch parallels the opcodes with a list of branch information and register mapping information

branch instructions have JIT_BRANCH_SOURCE

opcodes jumped to have JIT_BRANCH_TARGET

mapped arguments have register type + 1 and finally

after register allocation these have the processor register that got mapped

static void set_register_usage(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, Parrot_jit_optimizer_section_ptr cur_section, op_info_t *op_info, opcode_t *cur_op, opcode_t *code_start)

Sets the register usage counts.

static void make_sections(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, opcode_t *cur_op, opcode_t *code_start, opcode_t *code_end)

I386 has JITed vtables, which have the vtable# in extcall.

This Parrot_jit_vtable_n_op() does use register mappings.

static void make_branch_targets(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, opcode_t *code_start)

Makes the branch targets.

static void sort_registers(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, opcode_t *code_start)

Sorts the Parrot registers prior to mapping them to actual hardware registers.

static void assign_registers(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, Parrot_jit_optimizer_section_ptr cur_section, opcode_t *code_start, int from_imcc)

Called by map_registers() to actually assign the Parrot registers to hardware registers.

static void map_registers(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, opcode_t *code_start)

Maps the most used Parrot registers to hardware registers.

static void debug_sections(Interp *interpreter, Parrot_jit_optimizer_t *optimizer, opcode_t *code_start)

Prints out debugging info.

static Parrot_jit_optimizer_t *optimize_jit(Interp *interpreter, opcode_t *cur_op, opcode_t *code_start, opcode_t *code_end)

Called by build_asm() to initialize the optimizer.

static Parrot_jit_optimizer_t *optimize_imcc_jit(Interp *interpreter, opcode_t *cur_op, opcode_t *code_start, opcode_t *code_end, struct PackFile_Segment *jit_seg)

Generate optimizer stuff from the _JIT section in the packfile.

static char *reg_addr(Interp *interpreter, int typ, int i)

Returns the address of register typ[i].

static void Parrot_jit_load_registers(Parrot_jit_info_t *jit_info, Interp *interpreter)

Load registers for the current section from parrot to processor registers.

static void Parrot_jit_save_registers(Parrot_jit_info_t *jit_info, Interp *interpreter)

Save registers for the current section.

void Parrot_destroy_jit(void *ptr)

Frees the memory used by the JIT subsystem.

jit_f build_asm(Interp *interpreter, opcode_t *pc, opcode_t *code_start, opcode_t *code_end, void *objfile)

This is the main function of the JIT code generator.

It loops over the bytecode, calling the code generating routines for each opcode.

The information obtained is used to perform certain types of fixups on native code, as well as by the native code itself to convert bytecode program counters values to hardware program counter values.

void Parrot_jit_newfixup(Parrot_jit_info_t *jit_info)

Remember the current position in the native code for later update.


include/parrot/jit.h, docs/jit.pod and src/jit_debug.c.