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
19 changes: 19 additions & 0 deletions doc/string/hash.rdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Returns the integer hash value for +self+.

Two \String objects that have identical content and compatible encodings
also have the same hash value;
see Object#hash and {Encodings}[rdoc-ref:encodings.rdoc]:

s = 'foo'
h = s.hash # => -569050784
h == 'foo'.hash # => true
h == 'food'.hash # => false
h == 'FOO'.hash # => false

s0 = "äöü"
s1 = s0.encode(Encoding::ISO_8859_1)
s0.encoding # => #<Encoding:UTF-8>
s1.encoding # => #<Encoding:ISO-8859-1>
s0.hash == s1.hash # => false

Related: see {Querying}[rdoc-ref:String@Querying].
2 changes: 0 additions & 2 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,6 @@ rb_gc_multi_ractor_p(void)
return rb_multi_ractor_p();
}

bool rb_obj_is_main_ractor(VALUE gv);

bool
rb_gc_shutdown_call_finalizer_p(VALUE obj)
{
Expand Down
3 changes: 2 additions & 1 deletion proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4012,12 +4012,13 @@ proc_ruby2_keywords(VALUE procval)
switch (proc->block.type) {
case block_type_iseq:
if (ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_rest &&
!ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_post &&
!ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_kw &&
!ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_kwrest) {
ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.ruby2_keywords = 1;
}
else {
rb_warn("Skipping set of ruby2_keywords flag for proc (proc accepts keywords or proc does not accept argument splat)");
rb_warn("Skipping set of ruby2_keywords flag for proc (proc accepts keywords or post arguments or proc does not accept argument splat)");
}
break;
default:
Expand Down
8 changes: 0 additions & 8 deletions ractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,14 +585,6 @@ rb_ractor_main_p_(void)
return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
}

bool
rb_obj_is_main_ractor(VALUE gv)
{
if (!rb_ractor_p(gv)) return false;
rb_ractor_t *r = DATA_PTR(gv);
return r == GET_VM()->ractor.main_ractor;
}

int
rb_ractor_living_thread_num(const rb_ractor_t *r)
{
Expand Down
1 change: 0 additions & 1 deletion shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -1625,7 +1625,6 @@ Init_shape(void)
rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR));
rb_define_const(rb_cShape, "SHAPE_ID_NUM_BITS", INT2NUM(SHAPE_ID_NUM_BITS));
rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT));
rb_define_const(rb_cShape, "SPECIAL_CONST_SHAPE_ID", INT2NUM(SPECIAL_CONST_SHAPE_ID));
rb_define_const(rb_cShape, "SHAPE_MAX_VARIATIONS", INT2NUM(SHAPE_MAX_VARIATIONS));
rb_define_const(rb_cShape, "SIZEOF_RB_SHAPE_T", INT2NUM(sizeof(rb_shape_t)));
rb_define_const(rb_cShape, "SIZEOF_REDBLACK_NODE_T", INT2NUM(sizeof(redblack_node_t)));
Expand Down
1 change: 0 additions & 1 deletion shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ typedef uint32_t redblack_id_t;
#define ROOT_SHAPE_WITH_OBJ_ID 0x1
#define ROOT_TOO_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_TOO_COMPLEX)
#define ROOT_TOO_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_TOO_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
#define SPECIAL_CONST_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_FROZEN)

typedef struct redblack_node redblack_node_t;

Expand Down
17 changes: 15 additions & 2 deletions spec/ruby/core/module/ruby2_keywords_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def obj.foo(a, b, c) end

it "prints warning when a method accepts keywords" do
obj = Object.new
def obj.foo(a:, b:) end
def obj.foo(*a, b:) end

