Skip to content

implement Autogate support for Rust JSG#6366

Draft
anonrig wants to merge 1 commit intomainfrom
yagiz/add-autogate-to-rust
Draft

implement Autogate support for Rust JSG#6366
anonrig wants to merge 1 commit intomainfrom
yagiz/add-autogate-to-rust

Conversation

@anonrig
Copy link
Member

@anonrig anonrig commented Mar 19, 2026

Found a workaround for keeping the C++ and Rust implementations in sync. We could potentially get rid of the C++ Autogate in favor of Rust, if it makes sense in the future.

@anonrig anonrig requested review from a team as code owners March 19, 2026 20:27
@jasnell jasnell requested a review from danlapid March 19, 2026 20:28
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.

I'm Bonk, and I've done a quick review of your PR.

This PR adds Rust FFI bindings to the C++ autogate system, using extern "C" linkage and #[repr(C)] enums. It also refactors the C++ autogate to use an X-macro (WD_AUTOGATE_KEYS) as a single source of truth.

Findings (highest severity first):

  1. [MEDIUM] ffi.h's static_assert is never compiled — //src/rust/autogate:ffi-hdr has zero reverse dependencies
  2. [MEDIUM] ffi.rs is a dead file — never referenced via mod ffi; from lib.rs
  3. [LOW] Stale paths in autogate.h comments reference src/rust/jsg/autogate/ instead of src/rust/autogate/

This review was generated by an AI assistant and may contain errors. Please verify any suggestions before applying them.

Comment on lines +6 to +11
wd_cc_library(
name = "ffi-hdr",
hdrs = ["ffi.h"],
visibility = ["//visibility:public"],
deps = ["//src/workerd/util:autogate"],
)
Copy link
Contributor

Choose a reason for hiding this comment

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

ffi-hdr has zero reverse dependencies — nothing in the build graph depends on //src/rust/autogate:ffi-hdr. This means the static_assert in ffi.h:43 (which validates that the Rust and C++ enums stay in sync) is never compiled by any target. The key safety net of this design is inert.

Consider either:

  • Adding //src/rust/autogate:ffi-hdr as a dep of the autogate Rust crate (so it's always compiled when the crate is), or
  • Moving the static_assert into autogate.c++ (which IS compiled), alongside the workerd_autogate_is_enabled function.

Comment on lines +1 to +39
// 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

// When adding a gate:
// 1. Add WD_AUTOGATE_KEYS entry in src/workerd/util/autogate.h (single source of truth)
// 2. Add matching entry to WD_AUTOGATE_FFI_KEYS in src/rust/autogate/ffi.h
// 3. Add the variant here (value from the C++ enum via ffi.h)
// 4. Update the static_assert count in ffi.h

/// Mirrors `workerd::util::AutogateKey`.
///
/// `#[repr(C)]` with discriminants that match the C++ enum ordinals.
/// Defined once here — `ffi.h` builds its `AutogateKey` enum from this same
/// list (via `WD_AUTOGATE_FFI_KEYS`) so both sides always agree.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AutogateKey {
TestWorkerd = 0,
V8FastApi = 1,
StreamingTailWorker = 2,
TailStreamRefactor = 3,
RustBackedNodeDns = 4,
RpcUseExternalPusher = 5,
WasmShutdownSignalShim = 6,
EnableFastTextencoder = 7,
EnableDrainingReadOnStandardStreams = 8,
}

unsafe extern "C" {
// Implemented in src/workerd/util/autogate.c++ — one array lookup.
#[link_name = "workerd_autogate_is_enabled"]
fn autogate_is_enabled(key: AutogateKey) -> bool;
}

