summaryrefslogtreecommitdiff
path: root/test/ruby
AgeCommit message (Collapse)Author
2023-12-14[PRISM] Account for multiple anonymous localsJemma Issroff
This commit adjusts the local table size to be consistent regardless of the number of anonymous locals.
2023-12-14[PRISM] Fix bugs in compiling optional keyword parametersJemma Issroff
This PR fixes two bugs when compiling optional keyword parameters: - It moves keyword parameter compilation to STEP 5 in the parameters sequence, where the rest of compilation happens. This is important because keyword parameter compilation relies on the value of body->param.keyword->bits_start which gets set in an earlier step - It compiles array and hash values for keyword parameters, which it didn't previously
2023-12-14[PRISM] Use frozen flag on StringNodeJemma Issroff
2023-12-14Fix op asgn method calls passing mutable keyword splatsJeremy Evans
When passing the keyword splat to [], it cannot be mutable, because mutating the keyword splat inside [] would result in changes to the keyword splat passed to []=.
2023-12-14[PRISM] Add anon KW args to the block local tableMatt Valentine-House
2023-12-13[PRISM] Add a test with a non-static-literal hash keyUfuk Kayserilioglu
2023-12-13[Prism] Fix InterpolatedMatchLastLine Instructionseileencodes
I looked at this at RubyConf with Kevin, and we noticed that there was a `putobject` empty string missing from the instructions. I just got back around to implementing this and pushing a PR and while doing that noticed that we also have a `getspecial` when we want a `getglobal`. This change adds the `putobject` instruction and replaces the `getspecial` with a `getglobal`. If we look at the parsetree for the following code: ```ruby $pit = '.oo'; if /"#{$pit}"/mix; end ``` We can see it has a `NODE_GVAR` and the [Ruby compiler](https://github.com/ruby/ruby/blob/a4b43e92645e46ee5a8c9af42d3de57cd052e87c/compile.c#L10024-L10030) shows that should use `getglobal. ``` @ NODE_SCOPE (id: 14, line: 1, location: (1,0)-(22,36)) +- nd_tbl: (empty) +- nd_args: | (null node) +- nd_body: @ NODE_BLOCK (id: 12, line: 22, location: (22,0)-(22,36)) +- nd_head (1): | @ NODE_GASGN (id: 0, line: 22, location: (22,0)-(22,12))* | +- nd_vid: :$pit | +- nd_value: | @ NODE_STR (id: 1, line: 22, location: (22,7)-(22,12)) | +- nd_lit: ".oo" +- nd_head (2): @ NODE_IF (id: 11, line: 22, location: (22,14)-(22,36))* +- nd_cond: | @ NODE_MATCH2 (id: 10, line: 22, location: (22,14)-(22,36)) | +- nd_recv: | | @ NODE_DREGX (id: 2, line: 22, location: (22,17)-(22,31)) | | +- nd_lit: "\"" | | +- nd_next->nd_head: | | | @ NODE_EVSTR (id: 4, line: 22, location: (22,19)-(22,26)) | | | +- nd_body: | | | @ NODE_GVAR (id: 3, line: 22, location: (22,21)-(22,25)) | | | +- nd_vid: :$pit | | +- nd_next->nd_next: | | @ NODE_LIST (id: 7, line: 22, location: (22,26)-(22,27)) | | +- as.nd_alen: 1 | | +- nd_head: | | | @ NODE_STR (id: 6, line: 22, location: (22,26)-(22,27)) | | | +- nd_lit: "\"" | | +- nd_next: | | (null node) | +- nd_value: | @ NODE_GVAR (id: 9, line: 22, location: (22,14)-(22,36)) | +- nd_vid: :$_ +- nd_body: | @ NODE_BEGIN (id: 8, line: 22, location: (22,32)-(22,32)) | +- nd_body: | (null node) +- nd_else: (null node) ``` I'm struggling with writing a failing test, but the before/after instructions show that `getglobal` is correct here. I compared the instructions for the other `InterpolatedMatchLastLine` node tests and they also used `getglobal`. I've edited the existing `InterpolatedLastMatchLineNode` test so that it will use that instruction when copied out of the test. Without the quotes it thinks it's just a `MatchLastLineNode`. Incorrect instructions: ``` "********* Ruby *************" == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(22,36)> 0000 putstring ".oo" ( 22)[Li] 0002 setglobal :$pit 0004 putobject "\"" 0006 getglobal :$pit 0008 dup 0009 objtostring <calldata!mid:to_s, argc:0, FCALL|ARGS_SIMPLE> 0011 anytostring 0012 putobject "\"" 0014 toregexp 7, 3 0017 getglobal :$_ 0019 send <calldata!mid:=~, argc:1, ARGS_SIMPLE>, nil 0022 branchunless 30 0024 jump 26 0026 putnil 0027 jump 31 0029 pop 0030 putnil 0031 leave "********* PRISM *************" == disasm: #<ISeq:<compiled>@<compiled>:21 (21,0)-(21,36)> 0000 putstring ".oo" ( 21)[Li] 0002 setglobal :$pit 0004 putobject "\"" 0006 getglobal :$pit 0008 dup 0009 objtostring <calldata!mid:to_s, argc:0, FCALL|ARGS_SIMPLE> 0011 anytostring 0012 putobject "\"" 0014 toregexp 7, 3 0017 getspecial 0, 0 0020 send <calldata!mid:=~, argc:1, ARGS_SIMPLE>, nil 0023 branchunless 31 0025 jump 27 0027 putnil 0028 jump 32 0030 pop 0031 putnil 0032 leave ``` Fixed instructions: ``` == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(22,36)> 0000 putstring ".oo" ( 22)[Li] 0002 setglobal :$pit 0004 putobject "\"" 0006 getglobal :$pit 0008 dup 0009 objtostring <calldata!mid:to_s, argc:0, FCALL|ARGS_SIMPLE> 0011 anytostring 0012 putobject "\"" 0014 toregexp 7, 3 0017 getglobal :$_ 0019 send <calldata!mid:=~, argc:1, ARGS_SIMPLE>, nil 0022 branchunless 30 0024 jump 26 0026 putnil 0027 jump 31 0029 pop 0030 putnil 0031 leave "********* PRISM *************" == disasm: #<ISeq:<compiled>@<compiled>:21 (21,0)-(21,36)> 0000 putstring ".oo" ( 21)[Li] 0002 setglobal :$pit 0004 putobject "\"" 0006 getglobal :$pit 0008 dup 0009 objtostring <calldata!mid:to_s, argc:0, FCALL|ARGS_SIMPLE> 0011 anytostring 0012 putobject "\"" 0014 toregexp 7, 3 0017 getglobal :$_ 0019 send <calldata!mid:=~, argc:1, ARGS_SIMPLE>, nil 0022 branchunless 30 0024 jump 26 0026 putnil 0027 jump 31 0029 pop 0030 putnil 0031 leave ```
2023-12-13Fix memory leak in Hash#compare_by_identityAlan Wu
We didn't free the old ST before overwriting it which caused a leak. Found with RUBY_FREE_ON_EXIT. Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2023-12-13Make String#chomp! raise ArgumentError for 2+ arguments if string is emptyJeremy Evans
String#chomp! returned nil without checking the number of passed arguments in this case.
2023-12-13[PRISM] Generate instruction for when redo_label is setMatt Valentine-House
2023-12-13[PRISM] If receiver on CallNode is SelfNode, use FCALL flagsJemma Issroff
2023-12-13[PRISM] Fix attrset edge caseseileencodes
In some cases code may look like an attrset ID but should actually return the value of the method, not the passed values. In ruby/prism#2051 a flag was added when we have a attribute write call. I used this flag to add the proper instructions when we have a real attrset instead of using `rb_is_attrset_id` which was kind of hacky anyway. The value that should be returned in the newly added test is 42, not 2. Previously the changes we had made returned 2. Related to ruby/prism#1715
2023-12-12Skip a GC test for RJITTakashi Kokubun
It randomly fails like this: https://github.com/ruby/ruby/actions/runs/7191443542/job/19586164973
2023-12-12[PRISM] Correctly parse non-base 10 integers in PrismJemma Issroff
This commit passes an `end` to rb_int_parse_cstr which allows us to correctly parse non-base 10 integers which are enclosed in parenthesis. Prior to this commit, we were getting a putobject nil when compiling `(0o0)` for example.
2023-12-12[PRISM] Fix segv with regex once flageileencodes
When you have an interpolated regex with a `once` flag and local variable is outside the block created by the `once` flag, Prism would see a segv. This is because it was not taking the depth into account. To fix this, we need to add 1 to the `local_depth_offset` on the `scope`. Fixes: ruby/prism#2047
2023-12-12[PRISM] Compile NextNode argumentsMatt Valentine-House
2023-12-12[PRISM] Implementing forwarding of args for ForwardingSuperNodeJemma Issroff
ForwardingSuperNodes need to actually forward any applicable arguments. This commit implements that logic, by using the data stored on the local iseq about the parameters to forward the appropriate arguments.
2023-12-12[Bug #19114] Fix for multiple calls of TracePoint#enableKouhei Yanagita
2023-12-12Fix op asgn calls with keywordsJeremy Evans
Examples of such calls: ```ruby obj[kw: 1] += fo obj[**kw] &&= bar ``` Before this patch, literal keywords would segfault in the compiler, and keyword splat usage would result in TypeError. This handles all cases I can think of: * literal keywords * keyword splats * combined with positional arguments * combined with regular splats * both with and without blocks * both popped and non-popped cases This also makes sure that to_hash is only called once on the keyword splat argument, instead of twice, and make sure it is called before calling to_proc on a passed block. Fixes [Bug #20051] Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2023-12-12Make WeakKeyMap safe for compaction during allocationPeter Zhu
During allocation, the table may not have been allocated yet which would crash in the st_foreach.
2023-12-12Make WeakMap safe for compaction during allocationPeter Zhu
During allocation, the table may not have been allocated yet which would crash in the st_foreach.
2023-12-11Make Dir#chdir never yield args, and return block return valueJeremy Evans
If no block is given, return 0 instead of nil for consistency with Dir.chdir and Dir.fchdir.
2023-12-12Prevent a warning: method redefinedYusuke Endoh
2023-12-12Prevent warning: possibly useless use of a literal in void contextYusuke Endoh
2023-12-11[PRISM] Properly compile MultiTargetNodes within parametersJemma Issroff
If there are MultiTargetNodes within parameters, we need to iterate over them and compile them individually correctly, once the locals are all in the correct spaces. We need to add one getlocal for the hidden variable, and then can recurse into the MultiTargetNodes themselves
2023-12-11[PRISM] Fixed rest in MultiTargetNodesJemma Issroff
2023-12-11[PRISM] Define and use a pm_add_ensure_iseqJemma Issroff
Prior to this commit, we were using `add_ensure_iseq` which compiled a node as if it was a CRuby node. This commit defines `pm_add_ensure_iseq` which compiles the Prism node appropriately.
2023-12-11[PRISM] Fix ElseNode within CaseNodeJemma Issroff
The logic within the consequent for the CaseNodes in popped cases was incorrect as it wouldn't emit consequent instructions for a popped CaseNode. This commit fixes that.
2023-12-11Add handling of implicit hash argumentsUfuk Kayserilioglu
Arguments that are passed as a hash need special consideration since in certain case they are not treated as keyword arguments. For example, if a call is passing `"a" => 1` as an argument, this will be turned into an implicit hash argument and not a keyword argument. The existing compiler checks to see if all hash nodes can be treated as keyword arguments. If they can, then it will treat them as keyword arguments. If not, then it will treat them as implicit hash arguments. This commit implements the same logic inside the Prism compiler.
2023-12-09Ensure super(**kw, &block) calls kw.to_hash before block.to_procJeremy Evans
Similar as previous commit, but handles the super case with explicit arguments.
2023-12-09Ensure f(**kw, &block) calls kw.to_hash before block.to_procJeremy Evans
Previously, block.to_proc was called first, by vm_caller_setup_arg_block. kw.to_hash was called later inside CALLER_SETUP_ARG or setup_parameters_complex. This adds a splatkw instruction that is inserted before sends with ARGS_BLOCKARG and KW_SPLAT and without KW_SPLAT_MUT. This is not needed in the KW_SPLAT_MUT case, because then you know the value is a hash, and you don't need to call to_hash on it. The splatkw instruction checks whether the second to top block is a hash, and if not, replaces it with the value of calling to_hash on it (using rb_to_hash_type). As it is always before a send with ARGS_BLOCKARG and KW_SPLAT, second to top is the keyword splat, and top is the passed block.
2023-12-09Add a fudge factor to the GC compaction move up/down testsKJ Tsanaktsidis
There seems to be another manifestation of bug #20021, where some of the compaction tests are failing on i686 for unrelated PR's because of fake "live" references to moved objects on the machine stack. We _could_ solve this by counting how many objects are pinned during compaction, but doing that involves pushing down the mark & pin bitset merge into gc_compact_plane and out of gc_compact_page, which I thought was pretty ugly. Now that we've solved bug #20022 though, we're able to compact arbitrarily many objects with GC.verify_compaction_references, so the number of objects we're moving is now 50,000 instead of 500. Since that's now much larger than the number of objects likely to be pinned, I think it's safe enough to just add a fudge-factor to the tests. Any _other_ change in GC.verify_compaction_references that breaks compaction is now highly likely to break the assertion by more than 10 objects, since it's operating on so many more in the first place. [Bug #20021]
2023-12-08[PRISM] Fix `PM_CALL_NODE` assignmenteileencodes
This PR fixes ruby/prism#1963. Array and variable assignment was broken for call nodes. The change checks if the `method_id` is related to assignment and if is adds a `putnil`, `setn` and a `pop`. The incorrect instructions meant that in some cases (demonstrated in tests) the wrong value would be returned. I verified that this fixes the test mentioned in the issue (run: `RUBY_ISEQ_DUMP_DEBUG=prism make test/-ext-/st/test_numhash.rb`) Incorrect instructions: ``` "********* Ruby *************" == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(4,10)> 0000 putnil ( 4)[Li] 0001 putself 0002 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0005 putself 0006 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0009 putself 0010 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0013 setn 3 0015 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0018 pop 0019 leave "********* PRISM *************" == disasm: #<ISeq:<compiled>@<compiled>:3 (3,0)-(3,10)> 0000 putself ( 3)[Li] 0001 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0004 putself 0005 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0008 putself 0009 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0012 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0015 leave ``` Fixed instructions: ``` "********* Ruby *************" == disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(4,10)> 0000 putnil ( 4)[Li] 0001 putself 0002 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0005 putself 0006 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0009 putself 0010 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0013 setn 3 0015 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0018 pop 0019 leave "********* PRISM *************" == disasm: #<ISeq:<compiled>@<compiled>:3 (3,0)-(3,10)> 0000 putnil ( 3)[Li] 0001 putself 0002 send <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0005 putself 0006 send <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0009 putself 0010 send <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil 0013 setn 3 0015 send <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil 0018 pop 0019 leave ``` Fixes ruby/prism#1963
2023-12-08[Bug #19877] Flip-flop needs to be direct conditionNobuyoshi Nakada
2023-12-07YJIT: Fix on-stack ISEQ comparison for auto_compact (#9164)Takashi Kokubun
2023-12-07Support method calls inside `defined?`Aaron Patterson
This commit supports all kinds of method calls (including methods with parameters) inside `defined?` calls.
2023-12-07Free everything at shutdownAdam Hess
when the RUBY_FREE_ON_SHUTDOWN environment variable is set, manually free memory at shutdown. Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org> Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2023-12-07[PRISM] Account for multiple arguments when compiling ArgumentsNodeJemma Issroff
BreakNode, ReturnNode and NextNode all compile the ArgumentsNode directly, but we weren't accounting for multiple arguments. If there is more than one argument, we need to also emit a newarray instruction to put the arguments onto the stack
2023-12-07Prevent modification of splat array inside setup_parameters_complexJeremy Evans
For the following: ``` def f(*a); a end p f(*a, kw: 3) ``` `setup_parameters_complex` pushes `{kw: 3}` onto `a`. This worked fine back when `concatarray true` was used and `a` was already a copy. It does not work correctly with the optimization to switch to `concatarray false`. This duplicates the array on the callee side in such a case. This affects cases when passing a regular splat and a keyword splat (or literal keywords) in a method call, where the method does not accept keywords. This allocation could probably be avoided, but doing so would make `setup_parameters_complex` more complicated.
2023-12-07[PRISM] Stop catch table entries being deleted by the optimiserMatt Valentine-House
2023-12-07Support tracing of struct member accessor methodsJeremy Evans
This follows the same approach used for attr_reader/attr_writer in 2d98593bf54a37397c6e4886ccc7e3654c2eaf85, skipping the checking for tracing after the first call using the call cache, and clearing the call cache when tracing is turned on/off. Fixes [Bug #18886]
2023-12-07Support eval "return" at toplevelJeremy Evans
Since Ruby 2.4, `return` is supported at toplevel. This makes `eval "return"` also supported at toplevel. This mostly uses the same tests as direct `return` at toplevel, with a couple differences: `END {return if false}` is a SyntaxError, but `END {eval "return" if false}` is not an error since the eval is never executed. `END {return}` is a SyntaxError, but `END {eval "return"}` is a LocalJumpError. The following is a SyntaxError: ```ruby class X nil&defined?0--begin e=no_method_error(); return; 0;end end ``` However, the following is not, because the eval is never executed: ```ruby class X nil&defined?0--begin e=no_method_error(); eval "return"; 0;end end ``` Fixes [Bug #19779]
2023-12-07Fix keyword splat passing as regular argumentJeremy Evans
Since Ruby 3.0, Ruby has passed a keyword splat as a regular argument in the case of a call to a Ruby method where the method does not accept keyword arguments, if the method call does not contain an argument splat: ```ruby def self.f(obj) obj end def self.fs(*obj) obj[0] end h = {a: 1} f(**h).equal?(h) # Before: true; After: false fs(**h).equal?(h) # Before: true; After: false a = [] f(*a, **h).equal?(h) # Before and After: false fs(*a, **h).equal?(h) # Before and After: false ``` The fact that the behavior differs when passing an empty argument splat makes it obvious that something is not working the way it is intended. Ruby 2 always copied the keyword splat hash, and that is the expected behavior in Ruby 3. This bug is because of a missed check in setup_parameters_complex. If the keyword splat passed is not mutable, then it points to an existing object and not a new object, and therefore it must be copied. Now, there are 3 specs for the broken behavior of directly using the keyword splatted hash. Fix two specs and add a new version guard. Do not keep the specs for the broken behavior for earlier Ruby versions, in case this fix is backported. For the ruby2_keywords spec, just remove the related line, since that line is unrelated to what the spec is testing. Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2023-12-07[PRISM] Don't pop arguments on a return nodeJemma Issroff
Since ReturnNodes don't get popped, their arguments shouldn't either
2023-12-07Fix GC.verify_compaction_references not moving every objectKJ Tsanaktsidis
The intention of GC.verify_compaction_references is, I believe, to force every single movable object to be moved, so that it's possible to debug native extensions which not correctly updating their references to objects they mark as movable. To do this, it doubles the number of allocated pages for each size pool, and sorts the heap pages so that the free ones are swept first; thus, every object in an old page should be moved into a free slot in one of the new pages. This worked fine until movement of objects _between_ size pools during compaction was implemented. That causes some problems for verify_compaction_references: * We were doubling the number of pages in each size pool, but actually if some objects need to move into a _different_ pool, there's no guarantee that they'll be enough room in that one. * It's possible for the sweep & compact cursors to meet in one size pool before all the objects that want to move into that size pool from another are processed by the compaction. You can see these problems by changing some of the movement tests in test_gc_compact.rb to try and move e.g. 50,000 objects instead of 500; the test is not able to actually move all of the objects in a single compaction run. To fix this, we do two things in verify_compaction_references: * Firstly, we add enough pages to every size pool to make them the same size. This ensures that their compact cursors will all have space to move during compaction (even if that means empty pages are pointlessly compacted) * Then, we examine every object and determine where it _wants_ to be compacted into. We use this information to add additional pages to each size pool to handle all objects which should live there. With these two changes, we can move arbitrary amounts of objects into the correct size pool in a single call to verify_compaction_references. My _motivation_ for performing this work was to try and fix some test stability issues in test_gc_compact.rb. I now no longer think that we actually see this particular bug in rubyci.org, but I also think verify_compaction_references should do what it says on the tin, so it's worth keeping. [Bug #20022]
2023-12-07[PRISM] Rescue should set correct end_labelMatt Valentine-House
In order for a break inside the rescue to have the correct jump target
2023-12-07Warn `it` (#9152)Takashi Kokubun
https://bugs.ruby-lang.org/issues/18980
2023-12-06Copy encoding flags when copying a regex [Bug #20039]Dustin Brown
* :bug: Fixes [Bug #20039](https://bugs.ruby-lang.org/issues/20039) When a Regexp is initialized with another Regexp, we simply copy the properties from the original. However, the flags on the original were not being copied correctly. This caused an issue when the original had multibyte characters and was being compared with an ASCII string. Without the forced encoding flag (`KCODE_FIXED`) transferred on to the new Regexp, the comparison would fail. See the included test for an example. Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2023-12-07Fix SEGV caused by `GC::Profiler.raw_data` (#9122)Soutaro Matsumoto
2023-12-06[PRISM] Correct depth offset for block local varsMatt Valentine-House
Blocks should always look at their own local table first, even when defined inside an ensure/rescue or something else that uses depth offset. We can ignore the depth offset if we're doing local lookups inside a block