aboutsummaryrefslogtreecommitdiffstats
path: root/vm.c
Commit message (Collapse)AuthorAgeFilesLines
* Revert "allow enabling Prism via flag or env var"HParker2023-12-061-7/+0
| | | | This reverts commit 9b76c7fc89460ed8e9be40e4037c1d68395c0f6d.
* allow enabling Prism via flag or env varHParker2023-12-051-0/+7
| | | | | | | | | | Enable Prism using either --prism ruby --prism test.rb or via env var RUBY_PRISM=1 ruby test.rb
* Make env_copy compaction safePeter Zhu2023-12-051-5/+9
| | | | | | | | | | | | | | | The original order of events is: 1. Allocate env_body. 2. Fill env_body using elements in src_env, and it performs operations that can trigger a GC. 3. Create the copied_env using vm_env_new. However, if GC compaction runs during step 2, then copied_env would not have yet been created and objects on env_body could move but it would not be reference updated. This commit changes the the order to be (1), (3), (2).
* Fix imemo_env corruption under auto compactionAlan Wu2023-11-301-10/+17
| | | | | | | | | | | | | Previously, vm_make_env_each() did: 1. ALLOC env_body 2. Copy locals into env_body 3. Allocate imemo_env 4. Set up imemo_env with env_body If compaction runs during (3), locals copied to env_body could be moved and the imemo_env could end up with invalid references. Move (2) down so it reads references after potential movement.
* Adjust spaces [ci skip]Nobuyoshi Nakada2023-11-151-7/+7
|
* Remove invariant conditionNobuyoshi Nakada2023-11-151-6/+1
| | | | | The `while` loop condition dereferences `cfp` and no `break` there, `cfp` cannot be NULL just after the loop.
* [wasm] allocate Asyncify setjmp buffer in heapYuta Saito2023-11-131-1/+1
| | | | | | | | | | | | `rb_jmpbuf_t` type is considerably large due to inline-allocated Asyncify buffer, and it leads to stack overflow even with small number of C-method call frames. This commit allocates the Asyncify buffer used by `rb_wasm_setjmp` in heap to mitigate the issue. This patch introduces a new type `rb_vm_tag_jmpbuf_t` to abstract the representation of a jump buffer, and init/deinit hook points to manage lifetime of the buffer. These changes are effectively NFC for non-wasm platforms.
* Use a functional red-black tree for indexing the shapesAaron Patterson2023-10-241-1/+7
| | | | | | | | | | | | | | | | | | | | | | | This is an experimental commit that uses a functional red-black tree to create an index of the ancestor shapes. It uses an Okasaki style functional red black tree: https://www.cs.tufts.edu/comp/150FP/archive/chris-okasaki/redblack99.pdf This tree is advantageous because: * It offers O(n log n) insertions and O(n log n) lookups. * It shares memory with previous "versions" of the tree When we insert a node in the tree, only the parts of the tree that need to be rebalanced are newly allocated. Parts of the tree that don't need to be rebalanced are not reallocated, so "new trees" are able to share memory with old trees. This is in contrast to a sorted set where we would have to duplicate the set, and also resort the set on each insertion. I've added a new stat to RubyVM.stat so we can understand how the red black tree increases.
* Partly revert a change in #8705Takashi Kokubun2023-10-191-2/+3
| | | | | | | | | | | Having this variable actually helps the performance of non-JITed calls. ----- ----------- ---------- ---------- ---------- ------------- ------------ bench before (ms) stddev (%) after (ms) stddev (%) after 1st itr before/after fib 241.9 0.5 225.4 1.0 1.06 1.07 ----- ----------- ---------- ---------- ---------- ------------- ------------ (benchmarked with --yjit-cold-threshold=0)
* Call rb_jit_cont_init() even earlierTakashi Kokubun2023-10-191-0/+1
| | | | To fix https://github.com/ruby/ruby/actions/runs/6581593578/job/17881779994
* YJIT: Add RubyVM::YJIT.enable (#8705)Takashi Kokubun2023-10-191-4/+3
|
* YJIT: port call threshold logic from Rust to C for performance (#8628)Maxime Chevalier-Boisvert2023-10-121-5/+46
| | | | | | | | | | | | | | | | | * Port call threshold logic from Rust to C for performance * Prefix global/field names with yjit_ * Fix linker error * Fix preprocessor condition for rb_yjit_threshold_hit * Fix third linker issue * Exclude yjit_calls_at_interv from RJIT bindgen --------- Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
* M:N thread scheduler for RactorsKoichi Sasada2023-10-121-6/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch introduce M:N thread scheduler for Ractor system. In general, M:N thread scheduler employs N native threads (OS threads) to manage M user-level threads (Ruby threads in this case). On the Ruby interpreter, 1 native thread is provided for 1 Ractor and all Ruby threads are managed by the native thread. From Ruby 1.9, the interpreter uses 1:1 thread scheduler which means 1 Ruby thread has 1 native thread. M:N scheduler change this strategy. Because of compatibility issue (and stableness issue of the implementation) main Ractor doesn't use M:N scheduler on default. On the other words, threads on the main Ractor will be managed with 1:1 thread scheduler. There are additional settings by environment variables: `RUBY_MN_THREADS=1` enables M:N thread scheduler on the main ractor. Note that non-main ractors use the M:N scheduler without this configuration. With this configuration, single ractor applications run threads on M:1 thread scheduler (green threads, user-level threads). `RUBY_MAX_CPU=n` specifies maximum number of native threads for M:N scheduler (default: 8). This patch will be reverted soon if non-easy issues are found. [Bug #19842]
* YJIT: add heuristic to avoid compiling cold ISEQs (#8522)Maxime Chevalier-Boisvert2023-10-031-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * YJIT: Add counter to measure how often we compile "cold" ISEQs (#535) Fix counter name in DEFAULT_COUNTERS YJIT: add --yjit-cold-threshold, don't compile cold ISEQs YJIT: increase default cold threshold to 200_000 Remove rb_yjit_call_threshold() Remove conflict markers Fix compilation errors Threshold 1 should compile immediately Debug deadlock issue with test_ractor Fix call threshold issue with tests * Revert exception threshold logic. Document option in yjid.md * (void) for 0 parameter functions in C99 * Rename iseq_entry_cold => cold_iseq_entry * Document --yjit-cold-threshold in ruby.c * Update doc/yjit/yjit.md Co-authored-by: Jean byroot Boussier <jean.boussier+github@shopify.com> * Shorten help string to appease test * Address bug found by Kokubun. Reorder logic. --------- Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> Co-authored-by: Jean byroot Boussier <jean.boussier+github@shopify.com>
* Move IO#readline to RubyAaron Patterson2023-09-281-0/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit moves IO#readline to Ruby. In order to call C functions, keyword arguments must be converted to hashes. Prior to this commit, code like `io.readline(chomp: true)` would allocate a hash. This commits moves the keyword "denaturing" to Ruby, allowing us to send positional arguments to the C API and avoiding the hash allocation. Here is an allocation benchmark for the method: ``` x = GC.stat(:total_allocated_objects) File.open("/usr/share/dict/words") do |f| f.readline(chomp: true) until f.eof? end p ALLOCATIONS: GC.stat(:total_allocated_objects) - x ``` Before this commit, the output was this: ``` $ make run ./miniruby -I./lib -I. -I.ext/common -r./arm64-darwin22-fake ./test.rb {:ALLOCATIONS=>707939} ``` Now it is this: ``` $ make run ./miniruby -I./lib -I. -I.ext/common -r./arm64-darwin22-fake ./test.rb {:ALLOCATIONS=>471962} ``` [Bug #19890] [ruby-core:114803]
* Change RNode structure from union to structyui-knk2023-09-281-3/+7
| | | | | | | | | | | | | | | | | | | | | | | All kind of AST nodes use same struct RNode, which has u1, u2, u3 union members for holding different kind of data. This has two problems. 1. Low flexibility of data structure Some nodes, for example NODE_TRUE, don’t use u1, u2, u3. On the other hand, NODE_OP_ASGN2 needs more than three union members. However they use same structure definition, need to allocate three union members for NODE_TRUE and need to separate NODE_OP_ASGN2 into another node. This change removes the restriction so make it possible to change data structure by each node type. 2. No compile time check for union member access It’s developer’s responsibility for using correct member for each node type when it’s union. This change clarifies which node has which type of fields and enables compile time check. This commit also changes node_buffer_elem_struct buf management to handle different size data with alignment.
* Dump backtraces to an arbitrary streamNobuyoshi Nakada2023-09-251-1/+1
|
* [Bug #18257] Register the class path of FrozenCore to markNobuyoshi Nakada2023-09-191-0/+1
| | | | | ICLASS does not have the path usually, so it needs to be registered separately.
* Stop exposing FrozenCore in headersNobuyoshi Nakada2023-09-191-1/+4
| | | | | Revert commit "Directly allocate FrozenCore as an ICLASS", 813a5f4fc46a24ca1695d23c159250b9e1080ac7.
* Prevent rb_gc_mark_values from pinning objectsMatt Valentine-House2023-08-311-0/+2
| | | | | | | | | | | | | | | | This is an internal only function not exposed to the C extension API. It's only use so far is from rb_vm_mark, where it's used to mark the values in the vm->trap_list.cmd array. There shouldn't be any reason why these cannot move. This commit allows them to move by updating their references during the reference updating step of compaction. To do this we've introduced another internal function rb_gc_update_values as a partner to rb_gc_mark_values. This allows us to refactor rb_gc_mark_values to not pin
* Remove cfp parameter from hook_before_rewind()Alan Wu2023-08-241-5/+4
| | | | It's only used once, and it has to equal `ec->cfp`, so just use that.
* Make cfp constant and use it more in vm_exec_handle_exception()Alan Wu2023-08-241-4/+3
| | | | | For writing THROW_DATA_VAL, being able to see that it's writing to the same frame after modifying PC and SP is nice.
* Stop incrementing `jit_entry_calls` once threshold is hitJean Boussier2023-08-231-14/+10
| | | | | Otherwise the ISeq page will constantly be written into preventing it from being shared.
* YJIT: Compile exception handlers (#8171)Takashi Kokubun2023-08-081-23/+72
| | | Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
* Share duplicate code between Wasm and the othersNobuyoshi Nakada2023-08-081-63/+49
|
* Turn `jit_exec` and `jit_compile` into macros if disabledNobuyoshi Nakada2023-08-061-2/+2
|
* Just suppress a warning for non-Emscripten Wasm buildTakashi Kokubun2023-08-041-4/+2
| | | | | | | | | | Revert "Revert "Skip calling jit_exec on Wasm"" This reverts commit 2e94610f70baca4af004202f288a6b5dd10889ca. It's not about whether it's optimized away or not. I just don't want to leave and maintain the callsite (e.g. signature) in the path where YJIT is never built.
* Revert "Skip calling jit_exec on Wasm"Nobuyoshi Nakada2023-08-051-1/+3
| | | | | | | | This reverts commit e80752f9bbc5228dba3066cd95a81e2e496bd9d7. RJIT and YJIT are never enabled on Wasm. When both are disabled, `jit_exec` is defined to return `Qundef` constantly, and is optimized away.
* Skip calling jit_exec on WasmTakashi Kokubun2023-08-041-3/+1
| | | | | | | | We often break Wasm build when we modify how jit_exec works. I'm planning to modify it again soon. We actually don't support running Ruby JIT on Wasm, so it doesn't seem worth the maintenance effort.
* Remove an obsoleted initialization from WasmTakashi Kokubun2023-07-271-1/+1
|
* Remove an unused argument in vm_exec_coreTakashi Kokubun2023-07-271-12/+8
|
* Clean up OPT_STACK_CACHING (#8132)Takashi Kokubun2023-07-271-11/+0
|
* Adjust brace nestingNobuyoshi Nakada2023-07-251-6/+4
|
* Remove __bp__ and speed-up bmethod calls (#8060)Alan Wu2023-07-171-9/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Remove rb_control_frame_t::__bp__ and optimize bmethod calls This commit removes the __bp__ field from rb_control_frame_t. It was introduced to help MJIT, but since MJIT was replaced by RJIT, we can use vm_base_ptr() to compute it from the SP of the previous control frame instead. Removing the field avoids needing to set it up when pushing new frames. Simply removing __bp__ would cause crashes since RJIT and YJIT used a slightly different stack layout for bmethod calls than the interpreter. At the moment of the call, the two layouts looked as follows: ┌────────────┐ ┌────────────┐ │ frame_base │ │ frame_base │ ├────────────┤ ├────────────┤ │ ... │ │ ... │ ├────────────┤ ├────────────┤ │ args │ │ args │ ├────────────┤ └────────────┘<─prev_frame_sp │ receiver │ prev_frame_sp─>└────────────┘ RJIT & YJIT interpreter Essentially, vm_base_ptr() needs to compute the address to frame_base given prev_frame_sp in the diagrams. The presence of the receiver created an off-by-one situation. Make the interpreter use the layout the JITs use for iseq-to-iseq bmethod calls. Doing so removes unnecessary argument shifting and vm_exec_core() re-entry from the interpreter, yielding a speed improvement visible through `benchmark/vm_defined_method.yml`: patched: 7578743.1 i/s master: 4796596.3 i/s - 1.58x slower C-to-iseq bmethod calls now store one more VALUE than before, but that should have negligible impact on overall performance. Note that re-entering vm_exec_core() used to be necessary for firing TracePoint events, but that's no longer the case since 9121e57a5f50bc91bae48b3b91edb283bf96cb6b. Closes ruby/ruby#6428
* YJIT: refactoring to allow for fancier call threshold logic (#8078)Maxime Chevalier-Boisvert2023-07-171-1/+6
| | | | | | | | | | | | | * YJIT: refactoring to allow for fancier call threshold logic * Avoid potentially compiling functions multiple times. * Update vm.c Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> --------- Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
* macos: symbols for `rb_execution_context_t` should be internalNobuyoshi Nakada2023-07-081-10/+11
|
* Replace parser & node compile_option from Hash to bit fieldyui-knk2023-06-171-1/+2
| | | | This commit reduces dependency to CRuby object.
* Directly allocate FrozenCore as an ICLASSPeter Zhu2023-06-141-4/+1
| | | | | It's a bad idea to overwrite the flags as the garbage collector may have set other flags.
* [Feature #19719] Universal Parseryui-knk2023-06-121-1/+1
| | | | | | | | | Introduce Universal Parser mode for the parser. This commit includes these changes: * Introduce `UNIVERSAL_PARSER` macro. All of CRuby related functions are passed via `struct rb_parser_config_struct` when this macro is enabled. * Add CI task with 'cppflags=-DUNIVERSAL_PARSER' for ubuntu.
* [Bug #19597] Freeze script nameNobuyoshi Nakada2023-05-101-1/+2
|
* [Bug #19592] Fix ext/Setup supportAlan Wu2023-04-261-3/+0
| | | | | | | | | | | | | | After [1], using ext/Setup to link some, but not all extensions failed during linking. I did not know about this option, and had assumed that only `--with-static-linked-ext` builds can include statically linked extensions. Include the support code for statically linked extensions in all configurations like before [1]. Initialize the table lazily to minimize footprint on builds that have no statically linked extensions. [1]: 790cf4b6d0475614afb127b416e87cfa39044d67 "Fix autoload status of statically linked extensions"
* Generalize cfunc large array splat fix to fix many additional cases raising ↵Jeremy Evans2023-04-251-2/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | SystemStackError Originally, when 2e7bceb34ea858649e1f975a934ce1894d1f06a6 fixed cfuncs to no longer use the VM stack for large array splats, it was thought to have fully fixed Bug #4040, since the issue was fixed for methods defined in Ruby (iseqs) back in Ruby 2.2. After additional research, I determined that same issue affects almost all types of method calls, not just iseq and cfunc calls. There were two main types of remaining issues, important cases (where large array splat should work) and pedantic cases (where large array splat raised SystemStackError instead of ArgumentError). Important cases: ```ruby define_method(:a){|*a|} a(*1380888.times) def b(*a); end send(:b, *1380888.times) :b.to_proc.call(self, *1380888.times) def d; yield(*1380888.times) end d(&method(:b)) def self.method_missing(*a); end not_a_method(*1380888.times) ``` Pedantic cases: ```ruby def a; end a(*1380888.times) def b(_); end b(*1380888.times) def c(_=nil); end c(*1380888.times) c = Class.new do attr_accessor :a alias b a= end.new c.a(*1380888.times) c.b(*1380888.times) c = Struct.new(:a) do alias b a= end.new c.a(*1380888.times) c.b(*1380888.times) ``` This patch fixes all usage of CALLER_SETUP_ARG with splatting a large number of arguments, and required similar fixes to use a temporary hidden array in three other cases where the VM would use the VM stack for handling a large number of arguments. However, it is possible there may be additional cases where splatting a large number of arguments still causes a SystemStackError. This has a measurable performance impact, as it requires additional checks for a large number of arguments in many additional cases. This change is fairly invasive, as there were many different VM functions that needed to be modified to support this. To avoid too much API change, I modified struct rb_calling_info to add a heap_argv member for storing the array, so I would not have to thread it through many functions. This struct is always stack allocated, which helps ensure sure GC doesn't collect it early. Because of how invasive the changes are, and how rarely large arrays are actually splatted in Ruby code, the existing test/spec suites are not great at testing for correct behavior. To try to find and fix all issues, I tested this in CI with VM_ARGC_STACK_MAX to -1, ensuring that a temporary array is used for all array splat method calls. This was very helpful in finding breaking cases, especially ones involving flagged keyword hashes. Fixes [Bug #4040] Co-authored-by: Jimmy Miller <jimmy.miller@shopify.com>
* Emit special instruction for array literal + .(hash|min|max)Aaron Patterson2023-04-181-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit introduces a new instruction `opt_newarray_send` which is used when there is an array literal followed by either the `hash`, `min`, or `max` method. ``` [a, b, c].hash ``` Will emit an `opt_newarray_send` instruction. This instruction falls back to a method call if the "interested" method has been monkey patched. Here are some examples of the instructions generated: ``` $ ./miniruby --dump=insns -e '[@a, @b].max' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE) 0000 getinstancevariable :@a, <is:0> ( 1)[Li] 0003 getinstancevariable :@b, <is:1> 0006 opt_newarray_send 2, :max 0009 leave $ ./miniruby --dump=insns -e '[@a, @b].min' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE) 0000 getinstancevariable :@a, <is:0> ( 1)[Li] 0003 getinstancevariable :@b, <is:1> 0006 opt_newarray_send 2, :min 0009 leave $ ./miniruby --dump=insns -e '[@a, @b].hash' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,13)> (catch: FALSE) 0000 getinstancevariable :@a, <is:0> ( 1)[Li] 0003 getinstancevariable :@b, <is:1> 0006 opt_newarray_send 2, :hash 0009 leave ``` [Feature #18897] [ruby-core:109147] Co-authored-by: John Hawthorn <jhawthorn@github.com>
* Adjust function style [ci skip]Nobuyoshi Nakada2023-04-151-1/+2
|
* Speed up rebuilding the loaded feature indexJeremy Evans2023-04-131-0/+2
| | | | | | | | | | | | | | | Rebuilding the loaded feature index slowed down with the bug fix for #17885 in 79a4484a072e9769b603e7b4fbdb15b1d7eccb15. The slowdown was extreme if realpath emulation was used, but even when not emulated, it could be about 10x slower. This adds loaded_features_realpath_map to rb_vm_struct. This is a hidden hash mapping loaded feature paths to realpaths. When rebuilding the loaded feature index, look at this hash to get cached realpath values, and skip calling rb_check_realpath if a cached value is found. Fixes [Bug #19246]
* Pull the shape tree out of the vm objectMatt Valentine-House2023-04-061-15/+2
|
* `nt->serial` for `RUBY_DEBUG_LOG`Koichi Sasada2023-03-311-0/+3
| | | | | | Show native thread's serial on `RUBY_DEBUG_LOG`. `nt->serial` is also stored into `ruby_nt_serial` if the compiler supports `RB_THREAD_LOCAL_SPECIFIER`.
* YJIT: Leave cfp->pc uninitialized for VM_FRAME_MAGIC_CFUNCAlan Wu2023-03-291-1/+1
| | | | | | | | | C function frames don't need to use the VM-specific pc field to run properly. When pushing a control frame from output code, save one instruction by leaving the field uninitialized. Fix-up rb_vm_svar_lep(), which is used while setting local variables via Regexp#=~. Use cfp->iseq as a secondary signal so it can stop assuming that all CFUNC frames always have zero pc's.
* YJIT: Add `--yjit-pause` and `RubyVM::YJIT.resume` (#7609)Maxime Chevalier-Boisvert2023-03-281-1/+1
| | | | | | | | | | | | | | | | | | | * YJIT: Add --yjit-pause and RubyVM::YJIT.resume This allows booting YJIT in a suspended state. We chose to add a new command line option as opposed to simply allowing YJIT.resume to work without any command line option because it allows for combining with YJIT tuning command line options. It also simpifies implementation. Paired with Kokubun and Maxime. * Update yjit.rb Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com> --------- Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
* Fix shape allocation limitsAaron Patterson2023-03-221-2/+2
| | | | | | | | | | We can only allocate enough shapes to fit in the shape buffer. MAX_SHAPE_ID was based on the theoretical maximum number of shapes we could have, not on the amount of memory we can actually consume. This commit changes the MAX_SHAPE_ID to be based on the amount of memory we're allowed to consume. Co-Authored-By: Jemma Issroff <jemmaissroff@gmail.com>