pub fn is_enabled(key: AutogateKey) -> bool {
// SAFETY: reads from a process-global bool array written once at startup.
unsafe { autogate_is_enabled(key) }
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This file is never referenced from lib.rs (no mod ffi; declaration). Rust only compiles files reachable from the crate root, so even though Bazel's native.glob(["**/*.rs"]) includes it in the source set, rustc never compiles it. The AutogateKey enum and extern "C" block here are exact duplicates of what's in lib.rs.

This file should either be removed, or lib.rs should use mod ffi; and re-export from it (eliminating the duplication).

// This list is the single source of truth — it drives:
// - The AutogateKey enum (below)
// - KJ_STRINGIFY (autogate.c++)
// - The Rust FFI constexpr accessors (src/rust/jsg/autogate/ffi.h)
Copy link
Contributor

Choose a reason for hiding this comment

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

Path is stale — the file is at src/rust/autogate/ffi.h, not src/rust/jsg/autogate/ffi.h.

Suggested change
// - The Rust FFI constexpr accessors (src/rust/jsg/autogate/ffi.h)
// - The Rust FFI constexpr accessors (src/rust/autogate/ffi.h)

// - The Rust FFI constexpr accessors (src/rust/jsg/autogate/ffi.h)
//
// To add a gate: add one WD_AUTOGATE_KEY line here, then add a matching
// method in src/rust/jsg/autogate/lib.rs.
Copy link
Contributor

Choose a reason for hiding this comment

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

Same stale path — should be src/rust/autogate/lib.rs.

Suggested change
// method in src/rust/jsg/autogate/lib.rs.
// method in src/rust/autogate/lib.rs.

@ask-bonk
Copy link
Contributor

ask-bonk bot commented Mar 19, 2026

I'm Bonk, and I've done a quick review of your PR.

This PR adds Rust FFI bindings to the C++ autogate system and refactors autogate.h to use an X-macro. I posted a review on PR #6366 with 4 inline comments covering 3 findings:

  1. [MEDIUM] The static_assert in ffi.h (the key safety net ensuring C++ and Rust enums stay in sync) is never compiled because //src/rust/autogate:ffi-hdr has zero reverse dependencies in the build graph.

  2. [MEDIUM] ffi.rs is a dead file — it's never referenced via mod ffi; from lib.rs, so rustc never compiles it. The AutogateKey enum and extern "C" block are duplicated verbatim between ffi.rs and lib.rs.

  3. [LOW] Two comments in autogate.h reference src/rust/jsg/autogate/ but the actual path is src/rust/autogate/ — posted suggested edits for both.

github run

@jasnell
Copy link
Collaborator

jasnell commented Mar 19, 2026

I'm not thrilled that the list of autogates in this PR would apparently need to be maintained across 5 different files (one in C++ the others in rust).

Also keep in mind that a parallel change likely needs to be made internally.

I don't have many strong opinions about how autogates are implemented so long as the checks are fast and the maintenance is easier. With the changes here, I'm not convinced of the latter.

@danlapid
Copy link
Collaborator

I'm not thrilled that the list of autogates in this PR would apparently need to be maintained across 5 different files (one in C++ the others in rust).

Also keep in mind that a parallel change likely needs to be made internally.

I don't have many strong opinions about how autogates are implemented so long as the checks are fast and the maintenance is easier. With the changes here, I'm not convinced of the latter.

What an understatement

@anonrig
Copy link
Member Author

anonrig commented Mar 19, 2026

I don't have many strong opinions about how autogates are implemented so long as the checks are fast and the maintenance is easier. With the changes here, I'm not convinced of the latter.

I agree. I couldn't find a better way as well. I'll keep this in draft so we can think over it.

@anonrig anonrig marked this pull request as draft March 19, 2026 20:34
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 19, 2026

Merging this PR will improve performance by 26.15%

⚡ 1 improved benchmark
✅ 69 untouched benchmarks
⏩ 129 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
bodyWithHeaders[Response] 38.9 µs 30.9 µs +26.15%

Comparing yagiz/add-autogate-to-rust (92f77b2) with main (d05ea20)

Open in CodSpeed

Footnotes

  1. 129 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 85.18519% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.54%. Comparing base (2565b03) to head (92f77b2).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/workerd/util/autogate.c++ 37.50% 5 Missing ⚠️
src/rust/jsg-test/tests/autogate.rs 88.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6366      +/-   ##
==========================================
- Coverage   70.71%   70.54%   -0.18%     
==========================================
  Files         420      422       +2     
  Lines      113713   114032     +319     
  Branches    18735    18780      +45     
==========================================
+ Hits        80414    80439      +25     
- Misses      22070    22363     +293     
- Partials    11229    11230       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dom96
Copy link
Contributor

dom96 commented Mar 19, 2026

This to me feels like a good use case for proc macros. I would explore ingesting the autogate.h file in Rust using a macro and then outputting the AST for an equivalent enum in Rust. Parsing the enum class AutogateKey should be fairly trivial.

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.

5 participants