ZJIT uses the interpreter to take type profiles of what objects pass through
the code. It stores a compressed record of the history per opcode for the
opcodes we select.
Before this change, we re-used the HIR Type data-structure, a shallow type
lattice, to store historical type information. This was quick for bringup but
is quite lossy as profiles go: we get one bit per built-in type seen, and if we
see a non-built-in type in addition, we end up with BasicObject. Not very
helpful. Additionally, it does not give us any notion of cardinality: how many
of each type did we see?
This change brings with it a much more interesting slice of type history: a
histogram. A Distribution holds a record of the top-N (where N is fixed at Ruby
compile-time) `(Class, ShapeId)` pairs and their counts. It also holds an
*other* count in case we see more than N pairs.
Using this distribution, we can make more informed decisions about when we
should use type information. We can determine if we are strictly monomorphic,
very nearly monomorphic, or something else. Maybe the call-site is polymorphic,
so we should have a polymorphic inline cache. Exciting stuff.
I also plumb this new distribution into the HIR part of the compilation
pipeline.
Currently Prism returns `42` for code like this:
```ruby
42.tap { it = it; p it } # => 42
```
But parse.y returns `nil`:
```ruby
42.tap { it = it; p it } # => nil
```
In parse.y, it on the right-hand side is parsed as a local variable.
In Prism, it was parsed as the implicit block parameter it, which caused this inconsistent behavior.
This change makes the right-hand side it to be parsed as a local variable, aligning with parse.y's behavior.
Bug ticket: https://bugs.ruby-lang.org/issues/21139cf3bbf9d2c
Assuming not all objects are moved during compaction, it
is preferable to avoid rewriting references that haven't moved
as to avoid invalidating potentially shared memory pages.
When compiling with -fsanitize=address on macOS, the deprecation of
sprintf is effective and prevents compiling yjit.c.
More details: https://openradar.appspot.com/FB11761475.
The variable `prev_ext_config` is modified by `ext_config_push` between
`setjmp` and `longjmp` calls. Since `ext_config_push` and `ext_config_pop`
are small and likely to be inlined, `prev_ext_config` can be allocated on
a register and get clobbered. Fix by making it `volatile`.
This bug can be observed by adding a check for values greater than 1 in
`th2->ext_config.ractor_safe` after `ext_config_pop` and building with Clang.
The purpose of this commit is to fix Bug #21188. We need to detect when
stdin has run in to an EOF case. Unfortunately we can't _call_ the eof
function on IO because it will block.
Here is a short script to demonstrate the issue:
```ruby
x = STDIN.gets
puts x
puts x.eof?
```
If you run the script, then type some characters (but _NOT_ a newline),
then hit Ctrl-D twice, it will print the input string. Unfortunately,
calling `eof?` will try to read from STDIN again causing us to need a
3rd Ctrl-D to exit the program.
Before introducing the EOF callback to Prism, the input loop looked
kind of like this:
```ruby
loop do
str = STDIN.gets
process(str)
if str.nil?
p :DONE
end
end
```
Which required 3 Ctrl-D to exit. If we naively changed it to something
like this:
```ruby
loop do
str = STDIN.gets
process(str)
if STDIN.eof?
p :DONE
end
end
```
It would still require 3 Ctrl-D because `eof?` would block. In this
patch, we're wrapping the IO object, checking the buffer for a newline
and length, and then using that to simulate a non-blocking eof? method.
This commit wraps STDIN and emulates a non-blocking `eof` function.
[Bug #21188]
All the `json/add` related methods for string were
always defined unconditionally from the generators.
It's preferable to only define them if `json/add` is actually used.
Platform specific versions of ffi-1.17.2 are not compatible with Ruby
3.5, so Bundler fails to resolve in Ruby 3.5 using recorded VCR
responses.
Use the generic version of ffi-1.17.2, which should work for all rubies,
consistently to fix that.
a192f7e35d
This reverts a change of commit b3598cf2a3 .
On Windows on ARM64 with LLVM the "NM" tool is called with a parameter like so:
```
RbConfig::CONFIG["NM"] # => "llvm-nm --no-llvm-bc"
```
Therefore the command must be called with a shell string.
Previously, ARM64 panicked due to compiled_side_exits() when the memory
displacement got large enough to exceed the 9 bits limit. Usually, we split
these kind of memory operands, but compiled_side_exits() runs after
split.
Using scratch registers, implement `Insn::Store` on ARM such that it can
handle large displacements without split(). Do this for x86 as well, and
remove arch specific code from compiled_side_exits(). We can now run
`TestKeywordArguments`.
Since `Insn::Store` doesn't need splitting now, users enjoy lower
register pressure.
Downside is, using `Assembler::SCRATCH_REG` as a base register is now
sometimes an error, depending on whether `Insn::Store` also needs to
use the register. It seems a fair trade off since `SCRATCH_REG` is
not often used, and we don't put it as a base register anywhere at the
moment.