Skip to content

RFC: api redesign prototype and notes based on gc-arena#68

Merged
nekevss merged 6 commits intoboa-dev:mainfrom
shruti2522:api-redesign-prototype
Apr 4, 2026
Merged

RFC: api redesign prototype and notes based on gc-arena#68
nekevss merged 6 commits intoboa-dev:mainfrom
shruti2522:api-redesign-prototype

Conversation

@shruti2522
Copy link
Copy Markdown
Contributor

@shruti2522 shruti2522 commented Mar 27, 2026

functional prototype and notes for a new GC API based on the requiremnts fo an ideal Gc mentioned in boa#2631. It explores moving from the current implicit rooting behavior to zero overhead, lifetime branded model inspired by gc-arena.

  • prototype (oscars/examples/api_prototype): standalone implementation demonstrating the core design (Gc, Root, MutationContext) with examples

@shruti2522 shruti2522 force-pushed the api-redesign-prototype branch 2 times, most recently from c211cae to fed14b3 Compare March 27, 2026 12:31
@shruti2522 shruti2522 changed the title add api redesign prototype and notes based on gc-arena RFC: api redesign prototype and notes based on gc-arena Mar 27, 2026
@shruti2522 shruti2522 force-pushed the api-redesign-prototype branch from fed14b3 to 8a0ef34 Compare March 27, 2026 13:22
@shruti2522 shruti2522 force-pushed the api-redesign-prototype branch from 8a0ef34 to cf29ff4 Compare March 27, 2026 13:26
… feasibilty of context bound pointer lifetimes
@shruti2522 shruti2522 force-pushed the api-redesign-prototype branch from eb19a58 to f661622 Compare March 27, 2026 15:23
Comment thread notes/api-redesign-prototype/prototype_findings.md Outdated
Comment thread oscars/examples/api_prototype/main.rs
Comment thread oscars/examples/api_prototype/gc.rs Outdated
}

pub(crate) fn alloc<'gc, T: Trace + Finalize + 'gc>(&'gc self, value: T) -> Gc<'gc, T> {
let boxed = Box::new(GcBox {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm highly skeptical of a box usage here. We're just going to end up with the same fragmentation issue we have with the current implementation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed box usage here, used PoolAllocator instead

Comment thread notes/api-redesign-prototype/prototype_findings.md Outdated
| **Pointer** | `Gc<T>` | `Gc<'gc, T>` |
| **Lifetime** | `'static` + `extend_lifetime()` | `'gc` branded |
| **Rooting** | Implicit (inc/dec on clone/drop) | Explicit (`Root<T>`) |
| **Copy cost** | Cell write | Zero |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the drop cost is a required access to a TLS which uses a futex lock in most implementations. It's very expensive for the current GC. It would be free for the proposed one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, completely missed that. Added TLS futex drop cost to the table

@shruti2522 shruti2522 force-pushed the api-redesign-prototype branch from 61bed6b to 142d613 Compare March 28, 2026 04:18
@shruti2522
Copy link
Copy Markdown
Contributor Author

Replaced Vec root tracking with intrusive linked list for O(1) root removal, switched from Box allocation to PoolAllocator, and added compile fail tests to check that the 'gc lifetime correctly prevents pointers from escaping the mutation context.

I had kept the initial implementation simple since I wanted to focus the discussion on the API design first, but you're right that it should reflect the actual target implementation more closely. Hope this looks better

Comment on lines +52 to +53
collector_roots: Rc<RefCell<RootList>>,
node: RootListNode, // Intrusive list node
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slight tweak here. You don't need a collector_roots field, you just need to unlink the previous and next elements of RootListNode from the current node, then link them together.

To collect the roots the GC can just take the base root, the go through the linked list to get all the inner Gcs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the intrusive_collections crate could be a good inspiration for this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used intrusive_collections as the inspiration.RootLink holds only Cell<Option<NonNull<RootLink>>> for prev/next, with gc_ptr recovered via offset_of!

@shruti2522 shruti2522 force-pushed the api-redesign-prototype branch from eb0b461 to 8310612 Compare March 28, 2026 08:58
Comment thread oscars/examples/api_prototype/gc.rs Outdated
Comment on lines +188 to +189
// `T: Sized` ensures `gc_ptr` is always a thin (one-word) pointer, so
// `link` sits at the same byte offset in `Root<T>` for every sized `T`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also put the link at the start. right? Such that it doesn't matter if T is sized

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, though T: Sized is still required to keep gc_ptr as a thin pointer for sound type erased *mut u8 collector reads. Removing it would need a second NonNull<GcBox<()>> field for the GC to read, with Root::get() using the fat pointer. should I do that?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I guess it kinda doesn't matter, because in our current GC we do some vtable hacks to erase pointers in a slightly safer way, so we also require T:Sized

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I'll leave it as is then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually that's false. What we did in our current GC was to introduce the concept of a GcErasedPtr, which is just a NonNull<GcBox<NonTraceable>>, and because the GcBox has a VTable of every T, you don't need to ensure T: Sized

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to introduce that here though, since it's just a prototype. We can address these limitations after iterating on this

Copy link
Copy Markdown
Member

@jedel1043 jedel1043 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new API looks great! Nice job!

We might have some ways to statically ensure Root is not used with a different realm, like relating them to the GcContext itself by some invariant lifetime, but that's a future improvement that we can do while iterating on this.

@shruti2522
Copy link
Copy Markdown
Contributor Author

Thanks! Sounds good, I'll keep those improvements in mind for future iterations.

Copy link
Copy Markdown
Member

@nekevss nekevss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall and is super interesting

@nekevss nekevss merged commit 819cc7e into boa-dev:main Apr 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants