Allow recycling fibers by GC if not referenced directly

The patch assumes that `struct REnv::cxt` only performs checks with the `OP_BREAK` and `OP_RETURN_BLK` instructions, and does not reference the entity.
Therefore, by changing to a weak reference, it is possible to collect fibers that are no longer directly referenced while in the suspended state.

However, we need to detach the living env objects that remain in the call stack of the fiber.
So, in effect, it involves a revert of following commits.
  - commit a3365d8b3f
  - commit 57ffa1c150

Examples of the effects of change are shown below.
Note that it was built with `rake MRUBY_CONFIG=host-debug`.

```ruby
f = Fiber.new { (x, y, z) = "X", "Y", "Z"; Fiber.yield -> { [x, y, z] } }
g = f.resume
GC.start
p ObjectSpace.memsize_of_all
# => 59532
g.call
# => ["X", "Y", "Z"]
f = nil
GC.start
ObjectSpace.memsize_of_all
# BEFORE => 59532
# AFTER  => 58044
g.call
# => ["X", "Y", "Z"]
```
This commit is contained in:
dearblue
2024-04-23 22:30:32 +09:00
parent c8c7d1ab23
commit f1c9260ada
2 changed files with 16 additions and 5 deletions
+16 -4
View File
@@ -630,9 +630,8 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
{
struct REnv *e = (struct REnv*)obj;
if (MRB_ENV_ONSTACK_P(e) && e->cxt && e->cxt->fib) {
mrb_gc_mark(mrb, (struct RBasic*)e->cxt->fib);
}
// The data stack must always be protected from GC regardless of the MRB_ENV_CLOSE flag.
// This is because the data stack is not protected if the fiber is GC'd.
mrb_int len = MRB_ENV_LEN(e);
for (mrb_int i=0; i<len; i++) {
mrb_gc_mark_value(mrb, e->stack[i]);
@@ -773,7 +772,20 @@ obj_free(mrb_state *mrb, struct RBasic *obj, mrb_bool end)
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
if (c != mrb->root_c) {
if (c && c != mrb->root_c) {
if (!end && c->status != MRB_FIBER_TERMINATED) {
mrb_callinfo *ci = c->ci;
mrb_callinfo *ce = c->cibase;
while (ce <= ci) {
struct REnv *e = ci->u.env;
if (e && !is_dead(&mrb->gc, (struct RBasic*)e) &&
e->tt == MRB_TT_ENV && MRB_ENV_ONSTACK_P(e)) {
mrb_env_unshare(mrb, e, TRUE);
}
ci--;
}
}
mrb_free_context(mrb, c);
}
}
-1
View File
@@ -429,7 +429,6 @@ mrb_env_unshare(mrb_state *mrb, struct REnv *e, mrb_bool noraise)
{
if (e == NULL) return TRUE;
if (!MRB_ENV_ONSTACK_P(e)) return TRUE;
if (e->cxt != mrb->c) return TRUE;
e->cxt = NULL; /* make possible to GC the fiber that generated the env */