Skip to content

add gc support to Rust owned objects#6272

Open
anonrig wants to merge 1 commit intomainfrom
yagiz/rust-gc-v2
Open

add gc support to Rust owned objects#6272
anonrig wants to merge 1 commit intomainfrom
yagiz/rust-gc-v2

Conversation

@anonrig
Copy link
Member

@anonrig anonrig commented Mar 6, 2026

Adds gc support to Rust owned objects using the existing GC implementation, rather than using cppgc heap, which the draft implementation used: #5638.

@anonrig anonrig requested review from guybedford and mikea March 6, 2026 20:01
@anonrig anonrig requested review from a team as code owners March 6, 2026 20:01
ask-bonk[bot]

This comment was marked as outdated.

@ask-bonk

This comment was marked as outdated.

@ask-bonk ask-bonk bot requested a review from a team as a code owner March 6, 2026 20:10
@anonrig anonrig requested a review from harrishancock March 6, 2026 20:11
@anonrig anonrig force-pushed the yagiz/rust-gc-v2 branch 2 times, most recently from 4938422 to 170b02a Compare March 6, 2026 20:24
@anonrig
Copy link
Member Author

anonrig commented Mar 6, 2026

/bigbonk roast this pr

@ask-bonk

This comment was marked as outdated.

@anonrig anonrig force-pushed the yagiz/rust-gc-v2 branch 2 times, most recently from ba7b471 to 8a6f84a Compare March 6, 2026 23:08
@anonrig
Copy link
Member Author

anonrig commented Mar 6, 2026

/bigbonk roast this pr

@ask-bonk

This comment has been minimized.

@anonrig anonrig force-pushed the yagiz/rust-gc-v2 branch from 57bfc1c to 1d356e2 Compare March 6, 2026 23:22
@codspeed-hq

This comment has been minimized.

@anonrig anonrig force-pushed the yagiz/rust-gc-v2 branch from 1d356e2 to 1525e8e Compare March 6, 2026 23:54
@anonrig
Copy link
Member Author

anonrig commented Mar 7, 2026

/bigbonk roast this pr

@ask-bonk

This comment was marked as outdated.

@anonrig anonrig force-pushed the yagiz/rust-gc-v2 branch 3 times, most recently from d64dc80 to 2a09295 Compare March 9, 2026 15:59
@anonrig anonrig added the rust Pull requests that update rust code label Mar 9, 2026
@anonrig anonrig requested a review from kentonv March 9, 2026 23:14
@anonrig
Copy link
Member Author

anonrig commented Mar 10, 2026

/bigbonk roast this pr

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Mar 10, 2026

@anonrig Bonk workflow was cancelled.

View workflow run · To retry, trigger Bonk again.

@anonrig
Copy link
Member Author

anonrig commented Mar 10, 2026

/bigbonk roast this pr

Copy link
Contributor

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

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

Review Update

Re-reviewing after a thorough read of the full diff. My earlier review (review #3905780686) had several incorrect findings that I want to correct, plus new findings from this deeper pass.

Corrections to prior review

  • Issue #1 (was High): unwrap/unwrap_ref null handling — This was already correctly handled. WrappableRc::from_js() at v8.rs:1580 returns Option<Self> and checks handle.get().is_null(). Both unwrap and unwrap_ref propagate None via ?. Apologies for the false alarm.
  • Issue #2 (was Medium): Docstring mismatch — Fixed. The docstring and signature now both describe Option<Self>.
  • Issue #3 (was Medium): WeakRef::get() safety — No longer applicable. The get() method was removed; the API now uses upgrade() -> Option<Ref<R>> which is sound.
  • Issue #5 (was Low): todo!() in proc macro — Fixed. Now uses proper syn::Error at lib.rs:389-393.

New findings below (posted as inline comments)

This review was generated by an AI assistant and may contain inaccuracies.

@@ -0,0 +1,265 @@
use std::cell::Cell;
Copy link
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Missing copyright header on new file.

This file is new in this PR but is missing the project copyright/license header. Per the review checklist, every new .rs file must begin with:

// Copyright (c) 2026 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
//     https://opensource.org/licenses/Apache-2.0

Same applies to gc.rs and resource_conversion.rs.

}
.expect("wrappable data already cleared");
// data[0] is Rc::into_raw(*const R) — points directly to R.
trait_ptr.data.cast::<R>()
Copy link
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] resolve_resource performs an unchecked type cast.

