Skip to content

Expose methods for inspecting Micro JIT code blocks #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions misc/ujit_disasm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
begin
require "crabstone"
require "stringio"

module UJIT
def self.disasm(iseq)
blocks = UJIT.blocks_for(iseq)
return if blocks.empty?

io = StringIO.new

cs = Crabstone::Disassembler.new(Crabstone::ARCH_X86, Crabstone::MODE_64)

io.puts iseq.disasm

blocks.sort_by(&:address).reverse.each do |block|
io.puts "== ISEQ RANGE: #{block.iseq_start_index} -> #{block.iseq_end_index} ".ljust(80, "=")
cs.disasm(block.code, 0).each do |i|
io.printf(
"\t0x%<address>x:\t%<instruction>s\t%<details>s\n",
address: i.address,
instruction: i.mnemonic,
details: i.op_str
)
end
end
io.string
end
end
rescue
puts "Please install crabstone like this:"
puts " $ brew install capstone"
puts " $ gem install capstone"
end
102 changes: 102 additions & 0 deletions ujit_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@
#include "ujit_core.h"
#include "ujit_hooks.inc"

VALUE cUjitBlock;

extern st_table * version_tbl;
extern codeblock_t *cb;

static const rb_data_type_t ujit_block_type = {
"UJIT/Block",
{0, 0, 0, },
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};

bool rb_ujit_enabled;

// Hash table of encoded instructions
Expand Down Expand Up @@ -288,6 +299,87 @@ rb_ujit_compile_iseq(const rb_iseq_t *iseq)
#endif
}

struct ujit_block_itr {
const rb_iseq_t *iseq;
VALUE list;
};

static int
iseqw_ujit_collect_blocks(st_data_t key, st_data_t value, st_data_t argp)
{
block_t * block = (block_t *)value;
struct ujit_block_itr * itr = (struct ujit_block_itr *)argp;

if (block->blockid.iseq == itr->iseq) {
VALUE rb_block = TypedData_Wrap_Struct(cUjitBlock, &ujit_block_type, block);
rb_ary_push(itr->list, rb_block);
}
return ST_CONTINUE;
}

/* Get a list of the UJIT blocks associated with `rb_iseq` */
static VALUE
ujit_blocks_for(VALUE mod, VALUE rb_iseq)
{
const rb_iseq_t *iseq = rb_iseqw_to_iseq(rb_iseq);
st_table * vt = (st_table *)version_tbl;
struct ujit_block_itr itr;
itr.iseq = iseq;
itr.list = rb_ary_new();

rb_st_foreach(vt, iseqw_ujit_collect_blocks, (st_data_t)&itr);

return itr.list;
}

static VALUE
ujit_insert(VALUE mod, VALUE iseq)
{
rb_ujit_compile_iseq(rb_iseqw_to_iseq(iseq));
return iseq;
}

/* Get the address of the UJIT::Block */
static VALUE
block_address(VALUE self)
{
block_t * block;
TypedData_Get_Struct(self, block_t, &ujit_block_type, block);
return LONG2NUM((intptr_t)block);
}

/* Get the machine code for UJIT::Block as a binary string */
static VALUE
block_code(VALUE self)
{
block_t * block;
TypedData_Get_Struct(self, block_t, &ujit_block_type, block);

return rb_str_new(cb->mem_block + block->start_pos, block->end_pos - block->start_pos);
}

/* Get the start index in the Instruction Sequence that corresponds to this
* UJIT::Block */
static VALUE
iseq_start_index(VALUE self)
{
block_t * block;
TypedData_Get_Struct(self, block_t, &ujit_block_type, block);

return INT2NUM(block->blockid.idx);
}

/* Get the end index in the Instruction Sequence that corresponds to this
* UJIT::Block */
static VALUE
iseq_end_index(VALUE self)
{
block_t * block;
TypedData_Get_Struct(self, block_t, &ujit_block_type, block);

return INT2NUM(block->end_idx);
}

void
rb_ujit_init(void)
{
Expand All @@ -301,6 +393,16 @@ rb_ujit_init(void)
ujit_init_core();
ujit_init_codegen();

VALUE mUjit = rb_define_module("UJIT");
rb_define_module_function(mUjit, "install_entry", ujit_insert, 1);
rb_define_module_function(mUjit, "blocks_for", ujit_blocks_for, 1);

cUjitBlock = rb_define_class_under(mUjit, "Block", rb_cObject);
rb_define_method(cUjitBlock, "address", block_address, 0);
rb_define_method(cUjitBlock, "code", block_code, 0);
rb_define_method(cUjitBlock, "iseq_start_index", iseq_start_index, 0);
rb_define_method(cUjitBlock, "iseq_end_index", iseq_end_index, 0);

// Initialize the GC hooks
method_lookup_dependency = st_init_numtable();
struct ujit_root_struct *root;
Expand Down