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
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ They are still available on rubygems.org and can be installed with
* 3.7.5 to [3.7.6][test-unit-3.7.6], [3.7.7][test-unit-3.7.7], [3.7.8][test-unit-3.7.8]
* rss 0.3.3
* 0.3.2 to [0.3.3][rss-0.3.3]
* net-imap 0.6.6
* net-imap 0.6.7
* 0.6.2 to [v0.6.3][net-imap-v0.6.3], [v0.6.4][net-imap-v0.6.4], [v0.6.4.1][net-imap-v0.6.4.1], [v0.6.5][net-imap-v0.6.5], [v0.6.6][net-imap-v0.6.6]
* rbs 4.2.0
* 3.10.0 to [v3.10.1][rbs-v3.10.1], [v3.10.2][rbs-v3.10.2], [v3.10.3][rbs-v3.10.3], [v3.10.4][rbs-v3.10.4], [v4.0.0.dev.1][rbs-v4.0.0.dev.1], [v4.0.0.dev.2][rbs-v4.0.0.dev.2], [v4.0.0.dev.3][rbs-v4.0.0.dev.3], [v4.0.0.dev.4][rbs-v4.0.0.dev.4], [v4.0.0.dev.5][rbs-v4.0.0.dev.5], [v4.0.0][rbs-v4.0.0], [v4.0.1.dev.1][rbs-v4.0.1.dev.1], [v4.0.1.dev.2][rbs-v4.0.1.dev.2], [v4.0.1][rbs-v4.0.1], [v4.0.2][rbs-v4.0.2], [v4.0.3][rbs-v4.0.3], [v4.1.0.pre.1][rbs-v4.1.0.pre.1], [v4.1.0.pre.2][rbs-v4.1.0.pre.2], [v4.1.0][rbs-v4.1.0], [v4.1.1.pre.1][rbs-v4.1.1.pre.1], [v4.1.1][rbs-v4.1.1], [v4.1.2][rbs-v4.1.2], [v4.1.3][rbs-v4.1.3], [v4.2.0.pre.1][rbs-v4.2.0.pre.1], [v4.2.0][rbs-v4.2.0]
Expand Down
9 changes: 8 additions & 1 deletion gc/mmtk/mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,10 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
alloc_obj[0] = flags;
alloc_obj[1] = klass;

if (RB_UNLIKELY(!wb_protected)) {
mmtk_register_wb_unprotected_object((MMTk_ObjectReference)alloc_obj);
}

if (semantics == MMTK_ALLOCATION_SEMANTICS_LOS || ractor_cache->bump_pointer == NULL) {
mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, total_size, semantics);
}
Expand Down Expand Up @@ -1741,16 +1745,18 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)

// Miscellaneous

#define RB_GC_OBJECT_METADATA_ENTRY_COUNT 1
#define RB_GC_OBJECT_METADATA_ENTRY_COUNT 2
static struct rb_gc_object_metadata_entry object_metadata_entries[RB_GC_OBJECT_METADATA_ENTRY_COUNT + 1];

struct rb_gc_object_metadata_entry *
rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
{
static ID ID_wb_protected;
static ID ID_object_id;

if (!ID_object_id) {
#define I(s) ID_##s = rb_intern(#s);
I(wb_protected);
I(object_id);
#undef I
}
Expand All @@ -1764,6 +1770,7 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
n++; \
} while (0)

if (!mmtk_object_wb_unprotected_p((MMTk_ObjectReference)obj)) SET_ENTRY(wb_protected, Qtrue);
if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));