trait_ptr.data.cast::<R>() reinterprets the Rc::into_raw pointer as R with no runtime verification that the Wrappable actually holds type R. The C++ side only checks WORKERD_RUST_WRAPPABLE_TAG (confirming "this is a Rust object") but doesn't verify which specific Rust type it holds.

The safety contract ("caller must ensure the type R matches") is upheld by the proc-macro-generated code, but this is a one-line type confusion away from silent memory corruption. Consider storing a TypeId in an additional data slot and adding a debug_assert! check:

debug_assert_eq!(
    stored_type_id,
    TypeId::of::<R>(),
    "type mismatch in resolve_resource"
);

This would catch type confusion bugs during development/testing with zero cost in release builds.

reason = "Pin<&mut> comes from a raw pointer, not from &self"
)]
unsafe fn as_pin_mut(&self) -> Pin<&mut ffi::Wrappable> {
unsafe { Pin::new_unchecked(&mut *self.handle.get().cast_mut()) }
Copy link
Contributor

Choose a reason for hiding this comment

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

[LOW] as_pin_mut safety comment could be strengthened.

Invariant #3 ("Non-reentrant FFI") is not entirely accurate: wrappable_visit_ref at ffi.c++:454 calls wrappable.visitRef(*gcVisitor, parentMaybe, *ref_strong), which traces child Wrappables, which calls wrappable_invoke_trace, which calls back into Rust's GarbageCollected::trace(). However, the re-entry creates a Pin<&mut Wrappable> for a different Wrappable (the child), not the same one, so the &mut uniqueness invariant holds.

Consider clarifying the comment to say: "C++ methods may re-enter Rust for different Wrappables during tracing, but never create a second Pin<&mut Wrappable> for the same object."


### `WeakRef<R>`

Weak reference that doesn't prevent GC collection. Use `upgrade()` to get a `Ref<R>` if the resource is still alive, or `get()` for a temporary `&R`.
Copy link
Contributor

Choose a reason for hiding this comment

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

[LOW] Stale API reference.

get() is mentioned here but WeakRef only exposes upgrade() and is_alive() — there is no get() method.

Suggested change
Weak reference that doesn't prevent GC collection. Use `upgrade()` to get a `Ref<R>` if the resource is still alive, or `get()` for a temporary `&R`.
Weak reference that doesn't prevent GC collection. Use `upgrade()` to get a `Ref<R>` if the resource is still alive.

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Mar 10, 2026

Review posted successfully. Here's a summary of what was posted:

Corrections to prior review:

  • The "High" severity null-handling issue was already correctly handled — WrappableRc::from_js() returns Option<Self> with a null check, and both unwrap/unwrap_ref propagate None via ?.
  • The docstring mismatch, WeakRef::get() safety, and todo!() issues were all already resolved in the current code.

New findings (5 inline comments):

  1. [MEDIUM] Missing copyright headers on 3 new files (resource.rs, gc.rs, resource_conversion.rs) — per the project's review checklist, new .rs files need the copyright header.

  2. [MEDIUM] resolve_resource unchecked type cast (v8.rs:1709) — trait_ptr.data.cast::<R>() has no runtime type verification. The WORKERD_RUST_WRAPPABLE_TAG check only confirms "this is a Rust object," not which specific Rust type. Suggested adding a debug_assert! with TypeId for development-time safety.

  3. [LOW] Fat pointer transmute tracking (v8.rs:1319) — The inline TODO about ptr_metadata stabilization should be turned into a concrete tracking issue for visibility.

  4. [LOW] as_pin_mut safety comment clarification (v8.rs:1651) — The "non-reentrant FFI" invariant should clarify that re-entry occurs for different Wrappables during tracing, which is safe.

  5. [LOW] Stale get() reference in README (README.md:17) — Mentions a WeakRef::get() method that doesn't exist; should reference upgrade() instead. Included a suggested edit.

github run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant