[#120465] [Ruby master Bug#20998] rb_str_locktmp() changes flags of frozen strings and string literals — "Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>

Issue #20998 has been reported by Eregon (Benoit Daloze).

17 messages 2025/01/03

[#120469] [Ruby master Feature#21000] A way to avoid loading constant required by a type check — "Dan0042 (Daniel DeLorme) via ruby-core" <ruby-core@...>

Issue #21000 has been reported by Dan0042 (Daniel DeLorme).

13 messages 2025/01/03

[#120488] [Ruby master Feature#21005] Update the source location method to include line start/stop and column start/stop details — "bkuhlmann (Brooke Kuhlmann) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMDA1IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGJrdWhsbWFubiAoQnJvb2tlIEt1aGxt

16 messages 2025/01/05

[#120580] [Ruby master Bug#21021] "try to mark T_NONE object" with 3.4.1 — "Benoit_Tigeot (Benoit Tigeot) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMDIxIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IEJlbm9pdF9UaWdlb3QgKEJlbm9pdCBU

28 messages 2025/01/09

[#120601] [Ruby master Bug#21024] Ruby including <cstdbool> generates compilation warning with GCC 15, header is deprecated in C++17, — "jprokop (Jarek Prokop) via ruby-core" <ruby-core@...>

Issue #21024 has been reported by jprokop (Jarek Prokop).

7 messages 2025/01/10

[#120617] [Ruby master Feature#21028] Method for finding why an object isn't Ractor shareable — "tenderlovemaking (Aaron Patterson) via ruby-core" <ruby-core@...>

Issue #21028 has been reported by tenderlovemaking (Aaron Patterson).

7 messages 2025/01/11

[#120618] [Ruby master Bug#21029] Prism behavior for `defined? (;x)` differs — "qnighy (Masaki Hara) via ruby-core" <ruby-core@...>

Issue #21029 has been reported by qnighy (Masaki Hara).

12 messages 2025/01/12

[#120619] [Ruby master Bug#21030] Bug: #step with Range<ActiveSupport::Duration> behavior broken on Ruby 3.4.1 — "johnnyshields (Johnny Shields) via ruby-core" <ruby-core@...>

Issue #21030 has been reported by johnnyshields (Johnny Shields).

11 messages 2025/01/12

[#120628] [Ruby master Bug#21031] Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables — "ksss (Yuki Kurihara) via ruby-core" <ruby-core@...>

Issue #21031 has been reported by ksss (Yuki Kurihara).

8 messages 2025/01/13

[#120637] [Ruby master Bug#21032] `Module#autoload?` is slow when `$LOAD_PATH` contains a relative path — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

Issue #21032 has been reported by byroot (Jean Boussier).

9 messages 2025/01/13

[#120643] [Ruby master Feature#21033] Allow lambdas that don't access `self` to be Ractor shareable — "tenderlovemaking (Aaron Patterson) via ruby-core" <ruby-core@...>

Issue #21033 has been reported by tenderlovemaking (Aaron Patterson).

18 messages 2025/01/13

[#120650] [Ruby master Bug#21034] try to mark T_NONE object error after upgrading to 3.4.1 — "travisbell (Travis Bell) via ruby-core" <ruby-core@...>

Issue #21034 has been reported by travisbell (Travis Bell).

17 messages 2025/01/14

[#120657] [Ruby master Misc#21035] Clarify or redefine Module#autoload? and Module#const_defined? — "fxn (Xavier Noria) via ruby-core" <ruby-core@...>

Issue #21035 has been reported by fxn (Xavier Noria).

28 messages 2025/01/14

[#120694] [Ruby master Bug#21039] Ractor.make_shareable breaks block semantics (seeing updated captured variables) of existing blocks — "Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>

Issue #21039 has been reported by Eregon (Benoit Daloze).

26 messages 2025/01/15

[#120738] [Ruby master Bug#21048] [Prism] rescue in modifier form with condition behaves differently — "Earlopain (Earlopain _) via ruby-core" <ruby-core@...>

Issue #21048 has been reported by Earlopain (Earlopain _).

7 messages 2025/01/19

[#120774] [Ruby master Bug#21087] "try to mark T_NONE object" error in ActiveRecord with 3.4.1 upgrade — "p8 (Petrik de Heus) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMDg3IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHA4IChQZXRyaWsgZGUgSGV1cykuDQoN

6 messages 2025/01/23

[#120787] [Ruby master Bug#21088] TCPSocket.new raises Socket::ResolutionError instead of Errno::ECONNREFUSED for hosts defined in /etc/hosts — "dmlary (David Lary) via ruby-core" <ruby-core@...>

Issue #21088 has been reported by dmlary (David Lary).

9 messages 2025/01/24

[#120811] [Ruby master Bug#21095] Prefer `uname -n` over `hostname` in tests. — "ioquatix (Samuel Williams) via ruby-core" <ruby-core@...>

Issue #21095 has been reported by ioquatix (Samuel Williams).

10 messages 2025/01/28

[#120819] [Ruby master Bug#21097] `x = a rescue b in c` and `def f = a rescue b in c` parsed differently between parse.y and prism — "tompng (tomoya ishida) via ruby-core" <ruby-core@...>

Issue #21097 has been reported by tompng (tomoya ishida).

12 messages 2025/01/29

[#120840] [Ruby master Misc#21100] DevMeeting before or after RubyKaigi2025 — "ko1 (Koichi Sasada) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMTAwIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGtvMSAoS29pY2hpIFNhc2FkYSkuDQoN

9 messages 2025/01/30

[ruby-core:120749] [Ruby master Feature#21084] Declare objects have weak references

From: "peterzhu2118 (Peter Zhu) via ruby-core" <ruby-core@...>
Date: 2025-01-21 16:47:11 UTC
List: ruby-core #120749
Issue #21084 has been reported by peterzhu2118 (Peter Zhu).

----------------------------------------
Feature #21084: Declare objects have weak references
https://bugs.ruby-lang.org/issues/21084

* Author: peterzhu2118 (Peter Zhu)
* Status: Open
----------------------------------------
# Summary

The current way of marking weak references uses `rb_gc_mark_weak(VALUE *ptr=
)`. This presents challenges because Ruby's GC is incremental, meaning that=
 if the `ptr` changes (e.g. realloc'd or free'd), then we could have an inv=
alid memory access. This also overwrites `*ptr =3D Qundef` if `*ptr` is dea=
d, which prevents any cleanup to be run (e.g. freeing memory or deleting en=
tries from hash tables). This ticket proposes `rb_gc_declare_weak_reference=
s` which declares that an object has weak references and calls a cleanup fu=
nction after marking, allowing the object to clean up any memory for dead o=
bjects.

# Introduction

In [[Feature #19783]](https://bugs.ruby-lang.org/issues/19783), I introduce=
d an API allowing objects to mark weak references, the function signature l=
ooks like this:

```c
void rb_gc_mark_weak(VALUE *ptr);
```

`rb_gc_mark_weak` is called during the marking phase of the GC to specify t=
hat the memory at `ptr` holds a pointer to a Ruby object that is weakly ref=
erenced. `rb_gc_mark_weak` appends this pointer to a list that is processed=
 after the marking phase of the GC. If the object at `*ptr` is no longer al=
ive, then it overwrites the object reference with a special value (`*ptr =
=3D Qundef`).

However, this API resulted in two challenges:

1. Ruby's default GC is incremental, which means that the GC is not ran in =
one phase, but rather split into chunks of work that interleaves with Ruby =
execution. The `ptr` passed into `rb_gc_mark_weak` could be on the malloc h=
eap, and that memory could be realloc'd or even free'd. We had to use worka=
rounds such as `rb_gc_remove_weak` to ensure that there were no illegal mem=
ory accesses. This made `rb_gc_mark_weak` difficult to use, impacted runtim=
e performance, and increased memory usage.
2. When an object dies, `rb_gc_mark_weak` only overwites the reference with=
 `Qundef`. This means that if we want to do any cleanup (e.g. free a piece =
of memory or delete a hash table entry), we could not do that and had to de=
fer this process elsewhere (e.g. during marking or runtime).

# Declarative weak references

In this ticket, I'm proposing a new API for weak references. Instead of an =
object marking its weak references during the marking phase, the object dec=
lares that it has weak references using the `rb_gc_declare_weak_references`=
 function. This declaration occurs during runtime (e.g. after the object ha=
s been created) rather than during GC.

After an object declares that it has weak references, it will have its call=
back function called after marking as long as that object is alive. This ca=
llback function can then call a special function `rb_gc_handle_weak_referen=
ces_alive_p` to determine whether its references are alive. This will allow=
 the callback function to do whatever it wants on the object, allowing it t=
o perform any cleanup work it needs.

This significantly simplifies the code for `ObjectSpace::WeakMap` and `Obje=
ctSpace::WeakKeyMap` because it no longer needs to have the workarounds for=
 the limitations of `rb_gc_mark_weak`.

# Performance

The performance results below demonstrate that `ObjectSpace::WeakMap#[]=3D`=
 is now about 60% faster because the implementation has been simplified and=
 the number of allocations has been reduced. We can see that there is not a=
 significant impact on the performance of `ObjectSpace::WeakMap#[]`.

Base:

```
ObjectSpace::WeakMap#[]=3D
                          4.620M (=B1 6.4%) i/s  (216.44 ns/i) -     23.342=
M in   5.072149s
ObjectSpace::WeakMap#[]
                         30.967M (=B1 1.9%) i/s   (32.29 ns/i) -    154.998=
M in   5.007157s
```

Branch:

```
ObjectSpace::WeakMap#[]=3D
                          7.336M (=B1 2.8%) i/s  (136.31 ns/i) -     36.755=
M in   5.013983s
ObjectSpace::WeakMap#[]
                         30.902M (=B1 5.4%) i/s   (32.36 ns/i) -    155.901=
M in   5.064060s
```

Code:

```
require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "benchmark-ips"
end

wmap =3D ObjectSpace::WeakMap.new
key =3D Object.new
val =3D Object.new
wmap[key] =3D val

Benchmark.ips do |x|
  x.report("ObjectSpace::WeakMap#[]=3D") do |times|
    i =3D 0
    while i < times
      wmap[Object.new] =3D Object.new
      i +=3D 1
    end
  end

  x.report("ObjectSpace::WeakMap#[]") do |times|
    i =3D 0
    while i < times
      wmap[key]
      wmap[val] # does not exist
      i +=3D 1
    end
  end
end
```

# Alternative designs

Currently, `rb_gc_declare_weak_references` is designed to be an internal-on=
ly API. This allows us to assume the object types that call `rb_gc_declare_=
weak_references`. In the future, if we want to open up this API to third pa=
rties, we may want to change this function to something like:

```c
void rb_gc_add_cleaner(VALUE obj, void (*callback)(VALUE obj));
```

This will allow the third party to implement a custom `callback` that gets =
called after the marking phase of GC to clean up any dead references. I cho=
se not to implement this design because it is less efficient as we would ne=
ed to store a mapping from `obj` to `callback`, which requires extra memory.




--=20
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.rub=
y-lang.org/


In This Thread

Prev Next