Skip to content

Commit

Permalink
Working on macro threaded ops
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Phoenix committed Feb 13, 2008
1 parent 886c3fe commit 142b22e
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 94 deletions.
16 changes: 14 additions & 2 deletions kernel/core/iseq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ class InstructionSet
{:opcode => :push_ivar, :args => [:literal], :stack => [0,1]},
{:opcode => :goto_if_defined, :args => [:ip], :stack => [1,0],
:flow => :goto},
{:opcode => :push_const, :args => [:literal], :stack => [0,1]},
{:opcode => :push_const, :args => [:literal], :stack => [0,1], :flow => :send},
{:opcode => :set_const, :args => [:literal], :stack => [1,1],
:vm_flags => []},
{:opcode => :set_const_at, :args => [:literal], :stack => [2,0],
:vm_flags => []},
{:opcode => :find_const, :args => [:literal], :stack => [1,1]},
{:opcode => :find_const, :args => [:literal], :stack => [1,1], :flow => :send},
{:opcode => :attach_method, :args => [:literal], :stack => [2,1],
:vm_flags => [:check_interrupts]},
{:opcode => :add_method, :args => [:literal], :stack => [2,1],
Expand Down Expand Up @@ -288,6 +288,18 @@ def flow
@opcode_info[:flow] || :sequential
end

# Indicates if this instruction terminates a basic block. Used
# for translating the bytecode into macro ops.
def final?
[:send, :return].include? @opcode_info[:flow]
end

# Indicates that this is a goto, and thus the target must be
# the first instruction in a basic block.
def goto?
@opcode_info[:flow] == :goto
end

def to_s
@opcode_info[:opcode].to_s
end
Expand Down
4 changes: 4 additions & 0 deletions shotgun/lib/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ int cpu_simple_return(STATE, cpu c, OBJECT val);
void cpu_save_registers(STATE, cpu c, int offset);
void cpu_yield_debugger_check(STATE, cpu c);

void cpu_activate_method(STATE, cpu c, struct message *msg);
OBJECT cpu_open_module(STATE, cpu c, OBJECT under, OBJECT sym);
void cpu_send_message(STATE, cpu c, struct message *msg);

OBJECT cpu_const_get_in_context(STATE, cpu c, OBJECT sym);
OBJECT cpu_const_get_from(STATE, cpu c, OBJECT sym, OBJECT under);

Expand Down
247 changes: 224 additions & 23 deletions shotgun/lib/cpu_instructions.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ void cpu_show_lookup_time(STATE) {

#if DIRECT_THREADED
#include "shotgun/lib/instruction_funcs.gen"
DT_ADDRESSES;

#ifdef SHOW_OPS
#define NEXT_OP printf(" => %p\n", *ip_ptr); sassert(*ip_ptr); goto **ip_ptr++
Expand Down Expand Up @@ -407,6 +406,205 @@ static inline OBJECT cpu_check_serial(STATE, cpu c, OBJECT obj, OBJECT sym, int
return Qfalse;
}

const char *cpu_op_to_name(STATE, uint32_t op) {
#include "shotgun/lib/instruction_names.h"
return get_instruction_name(op);
}


/* Functions to translating the bytecode into a macro op series. */
#if DIRECT_THREADED

struct ins2block {
int block;
int jump_target;
int first;
};

/* the noop instruction contains NEXT_OP(), so we used it to copy
* the code to just move to the next instruction. */
#define INS_NEXT 0

void calculate_macro_size(STATE, OBJECT comp, OBJECT exc_table,
int *out, struct ins2block *tbl) {
OBJECT ent;
uint32_t *bytecode;
uint32_t op;
int args, total, i, size, cur_block;
int block_size;

/* Pull in jump targets from the exception table */
total = NUM_FIELDS(exc_table);
for(i = 0; i < total; i++) {
ent = tuple_at(state, exc_table, i);
native_int target = N2I(tuple_at(state, ent, 2));
tbl[target].jump_target = TRUE;
}

bytecode = (uint32_t*)BYTES_OF(comp);
total = NUM_FIELDS(comp);

size = 0;

/* Step 1: find all the jump targets and mark them. */

for(i = 0; i < total; i++) {
op = *bytecode++;
if(!op) continue;
args = _ip_size(op) - 1;

if(ins_info[op].jump) {
uint32_t target = *bytecode;
tbl[target].jump_target = TRUE;
}

i += args;
bytecode += args;
}

/* Step 2: calculate the block for each op */
bytecode = (uint32_t*)BYTES_OF(comp);

cur_block = 0;
block_size = 0;

for(i = 0; i < total; i++) {
op = *bytecode++;
if(!op) continue;
args = _ip_size(op) - 1;
size += ins_info[op].size;

if(tbl[i].jump_target) {
if(block_size > 1) {
cur_block++;
block_size = 0;
}
}

if(i > 0 && block_size == 0) tbl[i].first = TRUE;

block_size++;

tbl[i].block = cur_block;

if(ins_info[op].final) {
size += ins_info[INS_NEXT].size;
cur_block++;
block_size = 0;
}

i += args;
bytecode += args;
}

*out = size;
}

OBJECT create_macro(STATE, OBJECT exc_tbl, OBJECT in) {
OBJECT bc;
int macro_size;
int cur_block, total, i;

void *macro;
uint8_t *macro_ptr;
struct ins2block *tbl;
uint32_t *bytecode;
uint32_t op;
uintptr_t *macro_bc, *bc_ptr;

int bc_offset = 0;

#if !CONFIG_BIG_ENDIAN
int target_size = BYTEARRAY_SIZE(in) * sizeof(uintptr_t);
bc = bytearray_new(state, target_size);
iseq_flip(state, in, bc);
#else
bc = in;
#endif

bytecode = (uint32_t*)BYTES_OF(bc);
total = NUM_FIELDS(bc);

tbl = (struct ins2block*)calloc(NUM_FIELDS(bc), sizeof(struct ins2block));

calculate_macro_size(state, bc, exc_tbl, &macro_size, tbl);

/* we use one chunk of memory for both the new bytecode stream and the
* code for each macro. */

macro_size += sizeof(uintptr_t) * total;

macro_bc = (uintptr_t*)malloc(macro_size);
memset(macro_bc, 0, macro_size);

macro = (void*)(macro_bc + total);

cur_block = 0;

/* macro_bc is the converted instruction sequence. It's a mix of addresses and
* ints. The addresses are the start of a basic block, then ints are argumens
* to the instructions that make up the basic block. */

bc_ptr = macro_bc;
macro_ptr = (uint8_t*)macro;

/* Initialize the first block. */
*bc_ptr++ = (uintptr_t)macro;
bc_offset++;

printf("macro size: %d\n", macro_size);
printf("block 0: %p\n", macro_ptr);

for(i = 0; i < total; i++) {
op = *bytecode++;
if(!op) continue;

printf("[%3d] %3d (%20s), block %d (%d)\n", i, op, cpu_op_to_name(state, op), tbl[i].block, ins_info[op].size);

/* We've hit an instruction that must be the first instruction
* in a block. We fix up the current block and start a new one. */
if(tbl[i].first) {
/* Copy NEXT_OP into the end of the current block */
memcpy(macro_ptr, ins_info[INS_NEXT].start, ins_info[INS_NEXT].size);
macro_ptr += ins_info[INS_NEXT].size;

/* Stick the block number into instruction sequence. */
bc_offset += 2;
*bc_ptr++ = bc_offset;
*bc_ptr++ = (uintptr_t)macro_ptr;

printf("block %d: %p\n", tbl[i].block, macro_ptr);
}

/* Copy the code for this operation into the macro */
memcpy(macro_ptr, ins_info[op].start, ins_info[op].size);
macro_ptr += ins_info[op].size;

/* Copy the args to this op into the instruction stream */

switch(_ip_size(op) - 1) {
case 2:
printf(" arg: %d\n", *bytecode);
*bc_ptr++ = (uintptr_t)(*bytecode++);
bc_offset++;
i++;
/* fallow through */
case 1:
printf(" arg: %d\n", *bytecode);
*bc_ptr++ = (uintptr_t)(*bytecode++);
bc_offset++;
i++;
break;
}
}

OBJECT ptr = ffi_new_pointer(state, macro_bc);
ffi_autorelease(ptr, 1);
return ptr;
}

#endif

OBJECT cpu_compile_method(STATE, OBJECT cm) {
OBJECT ba, bc;
int target_size;
Expand All @@ -428,22 +626,14 @@ OBJECT cpu_compile_method(STATE, OBJECT cm) {
ba = bytearray_new(state, target_size);
}

#if DIRECT_THREADED
ba = create_macro(state, cmethod_get_exceptions(cm), bc);
cmethod_set_compiled(cm, ba);
#else
cpu_compile_instructions(state, bc, ba);
#endif
cmethod_set_compiled(cm, ba);

/* Allocate a tuple to hold the cache entries for method calls */
OBJECT cs;
cs = cmethod_get_cache(cm);
if(FIXNUM_P(cs)) {
native_int sz = N2I(cs);
if(sz > 0) {
cs = tuple_new(state, sz);
// Reserve field 0 for call sites that are not cached
fast_unsafe_set(cs, 0, Qfalse);
cmethod_set_cache(cm, cs);
}
}

return ba;
}

Expand Down Expand Up @@ -484,7 +674,8 @@ static inline OBJECT _allocate_context(STATE, cpu c, OBJECT meth, int locals) {
fc->sender = c->active_context;

fc->method = meth;
fc->data = bytearray_byte_address(state, ins);
fc->data = *DATA_STRUCT(ins, void**);
// fc->data = bytearray_byte_address(state, ins);
fc->literals = fast_fetch(meth, CMETHOD_f_LITERALS);

if(locals > 0) {
Expand Down Expand Up @@ -1022,7 +1213,7 @@ inline void cpu_perform_hook(STATE, cpu c, OBJECT recv, OBJECT meth, OBJECT arg)

/* Layer 4: direct activation. Used for calling a method thats already
been looked up. */
static inline void cpu_activate_method(STATE, cpu c, struct message *msg) {
inline void cpu_activate_method(STATE, cpu c, struct message *msg) {
OBJECT ctx;

c->depth++;
Expand Down Expand Up @@ -1460,27 +1651,31 @@ void cpu_yield_debugger(STATE, cpu c) {
}
}

const char *cpu_op_to_name(STATE, char op) {
#include "shotgun/lib/instruction_names.h"
return get_instruction_name(op);
}

void state_collect(STATE, cpu c);
void state_major_collect(STATE, cpu c);

void cpu_run(STATE, cpu c, int setup) {
uint32_t _int;
native_int j, k, m;
OBJECT _lit, t1, t2, t3, t4, t5;
struct message msg;
IP_TYPE op;
IP_TYPE *ip_ptr = NULL;
IP_TYPE *ip_ptr;
const char *firesuit_arg;
struct rubinius_globals *global;
struct inter_proxy *proxy;

ip_ptr = NULL;
proxy = state->proxy;
global = state->global;
c->ip_ptr = &ip_ptr;

struct rubinius_globals *global = state->global;

if(setup) {
(void)op;
#if DIRECT_THREADED
SETUP_DT_ADDRESSES;
_populate_ins_info();
return;
#else
return;
Expand Down Expand Up @@ -1544,8 +1739,14 @@ void cpu_run(STATE, cpu c, int setup) {
rbs_symbol_to_cstring(state, cmethod_get_name(cpu_current_method(state, c))),
(void*)*ip_ptr);
}
jump_next:
NEXT_OP;
jump_next_end:
#undef WB_FUNC
#define WB_FUNC proxy->write_barrier
#include "shotgun/lib/instruction_dt.gen"
#undef WB_FUNC
#define WB_FUNC object_memory_write_barrier
#else

next_op:
Expand Down
Loading

0 comments on commit 142b22e

Please sign in to comment.