Граф коммитов

596 Коммитов

Автор SHA1 Сообщение Дата
Étienne Barrié 257f78fb67 Show where mutated chilled strings were allocated
[Feature #20205]

The warning now suggests running with --debug-frozen-string-literal:

```
test.rb:3: warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information)
```

When using --debug-frozen-string-literal, the location where the string
was created is shown:

```
test.rb:3: warning: literal string will be frozen in the future
test.rb:1: info: the string was created here
```

When resurrecting strings and debug mode is not enabled, the overhead is a simple FL_TEST_RAW.
When mutating chilled strings and deprecation warnings are not enabled,
the overhead is a simple warning category enabled check.

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2024-10-21 12:33:02 +02:00
Kevin Newton e17243d325 Point keyword->table into iseq local table 2024-10-18 14:16:02 -04:00
Peter Zhu 90aa6aefc4 Fix memory leak in syntax error in prism
If there is a syntax error, there could be an ast_node in the result.
This could get leaked if there is a syntax error so parsing could not
complete (parsed is not set to true).

For example, the following script leaks memory:

    10.times do
      10_000.times do
        eval("def foo(...) super(...) {}; end")
      rescue SyntaxError
      end

      puts `ps -o rss= -p #{$$}`
    end

Before:

    31328
    42768
    53856
    65120
    76208
    86768
    97856
    109120
    120208
    131296

After:

    20944
    20944
    20944
    20944
    20944
    20944
    20944
    20944
    20944
    20944
2024-10-16 14:52:46 -04:00
Nobuyoshi Nakada 9a90cd2284 Cast via `uintptr_t` function pointer between object pointer
- ISO C forbids conversion of function pointer to object pointer type
- ISO C forbids conversion of object pointer to function pointer type
2024-10-08 23:29:49 +09:00
Kevin Newton 30038656aa Fix intermediate array off-by-one error
Co-authored-by: Adam Hess <HParker@github.com>
2024-10-04 15:04:26 -04:00
Luke Gruber d592ddd5e6 Fix compile issue with a short-circuited if/unless condition and `defined?`
This caused an issue when `defined?` was in the `if` condition. Its
instructions weren't appended to the instruction sequence even though it was compiled
if a compile-time known logical short-circuit happened before the `defined?`. The catch table
entry (`defined?` compilation produces a catch table entry) was still on the iseq even though the
instructions weren't there. This caused faulty exception handling in the method.
The solution is to no add the catch table entry for `defined?` after a compile-time known logical
short circuit.

This shouldn't touch much code, it's only for cases like the following,
which can occur during debugging:

    if false && defined?(Some::CONSTANT)
    "more code..."
    end

Fixes [Bug #20501]
2024-10-01 02:12:56 +09:00
Peter Zhu 6b8078cc03 Don't create empty string for interpolation
We don't need to create an empty string for interpolation unless it is
the only element.

For example:

    "#{hello} world"

Before:

    0000 putobject                              ""                        (   1)[Li]
    0002 putself
    0003 opt_send_without_block                 <calldata!mid:hello, argc:0, FCALL|VCALL|ARGS_SIMPLE>
    0005 dup
    0006 objtostring                            <calldata!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>
    0008 anytostring
    0009 putobject                              " world"
    0011 concatstrings                          3
    0013 leave

After:

    0000 putself                                                          (   1)[Li]
    0001 opt_send_without_block                 <calldata!mid:hello, argc:0, FCALL|VCALL|ARGS_SIMPLE>
    0003 dup
    0004 objtostring                            <calldata!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>
    0006 anytostring
    0007 putobject                              " world"
    0009 concatstrings                          2
    0011 leave
2024-09-30 09:09:09 -04:00
ydah 1b6c234fec s/reproducable/reproducible/ 2024-09-30 13:04:49 +09:00
Kevin Newton addb5fea94 Fix up compiling popped ranges with non-optimizable bounds
Fixes [Bug #20763]
2024-09-27 13:43:37 -04:00
Kevin Newton 6a168fbf41 Potentially fix ASAN checks for GC-ing operand 2024-09-25 12:23:29 -04:00
Kevin Newton ecbc4a67c9
Fix up new types for block arguments and splats in prism compiler 2024-09-25 09:52:47 -04:00
Kevin Newton a80a9cf9ef Further split up pm_compile_node to work on -O0 builds 2024-09-24 17:08:17 -04:00
Peter Zhu 19c617b51d Revert "GC guard current_string in the putobject instruction"
This reverts commit 69f28ab715.

This commit is being reverted because it does not fix the ASAN issue in
the objtostring instruction.
2024-09-23 11:45:21 -04:00
Peter Zhu 69f28ab715 GC guard current_string in the putobject instruction
This is a band-aid solution for #11655 that only applies the fix for the
putobject instruction before the objtostring instruction.

This should help fix the use-after-poison in the ASAN CI.

http://ci.rvm.jp/logfiles/brlog.trunk_asan.20240920-082802
2024-09-20 13:07:38 -04:00
Peter Zhu 7a2b5ed5ee Replace RB_OBJ_WRITTEN with RB_OBJ_WRITE in pm_compile_scope_node 2024-09-19 14:51:21 -04:00
Jeremy Evans 268c72377b
Raise a compile error for break/next/redo inside eval in cases where it is optimized away
In cases where break/next/redo are not valid syntax, they should
raise a SyntaxError even if inside a conditional block that is
optimized away.

Fixes [Bug #20597]

Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2024-09-18 16:54:56 -07:00
Jeremy Evans 29f2cb83fb
Fix evaluation order issue in f(**h, &h.delete(key))
Previously, this would delete the key in `h` before keyword
splatting `h`.  This goes against how ruby handles `f(*a, &a.pop)`
and similar expressions.

Fix this by having the compiler check whether the block pass
expression is safe.  If it is not safe, then dup the keyword
splatted hash before evaluating the block pass expression.

For expression: `h=nil; f(**h, &h.delete(:key))`

VM instructions before:

```
0000 putnil                                                           (   1)[Li]
0001 setlocal_WC_0                          h@0
0003 putself
0004 getlocal_WC_0                          h@0
0006 getlocal_WC_0                          h@0
0008 putobject                              :key
0010 opt_send_without_block                 <calldata!mid:delete, argc:1, ARGS_SIMPLE>
0012 splatkw
0013 send                                   <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT>, nil
0016 leave
```

VM instructions after:

```
0000 putnil                                                           (   1)[Li]
0001 setlocal_WC_0                          h@0
0003 putself
0004 putspecialobject                       1
0006 newhash                                0
0008 getlocal_WC_0                          h@0
0010 opt_send_without_block                 <calldata!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE>
0012 getlocal_WC_0                          h@0
0014 putobject                              :key
0016 opt_send_without_block                 <calldata!mid:delete, argc:1, ARGS_SIMPLE>
0018 send                                   <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT|KW_SPLAT_MUT>, nil
0021 leave
```

This is the same as 07d3bf4832, except that
it removes unnecessary hash allocations when using the prism compiler.

Fixes [Bug #20640]
2024-09-18 12:46:07 -07:00
Jeremy Evans 9c12c39ed1 Revert "Fix evaluation order issue in f(**h, &h.delete(key))"
This reverts commit 07d3bf4832.

No failures in the pull request CI, but there are now allocation
test failures.
2024-09-18 11:26:10 -07:00
Jeremy Evans 07d3bf4832
Fix evaluation order issue in f(**h, &h.delete(key))
Previously, this would delete the key in h before keyword
splatting h.  This goes against how ruby handles f(*a, &a.pop)
and similar expressions.

Fix this by having the compiler check whether the block pass
expression is safe.  If it is not safe, then dup the keyword
splatted hash before evaluating the block pass expression.

For expression: `h=nil; f(**h, &h.delete(:key))`

VM instructions before:

```
0000 putnil                                                           (   1)[Li]
0001 setlocal_WC_0                          h@0
0003 putself
0004 getlocal_WC_0                          h@0
0006 getlocal_WC_0                          h@0
0008 putobject                              :key
0010 opt_send_without_block                 <calldata!mid:delete, argc:1, ARGS_SIMPLE>
0012 splatkw
0013 send                                   <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT>, nil
0016 leave
```

VM instructions after:

```
0000 putnil                                                           (   1)[Li]
0001 setlocal_WC_0                          h@0
0003 putself
0004 putspecialobject                       1
0006 newhash                                0
0008 getlocal_WC_0                          h@0
0010 opt_send_without_block                 <calldata!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE>
0012 getlocal_WC_0                          h@0
0014 putobject                              :key
0016 opt_send_without_block                 <calldata!mid:delete, argc:1, ARGS_SIMPLE>
0018 send                                   <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT|KW_SPLAT_MUT>, nil
0021 leave
```

Fixes [Bug #20640]
2024-09-18 11:18:29 -07:00
Luke Gruber c14b60630d Fix coding issue in prism_compile.c
Make sure to set back `ISEQ_COMPILE_DATA(iseq)->current_block` for
forwarding super nodes with a block.

Fixes [Bug #20740]
2024-09-18 11:52:57 -04:00
Kevin Newton 2beb4c6e87 [PRISM] Assume an eval context for RubyVM::ISEQ compile
Fixes [Bug #20741]
2024-09-16 14:31:01 -04:00
Kevin Newton 1e52dde82a [PRISM] Match defined behavior for explicit block
Fixes [Bug #20748]
2024-09-16 11:53:56 -04:00
Kevin Newton 2d495300e2
[PRISM] Fix up pm_compile_branch_condition issue with single insn iseqs 2024-09-12 15:49:44 -04:00
Kevin Newton 9c461cd125 [PRISM] Check error type for parsing directory 2024-09-12 13:43:04 -04:00
Kevin Newton ca61729fa7 Fix opening multibyte character filepath on Windows 2024-09-12 13:43:04 -04:00
Kevin Newton d4af38ec9d Fix FILE_SHARE_* permissions for Windows in read_entire_file 2024-09-12 13:43:04 -04:00
Kevin Newton d4ab1e4482 [PRISM] Move compile scope node to its own function 2024-09-12 13:43:04 -04:00
Kevin Newton c4b43692db [PRISM] Move case node compilation into its own function 2024-09-12 13:43:04 -04:00
Kevin Newton ea2af5782d Switch the default parser from parse.y to Prism
This commit switches the default parser to Prism. There are a
couple of additional changes related to this that are a part of
this as well to make this happen.

* Switch the default parser in parse.h
* Remove the Prism-specific workflow and add a parse.y-specific
  workflow to CI so that it continues to be tested
* Update a few test exclusions since Prism has the correct
  behavior but parse.y doesn't per
  https://bugs.ruby-lang.org/issues/20504.
* Skips a couple of tests on RBS which are failing because they
  are using RubyVM::AbstractSyntaxTree.of.

Fixes [Feature #20564]
2024-09-12 13:43:04 -04:00
Luke Gruber 5d358b660d Fix issue with super and forwarding arguments in prism_compile.c
Fixes [Bug #20720]
2024-09-11 16:41:46 -04:00
Kevin Newton 767d0a1716
[PRISM] Fix up compile warning for sign comparison 2024-09-03 13:16:24 -04:00
Kevin Newton 371432b2d7 [PRISM] Handle RubyVM.keep_script_lines 2024-08-29 20:27:01 -04:00
Yuta Saito 591a157b0f prism_compile.c: Fix read_entire_file() for platforms without file mmap
Apply similar fix to https://github.com/ruby/prism/pull/2944
2024-08-29 14:09:35 -04:00
Kevin Newton 079161e1ba [PRISM] Respect PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING flag 2024-08-29 10:31:02 -04:00
Kevin Newton 14bb376b79 [PRISM] Copy the rest of the setup_args_dup_rest_p function 2024-08-29 10:29:34 -04:00
Alan Wu fe440c5967 [PRISM] Use node flags for dup_rest detection instead of looping 2024-08-28 19:27:15 -04:00
Alan Wu c3ffa7106b [PRISM] Set use_block parameter flag for forwardable methods
Match logic in compile.c:2133. Without this, the unused block warning
code allocates an array, causing TestAllocation to fail.
2024-08-28 17:17:33 -04:00
Kevin Newton 417bb8d4fd [PRISM] Field renaming
Rename some fields that do not quite make sense.

* CaseMatchNode#consequent -> CaseMatchNode#else_clause
* CaseNode#consequent -> CaseNode#else_clause
* IfNode#consequent -> IfNode#subsequent
* RescueNode#consequent -> RescueNode#subsequent
* UnlessNode#consequent -> UnlessNode#else_clause
2024-08-28 15:06:53 -04:00
Alan Wu 7c9bcdf397 [PRISM] Improve `dup_rest` optimization targeting
Part of implementing 3de20efc30 in
prism_compile.c. Down to 2 failures from 30 failures in
test/ruby/test_allocation.rb.
2024-08-28 13:34:37 -04:00
Alan Wu 1729f47e72 [PRISM] Wait for data before reading pipes and chardevs
With the parse.y parser, when a fifo (named pipe) is passed to
Kernel#load and friends, we wait for data to be available first before
reading. Note that with fifos, opening with `O_RDONLY|O_NONBLOCK` and
then reading will look like EOF with read(2) returning 0, but data can
become available later.

The prism compiler needs to match this behavior to pass
`test_loading_fifo_{fd_leak,threading_raise,threading_success}`. I chose
to use IO#read to do this.

An alternative way to match behavior would be to use open_load_file()
from ruby.c like parse.y, but I opted to only allocate an IO to deal
with threading when reading from pipes and character devices. The
memory mapping code seems to work fine for regular files.
2024-08-27 17:39:34 -04:00
eileencodes 7462cc7743 [PRISM] Fix allocations for keyword splat params
Fixes the following allocations tests:

* `test_keyword_and_keyword_splat_parameter`
* `test_keyword_parameter`
* `test_keyword_splat_parameter`
* `test_no_array_allocation_with_splat_and_nonstatic_keywords`
* `test_no_parameters`
* `test_positional_splat_and_keyword_splat_parameter`
* `test_ruby2_keywords`

* Checks for `first_chunk` and if `stack_length == 0` to match the
upstream parser. Otherwise, this optimization is skipped.
* Subtracts the index, otherwise it will skip the hash allocation for
the following: `keyword(*empty_array, a: 2, **empty_hash)`.
* Sets `dup_rest` in order to determine when to set the correct flags
* Doesn't set `VM_CALL_KW_SPLAT_MUT` flag unless `dup_rest` doesn't
match `initial_dup_rest`.

Given the following code:

```ruby
keyword(*empty_array, a: 2)
```

Instructions before:

```
== disasm: #<ISeq:test@test.rb:4 (4,0)-(8,3)>
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] empty_hash@0<Arg>[ 1] empty_array@1
0000 newarray                               0                         (   5)[LiCa]
0002 setlocal_WC_0                          empty_array@1
0004 putself                                                          (   7)[Li]
0005 getlocal_WC_0                          empty_array@1
0007 splatarray                             true
0009 putobject                              :a
0011 putobject                              2
0013 newhash                                2
0015 opt_send_without_block                 <calldata!mid:keyword, argc:2, ARGS_SPLAT|ARGS_SPLAT_MUT|FCALL|KW_SPLAT>
0017 leave                                                            (   8)[Re]
```

Instructions after:

```
== disasm: #<ISeq:test@test.rb:4 (4,0)-(8,3)>
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] empty_hash@0<Arg>[ 1] empty_array@1
0000 newarray                               0                         (   5)[LiCa]
0002 setlocal_WC_0                          empty_array@1
0004 putself                                                          (   7)[Li]
0005 getlocal_WC_0                          empty_array@1
0007 splatarray                             false
0009 putobject                              {:a=>2}
0011 opt_send_without_block                 <calldata!mid:keyword, argc:2, ARGS_SPLAT|FCALL|KW_SPLAT>
0013 leave                                                            (   8)[Re]
```

Differences:

* `splatarray` is `false` not `true
* `putobject`, `putobject`, `newhash` is simply `putobject` with
optimizations on
* Remove `ARGS_SPLAT_MUT` flag

Related: ruby/prism#2994

Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2024-08-27 16:01:46 -04:00
Kevin Newton 773cf883ac [PRISM] Reset $. when done reading STDIN 2024-08-21 16:59:03 -04:00
Kevin Newton f60499826f [PRISM] Fix TestTRICK#test_ksk_1
If an array element is a static literal that does not result in a
intermediate array, it still needs to be compiled normally.
2024-08-21 16:32:19 -04:00
eileencodes 7ad74d1686 [PRISM] Implement unused block warning
Related: ruby/prism#2935
2024-08-21 11:37:13 -04:00
Jean Boussier ca5b7276c6 compile.c: don't allocate empty default values list
It just wastes memory.
2024-08-11 15:04:35 +02:00
Kevin Newton 1a18b03ee7 [PRISM] Add anon_* flags for iseqs with anonymous * and ** 2024-07-24 12:02:33 -04:00
eileencodes b4a02502c2 [PRISM] Fix block param instructions when it has a recevier
In the following code:

```ruby
def foo(&blk)
  blk.call
end
```

Prism was using the `getblockparam` instruction but it should be
`getblockparamproxy`. In this case we have a receiver, if it's a local
variable read node, then it needs to go through the path to use
`getblockparamproxy`.

Before:

```
== disasm: #<ISeq:<main>@test2.rb:1 (1,0)-(3,3)>
0000 definemethod                           :foo, foo                 (   1)[Li]
0003 putobject                              :foo
0005 leave

== disasm: #<ISeq:foo@test2.rb:1 (1,0)-(3,3)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1])
[ 1] blk@0<Block>
0000 getblockparam                          blk@0, 0                  (   2)[LiCa]
0003 opt_send_without_block                 <calldata!mid:call, argc:0, ARGS_SIMPLE>
0005 leave                                                            (   3)[Re]
```

After:

```
== disasm: #<ISeq:<main>@test2.rb:1 (1,0)-(3,3)>
0000 definemethod                           :foo, foo                 (   1)[Li]
0003 putobject                              :foo
0005 leave

== disasm: #<ISeq:foo@test2.rb:1 (1,0)-(3,3)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1])
[ 1] blk@0<Block>
0000 getblockparamproxy                     blk@0, 0                  (   2)[LiCa]
0003 opt_send_without_block                 <calldata!mid:call, argc:0, ARGS_SIMPLE>
0005 leave                                                            (   3)[Re]
```

Fixes `test_getblockparamproxy` and `test_ifunc_getblockparamproxy` in
test_yjit.rb. Related to ruby/prism#2935.
2024-07-23 21:45:48 -04:00
eileencodes 70d4dcb76c [Prism] Use `putnil` for nil kwargs, not `putobject {}`
This addresses one of the issues in the `test_kw_splat_nil` failure, but
doesn't make the test pass because of other changes that need to be made
to Prism directly.

One issue was when we have the following code Prism was using
`putobject` with an empty hash whereas the parse.y parser used `putnil`.

```ruby
:ok.itself(**nil)
```

Before:

```
0000 putobject                              :ok                       (   1)[Li]
0002 putobject                              {}
0004 opt_send_without_block                 <calldata!mid:itself, argc:1, KW_SPLAT>
0006 leave
```

After:

```
== disasm: #<ISeq:<main>@test2.rb:1 (1,0)-(1,17)>
0000 putobject                              :ok                       (   1)[Li]
0002 putnil
0003 opt_send_without_block                 <calldata!mid:itself, argc:1, KW_SPLAT>
0005 leave
```

Related to ruby/prism#2935.
2024-07-23 21:45:40 -04:00
Kevin Newton b6800515e8 [PRISM] Fix up ensure compilation, match compile.c 2024-07-23 12:48:48 -04:00
Peter Zhu ec6f40e8f1 [PRISM] Use xcalloc for constants instead of calloc 2024-07-22 14:22:47 -04:00