mirror of
https://github.com/ruby/ruby.git
synced 2025-09-21 19:44:01 +02:00
126 lines
3 KiB
C
126 lines
3 KiB
C
#include "internal.h"
|
|
#include "ujit_asm.h"
|
|
#include "ujit_iface.h"
|
|
#include "ujit_core.h"
|
|
#include "ujit_codegen.h"
|
|
|
|
// Table of block versions indexed by (iseq, index) tuples
|
|
st_table * version_tbl;
|
|
|
|
int blockid_cmp(st_data_t arg0, st_data_t arg1)
|
|
{
|
|
const blockid_t *block0 = (const blockid_t*)arg0;
|
|
const blockid_t *block1 = (const blockid_t*)arg1;
|
|
return block0->iseq == block1->iseq && block0->idx == block1->idx;
|
|
}
|
|
|
|
st_index_t blockid_hash(st_data_t arg)
|
|
{
|
|
const blockid_t *blockid = (const blockid_t*)arg;
|
|
st_index_t hash0 = st_numhash((st_data_t)blockid->iseq);
|
|
st_index_t hash1 = st_numhash((st_data_t)blockid->idx);
|
|
|
|
// Use XOR to combine the hashes
|
|
return hash0 ^ hash1;
|
|
}
|
|
|
|
static const struct st_hash_type hashtype_blockid = {
|
|
blockid_cmp,
|
|
blockid_hash,
|
|
};
|
|
|
|
// Retrieve a basic block version for an (iseq, idx) tuple
|
|
// TODO: we need to add a versioning context here
|
|
uint8_t* get_block_version(const rb_iseq_t *iseq, unsigned int idx /*, ctx_t* ctx */)
|
|
{
|
|
blockid_t blockid = { iseq, idx };
|
|
|
|
// If there exists a version for this block id
|
|
st_data_t st_version;
|
|
if (rb_st_lookup(version_tbl, (st_data_t)&blockid, &st_version)) {
|
|
return (uint8_t*)st_version;
|
|
}
|
|
|
|
uint8_t* code_ptr = ujit_compile_block(iseq, idx, false);
|
|
|
|
st_insert(version_tbl, (st_data_t)&blockid, (st_data_t)code_ptr);
|
|
|
|
return code_ptr;
|
|
}
|
|
|
|
//
|
|
// Method to generate stubs for branches
|
|
// TODO: get_branch_stub() or get_branch() function
|
|
//
|
|
|
|
// Get the current instruction opcode from the context object
|
|
int
|
|
ctx_get_opcode(ctx_t *ctx)
|
|
{
|
|
return opcode_at_pc(ctx->iseq, ctx->pc);
|
|
}
|
|
|
|
// Get an instruction argument from the context object
|
|
VALUE
|
|
ctx_get_arg(ctx_t* ctx, size_t arg_idx)
|
|
{
|
|
assert (arg_idx + 1 < insn_len(ctx_get_opcode(ctx)));
|
|
return *(ctx->pc + arg_idx + 1);
|
|
}
|
|
|
|
/*
|
|
Get an operand for the adjusted stack pointer address
|
|
*/
|
|
x86opnd_t
|
|
ctx_sp_opnd(ctx_t* ctx, int32_t offset_bytes)
|
|
{
|
|
int32_t offset = (ctx->stack_size) * 8 + offset_bytes;
|
|
return mem_opnd(64, REG_SP, offset);
|
|
}
|
|
|
|
/*
|
|
Make space on the stack for N values
|
|
Return a pointer to the new stack top
|
|
*/
|
|
x86opnd_t
|
|
ctx_stack_push(ctx_t* ctx, size_t n)
|
|
{
|
|
ctx->stack_size += n;
|
|
|
|
// SP points just above the topmost value
|
|
int32_t offset = (ctx->stack_size - 1) * 8;
|
|
return mem_opnd(64, REG_SP, offset);
|
|
}
|
|
|
|
/*
|
|
Pop N values off the stack
|
|
Return a pointer to the stack top before the pop operation
|
|
*/
|
|
x86opnd_t
|
|
ctx_stack_pop(ctx_t* ctx, size_t n)
|
|
{
|
|
// SP points just above the topmost value
|
|
int32_t offset = (ctx->stack_size - 1) * 8;
|
|
x86opnd_t top = mem_opnd(64, REG_SP, offset);
|
|
|
|
ctx->stack_size -= n;
|
|
|
|
return top;
|
|
}
|
|
|
|
x86opnd_t
|
|
ctx_stack_opnd(ctx_t* ctx, int32_t idx)
|
|
{
|
|
// SP points just above the topmost value
|
|
int32_t offset = (ctx->stack_size - 1 - idx) * 8;
|
|
x86opnd_t opnd = mem_opnd(64, REG_SP, offset);
|
|
|
|
return opnd;
|
|
}
|
|
|
|
void
|
|
ujit_init_core(void)
|
|
{
|
|
// Initialize the version hash table
|
|
version_tbl = st_init_table(&hashtype_blockid);
|
|
}
|