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

1153 Коммитов

Автор SHA1 Сообщение Дата
Nobuyoshi Nakada 84d8dbe7a5 Enable redefinition check for rbinc methods 2024-02-12 11:51:06 -08:00
Peter Zhu d0b774cfb8 Remove null checks for xfree
xfree can handle null values, so we don't need to check it.
2024-01-19 10:25:02 -05:00
KJ Tsanaktsidis 807714447e Pass down "stack start" variables from closer to the top of the stack
This commit changes how stack extents are calculated for both the main
thread and other threads. Ruby uses the address of a local variable as
part of the calculation for machine stack extents:

* pthreads uses it as a lower-bound on the start of the stack, because
  glibc (and maybe other libcs) can store its own data on the stack
  before calling into user code on thread creation.
* win32 uses it as an argument to VirtualQuery, which gets the extent of
  the memory mapping which contains the variable

However, the local being used for this is actually too low (too close to
the leaf function call) in both the main thread case and the new thread
case.

In the main thread case, we have the `INIT_STACK` macro, which is used
for pthreads to set the `native_main_thread->stack_start` value. This
value is correctly captured at the very top level of the program (in
main.c). However, this is _not_ what's used to set the execution context
machine stack (`th->ec->machine_stack.stack_start`); that gets set as
part of a call to `ruby_thread_init_stack` in `Init_BareVM`, using the
address of a local variable allocated _inside_ `Init_BareVM`. This is
too low; we need to use a local allocated closer to the top of the
program.

In the new thread case, the lolcal is allocated inside
`native_thread_init_stack`, which is, again, too low.

In both cases, this means that we might have VALUEs lying outside the
bounds of `th->ec->machine.stack_{start,end}`, which won't be marked
correctly by the GC machinery.

To fix this,

* In the main thread case: We already have `INIT_STACK` at the right
  level, so just pass that local var to `ruby_thread_init_stack`.
* In the new thread case: Allocate the local one level above the call to
  `native_thread_init_stack` in `call_thread_start_func2`.

