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
11 changes: 5 additions & 6 deletions doc/string/start_with_p.rdoc
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
Returns whether +self+ starts with any of the given +string_or_regexp+.
Returns whether +self+ starts with any of the given +patterns+.

Matches patterns against the beginning of +self+.
For each given +string_or_regexp+, the pattern is:
For each argument, the pattern used is:

- +string_or_regexp+ itself, if it is a Regexp.
- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
- The pattern itself, if it is a Regexp.
- <tt>Regexp.quote(pattern)</tt>, if it is a string.

Returns +true+ if any pattern matches the beginning, +false+ otherwise:

Expand All @@ -15,4 +14,4 @@ Returns +true+ if any pattern matches the beginning, +false+ otherwise:
'тест'.start_with?('т') # => true
'こんにちは'.start_with?('こ') # => true

Related: String#end_with?.
Related: see {Querying}[rdoc-ref:String@Querying].
24 changes: 15 additions & 9 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -8903,8 +8903,12 @@ rb_str_delete(int argc, VALUE *argv, VALUE str)
* call-seq:
* squeeze!(*selectors) -> self or nil
*
* Like String#squeeze, but modifies +self+ in place.
* Returns +self+ if any changes were made, +nil+ otherwise.
* Like String#squeeze, except that:
*
* - Characters are squeezed in +self+ (not in a copy of +self+).
* - Returns +self+ if any changes are made, +nil+ otherwise.
*
* Related: See {Modifying}[rdoc-ref:String@Modifying].
*/

static VALUE
Expand Down Expand Up @@ -10482,10 +10486,12 @@ rb_str_rstrip(VALUE str)
* call-seq:
* strip! -> self or nil
*
* Like String#strip, except that any modifications are made in +self+;
* returns +self+ if any modification are made, +nil+ otherwise.
* Like String#strip, except that:
*
* Related: String#lstrip!, String#strip!.
* - Any modifications are made to +self+.
* - Returns +self+ if any modification are made, +nil+ otherwise.
*
* Related: see {Modifying}[rdoc-ref:String@Modifying].
*/

static VALUE
Expand Down Expand Up @@ -10519,15 +10525,15 @@ rb_str_strip_bang(VALUE str)
* call-seq:
* strip -> new_string
*
* Returns a copy of the receiver with leading and trailing whitespace removed;
* Returns a copy of +self+ with leading and trailing whitespace removed;
* see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
*
* whitespace = "\x00\t\n\v\f\r "
* s = whitespace + 'abc' + whitespace
* s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
* # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
* s.strip # => "abc"
*
* Related: String#lstrip, String#rstrip.
* Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/

static VALUE
Expand Down Expand Up @@ -11214,7 +11220,7 @@ rb_str_rpartition(VALUE str, VALUE sep)

