Skip to content
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
12 changes: 6 additions & 6 deletions insns.def
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ opt_new
// The bookkeeping slot should be empty.
RUBY_ASSERT(TOPN(argc + 1) == Qnil);

if (vm_method_cfunc_is(GET_ISEQ(), cd, val, rb_class_new_instance_pass_kw)) {
if (vm_method_cfunc_is(GET_CFP(), cd, val, rb_class_new_instance_pass_kw)) {
RB_DEBUG_COUNTER_INC(opt_new_hit);
val = rb_obj_alloc(val);
TOPN(argc) = val;
Expand All @@ -947,7 +947,7 @@ objtostring
// attr bool leaf = false;
// attr bool zjit_profile = true;
{
val = vm_objtostring(GET_ISEQ(), recv, cd);
val = vm_objtostring(GET_CFP(), recv, cd);

if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
Expand Down Expand Up @@ -1006,7 +1006,7 @@ opt_nil_p
(VALUE val)
// attr bool zjit_profile = true;
{
val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
val = vm_opt_nil_p(GET_CFP(), cd, recv);

if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
Expand Down Expand Up @@ -1435,7 +1435,7 @@ opt_eq
(VALUE val)
// attr bool zjit_profile = true;
{
val = opt_equality(GET_ISEQ(), recv, obj, cd);
val = opt_equality(GET_CFP(), recv, obj, cd);

if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
Expand All @@ -1450,7 +1450,7 @@ opt_neq
(VALUE val)
// attr bool zjit_profile = true;
{
val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
val = vm_opt_neq(GET_CFP(), cd, cd_eq, recv, obj);

if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
Expand Down Expand Up @@ -1672,7 +1672,7 @@ opt_not
(VALUE val)
// attr bool zjit_profile = true;
{
val = vm_opt_not(GET_ISEQ(), cd, recv);
val = vm_opt_not(GET_CFP(), cd, recv);

if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
Expand Down
8 changes: 8 additions & 0 deletions prism/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2627,6 +2627,14 @@ nodes:
end
- name: ForwardingSuperNode
fields:
- name: keyword_loc
type: location
comment: |
super
^^^^^

super { 123 }
^^^^^
- name: block
type: node?
kind: BlockNode
Expand Down
3,302 changes: 1,673 additions & 1,629 deletions prism/prism.c

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions spec/bundler/support/windows_tag_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module WindowsTagGroup
"spec/bundler/source/git/git_proxy_spec.rb",
"spec/bundler/source_list_spec.rb",
"spec/bundler/plugin/installer_spec.rb",
"spec/bundler/errors_spec.rb",
"spec/bundler/friendly_errors_spec.rb",
"spec/resolver/platform_spec.rb",
"spec/bundler/fetcher/downloader_spec.rb",
Expand Down
63 changes: 36 additions & 27 deletions vm_insnhelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -2352,9 +2352,9 @@ vm_search_method_slowpath0(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
return cc;
}

ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass));
ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass));
static const struct rb_callcache *
vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass)
{
const struct rb_callcache *cc = cd->cc;

Expand All @@ -2376,24 +2376,28 @@ vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
}
#endif

return vm_search_method_slowpath0(cd_owner, cd, klass);
return vm_search_method_slowpath0((VALUE)reg_cfp->iseq, cd, klass);
}

static const struct rb_callable_method_entry_struct *
vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
vm_search_method(struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE recv)
{
VALUE klass = CLASS_OF(recv);
VM_ASSERT(klass != Qfalse);
VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));

const struct rb_callcache *cc = vm_search_method_fastpath(cd_owner, cd, klass);
const struct rb_callcache *cc = vm_search_method_fastpath(reg_cfp, cd, klass);
return vm_cc_cme(cc);
}

const struct rb_callable_method_entry_struct *
rb_zjit_vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
{
return vm_search_method(cd_owner, cd, recv);
// Called from ZJIT with the compile-time iseq, which may differ from
// the iseq on the current CFP. Use the slowpath to avoid stale caches.
VALUE klass = CLASS_OF(recv);
const struct rb_callcache *cc = vm_search_method_slowpath0(cd_owner, cd, klass);
return vm_cc_cme(cc);
}

#if __has_attribute(transparent_union)
Expand Down Expand Up @@ -2453,10 +2457,10 @@ check_method_basic_definition(const rb_callable_method_entry_t *me)
}

static inline int
vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
vm_method_cfunc_is(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv, cfunc_type func)
{
VM_ASSERT(iseq != NULL);
const struct rb_callable_method_entry_struct *cme = vm_search_method((VALUE)iseq, cd, recv);
VM_ASSERT(reg_cfp != NULL);
const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
return check_cfunc(cme, func);
}

Expand All @@ -2469,11 +2473,16 @@ rb_zjit_cme_is_cfunc(const rb_callable_method_entry_t *me, const cfunc_type func
int
rb_vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
{
return vm_method_cfunc_is(iseq, cd, recv, func);
// Called from ZJIT with the compile-time iseq, which may differ from
// the iseq on the current CFP. Use the slowpath to avoid stale caches.
VALUE klass = CLASS_OF(recv);
const struct rb_callcache *cc = vm_search_method_slowpath0((VALUE)iseq, cd, klass);
const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
return check_cfunc(cme, func);
}

#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
#define vm_method_cfunc_is(iseq, cd, recv, func) vm_method_cfunc_is(iseq, cd, recv, make_cfunc_type(func))
#define vm_method_cfunc_is(reg_cfp, cd, recv, func) vm_method_cfunc_is(reg_cfp, cd, recv, make_cfunc_type(func))

#define EQ_UNREDEFINED_P(t) BASIC_OP_UNREDEFINED_P(BOP_EQ, t##_REDEFINED_OP_FLAG)

Expand Down Expand Up @@ -2542,14 +2551,14 @@ opt_equality_specialized(VALUE recv, VALUE obj)
}

static VALUE
opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
opt_equality(struct rb_control_frame_struct *reg_cfp, VALUE recv, VALUE obj, CALL_DATA cd)
{
VM_ASSERT(cd_owner != NULL);
VM_ASSERT(reg_cfp != NULL);

VALUE val = opt_equality_specialized(recv, obj);
if (!UNDEF_P(val)) return val;

if (!vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) {
if (!vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_equal)) {
return Qundef;
}
else {
Expand Down Expand Up @@ -5171,7 +5180,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
RB_OBJ_WRITE(reg_cfp->iseq, &cd->cc, cc);
}
else {
cc = vm_search_method_fastpath((VALUE)reg_cfp->iseq, cd, klass);
cc = vm_search_method_fastpath(reg_cfp, cd, klass);
const rb_callable_method_entry_t *cached_cme = vm_cc_cme(cc);

// define_method can cache for different method id
Expand Down Expand Up @@ -6123,7 +6132,7 @@ vm_sendish(

switch (method_explorer) {
case mexp_search_method:
calling.cc = cc = vm_search_method_fastpath((VALUE)reg_cfp->iseq, cd, CLASS_OF(recv));
calling.cc = cc = vm_search_method_fastpath(reg_cfp, cd, CLASS_OF(recv));
val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
break;
case mexp_search_super:
Expand Down Expand Up @@ -6230,14 +6239,14 @@ VALUE rb_mod_to_s(VALUE);
VALUE rb_mod_name(VALUE);

static VALUE
vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
{
int type = TYPE(recv);
if (type == T_STRING) {
return recv;
}

const struct rb_callable_method_entry_struct *cme = vm_search_method((VALUE)iseq, cd, recv);
const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);

switch (type) {
case T_SYMBOL:
Expand Down Expand Up @@ -6288,9 +6297,9 @@ vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
// ZJIT implementation is using the C function
// and needs to call a non-static function
VALUE
rb_vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
rb_vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
{
return vm_objtostring(iseq, recv, cd);
return vm_objtostring(reg_cfp, recv, cd);
}

static VALUE
Expand Down Expand Up @@ -6841,10 +6850,10 @@ vm_opt_mod(VALUE recv, VALUE obj)
}

static VALUE
vm_opt_neq(const rb_iseq_t *iseq, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
vm_opt_neq(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
{
if (vm_method_cfunc_is(iseq, cd, recv, rb_obj_not_equal)) {
VALUE val = opt_equality(iseq, recv, obj, cd_eq);
if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not_equal)) {
VALUE val = opt_equality(reg_cfp, recv, obj, cd_eq);

if (!UNDEF_P(val)) {
return RBOOL(!RTEST(val));
Expand Down Expand Up @@ -7096,13 +7105,13 @@ vm_opt_empty_p(VALUE recv)
VALUE rb_false(VALUE obj);

static VALUE
vm_opt_nil_p(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv)
vm_opt_nil_p(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
{
if (NIL_P(recv) &&
BASIC_OP_UNREDEFINED_P(BOP_NIL_P, NIL_REDEFINED_OP_FLAG)) {
return Qtrue;
}
else if (vm_method_cfunc_is(iseq, cd, recv, rb_false)) {
else if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_false)) {
return Qfalse;
}
else {
Expand Down Expand Up @@ -7158,9 +7167,9 @@ vm_opt_succ(VALUE recv)
}

static VALUE
vm_opt_not(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv)
vm_opt_not(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
{
if (vm_method_cfunc_is(iseq, cd, recv, rb_obj_not)) {
if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not)) {
return RBOOL(!RTEST(recv));
}
else {
Expand Down
25 changes: 12 additions & 13 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
Insn::NewRangeFixnum { low, high, flag, state } => gen_new_range_fixnum(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)),
Insn::AdjustBounds { index, length } => gen_adjust_bounds(asm, opnd!(index), opnd!(length)),
Insn::ArrayAref { array, index, .. } => gen_array_aref(asm, opnd!(array), opnd!(index)),
Insn::ArrayAset { array, index, val } => {
no_output!(gen_array_aset(asm, opnd!(array), opnd!(index), opnd!(val)))
Expand Down Expand Up @@ -742,8 +743,8 @@ fn gen_get_ep(asm: &mut Assembler, level: u32) -> Opnd {
fn gen_objtostring(jit: &mut JITState, asm: &mut Assembler, val: Opnd, cd: *const rb_call_data, state: &FrameState) -> Opnd {
gen_prepare_non_leaf_call(jit, asm, state);
// TODO: Specialize for immediate types
// Call rb_vm_objtostring(iseq, recv, cd)
let ret = asm_ccall!(asm, rb_vm_objtostring, VALUE::from(jit.iseq).into(), val, Opnd::const_ptr(cd));
// Call rb_vm_objtostring(cfp, recv, cd)
let ret = asm_ccall!(asm, rb_vm_objtostring, CFP, val, Opnd::const_ptr(cd));

// TODO: Call `to_s` on the receiver if rb_vm_objtostring returns Qundef
// Need to replicate what CALL_SIMPLE_METHOD does
Expand Down Expand Up @@ -1619,16 +1620,6 @@ fn gen_send_iseq_direct(
0
};

// Fill non-parameter locals with nil (they may be read by eval before being written)
let num_params = params.size.to_usize();
if local_size > num_params {
asm_comment!(asm, "initialize non-parameter locals to nil");
for local_idx in num_params..local_size {
let offset = local_size_and_idx_to_bp_offset(local_size, local_idx);
asm.store(Opnd::mem(64, SP, -offset * SIZEOF_VALUE_I32), Qnil.into());
}
}

// Make a method call. The target address will be rewritten once compiled.
let iseq_call = IseqCall::new(iseq, num_optionals_passed);
let dummy_ptr = cb.get_write_ptr().raw_ptr(cb);
Expand Down Expand Up @@ -1791,6 +1782,14 @@ fn gen_new_array(
}
}

/// Adjust potentially-negative index by the given length, returning the adjusted index. If still negative,
/// return a negative number, which indicates the index is still out-of-bounds.
fn gen_adjust_bounds(asm: &mut Assembler, index: Opnd, length: Opnd) -> lir::Opnd {
let adjusted = asm.add(index, length);
asm.test(index, index);
asm.csel_l(adjusted, index)
}

/// Compile array access (`array[index]`)
fn gen_array_aref(
asm: &mut Assembler,
Expand Down Expand Up @@ -2876,7 +2875,7 @@ c_callable! {
let pc = unsafe { rb_iseq_pc_at_idx(iseq, entry_insn_idxs[iseq_call.jit_entry_idx.to_usize()]) };
unsafe { rb_set_cfp_pc(cfp, pc) };

// Successful JIT-to-JIT calls fill nils to non-parameter locals in generated code.
// JIT-to-JIT calls don't eagerly fill nils to non-parameter locals.
// If we side-exit from function_stub_hit (before JIT code runs), we need to set them here.
fn prepare_for_exit(iseq: IseqPtr, cfp: CfpPtr, sp: *mut VALUE, compile_error: &CompileError) {
unsafe {
Expand Down
2 changes: 1 addition & 1 deletion zjit/src/cruby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ unsafe extern "C" {
pub fn rb_vm_stack_canary() -> VALUE;
pub fn rb_vm_push_cfunc_frame(cme: *const rb_callable_method_entry_t, recv_idx: c_int);
pub fn rb_obj_class(klass: VALUE) -> VALUE;
pub fn rb_vm_objtostring(iseq: IseqPtr, recv: VALUE, cd: *const rb_call_data) -> VALUE;
pub fn rb_vm_objtostring(reg_cfp: CfpPtr, recv: VALUE, cd: *const rb_call_data) -> VALUE;
}

// Renames
Expand Down
4 changes: 4 additions & 0 deletions zjit/src/cruby_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ fn inline_array_aref(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
let index = fun.push_insn(block, hir::Insn::UnboxFixnum { val: index });
let length = fun.push_insn(block, hir::Insn::ArrayLength { array: recv });
let index = fun.push_insn(block, hir::Insn::GuardLess { left: index, right: length, state });
let index = fun.push_insn(block, hir::Insn::AdjustBounds { index, length });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
let index = fun.push_insn(block, hir::Insn::GuardGreaterEq { left: index, right: zero, reason: SideExitReason::GuardGreaterEq, state });
Expand All @@ -378,6 +379,7 @@ fn inline_array_aset(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
let index = fun.push_insn(block, hir::Insn::UnboxFixnum { val: index });
let length = fun.push_insn(block, hir::Insn::ArrayLength { array: recv });
let index = fun.push_insn(block, hir::Insn::GuardLess { left: index, right: length, state });
let index = fun.push_insn(block, hir::Insn::AdjustBounds { index, length });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
let index = fun.push_insn(block, hir::Insn::GuardGreaterEq { left: index, right: zero, reason: SideExitReason::GuardGreaterEq, state });
Expand Down Expand Up @@ -475,6 +477,7 @@ fn inline_string_getbyte(fun: &mut hir::Function, block: hir::BlockId, recv: hir
//
// This is unlike most other guards.
let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, state });
let unboxed_index = fun.push_insn(block, hir::Insn::AdjustBounds { index: unboxed_index, length: len });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
let _ = fun.push_insn(block, hir::Insn::GuardGreaterEq { left: unboxed_index, right: zero, reason: SideExitReason::GuardGreaterEq, state });
Expand All @@ -498,6 +501,7 @@ fn inline_string_setbyte(fun: &mut hir::Function, block: hir::BlockId, recv: hir
return_type: types::CInt64,
});
let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, state });
let unboxed_index = fun.push_insn(block, hir::Insn::AdjustBounds { index: unboxed_index, length: len });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
let _ = fun.push_insn(block, hir::Insn::GuardGreaterEq { left: unboxed_index, right: zero, reason: SideExitReason::GuardGreaterEq, state });
Expand Down
Loading