From 7dd0c1f7a79bebc5c17549e9ca2984b3ff7dfc79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Tue, 25 Aug 2026 07:41:38 +0200 Subject: [PATCH 1/2] test: normalize method literal GC arms --- .../tests/static_method_object_literal.rs | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/crates/perry/tests/static_method_object_literal.rs b/crates/perry/tests/static_method_object_literal.rs index 453ba9d593..b20c40b4cd 100644 --- a/crates/perry/tests/static_method_object_literal.rs +++ b/crates/perry/tests/static_method_object_literal.rs @@ -8,6 +8,29 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Output}; use std::sync::Once; +/// Keep the forced-moving arm independent of ambient developer/CI settings. +/// Some inputs affect code generation, so normalize the runtime build, +/// fixture compile, and child process alike. +const GC_ENV_OVERRIDES: &[&str] = &[ + "PERRY_GEN_GC", + "PERRY_GC_SCAVENGE", + "PERRY_GC_SCAVENGE_NURSERY_MB", + "PERRY_GC_MOVING_SAFEPOINT", + "PERRY_GC_MOVING_LOOP_POLLS", + "PERRY_GC_FORCE_EVACUATE", + "PERRY_GC_VERIFY_EVACUATION", + "PERRY_CONSERVATIVE_STACK_SCAN", + "PERRY_WRITE_BARRIERS", + "PERRY_GC_INCREMENTAL", + "PERRY_GC_HEAP_LIMIT", +]; + +fn remove_gc_env_overrides(command: &mut Command) { + for key in GC_ENV_OVERRIDES { + command.env_remove(key); + } +} + fn perry_bin() -> PathBuf { PathBuf::from(env!("CARGO_BIN_EXE_perry")) } @@ -25,6 +48,7 @@ fn runtime_dir() -> PathBuf { let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); let mut command = Command::new(cargo); command.current_dir(workspace_root()).arg("build"); + remove_gc_env_overrides(&mut command); if !cfg!(debug_assertions) { command.arg("--release"); } @@ -48,14 +72,11 @@ fn runtime_dir() -> PathBuf { fn run_fixture(binary: &Path, force_evacuation: bool) -> Output { let mut command = Command::new(binary); + remove_gc_env_overrides(&mut command); if force_evacuation { command .env("PERRY_GC_FORCE_EVACUATE", "1") .env("PERRY_GC_VERIFY_EVACUATION", "1"); - } else { - command - .env_remove("PERRY_GC_FORCE_EVACUATE") - .env_remove("PERRY_GC_VERIFY_EVACUATION"); } command.output().expect("run method-literal fixture") } @@ -108,7 +129,8 @@ console.log( ) .expect("write method-literal fixture"); - let compile = Command::new(perry_bin()) + let mut compile_command = Command::new(perry_bin()); + compile_command .current_dir(dir.path()) .arg("compile") .arg(&entry) @@ -116,7 +138,9 @@ console.log( .arg(&binary) .arg("--no-cache") .arg("--no-auto-optimize") - .env("PERRY_RUNTIME_DIR", runtime_dir()) + .env("PERRY_RUNTIME_DIR", runtime_dir()); + remove_gc_env_overrides(&mut compile_command); + let compile = compile_command .output() .expect("compile method-literal fixture"); assert!( From 1ebf4574dcf202469688d091390a063997b99a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Tue, 25 Aug 2026 08:42:26 +0200 Subject: [PATCH 2/2] docs(runtime): pin captured cache hint bounds --- crates/perry-runtime/src/closure/alloc.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/perry-runtime/src/closure/alloc.rs b/crates/perry-runtime/src/closure/alloc.rs index f0c5b3da2b..ca21e81741 100644 --- a/crates/perry-runtime/src/closure/alloc.rs +++ b/crates/perry-runtime/src/closure/alloc.rs @@ -488,6 +488,10 @@ pub(crate) fn test_captured_singleton_closure_cache_entries( /// covers the per-batch fan-out shape (50 promises) found in /// `benchmarks/app-patterns/kernels/promise_all_chains.ts`. const MAX_CAPTURED_CLOSURE_SLOTS: usize = 64; +const _: () = assert!( + MAX_CAPTURED_CLOSURE_SLOTS <= u8::MAX as usize, + "hint_indices_plus_one stores an entry index plus one in a u8" +); /// Per-`func_ptr` cache miss-streak counter for the adaptive bypass. /// Closures whose captures change every call (per-call boxes for @@ -581,9 +585,8 @@ pub extern "C" fn js_closure_alloc_with_captures_singleton( } crate::promise::bump(&CLOSURE_CAP_SINGLETON_MISS); - // Slow path: allocate, populate captures, insert into cache as - // the most-recent entry. If the slot list is full, drop the - // least-recent (back of the Vec). + // Slow path: allocate, populate captures, and insert with a fresh usage + // timestamp. If the entry list is full, replace its oldest timestamp. let capture_scope = crate::gc::RuntimeHandleScope::new(); let capture_handles: Vec<_> = captures_slice .iter()