1350 Commits

Author SHA1 Message Date
Koichi Sasada
b1b73936c1 Primitive.mandatory_only? for fast path
Compare with the C methods, A built-in methods written in Ruby is
slower if only mandatory parameters are given because it needs to
check the argumens and fill default values for optional and keyword
parameters (C methods can check the number of parameters with `argc`,
so there are no overhead). Passing mandatory arguments are common
(optional arguments are exceptional, in many cases) so it is important
to provide the fast path for such common cases.

`Primitive.mandatory_only?` is a special builtin function used with
`if` expression like that:

```ruby
  def self.at(time, subsec = false, unit = :microsecond, in: nil)
    if Primitive.mandatory_only?
      Primitive.time_s_at1(time)
    else
      Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
    end
  end
```

and it makes two ISeq,

```
  def self.at(time, subsec = false, unit = :microsecond, in: nil)
    Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
  end

  def self.at(time)
    Primitive.time_s_at1(time)
  end
```

and (2) is pointed by (1). Note that `Primitive.mandatory_only?`
should be used only in a condition of an `if` statement and the
`if` statement should be equal to the methdo body (you can not
put any expression before and after the `if` statement).

A method entry with `mandatory_only?` (`Time.at` on the above case)
is marked as `iseq_overload`. When the method will be dispatch only
with mandatory arguments (`Time.at(0)` for example), make another
method entry with ISeq (2) as mandatory only method entry and it
will be cached in an inline method cache.

The idea is similar discussed in https://bugs.ruby-lang.org/issues/16254
but it only checks mandatory parameters or more, because many cases
only mandatory parameters are given. If we find other cases (optional
or keyword parameters are used frequently and it hurts performance),
we can extend the feature.
2021-11-15 15:58:56 +09:00
Nobuyoshi Nakada
9b751db99c Fix script_lines in loaded iseq as nil 2021-10-29 06:39:57 +09:00
Nobuyoshi Nakada
7459a32af3 suppress warnings for probable NULL dererefences 2021-10-24 19:24:50 +09:00
Koichi Sasada
c7550537f1 RubyVM.keep_script_lines
`RubyVM.keep_script_lines` enables to keep script lines
for each ISeq and AST. This feature is for debugger/REPL
support.

```ruby
RubyVM.keep_script_lines = true
RubyVM::keep_script_lines = true

eval("def foo = nil\ndef bar = nil")
pp RubyVM::InstructionSequence.of(method(:foo)).script_lines
```
2021-10-21 16:17:39 +09:00
Alan Wu
27358b6ee4 Simplify code for YJIT const cache in compile.c
Since opt_getinlinecache and opt_setinlinecache point to the same cache
struct, there is no need to track the index of the get instruction and
then store it on the cache struct later when processing the set
instruction. Setting it when processing the get instruction works just
as well.

This change reduces our diff.
2021-10-20 18:19:43 -04:00
Noah Gibbs
be06112d48 Fix changes from rebase 2021-10-20 18:19:42 -04:00
Alan Wu
5b4305f71c Simpler fix for -DUSE_EMBED_CI=0
Nobu pointed out that saving the old ci to a local is enough to keep it
reachable.
2021-10-20 18:19:38 -04:00
Alan Wu
8cf01dd25c Revert "Fix use-after-free on USE_EMBED_CI=0"
This reverts commit 1e0f2e4b09ca9443524acf4b50ffd50a80f330f3.
2021-10-20 18:19:38 -04:00
Alan Wu
736eb29a3c Fix use-after-free on USE_EMBED_CI=0
The old code didn't keep old_operands[0] reachable while allocating. You
can crash it by requiring erb under GC stress mode.
2021-10-20 18:19:38 -04:00
Alan Wu
b626dd7211 YJIT: Fancier opt_getinlinecache
Make sure `opt_getinlinecache` is in a block all on its own, and
invalidate it from the interpreter when `opt_setinlinecache`.
It will recompile with a filled cache the second time around.
This lets YJIT runs well when the IC for constant is cold.
2021-10-20 18:19:33 -04:00
Maxime Chevalier-Boisvert
e4c65ec49c Refactor uJIT code into more files for readability 2021-10-20 18:19:26 -04:00
Alan Wu
8bda11f690 MicroJIT: compile after ten calls 2021-10-20 18:19:25 -04:00
Alan Wu
e8c914c250 Implement the --disable-ujit command line option 2021-10-20 18:19:24 -04:00
Alan Wu
265c5ca8b1 Avoid triggering GC while translating threaded code 2021-10-20 18:19:23 -04:00
Maxime Chevalier-Boisvert
038f5d964f Avoid recompiling overlapping instruction sequences in ujit 2021-10-20 18:19:23 -04:00
Alan Wu
4929ba0a5c Generate multiple copies of native code for pop
Insert generated addresses into st_table for mapping native code
addresses back to info about VM instructions. Export `encoded_insn_data`
to do this. Also some style fixes.
2021-10-20 18:19:23 -04:00
Maxime Chevalier-Boisvert
1c8fb90f6b Add new files, ujit_compile.c, ujit_compile.h 2021-10-20 18:19:23 -04:00
Maxime Chevalier-Boisvert
566d4abee5 Added shift instructions 2021-10-20 18:19:23 -04:00
Alan Wu
16c5ce863c Yeah, this actually works! 2021-10-20 18:19:22 -04:00
Nobuyoshi Nakada
768ceb4ead
Cast to void pointer for %p in commented out code [ci skip] 2021-10-20 11:22:33 +09:00
Aaron Patterson
217df51f0e Dump outer variables tables when dumping an iseq to binary
This commit dumps the outer variables table when dumping an iseq to
binary.  This fixes a case where Ractors aren't able to tell what outer
variables belong to a lambda after the lambda is loaded via ISeq.load_from_binary