[Bug #20001]

fix
2024-01-19 09:55:12 +11:00
Jeremy Evans 5c823aa686
Support keyword splatting nil
nil is treated similarly to the empty hash in this case, passing
no keywords and not calling any conversion methods.

Fixes [Bug #20064]

Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-01-14 11:41:02 -08:00
KJ Tsanaktsidis 396e94666b Revert "Pass down "stack start" variables from closer to the top of the stack"
This reverts commit 4ba8f0dc99.
2024-01-12 17:58:54 +11:00
KJ Tsanaktsidis 4ba8f0dc99 Pass down "stack start" variables from closer to the top of the stack
The implementation of `native_thread_init_stack` for the various
threading models can use the address of a local variable as part of the
calculation of the machine stack extents:

* pthreads uses it as a lower-bound on the start of the stack, because
  glibc (and maybe other libcs) can store its own data on the stack
  before calling into user code on thread creation.
* win32 uses it as an argument to VirtualQuery, which gets the extent of
  the memory mapping which contains the variable

However, the local being used for this is actually allocated _inside_
the `native_thread_init_stack` frame; that means the caller might
allocate a VALUE on the stack that actually lies outside the bounds
stored in machine.stack_{start,end}.

A local variable from one level above the topmost frame that stores
VALUEs on the stack must be drilled down into the call to
`native_thread_init_stack` to be used in the calculation. This probably
doesn't _really_ matter for the win32 case (they'll be in the same
memory mapping so VirtualQuery should return the same thing), but
definitely could matter for the pthreads case.

[Bug #20001]
2024-01-12 17:29:48 +11:00
Peter Zhu 057df4379f Free environ when RUBY_FREE_AT_EXIT
The environ is malloc'd, so it gets reported as a memory leak. This
commit adds ruby_free_proctitle which frees it during shutdown when
RUBY_FREE_AT_EXIT is set.

    STACK OF 1 INSTANCE OF 'ROOT LEAK: <calloc in ruby_init_setproctitle>':
    5   dyld                                  0x18b7090e0 start + 2360
    4   ruby                                  0x10000e3a8 main + 100  main.c:58
    3   ruby                                  0x1000b4dfc ruby_options + 180  eval.c:121
    2   ruby                                  0x1001c5f70 ruby_process_options + 200  ruby.c:3014
    1   ruby                                  0x10035c9fc ruby_init_setproctitle + 76  setproctitle.c:105
    0   libsystem_malloc.dylib                0x18b8c7b78 _malloc_zone_calloc_instrumented_or_legacy + 100
2024-01-11 10:09:53 -05:00
Peter Zhu 46f7fac878 Free rb_native_thread of main thread
The rb_native_thread gets reported as a memory leak by the macOS leaks
tool:

    $ RUBY_FREE_AT_EXIT=1 leaks -q --atExit -- ./miniruby -e ""
    STACK OF 1 INSTANCE OF 'ROOT LEAK: <calloc in ruby_xcalloc_body>':
    6   dyld                                  0x1818a90e0 start + 2360
    5   miniruby                              0x104730128 main + 88  main.c:58
    4   miniruby                              0x1047d7710 ruby_init + 16  eval.c:102
    3   miniruby                              0x1047d757c ruby_setup + 112  eval.c:83
    2   miniruby                              0x104977278 Init_BareVM + 524  vm.c:4193
    1   miniruby                              0x1047f2478 ruby_xcalloc_body + 176  gc.c:12878
    0   libsystem_malloc.dylib                0x181a67b78 _malloc_zone_calloc_instrumented_or_legacy + 100
    ====
        1 (176 bytes) ROOT LEAK: <calloc in ruby_xcalloc_body 0x126604780> [176]
2024-01-03 15:41:08 -05:00
John Hawthorn f1b7424cbe FREE_AT_EXIT: Don't free main stack post-fork
When a forked process was started in a thread, this would result in a
double-free during the child process exit.

    RUBY_FREE_AT_EXIT=1 ./miniruby -e 'Thread.new { fork { } }.join; Process.waitpid'

This is because the main thread in the forked process was not the
initial VM thread, and the new thread's stack was freed as part of
objectspace iteration.

This change also allows rb_threadptr_root_fiber_release to run without
EC being available.
2023-12-22 18:07:22 -08:00
John Hawthorn 339978ef38 Free default_rand_key after freeing Ractors
Ractor's free iterates through its TLS keys so we need to keep this
memory available until after Ractors are freed.

Minimal reproduction:

    RUBY_FREE_AT_EXIT=1 ./miniruby -e rand
2023-12-22 18:07:22 -08:00
HParker 7ef90b3978 Correct free_on_exit env var to free_at_exit 2023-12-20 14:36:32 +09:00
Nobuyoshi Nakada 40fc9b070c
[DOC] No document for internal or debug methods 2023-12-18 20:17:45 +09:00
HParker 55326a915f Introduce --parser runtime flag
Introduce runtime flag for specifying the parser,

```
ruby --parser=prism
```

also update the description:

```
$ ruby --parser=prism --version
ruby 3.3.0dev (2023-12-08T04:47:14Z add-parser-runtime.. 0616384c9f) +PRISM [x86_64-darwin23]
```

[Bug #20044]
2023-12-15 13:42:19 -05:00
HParker 474b4c42f4 free ractors with ractor_free
Previously with RUBY_FREE_ON_EXIT, ractors where being xfree-ed which is incorrect since they are not xmalloced.
Instead we can free ractors with ractor free during shutdown. This change only effects main ractor freeing when RUBY_FREE_ON_EXIT is set.

Co-authored-by: John Hawthorn <john@hawthorn.email>
2023-12-15 10:31:15 -05:00
KJ Tsanaktsidis f8effa209a Change the semantics of rb_postponed_job_register
Our current implementation of rb_postponed_job_register suffers from
some safety issues that can lead to interpreter crashes (see bug #1991).
Essentially, the issue is that jobs can be called with the wrong
arguments.

We made two attempts to fix this whilst keeping the promised semantics,
but:
  * The first one involved masking/unmasking when flushing jobs, which
    was believed to be too expensive
  * The second one involved a lock-free, multi-producer, single-consumer
    ringbuffer, which was too complex

The critical insight behind this third solution is that essentially the
only user of these APIs are a) internal, or b) profiling gems.

For a), none of the usages actually require variable data; they will
work just fine with the preregistration interface.

For b), generally profiling gems only call a single callback with a
single piece of data (which is actually usually just zero) for the life
of the program. The ringbuffer is complex because it needs to support
multi-word inserts of job & data (which can't be atomic); but nobody
actually even needs that functionality, really.

So, this comit:
  * Introduces a pre-registration API for jobs, with a GVL-requiring
    rb_postponed_job_prereigster, which returns a handle which can be
    used with an async-signal-safe rb_postponed_job_trigger.
  * Deprecates rb_postponed_job_register (and re-implements it on top of
    the preregister function for compatability)
  * Moves all the internal usages of postponed job register
    pre-registration
2023-12-10 15:00:37 +09:00
Koichi Sasada 352a885a0f Thread specific storage APIs
This patch introduces thread specific storage APIs
for tools which use `rb_internal_thread_event_hook` APIs.

* `rb_internal_thread_specific_key_create()` to create a tool specific
  thread local storage key and allocate the storage if not available.
* `rb_internal_thread_specific_set()` sets a data to thread and tool
  specific storage.
* `rb_internal_thread_specific_get()` gets a data in thread and tool
  specific storage.

Note that `rb_internal_thread_specific_get|set(thread_val, key)`
can be called without GVL and safe for async signal and safe for
multi-threading (native threads). So you can call it in any internal
thread event hooks. Further more you can call it from other native
threads. Of course `thread_val` should be living while accessing the
data from this function.

Note that you should not forget to clean up the set data.
2023-12-08 13:16:19 +09:00
Adam Hess 6816e8efcf Free everything at shutdown
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 15:52:35 -05:00
Alan Wu 195dbf241f Fix potential compaction issue in env_copy()
`src_ep[VM_ENV_DATA_INDEX_ME_CREF]` was read out and held without
marking across the allocation in vm_env_new(). In case vm_env_new() ran
compaction, an invalid reference could have been written into
`copied_env`.

It might've been hard to actually produce a crash with this issue due to
the pinning marking of the field in rb_execution_context_mark().
2023-12-07 11:16:12 -05:00
Alan Wu 050806f425 Add missing write barrier to env_copy()
Previously, the following crashed with
`vm_assert_env:imemo_type_p(obj, imemo_env)` due to missing a missing
WB:

    o = Object.new
    def o.foo(n)
      freeze

      GC.stress = 1

      # inflate block nesting get an imemo_env for each level
      n.tap do |i|
        i.tap do |local|
          return Ractor.make_shareable(-> do
            local + i + n
          end)
        end
      end
    ensure
      GC.stress = false
      GC.verify_internal_consistency
    end

    p o.foo(1)[]

By the time the recursive env_copy() call returns, `copied_env` could
have aged or have turned greyed, so we need a WB for the
`ep[VM_ENV_DATA_INDEX_SPECVAL]` assignment which adds an edge.

Fix: 674eb7df7f
2023-12-07 11:16:12 -05:00
HParker b8b319dd1a Revert "allow enabling Prism via flag or env var"
This reverts commit 9b76c7fc89.
2023-12-06 10:21:12 +09:00
HParker 9b76c7fc89 allow enabling Prism via flag or env var
Enable Prism using either --prism

    ruby --prism test.rb

or via env var

    RUBY_PRISM=1 ruby test.rb
2023-12-05 12:17:14 -05:00
Peter Zhu 674eb7df7f Make env_copy compaction safe
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).
2023-12-05 08:42:25 -05:00
Alan Wu 85092ecd6f Fix imemo_env corruption under auto compaction
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.
2023-11-30 11:59:32 -05:00
Nobuyoshi Nakada 8f1ec6e171
Adjust spaces [ci skip] 2023-11-15 19:05:10 +09:00
Nobuyoshi Nakada 7998dcdedc
Remove invariant condition
The `while` loop condition dereferences `cfp` and no `break` there,
`cfp` cannot be NULL just after the loop.
2023-11-15 17:52:40 +09:00
Yuta Saito 50a5b76dec [wasm] allocate Asyncify setjmp buffer in heap
`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.
2023-11-13 19:17:16 +09:00
Aaron Patterson 84e4453436 Use a functional red-black tree for indexing the shapes
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.
2023-10-24 10:52:06 -07:00
Takashi Kokubun 62c1d8187b Partly revert a change in #8705
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)
2023-10-19 17:52:03 -07:00
Takashi Kokubun 985370406d Call rb_jit_cont_init() even earlier
To fix https://github.com/ruby/ruby/actions/runs/6581593578/job/17881779994
2023-10-19 17:12:09 -07:00
Takashi Kokubun 6beb09c2c9
YJIT: Add RubyVM::YJIT.enable (#8705) 2023-10-19 10:54:35 -07:00
Maxime Chevalier-Boisvert b2e1ddffa5
YJIT: port call threshold logic from Rust to C for performance (#8628)
* 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>
2023-10-12 10:05:34 -04:00
Koichi Sasada be1bbd5b7d M:N thread scheduler for Ractors
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]
2023-10-12 14:47:01 +09:00
Maxime Chevalier-Boisvert ea491802fa
YJIT: add heuristic to avoid compiling cold ISEQs (#8522)
* 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>
2023-10-03 17:45:46 -04:00
Aaron Patterson d3574c117a Move IO#readline to Ruby
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]
2023-09-28 10:43:45 -07:00
yui-knk 74c6781153 Change RNode structure from union to struct
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.
2023-09-28 11:58:10 +09:00
Nobuyoshi Nakada ac244938e8 Dump backtraces to an arbitrary stream 2023-09-25 22:57:28 +09:00
Nobuyoshi Nakada 6473903082
[Bug #18257] Register the class path of FrozenCore to mark
ICLASS does not have the path usually, so it needs to be registered
separately.
2023-09-19 14:09:53 +09:00
Nobuyoshi Nakada 4634405f7c
Stop exposing FrozenCore in headers
Revert commit "Directly allocate FrozenCore as an ICLASS",
813a5f4fc4.
2023-09-19 14:08:05 +09:00
Matt Valentine-House 322548180d Prevent rb_gc_mark_values from pinning objects
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
2023-08-31 19:31:18 +01:00
Alan Wu ebb9034710 Remove cfp parameter from hook_before_rewind()
It's only used once, and it has to equal `ec->cfp`, so just use that.
2023-08-24 17:37:07 -04:00
Alan Wu 05e827427f Make cfp constant and use it more in vm_exec_handle_exception()
For writing THROW_DATA_VAL, being able to see that it's writing to the
same frame after modifying PC and SP is nice.
2023-08-24 17:37:07 -04:00
Jean Boussier cedb333063 Stop incrementing `jit_entry_calls` once threshold is hit
Otherwise the ISeq page will constantly be written
into preventing it from being shared.
2023-08-23 20:20:17 +02:00
Takashi Kokubun cd8d20cd1f
YJIT: Compile exception handlers (#8171)
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
2023-08-08 16:06:22 -07:00
Nobuyoshi Nakada 694d99dda2
Share duplicate code between Wasm and the others 2023-08-08 08:48:53 +09:00
Nobuyoshi Nakada ef5b1d19c1
Turn `jit_exec` and `jit_compile` into macros if disabled 2023-08-06 18:45:40 +09:00
Takashi Kokubun e176f84138 Just suppress a warning for non-Emscripten Wasm build
Revert "Revert "Skip calling jit_exec on Wasm""

This reverts commit 2e94610f70.

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.
2023-08-04 20:50:46 -07:00
Nobuyoshi Nakada 2e94610f70 Revert "Skip calling jit_exec on Wasm"
This reverts commit e80752f9bb.

RJIT and YJIT are never enabled on Wasm.  When both are disabled,
`jit_exec` is defined to return `Qundef` constantly, and is optimized
away.
2023-08-05 12:12:42 +09:00
Takashi Kokubun e80752f9bb Skip calling jit_exec on Wasm
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.
2023-08-04 15:39:02 -07:00
Takashi Kokubun 44b19b01e2 Remove an obsoleted initialization from Wasm 2023-07-27 17:36:07 -07:00
Takashi Kokubun 8c7cf2de98 Remove an unused argument in vm_exec_core 2023-07-27 17:31:27 -07:00