/*
* call-seq:
* start_with?(*string_or_regexp) -> true or false
* start_with?(*patterns) -> true or false
*
* :include: doc/string/start_with_p.rdoc
*
Expand Down
29 changes: 29 additions & 0 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,20 @@ def self.test = @@x
}
end

def test_getclassvariable_raises
assert_compiles '"uninitialized class variable @@x in Foo"', %q{
class Foo
def self.test = @@x
end

begin
Foo.test
rescue NameError => e
e.message
end
}
end

def test_setclassvariable
assert_compiles '42', %q{
class Foo
Expand All @@ -1686,6 +1700,21 @@ def self.test = @@x = 42
}
end

def test_setclassvariable_raises
assert_compiles '"can\'t modify frozen #<Class:Foo>: Foo"', %q{
class Foo
def self.test = @@x = 42
freeze
end

begin
Foo.test
rescue FrozenError => e
e.message
end
}
end

def test_attr_reader
assert_compiles '[4, 4]', %q{
class C
Expand Down
10 changes: 5 additions & 5 deletions zjit/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,35 @@
/// the method `into()` also causes a name conflict.
pub(crate) trait IntoUsize {
/// Convert to usize. Implementation conditional on width of [usize].
fn as_usize(self) -> usize;
fn to_usize(self) -> usize;
}

#[cfg(target_pointer_width = "64")]
impl IntoUsize for u64 {
fn as_usize(self) -> usize {
fn to_usize(self) -> usize {
self as usize
}
}

#[cfg(target_pointer_width = "64")]
impl IntoUsize for u32 {
fn as_usize(self) -> usize {
fn to_usize(self) -> usize {
self as usize
}
}

impl IntoUsize for u16 {
/// Alias for `.into()`. For convenience so you could use the trait for
/// all unsgined types.
fn as_usize(self) -> usize {
fn to_usize(self) -> usize {
self.into()
}
}

impl IntoUsize for u8 {
/// Alias for `.into()`. For convenience so you could use the trait for
/// all unsgined types.
fn as_usize(self) -> usize {
fn to_usize(self) -> usize {
self.into()
}
}
Expand Down
46 changes: 23 additions & 23 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ fn gen_entry(cb: &mut CodeBlock, iseq: IseqPtr, function_ptr: CodePtr) -> Result
let (code_ptr, gc_offsets) = asm.compile(cb)?;
assert!(gc_offsets.is_empty());
if get_option!(perf) {
let start_ptr = code_ptr.raw_ptr(cb) as usize;
let end_ptr = cb.get_write_ptr().raw_ptr(cb) as usize;
let start_ptr = code_ptr.raw_addr(cb);
let end_ptr = cb.get_write_ptr().raw_addr(cb);
let code_size = end_ptr - start_ptr;
let iseq_name = iseq_get_location(iseq, 0);
register_with_perf(format!("entry for {iseq_name}"), start_ptr, code_size);
Expand Down Expand Up @@ -298,8 +298,8 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Resul
let result = asm.compile(cb);
if let Ok((start_ptr, _)) = result {
if get_option!(perf) {
let start_usize = start_ptr.raw_ptr(cb) as usize;
let end_usize = cb.get_write_ptr().raw_ptr(cb) as usize;
let start_usize = start_ptr.raw_addr(cb);
let end_usize = cb.get_write_ptr().raw_addr(cb);
let code_size = end_usize - start_usize;
let iseq_name = iseq_get_location(iseq, 0);
register_with_perf(iseq_name, start_usize, code_size);
Expand Down Expand Up @@ -508,7 +508,7 @@ fn gen_objtostring(jit: &mut JITState, asm: &mut Assembler, val: Opnd, cd: *cons
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(jit.iseq as usize).into(), val, (cd as usize).into());
let ret = asm_ccall!(asm, rb_vm_objtostring, VALUE::from(jit.iseq).into(), 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 @@ -736,7 +736,7 @@ fn gen_ccall_with_frame(
});

asm_comment!(asm, "switch to new SP register");
let sp_offset = (caller_stack_size + VM_ENV_DATA_SIZE.as_usize()) * SIZEOF_VALUE;
let sp_offset = (caller_stack_size + VM_ENV_DATA_SIZE.to_usize()) * SIZEOF_VALUE;
let new_sp = asm.add(SP, sp_offset.into());
asm.mov(SP, new_sp);

Expand Down Expand Up @@ -792,7 +792,7 @@ fn gen_ccall_variadic(
});

asm_comment!(asm, "switch to new SP register");
let sp_offset = (state.stack().len() - args.len() + VM_ENV_DATA_SIZE.as_usize()) * SIZEOF_VALUE;
let sp_offset = (state.stack().len() - args.len() + VM_ENV_DATA_SIZE.to_usize()) * SIZEOF_VALUE;
let new_sp = asm.add(SP, sp_offset.into());
asm.mov(SP, new_sp);

Expand Down Expand Up @@ -833,12 +833,12 @@ fn gen_setivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, val:

fn gen_getclassvar(jit: &mut JITState, asm: &mut Assembler, id: ID, ic: *const iseq_inline_cvar_cache_entry, state: &FrameState) -> Opnd {
gen_prepare_non_leaf_call(jit, asm, state);
asm_ccall!(asm, rb_vm_getclassvariable, VALUE(jit.iseq as usize).into(), CFP, id.0.into(), Opnd::const_ptr(ic))
asm_ccall!(asm, rb_vm_getclassvariable, VALUE::from(jit.iseq).into(), CFP, id.0.into(), Opnd::const_ptr(ic))
}

fn gen_setclassvar(jit: &mut JITState, asm: &mut Assembler, id: ID, val: Opnd, ic: *const iseq_inline_cvar_cache_entry, state: &FrameState) {
gen_prepare_non_leaf_call(jit, asm, state);
asm_ccall!(asm, rb_vm_setclassvariable, VALUE(jit.iseq as usize).into(), CFP, id.0.into(), val, Opnd::const_ptr(ic));
asm_ccall!(asm, rb_vm_setclassvariable, VALUE::from(jit.iseq).into(), CFP, id.0.into(), val, Opnd::const_ptr(ic));
}

/// Look up global variables
Expand Down Expand Up @@ -975,7 +975,7 @@ fn gen_load_ivar_embedded(asm: &mut Assembler, self_val: Opnd, id: ID, index: u1
// See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h

asm_comment!(asm, "Load embedded ivar id={} index={}", id.contents_lossy(), index);
let offs = ROBJECT_OFFSET_AS_ARY as i32 + (SIZEOF_VALUE * index as usize) as i32;
let offs = ROBJECT_OFFSET_AS_ARY as i32 + (SIZEOF_VALUE * index.to_usize()) as i32;
let self_val = asm.load(self_val);
let ivar_opnd = Opnd::mem(64, self_val, offs);
asm.load(ivar_opnd)
Expand All @@ -990,7 +990,7 @@ fn gen_load_ivar_extended(asm: &mut Assembler, self_val: Opnd, id: ID, index: u1
let tbl_opnd = asm.load(Opnd::mem(64, self_val, ROBJECT_OFFSET_AS_HEAP_FIELDS as i32));

// Read the ivar from the extended table
let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * index as usize) as i32);
let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * index.to_usize()) as i32);
asm.load(ivar_opnd)
}

Expand Down Expand Up @@ -1113,7 +1113,7 @@ fn gen_send(
}
asm.ccall(
rb_vm_send as *const u8,
vec![EC, CFP, (cd as usize).into(), VALUE(blockiseq as usize).into()],
vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
)
}

Expand All @@ -1136,7 +1136,7 @@ fn gen_send_forward(
}
asm.ccall(
rb_vm_sendforward as *const u8,
vec![EC, CFP, (cd as usize).into(), VALUE(blockiseq as usize).into()],
vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
)
}

Expand All @@ -1157,7 +1157,7 @@ fn gen_send_without_block(
}
asm.ccall(
rb_vm_opt_send_without_block as *const u8,
vec![EC, CFP, (cd as usize).into()],
vec![EC, CFP, Opnd::const_ptr(cd)],
)
}

Expand All @@ -1174,8 +1174,8 @@ fn gen_send_without_block_direct(
) -> lir::Opnd {
gen_incr_counter(asm, Counter::iseq_optimized_send_count);

let local_size = unsafe { get_iseq_body_local_table_size(iseq) }.as_usize();
let stack_growth = state.stack_size() + local_size + unsafe { get_iseq_body_stack_max(iseq) }.as_usize();
let local_size = unsafe { get_iseq_body_local_table_size(iseq) }.to_usize();
let stack_growth = state.stack_size() + local_size + unsafe { get_iseq_body_stack_max(iseq) }.to_usize();
gen_stack_overflow_check(jit, asm, state, stack_growth);

// Save cfp->pc and cfp->sp for the caller frame
Expand Down Expand Up @@ -1211,7 +1211,7 @@ fn gen_send_without_block_direct(
});

asm_comment!(asm, "switch to new SP register");
let sp_offset = (state.stack().len() + local_size - args.len() + VM_ENV_DATA_SIZE.as_usize()) * SIZEOF_VALUE;
let sp_offset = (state.stack().len() + local_size - args.len() + VM_ENV_DATA_SIZE.to_usize()) * SIZEOF_VALUE;
let new_sp = asm.add(SP, sp_offset.into());
asm.mov(SP, new_sp);

Expand Down Expand Up @@ -1263,7 +1263,7 @@ fn gen_invokeblock(
}
asm.ccall(
rb_vm_invokeblock as *const u8,
vec![EC, CFP, (cd as usize).into()],
vec![EC, CFP, Opnd::const_ptr(cd)],
)
}

Expand All @@ -1285,7 +1285,7 @@ fn gen_invokesuper(
}
asm.ccall(
rb_vm_invokesuper as *const u8,
vec![EC, CFP, (cd as usize).into(), VALUE(blockiseq as usize).into()],
vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
)
}

Expand Down Expand Up @@ -1544,7 +1544,7 @@ fn gen_is_method_cfunc(jit: &JITState, asm: &mut Assembler, val: lir::Opnd, cd:
unsafe extern "C" {
fn rb_vm_method_cfunc_is(iseq: IseqPtr, cd: *const rb_call_data, recv: VALUE, cfunc: *const u8) -> VALUE;
}
asm_ccall!(asm, rb_vm_method_cfunc_is, VALUE(jit.iseq as usize).into(), (cd as usize).into(), val, (cfunc as usize).into())
asm_ccall!(asm, rb_vm_method_cfunc_is, VALUE::from(jit.iseq).into(), Opnd::const_ptr(cd), val, Opnd::const_ptr(cfunc))
}

fn gen_is_bit_equal(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd {
Expand Down Expand Up @@ -1889,7 +1889,7 @@ fn param_opnd(idx: usize) -> Opnd {
/// Inverse of ep_offset_to_local_idx(). See ep_offset_to_local_idx() for details.
pub fn local_idx_to_ep_offset(iseq: IseqPtr, local_idx: usize) -> i32 {
let local_size = unsafe { get_iseq_body_local_table_size(iseq) };
local_size_and_idx_to_ep_offset(local_size as usize, local_idx)
local_size_and_idx_to_ep_offset(local_size.to_usize(), local_idx)
}

/// Convert the number of locals and a local index to an offset from the EP
Expand Down Expand Up @@ -2005,8 +2005,8 @@ c_callable! {
rb_set_cfp_sp(cfp, sp);

// Fill nils to uninitialized (non-argument) locals
let local_size = get_iseq_body_local_table_size(iseq) as usize;
let num_params = get_iseq_body_param_size(iseq) as usize;
let local_size = get_iseq_body_local_table_size(iseq).to_usize();
let num_params = get_iseq_body_param_size(iseq).to_usize();
let base = sp.offset(-local_size_and_idx_to_bp_offset(local_size, num_params) as isize);
slice::from_raw_parts_mut(base, local_size - num_params).fill(Qnil);
}
Expand Down
11 changes: 11 additions & 0 deletions zjit/src/cruby_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ pub fn init() -> Annotations {
annotate!(rb_cArray, "reverse", types::ArrayExact, leaf, elidable);
annotate!(rb_cArray, "join", types::StringExact);
annotate!(rb_cArray, "[]", inline_array_aref);
annotate!(rb_cArray, "<<", inline_array_push);
annotate!(rb_cArray, "push", inline_array_push);
annotate!(rb_cHash, "[]", inline_hash_aref);
annotate!(rb_cHash, "size", types::Fixnum, no_gc, leaf, elidable);
annotate!(rb_cHash, "empty?", types::BoolExact, no_gc, leaf, elidable);
Expand Down Expand Up @@ -266,6 +268,15 @@ fn inline_array_aref(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
None
}

fn inline_array_push(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
// Inline only the case of `<<` or `push` when called with a single argument.
if let &[val] = args {
let _ = fun.push_insn(block, hir::Insn::ArrayPush { array: recv, val, state });
return Some(recv);
}
None
}

fn inline_hash_aref(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
if let &[key] = args {
let result = fun.push_insn(block, hir::Insn::HashAref { hash: recv, key, state });
Expand Down
Loading