[Bug #18232] [ruby-core:105504]
2021-10-07 15:39:47 -07:00
S.H
dc9112cf10
Using NIL_P macro instead of == Qnil 2021-10-03 22:34:45 +09:00
S-H-GAMELINKS
83a5e2bb5c Using RB_FLOAT_TYPE_P macro 2021-09-12 11:16:31 +09:00
S-H-GAMELINKS
56065f0686 Using SYMBOL_P macro 2021-09-11 08:48:56 +09:00
Nobuyoshi Nakada
cfbf2bde40
Remove unused argument 2021-09-10 21:26:16 +09:00
卜部昌平
dddc618d30 suppress GCC's -Wsuggest-attribute=format
I was not aware of this because I use clang these days.
2021-09-10 20:00:06 +09:00
S-H-GAMELINKS
bdd6d8746f Replace RBOOL macro 2021-09-05 23:01:27 +09:00
Nobuyoshi Nakada
cb3df3d87b
Extract compile_attrasgn from iseq_compile_each0 2021-09-01 15:19:11 +09:00
Nobuyoshi Nakada
aac2b0fc6b
Extract compile_kw_arg from iseq_compile_each0 2021-09-01 15:19:11 +09:00
Nobuyoshi Nakada
cbf841e3ed
Extract compile_errinfo from iseq_compile_each0 2021-09-01 15:19:11 +09:00
Nobuyoshi Nakada
d7bba95eba
Extract compile_dots from iseq_compile_each0 2021-09-01 15:19:10 +09:00
Nobuyoshi Nakada
d58143f3b5
Extract compile_colon3 from iseq_compile_each0 2021-09-01 15:19:10 +09:00
Nobuyoshi Nakada
70c8155d8b
Extract compile_colon2 from iseq_compile_each0 2021-09-01 15:19:10 +09:00
Nobuyoshi Nakada
270a674a79
Extract compile_match from iseq_compile_each0 2021-09-01 15:19:09 +09:00
Nobuyoshi Nakada
a92fdc90da
Extract compile_yield from iseq_compile_each0 2021-09-01 15:19:09 +09:00
Nobuyoshi Nakada
996489d7e0
Extract compile_super from iseq_compile_each0 2021-09-01 15:19:09 +09:00
Nobuyoshi Nakada
6cf9f17191
Extract compile_op_log from iseq_compile_each0 2021-09-01 15:19:08 +09:00
Nobuyoshi Nakada
d045d5f860
Extract compile_op_cdecl from iseq_compile_each0 2021-09-01 15:19:08 +09:00
Nobuyoshi Nakada
0c7ff37540
Extract compile_op_asgn2 from iseq_compile_each0 2021-09-01 15:19:08 +09:00
Nobuyoshi Nakada
0b87b75ae9
Extract compile_op_asgn1 from iseq_compile_each0 2021-09-01 15:19:07 +09:00
Nobuyoshi Nakada
f781e537b5
Remove no longer used variable line_node 2021-08-31 15:27:02 +09:00
Nobuyoshi Nakada
d23264d359
Extract compile_block from iseq_compile_each0
And constify `node` argument of `iseq_compile_each0`.
2021-08-31 15:27:02 +09:00
Nobuyoshi Nakada
181207e830
Constify line_node in iseq_compile_each0 2021-08-31 10:21:22 +09:00
Jeremy Evans
48c8df9e0e
Allow tracing of optimized methods
This updates the trace instructions to directly dispatch to
opt_send_without_block.  So this should cause no slowdown in
non-trace mode.

To enable the tracing of the optimized methods, RUBY_EVENT_C_CALL
and RUBY_EVENT_C_RETURN are added as events to the specialized
instructions.

Fixes [Bug #14870]

Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
2021-08-21 10:15:01 -07:00
Kazuki Tsujimoto
4568ba0711
Show verbose error messages when single pattern match fails
[0] => [0, *, a]
    #=> [0] length mismatch (given 1, expected 2+) (NoMatchingPatternError)

Ignore test failures of typeprof caused by this change for now.
2021-08-15 09:38:24 +09:00
Alan Wu
cbecf9c7ba
Fix use-after-free on -DUSE_EMBED_CI=0
On -DUSE_EMBED_CI=0, there are more GC allocations and the old code
didn't keep old_operands[0] reachable while allocating. On a Debian
based system, I get a crash requiring erb under GC stress mode. On
macOS, tool/transcode-tblgen.rb runs incorrectly if I put GC.stress=true
as the first line.
2021-07-29 12:04:36 -04:00
Jeremy Evans
fa87f72e1e Add pattern matching pin support for instance/class/global variables
Pin matching for local variables and constants is already supported,
and it is fairly simple to add support for these variable types.

Note that pin matching for method calls is still not supported
without wrapping in parentheses (pin expressions).  I think that's
for the best as method calls are far more complex (arguments/blocks).

Implements [Feature #17724]
2021-07-15 09:56:02 -07:00
Aaron Patterson
2599d1a8df Store the dup'd CDHASH in the object list during IBF load
Since b2fc592c304 nothing was holding a reference to the dup'd CDHASH
during IBF loading.  If a GC happened to run during IBF load then the
copied hash wouldn't have anything to keep it alive.  We don't really
want to keep the originally loaded CDHASH hash, so this patch just
overwrites the original hash with the copied / modified hash.

[Bug #17984] [ruby-core:104259]
2021-07-06 17:48:40 -07:00
eileencodes
31f4d26273 Check type of instruction - can be INSN or ADJUST
If the type is ADJUST we don't want to treat it like an INSN so we have
to check the type before reading from `insn_info.events`.

[Bug #18001] [ruby-core:104371]

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2021-06-23 11:34:37 -07:00
eileencodes
b91b3bc771 Add a cache for class variables
Redo of 34a2acdac788602c14bf05fb616215187badd504 and
931138b00696419945dc03e10f033b1f53cd50f3 which were reverted.

GitHub PR #4340.

This change implements a cache for class variables. Previously there was
no cache for cvars. Cvar access is slow due to needing to travel all the
way up th ancestor tree before returning the cvar value. The deeper the
ancestor tree the slower cvar access will be.

The benefits of the cache are more visible with a higher number of
included modules due to the way Ruby looks up class variables. The
benchmark here includes 26 modules and shows with the cache, this branch
is 6.5x faster when accessing class variables.

```
compare-ruby: ruby 3.1.0dev (2021-03-15T06:22:34Z master 9e5105c) [x86_64-darwin19]
built-ruby: ruby 3.1.0dev (2021-03-15T12:12:44Z add-cache-for-clas.. c6be009) [x86_64-darwin19]

|         |compare-ruby|built-ruby|
|:--------|-----------:|---------:|
|vm_cvar  |      5.681M|   36.980M|
|         |           -|     6.51x|
```

Benchmark.ips calling `ActiveRecord::Base.logger` from within a Rails
application. ActiveRecord::Base.logger has 71 ancestors. The more
ancestors a tree has, the more clear the speed increase. IE if Base had
only one ancestor we'd see no improvement. This benchmark is run on a
vanilla Rails application.

Benchmark code:

```ruby
require "benchmark/ips"
require_relative "config/environment"

Benchmark.ips do |x|
  x.report "logger" do
    ActiveRecord::Base.logger
  end
end
```

Ruby 3.0 master / Rails 6.1:

```
Warming up --------------------------------------
              logger   155.251k i/100ms
Calculating -------------------------------------
```

Ruby 3.0 with cvar cache /  Rails 6.1:

```
Warming up --------------------------------------
              logger     1.546M i/100ms
Calculating -------------------------------------
              logger     14.857M (± 4.8%) i/s -     74.198M in   5.006202s
```

Lastly we ran a benchmark to demonstate the difference between master
and our cache when the number of modules increases. This benchmark
measures 1 ancestor, 30 ancestors, and 100 ancestors.

Ruby 3.0 master:

```
Warming up --------------------------------------
            1 module     1.231M i/100ms
          30 modules   432.020k i/100ms
         100 modules   145.399k i/100ms
Calculating -------------------------------------
            1 module     12.210M (± 2.1%) i/s -     61.553M in   5.043400s
          30 modules      4.354M (± 2.7%) i/s -     22.033M in   5.063839s
         100 modules      1.434M (± 2.9%) i/s -      7.270M in   5.072531s

Comparison:
            1 module: 12209958.3 i/s
          30 modules:  4354217.8 i/s - 2.80x  (± 0.00) slower
         100 modules:  1434447.3 i/s - 8.51x  (± 0.00) slower
```

Ruby 3.0 with cvar cache:

```
Warming up --------------------------------------
            1 module     1.641M i/100ms
          30 modules     1.655M i/100ms
         100 modules     1.620M i/100ms
Calculating -------------------------------------
            1 module     16.279M (± 3.8%) i/s -     82.038M in   5.046923s
          30 modules     15.891M (± 3.9%) i/s -     79.459M in   5.007958s
         100 modules     16.087M (± 3.6%) i/s -     81.005M in   5.041931s

Comparison:
            1 module: 16279458.0 i/s
         100 modules: 16087484.6 i/s - same-ish: difference falls within error
          30 modules: 15891406.2 i/s - same-ish: difference falls within error
```

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2021-06-18 10:02:44 -07:00