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
26 changes: 24 additions & 2 deletions array.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ VALUE rb_cArray_empty_frozen;
* 14: RARRAY_PTR_IN_USE_FLAG
* The buffer of the array is in use. This is only used during
* debugging.
* 19: RARRAY_FAKEARY
* The array is not allocated or managed by the garbage collector.
* Typically, the array object header (struct RString) is temporarily
* allocated on C stack.
*/

/* for OPTIMIZED_CMP: */
Expand Down Expand Up @@ -188,7 +192,7 @@ ARY_SET(VALUE a, long i, VALUE v)
static long
ary_embed_capa(VALUE ary)
{
size_t size = rb_gc_obj_slot_size(ary) - offsetof(struct RArray, as.ary);
size_t size = rb_obj_shape_slot_size(ary) - offsetof(struct RArray, as.ary);
RUBY_ASSERT(size % sizeof(VALUE) == 0);
return size / sizeof(VALUE);
}
Expand Down Expand Up @@ -900,7 +904,7 @@ static VALUE
init_fake_ary_flags(void)
{
struct RArray fake_ary = {0};
fake_ary.basic.flags = T_ARRAY;
fake_ary.basic.flags = T_ARRAY | RARRAY_FAKEARY;
VALUE ary = (VALUE)&fake_ary;
RBASIC_SET_FULL_SHAPE_ID(ary, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
rb_ary_freeze(ary);
Expand Down Expand Up @@ -2380,6 +2384,24 @@ rb_ary_set_len(VALUE ary, long len)
ARY_SET_LEN(ary, len);
}

VALUE
rb_ary_modify_expand(VALUE ary, long expand)
{
long len = RARRAY_LEN(ary);

if (expand < 0) {
rb_raise(rb_eArgError, "negative expanding array size");
}
if (expand >= ARY_MAX_SIZE - len) {
rb_raise(rb_eArgError, " size too big");
}
rb_ary_modify_check(ary);
if (len + expand > ARY_CAPA(ary)) {
ary_resize_capa(ary, len + expand);
}
return ary;
}

VALUE
rb_ary_resize(VALUE ary, long len)
{
Expand Down
8 changes: 8 additions & 0 deletions benchmark/string_concat.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
prelude: |
# frozen_string_literal: true
CHUNK = "a" * 64
UCHUNK = "é" * 32
SHORT = "a" * (GC.stat_heap(0, :slot_size) / 2)
LONG = "a" * (GC.stat_heap(0, :slot_size) * 2)
GC.disable # GC causes a lot of variance
benchmark:
binary_concat_embedded: |
# Concat 20 times in a String with 23 capacity
# Excercise `str_embed_capa`
buffer = +""
buffer << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "0"
buffer << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "0"

binary_concat_7bit: |
buffer = String.new(capacity: 4096, encoding: Encoding::BINARY)
buffer << CHUNK << CHUNK << CHUNK << CHUNK << CHUNK << CHUNK << CHUNK << CHUNK
Expand Down
2 changes: 1 addition & 1 deletion bignum.c
Original file line number Diff line number Diff line change
Expand Up @@ -3002,7 +3002,7 @@ rb_cmpint(VALUE val, VALUE a, VALUE b)
static size_t
big_embed_capa(VALUE big)
{
size_t size = rb_gc_obj_slot_size(big) - offsetof(struct RBignum, as.ary);
size_t size = rb_obj_shape_slot_size(big) - offsetof(struct RBignum, as.ary);
RUBY_ASSERT(size % sizeof(BDIGIT) == 0);
size_t capa = size / sizeof(BDIGIT);
RUBY_ASSERT(capa <= BIGNUM_EMBED_LEN_MAX);
Expand Down
16 changes: 13 additions & 3 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,6 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
void
rb_gc_obj_changed_slot_size(VALUE obj, size_t slot_size)
{
RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT));

RBASIC_SET_FULL_SHAPE_ID(obj, rb_obj_shape_transition_slot_size(obj, slot_size));
}

Expand Down Expand Up @@ -5577,14 +5575,24 @@ ruby_xrealloc2(void *ptr, size_t n, size_t size)
#undef ruby_xfree_sized
#endif

/*
* This is a debugging flag for measuring the cost of `xfree`.
* It can be enabled at compile time using `-DRUBY_NO_FREE`.
* At run time, if the `RUBY_NO_FREE` environment variable is set to "1",
* then `xfree` will not free any memory.
*/
#ifdef RUBY_NO_FREE
static bool g_nofree = false;
#endif

void
ruby_xfree_sized(void *x, size_t size)
{
#ifdef RUBY_NO_FREE
if (g_nofree) {
return;
}
#endif

if (RUBY_DTRACE_GC_XFREE_ENABLED()) {
RUBY_DTRACE_GC_XFREE(x, size);
Expand Down Expand Up @@ -5853,11 +5861,13 @@ rb_gc_checking_shareable(void)
void
Init_GC(void)
{
#ifdef RUBY_NO_FREE
const char* nofree_str = getenv("RUBY_NO_FREE");
if (nofree_str && strcmp(nofree_str, "yes") == 0) {
if (nofree_str && strcmp(nofree_str, "1") == 0) {
fprintf(stderr, "WARNING: Enabling no-free mode! xfree() will never free anything!\n");
g_nofree = true;
}
#endif

#undef rb_intern
rb_gc_register_address(&id2ref_value);
Expand Down
2 changes: 1 addition & 1 deletion gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -7616,7 +7616,7 @@ gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, struct heap_page *src_pa
/* Move the object */
memcpy((void *)dest, (void *)src, MIN(src_slot_size, slot_size));

if (src_slot_size != slot_size && RB_TYPE_P(src, T_OBJECT)) {
if (src_slot_size != slot_size) {
rb_gc_obj_changed_slot_size(dest, slot_size - RVALUE_OVERHEAD);
}

Expand Down
2 changes: 2 additions & 0 deletions internal/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define RARRAY_SHARED_FLAG ELTS_SHARED
#define RARRAY_SHARED_ROOT_FLAG FL_USER12
#define RARRAY_PTR_IN_USE_FLAG FL_USER14
#define RARRAY_FAKEARY FL_USER19

/* array.c */
VALUE rb_ary_hash_values(long len, const VALUE *elements);
Expand All @@ -38,6 +39,7 @@ void rb_ary_make_embedded(VALUE ary);
bool rb_ary_embeddable_p(VALUE ary);
VALUE rb_ary_diff(VALUE ary1, VALUE ary2);
VALUE rb_ary_compact_bang(VALUE ary);
VALUE rb_ary_modify_expand(VALUE ary, long expand);
RUBY_EXTERN VALUE rb_cArray_empty_frozen;

static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
Expand Down
1 change: 1 addition & 0 deletions internal/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define STR_CHILLED (FL_USER2 | FL_USER3)
#define STR_CHILLED_LITERAL FL_USER2
#define STR_CHILLED_SYMBOL_TO_S FL_USER3
#define STR_FAKESTR FL_USER19

enum ruby_rstring_private_flags {
RSTRING_CHILLED = STR_CHILLED,
Expand Down
12 changes: 8 additions & 4 deletions pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,9 @@ hex2num(char c)

#define PACK_LENGTH_ADJUST_SIZE(sz) do { \
tmp_len = 0; \
if (mode == UNPACK_ARRAY) { \
rb_ary_modify_expand(ary, len); \
} \
if (len > (long)((send-s)/(sz))) { \
if (!star) { \
tmp_len = len-(send-s)/(sz); \
Expand All @@ -972,7 +975,7 @@ hex2num(char c)

#define PACK_ITEM_ADJUST() do { \
if (tmp_len > 0 && mode == UNPACK_ARRAY) \
rb_ary_store(ary, RARRAY_LEN(ary)+tmp_len-1, Qnil); \
rb_ary_resize(ary, RARRAY_LEN(ary)+tmp_len); \
} while (0)

/* Workaround for Oracle Developer Studio (Oracle Solaris Studio)
Expand All @@ -992,7 +995,7 @@ enum unpack_mode {
};

static VALUE
pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
pack_unpack_internal(VALUE str, VALUE fmt, VALUE ofs, enum unpack_mode mode)
{
#define hexdigits ruby_hexdigits
const char *s, *send;
Expand All @@ -1016,6 +1019,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)

StringValue(str);
StringValue(fmt);
long offset = NUM2LONG(ofs);
rb_must_asciicompat(fmt);

len = RSTRING_LEN(str);
Expand Down Expand Up @@ -1672,13 +1676,13 @@ static VALUE
pack_unpack(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
{
enum unpack_mode mode = rb_block_given_p() ? UNPACK_BLOCK : UNPACK_ARRAY;
return pack_unpack_internal(str, fmt, mode, RB_NUM2LONG(offset));
return pack_unpack_internal(str, fmt, offset, mode);
}

static VALUE
pack_unpack1(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
{
return pack_unpack_internal(str, fmt, UNPACK_1, RB_NUM2LONG(offset));
return pack_unpack_internal(str, fmt, offset, UNPACK_1);
}

int
Expand Down
45 changes: 42 additions & 3 deletions pathname_builtin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,22 @@ def directory?() FileTest.directory?(@path) end
# See <tt>FileTest.file?</tt>.
def file?() FileTest.file?(@path) end

# See <tt>FileTest.pipe?</tt>.
# :markup: markdown
#
# call-seq:
# pipe? -> true or false
#
# Returns whether the path in +self+ points to a pipe:
#
# ```ruby
# path = '/tmp/foo'
# File.mkfifo(path)
# pn = Pathname(path) # => #<Pathname:/tmp/foo>
# pn.pipe? # => true
# Pathname('.').pipe? # => false
# pn.delete # Clean up.
# ```
#
def pipe?() FileTest.pipe?(@path) end

# See <tt>FileTest.socket?</tt>.
Expand Down Expand Up @@ -1917,13 +1932,37 @@ def socket?() FileTest.socket?(@path) end
#
def owned?() FileTest.owned?(@path) end

# See <tt>FileTest.readable?</tt>.
# :markup: markdown
#
# call-seq:
# readable? -> true or false
#
# Returns whether the path in `self` points to an entry
# that is readable by the owner and group of the current process:
#
# ```ruby
# pn = Pathname('/tmp/secret.txt')
# pn.write('foo')
# pn.readable? # => true
# pn.chmod(0o000)
# pn.readable? # => false
# pn.delete # Clean up.
# Pathname('nosuch').readable? # => false
# ```
#
def readable?() FileTest.readable?(@path) end

# See <tt>FileTest.world_readable?</tt>.
def world_readable?() File.world_readable?(@path) end

# See <tt>FileTest.readable_real?</tt>.
# :markup: markdown
#
# call-seq:
#
# readable_real? -> true or false
#
# Like #readable?, but checks against the real user and group ids
# instead of the effective ids.
def readable_real?() FileTest.readable_real?(@path) end

# See <tt>FileTest.setuid?</tt>.
Expand Down
4 changes: 2 additions & 2 deletions ractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -2032,7 +2032,7 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
}
else {
VALUE type = RB_BUILTIN_TYPE(obj);
size_t slot_size = rb_gc_obj_slot_size(obj);
size_t slot_size = rb_obj_shape_slot_size(obj);
VALUE moved = rb_newobj(GET_EC(), 0, type, RBASIC_SHAPE_ID(obj), wb_protected_types[type], slot_size);
MEMZERO(((struct RBasic *)moved) + 1, char, slot_size - sizeof(struct RBasic));
data->replacement = (VALUE)moved;
Expand All @@ -2050,7 +2050,7 @@ move_leave(VALUE obj, struct obj_traverse_replace_data *data)
memcpy(
(char *)data->replacement + sizeof(VALUE),
(char *)obj + sizeof(VALUE),
rb_gc_obj_slot_size(obj) - sizeof(VALUE)
rb_obj_shape_slot_size(obj) - sizeof(VALUE)
);

// We've copied obj's references to the replacement
Expand Down
Loading