Skip to content

Commit 566eeeb

Browse files
author
Noah Gibbs
authored
Merge pull request ruby#216 from Shopify/noah_builtin_function
Port gen_opt_builtin* and getblockparamproxy
2 parents 9c3eeec + 8d0c510 commit 566eeeb

File tree

3 files changed

+42
-36
lines changed

3 files changed

+42
-36
lines changed

yjit/bindgen/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ fn main() {
110110
// From vm_insnhelper.h
111111
.allowlist_var("ruby_vm_global_constant_state")
112112
.allowlist_var("VM_ENV_DATA_INDEX_ME_CREF")
113+
.allowlist_var("rb_block_param_proxy")
113114

114115
// From include/ruby/internal/intern/range.h
115116
.allowlist_function("rb_range_new")
@@ -199,6 +200,9 @@ fn main() {
199200
// From iseq.h
200201
.allowlist_function("rb_vm_insn_addr2opcode")
201202

203+
// From builtin.h
204+
.allowlist_type("rb_builtin_function.*")
205+
202206
// From internal/variable.h
203207
.allowlist_function("rb_gvar_(get|set)")
204208
.allowlist_function("rb_obj_ensure_iv_index_mapping")

yjit/src/codegen.rs

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4942,29 +4942,29 @@ fn gen_opt_getinlinecache(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBl
49424942
EndBlock
49434943
}
49444944

4945-
/*
4946-
// Push the explict block parameter onto the temporary stack. Part of the
4945+
// Push the explicit block parameter onto the temporary stack. Part of the
49474946
// interpreter's scheme for avoiding Proc allocations when delegating
49484947
// explict block parameters.
49494948
fn gen_getblockparamproxy(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
49504949
{
49514950
// A mirror of the interpreter code. Checking for the case
49524951
// where it's pushing rb_block_param_proxy.
4953-
uint8_t *side_exit = get_side_exit(jit, ocb, ctx);
4952+
let side_exit = get_side_exit(jit, ocb, ctx);
49544953

49554954
// EP level
4956-
uint32_t level = (uint32_t)jit_get_arg(jit, 1);
4955+
let level = jit_get_arg(jit, 1).as_u32();
49574956

49584957
// Load environment pointer EP from CFP
49594958
gen_get_ep(cb, REG0, level);
49604959

49614960
// Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero
4962-
test(cb, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_FLAGS), imm_opnd(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM));
4961+
let flag_check = mem_opnd(64, REG0, (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_FLAGS as i32));
4962+
test(cb, flag_check, uimm_opnd(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into()));
49634963
jnz_ptr(cb, counted_exit!(ocb, side_exit, gbpp_block_param_modified));
49644964

49654965
// Load the block handler for the current frame
49664966
// note, VM_ASSERT(VM_ENV_LOCAL_P(ep))
4967-
mov(cb, REG0, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_SPECVAL));
4967+
mov(cb, REG0, mem_opnd(64, REG0, (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_SPECVAL as i32)));
49684968

49694969
// Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
49704970
and(cb, REG0_8, imm_opnd(0x3));
@@ -4974,8 +4974,8 @@ fn gen_getblockparamproxy(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBl
49744974
jnz_ptr(cb, counted_exit!(ocb, side_exit, gbpp_block_handler_not_iseq));
49754975

49764976
// Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr.
4977-
mov(cb, REG0, const_ptr_opnd((void *)rb_block_param_proxy));
4978-
RUBY_ASSERT(!SPECIAL_CONST_P(rb_block_param_proxy));
4977+
mov(cb, REG0, const_ptr_opnd(unsafe { rb_block_param_proxy }.as_ptr()));
4978+
assert!(! unsafe { rb_block_param_proxy }.special_const_p());
49794979
let top = ctx.stack_push(Type::UnknownHeap);
49804980
mov(cb, top, REG0);
49814981

@@ -4984,10 +4984,11 @@ fn gen_getblockparamproxy(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBl
49844984

49854985
fn gen_invokebuiltin(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
49864986
{
4987-
const struct rb_builtin_function *bf = (struct rb_builtin_function *)jit_get_arg(jit, 0);
4987+
let bf: *const rb_builtin_function = jit_get_arg(jit, 0).as_ptr();
4988+
let bf_argc: usize = unsafe { (*bf).argc }.try_into().expect("non negative argc");
49884989

49894990
// ec, self, and arguments
4990-
if (bf->argc + 2 > NUM_C_ARG_REGS) {
4991+
if bf_argc + 2 > C_ARG_REGS.len() {
49914992
return CantCompile;
49924993
}
49934994

@@ -4996,19 +4997,19 @@ fn gen_invokebuiltin(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock,
49964997

49974998
// Call the builtin func (ec, recv, arg1, arg2, ...)
49984999
mov(cb, C_ARG_REGS[0], REG_EC);
4999-
mov(cb, C_ARG_REGS[1], member_opnd(REG_CFP, rb_control_frame_t, self));
5000+
mov(cb, C_ARG_REGS[1], mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_SELF));
50005001

50015002
// Copy arguments from locals
5002-
for (int32_t i = 0; i < bf->argc; i++) {
5003-
let stack_opnd = ctx.stack_opnd(bf->argc - i - 1);
5003+
for i in 0..bf_argc {
5004+
let stack_opnd = ctx.stack_opnd((bf_argc - i - 1) as i32);
50045005
let c_arg_reg = C_ARG_REGS[2 + i];
50055006
mov(cb, c_arg_reg, stack_opnd);
50065007
}
50075008

5008-
call_ptr(cb, REG0, (void *)bf->func_ptr);
5009+
call_ptr(cb, REG0, unsafe { (*bf).func_ptr } as *const u8);
50095010

50105011
// Push the return value
5011-
ctx.stack_pop(bf->argc);
5012+
ctx.stack_pop(bf_argc);
50125013
let stack_ret = ctx.stack_push(Type::Unknown);
50135014
mov(cb, stack_ret, RAX);
50145015

@@ -5020,46 +5021,44 @@ fn gen_invokebuiltin(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock,
50205021
// stack uses the argument locals (and self) from the current method.
50215022
fn gen_opt_invokebuiltin_delegate(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
50225023
{
5023-
const struct rb_builtin_function *bf = (struct rb_builtin_function *)jit_get_arg(jit, 0);
5024-
int32_t start_index = (int32_t)jit_get_arg(jit, 1);
5024+
let bf: *const rb_builtin_function = jit_get_arg(jit, 0).as_ptr();
5025+
let bf_argc = unsafe { (*bf).argc };
5026+
let start_index = jit_get_arg(jit, 1).as_i32();
50255027

50265028
// ec, self, and arguments
5027-
if (bf->argc + 2 > NUM_C_ARG_REGS) {
5029+
if bf_argc + 2 > (C_ARG_REGS.len() as i32) {
50285030
return CantCompile;
50295031
}
50305032

50315033
// If the calls don't allocate, do they need up to date PC, SP?
50325034
jit_prepare_routine_call(jit, ctx, cb, REG0);
50335035

5034-
if (bf->argc > 0) {
5036+
if bf_argc > 0 {
50355037
// Load environment pointer EP from CFP
5036-
mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
5038+
mov(cb, REG0, mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_EP));
50375039
}
50385040

50395041
// Call the builtin func (ec, recv, arg1, arg2, ...)
50405042
mov(cb, C_ARG_REGS[0], REG_EC);
5041-
mov(cb, C_ARG_REGS[1], member_opnd(REG_CFP, rb_control_frame_t, self));
5043+
mov(cb, C_ARG_REGS[1], mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_SELF));
50425044

50435045
// Copy arguments from locals
5044-
for (int32_t i = 0; i < bf->argc; i++) {
5045-
const int32_t offs = -jit->iseq->body->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index + i;
5046-
let local_opnd = mem_opnd(64, REG0, offs * SIZEOF_VALUE);
5047-
let c_arg_reg = C_ARG_REGS[i + 2];
5046+
for i in 0..bf_argc {
5047+
let table_size = unsafe { get_iseq_body_local_table_size(jit.iseq) };
5048+
let offs:i32 = -(table_size as i32) - (VM_ENV_DATA_SIZE as i32) + 1 + start_index + i;
5049+
let local_opnd = mem_opnd(64, REG0, offs * (SIZEOF_VALUE as i32));
5050+
let offs:usize = (i + 2) as usize;
5051+
let c_arg_reg = C_ARG_REGS[offs];
50485052
mov(cb, c_arg_reg, local_opnd);
50495053
}
5050-
call_ptr(cb, REG0, (void *)bf->func_ptr);
5054+
call_ptr(cb, REG0, unsafe { (*bf).func_ptr } as *const u8);
50515055

50525056
// Push the return value
50535057
let stack_ret = ctx.stack_push(Type::Unknown);
50545058
mov(cb, stack_ret, RAX);
50555059

50565060
KeepCompiling
50575061
}
5058-
*/
5059-
5060-
5061-
5062-
50635062

50645063

50655064

@@ -5136,16 +5135,16 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn>
51365135
OP_OPT_LENGTH => Some(gen_opt_length),
51375136
OP_OPT_REGEXPMATCH2 => Some(gen_opt_regexpmatch2),
51385137
OP_OPT_GETINLINECACHE => Some(gen_opt_getinlinecache),
5139-
//yjit_reg_op(BIN(invokebuiltin), gen_invokebuiltin);
5140-
//yjit_reg_op(BIN(opt_invokebuiltin_delegate), gen_opt_invokebuiltin_delegate);
5141-
//yjit_reg_op(BIN(opt_invokebuiltin_delegate_leave), gen_opt_invokebuiltin_delegate);
5138+
OP_INVOKEBUILTIN => Some(gen_invokebuiltin),
5139+
OP_OPT_INVOKEBUILTIN_DELEGATE => Some(gen_opt_invokebuiltin_delegate),
5140+
OP_OPT_INVOKEBUILTIN_DELEGATE_LEAVE => Some(gen_opt_invokebuiltin_delegate),
51425141
OP_OPT_CASE_DISPATCH => Some(gen_opt_case_dispatch),
51435142
OP_BRANCHIF => Some(gen_branchif),
51445143
OP_BRANCHUNLESS => Some(gen_branchunless),
51455144
OP_BRANCHNIL => Some(gen_branchnil),
51465145
OP_JUMP => Some(gen_jump),
51475146

5148-
//yjit_reg_op(BIN(getblockparamproxy), gen_getblockparamproxy);
5147+
OP_GETBLOCKPARAMPROXY => Some(gen_getblockparamproxy),
51495148
OP_OPT_SEND_WITHOUT_BLOCK => Some(gen_opt_send_without_block),
51505149
OP_SEND => Some(gen_send),
51515150
OP_INVOKESUPER => Some(gen_invokesuper),

yjit/src/cruby_bindings.inc.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,8 +505,11 @@ pub const BOP_AND: ruby_basic_operators = 27;
505505
pub const BOP_OR: ruby_basic_operators = 28;
506506
pub const BOP_LAST_: ruby_basic_operators = 29;
507507
pub type ruby_basic_operators = u32;
508-
pub type IC = *mut iseq_inline_constant_cache;
509508
pub type rb_control_frame_t = rb_control_frame_struct;
509+
extern "C" {
510+
pub static mut rb_block_param_proxy: VALUE;
511+
}
512+
pub type IC = *mut iseq_inline_constant_cache;
510513
pub type IVC = *mut iseq_inline_iv_cache_entry;
511514
pub type ICVARC = *mut iseq_inline_cvar_cache_entry;
512515
pub const VM_FRAME_MAGIC_METHOD: u32 = 286326785;

0 commit comments

Comments
 (0)