| Age | Commit message (Collapse) | Author |
|
Replace `rb_yarv_class_of` call with:
- a constant check for special constants (nil, fixnums, symbols, etc)
- a check for false
- direct memory read at offset 8 for regular heap objects for the class check
|
|
We can rewrite SendWithoutBlock to GetIvar.
|
|
* ZJIT: Implement SingleRactorMode invalidation
* ZJIT: Add macro for compiling jumps
* ZJIT: Fix typo in comment
* YJIT: Fix typo in comment
* ZJIT: Avoid using unexported types in zjit.h
`enum ruby_vminsn_type` is declared in `insns.inc` and is not exported.
Using it in `zjit.h` would cause build errors when the file including it
doesn't include `insns.inc`.
|
|
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
|
|
Add `keyword_module` amd `keyword_end` locations to struct `RNode_MODULE`.
memo:
```
>ruby --dump=parsetree -e 'module A end'
@ ProgramNode (location: (1,0)-(1,12))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,12))
+-- body: (length: 1)
+-- @ ModuleNode (location: (1,0)-(1,12))
+-- locals: []
+-- module_keyword_loc: (1,0)-(1,6) = "module"
+-- constant_path:
| @ ConstantReadNode (location: (1,7)-(1,8))
| +-- name: :A
+-- body: nil
+-- end_keyword_loc: (1,9)-(1,12) = "end"
+-- name: :A
```
|
|
It's not rare for structs to have additional ivars, hence are one
of the most common, if not the most common type in the `gen_fields_tbl`.
This can cause Ractor contention, but even in single ractor mode
means having to do a hash lookup to access the ivars, and increase
GC work.
Instead, unless the struct is perfectly right sized, we can store
a reference to the associated IMEMO/fields object right after the
last struct member.
```
compare-ruby: ruby 3.5.0dev (2025-08-06T12:50:36Z struct-ivar-fields-2 9a30d141a1) +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-06T12:57:59Z struct-ivar-fields-2 2ff3ec237f) +PRISM [arm64-darwin24]
warming up.....
| |compare-ruby|built-ruby|
|:---------------------|-----------:|---------:|
|member_reader | 590.317k| 579.246k|
| | 1.02x| -|
|member_writer | 543.963k| 527.104k|
| | 1.03x| -|
|member_reader_method | 213.540k| 213.004k|
| | 1.00x| -|
|member_writer_method | 192.657k| 191.491k|
| | 1.01x| -|
|ivar_reader | 403.993k| 569.915k|
| | -| 1.41x|
```
Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
|
|
|
|
Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
|
|
If `get_next_shape_internal` fail to return a shape, we must
transitiont to a complex shape. `shape_transition_object_id`
mistakenly didn't.
Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
|
|
On the ruby side, this fixes a crash for methods with 39 or more
parameters. We used to miscomp those entry points due to Insn::Lea
picking ADDS which cannot reference SP:
# set method params: 40
mov x0, #0xfee8
movk x0, #0xffff, lsl #16
movk x0, #0xffff, lsl #32
movk x0, #0xffff, lsl #48
adds x0, xzr, x0
Have Lea work for all i32 displacements and avoid involving the split
pass. Previously, direct use of Insn::Lea directly from the user (as
opposed to generated by the split pass for some memory operations)
wasn't split, so being able to handle the whole range in arm64_emit()
was implicitly required. Also, not going through split reduces register
pressure.
|
|
|
|
Implement rb_big_aref2.
Taking a small slice from large bignum was slow in rb_int_aref2.
|
|
ref: https://bugs.ruby-lang.org/issues/21513
Before this patch, trying to convert endless range (e.g. `(1..)`) to set
(using `to_set`) would hang
|
|
|
|
Previously, ZJIT miscompiled the following because of native SP
interference.
def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8]
a(0,0,0,0,0,0,0, :ok)
Commented problematic disassembly:
; call rb_ary_new_capa
mov x0, #1
mov x16, #0x1278
movk x16, #0x4bc, lsl #16
movk x16, #1, lsl #32
blr x16
; call rb_ary_push
mov x1, x0
str x1, [sp, #-0x10]! ; c_push() from alloc_regs()
mov x0, x1 ; arg0, the array
ldur x1, [sp] ; meant to be arg1=n8, but sp just moved!
mov x16, #0x3968
movk x16, #0x4bc, lsl #16
movk x16, #1, lsl #32
blr x16
Since the frame pointer stays constant in the body of the function,
static offsets based on it don't run the risk of being invalidated by SP
movements.
Pass the registers to preserve through Insn::FrameSetup. This allows ARM
to use STP and waste no gaps between EC, SP, and CFP.
x86 now preserves and restores RBP since we use it as the frame pointer.
Since all arches now have a frame pointer, remove offset based SP
movement in the epilogue and restore registers using the frame pointer.
|
|
More comprehensive pack/unpack tests are in test_pack.rb.
|
|
|
|
|
|
Add keyword_defined locations to struct RNode_DEFINED
|
|
Previously, for 8+ params we wound up clobbering the self param when
putting the last param in memory in the JIT entry point:
# ZJIT entry point: a@../test.rb:5
<snip>
ldur x0, [x19, #0x18]
# set method params: 8
ldur x1, [x21, #-0x58]
ldur x2, [x21, #-0x50]
ldur x3, [x21, #-0x48]
ldur x4, [x21, #-0x40]
ldur x5, [x21, #-0x38]
ldur x11, [x21, #-0x30]
ldur x12, [x21, #-0x28]
ldur x0, [x21, #-0x20]
stur x0, [sp, #-0x20]
bl #0x11e17018c
Doing the memcpys for parameters in memory first avoids this clobbering.
# set method params: 8
ldur x0, [x21, #-0x20]
stur x0, [sp, #-0x20]
ldur x12, [x21, #-0x28]
ldur x11, [x21, #-0x30]
ldur x5, [x21, #-0x38]
ldur x4, [x21, #-0x40]
ldur x3, [x21, #-0x48]
ldur x2, [x21, #-0x50]
ldur x1, [x21, #-0x58]
ldur x0, [x19, #0x18]
|
|
Or else the following returns garbage since it loads after
moving SP. Prior bad disassembly:
def a(n1,n2,n3,n4,n5,n6,n7,n8) = n8
a(1,1,1,1,1,1,1,0)
# Block: bb0(v0, v1, v2, v3, v4, v5, v6, v7, v8)
stp x29, x30, [sp, #-0x10]!
mov x29, sp
# bump C stack pointer
sub sp, sp, #0x10
# Insn: v10 Return v8
# pop stack frame
adds x19, x19, #0x38
stur x19, [x20, #0x10]
# restore C stack pointer
add sp, sp, #0x10
mov sp, x29
ldp x29, x30, [sp], #0x10
ldur x0, [sp]
ret
|
|
ZJIT: Support invalidating method redefinition
This commit adds support for the MethodRedefined invariant to be invalidated
when a method is redefined.
Changes:
- Added CME pointer to the MethodRedefined invariant in HIR
- Updated all places where MethodRedefined invariants are created to
include the CME pointer
- Added handling for MethodRedefined invariants in gen_patch_point to
call track_cme_assumption, which registers the patch point for
invalidation when rb_zjit_cme_invalidate is called
This ensures that when a method is redefined, all JIT code that
depends on that method will be properly invalidated.
|
|
is…"
This reverts commit 265059603c3aa6a13f90096c71b32046a17938f3.
|
|
[Bug #21326]
|
|
It was failing to set the leads, like numblocks do, causing the result to be wrapped in an array
|
|
|
|
Fix https://github.com/Shopify/ruby/issues/627
|
|
See: 58bc97628c1
getpwnam(3) says the same thing. I got ENOENT in my Linux environment.
1) Failure:
TestProcess#test_uid_from_name [/home/k0kubun/src/github.com/ruby/ruby/test/ruby/test_process.rb:1685]:
Exception(ArgumentError) with message matches to /\u{4e0d 5b58 5728}/.
[ArgumentError] exception expected, not #<Errno::ENOENT: No such file or directory - getpwnam_r>.
|
|
|
|
|
|
|
|
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
Co-authored-by: Stan Lo <stan.lo@shopify.com>
|
|
|
|
Co-authored-by: Max Bernstein <max@bernsteinbear.com>
|
|
* ZJIT: Avoid optimizing locals on eval
* Maintain the local state for eval
|
|
... to conform to UTS 18 as mentioned in https://bugs.ruby-lang.org/issues/19417#note-3
https://unicode.org/reports/tr18/#word states word should match join_control chars.
It currently does not:
```ruby
[*0x0..0xD799, *0xE000..0x10FFFF].map { |n| n.chr 'utf-8' } => all_chars
all_chars.grep(/\p{join_control}/) => jc
jc.count # => 2
jc.grep(/\p{word}/).count # => 0
```
|
|
|
|
|
|
|
|
|
|
0a0eb2807ed7 has already replaced most of that code.
|
|
ZJIT already can generate guard type instructions for *Exact types.
For example:
```
def test(strings)
strings.map do |string|
string.bytesize
end
end
test(["foo", "bar"])
```
```
HIR:
fn block in test:
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint MethodRedefined(String@0x1014be890, bytesize@0x19f1)
v7:StringExact = GuardType v1, StringExact
v8:Fixnum = CCall bytesize@0x16fa4cc18, v7
Return v8
```
But zjit only supported guarding fixnums so this script would panic.
This commit adds support for guarding *Exact types.
|
|
None of the datastructures involved in the require process are
safe to call on a secondary ractor, however when autoloading
encodings, we do so from the current ractor.
So all sorts of corruption can happen when using an autoloaded
encoding for the first time from a secondary ractor.
|
|
This reverts commit cf4d37fbc079116453e69cf08ea8007d0e1c73e6.
|
|
This reverts commit dda5a04f2b4835582dba09ba33797258a61efafe.
|
|
Also, make sure autoloading of encodings is safe across ractors.
|
|
This fixes segfaults and errors of the type "Encoding not found" when
using encoding-related methods and internal encoding c functions across
ractors.
Example of a possible segfault in release mode or assertion error in debug mode:
```ruby
rs = []
100.times do
rs << Ractor.new do
"abc".force_encoding(Encoding.list.shuffle.first)
end
end
while rs.any?
r, obj = Ractor.select(*rs)
rs.delete(r)
end
```
|
|
|
|
|
|
Co-authored-by: Max Bernstein <max@bernsteinbear.com>
|