Skip to content

[pull] master from ruby:master - #1436

Merged
pull[bot] merged 31 commits into
turkdevops:masterfrom
ruby:master
Sep 23, 2026
Merged

pull[bot] merged 31 commits into
turkdevops:masterfrom
ruby:master

Conversation

@pull

@pull pull Bot commented Sep 23, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

rafaelfranca and others added 30 commits September 22, 2026 09:36
When running benchmarks, sometimes there is a overhead in the statistics collection, so it can be useful to disable `zjit-stats`.

In my case I was investigating Shopify#1051 and was confused why I was not seeing any new instruction being generated in the LIR but there was still performance difference when running zjit-diff. The cause for the performance difference in that PR was new instructions to increment stats counters.

So this PR allow running the tool without stats enabled.

I'm even wondering if the default should not be with it disabled.
We should not ever hit this from Ruby code; user code cannot modify
ivars that do not start with @.

This makes `num_members` leaf and therefore Struct class allocation also
leaf.
Now fibers can be collected by multiple ractors at once when those Ractors
are running local GCs. Fibers are created in the Ractor that owns them, so
if multiple Ractors have unmarked fibers during local GC sweeping, we can
now collect them concurrently instead of deferring their collection to a
postponed job. Each fiber pool is protected by its own native mutex.

In the future, maybe fiber pools will be ractor-local, but we have to
experiment with it first and see if it's enough of a performance win to
justify the change. We also want to minimize resource acquisition for each
Ractor as they're supposed to be lighweight.
Preserve `ELOOP` instead of hiding symbolic-link resolution errors
with the file-enumeration fallback, so existence checks return false.
Cover equal and different file contents in `test_cmp` and verify
that `compare_file` and `identical?` remain aliases.

Fix ruby/fileutils#180
Fix ruby/fileutils#184

ruby/fileutils@01ac124ce4
Cover directory changes, block behavior, and verbose output through
`cd`, and verify that `chdir` remains an alias.

Fix ruby/fileutils#182

ruby/fileutils@8476509760
Avoid duplicating working-directory coverage already in `test_pwd`.

Fix ruby/fileutils#183

ruby/fileutils@d937a3d5ba
Verify that `ln` creates hard links and that `link` remains an alias.

Fix ruby/fileutils#185

ruby/fileutils@46db9d557b
Check `mkdir_p` return values and verify the `makedirs` and `mkpath`
aliases without duplicating directory creation tests.

Fix ruby/fileutils#186

ruby/fileutils@72ff748e26
Check the result and effects of `mv` and verify the `move` alias.

Fix ruby/fileutils#187

ruby/fileutils@3bed6e74a1
Cover removal of existing and missing trees through `rm_rf` and
verify the `rmtree` alias.

Fix ruby/fileutils#188

ruby/fileutils@07cc858f16
Cover removal of existing and missing files through `rm_f` and
verify the `safe_unlink` alias.

Fix ruby/fileutils#189

ruby/fileutils@902bcce36b
Cover single, multiple, and dangling links through `ln_s`, keeping
valid-link tests available where dangling links are unsupported.

Fix ruby/fileutils#190

ruby/fileutils@189aefb679
Windows reports self-referential links as existing, so use a missing
target to test a dangling link rather than a symbolic-link loop.

ruby/fileutils@803fe3be07
I saw that YJIT has a fast-path for this so I figured we should too.
`rb_obj_dup` skips immediates:

