Skip to content

Commit

Permalink
YJIT: Introduce no_gc attribute (#7511)
Browse files Browse the repository at this point in the history
  • Loading branch information
k0kubun committed Mar 14, 2023
1 parent 868f03c commit 70ba310
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 30 deletions.
3 changes: 3 additions & 0 deletions compile.c
Expand Up @@ -8236,6 +8236,9 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
}
else if (strcmp(RSTRING_PTR(string), "no_gc") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_NO_GC;
}
else {
goto unknown_arg;
}
Expand Down
2 changes: 1 addition & 1 deletion kernel.rb
Expand Up @@ -16,7 +16,7 @@ module Kernel
#++
#
def class
Primitive.attr! :leaf
Primitive.attr! :leaf, :no_gc
Primitive.cexpr! 'rb_obj_class(self)'
end

Expand Down
2 changes: 1 addition & 1 deletion tool/mk_builtin_loader.rb
Expand Up @@ -6,7 +6,7 @@

SUBLIBS = {}
REQUIRED = {}
BUILTIN_ATTRS = %w[leaf]
BUILTIN_ATTRS = %w[leaf no_gc]

def string_literal(lit, str = [])
while lit
Expand Down
4 changes: 3 additions & 1 deletion vm_core.h
Expand Up @@ -370,8 +370,10 @@ enum rb_iseq_type {

// Attributes specified by Primitive.attr!
enum rb_builtin_attr {
// If true, this ISeq does not call methods.
// The iseq does not call methods.
BUILTIN_ATTR_LEAF = 0x01,
// The iseq does not allocate objects.
BUILTIN_ATTR_NO_GC = 0x02,
};

struct rb_iseq_constant_body {
Expand Down
29 changes: 17 additions & 12 deletions yjit.c
Expand Up @@ -724,28 +724,33 @@ rb_optimized_call(VALUE *recv, rb_execution_context_t *ec, int argc, VALUE *argv
return rb_vm_invoke_proc(ec, proc, argc, argv, kw_splat, block_handler);
}

unsigned int
rb_yjit_iseq_builtin_attrs(const rb_iseq_t *iseq)
{
return iseq->body->builtin_attrs;
}

// If true, the iseq is leaf and it can be replaced by a single C call.
bool
rb_leaf_invokebuiltin_iseq_p(const rb_iseq_t *iseq)
// If true, the iseq has only opt_invokebuiltin_delegate_leave and leave insns.
static bool
invokebuiltin_delegate_leave_p(const rb_iseq_t *iseq)
{
unsigned int invokebuiltin_len = insn_len(BIN(opt_invokebuiltin_delegate_leave));
unsigned int leave_len = insn_len(BIN(leave));

return (iseq->body->iseq_size == (invokebuiltin_len + leave_len) &&
return iseq->body->iseq_size == (invokebuiltin_len + leave_len) &&
rb_vm_insn_addr2opcode((void *)iseq->body->iseq_encoded[0]) == BIN(opt_invokebuiltin_delegate_leave) &&
rb_vm_insn_addr2opcode((void *)iseq->body->iseq_encoded[invokebuiltin_len]) == BIN(leave) &&
(iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF) != 0
);
rb_vm_insn_addr2opcode((void *)iseq->body->iseq_encoded[invokebuiltin_len]) == BIN(leave);
}

// Return an rb_builtin_function if the iseq contains only that leaf builtin function.
// Return an rb_builtin_function if the iseq contains only that builtin function.
const struct rb_builtin_function *
rb_leaf_builtin_function(const rb_iseq_t *iseq)
rb_yjit_builtin_function(const rb_iseq_t *iseq)
{
if (!rb_leaf_invokebuiltin_iseq_p(iseq))
if (invokebuiltin_delegate_leave_p(iseq)) {
return (const struct rb_builtin_function *)iseq->body->iseq_encoded[1];
}
else {
return NULL;
return (const struct rb_builtin_function *)iseq->body->iseq_encoded[1];
}
}

VALUE
Expand Down
5 changes: 3 additions & 2 deletions yjit/bindgen/src/main.rs
Expand Up @@ -286,6 +286,7 @@ fn main() {
.allowlist_var("VM_ENV_DATA_INDEX_FLAGS")
.allowlist_var("VM_ENV_DATA_SIZE")
.allowlist_function("rb_iseq_path")
.allowlist_type("rb_builtin_attr")

// From yjit.c
.allowlist_function("rb_iseq_(get|set)_yjit_payload")
Expand All @@ -296,8 +297,8 @@ fn main() {
.allowlist_function("rb_yjit_mark_executable")
.allowlist_function("rb_yjit_mark_unused")
.allowlist_function("rb_yjit_get_page_size")
.allowlist_function("rb_leaf_invokebuiltin_iseq_p")
.allowlist_function("rb_leaf_builtin_function")
.allowlist_function("rb_yjit_iseq_builtin_attrs")
.allowlist_function("rb_yjit_builtin_function")
.allowlist_function("rb_set_cfp_(pc|sp)")
.allowlist_function("rb_cfp_get_iseq")
.allowlist_function("rb_yjit_multi_ractor_p")
Expand Down
22 changes: 11 additions & 11 deletions yjit/src/codegen.rs
Expand Up @@ -5591,14 +5591,10 @@ fn gen_send_iseq(
}
}

let leaf_builtin_raw = unsafe { rb_leaf_builtin_function(iseq) };
let leaf_builtin: Option<*const rb_builtin_function> = if leaf_builtin_raw.is_null() {
None
} else {
Some(leaf_builtin_raw)
};
if let (None, Some(builtin_info)) = (block, leaf_builtin) {

let builtin_attrs = unsafe { rb_yjit_iseq_builtin_attrs(iseq) };
let builtin_func_raw = unsafe { rb_yjit_builtin_function(iseq) };
let builtin_func = if builtin_func_raw.is_null() { None } else { Some(builtin_func_raw) };
if let (None, Some(builtin_info), true) = (block, builtin_func, builtin_attrs & BUILTIN_ATTR_LEAF != 0) {
// this is a .send call not currently supported for builtins
if flags & VM_CALL_OPT_SEND != 0 {
gen_counter_incr!(asm, send_send_builtin);
Expand All @@ -5609,9 +5605,13 @@ fn gen_send_iseq(
if builtin_argc + 1 < (C_ARG_OPNDS.len() as i32) {
asm.comment("inlined leaf builtin");

// Save the PC and SP because the callee may allocate
// e.g. Integer#abs on a bignum
jit_prepare_routine_call(jit, ctx, asm);
// Skip this if it doesn't trigger GC
if builtin_attrs & BUILTIN_ATTR_NO_GC == 0 {
// The callee may allocate, e.g. Integer#abs on a Bignum.
// Save SP for GC, save PC for allocation tracing, and prepare
// for global invalidation after GC's VM lock contention.
jit_prepare_routine_call(jit, ctx, asm);
}

// Call the builtin func (ec, recv, arg1, arg2, ...)
let mut args = vec![EC];
Expand Down
7 changes: 5 additions & 2 deletions yjit/src/cruby_bindings.inc.rs
Expand Up @@ -662,6 +662,9 @@ pub struct iseq_inline_iv_cache_entry {
pub struct iseq_inline_cvar_cache_entry {
pub entry: *mut rb_cvar_class_tbl_entry,
}
pub const BUILTIN_ATTR_LEAF: rb_builtin_attr = 1;
pub const BUILTIN_ATTR_NO_GC: rb_builtin_attr = 2;
pub type rb_builtin_attr = u32;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct rb_iseq_constant_body__bindgen_ty_1_rb_iseq_param_keyword {
Expand Down Expand Up @@ -1276,8 +1279,8 @@ extern "C" {
kw_splat: ::std::os::raw::c_int,
block_handler: VALUE,
) -> VALUE;
pub fn rb_leaf_invokebuiltin_iseq_p(iseq: *const rb_iseq_t) -> bool;
pub fn rb_leaf_builtin_function(iseq: *const rb_iseq_t) -> *const rb_builtin_function;
pub fn rb_yjit_iseq_builtin_attrs(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_yjit_builtin_function(iseq: *const rb_iseq_t) -> *const rb_builtin_function;
pub fn rb_yjit_str_simple_append(str1: VALUE, str2: VALUE) -> VALUE;
pub fn rb_get_ec_cfp(ec: *const rb_execution_context_t) -> *mut rb_control_frame_struct;
pub fn rb_get_cfp_pc(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
Expand Down

0 comments on commit 70ba310

Please sign in to comment.