Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1fcccae
ZJIT: Inline GC fastpath in ZJIT for object allocation
eightbitraptor Jul 9, 2026
9660b88
ZJIT: Make IsBlockGiven just a comparison (#17756)
tekknolagi Jul 9, 2026
d939495
Fix unused variable warning in thread_sched_set_running on non-DTrace…
Copilot Jul 9, 2026
924f3fb
ZJIT: Fix CFP publication for direct calls (#17760)
k0kubun Jul 9, 2026
a8a6890
Remove obj_free_object_id
jhawthorn Jul 9, 2026
2e5922e
ZJIT: GC fastpath alloc for hashes with symbol keys
luke-gruber Jul 9, 2026
e2403ac
win32/rm.bat: fix `-r` failing to remove directories
hsbt Jul 3, 2026
2bd6bf4
win32/rm.bat: fix exist check for paths expanded from wildcards
hsbt Jul 3, 2026
3a372f0
[DOC] Restore Windows backslash note for filename globbing
hsbt Jul 3, 2026
fdad6b5
[DOC] Restore glob documentation lost in consolidation
hsbt Jul 3, 2026
07490d1
tool/redmine-backporter.rb: Authenticate GET requests
k0kubun Jul 9, 2026
014f7f1
YJIT: Fix `warn(unused_assignments)` in test_gen_opt_reverse
XrXr Jul 9, 2026
0ef01bc
[ruby/rubygems] Skip the make jobserver when using BSD make
flavorjones Jul 6, 2026
b226c59
[DOC] Fix man page markup for groff 1.24
tsimonq2 Jul 10, 2026
c62bfaf
Bump the github-actions group across 1 directory with 5 updates
dependabot[bot] Jul 10, 2026
59d4afa
[ruby/net-http] Add support for HTTP `QUERY` method
seanpdoyle Jul 6, 2026
b9be3d6
[DOC] Minor updates to Set documentation
BurdetteLamar Jul 10, 2026
6445029
sprintf.c: don't raise "too many arguments" errors when $DEBUG is set
byroot Jun 30, 2026
52f5888
Make the object-traversal mark redirect per-Ractor
ko1 Jul 10, 2026
a1392b9
Make mark_object_ary per-Ractor
ko1 Jul 10, 2026
ef67c37
Respect `handle_interrupt` for default `SIGINT`. (#17533)
samuel-williams-shopify Jul 10, 2026
5f96131
[DOC] Doc for Pathname#readlines
BurdetteLamar Jul 10, 2026
b416f90
Remove `String#to_f` and `Kernel#Float` out of range warning
byroot Jul 10, 2026
9eb455c
[DOC] Doc for Pathname.rename
BurdetteLamar Jul 9, 2026
79da507
Prevent overflow of length bits for embedded arrays
peterzhu2118 Jul 9, 2026
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
6 changes: 3 additions & 3 deletions .github/workflows/check_sast.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ jobs:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
with:
languages: ${{ matrix.language }}
build-mode: none
config-file: .github/codeql/codeql-config.yml

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
with:
category: '/language:${{ matrix.language }}'
upload: False
Expand Down Expand Up @@ -127,7 +127,7 @@ jobs:
continue-on-error: true

- name: Upload SARIF
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
with:
sarif_file: sarif-results/${{ matrix.language }}.sarif
continue-on-error: true
2 changes: 1 addition & 1 deletion .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
2 changes: 1 addition & 1 deletion .github/workflows/scorecards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
with:
sarif_file: results.sarif
2 changes: 1 addition & 1 deletion .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}
- uses: taiki-e/install-action@50414676f9f5d50a65992c6dd2ed02641263226c # v2.82.10
- uses: taiki-e/install-action@c7eb1735f09259a5035e8e5d44b1406b1cddc0fb # v2.83.0
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ jobs:
ruby-version: '3.1'
bundler: none

- uses: taiki-e/install-action@50414676f9f5d50a65992c6dd2ed02641263226c # v2.82.10
- uses: taiki-e/install-action@c7eb1735f09259a5035e8e5d44b1406b1cddc0fb # v2.83.0
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
4 changes: 3 additions & 1 deletion array.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ ary_embed_size(long capa)
static bool
ary_embeddable_p(long capa)
{
return rb_gc_size_allocatable_p(ary_embed_size(capa));
const long embed_len_max = RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT;

return capa <= embed_len_max && rb_gc_size_allocatable_p(ary_embed_size(capa));
}

bool
Expand Down
2 changes: 2 additions & 0 deletions depend
Original file line number Diff line number Diff line change
Expand Up @@ -16094,6 +16094,7 @@ scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/set_table.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/struct.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/thread.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/variable.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.h
Expand Down Expand Up @@ -16897,6 +16898,7 @@ signal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
signal.$(OBJEXT): $(top_srcdir)/internal/signal.h
signal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
signal.$(OBJEXT): $(top_srcdir)/internal/string.h
signal.$(OBJEXT): $(top_srcdir)/internal/struct.h
signal.$(OBJEXT): $(top_srcdir)/internal/thread.h
signal.$(OBJEXT): $(top_srcdir)/internal/variable.h
signal.$(OBJEXT): $(top_srcdir)/internal/vm.h
Expand Down
15 changes: 13 additions & 2 deletions dir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,29 @@ def initialize(name, encoding: nil)
end

# call-seq:
# Dir[patterns, base: nil, sort: true] -> array
# Dir[*patterns, base: nil, sort: true] -> array
#
# Like Dir.glob, but does not accept keyword argument +flags+,
# and may take multiple patterns as arguments:
#
# Dir['*.rb', '*.h'].take(3) # => ["KNOWNBUGS.rb", "array.rb", "ast.rb"]
#
# Like Dir.glob, but does not accept keyword argument +flags+.
def self.[](*args, base: nil, sort: true)
Primitive.dir_s_aref(args, base, sort)
end

# call-seq:
# Dir.glob(patterns, flags: 0, base: '.', sort: true) -> array_of_entries
# Dir.glob(patterns, flags: 0, base: '.', sort: true) {|entry_name| ... } -> nil
#
# Returns an array of filesystem entries;
# see {Filename Globbing}[rdoc-ref:file/filename_globbing.md].
#
# With a block given, calls the block with each of the selected entry names
# and returns +nil+:
#
# Dir.glob('*.rb') {|entry_name| puts entry_name } # => nil
#
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true)
Primitive.attr! :use_block
Primitive.dir_s_glob(pattern, flags, base, sort)
Expand Down
50 changes: 49 additions & 1 deletion doc/file/filename_globbing.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ Inputs to the filename-globbing methods:

Their return values:

- Each of the methods `Dir[]` and Dir.glob returns an array of the selected string entries.
- \Method `Dir[]` returns an array of the selected string entries.
- \Method Dir.glob with no block returns an array of the selected string entries.
- \Method Dir.glob with a block calls the block with each selected string entry
and returns `nil`.
- \Method Pathname#glob with no block returns an array of Pathname objects
each based on a selected string entry.
- \Method Pathname#glob with a block calls the block with each pathname
Expand All @@ -44,8 +47,13 @@ Examples:
```ruby
Dir['*'].take(3)
# => ["BSDL", "CONTRIBUTING.md", "COPYING"]
Dir['*.rb', '*.h'].take(3)
# => ["KNOWNBUGS.rb", "array.rb", "ast.rb"]
Dir.glob('*').take(3)
# => ["BSDL", "CONTRIBUTING.md", "COPYING"]
Dir.glob(['*.rb', '*.h']).take(3)
# => ["KNOWNBUGS.rb", "array.rb", "ast.rb"]
Dir.glob('*.rb') {|entry_name| puts entry_name } # => nil
Pathname('.').glob('*').take(3)
# => [#<Pathname:BSDL>, #<Pathname:CONTRIBUTING.md>, #<Pathname:COPYING>]
a = []
Expand Down Expand Up @@ -299,6 +307,25 @@ Pathname('.').glob('test/ruby/**/*.rb').take(3)
# #<Pathname:test/ruby/box/a.1_1_0.rb>]
```

The double-asterisk pattern matches directories recursively
only when followed by the slash character `'/'`;
otherwise it is equivalent to pattern `'*'`:

```ruby
Dir.glob('**') == Dir.glob('*') # => true
```

A pattern ending with `'/'` matches directory names only;
each matched name ends with `'/'`:

```ruby
# Find the directories at the top level.
Dir.glob('*/').take(3) # => ["basictest/", "benchmark/", "bin/"]

# Find all directories everywhere.
Dir.glob('**/').take(3) # => ["basictest/", "benchmark/", "benchmark/gc/"]
```

The pattern may be escaped:

```ruby
Expand All @@ -325,6 +352,22 @@ Pathname('.').glob('\[k-m][h-j][a-c]') # => []
Pathname('.').glob('\**/*.rb') # => []
```

Note that the backslash escapes the following character on Windows as well,
and therefore cannot be used as a path separator in the pattern;
`Dir.glob('C:\Users\*')` matches nothing.
Write the pattern with forward slashes instead:

```ruby
Dir.glob('C:/Users/*')
```

A Windows path taken from an external source (such as an environment variable)
may be converted for use as a pattern:

```ruby
pattern = path.tr('\\', '/')
```

## Keyword Arguments

| Keyword | Value | Default | Meaning |
Expand Down Expand Up @@ -417,6 +460,11 @@ Pathname('.').glob('\*').size # => 0
Pathname('.').glob('\*', File::FNM_NOESCAPE).size # => 0
```

Note that on Windows this flag does not make the backslash usable
as a path separator in the pattern;
the backslash is then matched as an ordinary character,
which cannot occur in an entry name.

#### Constant File::FNM_SHORTNAME

By default, Windows shortname matching is disabled;
Expand Down
77 changes: 54 additions & 23 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,16 @@ VALUE class_allocate_complex_instance(VALUE klass, uint32_t capacity)
return obj;
}

static inline size_t
robject_embedded_size(uint32_t fields_count)
{
size_t size = rb_obj_embedded_size(fields_count);
if (!rb_gc_size_allocatable_p(size)) {
size = sizeof(struct RObject);
}
return size;
}

VALUE
rb_class_allocate_instance(VALUE klass)
{
Expand All @@ -1118,10 +1128,7 @@ rb_class_allocate_instance(VALUE klass)
obj = class_allocate_complex_instance(klass, index_tbl_num_entries);
}
else {
size_t size = rb_obj_embedded_size(index_tbl_num_entries);
if (!rb_gc_size_allocatable_p(size)) {
size = sizeof(struct RObject);
}
size_t size = robject_embedded_size(index_tbl_num_entries);

// There might be a NEWOBJ tracepoint callback, and it may set fields.
// So the shape must be passed to `NEWOBJ_OF`.
Expand All @@ -1145,6 +1152,25 @@ rb_class_allocate_instance(VALUE klass)
return obj;
}

#if USE_ZJIT
bool
rb_zjit_class_allocate_instance_fastpath(VALUE klass, size_t *size_out, shape_id_t *shape_id_out)
{
uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);

RUBY_ASSERT(rb_shape_max_capacity() > 0);
if (RB_UNLIKELY(index_tbl_num_entries > rb_shape_max_capacity())) {
return false;
}

size_t size = robject_embedded_size(index_tbl_num_entries);
*size_out = size;
*shape_id_out = rb_shape_transition_slot_size(rb_shape_transition_robject(0),
rb_gc_size_slot_size(size));
return true;
}
#endif

void
rb_gc_register_pinning_obj(VALUE obj)
{
Expand Down Expand Up @@ -2159,16 +2185,10 @@ object_id(VALUE obj)
return object_id0(obj);
}

static inline void
obj_free_object_id(VALUE obj)
{
}

void
rb_gc_obj_free_vm_weak_references(VALUE obj)
{
ASSUME(!RB_SPECIAL_CONST_P(obj));
obj_free_object_id(obj);

if (rb_obj_gen_fields_p(obj)) {
rb_free_generic_ivar(obj);
Expand Down Expand Up @@ -2636,11 +2656,22 @@ ruby_stack_check(void)

/* ==================== Marking ==================== */

/* The traversal mark redirect is per-Ractor, except on a modular GC where
* marking can run on worker threads with no current EC and it lives in the VM.
* GC_MARK_FUNC_DATA_SLOTP() points at the active slot; a non-modular build pays
* nothing extra over a plain GET_VM() (one GET_RACTOR(), no NULL check). */
#if USE_MODULAR_GC
# define GC_MARK_FUNC_DATA_SLOTP() (&GET_VM()->gc.mark_func_data)
#else
# define GC_MARK_FUNC_DATA_SLOTP() (&GET_RACTOR()->mark_func_data)
#endif

#define RB_GC_MARK_OR_TRAVERSE(func, obj_or_ptr, obj, check_obj) do { \
if (!RB_SPECIAL_CONST_P(obj)) { \
rb_vm_t *vm = GET_VM(); \
void *objspace = vm->gc.objspace; \
if (LIKELY(vm->gc.mark_func_data == NULL)) { \
struct gc_mark_func_data_struct **mfdp = GC_MARK_FUNC_DATA_SLOTP(); \
struct gc_mark_func_data_struct *mark_func_data = *mfdp; \
void *objspace = GET_VM()->gc.objspace; \
if (LIKELY(mark_func_data == NULL)) { \
GC_ASSERT(rb_gc_impl_during_gc_p(objspace)); \
(func)(objspace, (obj_or_ptr)); \
} \
Expand All @@ -2649,10 +2680,9 @@ ruby_stack_check(void)
!rb_gc_impl_garbage_object_p(objspace, obj) : \
true) { \
GC_ASSERT(!rb_gc_impl_during_gc_p(objspace)); \
struct gc_mark_func_data_struct *mark_func_data = vm->gc.mark_func_data; \
vm->gc.mark_func_data = NULL; \
*mfdp = NULL; \
mark_func_data->mark_func((obj), mark_func_data->data); \
vm->gc.mark_func_data = mark_func_data; \
*mfdp = mark_func_data; \
} \
} \
} while (0)
Expand Down Expand Up @@ -4519,16 +4549,16 @@ rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *
if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_objspace_reachable_objects_from() is not supported while during GC");

if (!RB_SPECIAL_CONST_P(obj)) {
rb_vm_t *vm = GET_VM();
struct gc_mark_func_data_struct *prev_mfd = vm->gc.mark_func_data;
struct gc_mark_func_data_struct **mfdp = GC_MARK_FUNC_DATA_SLOTP();
struct gc_mark_func_data_struct *prev_mfd = *mfdp;
struct gc_mark_func_data_struct mfd = {
.mark_func = func,
.data = data,
};

vm->gc.mark_func_data = &mfd;
*mfdp = &mfd;
rb_gc_mark_children(rb_gc_get_objspace(), obj);
vm->gc.mark_func_data = prev_mfd;
*mfdp = prev_mfd;
}
}
}
Expand Down Expand Up @@ -4558,16 +4588,17 @@ rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE,
.data = passing_data,
};

struct gc_mark_func_data_struct *prev_mfd = vm->gc.mark_func_data;
struct gc_mark_func_data_struct **mfdp = GC_MARK_FUNC_DATA_SLOTP();
struct gc_mark_func_data_struct *prev_mfd = *mfdp;
struct gc_mark_func_data_struct mfd = {
.mark_func = root_objects_from,
.data = &data,
};

vm->gc.mark_func_data = &mfd;
*mfdp = &mfd;
rb_gc_save_machine_context();
rb_gc_mark_roots(vm->gc.objspace, &data.category);
vm->gc.mark_func_data = prev_mfd;
*mfdp = prev_mfd;
}

/*
Expand Down
11 changes: 8 additions & 3 deletions io.c
Original file line number Diff line number Diff line change
Expand Up @@ -12141,7 +12141,7 @@ io_s_foreach(VALUE v)
*
* - {Open Options}[rdoc-ref:IO@Open+Options].
* - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
* - {Line Options}[rdoc-ref:IO@Line+IO].
* - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
*
* Returns an Enumerator if no block is given.
*
Expand Down Expand Up @@ -12217,7 +12217,7 @@ io_s_readlines(VALUE v)
*
* - {Open Options}[rdoc-ref:IO@Open+Options].
* - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
* - {Line Options}[rdoc-ref:IO@Line+IO].
* - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
*
*/

Expand Down Expand Up @@ -15253,7 +15253,12 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* === Line Input
*
* Class \IO supports line-oriented input for
* {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
* {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
*
* ==== Line Input Options
*
* Optional keyword argument +chomp+ (default: +false+)
* specifies whether line separators are to be excluded from the result of a read.
*
* ==== \File Line Input
*
Expand Down
3 changes: 3 additions & 0 deletions jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ enum jit_bindgen_constants {
// Field offset for the RHash struct
RUBY_OFFSET_RHASH_IFNONE = offsetof(struct RHash, ifnone),

// Max pairs an embedded ar_table hash holds before it converts to an st_table
RUBY_RHASH_AR_TABLE_MAX_SIZE = RHASH_AR_TABLE_MAX_SIZE,

// Field offsets for the RString struct
RUBY_OFFSET_RSTRING_LEN = offsetof(struct RString, len),

Expand Down
Loading