object_metadata_entries[n].name = 0;
Expand Down
2 changes: 1 addition & 1 deletion gems/bundled_gems
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ rake 13.4.2 https://github.com/ruby/rake
test-unit 3.7.8 https://github.com/test-unit/test-unit
rexml 3.4.4 https://github.com/ruby/rexml
rss 0.3.3 https://github.com/ruby/rss
net-imap 0.6.6 https://github.com/ruby/net-imap
net-imap 0.6.7 https://github.com/ruby/net-imap
net-smtp 0.5.1 https://github.com/ruby/net-smtp
matrix 0.4.3 https://github.com/ruby/matrix
prime 0.1.4 https://github.com/ruby/prime
Expand Down
22 changes: 12 additions & 10 deletions io_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,8 @@ io_buffer_validate_for_writing(struct rb_io_buffer *buffer)
static struct rb_io_buffer *
get_io_buffer_for_writing(VALUE self)
{
rb_check_frozen(self);

struct rb_io_buffer *buffer = get_io_buffer(self);
io_buffer_validate_for_writing(buffer);
return buffer;
Expand Down Expand Up @@ -3302,7 +3304,7 @@ io_buffer_set_string(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 4);

struct rb_io_buffer *buffer = get_io_buffer(self);
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

VALUE string = rb_str_to_str(argv[0]);

Expand All @@ -3317,7 +3319,7 @@ io_buffer_set_string(int argc, VALUE *argv, VALUE self)
void
rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length)
{
struct rb_io_buffer *buffer = get_io_buffer(self);
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

void *base;
size_t size;
Expand Down Expand Up @@ -3472,10 +3474,10 @@ io_buffer_read_internal(void *_argument)
VALUE
rb_io_buffer_read(VALUE self, VALUE io, size_t offset, size_t length)
{
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

io = rb_io_get_io(io);

struct rb_io_buffer *buffer = get_io_buffer(self);
io_buffer_validate_for_writing(buffer);
io_buffer_validate_range(buffer, offset, length);

if (length == 0) return SIZET2NUM(0);
Expand Down Expand Up @@ -3563,10 +3565,10 @@ io_buffer_pread_internal(void *_argument)
VALUE
rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t offset, size_t length)
{
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

io = rb_io_get_io(io);

struct rb_io_buffer *buffer = get_io_buffer(self);
io_buffer_validate_for_writing(buffer);
io_buffer_validate_range(buffer, offset, length);

if (length == 0) return SIZET2NUM(0);
Expand Down Expand Up @@ -4032,7 +4034,7 @@ memory_and_inplace(unsigned char * restrict base, size_t size, unsigned char * r
static VALUE
io_buffer_and_inplace(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = get_io_buffer(self);
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

struct rb_io_buffer *mask_buffer = get_io_buffer(mask);

Expand Down Expand Up @@ -4080,7 +4082,7 @@ memory_or_inplace(unsigned char * restrict base, size_t size, unsigned char * re
static VALUE
io_buffer_or_inplace(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = get_io_buffer(self);
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

struct rb_io_buffer *mask_buffer = get_io_buffer(mask);

Expand Down Expand Up @@ -4128,7 +4130,7 @@ memory_xor_inplace(unsigned char * restrict base, size_t size, unsigned char * r
static VALUE
io_buffer_xor_inplace(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = get_io_buffer(self);
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

struct rb_io_buffer *mask_buffer = get_io_buffer(mask);

Expand Down Expand Up @@ -4176,7 +4178,7 @@ memory_not_inplace(unsigned char * restrict base, size_t size)
static VALUE
io_buffer_not_inplace(VALUE self)
{
struct rb_io_buffer *buffer = get_io_buffer(self);
struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);

void *base;
size_t size;
Expand Down
15 changes: 8 additions & 7 deletions spec/ruby/core/kernel/require_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,16 @@
when "jruby"
features -= %w[java.rb jruby/util.rb]
when "ruby"
so = RbConfig::CONFIG['DLEXT']
features.reject! { |feature| feature.end_with?("windows_1252.#{so}", "windows_31j.#{so}") }
features.reject! { |feature| feature.end_with? "encdb.#{so}" }
features.reject! { |feature| feature.end_with? "transdb.#{so}" }
features.reject! { |feature| feature.include?('-fake') }
# remove all external libraries first
features.reject! { |feature| File.absolute_path?(feature) }

# for statically-linked ruby
features -= [ "encdb.so", "trans/transdb.so" ] # the suffixes are always ".so"
features.reject! { |feature| feature.start_with?("enc/") } # and "enc/trans/"
end

features_no_ext = features.map { |path| File.basename(path, '.*') }
features_no_ext.sort.should == provided.sort
features_no_ext = features.map { |path| path.sub(/\.(?:rb|so)\z/, '') }
features_no_ext.sort.uniq.should == provided.sort

requires = features
code = requires.map { |f| "puts require #{f.inspect}\n" }.join
Expand Down
27 changes: 26 additions & 1 deletion spec/ruby/core/string/tr_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
"hello".tr("a-z", "A-H.").should == "HE..."
end

it "raises an ArgumentError when the receiver has broken encoding" do
-> { "\xFF".tr("€", "b") }.should.raise(ArgumentError)
-> { "\xFF".tr("", "") }.should.raise(ArgumentError)
end

it "raises an ArgumentError when given wrong number of arguments" do
-> { "hello".tr }.should.raise(ArgumentError)
ruby_version_is ""..."4.1" do
Expand Down Expand Up @@ -141,6 +146,10 @@
"h€llø".tr("€" => "e", "ø" => "o").should == "hello"
end

it "returns a copy of self if the translation hash is empty" do
"hello".tr({}).should == "hello"
end

it "returns a string in the combined encoding" do
str = "hello".encode(Encoding::US_ASCII).tr("e" => "é")
str.should == "héllo"
Expand All @@ -160,6 +169,11 @@
).should == "hello".encode(Encoding::UTF_16LE)
end

it "raises ArgumentError the string encoding is broken" do
-> { "\xFF".tr("€" => "b") }.should.raise(ArgumentError)
-> { "\xFF".tr({}) }.should.raise(ArgumentError)
end

it "raises ArgumentError if a key is more than one codepoint" do
-> { "hello".tr("hel" => "") }.should.raise(ArgumentError)
-> { "🤦🏼‍♂️".tr("🤦🏼‍♂️" => "") }.should.raise(ArgumentError)
Expand Down Expand Up @@ -231,7 +245,18 @@
end

it "returns nil if the string wasn't modified" do
"hello".tr!("€" => "", "Ø" => "").should == nil
s = "hello"
s.tr!({}).should == nil
s.should == "hello"

s = "hello"
s.tr!("€" => "", "Ø" => "").should == nil
s.should == "hello"
end

it "raises ArgumentError the string encoding is broken" do
-> { "\xFF".tr!("€" => "b") }.should.raise(ArgumentError)
-> { "\xFF".tr!({}) }.should.raise(ArgumentError)
end

it "raises ArgumentError if a key is more than one codepoint" do
Expand Down
44 changes: 32 additions & 12 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -9362,7 +9362,7 @@ tr_trans_pairs_search_sse2(struct tr_trans_pairs_search *search)
matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
}

for (i = i; i < search->needles_count; i++) {
for (i = 1; i < search->needles_count; i++) {
matches[0] = _mm_or_si128(matches[0], matches[i]);
}

Expand Down Expand Up @@ -9427,7 +9427,7 @@ tr_trans_pairs_search_neon(struct tr_trans_pairs_search *search)
matches[i] = vceqq_u8(bytes, masks[i]);
}

for (i = i; i < search->needles_count; i++) {
for (i = 1; i < search->needles_count; i++) {
matches[0] = vorrq_u8(matches[0], matches[i]);
}

Expand Down Expand Up @@ -9457,6 +9457,7 @@ tr_trans_pairs(VALUE str, VALUE pairs_val)
{
Check_Type(pairs_val, T_HASH);
size_t pairs_count = RHASH_SIZE(pairs_val);
mustnot_broken(str);
rb_str_modify(str);

if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0) return Qnil;
Expand Down Expand Up @@ -9486,6 +9487,7 @@ tr_trans_pairs(VALUE str, VALUE pairs_val)
bool modify = false;

if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {

struct tr_trans_pairs_search search = {
.s = sstart,
.send = sstart + str_len,
Expand Down Expand Up @@ -9609,6 +9611,10 @@ tr_trans_pairs(VALUE str, VALUE pairs_val)
}
}

if (!modify) {
return Qnil;
}

if (!STR_EMBED_P(str)) {
SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
}
Expand All @@ -9621,13 +9627,10 @@ tr_trans_pairs(VALUE str, VALUE pairs_val)

RB_GC_GUARD(hash);

if (modify) {
if (cr != ENC_CODERANGE_BROKEN)
ENC_CODERANGE_SET(str, cr);
rb_enc_associate(str, e1);
return str;
}
return Qnil;
if (cr != ENC_CODERANGE_BROKEN)
ENC_CODERANGE_SET(str, cr);
rb_enc_associate(str, e1);
return str;
}

/*
Expand Down Expand Up @@ -9661,9 +9664,24 @@ rb_str_tr_bang(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
* tr(selector, replacements) -> new_string
* tr(pairs) -> new_string
*
* Accepts either a +selector+ and a +replacements+ string,
* or a single +pairs+ Hash.
*
* When a +pairs+ Hash is provided the keys, returns a copy of +self+ with
* the keys of the hash replaced by the values.
*
* - They keys must be strings containing a single codepoints.
* - The values can be of any length.
*
* Returns a copy of +self+ with each character specified by string +selector+
* translated to the corresponding character in string +replacements+.
* Example:
*
* 'hello'.tr('e' => 'er', 'l' => '', 'o' => 'o !') #=> "hero !"
*
* When +selector+ and +replacements+are provided, returns a copy of +self+
* with each character specified by string +selector+ translated to the
* corresponding character in string +replacements+.
* The correspondence is _positional_:
*
* - Each occurrence of the first character specified by +selector+
Expand Down Expand Up @@ -9704,7 +9722,9 @@ rb_str_tr(int argc, VALUE *argv, VALUE str)

if (argc == 1) {
VALUE pairs = argv[0];
return tr_trans_pairs(str, pairs);
VALUE result = tr_trans_pairs(str, pairs);
if (NIL_P(result)) result = str;
return str;
}

VALUE src = argv[0], repl = argv[1];
Expand Down
1 change: 0 additions & 1 deletion test/.excludes-mmtk/TestObjSpace.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
exclude(:test_dump_all_full, "testing behaviour specific to default GC")
exclude(:test_dump_flag_age, "testing behaviour specific to default GC")
exclude(:test_dump_flags, "testing behaviour specific to default GC")
exclude(:test_dump_flags_wb_protected, "testing behaviour specific to default GC")
exclude(:test_dump_objects_dumps_page_slot_sizes, "testing behaviour specific to default GC")
exclude(:test_trace_object_allocations_does_not_reuse_freed_allocation_info, "hang up")
24 changes: 24 additions & 0 deletions test/ruby/test_io_buffer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,30 @@ def test_transfer_frozen_external
assert_equal string, buffer.get_string
end

def test_write_frozen
buffer = IO::Buffer.new(8)
buffer.freeze

mask = IO::Buffer.new(8)

assert_raise(FrozenError) {buffer.set_string("x")}
assert_raise(FrozenError) {buffer.copy(IO::Buffer.new(8))}
assert_raise(FrozenError) {buffer.clear}
assert_raise(FrozenError) {buffer.set_value(:U8, 0, 1)}
assert_raise(FrozenError) {buffer.set_values([:U8], 0, [1])}
assert_raise(FrozenError) {buffer.and!(mask)}
assert_raise(FrozenError) {buffer.or!(mask)}
assert_raise(FrozenError) {buffer.xor!(mask)}
assert_raise(FrozenError) {buffer.not!}

File.open(__FILE__) do |file|
assert_raise(FrozenError) {buffer.read(file)}
assert_raise(FrozenError) {buffer.pread(file, 0)}
end

assert_equal "\0" * 8, buffer.get_string
end

def test_counted_locking
buffer = IO::Buffer.new(128)

Expand Down
2 changes: 2 additions & 0 deletions test/ruby/test_string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2687,6 +2687,8 @@ def test_tr_hash
assert_equal S(("A"*16 + "x" + "B"*3)), S(("A"*16 + "<" + "B"*3)).tr({"<"=>"x"})
assert_equal S(("x"+"A"*16 + "B"*3)), S(("<"+"A"*16 + "B"*3)).tr({"<"=>"x"})
assert_equal S(("."*15 + "<" * 17)), S(("."*15 + "x"*17)).tr({"x"=>"<"})

assert_equal(S("01@3456789abcdefgHij"), S("0123456789abcdefghij").tr("h" => "H", "2" => "@"))
end

def test_tr!
Expand Down