-> {
obj.singleton_class.class_exec do
Expand All @@ -224,12 +224,25 @@ def obj.foo(a:, b:) end

it "prints warning when a method accepts keyword splat" do
obj = Object.new
def obj.foo(**a) end
def obj.foo(*a, **b) end

-> {
obj.singleton_class.class_exec do
ruby2_keywords :foo
end
}.should complain(/Skipping set of ruby2_keywords flag for/)
end

ruby_version_is "3.5" do
it "prints warning when a method accepts post arguments" do
obj = Object.new
def obj.foo(*a, b) end

-> {
obj.singleton_class.class_exec do
ruby2_keywords :foo
end
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
end
end
14 changes: 12 additions & 2 deletions spec/ruby/core/proc/ruby2_keywords_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,28 @@
end

it "prints warning when a proc accepts keywords" do
f = -> a:, b: { }
f = -> *a, b: { }

-> {
f.ruby2_keywords
}.should complain(/Skipping set of ruby2_keywords flag for/)
end

it "prints warning when a proc accepts keyword splat" do
f = -> **a { }
f = -> *a, **b { }

-> {
f.ruby2_keywords
}.should complain(/Skipping set of ruby2_keywords flag for/)
end

ruby_version_is "3.5" do
it "prints warning when a proc accepts post arguments" do
f = -> *a, b { }

-> {
f.ruby2_keywords
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
end
end
4 changes: 1 addition & 3 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -4133,10 +4133,8 @@ rb_str_hash_cmp(VALUE str1, VALUE str2)
* call-seq:
* hash -> integer
*
* Returns the integer hash value for +self+.
* The value is based on the length, content and encoding of +self+.
* :include: doc/string/hash.rdoc
*
* Related: Object#hash.
*/

static VALUE
Expand Down
32 changes: 29 additions & 3 deletions test/ruby/test_keyword.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2424,6 +2424,21 @@ class << c
assert_raise(ArgumentError) { m.call(42, a: 1, **h2) }
end

def test_ruby2_keywords_post_arg
def self.a(*c, **kw) [c, kw] end
def self.b(*a, b) a(*a, b) end
assert_warn(/Skipping set of ruby2_keywords flag for b \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
assert_nil(singleton_class.send(:ruby2_keywords, :b))
end
assert_equal([[{foo: 1}, {bar: 1}], {}], b({foo: 1}, bar: 1))

b = ->(*a, b){a(*a, b)}
assert_warn(/Skipping set of ruby2_keywords flag for proc \(proc accepts keywords or post arguments or proc does not accept argument splat\)/) do
b.ruby2_keywords
end
assert_equal([[{foo: 1}, {bar: 1}], {}], b.({foo: 1}, bar: 1))
end

def test_proc_ruby2_keywords
h1 = {:a=>1}
foo = ->(*args, &block){block.call(*args)}
Expand All @@ -2436,8 +2451,8 @@ def test_proc_ruby2_keywords
assert_raise(ArgumentError) { foo.call(:a=>1, &->(arg, **kw){[arg, kw]}) }
assert_equal(h1, foo.call(:a=>1, &->(arg){arg}))

[->(){}, ->(arg){}, ->(*args, **kw){}, ->(*args, k: 1){}, ->(*args, k: ){}].each do |pr|
assert_warn(/Skipping set of ruby2_keywords flag for proc \(proc accepts keywords or proc does not accept argument splat\)/) do
[->(){}, ->(arg){}, ->(*args, x){}, ->(*args, **kw){}, ->(*args, k: 1){}, ->(*args, k: ){}].each do |pr|
assert_warn(/Skipping set of ruby2_keywords flag for proc \(proc accepts keywords or post arguments or proc does not accept argument splat\)/) do
pr.ruby2_keywords
end
end
Expand Down Expand Up @@ -2790,10 +2805,21 @@ def method_missing(*args)
assert_equal(:opt, o.clear_last_opt(a: 1))
assert_nothing_raised(ArgumentError) { o.clear_last_empty_method(a: 1) }

assert_warn(/Skipping set of ruby2_keywords flag for bar \(method accepts keywords or method does not accept argument splat\)/) do
assert_warn(/Skipping set of ruby2_keywords flag for bar \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
assert_nil(c.send(:ruby2_keywords, :bar))
end

c.class_eval do
def bar_post(*a, x) = nil
define_method(:bar_post_bmethod) { |*a, x| }
end
assert_warn(/Skipping set of ruby2_keywords flag for bar_post \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
assert_nil(c.send(:ruby2_keywords, :bar_post))
end
assert_warn(/Skipping set of ruby2_keywords flag for bar_post_bmethod \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
assert_nil(c.send(:ruby2_keywords, :bar_post_bmethod))
end

utf16_sym = "abcdef".encode("UTF-16LE").to_sym
c.send(:define_method, utf16_sym, c.instance_method(:itself))
assert_warn(/abcdef/) do
Expand Down
7 changes: 7 additions & 0 deletions test/ruby/test_ractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@ def ractor_job(job_count, array_size)
RUBY
end

# [Bug #20146]
def test_max_cpu_1
assert_ractor(<<~'RUBY', args: [{ "RUBY_MAX_CPU" => "1" }])
assert_equal :ok, Ractor.new { :ok }.value
RUBY
end

def assert_make_shareable(obj)
refute Ractor.shareable?(obj), "object was already shareable"
Ractor.make_shareable(obj)
Expand Down
6 changes: 4 additions & 2 deletions test/ruby/test_shapes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1051,8 +1051,10 @@ def test_raise_on_special_consts
# RUBY_PLATFORM =~ /i686/
end

def test_root_shape_transition_to_special_const_on_frozen
assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of([].freeze).id)
def test_root_shape_frozen
frozen_root_shape = RubyVM::Shape.of([].freeze)
assert_predicate(frozen_root_shape, :frozen?)
assert_equal(RubyVM::Shape.root_shape.id, frozen_root_shape.raw_id)
end

def test_basic_shape_transition
Expand Down
10 changes: 7 additions & 3 deletions thread_pthread_mn.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,15 @@ native_thread_check_and_create_shared(rb_vm_t *vm)

rb_native_mutex_lock(&vm->ractor.sched.lock);
{
unsigned int snt_cnt = vm->ractor.sched.snt_cnt;
if (!vm->ractor.main_ractor->threads.sched.enable_mn_threads) snt_cnt++; // do not need snt for main ractor
unsigned int schedulable_ractor_cnt = vm->ractor.cnt;
RUBY_ASSERT(schedulable_ractor_cnt >= 1);

if (!vm->ractor.main_ractor->threads.sched.enable_mn_threads)
schedulable_ractor_cnt--; // do not need snt for main ractor

unsigned int snt_cnt = vm->ractor.sched.snt_cnt;
if (((int)snt_cnt < MINIMUM_SNT) ||
(snt_cnt < vm->ractor.cnt &&
(snt_cnt < schedulable_ractor_cnt &&
snt_cnt < vm->ractor.sched.max_cpu)) {

RUBY_DEBUG_LOG("added snt:%u dnt:%u ractor_cnt:%u grq_cnt:%u",
Expand Down
6 changes: 4 additions & 2 deletions vm_method.c
Original file line number Diff line number Diff line change
Expand Up @@ -2959,13 +2959,14 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
switch (me->def->type) {
case VM_METHOD_TYPE_ISEQ:
if (ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_rest &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_post &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kw &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kwrest) {
ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.ruby2_keywords = 1;
rb_clear_method_cache(module, name);
}
else {
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name));
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
}
break;
case VM_METHOD_TYPE_BMETHOD: {
Expand All @@ -2978,13 +2979,14 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval);
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
if (ISEQ_BODY(iseq)->param.flags.has_rest &&
!ISEQ_BODY(iseq)->param.flags.has_post &&
!ISEQ_BODY(iseq)->param.flags.has_kw &&
!ISEQ_BODY(iseq)->param.flags.has_kwrest) {
ISEQ_BODY(iseq)->param.flags.ruby2_keywords = 1;
rb_clear_method_cache(module, name);
}
else {
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name));
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
}
break;
}
Expand Down
1 change: 0 additions & 1 deletion zjit.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,6 @@ rb_zjit_shape_obj_too_complex_p(VALUE obj)
}

enum {
RB_SPECIAL_CONST_SHAPE_ID = SPECIAL_CONST_SHAPE_ID,
RB_INVALID_SHAPE_ID = INVALID_SHAPE_ID,
};

Expand Down
1 change: 0 additions & 1 deletion zjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@ fn main() {
.allowlist_function("rb_zjit_singleton_class_p")
.allowlist_type("robject_offsets")
.allowlist_type("rstring_offsets")
.allowlist_var("RB_SPECIAL_CONST_SHAPE_ID")
.allowlist_var("RB_INVALID_SHAPE_ID")

// From jit.c
Expand Down
28 changes: 2 additions & 26 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,35 +1005,11 @@ fn gen_new_hash(
pairs.push(val);
}

let n = pairs.len();

// Calculate the compile-time NATIVE_STACK_PTR offset from NATIVE_BASE_PTR
// At this point, frame_setup(&[], jit.c_stack_slots) has been called,
// which allocated aligned_stack_bytes(jit.c_stack_slots) on the stack
let frame_size = aligned_stack_bytes(jit.c_stack_slots);
let allocation_size = aligned_stack_bytes(n);

asm_comment!(asm, "allocate {} bytes on C stack for {} hash elements", allocation_size, n);
asm.sub_into(NATIVE_STACK_PTR, allocation_size.into());

// Calculate the total offset from NATIVE_BASE_PTR to our buffer
let total_offset_from_base = (frame_size + allocation_size) as i32;

for (idx, &pair_opnd) in pairs.iter().enumerate() {
let slot_offset = -total_offset_from_base + (idx as i32 * SIZEOF_VALUE_I32);
asm.mov(
Opnd::mem(VALUE_BITS, NATIVE_BASE_PTR, slot_offset),
pair_opnd
);
}

let argv = asm.lea(Opnd::mem(64, NATIVE_BASE_PTR, -total_offset_from_base));

let argv = gen_push_opnds(jit, asm, &pairs);
let argc = (elements.len() * 2) as ::std::os::raw::c_long;
asm_ccall!(asm, rb_hash_bulk_insert, lir::Opnd::Imm(argc), argv, new_hash);

asm_comment!(asm, "restore C stack pointer");
asm.add_into(NATIVE_STACK_PTR, allocation_size.into());
gen_pop_opnds(asm, &pairs);
}

new_hash
Expand Down
1 change: 0 additions & 1 deletion zjit/src/cruby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ pub type IseqPtr = *const rb_iseq_t;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ShapeId(pub u32);

pub const SPECIAL_CONST_SHAPE_ID: ShapeId = ShapeId(RB_SPECIAL_CONST_SHAPE_ID);
pub const INVALID_SHAPE_ID: ShapeId = ShapeId(RB_INVALID_SHAPE_ID);

// Given an ISEQ pointer, convert PC to insn_idx
Expand Down
1 change: 0 additions & 1 deletion zjit/src/cruby_bindings.inc.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.