summaryrefslogtreecommitdiff
path: root/tool/ruby_vm
AgeCommit message (Collapse)Author
2025-09-10Explicitly declare VM instruction dependencies (#14509)Takashi Kokubun
instead of mutating RubyVM::Instructions and letting the order of `require` impact its behavior. Now that we have both RubyVM::TraceInstruction and RubyVM::ZJITInstruction, it feels too much of a tight coupling to rely on `require` to be ordered properly.
2025-09-10Rename VM instruction classes to singular names (#14507)Takashi Kokubun
2025-09-05ZJIT: Invalidate local variables on EP escape (#14448)Takashi Kokubun
2025-09-05Mark leaf defined instructions as leafAlan Wu
For example, `defined?(yield)` never calls a method, so it's leaf.
2025-09-05bare_instructions.rb: Remove unused always_leaf?Takashi Kokubun
83bc6ced920c51ffc3783b03f2e1c7f89f5c2fd5 was the last use of it.
2025-09-05insns.def: Drop unused leafness_of_check_intsTakashi Kokubun
It was used to let MJIT override the leafness of the instruction when it decides to remove check_ints for it. Now that MJIT is gone, nobody needs to "override" the leafness using this.
2025-09-04Drop unused tool/ruby_vm/views/_insn_sp_pc_dependency.erbTakashi Kokubun
MJIT was probably the last user of it. It's not even part of build dependencies now.
2025-05-02Add an include guard for insns_info.incAlan Wu
The JIT bindgens need this. Notes: Merged: https://github.com/ruby/ruby/pull/13229
2025-04-29Explain a missing USE_ZJIT check on rb_vm_max_insn_name_sizeTakashi Kokubun
2025-04-29ZJIT: Disable ZJIT instructions when USE_ZJIT is 0 (#13199)Takashi Kokubun
* ZJIT: Disable ZJIT instructions when USE_ZJIT is 0 * Test the order of ZJIT instructions * Add more jobs that disable JITs * Show instruction names in the message Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
2025-04-28ZJIT: Drop trace_zjit_* instructions (#13189)Takashi Kokubun
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
2025-04-18Disable ZJIT profiling at call-threshold ↵Takashi Kokubun
(https://github.com/Shopify/zjit/pull/99) * Disable ZJIT profiling at call-threshold * Stop referencing ZJIT instructions in codegen Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-04-18Add zjit_* instructions to profile the interpreter ↵Takashi Kokubun
(https://github.com/Shopify/zjit/pull/16) * Add zjit_* instructions to profile the interpreter * Rename FixnumPlus to FixnumAdd * Update a comment about Invalidate * Rename Guard to GuardType * Rename Invalidate to PatchPoint * Drop unneeded debug!() * Plan on profiling the types * Use the output of GuardType as type refined outputs Notes: Merged: https://github.com/ruby/ruby/pull/13131
2025-03-05Remove obsoleted insn_may_depend_on_sp_or_pc()Takashi Kokubun
which was for MJIT
2025-02-21Remove an unused empty directory [ci skip]Nobuyoshi Nakada
2025-02-21Remove useless shebang in non-executable files [ci skip]Nobuyoshi Nakada
2025-02-21Remove useless shebang in non-executable file [ci skip]Nobuyoshi Nakada
2025-02-20chmod -x tool/ruby_vm/models/bare_instructions.rbTakashi Kokubun
We run only tool/insns2vm.rb as the executable. It seems confusing to have an executable flag on this file.
2025-02-13[Feature #21116] Extract RJIT as a third-party gemNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/12740
2024-06-18Optimized forwarding callers and calleesAaron Patterson
This patch optimizes forwarding callers and callees. It only optimizes methods that only take `...` as their parameter, and then pass `...` to other calls. Calls it optimizes look like this: ```ruby def bar(a) = a def foo(...) = bar(...) # optimized foo(123) ``` ```ruby def bar(a) = a def foo(...) = bar(1, 2, ...) # optimized foo(123) ``` ```ruby def bar(*a) = a def foo(...) list = [1, 2] bar(*list, ...) # optimized end foo(123) ``` All variants of the above but using `super` are also optimized, including a bare super like this: ```ruby def foo(...) super end ``` This patch eliminates intermediate allocations made when calling methods that accept `...`. We can observe allocation elimination like this: ```ruby def m x = GC.stat(:total_allocated_objects) yield GC.stat(:total_allocated_objects) - x end def bar(a) = a def foo(...) = bar(...) def test m { foo(123) } end test p test # allocates 1 object on master, but 0 objects with this patch ``` ```ruby def bar(a, b:) = a + b def foo(...) = bar(...) def test m { foo(1, b: 2) } end test p test # allocates 2 objects on master, but 0 objects with this patch ``` How does it work? ----------------- This patch works by using a dynamic stack size when passing forwarded parameters to callees. The caller's info object (known as the "CI") contains the stack size of the parameters, so we pass the CI object itself as a parameter to the callee. When forwarding parameters, the forwarding ISeq uses the caller's CI to determine how much stack to copy, then copies the caller's stack before calling the callee. The CI at the forwarded call site is adjusted using information from the caller's CI. I think this description is kind of confusing, so let's walk through an example with code. ```ruby def delegatee(a, b) = a + b def delegator(...) delegatee(...) # CI2 (FORWARDING) end def caller delegator(1, 2) # CI1 (argc: 2) end ``` Before we call the delegator method, the stack looks like this: ``` Executing Line | Code | Stack ---------------+---------------------------------------+-------- 1| def delegatee(a, b) = a + b | self 2| | 1 3| def delegator(...) | 2 4| # | 5| delegatee(...) # CI2 (FORWARDING) | 6| end | 7| | 8| def caller | -> 9| delegator(1, 2) # CI1 (argc: 2) | 10| end | ``` The ISeq for `delegator` is tagged as "forwardable", so when `caller` calls in to `delegator`, it writes `CI1` on to the stack as a local variable for the `delegator` method. The `delegator` method has a special local called `...` that holds the caller's CI object. Here is the ISeq disasm fo `delegator`: ``` == disasm: #<ISeq:delegator@-e:1 (1,0)-(1,39)> local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 1] "..."@0 0000 putself ( 1)[LiCa] 0001 getlocal_WC_0 "..."@0 0003 send <calldata!mid:delegatee, argc:0, FCALL|FORWARDING>, nil 0006 leave [Re] ``` The local called `...` will contain the caller's CI: CI1. Here is the stack when we enter `delegator`: ``` Executing Line | Code | Stack ---------------+---------------------------------------+-------- 1| def delegatee(a, b) = a + b | self 2| | 1 3| def delegator(...) | 2 -> 4| # | CI1 (argc: 2) 5| delegatee(...) # CI2 (FORWARDING) | cref_or_me 6| end | specval 7| | type 8| def caller | 9| delegator(1, 2) # CI1 (argc: 2) | 10| end | ``` The CI at `delegatee` on line 5 is tagged as "FORWARDING", so it knows to memcopy the caller's stack before calling `delegatee`. In this case, it will memcopy self, 1, and 2 to the stack before calling `delegatee`. It knows how much memory to copy from the caller because `CI1` contains stack size information (argc: 2). Before executing the `send` instruction, we push `...` on the stack. The `send` instruction pops `...`, and because it is tagged with `FORWARDING`, it knows to memcopy (using the information in the CI it just popped): ``` == disasm: #<ISeq:delegator@-e:1 (1,0)-(1,39)> local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 1] "..."@0 0000 putself ( 1)[LiCa] 0001 getlocal_WC_0 "..."@0 0003 send <calldata!mid:delegatee, argc:0, FCALL|FORWARDING>, nil 0006 leave [Re] ``` Instruction 001 puts the caller's CI on the stack. `send` is tagged with FORWARDING, so it reads the CI and _copies_ the callers stack to this stack: ``` Executing Line | Code | Stack ---------------+---------------------------------------+-------- 1| def delegatee(a, b) = a + b | self 2| | 1 3| def delegator(...) | 2 4| # | CI1 (argc: 2) -> 5| delegatee(...) # CI2 (FORWARDING) | cref_or_me 6| end | specval 7| | type 8| def caller | self 9| delegator(1, 2) # CI1 (argc: 2) | 1 10| end | 2 ``` The "FORWARDING" call site combines information from CI1 with CI2 in order to support passing other values in addition to the `...` value, as well as perfectly forward splat args, kwargs, etc. Since we're able to copy the stack from `caller` in to `delegator`'s stack, we can avoid allocating objects. I want to do this to eliminate object allocations for delegate methods. My long term goal is to implement `Class#new` in Ruby and it uses `...`. I was able to implement `Class#new` in Ruby [here](https://github.com/ruby/ruby/pull/9289). If we adopt the technique in this patch, then we can optimize allocating objects that take keyword parameters for `initialize`. For example, this code will allocate 2 objects: one for `SomeObject`, and one for the kwargs: ```ruby SomeObject.new(foo: 1) ``` If we combine this technique, plus implement `Class#new` in Ruby, then we can reduce allocations for this common operation. Co-Authored-By: John Hawthorn <john@hawthorn.email> Co-Authored-By: Alan Wu <XrXr@users.noreply.github.com>
2024-03-03Drop support for old ERBNobuyoshi Nakada
2023-08-24Escape non-ascii characters in prelude C commentsNobuyoshi Nakada
Non-ASCII code are often warned by localized compilers. Notes: Merged: https://github.com/ruby/ruby/pull/8276
2023-08-16Move the PC regardless of the leaf flag (#8232)Takashi Kokubun
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com> Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
2023-07-27Clean up OPT_STACK_CACHING (#8132)Takashi Kokubun
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
2023-03-16Rename opes to operands on RubyVM::BaseInstructionJohn Hawthorn
Notes: Merged: https://github.com/ruby/ruby/pull/7523
2023-03-16Rename opes to operandsJohn Hawthorn
Co-authored-by: Aaron Patterson <aaron.patterson@gmail.com> Notes: Merged: https://github.com/ruby/ruby/pull/7523
2023-03-16Re-add RJIT::Instruction#opesJohn Hawthorn
Notes: Merged: https://github.com/ruby/ruby/pull/7523
2023-03-10RJIT: Simplify RubyVM::RJIT::InstructionTakashi Kokubun
2023-03-06s/MJIT/RJIT/Takashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/7462
2023-03-06Rename MJIT filenames to RJITTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/7462
2023-03-06Remove obsoleted mjit_sp_inc.inc.erbTakashi Kokubun
2023-03-05Decode trace insns properlyTakashi Kokubun
2023-03-05Move modules aroundTakashi Kokubun
2023-02-24Fix incorrect line numbers in GC hookPeter Zhu
If the previous instruction is not a leaf instruction, then the PC was incremented before the instruction was ran (meaning the currently executing instruction is actually the previous instruction), so we should not increment the PC otherwise we will calculate the source line for the next instruction. This bug can be reproduced in the following script: ``` require "objspace" ObjectSpace.trace_object_allocations_start a = 1.0 / 0.0 p [ObjectSpace.allocation_sourceline(a), ObjectSpace.allocation_sourcefile(a)] ``` Which outputs: [4, "test.rb"] This is incorrect because the object was allocated on line 10 and not line 4. The behaviour is correct when we use a leaf instruction (e.g. if we replaced `1.0 / 0.0` with `"hello"`), then the output is: [10, "test.rb"]. [Bug #19456] Notes: Merged: https://github.com/ruby/ruby/pull/7357
2023-02-24Fix RubyVM::CExpr#inspectPeter Zhu
@__LINE__ can be nil which causes the inspect method to fail. Notes: Merged: https://github.com/ruby/ruby/pull/7357
2022-12-22Polish the public docs for MJIT [ci skip]Takashi Kokubun
Now every private interface is cleaned up, and the public interface is documented.
2022-12-21Put RubyVM::MJIT::Compiler under ruby_vm directory (#6989)Takashi Kokubun
[Misc #19250] Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
2022-11-29MJIT: Rename mjit_compile_attr to mjit_sp_incTakashi Kokubun
There's no mjit_compile.inc, so no need to use this prefix anymore.
2022-10-13Revert "FreeBSD make uses the target under srcdir [ci skip]"Nobuyoshi Nakada
This reverts commit 751ffb276f658518c6fe06461a9d3d1c136c7d5d, which caused build failures on other platforms.
2022-10-13FreeBSD make uses the target under srcdir [ci skip]Nobuyoshi Nakada
2022-09-23mjit_c.rb doesn't need to be an erbTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/6418
2022-09-23Mix manual and auto-generated C APIsTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/6418
2022-09-23Bindgen macro with builtinTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/6418
2022-09-23Builtin RubyVM::MJIT::CTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/6418
2022-09-22Expand paths used for dumper.rbTakashi Kokubun
This seems to be needed on Samuel's environment
2022-09-18Introduce --basedir to insns2vm.rbTakashi Kokubun
and leverage that to preserve the directory structure under tool/ruby_vm/views
2022-09-18Revert "Preserve the directory structure under tool/ruby_vm/views"Takashi Kokubun
This reverts commit 62ec621f8c7457374d1f08aec97138ac1b7bdf2a. will revisit this once fixing non-MJIT targets
2022-09-18Preserve the directory structure under tool/ruby_vm/viewsTakashi Kokubun
for nested target directories
2022-09-18Demote mjit_instruction.rb from builtin to stdlibTakashi Kokubun
2022-09-05Fix warnings from private_constantTakashi Kokubun
`private_constant *constants` seems to be warned for some reason