```c
VALUE
rb_obj_dup(VALUE obj)
{
    VALUE dup;

    if (special_object_p(obj)) {
        return obj;
    }

    // ...
}

static inline int
special_object_p(VALUE obj)
{
    if (SPECIAL_CONST_P(obj)) return TRUE;
    switch (BUILTIN_TYPE(obj)) {
      case T_BIGNUM:
      case T_FLOAT:
      case T_SYMBOL:
      case T_RATIONAL:
      case T_COMPLEX:
        /* not a comprehensive list */
        return TRUE;
      default:
        return FALSE;
    }
}
```
(ruby/prism#4232)

Followup to ruby/prism@ba16ae2

I can't run rake `cargo:test`:
```
$ cargo build
   Compiling ruby-prism-sys v1.9.0 (ruby-prism/rust/ruby-prism-sys)
   Compiling ruby-prism v1.9.0 (ruby-prism/rust/ruby-prism)
warning: ruby-prism-sys@1.9.0: In file included from ruby-prism/rust/ruby-prism-sys/vendor/prism-1.9.0/include/prism/ast.h:22,
warning: ruby-prism-sys@1.9.0:                  from ruby-prism/rust/ruby-prism-sys/vendor/prism-1.9.0/include/prism/internal/static_literals.h:6,
warning: ruby-prism-sys@1.9.0:                  from ruby-prism/rust/ruby-prism-sys/vendor/prism-1.9.0/src/static_literals.c:1:
warning: ruby-prism-sys@1.9.0: ruby-prism/rust/ruby-prism-sys/vendor/prism-1.9.0/include/prism/arena.h:28:1: warning: 'nodiscard' attribute ignored [-Wattributes]
warning: ruby-prism-sys@1.9.0:    28 | PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_arena_t * pm_arena_new(void);
warning: ruby-prism-sys@1.9.0:       | ^~~~~~~~~~~~~~~~~~~~~~~
warning: ruby-prism-sys@1.9.0: ruby-prism/rust/ruby-prism-sys/vendor/prism-1.9.0/include/prism/arena.h:28:41: error: expected identifier or '(' before 'pm_arena_t'
warning: ruby-prism-sys@1.9.0:    28 | PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_arena_t * pm_arena_new(void);
warning: ruby-prism-sys@1.9.0:       |                                         ^~~~~~~~~~
error: failed to run custom build command for `ruby-prism-sys v1.9.0 (ruby-prism/rust/ruby-prism-sys)`
```

It expands to `__attribute__((__visibility__("default"))) extern [[nodiscard]] pm_arena_t * pm_arena_new(void);`, which is not valid in that order.

ruby/prism@3942928d8f
We can use `ObjectAllocClass` for Structs because they are basically
a `__members__` ivar lookup for sizing plus the default allocator.

Requires #18888 to make sure the constructor does not raise.
We previously only had this in `gen_insn` which left terminators
un-commented.
It's an abrupt end to a block, but it definitely ends the block. No need
to put a return instruction after it.
We use `HasType`+`CondBranch` a lot—it is how we do polymorphic dispatch in HIR—so it's pretty hot. Without smarter instruction fusion/instruction selection, this generates a lot of code. Kokubun identified this in Shopify#1039

Right now, `HasType` materializes a boolean just for `CondBranch` to go check it again. Since we only use `HasType` for `CondBranch` today, make a new fused instruction.

This reduces interstitial values and also intermediate double branching. See for example this polymorphic method dispatch and its generated HIR and asm.

Source:

```ruby
class C
  def foo = 3
end

class D
  def foo = 4
end

def test(o) = o.foo
```

Before HIR:

```
Optimized HIR:
fn test@../tmp/poly.rb:9:
bb1():
  EntryPoint interpreter
  v1:BasicObject = LoadSelf
  v2:CPtr = LoadSP
  v3:BasicObject = LoadField v2, :o@-0x20
  Jump bb3(v1, v3)
bb2():
  EntryPoint JIT(0)
  v6:BasicObject = LoadArg :self@0
  v7:BasicObject = LoadArg :o@1
  Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
  v16:CBool = HasType v10, ObjectSubclass[class_exact:C]
  CondBranch v16, bb5(), bb6()
bb5():
  PatchPoint NoSingletonClass(C@0x124574200)
  PatchPoint MethodRedefined(C@0x124574200, foo@0xec31, cme:0x12455e298)
  v37:Fixnum[3] = Const Value(3)
  Jump bb4(v37)
bb6():
  v22:CBool = HasType v10, ObjectSubclass[class_exact:D]
  CondBranch v22, bb7(), bb8()
bb7():
  PatchPoint NoSingletonClass(D@0x124574340)
  PatchPoint MethodRedefined(D@0x124574340, foo@0xec31, cme:0x12455e2e8)
  v40:Fixnum[4] = Const Value(4)
  Jump bb4(v40)
bb8():
  v28:BasicObject = Send v10, :foo # SendFallbackReason: Send: polymorphic call site
  Jump bb4(v28)
bb4(v15:BasicObject):
  CheckInterrupts
  Return v15
```

Before asm:

```
  # Insn: v16 HasType v10, ObjectSubclass[class_exact:C]
  0x124f4012c: tst x0, #7
  0x124f40130: b.ne #0x124f4016c
  0x124f40134: cmp x0, #0
  0x124f40138: b.eq #0x124f40164
  0x124f4013c: ldur x1, [x0, #8]
  0x124f40140: ldr x2, #0x124f40148
  0x124f40144: b #0x124f40150
  0x124f40148: sel z0.d, p0, z26.d, z16.d
  0x124f4014c: udf #1
  0x124f40150: cmp x1, x2
  0x124f40154: mov x1, #1
  0x124f40158: mov x2, #0
  0x124f4015c: csel x1, x1, x2, eq
  0x124f40160: b #0x124f40170
  0x124f40164: mov x1, #0
  0x124f40168: b #0x124f40170
  0x124f4016c: mov x1, #0
  # Insn: v17 CondBranch v16, bb5(), bb6()
  0x124f40170: tst x1, x1
  0x124f40174: b.ne #0x124f40228
```

After HIR:

```
Optimized HIR:
fn test@../tmp/poly.rb:9:
bb1():
  EntryPoint interpreter
  v1:BasicObject = LoadSelf
  v2:CPtr = LoadSP
  v3:BasicObject = LoadField v2, :o@-0x20
  Jump bb3(v1, v3)
bb2():
  EntryPoint JIT(0)
  v6:BasicObject = LoadArg :self@0
  v7:BasicObject = LoadArg :o@1
  Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
  CondBranchHasType v10, ObjectSubclass[class_exact:C], bb5(), bb6()
bb5():
  PatchPoint NoSingletonClass(C@0x11fd14140)
  PatchPoint MethodRedefined(C@0x11fd14140, foo@0xec31, cme:0x11fcfe2f0)
  v35:Fixnum[3] = Const Value(3)
  Jump bb4(v35)
bb6():
  CondBranchHasType v10, ObjectSubclass[class_exact:D], bb7(), bb8()
bb7():
  PatchPoint NoSingletonClass(D@0x11fd14280)
  PatchPoint MethodRedefined(D@0x11fd14280, foo@0xec31, cme:0x11fcfe340)
  v38:Fixnum[4] = Const Value(4)
  Jump bb4(v38)
bb8():
  v26:BasicObject = Send v10, :foo # SendFallbackReason: Send: polymorphic call site
  Jump bb4(v26)
bb4(v15:BasicObject):
  CheckInterrupts
  Return v15
```

After asm:

```
  # Insn: v16 CondBranchHasType v10, ObjectSubclass[class_exact:C], bb5(), bb6()
  0x127e0412c: tst x0, #7
  0x127e04130: b.ne #0x127e04168
  0x127e04134: cmp x0, #0
  0x127e04138: b.eq #0x127e04168
  0x127e0413c: ldur x1, [x0, #8]
  0x127e04140: ldr x2, #0x127e04148
  0x127e04144: b #0x127e04150
  0x127e04148: sel z0.d, p0, z25.d, z28.d
  0x127e0414c: udf #1
  0x127e04150: cmp x1, x2
  0x127e04154: b.eq #0x127e0415c
  0x127e04158: b #0x127e04168
```
The precision in Time.new calls to_int which can modify the string passed
into Time.new. This can cause an use-after-free. For example, the following
script crashes:

    str = "2000-01-01 00:00:00" + "0" * 1_000_000
    obj = Object.new
    obj.define_singleton_method(:to_int) { str.clear; 9 }
    Time.new(str, precision: obj)
@pull pull Bot locked and limited conversation to collaborators Sep 23, 2026
@pull pull Bot added the ⤵️ pull label Sep 23, 2026
@pull
pull Bot merged commit bb382ae into turkdevops:master Sep 23, 2026
1 of 3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants