From 688fb4721eafe8b3b3b9593f9fe7aff5f1a38a96 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:04:36 +0200 Subject: [PATCH 01/18] chore(warnings): sweep machine-fixable warnings via cargo fix --all-targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run `cargo fix --workspace --all-targets` now that the workspace test targets compile again, so test-only imports are seen instead of pruned. Clears 87 warnings: 74 unused_imports, 11 function_casts_as_integer (new in rustc 1.95 — casting a function item straight to an integer), plus one each of unused_mut and unused_variables. Two things the tool could not do on its own: - optimized_libs/tests.rs reached build_missing_prebuilt_ext_lib through `super::*`, so cargo fix pruned the re-export it needed. The test now imports the function from no_auto directly. - 49 of the pruned imports were duplicate preambles introduced when commands/compile.rs was split into submodules after #6639. --- crates/perry-codegen-wasm/src/emit/mod.rs | 1 - .../src/emit/runtime_imports.rs | 2 -- .../src/emit/ui_method_map.rs | 2 -- crates/perry-codegen/src/stmt/loops.rs | 2 +- .../tests/backend_tests.rs | 1 - .../perry-ext-http-server/src/http2_server.rs | 32 ++++++++----------- crates/perry-hir/src/lower/builder_fold.rs | 15 ++------- crates/perry-runtime/src/abi_trampoline.rs | 4 +-- crates/perry-runtime/src/builtins/mod.rs | 3 -- crates/perry-runtime/src/bun_ffi/call.rs | 18 +++++------ crates/perry-runtime/src/dgram.rs | 1 - .../src/object/class_registry.rs | 7 ++-- crates/perry-runtime/src/object/object_ops.rs | 2 +- crates/perry-runtime/src/promise/mod.rs | 2 +- crates/perry-runtime/src/string/tests.rs | 2 +- crates/perry-transform/src/generator/lower.rs | 23 ++++--------- crates/perry/src/commands/compile.rs | 12 ++----- .../src/commands/compile/cjs_wrap/detect.rs | 2 -- .../compile/cjs_wrap/extract_requires.rs | 2 -- .../compile/cjs_wrap/hoist_classes.rs | 2 -- .../src/commands/compile/collect_modules.rs | 2 +- crates/perry/src/commands/compile/helpers.rs | 8 ++--- .../src/commands/compile/optimized_libs.rs | 15 ++------- .../commands/compile/optimized_libs/driver.rs | 5 +-- .../compile/optimized_libs/freshness.rs | 7 +--- .../compile/optimized_libs/no_auto.rs | 5 --- .../commands/compile/optimized_libs/paths.rs | 11 ------- .../commands/compile/optimized_libs/tests.rs | 3 +- .../src/commands/compile/run_pipeline.rs | 1 - 29 files changed, 52 insertions(+), 140 deletions(-) diff --git a/crates/perry-codegen-wasm/src/emit/mod.rs b/crates/perry-codegen-wasm/src/emit/mod.rs index c479ce49f8..fec4d4e5b6 100644 --- a/crates/perry-codegen-wasm/src/emit/mod.rs +++ b/crates/perry-codegen-wasm/src/emit/mod.rs @@ -53,7 +53,6 @@ use wasm_encoder::{ use closures::{collect_closures_from_expr, collect_closures_from_stmts}; // `f64_const_bits` is held alive for future use (matches the pre-split // `#[allow(dead_code)]` annotation on its original definition). -use constants::f64_const_bits; use constants::{ f64_const, EnumResolvedValue, STRING_TAG, TAG_FALSE, TAG_NULL, TAG_TRUE, TAG_UNDEFINED, }; diff --git a/crates/perry-codegen-wasm/src/emit/runtime_imports.rs b/crates/perry-codegen-wasm/src/emit/runtime_imports.rs index a2e26a3292..f1cda09ca8 100644 --- a/crates/perry-codegen-wasm/src/emit/runtime_imports.rs +++ b/crates/perry-codegen-wasm/src/emit/runtime_imports.rs @@ -3,8 +3,6 @@ //! //! Pure code-movement from `mod.rs`. -use super::*; - /// Import function indices (must match the order imports are added) /// Most fields are unused directly but their indices define the WASM import order. #[derive(Clone, Copy)] diff --git a/crates/perry-codegen-wasm/src/emit/ui_method_map.rs b/crates/perry-codegen-wasm/src/emit/ui_method_map.rs index 817ccb5399..e2fe58c7de 100644 --- a/crates/perry-codegen-wasm/src/emit/ui_method_map.rs +++ b/crates/perry-codegen-wasm/src/emit/ui_method_map.rs @@ -1,8 +1,6 @@ //! `map_ui_method`: maps perry/ui and perry/system method names to bridge //! function names. Pure code-movement from `mod.rs`. -use super::*; - /// Map perry/ui and perry/system method names to bridge function names. /// Mirrors the mapping in perry-codegen-js's emit_ui_method_call. pub(super) fn map_ui_method(method: &str, class_name: Option<&str>) -> &'static str { diff --git a/crates/perry-codegen/src/stmt/loops.rs b/crates/perry-codegen/src/stmt/loops.rs index 90bd3a16a9..4990af3bdc 100644 --- a/crates/perry-codegen/src/stmt/loops.rs +++ b/crates/perry-codegen/src/stmt/loops.rs @@ -2368,7 +2368,7 @@ fn lower_object_array_write_versioned_for( ) }; let preheader_idx = ctx.current_block; - let preheader_label = ctx.block().label.clone(); + let _preheader_label = ctx.block().label.clone(); // Emit the fallback first. Besides preserving the original semantics, this // creates the ordinary local slots for the nested counter, allowing the diff --git a/crates/perry-container-compose/tests/backend_tests.rs b/crates/perry-container-compose/tests/backend_tests.rs index 79a7ad8ae4..4d1671ebbb 100644 --- a/crates/perry-container-compose/tests/backend_tests.rs +++ b/crates/perry-container-compose/tests/backend_tests.rs @@ -1,6 +1,5 @@ use perry_container_compose::backend::*; use perry_container_compose::types::ContainerSpec; -use std::collections::HashMap; // Feature: perry-container | Layer: unit | Req: 1.1 | Property: - #[test] diff --git a/crates/perry-ext-http-server/src/http2_server.rs b/crates/perry-ext-http-server/src/http2_server.rs index d22a6a6a8c..ace23167e4 100644 --- a/crates/perry-ext-http-server/src/http2_server.rs +++ b/crates/perry-ext-http-server/src/http2_server.rs @@ -20,17 +20,15 @@ use std::sync::atomic::{AtomicI64, Ordering}; use std::sync::{Arc, Mutex}; use bytes::Bytes; -use http_body_util::{BodyExt, Full}; -use hyper::header::{HeaderName, HeaderValue}; +use http_body_util::BodyExt; use hyper::service::service_fn; -use hyper::{body::Incoming, Request, Response, Version}; +use hyper::{body::Incoming, Request}; use hyper_util::rt::{TokioExecutor, TokioIo}; use hyper_util::server::conn::auto::Builder as AutoBuilder; use lazy_static::lazy_static; use perry_ffi::{ - alloc_buffer, alloc_string, get_handle, get_handle_mut, iter_handle_ids_of, iter_handles_of, - iter_handles_of_mut, register_handle, JsClosure, JsValue, ObjectHeader, RawClosureHeader, - StringHeader, + alloc_buffer, alloc_string, get_handle_mut, register_handle, JsClosure, JsValue, ObjectHeader, + RawClosureHeader, StringHeader, }; use tokio::net::TcpListener; use tokio::sync::{mpsc, oneshot}; @@ -38,20 +36,16 @@ use tokio_rustls::TlsAcceptor; use crate::ensure_gc_scanner_registered; use crate::http2_session_settings::Http2SettingsState; -use crate::request::{ - alloc_incoming_message, emit_no_arg_to_listeners, handle_to_pointer_f64, with_implicit_this, - IncomingMessage, -}; -use crate::response::{alloc_server_response_for_request, HyperResponseShape, ResponseBody}; -use crate::server::{synthesize_default_response_if_needed, HttpPendingRequest, HttpServer}; +use crate::request::handle_to_pointer_f64; +use crate::response::HyperResponseShape; +use crate::server::{HttpPendingRequest, HttpServer}; use crate::tls::{ build_server_config, has_pem_material, json_value_to_pem_bytes, parse_cert_chain, parse_private_key, }; use crate::types::{ - extract_host, extract_port, js_promise_run_microtasks, js_value_is_closure, - jsvalue_to_body_bytes, jsvalue_to_owned_string, read_string_header, POINTER_TAG, PTR_MASK, - STRING_TAG, TAG_NULL, TAG_UNDEFINED, + extract_host, extract_port, js_value_is_closure, jsvalue_to_owned_string, POINTER_TAG, + PTR_MASK, STRING_TAG, TAG_NULL, TAG_UNDEFINED, }; extern "C" { @@ -72,13 +66,13 @@ pub(crate) use controls::{ numeric_value, queue_session_goaway, queue_session_ping, queue_session_settings, }; pub(crate) use pump::{ - has_active_h2_clients, has_pending_h2_events, process_pending_h2, process_pending_h2_events, + has_active_h2_clients, process_pending_h2, process_pending_h2_events, try_recv_pending_h2_nonblocking, }; pub(crate) use session::{ - h2_listening_server_for_authority, local_client_connect_ready, local_server_handle_for_client, - local_server_session_event_ready, mark_server_sessions_closed, mark_session_closed, - parse_headers_object, register_server_session, start_client_request, + local_client_connect_ready, local_server_handle_for_client, local_server_session_event_ready, + mark_server_sessions_closed, mark_session_closed, parse_headers_object, + register_server_session, start_client_request, }; // `handle_h2_request` is consumed by `js_node_http2_server_listen` below. diff --git a/crates/perry-hir/src/lower/builder_fold.rs b/crates/perry-hir/src/lower/builder_fold.rs index deb0d9cbeb..259d4ede63 100644 --- a/crates/perry-hir/src/lower/builder_fold.rs +++ b/crates/perry-hir/src/lower/builder_fold.rs @@ -90,9 +90,7 @@ fn scan_stmt(s: &ast::Stmt) -> bool { match s { ast::Stmt::Block(b) => stmts_have_candidate(&b.stmts), ast::Stmt::If(i) => { - scan_expr(&i.test) - || scan_stmt(&i.cons) - || i.alt.as_deref().is_some_and(scan_stmt) + scan_expr(&i.test) || scan_stmt(&i.cons) || i.alt.as_deref().is_some_and(scan_stmt) } ast::Stmt::While(w) => scan_expr(&w.test) || scan_stmt(&w.body), ast::Stmt::DoWhile(d) => scan_stmt(&d.body) || scan_expr(&d.test), @@ -115,8 +113,7 @@ fn scan_stmt(s: &ast::Stmt) -> bool { .is_some_and(|f| stmts_have_candidate(&f.stmts)) } ast::Stmt::Switch(sw) => { - scan_expr(&sw.discriminant) - || sw.cases.iter().any(|c| stmts_have_candidate(&c.cons)) + scan_expr(&sw.discriminant) || sw.cases.iter().any(|c| stmts_have_candidate(&c.cons)) } ast::Stmt::Decl(d) => scan_decl(d), ast::Stmt::Expr(es) => scan_expr(&es.expr), @@ -209,13 +206,7 @@ fn scan_expr(e: &ast::Expr) -> bool { matches!(&c.callee, ast::Callee::Expr(e) if scan_expr(e)) || c.args.iter().any(|a| scan_expr(&a.expr)) } - E::New(n) => { - scan_expr(&n.callee) - || n.args - .iter() - .flatten() - .any(|a| scan_expr(&a.expr)) - } + E::New(n) => scan_expr(&n.callee) || n.args.iter().flatten().any(|a| scan_expr(&a.expr)), E::Seq(s) => s.exprs.iter().any(|e| scan_expr(e)), E::Tpl(t) => t.exprs.iter().any(|e| scan_expr(e)), E::Paren(p) => scan_expr(&p.expr), diff --git a/crates/perry-runtime/src/abi_trampoline.rs b/crates/perry-runtime/src/abi_trampoline.rs index 28f0eed6a6..eadf84c795 100644 --- a/crates/perry-runtime/src/abi_trampoline.rs +++ b/crates/perry-runtime/src/abi_trampoline.rs @@ -378,7 +378,7 @@ mod tests { for i in 1..70 { args.push(i as f64); } - let got = unsafe { call_all_f64(sum70 as usize, &args) }; + let got = unsafe { call_all_f64(sum70 as *const () as usize, &args) }; // expected = sum(args[i]*(i+1)) let expected: f64 = args .iter() @@ -409,7 +409,7 @@ mod tests { #[test] fn trampoline_stack_spill_args_9_and_10() { let args = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 42.0, 7.0]; - let got = unsafe { call_all_f64(pick as usize, &args) }; + let got = unsafe { call_all_f64(pick as *const () as usize, &args) }; assert_eq!(got, 42.0 * 1000.0 + 7.0); } } diff --git a/crates/perry-runtime/src/builtins/mod.rs b/crates/perry-runtime/src/builtins/mod.rs index b526b77b9e..4755122209 100644 --- a/crates/perry-runtime/src/builtins/mod.rs +++ b/crates/perry-runtime/src/builtins/mod.rs @@ -107,9 +107,6 @@ pub use numbers::{ js_to_integer_or_infinity, reject_symbol_to_string, }; -#[cfg(test)] -pub(crate) use numbers::parse_float_bytes; - pub use table::{js_console_table, js_console_table_with_properties}; #[cfg(test)] diff --git a/crates/perry-runtime/src/bun_ffi/call.rs b/crates/perry-runtime/src/bun_ffi/call.rs index 46c150009d..c40a152730 100644 --- a/crates/perry-runtime/src/bun_ffi/call.rs +++ b/crates/perry-runtime/src/bun_ffi/call.rs @@ -600,7 +600,7 @@ mod tests { let image = image_from(&[1, 2, 3, 4, 5, 6, 7, 8], &[]); let r = unsafe { raw::call_int( - sum8_i32 as usize, + sum8_i32 as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -615,7 +615,7 @@ mod tests { let image = image_from(&[], &[0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]); let r = unsafe { raw::call_f64( - dsum8 as usize, + dsum8 as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -633,7 +633,7 @@ mod tests { let image = image_from(&[10, 20, 30], &[2.0, 4.0, f_img]); let r = unsafe { raw::call_f64( - mixed as usize, + mixed as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -648,7 +648,7 @@ mod tests { let image = image_from(&[], &[f64::from_bits((21.0f32).to_bits() as u64)]); let r = unsafe { raw::call_f32( - f32_half as usize, + f32_half as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -663,7 +663,7 @@ mod tests { let image = image_from(&[u64::MAX as usize], &[]); let r = unsafe { raw::call_int( - u64_id as usize, + u64_id as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -678,7 +678,7 @@ mod tests { let image = image_from(&[1], &[]); let r = unsafe { raw::call_int( - bool_not as usize, + bool_not as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -691,7 +691,7 @@ mod tests { let image = image_from(&[5], &[]); let r = unsafe { raw::call_int( - i8_neg as usize, + i8_neg as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -716,7 +716,7 @@ mod tests { let image = image_from(&[100, 20, 3], &[]); let r = unsafe { raw::call_int( - add3 as usize, + add3 as *const () as usize, image.n_int, &image.ints, image.n_float, @@ -731,7 +731,7 @@ mod tests { let image = image_from(&[], &[]); let r = unsafe { raw::call_int( - noargs as usize, + noargs as *const () as usize, image.n_int, &image.ints, image.n_float, diff --git a/crates/perry-runtime/src/dgram.rs b/crates/perry-runtime/src/dgram.rs index 0dfc8afa09..0d28e15a20 100644 --- a/crates/perry-runtime/src/dgram.rs +++ b/crates/perry-runtime/src/dgram.rs @@ -10,7 +10,6 @@ //! touching the network. use std::collections::HashMap; -use std::net::ToSocketAddrs; use std::sync::{LazyLock, Mutex}; use crate::array::ArrayHeader; diff --git a/crates/perry-runtime/src/object/class_registry.rs b/crates/perry-runtime/src/object/class_registry.rs index ed4df5399d..cef7414a05 100644 --- a/crates/perry-runtime/src/object/class_registry.rs +++ b/crates/perry-runtime/src/object/class_registry.rs @@ -93,8 +93,6 @@ pub(crate) use class_meta::{ }; #[cfg(test)] pub(crate) use prototype_methods::CLASS_PROTOTYPE_FAST_GUARDS_INVALIDATED; -#[cfg(test)] -pub(crate) use state::CLASS_DELETED_KEYS; // ── prototype_methods.rs ──────────────────────────────────────────────────── pub(crate) use prototype_methods::{ @@ -131,9 +129,8 @@ pub(crate) use gc_roots::{ test_class_prototype_method_root_bits, test_class_prototype_method_value_root_bits, test_class_prototype_object_root_addr, test_clear_class_side_table_roots, test_function_class_id_key_for_class, test_seed_class_dynamic_prop_root, - test_seed_class_parent_closure_root, test_seed_class_prototype_method_root, - test_seed_class_prototype_method_value_root, test_seed_class_prototype_object_root, - test_seed_function_class_id_key, + test_seed_class_prototype_method_root, test_seed_class_prototype_method_value_root, + test_seed_class_prototype_object_root, test_seed_function_class_id_key, }; // ── registration.rs ───────────────────────────────────────────────────────── diff --git a/crates/perry-runtime/src/object/object_ops.rs b/crates/perry-runtime/src/object/object_ops.rs index 802fa84fd0..b4ddf8705a 100644 --- a/crates/perry-runtime/src/object/object_ops.rs +++ b/crates/perry-runtime/src/object/object_ops.rs @@ -39,7 +39,7 @@ pub(crate) use descriptor_helpers::{ registered_buffer_index_own_property_present, throw_object_type_error, throw_object_type_error_with_suffix, try_decode_descriptor, validate_nonconfigurable_redefine, validate_property_descriptor, validate_property_descriptor_view, value_is_object_like, - DescView, DESC_CONFIGURABLE, DESC_ENUMERABLE, DESC_GET, DESC_SET, DESC_VALUE, DESC_WRITABLE, + DESC_CONFIGURABLE, DESC_ENUMERABLE, DESC_GET, DESC_SET, DESC_VALUE, DESC_WRITABLE, }; // Module-private `unsafe fn value_is_callable` (descriptor_helpers): used by the // object_ops children (`accessors.rs`, `descriptor_helpers.rs`) but NOT diff --git a/crates/perry-runtime/src/promise/mod.rs b/crates/perry-runtime/src/promise/mod.rs index 33cfb5e6d3..1375cc0ae5 100644 --- a/crates/perry-runtime/src/promise/mod.rs +++ b/crates/perry-runtime/src/promise/mod.rs @@ -96,7 +96,7 @@ pub(crate) use scanners::{ test_async_step_thunk_cache, test_clear_promise_scanner_roots, test_current_microtask_value, test_promise_context_keys, test_promise_scanner_snapshot, test_seed_async_step_thunk_cache, test_seed_many_promise_task_roots, test_seed_promise_context, test_seed_promise_scanner_roots, - test_store_with_resolvers_result_fields, TestPromiseScannerSnapshot, + test_store_with_resolvers_result_fields, }; // Cached `PERRY_MT_PROFILE` flag, populated once at process start. diff --git a/crates/perry-runtime/src/string/tests.rs b/crates/perry-runtime/src/string/tests.rs index 4618577d7c..e3c5587d3e 100644 --- a/crates/perry-runtime/src/string/tests.rs +++ b/crates/perry-runtime/src/string/tests.rs @@ -2,7 +2,7 @@ //! //! Moved verbatim from the pre-split monolithic `string.rs`. -use super::intern::{with_intern_table, InternEntry, INTERN_TABLE_MASK}; +use super::intern::{with_intern_table, INTERN_TABLE_MASK}; use super::*; fn malloc_object_count_for_test() -> usize { diff --git a/crates/perry-transform/src/generator/lower.rs b/crates/perry-transform/src/generator/lower.rs index 79d548f35c..45a1f8d0cf 100644 --- a/crates/perry-transform/src/generator/lower.rs +++ b/crates/perry-transform/src/generator/lower.rs @@ -15,24 +15,13 @@ mod yield_await; // `use super::*`) reference. Globs do not propagate transitively in this // repo, so spell every cross-module symbol explicitly. pub(crate) use abrupt::{ - build_abrupt_routing, build_async_catch_route_body, build_async_throw_body, - build_completion_resume_stmts, build_dispatch_catch_handler, build_finally_run_stmts, - build_yield_star_return_routes, build_yield_star_throw_routes, catch_route_condition, - finally_abrupt_condition, finally_route_condition, rewrite_dispatch_continue_to_suspend, - wrap_dispatch_loop, -}; -pub(crate) use async_step::{ - build_async_catch_route_body_direct, build_async_step_driver_direct, - build_async_throw_body_direct, -}; -pub(crate) use call_this::{ - generator_body_uses_call_this, generator_expr_uses_call_this, generator_stmt_uses_call_this, -}; -pub(crate) use resume::{ - generator_executing_guard, generator_executing_type_error, generator_resume_rethrow, - prepend_executing_clear_before_returns, promise_reject, wrap_async_gen_step_body, - wrap_generator_resume_body, + build_abrupt_routing, build_async_throw_body, build_completion_resume_stmts, + build_finally_run_stmts, build_yield_star_return_routes, build_yield_star_throw_routes, + catch_route_condition, wrap_dispatch_loop, }; +pub(crate) use async_step::build_async_step_driver_direct; +pub(crate) use call_this::generator_body_uses_call_this; +pub(crate) use resume::{wrap_async_gen_step_body, wrap_generator_resume_body}; pub(crate) use yield_await::await_async_generator_yield_operands; /// #6709: read the currently-running step closure (`Expr::CurrentStepClosure`). diff --git a/crates/perry/src/commands/compile.rs b/crates/perry/src/commands/compile.rs index fa6ddcb5cc..cdb0685d32 100644 --- a/crates/perry/src/commands/compile.rs +++ b/crates/perry/src/commands/compile.rs @@ -1,12 +1,7 @@ //! Compile command - compiles TypeScript to native executable -use anyhow::{anyhow, Result}; +use anyhow::Result; use rayon::prelude::*; -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::sync::atomic::{AtomicUsize, Ordering}; use crate::OutputFormat; @@ -139,9 +134,8 @@ mod run_pipeline; #[cfg(windows)] pub(crate) use helpers::is_windows_reserved_file_stem; pub(crate) use helpers::{ - apply_libc_to_target, backend_disabled_msg, canonical_class_source_prefix, - native_object_file_stem, object_cache_project_root, print_deferred_eval_notice, - NativeObjectArtifact, + apply_libc_to_target, canonical_class_source_prefix, native_object_file_stem, + object_cache_project_root, print_deferred_eval_notice, NativeObjectArtifact, }; pub use run_pipeline::run_with_parse_cache; diff --git a/crates/perry/src/commands/compile/cjs_wrap/detect.rs b/crates/perry/src/commands/compile/cjs_wrap/detect.rs index 7ba381fe8e..694cb44780 100644 --- a/crates/perry/src/commands/compile/cjs_wrap/detect.rs +++ b/crates/perry/src/commands/compile/cjs_wrap/detect.rs @@ -1,7 +1,5 @@ //! CommonJS-vs-ESM heuristic detection plus reserved-word filtering. -use super::*; - /// Heuristic CJS detection. Same shape as /// `perry-jsruntime/src/modules.rs::is_commonjs`. False negatives are /// acceptable (the file just falls through to the existing ESM-only diff --git a/crates/perry/src/commands/compile/cjs_wrap/extract_requires.rs b/crates/perry/src/commands/compile/cjs_wrap/extract_requires.rs index a0a8a3de6c..c57efbb0d6 100644 --- a/crates/perry/src/commands/compile/cjs_wrap/extract_requires.rs +++ b/crates/perry/src/commands/compile/cjs_wrap/extract_requires.rs @@ -1,7 +1,5 @@ //! `require(...)` specifier extraction and alias detection. -use super::*; - /// Extract `require('X')` / `require("X")` specifiers, preserving order and /// deduping. Only matches static string literal arguments — dynamic /// `require(someVar)` is unrepresentable as ESM and the bound `require` diff --git a/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs b/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs index 494c04bc35..3ff27f67ca 100644 --- a/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs +++ b/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs @@ -1,7 +1,5 @@ //! Top-level `class` hoisting and `module.exports = class …` rewrite passes. -use super::*; - /// Issue #665 (fifth pass): rewrite the leaf-file shape /// `module.exports = class Name { ... };` into declaration form /// `class Name { ... }\nmodule.exports = Name;` so the existing diff --git a/crates/perry/src/commands/compile/collect_modules.rs b/crates/perry/src/commands/compile/collect_modules.rs index 7a8811d037..02eb09fc9b 100644 --- a/crates/perry/src/commands/compile/collect_modules.rs +++ b/crates/perry/src/commands/compile/collect_modules.rs @@ -227,7 +227,7 @@ fn collect_module_one( target: Option<&str>, next_class_id: &mut perry_hir::ClassId, progress: &VerboseProgress, - mut parse_cache: Option<&mut ParseCache>, + parse_cache: Option<&mut ParseCache>, ) -> Result { let mut pending = Vec::new(); diff --git a/crates/perry/src/commands/compile/helpers.rs b/crates/perry/src/commands/compile/helpers.rs index 380b3732bc..51b816cb03 100644 --- a/crates/perry/src/commands/compile/helpers.rs +++ b/crates/perry/src/commands/compile/helpers.rs @@ -7,13 +7,9 @@ use super::*; -use anyhow::{anyhow, Result}; -use rayon::prelude::*; -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; -use std::fs; +use anyhow::Result; +use std::collections::HashMap; use std::path::{Path, PathBuf}; -use std::process::Command; -use std::sync::atomic::{AtomicUsize, Ordering}; use crate::OutputFormat; diff --git a/crates/perry/src/commands/compile/optimized_libs.rs b/crates/perry/src/commands/compile/optimized_libs.rs index 18849b2559..5077afc3d1 100644 --- a/crates/perry/src/commands/compile/optimized_libs.rs +++ b/crates/perry/src/commands/compile/optimized_libs.rs @@ -12,16 +12,9 @@ //! profile are no-ops after the first build. use std::collections::BTreeSet; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::time::SystemTime; +use std::path::PathBuf; -use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; -use crate::OutputFormat; - -use super::library_search::{find_harmonyos_sdk, harmonyos_cross_env}; -use super::{find_perry_workspace_root, rust_target_triple, CompilationContext}; +use super::CompilationContext; mod driver; mod freshness; @@ -34,9 +27,7 @@ pub(crate) use freshness::{ auto_optimized_cross_features, auto_optimized_source_fingerprint, binding_needs_shared_tokio, resolve_auto_well_known_libs, }; -pub(crate) use no_auto::{ - build_missing_prebuilt_ext_lib, resolve_no_auto_optimized_libs, resolve_prebuilt_ext_libs, -}; +pub(crate) use no_auto::{resolve_no_auto_optimized_libs, resolve_prebuilt_ext_libs}; pub(crate) use paths::{ android_global_dynamic_tls_rustflag, auto_target_dir_paths, cargo_target_dir_path, }; diff --git a/crates/perry/src/commands/compile/optimized_libs/driver.rs b/crates/perry/src/commands/compile/optimized_libs/driver.rs index fcb13e09e5..efecb04803 100644 --- a/crates/perry/src/commands/compile/optimized_libs/driver.rs +++ b/crates/perry/src/commands/compile/optimized_libs/driver.rs @@ -1,10 +1,7 @@ use super::*; -use std::collections::BTreeSet; -use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process::Command; -use std::time::SystemTime; use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; use crate::OutputFormat; diff --git a/crates/perry/src/commands/compile/optimized_libs/freshness.rs b/crates/perry/src/commands/compile/optimized_libs/freshness.rs index 25721af4d5..4bb2a9f114 100644 --- a/crates/perry/src/commands/compile/optimized_libs/freshness.rs +++ b/crates/perry/src/commands/compile/optimized_libs/freshness.rs @@ -1,16 +1,11 @@ -use super::*; - use std::collections::BTreeSet; use std::fs; use std::path::{Path, PathBuf}; -use std::process::Command; use std::time::SystemTime; -use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; use crate::OutputFormat; -use super::super::library_search::{find_harmonyos_sdk, harmonyos_cross_env}; -use super::super::{find_perry_workspace_root, rust_target_triple, CompilationContext}; +use super::super::{rust_target_triple, CompilationContext}; pub(crate) fn auto_optimized_archives_are_fresh( workspace_root: &Path, diff --git a/crates/perry/src/commands/compile/optimized_libs/no_auto.rs b/crates/perry/src/commands/compile/optimized_libs/no_auto.rs index c821ca30bc..73c608bb3a 100644 --- a/crates/perry/src/commands/compile/optimized_libs/no_auto.rs +++ b/crates/perry/src/commands/compile/optimized_libs/no_auto.rs @@ -1,15 +1,10 @@ use super::*; -use std::collections::BTreeSet; -use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use std::time::SystemTime; -use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; use crate::OutputFormat; -use super::super::library_search::{find_harmonyos_sdk, harmonyos_cross_env}; use super::super::{find_perry_workspace_root, rust_target_triple, CompilationContext}; /// Resolve well-known wrapper archives without rebuilding runtime/stdlib. diff --git a/crates/perry/src/commands/compile/optimized_libs/paths.rs b/crates/perry/src/commands/compile/optimized_libs/paths.rs index 5fdc1b26bf..601a965596 100644 --- a/crates/perry/src/commands/compile/optimized_libs/paths.rs +++ b/crates/perry/src/commands/compile/optimized_libs/paths.rs @@ -1,16 +1,5 @@ -use super::*; - -use std::collections::BTreeSet; -use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use std::time::SystemTime; - -use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; -use crate::OutputFormat; - -use super::super::library_search::{find_harmonyos_sdk, harmonyos_cross_env}; -use super::super::{find_perry_workspace_root, rust_target_triple, CompilationContext}; /// (#1529) Android's `libperry_app.so` is loaded via `dlopen`, so its TLS /// relocations must use the global-dynamic model — the aarch64-linux-android diff --git a/crates/perry/src/commands/compile/optimized_libs/tests.rs b/crates/perry/src/commands/compile/optimized_libs/tests.rs index a523e7559d..da03ad5197 100644 --- a/crates/perry/src/commands/compile/optimized_libs/tests.rs +++ b/crates/perry/src/commands/compile/optimized_libs/tests.rs @@ -1,5 +1,6 @@ +use super::no_auto::build_missing_prebuilt_ext_lib; use super::*; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::sync::{Mutex, OnceLock}; use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; diff --git a/crates/perry/src/commands/compile/run_pipeline.rs b/crates/perry/src/commands/compile/run_pipeline.rs index ff839fd55c..1a01246d8e 100644 --- a/crates/perry/src/commands/compile/run_pipeline.rs +++ b/crates/perry/src/commands/compile/run_pipeline.rs @@ -8,7 +8,6 @@ use super::*; use anyhow::{anyhow, bail, Context, Result}; -use rayon::prelude::*; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fs; use std::path::{Path, PathBuf}; From ebdf7daad8752f8d882649237c0e012e92239593 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:08:30 +0200 Subject: [PATCH 02/18] chore(warnings): drop 150 redundant `unsafe` blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rustc reports these as `unused_unsafe`: the block wraps code that needs no unsafe context, so the marker hides the sites that do. rustc gives no machine-applicable fix, so this was scripted off the diagnostic byte spans. Where the block only held expressions or statements, the block goes with the keyword. Where it held a top-level `let`, `use`, or item, only the keyword goes and the braces stay — splicing those into the enclosing scope would widen the binding and could silently re-resolve a later name. 106 blocks removed, 44 kept as plain scoping blocks. --- crates/perry-runtime/src/array/from_concat.rs | 10 +- crates/perry-runtime/src/array/push_pop.rs | 2 +- crates/perry-runtime/src/buffer/from.rs | 4 +- crates/perry-runtime/src/buffer/mutate.rs | 2 +- .../perry-runtime/src/builtins/formatting.rs | 2 +- .../src/builtins/formatting/util_format.rs | 2 +- crates/perry-runtime/src/builtins/globals.rs | 2 +- crates/perry-runtime/src/builtins/numbers.rs | 2 +- .../src/child_process/v8_serde.rs | 8 +- .../src/closure/dispatch/bound.rs | 2 +- .../src/closure/dynamic_props.rs | 4 +- crates/perry-runtime/src/error.rs | 22 +- crates/perry-runtime/src/fs/fd_ops.rs | 8 +- crates/perry-runtime/src/fs/mod.rs | 4 +- crates/perry-runtime/src/gc/heap_snapshot.rs | 2 +- .../perry-runtime/src/gc/tests/cycle_state.rs | 32 ++- crates/perry-runtime/src/gc/verify.rs | 4 +- .../perry-runtime/src/intl/number_format.rs | 2 +- .../src/node_submodules/diagnostics.rs | 4 +- .../perry-runtime/src/node_submodules/mod.rs | 8 +- crates/perry-runtime/src/node_v8.rs | 16 +- crates/perry-runtime/src/object/assert.rs | 4 +- .../src/object/class_registry/class_meta.rs | 2 +- .../src/object/class_registry/registration.rs | 10 +- .../perry-runtime/src/object/delete_rest.rs | 2 +- .../src/object/field_get_set/enumeration.rs | 8 +- .../object/field_get_set/get_field_by_name.rs | 2 +- .../src/object/field_get_set/has_property.rs | 2 +- .../src/object/field_get_set/ic_miss.rs | 2 +- .../src/object/global_this/bigint_promise.rs | 6 +- .../src/object/map_set_subclass.rs | 144 ++++++------- .../src/object/native_module/constants.rs | 2 +- .../object/object_ops/define_properties.rs | 7 +- crates/perry-runtime/src/object/tests.rs | 10 +- crates/perry-runtime/src/object/util_types.rs | 8 +- crates/perry-runtime/src/object/with_env.rs | 2 +- crates/perry-runtime/src/perf_hooks.rs | 21 +- crates/perry-runtime/src/plugin.rs | 32 ++- crates/perry-runtime/src/pointer_event.rs | 10 +- .../perry-runtime/src/process/credentials.rs | 4 +- crates/perry-runtime/src/regex.rs | 2 +- crates/perry-runtime/src/regex/tests.rs | 4 +- crates/perry-runtime/src/safe_area.rs | 8 +- crates/perry-runtime/src/string/compare.rs | 12 +- .../src/string/tests_guard_page.rs | 2 +- crates/perry-runtime/src/tty.rs | 204 +++++++++--------- crates/perry-runtime/src/url/search_params.rs | 6 +- crates/perry-runtime/src/util_promisify.rs | 5 +- crates/perry-runtime/src/weakref.rs | 8 +- crates/perry-stdlib/src/commander.rs | 2 +- crates/perry-stdlib/src/fetch/dispatch.rs | 9 +- crates/perry-stdlib/src/http.rs | 12 +- crates/perry-stdlib/src/querystring.rs | 6 +- crates/perry-stdlib/src/streams/transform.rs | 2 +- crates/perry-stdlib/src/tls.rs | 4 +- crates/perry-stdlib/src/zlib.rs | 2 +- crates/perry-ui-macos/src/app.rs | 2 +- crates/perry-ui-macos/src/widgets/hstack.rs | 14 +- crates/perry-ui-macos/src/widgets/mod.rs | 16 +- crates/perry-ui-macos/src/widgets/vstack.rs | 14 +- 60 files changed, 352 insertions(+), 402 deletions(-) diff --git a/crates/perry-runtime/src/array/from_concat.rs b/crates/perry-runtime/src/array/from_concat.rs index d3ed84bfd1..63f030f5de 100644 --- a/crates/perry-runtime/src/array/from_concat.rs +++ b/crates/perry-runtime/src/array/from_concat.rs @@ -524,12 +524,10 @@ fn items_is_iterable(items: f64) -> bool { } // A bare iterator / generator object exposes a callable `next`. let next_key = crate::string::js_string_from_bytes(b"next".as_ptr(), 4); - let next_val = unsafe { - crate::object::js_object_get_field_by_name( - raw as *const crate::object::ObjectHeader, - next_key, - ) - }; + let next_val = crate::object::js_object_get_field_by_name( + raw as *const crate::object::ObjectHeader, + next_key, + ); if next_val.is_undefined() { return false; } diff --git a/crates/perry-runtime/src/array/push_pop.rs b/crates/perry-runtime/src/array/push_pop.rs index 15cb382948..2c6345a53b 100644 --- a/crates/perry-runtime/src/array/push_pop.rs +++ b/crates/perry-runtime/src/array/push_pop.rs @@ -400,7 +400,7 @@ pub extern "C" fn js_array_set_length_strict(arr: *mut ArrayHeader, new_length: if arr.is_null() { return; } - if unsafe { array_object_flags(arr) } & crate::gc::OBJ_FLAG_FROZEN != 0 { + if array_object_flags(arr) & crate::gc::OBJ_FLAG_FROZEN != 0 { throw_non_writable_length(); } js_array_set_length(arr, new_length); diff --git a/crates/perry-runtime/src/buffer/from.rs b/crates/perry-runtime/src/buffer/from.rs index 67eaa88d34..1ff26a2654 100644 --- a/crates/perry-runtime/src/buffer/from.rs +++ b/crates/perry-runtime/src/buffer/from.rs @@ -955,7 +955,7 @@ fn throw_buffer_alloc_size_out_of_range() -> ! { crate::object::js_register_class_extends_error(crate::error::CLASS_ID_RANGE_ERROR); }); let obj = crate::object::js_object_alloc(crate::error::CLASS_ID_RANGE_ERROR, 4); - unsafe { + { let set = |key: &[u8], value: f64| { let key_ptr = crate::string::js_string_from_bytes(key.as_ptr(), key.len() as u32); crate::object::js_object_set_field_by_name(obj, key_ptr, value); @@ -1218,7 +1218,7 @@ fn throw_buffer_concat_invalid_arg_type(index: usize, element: f64) -> ! { }); let obj = crate::object::js_object_alloc(crate::error::CLASS_ID_TYPE_ERROR, 4); - unsafe { + { let set = |key: &[u8], value: f64| { let key_ptr = crate::string::js_string_from_bytes(key.as_ptr(), key.len() as u32); crate::object::js_object_set_field_by_name(obj, key_ptr, value); diff --git a/crates/perry-runtime/src/buffer/mutate.rs b/crates/perry-runtime/src/buffer/mutate.rs index 5ce3a5e554..69c4b92ee4 100644 --- a/crates/perry-runtime/src/buffer/mutate.rs +++ b/crates/perry-runtime/src/buffer/mutate.rs @@ -6,7 +6,7 @@ fn throw_invalid_buffer_size() -> ! { crate::object::js_register_class_extends_error(crate::error::CLASS_ID_RANGE_ERROR); }); let obj = crate::object::js_object_alloc(crate::error::CLASS_ID_RANGE_ERROR, 4); - unsafe { + { let set = |key: &[u8], value: f64| { let key_ptr = crate::string::js_string_from_bytes(key.as_ptr(), key.len() as u32); crate::object::js_object_set_field_by_name(obj, key_ptr, value); diff --git a/crates/perry-runtime/src/builtins/formatting.rs b/crates/perry-runtime/src/builtins/formatting.rs index 50916b0bec..f1ae5ba214 100644 --- a/crates/perry-runtime/src/builtins/formatting.rs +++ b/crates/perry-runtime/src/builtins/formatting.rs @@ -1531,7 +1531,7 @@ fn format_accessor_property(acc: crate::object::AccessorDescriptor, depth: usize let closure = (acc.get & crate::value::POINTER_MASK) as *const crate::closure::ClosureHeader; if !closure.is_null() { - let value = unsafe { crate::closure::js_closure_call0(closure) }; + let value = crate::closure::js_closure_call0(closure); return format!("[{}: {}]", label, format_jsvalue_for_json(value, depth + 1)); } } diff --git a/crates/perry-runtime/src/builtins/formatting/util_format.rs b/crates/perry-runtime/src/builtins/formatting/util_format.rs index eeb93b77f7..cb37ff5023 100644 --- a/crates/perry-runtime/src/builtins/formatting/util_format.rs +++ b/crates/perry-runtime/src/builtins/formatting/util_format.rs @@ -316,7 +316,7 @@ pub extern "C" fn js_util_format(arr_ptr: *const crate::array::ArrayHeader) -> f } } b'j' => { - unsafe { + { if util_format_json_arg_has_cycle(val) { out.push_str("[Circular]"); i += 2; diff --git a/crates/perry-runtime/src/builtins/globals.rs b/crates/perry-runtime/src/builtins/globals.rs index 5961cc498e..859bd87fe7 100644 --- a/crates/perry-runtime/src/builtins/globals.rs +++ b/crates/perry-runtime/src/builtins/globals.rs @@ -1174,7 +1174,7 @@ mod structured_clone_tests { /// `{}`-born objects with no inline capacity) must survive structuredClone. #[test] fn structured_clone_keeps_overflow_properties() { - unsafe { + { let src = crate::object::js_object_alloc(0, 0); let mut names = Vec::new(); for i in 0..50 { diff --git a/crates/perry-runtime/src/builtins/numbers.rs b/crates/perry-runtime/src/builtins/numbers.rs index 821c4ec0fc..73f20e0637 100644 --- a/crates/perry-runtime/src/builtins/numbers.rs +++ b/crates/perry-runtime/src/builtins/numbers.rs @@ -561,7 +561,7 @@ pub extern "C" fn js_number_coerce(value: f64) -> f64 { if crate::array::js_array_is_array(value).to_bits() == TAG_TRUE_BITS { let arr_ptr = jsval.as_pointer::(); let comma = crate::string::js_string_from_bytes(b",".as_ptr(), 1); - let joined = unsafe { crate::array::js_array_join(arr_ptr, comma) }; + let joined = crate::array::js_array_join(arr_ptr, comma); return js_number_coerce(crate::value::js_nanbox_string(joined as i64)); } // TypedArray → OrdinaryToPrimitive(number): a *patched own* diff --git a/crates/perry-runtime/src/child_process/v8_serde.rs b/crates/perry-runtime/src/child_process/v8_serde.rs index f554e812fd..78ebcb52c3 100644 --- a/crates/perry-runtime/src/child_process/v8_serde.rs +++ b/crates/perry-runtime/src/child_process/v8_serde.rs @@ -277,16 +277,18 @@ impl Serializer { fn write_bigint(&mut self, value: f64) { let ptr = JSValue::from_bits(value.to_bits()).as_bigint_ptr(); - let negative = unsafe { crate::bigint::js_bigint_is_negative(ptr) } != 0; + let negative = crate::bigint::js_bigint_is_negative(ptr) != 0; // Read the magnitude as big-endian bytes (negate first if needed), then // reverse to the little-endian order V8's bigint digits use. let mag_ptr = if negative { - unsafe { crate::bigint::js_bigint_neg(ptr) as *const crate::bigint::BigIntHeader } + { + crate::bigint::js_bigint_neg(ptr) as *const crate::bigint::BigIntHeader + } } else { ptr }; let nbytes = crate::bigint::BIGINT_LIMBS * 8; - let be_buf = unsafe { crate::bigint::js_bigint_to_buffer(mag_ptr, nbytes as i32) }; + let be_buf = crate::bigint::js_bigint_to_buffer(mag_ptr, nbytes as i32); let mut le: Vec = if be_buf.is_null() { Vec::new() } else { diff --git a/crates/perry-runtime/src/closure/dispatch/bound.rs b/crates/perry-runtime/src/closure/dispatch/bound.rs index c568999a7e..99c64cb0dd 100644 --- a/crates/perry-runtime/src/closure/dispatch/bound.rs +++ b/crates/perry-runtime/src/closure/dispatch/bound.rs @@ -269,7 +269,7 @@ pub(crate) fn coerce_call_this(target: f64, this_arg: f64) -> f64 { return this_arg; } if std::ptr::eq(unsafe { (*closure).func_ptr }, BOUND_FUNCTION_FUNC_PTR) { - let inner = unsafe { js_closure_get_capture_f64(closure, 0) }; + let inner = js_closure_get_capture_f64(closure, 0); let ij = crate::value::JSValue::from_bits(inner.to_bits()); if !ij.is_pointer() { return this_arg; diff --git a/crates/perry-runtime/src/closure/dynamic_props.rs b/crates/perry-runtime/src/closure/dynamic_props.rs index 08331a3f8d..663f77c0e6 100644 --- a/crates/perry-runtime/src/closure/dynamic_props.rs +++ b/crates/perry-runtime/src/closure/dynamic_props.rs @@ -554,7 +554,7 @@ pub fn closure_get_dynamic_prop(ptr: usize, prop: &str) -> f64 { crate::object::js_implicit_this_set(prev); return result; } - unsafe { + { let key_hdr = crate::string::js_string_from_bytes(prop.as_ptr(), prop.len() as u32); let v = crate::object::js_object_get_field_by_name( proto_ptr as *const crate::object::ObjectHeader, @@ -589,7 +589,7 @@ pub fn closure_get_dynamic_prop(ptr: usize, prop: &str) -> f64 { } return f64::from_bits(crate::value::TAG_UNDEFINED); } - unsafe { + { let key_hdr = crate::string::js_string_from_bytes(prop.as_ptr(), prop.len() as u32); let v = crate::object::js_object_get_field_by_name( proto_ptr as *const crate::object::ObjectHeader, diff --git a/crates/perry-runtime/src/error.rs b/crates/perry-runtime/src/error.rs index 0366565c4c..da91d31e9a 100644 --- a/crates/perry-runtime/src/error.rs +++ b/crates/perry-runtime/src/error.rs @@ -981,7 +981,7 @@ pub extern "C" fn js_global_get_or_throw_unresolved(name_value: f64) -> f64 { let gptr = (gj.bits() & crate::value::POINTER_MASK) as *const crate::object::ObjectHeader; let key = crate::builtins::js_string_coerce(name_value); if !gptr.is_null() && !key.is_null() { - let v = unsafe { crate::object::js_object_get_field_by_name(gptr, key) }; + let v = crate::object::js_object_get_field_by_name(gptr, key); if !v.is_undefined() { return f64::from_bits(v.bits()); } @@ -1032,12 +1032,10 @@ pub extern "C" fn js_global_update(name_value: f64, is_increment: f64, is_prefix let old = if gj.is_pointer() && !key.is_null() { let gptr = (gj.bits() & crate::value::POINTER_MASK) as *const crate::object::ObjectHeader; if !gptr.is_null() { - let v = unsafe { crate::object::js_object_get_field_by_name(gptr, key) }; + let v = crate::object::js_object_get_field_by_name(gptr, key); if !v.is_undefined() - || unsafe { - crate::object::js_object_has_own(g, name_value).to_bits() - == crate::value::TAG_TRUE - } + || crate::object::js_object_has_own(g, name_value).to_bits() + == crate::value::TAG_TRUE { present = true; } @@ -1058,7 +1056,7 @@ pub extern "C" fn js_global_update(name_value: f64, is_increment: f64, is_prefix let numeric = unsafe { crate::value::js_to_numeric(old) }; let stepped = unsafe { crate::value::js_numeric_step(numeric, is_increment) }; let gptr = (gj.bits() & crate::value::POINTER_MASK) as *mut crate::object::ObjectHeader; - unsafe { crate::object::js_object_set_field_by_name(gptr, key, stepped) }; + crate::object::js_object_set_field_by_name(gptr, key, stepped); if is_prefix { stepped } else { @@ -1095,12 +1093,10 @@ pub extern "C" fn js_global_assign_existing_or_throw(name_value: f64, value: f64 if gj.is_pointer() && !key.is_null() { let gptr = (gj.bits() & crate::value::POINTER_MASK) as *const crate::object::ObjectHeader; if !gptr.is_null() { - let v = unsafe { crate::object::js_object_get_field_by_name(gptr, key) }; + let v = crate::object::js_object_get_field_by_name(gptr, key); if !v.is_undefined() - || unsafe { - crate::object::js_object_has_own(g, name_value).to_bits() - == crate::value::TAG_TRUE - } + || crate::object::js_object_has_own(g, name_value).to_bits() + == crate::value::TAG_TRUE { present = true; } @@ -1132,7 +1128,7 @@ pub extern "C" fn js_global_get_optional(name_value: f64) -> f64 { let gptr = (gj.bits() & crate::value::POINTER_MASK) as *const crate::object::ObjectHeader; let key = crate::builtins::js_string_coerce(name_value); if !gptr.is_null() && !key.is_null() { - let v = unsafe { crate::object::js_object_get_field_by_name(gptr, key) }; + let v = crate::object::js_object_get_field_by_name(gptr, key); return f64::from_bits(v.bits()); } } diff --git a/crates/perry-runtime/src/fs/fd_ops.rs b/crates/perry-runtime/src/fs/fd_ops.rs index 74b90b55cc..5c30b4de8d 100644 --- a/crates/perry-runtime/src/fs/fd_ops.rs +++ b/crates/perry-runtime/src/fs/fd_ops.rs @@ -471,8 +471,8 @@ pub extern "C" fn js_fs_readv_sync(fd_value: f64, buffers_value: f64, position_v // common-case `readv(123, [buf])` → `EBADF` parity and leave the // empty-array divergence as a follow-up. let buffers_for_check = array_ptr_from_value(buffers_value); - let buffers_nonempty = !buffers_for_check.is_null() - && unsafe { crate::array::js_array_length(buffers_for_check) } > 0; + let buffers_nonempty = + !buffers_for_check.is_null() && crate::array::js_array_length(buffers_for_check) > 0; if buffers_nonempty { crate::fs::validate::validate_fd_open(fd_value, "read"); } else { @@ -551,8 +551,8 @@ pub extern "C" fn js_fs_writev_sync(fd_value: f64, buffers_value: f64, position_ // own writev returns 0 without touching the fd), validate only when // there's something to write. let buffers_for_check = array_ptr_from_value(buffers_value); - let buffers_nonempty = !buffers_for_check.is_null() - && unsafe { crate::array::js_array_length(buffers_for_check) } > 0; + let buffers_nonempty = + !buffers_for_check.is_null() && crate::array::js_array_length(buffers_for_check) > 0; if buffers_nonempty { // #2013: upgrade from type-only validation to type + EBADF so // `fs.writevSync(123, [buf])` matches Node's diff --git a/crates/perry-runtime/src/fs/mod.rs b/crates/perry-runtime/src/fs/mod.rs index 79c09de14a..6f8422968d 100644 --- a/crates/perry-runtime/src/fs/mod.rs +++ b/crates/perry-runtime/src/fs/mod.rs @@ -1726,7 +1726,7 @@ pub extern "C" fn js_fs_readlink_sync_options(path_value: f64, options_value: f6 let enc = fs_encoding_option(options_value).unwrap_or_else(|| "utf8".to_string()); encoded_string_ptr(&bytes, &enc) as i64 } - Err(err_val) => unsafe { crate::exception::js_throw(err_val) }, + Err(err_val) => crate::exception::js_throw(err_val), } } @@ -1735,7 +1735,7 @@ pub extern "C" fn js_fs_readlink_dispatch(path_value: f64, options_value: f64) - validate::validate_path("path", path_value); match readlink_value_result(path_value, options_value) { Ok(v) => v, - Err(err_val) => unsafe { crate::exception::js_throw(err_val) }, + Err(err_val) => crate::exception::js_throw(err_val), } } diff --git a/crates/perry-runtime/src/gc/heap_snapshot.rs b/crates/perry-runtime/src/gc/heap_snapshot.rs index baf3b3767f..11448c2cf5 100644 --- a/crates/perry-runtime/src/gc/heap_snapshot.rs +++ b/crates/perry-runtime/src/gc/heap_snapshot.rs @@ -505,7 +505,7 @@ mod tests { #[test] fn snapshot_has_real_nodes_and_edges() { // Allocate a recognizable object graph, then snapshot. - unsafe { + { let marker = b"__heap_snapshot_test_marker__"; let key = crate::string::js_string_from_bytes(marker.as_ptr(), marker.len() as u32); let obj = crate::object::js_object_alloc(0, 1); diff --git a/crates/perry-runtime/src/gc/tests/cycle_state.rs b/crates/perry-runtime/src/gc/tests/cycle_state.rs index 3820333d4e..112519b8b3 100644 --- a/crates/perry-runtime/src/gc/tests/cycle_state.rs +++ b/crates/perry-runtime/src/gc/tests/cycle_state.rs @@ -767,14 +767,12 @@ fn born_black_build_phase_object_is_traced() { (*ch).gc_flags &= !GC_FLAG_MARKED; } crate::object::test_seed_overflow_fields_root(child as usize, 7f64.to_bits()); - unsafe { - runtime_store_jsvalue_slot( - parent as usize, - fields as usize, - 0, - ptr_bits(child as usize), - ); - } + runtime_store_jsvalue_slot( + parent as usize, + fields as usize, + 0, + ptr_bits(child as usize), + ); // Age the parent/child block out of the block-persistence window // (BLOCK_PERSIST_WINDOW = 5 recent general blocks get their objects @@ -784,7 +782,7 @@ fn born_black_build_phase_object_is_traced() { let mut filler_blocks = 0usize; while filler_blocks < 7 { for _ in 0..64 { - let _ = unsafe { crate::arena::arena_alloc_gc(4096, 8, GC_TYPE_STRING) }; + let _ = crate::arena::arena_alloc_gc(4096, 8, GC_TYPE_STRING); } filler_blocks = crate::arena::general_block_count().saturating_sub(aged_from); } @@ -844,14 +842,12 @@ fn gap_born_child_stored_between_finalize_and_sweep_survives() { // same way the production failure was (a swept child has its // OVERFLOW_FIELDS entry cleared by the dead-payload sweep arm). crate::object::test_seed_overflow_fields_root(child as usize, 42f64.to_bits()); - unsafe { - runtime_store_jsvalue_slot( - parent as usize, - fields as usize, - 0, - ptr_bits(child as usize), - ); - } + runtime_store_jsvalue_slot( + parent as usize, + fields as usize, + 0, + ptr_bits(child as usize), + ); run_cycle_in_single_unit_steps(&mut state); let _ = state.take_outcome().expect("cycle should complete"); @@ -915,7 +911,7 @@ fn overflow_slots_beyond_layout_mask_are_traced() { let mut filler_blocks = 0usize; while filler_blocks < 7 { for _ in 0..64 { - let _ = unsafe { crate::arena::arena_alloc_gc(4096, 8, GC_TYPE_STRING) }; + let _ = crate::arena::arena_alloc_gc(4096, 8, GC_TYPE_STRING); } filler_blocks = crate::arena::general_block_count().saturating_sub(aged_from); } diff --git a/crates/perry-runtime/src/gc/verify.rs b/crates/perry-runtime/src/gc/verify.rs index fef9e3a241..81b9157f99 100644 --- a/crates/perry-runtime/src/gc/verify.rs +++ b/crates/perry-runtime/src/gc/verify.rs @@ -205,7 +205,7 @@ pub(super) fn restore_surviving_dirty_coverage(snapshot: &RememberedDirtySnapsho { return; } - visit_gc_rewrite_slots(header, |slot| unsafe { + visit_gc_rewrite_slots(header, |slot| { if crate::weakref::is_weak_target_trace_slot(header, slot.slot) { return; } @@ -760,7 +760,7 @@ pub(super) fn verify_minor_unmarked_young_children_report(phase: &str) { return; } checked_parents += 1; - visit_gc_rewrite_slots(header, |slot| unsafe { + visit_gc_rewrite_slots(header, |slot| { if crate::weakref::is_weak_target_trace_slot(header, slot.slot) { return; } diff --git a/crates/perry-runtime/src/intl/number_format.rs b/crates/perry-runtime/src/intl/number_format.rs index 10b783e050..386b4e5a60 100644 --- a/crates/perry-runtime/src/intl/number_format.rs +++ b/crates/perry-runtime/src/intl/number_format.rs @@ -1144,7 +1144,7 @@ fn bigint_number_parts_exact( /// where both are lossy for BigInts past 2^53. pub(crate) fn bigint_to_locale_string(value: f64, locales: f64, options: f64) -> *mut StringHeader { let ptr = JSValue::from_bits(value.to_bits()).as_bigint_ptr(); - let negative = unsafe { crate::bigint::js_bigint_is_negative(ptr) } != 0; + let negative = crate::bigint::js_bigint_is_negative(ptr) != 0; let digits_ptr = crate::bigint::js_bigint_to_string(ptr); // Copy into an owned `String` right away — `digits_ptr` is GC-managed and // `make_instance` below allocates, which can move/free it. diff --git a/crates/perry-runtime/src/node_submodules/diagnostics.rs b/crates/perry-runtime/src/node_submodules/diagnostics.rs index e5dae3768f..0f23f8ffcd 100644 --- a/crates/perry-runtime/src/node_submodules/diagnostics.rs +++ b/crates/perry-runtime/src/node_submodules/diagnostics.rs @@ -694,14 +694,14 @@ pub(crate) fn closure_ptr(v: f64) -> *const ClosureHeader { } pub(crate) fn set_field_value(obj: *mut ObjectHeader, name: &str, value: f64) { - unsafe { + { let key = js_string_from_bytes(name.as_bytes().as_ptr(), name.len() as u32); js_object_set_field_by_name(obj, key, value); } } pub(crate) fn get_field_value(obj: *mut ObjectHeader, name: &str) -> f64 { - unsafe { + { let key = js_string_from_bytes(name.as_bytes().as_ptr(), name.len() as u32); js_object_get_field_by_name_f64(obj, key) } diff --git a/crates/perry-runtime/src/node_submodules/mod.rs b/crates/perry-runtime/src/node_submodules/mod.rs index e347833c66..7614e325c6 100644 --- a/crates/perry-runtime/src/node_submodules/mod.rs +++ b/crates/perry-runtime/src/node_submodules/mod.rs @@ -1237,9 +1237,7 @@ fn fs_promises_constants_value() -> f64 { fn set_named_value(obj: *mut ObjectHeader, name: &str, value: f64) { let name_bytes = name.as_bytes(); let name_header = js_string_from_bytes(name_bytes.as_ptr(), name_bytes.len() as u32); - unsafe { - crate::object::js_object_set_field_by_name(obj, name_header, value); - } + crate::object::js_object_set_field_by_name(obj, name_header, value); } fn submodule_export_value(submod: &'static SubmoduleSpec, spec: &'static ExportSpec) -> f64 { @@ -1341,9 +1339,7 @@ fn ensure_namespace_singleton(submod: &'static SubmoduleSpec) -> *mut ObjectHead let value = value_from_ptr(obj as *const u8); let name = b"default"; let name_header = js_string_from_bytes(name.as_ptr(), name.len() as u32); - unsafe { - crate::object::js_object_set_field_by_name(obj, name_header, value); - } + crate::object::js_object_set_field_by_name(obj, name_header, value); } if submod.key == "timers" { let value = crate::object::timers_promises_parent_namespace(); diff --git a/crates/perry-runtime/src/node_v8.rs b/crates/perry-runtime/src/node_v8.rs index b6bdd53065..aef4719a98 100644 --- a/crates/perry-runtime/src/node_v8.rs +++ b/crates/perry-runtime/src/node_v8.rs @@ -405,7 +405,7 @@ pub(crate) fn v8_instance_id_from_value(val: f64) -> usize { if !jsv.is_pointer() { return 0; } - unsafe { + { let obj = (val.to_bits() & crate::value::POINTER_MASK) as *mut ObjectHeader; let f = crate::object::js_object_get_field(obj, 1); if f.is_number() { @@ -533,7 +533,7 @@ pub(crate) fn v8_deserializer_read_uint64(recv: f64) -> f64 { // Node returns `[hi, lo]`. let (hi, lo) = crate::child_process::v8_class_deserializer_read_uint64(v8_instance_id_from_value(recv)); - unsafe { + { let arr = crate::array::js_array_alloc(2); crate::array::js_array_push_f64(arr, hi as f64); crate::array::js_array_push_f64(arr, lo as f64); @@ -626,7 +626,7 @@ pub extern "C" fn js_v8_promise_hook_register() -> f64 { /// `new v8.GCProfiler()` → fresh profiler object. #[no_mangle] pub extern "C" fn js_v8_gc_profiler_new() -> f64 { - unsafe { + { let module = "v8.GCProfiler"; crate::object::install_native_module_vtable(); let obj = crate::object::js_object_alloc(crate::object::NATIVE_MODULE_CLASS_ID, 2); @@ -659,9 +659,7 @@ fn gc_profiler_object(recv: f64) -> Option<*mut ObjectHeader> { #[no_mangle] pub extern "C" fn js_v8_gc_profiler_start(recv: f64) -> f64 { if let Some(obj) = gc_profiler_object(recv) { - unsafe { - crate::object::js_object_set_field(obj, 1, JSValue::bool(true)); - } + crate::object::js_object_set_field(obj, 1, JSValue::bool(true)); } undefined() } @@ -672,13 +670,11 @@ pub extern "C" fn js_v8_gc_profiler_stop(recv: f64) -> f64 { let Some(obj) = gc_profiler_object(recv) else { return undefined(); }; - let started = unsafe { crate::object::js_object_get_field(obj, 1) }; + let started = crate::object::js_object_get_field(obj, 1); if !started.is_bool() || !started.as_bool() { return undefined(); } - unsafe { - crate::object::js_object_set_field(obj, 1, JSValue::bool(false)); - } + crate::object::js_object_set_field(obj, 1, JSValue::bool(false)); js_v8_gc_profiler_report() } diff --git a/crates/perry-runtime/src/object/assert.rs b/crates/perry-runtime/src/object/assert.rs index 88f243d71c..f2ba8a5334 100644 --- a/crates/perry-runtime/src/object/assert.rs +++ b/crates/perry-runtime/src/object/assert.rs @@ -394,7 +394,7 @@ fn make_assertion_error( js_register_class_extends_error(crate::error::CLASS_ID_ASSERTION_ERROR); }); let obj = js_object_alloc(crate::error::CLASS_ID_ASSERTION_ERROR, 8); - unsafe { + { let set = |key: &str, value: f64| { let key_ptr = crate::string::js_string_from_bytes(key.as_ptr(), key.len() as u32); js_object_set_field_by_name(obj, key_ptr, value); @@ -1219,7 +1219,7 @@ pub extern "C" fn js_assert_assertion_error_ctor(options: f64) -> f64 { ); crate::fs::validate::throw_type_error_with_code(&message, "ERR_INVALID_ARG_TYPE"); } - unsafe { + { let read = |key: &str| -> f64 { let key_ptr = crate::string::js_string_from_bytes(key.as_ptr(), key.len() as u32); let obj_ptr = diff --git a/crates/perry-runtime/src/object/class_registry/class_meta.rs b/crates/perry-runtime/src/object/class_registry/class_meta.rs index 3f2e34f827..a49ea72750 100644 --- a/crates/perry-runtime/src/object/class_registry/class_meta.rs +++ b/crates/perry-runtime/src/object/class_registry/class_meta.rs @@ -318,7 +318,7 @@ pub(crate) fn identify_global_builtin_constructor(func_value: f64) -> Option<&'s } for name in GLOBAL_THIS_BUILTIN_CONSTRUCTORS.iter().copied() { let key = crate::string::js_string_from_bytes(name.as_ptr(), name.len() as u32); - let v = unsafe { js_object_get_field_by_name(global_obj, key) }; + let v = js_object_get_field_by_name(global_obj, key); if v.bits() == jv.bits() { return Some(name); } diff --git a/crates/perry-runtime/src/object/class_registry/registration.rs b/crates/perry-runtime/src/object/class_registry/registration.rs index 8a938c968a..6369cad8f5 100644 --- a/crates/perry-runtime/src/object/class_registry/registration.rs +++ b/crates/perry-runtime/src/object/class_registry/registration.rs @@ -109,7 +109,7 @@ pub(crate) fn class_own_static_accessor_ptrs(class_id: u32, name: &str) -> Optio /// closure calling convention. The receiver comes from `IMPLICIT_THIS`, set /// by the method-call dispatch the closure value travels through. extern "C" fn class_accessor_getter_thunk(closure: *const crate::closure::ClosureHeader) -> f64 { - let raw = unsafe { crate::closure::js_closure_get_capture_ptr(closure, 0) } as usize; + let raw = crate::closure::js_closure_get_capture_ptr(closure, 0) as usize; if raw == 0 { return f64::from_bits(crate::value::TAG_UNDEFINED); } @@ -123,7 +123,7 @@ extern "C" fn class_accessor_setter_thunk( closure: *const crate::closure::ClosureHeader, value: f64, ) -> f64 { - let raw = unsafe { crate::closure::js_closure_get_capture_ptr(closure, 0) } as usize; + let raw = crate::closure::js_closure_get_capture_ptr(closure, 0) as usize; if raw == 0 { return f64::from_bits(crate::value::TAG_UNDEFINED); } @@ -156,7 +156,7 @@ pub(crate) fn class_accessor_function_value( if closure.is_null() { return f64::from_bits(crate::value::TAG_UNDEFINED); } - unsafe { crate::closure::js_closure_set_capture_ptr(closure, 0, raw_ptr as i64) }; + crate::closure::js_closure_set_capture_ptr(closure, 0, raw_ptr as i64); // Spec `.length`: params before the first default/rest. A getter takes no // params (0); a setter takes exactly one formal param — but `set m(x = 42)` // has `.length === 0` (defaults don't count). Codegen registers the raw @@ -176,9 +176,7 @@ pub(crate) fn class_accessor_function_value( let fn_name = format!("{prefix}{prop_name}"); let name_ptr = crate::string::js_string_from_bytes(fn_name.as_ptr(), fn_name.len() as u32); let name_value = f64::from_bits(crate::value::JSValue::string_ptr(name_ptr).bits()); - unsafe { - crate::closure::closure_set_dynamic_prop(closure as usize, "name", name_value); - } + crate::closure::closure_set_dynamic_prop(closure as usize, "name", name_value); crate::object::set_builtin_property_attrs( closure as usize, "name".to_string(), diff --git a/crates/perry-runtime/src/object/delete_rest.rs b/crates/perry-runtime/src/object/delete_rest.rs index 43d2bf97fb..ac5c5c975f 100644 --- a/crates/perry-runtime/src/object/delete_rest.rs +++ b/crates/perry-runtime/src/object/delete_rest.rs @@ -595,7 +595,7 @@ mod sso_tests_1781 { /// vacuously") and the property stayed put. #[test] fn delete_dynamic_removes_property_via_sso_key() { - unsafe { + { let obj = crate::object::js_object_alloc(0, 0); let key = crate::string::js_string_from_bytes(b"id".as_ptr(), 2); crate::object::js_object_set_field_by_name(obj, key, 42.0); diff --git a/crates/perry-runtime/src/object/field_get_set/enumeration.rs b/crates/perry-runtime/src/object/field_get_set/enumeration.rs index 8a729dbf03..82cde1f4ad 100644 --- a/crates/perry-runtime/src/object/field_get_set/enumeration.rs +++ b/crates/perry-runtime/src/object/field_get_set/enumeration.rs @@ -76,9 +76,7 @@ pub extern "C" fn js_object_keys_value(value: f64) -> *mut ArrayHeader { if jv.is_any_string() { let mut scratch = [0u8; crate::value::SHORT_STRING_MAX_LEN]; let len = match crate::string::str_bytes_from_jsvalue(value, &mut scratch) { - Some((ptr, blen)) if !ptr.is_null() => unsafe { - crate::string::compute_utf16_len(ptr, blen) - }, + Some((ptr, blen)) if !ptr.is_null() => crate::string::compute_utf16_len(ptr, blen), _ => 0, }; let arr = crate::array::js_array_alloc(len.max(1)); @@ -93,9 +91,7 @@ pub extern "C" fn js_object_keys_value(value: f64) -> *mut ArrayHeader { if let Some((_, payload)) = crate::builtins::boxed_primitive_payload(value) { let mut scratch = [0u8; crate::value::SHORT_STRING_MAX_LEN]; let len = match crate::string::str_bytes_from_jsvalue(payload, &mut scratch) { - Some((ptr, blen)) if !ptr.is_null() => unsafe { - crate::string::compute_utf16_len(ptr, blen) - }, + Some((ptr, blen)) if !ptr.is_null() => crate::string::compute_utf16_len(ptr, blen), _ => 0, }; let arr = crate::array::js_array_alloc(len.max(1)); diff --git a/crates/perry-runtime/src/object/field_get_set/get_field_by_name.rs b/crates/perry-runtime/src/object/field_get_set/get_field_by_name.rs index f8b5c0f679..c7e10d73f3 100644 --- a/crates/perry-runtime/src/object/field_get_set/get_field_by_name.rs +++ b/crates/perry-runtime/src/object/field_get_set/get_field_by_name.rs @@ -1423,7 +1423,7 @@ mod null_key_guard_5972 { /// SIGSEGV by dereferencing `(*key).byte_len` at offset 4. #[test] fn null_key_returns_undefined_not_segfault() { - unsafe { + { let obj = crate::object::js_object_alloc(0, 0); let key = crate::string::js_string_from_bytes(b"present".as_ptr(), 7); crate::object::js_object_set_field_by_name(obj, key, 42.0); diff --git a/crates/perry-runtime/src/object/field_get_set/has_property.rs b/crates/perry-runtime/src/object/field_get_set/has_property.rs index 3ba3aad245..3998ab10f6 100644 --- a/crates/perry-runtime/src/object/field_get_set/has_property.rs +++ b/crates/perry-runtime/src/object/field_get_set/has_property.rs @@ -554,7 +554,7 @@ pub extern "C" fn js_object_has_property(obj: f64, key: f64) -> f64 { // (bounds) and the own/inherited members property-get can resolve. if crate::buffer::is_registered_buffer(obj_addr as usize) { let buf = obj_addr as *const crate::buffer::BufferHeader; - let len = unsafe { crate::buffer::js_buffer_length(buf) }; + let len = crate::buffer::js_buffer_length(buf); if key_val.is_int32() { let idx = key_val.as_int32(); return if idx >= 0 && idx < len { diff --git a/crates/perry-runtime/src/object/field_get_set/ic_miss.rs b/crates/perry-runtime/src/object/field_get_set/ic_miss.rs index dec68ccd0c..2d13ff7ac4 100644 --- a/crates/perry-runtime/src/object/field_get_set/ic_miss.rs +++ b/crates/perry-runtime/src/object/field_get_set/ic_miss.rs @@ -611,7 +611,7 @@ mod sso_tests_1781 { /// SSO lookup key lets js_string_equals match). #[test] fn in_operator_finds_object_key_via_sso_lookup() { - unsafe { + { let obj = crate::object::js_object_alloc(0, 0); let key = crate::string::js_string_from_bytes(b"id".as_ptr(), 2); crate::object::js_object_set_field_by_name(obj, key, 42.0); diff --git a/crates/perry-runtime/src/object/global_this/bigint_promise.rs b/crates/perry-runtime/src/object/global_this/bigint_promise.rs index b369a7e912..da3b9dd67f 100644 --- a/crates/perry-runtime/src/object/global_this/bigint_promise.rs +++ b/crates/perry-runtime/src/object/global_this/bigint_promise.rs @@ -272,7 +272,7 @@ fn bigint_to_bigint_arg(value: f64) -> f64 { if crate::array::js_array_is_array(value).to_bits() == TAG_TRUE_BITS { let arr_ptr = jv.as_pointer::(); let comma = crate::string::js_string_from_bytes(b",".as_ptr(), 1); - let joined = unsafe { crate::array::js_array_join(arr_ptr, comma) }; + let joined = crate::array::js_array_join(arr_ptr, comma); return bigint_to_bigint_arg(crate::value::js_nanbox_string(joined as i64)); } // Object: ToPrimitive("number") then re-coerce. Try a custom @@ -629,7 +629,7 @@ pub(crate) extern "C" fn typed_array_from_thunk( ) }); let ta_ptr = addr as *mut crate::typedarray::TypedArrayHeader; - let target_len = unsafe { crate::typedarray::js_typed_array_length(ta_ptr) } as usize; + let target_len = crate::typedarray::js_typed_array_length(ta_ptr) as usize; if target_len < len { super::super::object_ops::throw_object_type_error( b"Derived TypedArray constructor created an array which was too small", @@ -709,7 +709,7 @@ fn typed_array_create_from_values( ) }); let ta_ptr = addr as *mut crate::typedarray::TypedArrayHeader; - let target_len = unsafe { crate::typedarray::js_typed_array_length(ta_ptr) } as usize; + let target_len = crate::typedarray::js_typed_array_length(ta_ptr) as usize; if target_len < len { // `TypedArrayCreate(C, «len»)` throws a *TypeError* (not RangeError) // when the constructed typed array is shorter than the requested length diff --git a/crates/perry-runtime/src/object/map_set_subclass.rs b/crates/perry-runtime/src/object/map_set_subclass.rs index 2cbb42cfe8..cd5deec60d 100644 --- a/crates/perry-runtime/src/object/map_set_subclass.rs +++ b/crates/perry-runtime/src/object/map_set_subclass.rs @@ -171,80 +171,78 @@ pub(crate) fn super_collection_method(this_value: f64, name: &str, args: &[f64]) let this_handle = scope.root_nanbox_f64(this_value); let boxed = |ptr: i64| f64::from_bits(JSValue::pointer(ptr as *const u8).bits()); let boolean = |b: bool| f64::from_bits(JSValue::bool(b).bits()); - unsafe { - match backing { - CollectionBacking::Map(map) => match name { - "get" => Some(crate::map::js_map_get(map, *args.first()?)), - "set" => { - let key = *args.first()?; - let value = args.get(1).copied().unwrap_or(undefined); - crate::map::js_map_set(map, key, value); - Some(this_handle.get_nanbox_f64()) - } - "has" => Some(boolean(crate::map::js_map_has(map, *args.first()?) != 0)), - "delete" => Some(boolean(crate::map::js_map_delete(map, *args.first()?) != 0)), - "clear" => { - crate::map::js_map_clear(map); - Some(undefined) - } - "forEach" => { - let callback = *args.first()?; - let this_arg = args.get(1).copied().unwrap_or(undefined); - // The callback's 3rd argument must be the SUBCLASS instance, - // not the backing — same receiver-identity rule the ordinary - // dispatch path applies. - crate::map::js_map_foreach_with_collection( - map, - callback, - this_arg, - this_handle.get_nanbox_f64(), - ); - Some(undefined) - } - "keys" => Some(boxed(crate::collection_iter_object::js_map_keys_iter_obj( + match backing { + CollectionBacking::Map(map) => match name { + "get" => Some(crate::map::js_map_get(map, *args.first()?)), + "set" => { + let key = *args.first()?; + let value = args.get(1).copied().unwrap_or(undefined); + crate::map::js_map_set(map, key, value); + Some(this_handle.get_nanbox_f64()) + } + "has" => Some(boolean(crate::map::js_map_has(map, *args.first()?) != 0)), + "delete" => Some(boolean(crate::map::js_map_delete(map, *args.first()?) != 0)), + "clear" => { + crate::map::js_map_clear(map); + Some(undefined) + } + "forEach" => { + let callback = *args.first()?; + let this_arg = args.get(1).copied().unwrap_or(undefined); + // The callback's 3rd argument must be the SUBCLASS instance, + // not the backing — same receiver-identity rule the ordinary + // dispatch path applies. + crate::map::js_map_foreach_with_collection( map, - ))), - "values" => Some(boxed( - crate::collection_iter_object::js_map_values_iter_obj(map), - )), - "entries" | "Symbol.iterator" | "@@iterator" => Some(boxed( - crate::collection_iter_object::js_map_entries_iter_obj(map), - )), - _ => None, - }, - CollectionBacking::Set(set) => match name { - "add" => { - crate::set::js_set_add(set, *args.first()?); - Some(this_handle.get_nanbox_f64()) - } - "has" => Some(boolean(crate::set::js_set_has(set, *args.first()?) != 0)), - "delete" => Some(boolean(crate::set::js_set_delete(set, *args.first()?) != 0)), - "clear" => { - crate::set::js_set_clear(set); - Some(undefined) - } - "forEach" => { - let callback = *args.first()?; - let this_arg = args.get(1).copied().unwrap_or(undefined); - crate::set::js_set_foreach_with_collection( - set, - callback, - this_arg, - this_handle.get_nanbox_f64(), - ); - Some(undefined) - } - // `Set.prototype.keys` is an alias of `values`, and the default - // iterator is `values` — matching the builtin. - "keys" | "values" | "Symbol.iterator" | "@@iterator" => Some(boxed( - crate::collection_iter_object::js_set_values_iter_obj(set), - )), - "entries" => Some(boxed( - crate::collection_iter_object::js_set_entries_iter_obj(set), - )), - _ => None, - }, - } + callback, + this_arg, + this_handle.get_nanbox_f64(), + ); + Some(undefined) + } + "keys" => Some(boxed(crate::collection_iter_object::js_map_keys_iter_obj( + map, + ))), + "values" => Some(boxed( + crate::collection_iter_object::js_map_values_iter_obj(map), + )), + "entries" | "Symbol.iterator" | "@@iterator" => Some(boxed( + crate::collection_iter_object::js_map_entries_iter_obj(map), + )), + _ => None, + }, + CollectionBacking::Set(set) => match name { + "add" => { + crate::set::js_set_add(set, *args.first()?); + Some(this_handle.get_nanbox_f64()) + } + "has" => Some(boolean(crate::set::js_set_has(set, *args.first()?) != 0)), + "delete" => Some(boolean(crate::set::js_set_delete(set, *args.first()?) != 0)), + "clear" => { + crate::set::js_set_clear(set); + Some(undefined) + } + "forEach" => { + let callback = *args.first()?; + let this_arg = args.get(1).copied().unwrap_or(undefined); + crate::set::js_set_foreach_with_collection( + set, + callback, + this_arg, + this_handle.get_nanbox_f64(), + ); + Some(undefined) + } + // `Set.prototype.keys` is an alias of `values`, and the default + // iterator is `values` — matching the builtin. + "keys" | "values" | "Symbol.iterator" | "@@iterator" => Some(boxed( + crate::collection_iter_object::js_set_values_iter_obj(set), + )), + "entries" => Some(boxed( + crate::collection_iter_object::js_set_entries_iter_obj(set), + )), + _ => None, + }, } } diff --git a/crates/perry-runtime/src/object/native_module/constants.rs b/crates/perry-runtime/src/object/native_module/constants.rs index 32d0f69eb7..ecba64d878 100644 --- a/crates/perry-runtime/src/object/native_module/constants.rs +++ b/crates/perry-runtime/src/object/native_module/constants.rs @@ -1588,7 +1588,7 @@ pub(crate) unsafe fn get_native_module_constant( "perf_histogram" => match property { "mean" | "min" | "max" | "stddev" | "exceeds" | "count" => Some(0.0), "percentiles" | "percentilesBigInt" => { - let obj = unsafe { js_object_alloc(0, 0) }; + let obj = js_object_alloc(0, 0); Some(f64::from_bits(JSValue::pointer(obj as *const u8).bits())) } _ => None, diff --git a/crates/perry-runtime/src/object/object_ops/define_properties.rs b/crates/perry-runtime/src/object/object_ops/define_properties.rs index 052852f0eb..6c3f356434 100644 --- a/crates/perry-runtime/src/object/object_ops/define_properties.rs +++ b/crates/perry-runtime/src/object/object_ops/define_properties.rs @@ -24,8 +24,7 @@ pub extern "C" fn js_object_define_properties(target: f64, descriptors: f64) -> let target_is_class_ref = super::super::class_ref_id(target).is_some(); let target_is_handle = { let jv = crate::value::JSValue::from_bits(target.to_bits()); - jv.is_pointer() - && crate::value::addr_class::is_small_handle(unsafe { jv.as_pointer::() } as usize) + jv.is_pointer() && crate::value::addr_class::is_small_handle(jv.as_pointer::() as usize) }; if !target_is_class_ref && !target_is_handle && !unsafe { value_is_object_like(target) } { throw_object_type_error(b"Object.defineProperties called on non-object"); @@ -61,9 +60,9 @@ pub extern "C" fn js_object_define_properties(target: f64, descriptors: f64) -> crate::value::js_nanbox_get_pointer(names_value) as *const crate::array::ArrayHeader; let mut keys: Vec = Vec::new(); if !names_arr.is_null() { - let len = unsafe { crate::array::js_array_length(names_arr) } as usize; + let len = crate::array::js_array_length(names_arr) as usize; for i in 0..len { - let k = unsafe { crate::array::js_array_get(names_arr, i as u32) }; + let k = crate::array::js_array_get(names_arr, i as u32); let k_f64 = f64::from_bits(k.bits()); // Skip non-enumerable own keys (spec step: descriptor must be // enumerable). `propertyIsEnumerable` returns false for absent or diff --git a/crates/perry-runtime/src/object/tests.rs b/crates/perry-runtime/src/object/tests.rs index 8a29517e3f..f01e425706 100644 --- a/crates/perry-runtime/src/object/tests.rs +++ b/crates/perry-runtime/src/object/tests.rs @@ -247,7 +247,7 @@ fn builtin_prototype_methods_reject_dynamic_new() { #[test] fn closure_name_and_length_ignore_plain_assignment() { crate::closure::test_clear_closure_side_tables(); - unsafe { + { let closure = crate::closure::js_closure_alloc( crate::object::global_this_builtin_noop_thunk as *const u8, 0, @@ -281,7 +281,7 @@ fn closure_name_and_length_ignore_plain_assignment() { #[test] fn closure_name_can_be_redefined_with_define_property() { crate::closure::test_clear_closure_side_tables(); - unsafe { + { let closure = crate::closure::js_closure_alloc( crate::object::global_this_builtin_noop_thunk as *const u8, 0, @@ -589,7 +589,7 @@ fn text_encoding_stream_globals_construct_readable_writable_shape() { #[test] fn navigator_global_constructor_identity_shape() { - unsafe { + { let ctor_raw = test_global_this_builtin_constructor_value("Navigator"); let ctor = JSValue::from_bits(ctor_raw.to_bits()); assert!(ctor.is_pointer()); @@ -742,7 +742,7 @@ fn transition_cache_lookup_rejects_grown_shared_target() { fn entries_and_values_skip_non_enumerable_descriptor_slots() { // #5046: Object.defineProperty(o, 'hidden', { value: 1 }) defaults to // enumerable: false. Object.keys filtered it; entries/values did not. - unsafe { + { let obj = js_object_alloc(0, 0); let hidden_key = crate::string::js_string_from_bytes(b"hidden".as_ptr(), 6); let shown_key = crate::string::js_string_from_bytes(b"shown".as_ptr(), 5); @@ -788,7 +788,7 @@ fn entries_and_values_skip_non_enumerable_descriptor_slots() { /// the dynamic-write fast path must still respect descriptors installed later. #[test] fn wide_object_index_reads_and_descriptor_writes() { - unsafe { + { let obj = js_object_alloc(0, 0); let n = 600u32; for i in 0..n { diff --git a/crates/perry-runtime/src/object/util_types.rs b/crates/perry-runtime/src/object/util_types.rs index dff5100cb5..aa2237dbee 100644 --- a/crates/perry-runtime/src/object/util_types.rs +++ b/crates/perry-runtime/src/object/util_types.rs @@ -172,11 +172,9 @@ pub extern "C" fn js_util_types_is_promise(value: f64) -> f64 { let v = JSValue::from_bits(value.to_bits()); nanbox_bool( v.is_pointer() - && unsafe { - crate::promise::js_is_promise( - v.as_pointer::() as *mut crate::promise::Promise - ) != 0 - }, + && crate::promise::js_is_promise( + v.as_pointer::() as *mut crate::promise::Promise + ) != 0, ) } diff --git a/crates/perry-runtime/src/object/with_env.rs b/crates/perry-runtime/src/object/with_env.rs index c154af779a..f295583e08 100644 --- a/crates/perry-runtime/src/object/with_env.rs +++ b/crates/perry-runtime/src/object/with_env.rs @@ -153,7 +153,7 @@ pub extern "C" fn js_with_implicit_read(value: f64, name: f64) -> f64 { let gptr = (gj.bits() & crate::value::POINTER_MASK) as *const ObjectHeader; let key = crate::builtins::js_string_coerce(name); if !gptr.is_null() && !key.is_null() { - let v = unsafe { crate::object::js_object_get_field_by_name(gptr, key) }; + let v = crate::object::js_object_get_field_by_name(gptr, key); return f64::from_bits(v.bits()); } } diff --git a/crates/perry-runtime/src/perf_hooks.rs b/crates/perry-runtime/src/perf_hooks.rs index c44b58e868..1c7a10f25d 100644 --- a/crates/perry-runtime/src/perf_hooks.rs +++ b/crates/perry-runtime/src/perf_hooks.rs @@ -234,8 +234,7 @@ pub fn performance_namespace() -> f64 { return f64::from_bits(cached); } let module = b"perf_hooks"; - let ns = - unsafe { crate::object::js_create_native_module_namespace(module.as_ptr(), module.len()) }; + let ns = crate::object::js_create_native_module_namespace(module.as_ptr(), module.len()); PERFORMANCE_NS.with(|c| c.set(ns.to_bits())); ns } @@ -1246,13 +1245,9 @@ fn entry_type_code(name: &str) -> Option { /// Read the registry index out of a `perf_observer` namespace object value's /// field[1]. pub fn observer_id_from_value(obs_val: f64) -> usize { - unsafe { - match as_object_ptr(obs_val) { - Some(obj) => { - observer_id_from_field(crate::object::js_object_get_field(obj as *mut _, 1)) - } - None => 0, - } + match as_object_ptr(obs_val) { + Some(obj) => observer_id_from_field(crate::object::js_object_get_field(obj as *mut _, 1)), + None => 0, } } @@ -1424,7 +1419,7 @@ fn schedule_flush() { return; } FLUSH_SCHEDULED.with(|f| f.set(true)); - unsafe { + { let closure = crate::closure::js_closure_alloc_singleton(js_perf_observer_flush_all as *const u8); crate::timer::js_set_timeout_callback(closure as i64, 0.0); @@ -1445,7 +1440,7 @@ pub extern "C" fn js_perf_observer_flush_all( .collect() }); for (cb_bits, obj_bits, entries) in work { - unsafe { + { CURRENT_LIST.with(|c| *c.borrow_mut() = entries); let module = b"perf_observer_list"; let list = @@ -1496,7 +1491,7 @@ pub unsafe fn current_list_get_by_name(name_val: f64) -> f64 { /// Build the `PerformanceObserver.supportedEntryTypes` array. #[no_mangle] pub extern "C" fn js_perf_supported_entry_types() -> f64 { - unsafe { + { let mut arr = crate::array::js_array_alloc(4); for t in ["function", "mark", "measure", "resource"] { arr = crate::array::js_array_push(arr, str_value(t)); @@ -1638,7 +1633,7 @@ mod sso_tests_1781 { /// `"mark"` must still filter to the mark entry (site #509). #[test] fn get_entries_by_name_filters_on_sso_type() { - unsafe { + { let undef = f64::from_bits(crate::value::TAG_UNDEFINED); let name = JSValue::string_ptr(crate::string::js_string_from_bytes(b"phase".as_ptr(), 5)); diff --git a/crates/perry-runtime/src/plugin.rs b/crates/perry-runtime/src/plugin.rs index 936fe9362f..7cbf601c68 100644 --- a/crates/perry-runtime/src/plugin.rs +++ b/crates/perry-runtime/src/plugin.rs @@ -641,9 +641,7 @@ pub extern "C" fn perry_plugin_unregister_service(api_handle: i64, name: f64) -> reg.services.remove(idx); } else { drop(reg); - unsafe { - crate::closure::js_closure_call0(stop_ptr); - } + crate::closure::js_closure_call0(stop_ptr); let mut reg = REGISTRY.lock().unwrap(); if let Some(idx2) = reg .services @@ -1316,7 +1314,7 @@ mod unregister_tests { let handle = fresh_api_handle(); let hook_name = unsafe { make_nanboxed_string("beforeSave") }; let target_handler = f64::from_bits(0xAAAA_0001_0001_u64); - let _ = unsafe { perry_plugin_unregister_hook(handle, hook_name, target_handler) }; + let _ = perry_plugin_unregister_hook(handle, hook_name, target_handler); let reg = REGISTRY.lock().unwrap(); let hooks = reg @@ -1330,7 +1328,7 @@ mod unregister_tests { // Second call with the remaining handler — bucket should now be empty // and the parent map entry pruned. let other_handler = f64::from_bits(0xAAAA_0001_0002_u64); - let _ = unsafe { perry_plugin_unregister_hook(handle, hook_name, other_handler) }; + let _ = perry_plugin_unregister_hook(handle, hook_name, other_handler); let reg = REGISTRY.lock().unwrap(); assert!( reg.hooks.get("beforeSave").is_none(), @@ -1348,7 +1346,7 @@ mod unregister_tests { let hook_name = unsafe { make_nanboxed_string("beforeSave") }; let bogus_handler = f64::from_bits(0xDEAD_BEEF_DEAD_BEEF_u64); - let _ = unsafe { perry_plugin_unregister_hook(handle, hook_name, bogus_handler) }; + let _ = perry_plugin_unregister_hook(handle, hook_name, bogus_handler); let reg = REGISTRY.lock().unwrap(); let hooks = reg.hooks.get("beforeSave").unwrap(); @@ -1369,7 +1367,7 @@ mod unregister_tests { let hook_name = unsafe { make_nanboxed_string("beforeSave") }; let target = f64::from_bits(0xAAAA_0001_0001_u64); - let _ = unsafe { perry_plugin_unregister_hook(handle_2, hook_name, target) }; + let _ = perry_plugin_unregister_hook(handle_2, hook_name, target); let reg = REGISTRY.lock().unwrap(); assert_eq!(reg.hooks.get("beforeSave").unwrap().len(), 2); @@ -1383,7 +1381,7 @@ mod unregister_tests { seed(); let handle = fresh_api_handle(); let name = unsafe { make_nanboxed_string("formatCode") }; - let _ = unsafe { perry_plugin_unregister_tool(handle, name) }; + let _ = perry_plugin_unregister_tool(handle, name); let reg = REGISTRY.lock().unwrap(); assert_eq!(reg.tools.len(), 1, "only the matching tool is removed"); @@ -1398,7 +1396,7 @@ mod unregister_tests { seed(); let handle = fresh_api_handle(); let bogus = unsafe { make_nanboxed_string("doesNotExist") }; - let _ = unsafe { perry_plugin_unregister_tool(handle, bogus) }; + let _ = perry_plugin_unregister_tool(handle, bogus); let reg = REGISTRY.lock().unwrap(); assert_eq!(reg.tools.len(), 2); @@ -1412,7 +1410,7 @@ mod unregister_tests { seed(); let handle = fresh_api_handle(); let path = unsafe { make_nanboxed_string("/api/foo") }; - let _ = unsafe { perry_plugin_unregister_route(handle, path) }; + let _ = perry_plugin_unregister_route(handle, path); let reg = REGISTRY.lock().unwrap(); assert_eq!(reg.routes.len(), 0); @@ -1436,7 +1434,7 @@ mod unregister_tests { svc.stop_fn = 0; } } - let _ = unsafe { perry_plugin_unregister_service(handle, name) }; + let _ = perry_plugin_unregister_service(handle, name); let reg = REGISTRY.lock().unwrap(); assert_eq!(reg.services.len(), 0, "worker service removed"); @@ -1451,7 +1449,7 @@ mod unregister_tests { let handle = fresh_api_handle(); let event = unsafe { make_nanboxed_string("dataUpdated") }; let handler = f64::from_bits(0xEEEE_0001_0001_u64); - let _ = unsafe { perry_plugin_off(handle, event, handler) }; + let _ = perry_plugin_off(handle, event, handler); let reg = REGISTRY.lock().unwrap(); assert!( @@ -1470,14 +1468,14 @@ mod unregister_tests { // plugin_id_for_handle → every unregister path's body is skipped. let ghost_handle: i64 = 9999; let hook_name = unsafe { make_nanboxed_string("beforeSave") }; - let _ = unsafe { perry_plugin_unregister_hook(ghost_handle, hook_name, 0.0) }; + let _ = perry_plugin_unregister_hook(ghost_handle, hook_name, 0.0); let name = unsafe { make_nanboxed_string("formatCode") }; - let _ = unsafe { perry_plugin_unregister_tool(ghost_handle, name) }; + let _ = perry_plugin_unregister_tool(ghost_handle, name); let path = unsafe { make_nanboxed_string("/api/foo") }; - let _ = unsafe { perry_plugin_unregister_route(ghost_handle, path) }; - let _ = unsafe { perry_plugin_unregister_service(ghost_handle, name) }; + let _ = perry_plugin_unregister_route(ghost_handle, path); + let _ = perry_plugin_unregister_service(ghost_handle, name); let event = unsafe { make_nanboxed_string("dataUpdated") }; - let _ = unsafe { perry_plugin_off(ghost_handle, event, 0.0) }; + let _ = perry_plugin_off(ghost_handle, event, 0.0); let reg = REGISTRY.lock().unwrap(); assert_eq!(reg.hooks.get("beforeSave").unwrap().len(), 2); diff --git a/crates/perry-runtime/src/pointer_event.rs b/crates/perry-runtime/src/pointer_event.rs index 8263801684..a2a9d958e9 100644 --- a/crates/perry-runtime/src/pointer_event.rs +++ b/crates/perry-runtime/src/pointer_event.rs @@ -98,12 +98,12 @@ mod tests { assert_eq!(bits & 0xFFFF_0000_0000_0000, POINTER_TAG); let obj_ptr = (bits & 0x0000_FFFF_FFFF_FFFF) as *mut crate::object::ObjectHeader; - let x = unsafe { js_object_get_field(obj_ptr, 0) }; - let y = unsafe { js_object_get_field(obj_ptr, 1) }; - let button = unsafe { js_object_get_field(obj_ptr, 2) }; + let x = js_object_get_field(obj_ptr, 0); + let y = js_object_get_field(obj_ptr, 1); + let button = js_object_get_field(obj_ptr, 2); // Field 3 (pointerType) is a string — exercise only that the // value carries the STRING_TAG so we know we wrote *a* string. - let pt = unsafe { js_object_get_field(obj_ptr, 3) }; + let pt = js_object_get_field(obj_ptr, 3); assert_eq!(f64::from_bits(x.bits()), 10.5); assert_eq!(f64::from_bits(y.bits()), 20.25); @@ -125,7 +125,7 @@ mod tests { let pen = js_pointer_event_new(0.0, 0.0, 0, POINTER_TYPE_PEN); let pt = |nb: f64| { let obj = (nb.to_bits() & 0x0000_FFFF_FFFF_FFFF) as *mut crate::object::ObjectHeader; - unsafe { js_object_get_field(obj, 3) }.bits() + js_object_get_field(obj, 3).bits() }; let m = pt(mouse); let t = pt(touch); diff --git a/crates/perry-runtime/src/process/credentials.rs b/crates/perry-runtime/src/process/credentials.rs index 3f6434342b..2502c4d6c0 100644 --- a/crates/perry-runtime/src/process/credentials.rs +++ b/crates/perry-runtime/src/process/credentials.rs @@ -209,12 +209,12 @@ pub extern "C" fn js_process_setgroups(groups: f64) { if arr_ptr.is_null() { return; } - let len = unsafe { crate::array::js_array_length(arr_ptr) }; + let len = crate::array::js_array_length(arr_ptr); #[cfg(unix)] { let mut gids: Vec = Vec::with_capacity(len as usize); for i in 0..len { - let v = unsafe { crate::array::js_array_get_f64(arr_ptr, i) }; + let v = crate::array::js_array_get_f64(arr_ptr, i); if let Some(id) = unix_id_arg(v) { gids.push(id as libc::gid_t); } diff --git a/crates/perry-runtime/src/regex.rs b/crates/perry-runtime/src/regex.rs index c52736a530..59ddcf289e 100644 --- a/crates/perry-runtime/src/regex.rs +++ b/crates/perry-runtime/src/regex.rs @@ -1618,7 +1618,7 @@ pub extern "C" fn js_regexp_get_flags(re: *const RegExpHeader) -> *mut StringHea pub extern "C" fn js_regexp_to_string(re: *const RegExpHeader) -> *mut StringHeader { let src = js_regexp_get_source(re); let flg = js_regexp_get_flags(re); - let out = unsafe { format!("/{}/{}", string_as_str(src), string_as_str(flg)) }; + let out = format!("/{}/{}", string_as_str(src), string_as_str(flg)); js_string_from_str(&out) } diff --git a/crates/perry-runtime/src/regex/tests.rs b/crates/perry-runtime/src/regex/tests.rs index 5a13cf747b..201914bd6b 100644 --- a/crates/perry-runtime/src/regex/tests.rs +++ b/crates/perry-runtime/src/regex/tests.rs @@ -75,7 +75,7 @@ fn fancy_backreference_match() { let re = js_regexp_new(make_string(r"(\w)\1"), make_string("")); let result = js_string_match(make_string("hello"), re); assert!(!result.is_null()); - unsafe { + { let v = crate::array::js_array_get_f64(result, 0); let sp = crate::value::js_get_string_pointer_unified(v) as *const StringHeader; assert_eq!(string_as_str(sp), "ll"); @@ -127,7 +127,7 @@ fn fancy_lookbehind_exec_index() { let result = js_regexp_exec(re, make_string("price: $42")); assert!(!result.is_null()); assert_eq!(js_regexp_exec_get_index(), 8.0); - unsafe { + { let v = crate::array::js_array_get_f64(result, 0); let sp = crate::value::js_get_string_pointer_unified(v) as *const StringHeader; assert_eq!(string_as_str(sp), "42"); diff --git a/crates/perry-runtime/src/safe_area.rs b/crates/perry-runtime/src/safe_area.rs index cd51f3b986..d5094496fe 100644 --- a/crates/perry-runtime/src/safe_area.rs +++ b/crates/perry-runtime/src/safe_area.rs @@ -57,10 +57,10 @@ mod tests { assert_eq!(bits & 0xFFFF_0000_0000_0000, POINTER_TAG); let obj_ptr = (bits & 0x0000_FFFF_FFFF_FFFF) as *mut crate::object::ObjectHeader; - let top = unsafe { js_object_get_field(obj_ptr, 0) }; - let right = unsafe { js_object_get_field(obj_ptr, 1) }; - let bottom = unsafe { js_object_get_field(obj_ptr, 2) }; - let left = unsafe { js_object_get_field(obj_ptr, 3) }; + let top = js_object_get_field(obj_ptr, 0); + let right = js_object_get_field(obj_ptr, 1); + let bottom = js_object_get_field(obj_ptr, 2); + let left = js_object_get_field(obj_ptr, 3); assert_eq!(f64::from_bits(top.bits()), 59.0); assert_eq!(f64::from_bits(right.bits()), 0.0); diff --git a/crates/perry-runtime/src/string/compare.rs b/crates/perry-runtime/src/string/compare.rs index f656d74434..040a42e0d0 100644 --- a/crates/perry-runtime/src/string/compare.rs +++ b/crates/perry-runtime/src/string/compare.rs @@ -596,7 +596,7 @@ pub extern "C" fn js_string_locale_compare_opts( b: *const StringHeader, options: f64, ) -> f64 { - let numeric = unsafe { + let numeric = { let ptr = crate::value::js_nanbox_get_pointer(options) as *const crate::object::ObjectHeader; if ptr.is_null() || (ptr as usize) < 0x10000 { @@ -740,7 +740,7 @@ mod tests_sso_helpers { let bytes = name.as_bytes(); assert!(bytes.len() <= SHORT_STRING_MAX_LEN); - let incoming = unsafe { js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) }; + let incoming = js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32); let heap_stored = JSValue::string_ptr(incoming); let sso_stored = JSValue::try_short_string(bytes).expect("len<=5 encodes as SSO"); assert!(sso_stored.is_short_string(), "{name:?} should be SSO"); @@ -770,9 +770,9 @@ mod tests_sso_helpers { /// is SSO and the other is heap. #[test] fn key_matches_rejects_different_bytes_across_reps() { - let incoming = unsafe { js_string_from_bytes(b"id".as_ptr(), 2) }; + let incoming = js_string_from_bytes(b"id".as_ptr(), 2); let sso_other = JSValue::try_short_string(b"tag").expect("SSO"); - let heap_other_ptr = unsafe { js_string_from_bytes(b"other".as_ptr(), 5) }; + let heap_other_ptr = js_string_from_bytes(b"other".as_ptr(), 5); let heap_other = JSValue::string_ptr(heap_other_ptr); unsafe { @@ -785,7 +785,7 @@ mod tests_sso_helpers { /// without dereferencing the payload. #[test] fn key_matches_rejects_non_string_stored() { - let incoming = unsafe { js_string_from_bytes(b"id".as_ptr(), 2) }; + let incoming = js_string_from_bytes(b"id".as_ptr(), 2); for stored in [ JSValue::undefined(), JSValue::null(), @@ -804,7 +804,7 @@ mod tests_sso_helpers { #[test] fn key_bytes_round_trips_sso_and_heap() { let sso = JSValue::try_short_string(b"path").expect("SSO"); - let heap = JSValue::string_ptr(unsafe { js_string_from_bytes(b"longish".as_ptr(), 7) }); + let heap = JSValue::string_ptr(js_string_from_bytes(b"longish".as_ptr(), 7)); let mut buf = [0u8; SHORT_STRING_MAX_LEN]; unsafe { assert_eq!(js_string_key_bytes(sso, &mut buf), Some(b"path".as_ref())); diff --git a/crates/perry-runtime/src/string/tests_guard_page.rs b/crates/perry-runtime/src/string/tests_guard_page.rs index 977d13529b..914bc4dd37 100644 --- a/crates/perry-runtime/src/string/tests_guard_page.rs +++ b/crates/perry-runtime/src/string/tests_guard_page.rs @@ -291,7 +291,7 @@ fn split_parts_preserve_lone_surrogate_flag() { f0, STRING_FLAG_HAS_LONE_SURROGATES, "the part holding the lone surrogate must stay flagged" ); - let part0 = unsafe { + let part0 = { let v = crate::array::js_array_get_f64(arr, 0); crate::value::js_nanbox_get_pointer(v) as *const StringHeader }; diff --git a/crates/perry-runtime/src/tty.rs b/crates/perry-runtime/src/tty.rs index c38d04cf85..a44e80a90a 100644 --- a/crates/perry-runtime/src/tty.rs +++ b/crates/perry-runtime/src/tty.rs @@ -672,20 +672,18 @@ fn ensure_tty_prototypes() { read_keys.as_ptr(), read_keys.len() as u32, ); - unsafe { - crate::object::js_object_set_field( - read_proto, - 1, - JSValue::from_bits( - closure_value( - js_tty_read_stream_set_raw_mode as *const u8, - "setRawMode", - 1, - ) - .to_bits(), - ), - ); - } + crate::object::js_object_set_field( + read_proto, + 1, + JSValue::from_bits( + closure_value( + js_tty_read_stream_set_raw_mode as *const u8, + "setRawMode", + 1, + ) + .to_bits(), + ), + ); crate::object::class_prototype_object_root_store(CLASS_ID_TTY_READ_STREAM, read_proto); let write_keys = b"constructor\0isTTY\0getColorDepth\0hasColors\0_refreshSize\0cursorTo\0moveCursor\0clearLine\0clearScreenDown\0getWindowSize\0"; @@ -695,92 +693,88 @@ fn ensure_tty_prototypes() { write_keys.as_ptr(), write_keys.len() as u32, ); - unsafe { - crate::object::js_object_set_field(write_proto, 1, JSValue::from_bits(TAG_TRUE)); - crate::object::js_object_set_field( - write_proto, - 2, - JSValue::from_bits( - closure_value( - js_tty_write_stream_get_color_depth as *const u8, - "getColorDepth", - 1, - ) - .to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 3, - JSValue::from_bits( - closure_value(js_tty_write_stream_has_colors as *const u8, "hasColors", 2) - .to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 4, - JSValue::from_bits( - closure_value( - js_tty_write_stream_refresh_size as *const u8, - "_refreshSize", - 0, - ) - .to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 5, - JSValue::from_bits( - closure_value(js_tty_write_stream_cursor_to as *const u8, "cursorTo", 3).to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 6, - JSValue::from_bits( - closure_value( - js_tty_write_stream_move_cursor as *const u8, - "moveCursor", - 3, - ) - .to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 7, - JSValue::from_bits( - closure_value(js_tty_write_stream_clear_line as *const u8, "clearLine", 2) - .to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 8, - JSValue::from_bits( - closure_value( - js_tty_write_stream_clear_screen_down as *const u8, - "clearScreenDown", - 1, - ) - .to_bits(), - ), - ); - crate::object::js_object_set_field( - write_proto, - 9, - JSValue::from_bits( - closure_value( - js_tty_write_stream_get_window_size as *const u8, - "getWindowSize", - 0, - ) - .to_bits(), - ), - ); - } + crate::object::js_object_set_field(write_proto, 1, JSValue::from_bits(TAG_TRUE)); + crate::object::js_object_set_field( + write_proto, + 2, + JSValue::from_bits( + closure_value( + js_tty_write_stream_get_color_depth as *const u8, + "getColorDepth", + 1, + ) + .to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 3, + JSValue::from_bits( + closure_value(js_tty_write_stream_has_colors as *const u8, "hasColors", 2).to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 4, + JSValue::from_bits( + closure_value( + js_tty_write_stream_refresh_size as *const u8, + "_refreshSize", + 0, + ) + .to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 5, + JSValue::from_bits( + closure_value(js_tty_write_stream_cursor_to as *const u8, "cursorTo", 3).to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 6, + JSValue::from_bits( + closure_value( + js_tty_write_stream_move_cursor as *const u8, + "moveCursor", + 3, + ) + .to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 7, + JSValue::from_bits( + closure_value(js_tty_write_stream_clear_line as *const u8, "clearLine", 2).to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 8, + JSValue::from_bits( + closure_value( + js_tty_write_stream_clear_screen_down as *const u8, + "clearScreenDown", + 1, + ) + .to_bits(), + ), + ); + crate::object::js_object_set_field( + write_proto, + 9, + JSValue::from_bits( + closure_value( + js_tty_write_stream_get_window_size as *const u8, + "getWindowSize", + 0, + ) + .to_bits(), + ), + ); crate::object::class_prototype_object_root_store(CLASS_ID_TTY_WRITE_STREAM, write_proto); } @@ -803,7 +797,7 @@ pub(crate) fn attach_tty_constructor_prototype(constructor_value: f64, name: &st if proto.is_null() { return; } - unsafe { + { crate::object::js_object_set_field( proto, 0, @@ -864,10 +858,8 @@ pub extern "C" fn js_tty_read_stream_new(fd: f64) -> f64 { keys.as_ptr(), keys.len() as u32, ); - unsafe { - crate::object::js_object_set_field(obj, 0, JSValue::from_bits(TAG_FALSE)); - crate::object::js_object_set_field(obj, 1, JSValue::from_bits(TAG_TRUE)); - } + crate::object::js_object_set_field(obj, 0, JSValue::from_bits(TAG_FALSE)); + crate::object::js_object_set_field(obj, 1, JSValue::from_bits(TAG_TRUE)); ptr_value(obj) } @@ -1115,7 +1107,7 @@ pub extern "C" fn js_tty_write_stream_remove_all_listeners( pub fn throw_invalid_fd(fd: f64) -> ! { let obj = crate::object::js_object_alloc(crate::error::CLASS_ID_RANGE_ERROR, 4); - unsafe { + { crate::object::js_register_class_extends_error(crate::error::CLASS_ID_RANGE_ERROR); let str_val = |s: &str| -> f64 { let ptr = crate::string::js_string_from_bytes(s.as_ptr(), s.len() as u32); diff --git a/crates/perry-runtime/src/url/search_params.rs b/crates/perry-runtime/src/url/search_params.rs index b81b658b08..914404b0d6 100644 --- a/crates/perry-runtime/src/url/search_params.rs +++ b/crates/perry-runtime/src/url/search_params.rs @@ -46,7 +46,7 @@ pub(crate) fn resolve_search_params_receiver(params: *mut ObjectHeader) -> *mut URL_SEARCH_PARAMS_BACKING_KEY.len() as u32, ); let params = params_handle.get_raw_mut_ptr::(); - let backing = unsafe { crate::object::js_object_get_field_by_name(params, key) }; + let backing = crate::object::js_object_get_field_by_name(params, key); if backing.is_pointer() { let ptr = backing.as_pointer::() as *mut ObjectHeader; if !ptr.is_null() { @@ -79,7 +79,7 @@ pub(crate) fn url_search_params_backing_of(object: f64) -> Option<*mut ObjectHea URL_SEARCH_PARAMS_BACKING_KEY.len() as u32, ); let obj = obj_handle.get_raw_mut_ptr::(); - let backing = unsafe { crate::object::js_object_get_field_by_name(obj, key) }; + let backing = crate::object::js_object_get_field_by_name(obj, key); if backing.is_pointer() { let ptr = backing.as_pointer::() as *mut ObjectHeader; if !ptr.is_null() { @@ -121,7 +121,7 @@ pub extern "C" fn js_url_search_params_subclass_init(this: f64, init: f64) -> f6 let key = key_handle.get_raw_const_ptr::(); let backing_ptr = backing_handle.get_raw_mut_ptr::(); let backing_f64 = crate::value::js_nanbox_pointer(backing_ptr as i64); - unsafe { crate::object::js_object_set_field_by_name(this_obj, key, backing_f64) }; + crate::object::js_object_set_field_by_name(this_obj, key, backing_f64); undef } diff --git a/crates/perry-runtime/src/util_promisify.rs b/crates/perry-runtime/src/util_promisify.rs index 00a882b1ac..322caeae16 100644 --- a/crates/perry-runtime/src/util_promisify.rs +++ b/crates/perry-runtime/src/util_promisify.rs @@ -763,9 +763,8 @@ fn callable_then_field(value: f64) -> Option { } let obj = addr as *const crate::object::ObjectHeader; let key = js_string_from_bytes(b"then".as_ptr(), 4); - let then_value = unsafe { - crate::object::js_object_get_field_by_name_f64(obj, key as *const crate::StringHeader) - }; + let then_value = + crate::object::js_object_get_field_by_name_f64(obj, key as *const crate::StringHeader); if is_callable_closure(then_value) { Some(then_value) } else { diff --git a/crates/perry-runtime/src/weakref.rs b/crates/perry-runtime/src/weakref.rs index c565b31234..d92af6ea00 100644 --- a/crates/perry-runtime/src/weakref.rs +++ b/crates/perry-runtime/src/weakref.rs @@ -1414,9 +1414,9 @@ pub extern "C" fn js_weakmap_init_iterable(map: f64, iterable: f64) -> f64 { let arr_handle = scope.root_nanbox_f64(arr_value); let arr_ptr = js_nanbox_get_pointer(arr_handle.get_nanbox_f64()) as *mut ArrayHeader; if !arr_ptr.is_null() { - let len = unsafe { js_array_length(arr_ptr) as usize }; + let len = js_array_length(arr_ptr) as usize; for i in 0..len { - let entry = unsafe { + let entry = { let arr = js_nanbox_get_pointer(arr_handle.get_nanbox_f64()) as *const ArrayHeader; js_array_get_f64(arr, i as u32) @@ -1723,9 +1723,9 @@ pub extern "C" fn js_weakset_init_iterable(set: f64, iterable: f64) -> f64 { let arr_handle = scope.root_nanbox_f64(arr_value); let arr_ptr = js_nanbox_get_pointer(arr_handle.get_nanbox_f64()) as *mut ArrayHeader; if !arr_ptr.is_null() { - let len = unsafe { js_array_length(arr_ptr) as usize }; + let len = js_array_length(arr_ptr) as usize; for i in 0..len { - let element = unsafe { + let element = { let arr = js_nanbox_get_pointer(arr_handle.get_nanbox_f64()) as *const ArrayHeader; js_array_get_f64(arr, i as u32) diff --git a/crates/perry-stdlib/src/commander.rs b/crates/perry-stdlib/src/commander.rs index d6152cacee..eb373fa5a7 100644 --- a/crates/perry-stdlib/src/commander.rs +++ b/crates/perry-stdlib/src/commander.rs @@ -598,7 +598,7 @@ pub extern "C" fn js_commander_args_array(handle: Handle) -> Handle { Some(cmd) => cmd.args.clone(), None => Vec::new(), }; - unsafe { + { let boxed: Vec = args .iter() .map(|a| { diff --git a/crates/perry-stdlib/src/fetch/dispatch.rs b/crates/perry-stdlib/src/fetch/dispatch.rs index 9d55f160d7..ef824cc38b 100644 --- a/crates/perry-stdlib/src/fetch/dispatch.rs +++ b/crates/perry-stdlib/src/fetch/dispatch.rs @@ -37,7 +37,7 @@ pub extern "C" fn js_response_body_init_ptr(value: f64) -> i64 { // payload came back all zeroes (#5435). Materialize the bytes into a heap // StringHeader so `js_response_new`'s lossless byte read recovers them. if let Some(bytes) = unsafe { body_value_buffer_bytes(value) } { - return unsafe { js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) } as i64; + return js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) as i64; } // A Blob / File body contributes its raw bytes. Blob handles are handle-band // ids (>= FETCH_HANDLE_BAND_START, 0x40000), NOT real pointers, so they must @@ -50,8 +50,7 @@ pub extern "C" fn js_response_body_init_ptr(value: f64) -> i64 { let addr = jsval.as_pointer::() as usize; if perry_runtime::value::addr_class::is_handle_band(addr) { if let Some(bytes) = crate::fetch::blob_bytes_clone(addr) { - return unsafe { js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) } - as i64; + return js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) as i64; } } } @@ -68,7 +67,7 @@ pub extern "C" fn js_response_body_init_ptr(value: f64) -> i64 { // kind == 1 ⇒ live ReadableStream. if crate::streams::js_stream_handle_kind(id) == 1 { let bytes = crate::streams::drain_readable_into_bytes(id); - return unsafe { js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) } as i64; + return js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) as i64; } } // #5437: a Node `IncomingMessage` body — the request-body bridge Next.js's @@ -80,7 +79,7 @@ pub extern "C" fn js_response_body_init_ptr(value: f64) -> i64 { if let Some(bytes) = unsafe { incoming_message_raw_body_bytes(jsval.as_pointer::() as usize) } { - return unsafe { js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) } as i64; + return js_string_from_bytes(bytes.as_ptr(), bytes.len() as u32) as i64; } } } diff --git a/crates/perry-stdlib/src/http.rs b/crates/perry-stdlib/src/http.rs index cb5e65023e..98e946a124 100644 --- a/crates/perry-stdlib/src/http.rs +++ b/crates/perry-stdlib/src/http.rs @@ -1179,7 +1179,7 @@ pub extern "C" fn js_http_client_request_method(handle: Handle) -> *mut StringHe String::new() } }; - unsafe { js_string_from_bytes(method.as_ptr(), method.len() as u32) } + js_string_from_bytes(method.as_ptr(), method.len() as u32) } #[no_mangle] @@ -1198,7 +1198,7 @@ pub extern "C" fn js_http_client_request_protocol(handle: Handle) -> *mut String String::new() } }; - unsafe { js_string_from_bytes(protocol.as_ptr(), protocol.len() as u32) } + js_string_from_bytes(protocol.as_ptr(), protocol.len() as u32) } #[no_mangle] @@ -1216,7 +1216,7 @@ pub extern "C" fn js_http_client_request_host(handle: Handle) -> *mut StringHead String::new() } }; - unsafe { js_string_from_bytes(host.as_ptr(), host.len() as u32) } + js_string_from_bytes(host.as_ptr(), host.len() as u32) } #[no_mangle] @@ -1243,7 +1243,7 @@ pub extern "C" fn js_http_client_request_path(handle: Handle) -> *mut StringHead String::new() } }; - unsafe { js_string_from_bytes(path.as_ptr(), path.len() as u32) } + js_string_from_bytes(path.as_ptr(), path.len() as u32) } #[no_mangle] @@ -1546,7 +1546,7 @@ fn throw_agent_out_of_range(name: &str, bound: &str, received: f64) -> ! { "The value of \"{}\" is out of range. It must be {}. Received {}", name, bound, received_str ); - let msg_ptr = unsafe { js_string_from_bytes(message.as_ptr(), message.len() as u32) }; + let msg_ptr = js_string_from_bytes(message.as_ptr(), message.len() as u32); perry_runtime::node_submodules::register_error_code_pub(msg_ptr, "ERR_OUT_OF_RANGE"); let err = perry_runtime::error::js_rangeerror_new(msg_ptr); perry_runtime::exception::js_throw(perry_runtime::value::js_nanbox_pointer(err as i64)) @@ -1846,7 +1846,7 @@ pub extern "C" fn js_http_agent_protocol(handle: Handle) -> *mut StringHeader { let s = get_handle_mut::(handle) .and_then(|a| a.protocol.clone()) .unwrap_or_else(|| "http:".to_string()); - unsafe { js_string_from_bytes(s.as_ptr(), s.len() as u32) } + js_string_from_bytes(s.as_ptr(), s.len() as u32) } #[no_mangle] diff --git a/crates/perry-stdlib/src/querystring.rs b/crates/perry-stdlib/src/querystring.rs index 30deb75f62..ace744b458 100644 --- a/crates/perry-stdlib/src/querystring.rs +++ b/crates/perry-stdlib/src/querystring.rs @@ -87,7 +87,7 @@ unsafe fn nanboxed_to_string(value: f64) -> Option { /// Allocate a heap StringHeader from a Rust `&str`. fn intern_string(s: &str) -> *mut StringHeader { - unsafe { js_string_from_bytes(s.as_ptr(), s.len() as u32) } + js_string_from_bytes(s.as_ptr(), s.len() as u32) } /// NaN-box a `*mut StringHeader` with STRING_TAG so it returns through @@ -405,7 +405,7 @@ fn resolve_max_keys(options: f64) -> Option { return Some(1000); } let key = intern_string("maxKeys"); - let max_keys = unsafe { js_object_get_field_by_name(obj, key) }; + let max_keys = js_object_get_field_by_name(obj, key); if max_keys.is_undefined() || max_keys.is_null() { return Some(1000); } @@ -628,7 +628,7 @@ fn querystring_scalar_to_string(value_bits: u64) -> String { if ptr.is_null() { return String::new(); } - let hdr = unsafe { perry_runtime::bigint::js_bigint_to_string(ptr) }; + let hdr = perry_runtime::bigint::js_bigint_to_string(ptr); if hdr.is_null() { return String::new(); } diff --git a/crates/perry-stdlib/src/streams/transform.rs b/crates/perry-stdlib/src/streams/transform.rs index a0ffd0926e..e20851b4a7 100644 --- a/crates/perry-stdlib/src/streams/transform.rs +++ b/crates/perry-stdlib/src/streams/transform.rs @@ -267,7 +267,7 @@ pub(super) unsafe fn transform_write(writable_id: usize, chunk: f64) -> *mut Pro /// teepipe2.js shows the transform output landing one tick later than a /// single-job deferral produces. Re-queue once, then run the transform. extern "C" fn transform_write_job(closure: *const ClosureHeader) -> f64 { - unsafe { + { let job_fn = transform_write_job2 as *const u8; perry_runtime::closure::js_register_closure_arity(job_fn, 0); let job = perry_runtime::closure::js_closure_alloc(job_fn, 5); diff --git a/crates/perry-stdlib/src/tls.rs b/crates/perry-stdlib/src/tls.rs index f81f02f7eb..3f9e859469 100644 --- a/crates/perry-stdlib/src/tls.rs +++ b/crates/perry-stdlib/src/tls.rs @@ -200,7 +200,7 @@ fn undefined() -> f64 { } fn nanbox_str(s: &str) -> f64 { - unsafe { + { let ptr = js_string_from_bytes(s.as_ptr(), s.len() as u32); f64::from_bits(JSValue::string_ptr(ptr).bits()) } @@ -297,7 +297,7 @@ fn throw_type_error(message: &str, code: &'static str) -> ! { } fn throw_error(message: &str, code: &'static str) -> ! { - unsafe { + { let msg = js_string_from_bytes(message.as_ptr(), message.len() as u32); perry_runtime::node_submodules::register_error_code_pub(msg, code); let err = perry_runtime::error::js_error_new_with_message(msg); diff --git a/crates/perry-stdlib/src/zlib.rs b/crates/perry-stdlib/src/zlib.rs index c6987f9307..fdc7f19dd9 100644 --- a/crates/perry-stdlib/src/zlib.rs +++ b/crates/perry-stdlib/src/zlib.rs @@ -25,7 +25,7 @@ use std::sync::Mutex; /// reports invalid input so callers see a Node-shaped exception instead /// of a sentinel null return. fn throw_zlib_error(message: &str) -> ! { - unsafe { + { let msg = js_string_from_bytes(message.as_ptr(), message.len() as u32); let err = perry_runtime::error::js_error_new_with_message(msg); perry_runtime::exception::js_throw(perry_runtime::value::js_nanbox_pointer(err as i64)) diff --git a/crates/perry-ui-macos/src/app.rs b/crates/perry-ui-macos/src/app.rs index 3676c5099b..b66ad219d4 100644 --- a/crates/perry-ui-macos/src/app.rs +++ b/crates/perry-ui-macos/src/app.rs @@ -1123,7 +1123,7 @@ pub fn add_keyboard_shortcut(key_ptr: *const u8, modifiers: f64, callback: f64) let app = NSApplication::sharedApplication(mtm); // If the menu bar exists, install immediately; otherwise buffer for later. - let has_menu = unsafe { app.mainMenu().is_some() }; + let has_menu = app.mainMenu().is_some(); if has_menu { install_keyboard_shortcut(key_ptr, modifiers, callback, mtm); } else { diff --git a/crates/perry-ui-macos/src/widgets/hstack.rs b/crates/perry-ui-macos/src/widgets/hstack.rs index 5cae2afc59..95059ad78e 100644 --- a/crates/perry-ui-macos/src/widgets/hstack.rs +++ b/crates/perry-ui-macos/src/widgets/hstack.rs @@ -31,14 +31,12 @@ pub fn create_with_insets(spacing: f64, top: f64, left: f64, bottom: f64, right: stack.setSpacing(spacing); stack.setAlignment(NSLayoutAttribute::CenterY); set_gravity_distribution(&stack); - unsafe { - stack.setEdgeInsets(objc2_foundation::NSEdgeInsets { - top, - left, - bottom, - right, - }); - } + stack.setEdgeInsets(objc2_foundation::NSEdgeInsets { + top, + left, + bottom, + right, + }); let view: Retained = unsafe { Retained::cast_unchecked(stack) }; super::register_widget(view) } diff --git a/crates/perry-ui-macos/src/widgets/mod.rs b/crates/perry-ui-macos/src/widgets/mod.rs index 4da3a9a75d..d0426b2748 100644 --- a/crates/perry-ui-macos/src/widgets/mod.rs +++ b/crates/perry-ui-macos/src/widgets/mod.rs @@ -590,7 +590,7 @@ pub fn add_overlay(parent_handle: i64, child_handle: i64) { /// x/y are relative to the parent's coordinate system. pub fn set_overlay_frame(handle: i64, x: f64, y: f64, w: f64, h: f64) { if let Some(view) = get_widget(handle) { - unsafe { + { view.setTranslatesAutoresizingMaskIntoConstraints(true); let frame = objc2_core_foundation::CGRect::new( objc2_core_foundation::CGPoint::new(x, y), @@ -851,14 +851,12 @@ pub fn set_edge_insets(handle: i64, top: f64, left: f64, bottom: f64, right: f64 }; if is_stack { let stack: &NSStackView = unsafe { &*(Retained::as_ptr(&view) as *const NSStackView) }; - unsafe { - stack.setEdgeInsets(objc2_foundation::NSEdgeInsets { - top, - left, - bottom, - right, - }); - } + stack.setEdgeInsets(objc2_foundation::NSEdgeInsets { + top, + left, + bottom, + right, + }); } } } diff --git a/crates/perry-ui-macos/src/widgets/vstack.rs b/crates/perry-ui-macos/src/widgets/vstack.rs index 13d257fe19..0e368ab786 100644 --- a/crates/perry-ui-macos/src/widgets/vstack.rs +++ b/crates/perry-ui-macos/src/widgets/vstack.rs @@ -38,14 +38,12 @@ pub fn create_with_insets(spacing: f64, top: f64, left: f64, bottom: f64, right: stack.setSpacing(spacing); stack.setAlignment(NSLayoutAttribute::Leading); set_gravity_distribution(&stack); - unsafe { - stack.setEdgeInsets(objc2_foundation::NSEdgeInsets { - top, - left, - bottom, - right, - }); - } + stack.setEdgeInsets(objc2_foundation::NSEdgeInsets { + top, + left, + bottom, + right, + }); let view: Retained = unsafe { Retained::cast_unchecked(stack) }; super::register_widget(view) } From 1acaf646057962c9da56a99be18dad8d415c3056 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:09:33 +0200 Subject: [PATCH 03/18] chore(warnings): delete two self-declared extern "C" HTTP symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handle_dispatch.rs declares `js_node_http_res_write` and `js_node_http_res_end` in an `extern "C"` block, but perry-ext-http-server defines both itself (response.rs:1136 and response.rs:1393). Nothing calls the declarations, so rustc reports them as dead functions. Both signatures matched their definitions, so the deletion is a no-op at link time. The other ~62 declarations in that block are used and stay for now; they carry the same hazard — a local declaration of a symbol you also define is never checked against the definition, which is how #6646 shipped an ABI mismatch on `len: i64` vs `u32`. Tracked separately. --- crates/perry-ext-http-server/src/handle_dispatch.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/perry-ext-http-server/src/handle_dispatch.rs b/crates/perry-ext-http-server/src/handle_dispatch.rs index 4ac6ed1fc7..bbb813c24c 100644 --- a/crates/perry-ext-http-server/src/handle_dispatch.rs +++ b/crates/perry-ext-http-server/src/handle_dispatch.rs @@ -155,9 +155,7 @@ extern "C" { fn js_node_http_res_set_strict_content_length(handle: i64, value: f64); fn js_node_http_res_req_handle(handle: i64) -> i64; fn js_node_http_res_write_head(handle: i64, status: f64, arg2: i64, arg3: i64); - fn js_node_http_res_write(handle: i64, chunk: f64) -> i32; fn js_node_http_res_add_trailers(handle: i64, headers_value: f64); - fn js_node_http_res_end(handle: i64, chunk: f64); fn js_node_http_res_flush_headers(handle: i64); fn js_node_http_res_cork(handle: i64); fn js_node_http_res_uncork(handle: i64); From 59c3db89d2f98b627aa3c611167a4bcc751f6c18 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:13:11 +0200 Subject: [PATCH 04/18] chore(warnings): clear 101 dead_code warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deletes refactor leftovers — helpers, thunks, fields and constants nothing calls any more. Keeps, with a justified `#[allow(dead_code)]`, the GC verifiers, the `#[cfg(test)]`-only helpers and the FFI keepalives that exist to be reachable from generated code rather than from Rust. No `#[no_mangle]` function is deleted, so no symbol the compiler emits calls to can go missing at link time. The 11 deleted `extern "C"` items are Rust-internal closure thunks addressed by function pointer, which rustc tracks precisely. Rebased from the triage done on 2026-07-18, so three sites needed fixing against current main: - `path::resolve_win32_str` is no longer dead — url/node_compat.rs calls it. Restored. - `class_field_inline_guard_enabled` and `test_reset_class_field_inline_guard` arrived after that triage (#6802). Kept. - The CGContext* declarations in widgets/chart.rs were already removed by #6646. Kept removed. --- crates/perry-codegen/src/codegen/helpers.rs | 51 ------- crates/perry-codegen/src/codegen/typed_abi.rs | 4 - .../src/lower_call/early_branches.rs | 16 --- .../perry-codegen/src/lower_call/func_ref.rs | 8 -- .../src/lower_call/method_override.rs | 16 --- crates/perry-codegen/src/nm_install.rs | 66 --------- crates/perry-doc-tests/src/main.rs | 10 -- crates/perry-ext-http/src/agent.rs | 4 - crates/perry-ext-net/src/lib.rs | 5 - crates/perry-ext-zlib/src/stream.rs | 1 + crates/perry-hir/src/lower/const_fold_fn.rs | 19 +-- crates/perry-hir/src/lower/context.rs | 11 -- .../lower/expr_call/intrinsics/eval_strict.rs | 34 ----- crates/perry-hir/src/lower/fn_ctor_env.rs | 2 + .../perry-hir/src/lower/lowering_context.rs | 3 - crates/perry-hir/src/lower/misc.rs | 21 --- crates/perry-hir/src/lower/pre_scan.rs | 1 - .../src/lower_decl/class_captures.rs | 7 - crates/perry-runtime/src/array/species.rs | 8 -- crates/perry-runtime/src/buffer/dataview.rs | 10 -- crates/perry-runtime/src/buffer/header.rs | 6 - crates/perry-runtime/src/collection_iter.rs | 32 ----- crates/perry-runtime/src/date.rs | 7 - crates/perry-runtime/src/fs/cp.rs | 7 - crates/perry-runtime/src/fs/validate.rs | 12 -- crates/perry-runtime/src/gc/barrier.rs | 128 ------------------ crates/perry-runtime/src/gc/cycle.rs | 2 + crates/perry-runtime/src/gc/mod.rs | 1 + crates/perry-runtime/src/gc/roots.rs | 1 + crates/perry-runtime/src/gc/telemetry.rs | 2 + crates/perry-runtime/src/gc/trace.rs | 1 + crates/perry-runtime/src/gc/verify.rs | 2 + crates/perry-runtime/src/intl.rs | 1 + .../perry-runtime/src/intl/date_collator.rs | 29 ---- crates/perry-runtime/src/json/reviver.rs | 4 - .../node_stream_constructors/web_adapter.rs | 1 + .../src/node_stream_iter_helpers.rs | 62 --------- .../src/node_stream_readable_read.rs | 14 -- .../src/node_stream_readwrite.rs | 4 - .../src/node_submodules/stream_promises.rs | 6 +- .../perry-runtime/src/node_submodules/test.rs | 5 - crates/perry-runtime/src/node_test.rs | 91 ------------- crates/perry-runtime/src/object/assert.rs | 6 - crates/perry-runtime/src/object/mod.rs | 1 - .../object/native_module/callable_exports.rs | 15 -- .../object/native_module_dispatch_crypto.rs | 116 ---------------- .../object/object_ops/define_properties.rs | 2 - crates/perry-runtime/src/path.rs | 8 +- .../perry-runtime/src/promise/keyed_table.rs | 1 + crates/perry-runtime/src/promise/then.rs | 42 ------ crates/perry-runtime/src/temporal/dispatch.rs | 21 --- crates/perry-runtime/src/typedarray/mod.rs | 13 -- crates/perry-runtime/src/url/mod.rs | 13 -- crates/perry-runtime/src/url/node_compat.rs | 16 +-- crates/perry-stdlib/src/crypto/sign.rs | 16 --- crates/perry-stdlib/src/streams/writable.rs | 18 --- crates/perry-stdlib/src/tls.rs | 2 + crates/perry-stdlib/src/zlib.rs | 6 +- crates/perry-ui-geisterhand/src/server.rs | 1 + crates/perry-ui-macos/src/audio.rs | 12 -- crates/perry-ui-macos/src/audio_playback.rs | 2 + crates/perry-ui-macos/src/geolocation.rs | 4 + crates/perry-ui-macos/src/network.rs | 5 - crates/perry-ui-macos/src/widgets/mod.rs | 1 - crates/perry-ui-macos/src/widgets/table.rs | 2 + .../perry-ui-macos/src/widgets/tree_view.rs | 1 + .../src/commands/compile/object_cache.rs | 1 + crates/perry/src/commands/compile/resolve.rs | 22 +-- crates/perry/src/commands/compile/types.rs | 4 + 69 files changed, 44 insertions(+), 1022 deletions(-) delete mode 100644 crates/perry-runtime/src/object/native_module_dispatch_crypto.rs diff --git a/crates/perry-codegen/src/codegen/helpers.rs b/crates/perry-codegen/src/codegen/helpers.rs index a4f59b09e4..95b82f5cec 100644 --- a/crates/perry-codegen/src/codegen/helpers.rs +++ b/crates/perry-codegen/src/codegen/helpers.rs @@ -985,57 +985,6 @@ pub(super) fn init_static_fields_late( Ok(()) } -/// Returns true if `stmt` contains, at any nesting depth (through -/// if/while/do-while/for/labeled/try/switch bodies), an `Expr( -/// StaticMethodCall)` invoking the (`class_name`, `method_name`) pair — -/// the shape HIR lowering emits at the class-decl position for each -/// `__perry_static_init_*` synthetic method. Used by -/// `init_static_fields_late` to skip per-(class, block) pairs that -/// have already been invoked inline. (#2278) -/// -/// Must recurse: a class declared inside `try { class C { static {...} -/// } }` (test262 static-init-abrupt.js wraps its whole class this way) -/// lowers its inline `StaticMethodCall` into the `Try`'s `body`, not at -/// `hir.init`'s top level. A shallow top-level-only scan missed it, so -/// this late fallback re-invoked the block a second time — outside the -/// user's `try`, so a throwing block's second run surfaced as an -/// uncaught exception instead of staying silently absent. -fn init_calls_static_block(stmt: &perry_hir::Stmt, class_name: &str, method_name: &str) -> bool { - use perry_hir::Stmt; - let any_calls = |stmts: &[Stmt]| { - stmts - .iter() - .any(|s| init_calls_static_block(s, class_name, method_name)) - }; - match stmt { - Stmt::Expr(perry_hir::Expr::StaticMethodCall { - class_name: c, - method_name: m, - .. - }) => c == class_name && m == method_name, - Stmt::If { - then_branch, - else_branch, - .. - } => any_calls(then_branch) || else_branch.as_ref().is_some_and(|b| any_calls(b)), - Stmt::While { body, .. } | Stmt::DoWhile { body, .. } | Stmt::For { body, .. } => { - any_calls(body) - } - Stmt::Labeled { body, .. } => init_calls_static_block(body, class_name, method_name), - Stmt::Try { - body, - catch, - finally, - } => { - any_calls(body) - || catch.as_ref().is_some_and(|c| any_calls(&c.body)) - || finally.as_ref().is_some_and(|f| any_calls(f)) - } - Stmt::Switch { cases, .. } => cases.iter().any(|case| any_calls(&case.body)), - _ => false, - } -} - /// #5989: collect every `(class, method)` invoked via a `StaticMethodCall` /// ANYWHERE in the module — module init, top-level function bodies, and /// (crucially) recursively inside nested closures. `init_calls_static_block` diff --git a/crates/perry-codegen/src/codegen/typed_abi.rs b/crates/perry-codegen/src/codegen/typed_abi.rs index 7e51497f6c..9fa360b182 100644 --- a/crates/perry-codegen/src/codegen/typed_abi.rs +++ b/crates/perry-codegen/src/codegen/typed_abi.rs @@ -614,10 +614,6 @@ pub(crate) fn typed_i1_closure_rejection_reason_with_types( typed_i1_body_rejection_reason(body, locals) } -pub(crate) fn typed_i32_closure_rejection_reason(expr: &Expr) -> Option { - typed_i32_closure_rejection_reason_with_types(expr, &HashMap::new()) -} - pub(crate) fn typed_i32_closure_rejection_reason_with_types( expr: &Expr, module_local_types: &HashMap, diff --git a/crates/perry-codegen/src/lower_call/early_branches.rs b/crates/perry-codegen/src/lower_call/early_branches.rs index 737868951d..34a57dfd7e 100644 --- a/crates/perry-codegen/src/lower_call/early_branches.rs +++ b/crates/perry-codegen/src/lower_call/early_branches.rs @@ -31,14 +31,6 @@ fn typed_i1_closure_signature_note(reps: &[crate::codegen::TypedParamRep]) -> St } } -fn typed_string_closure_signature_note(arg_count: usize) -> String { - if arg_count <= 1 { - "typed_signature=string(i64 closure, string)->string".to_string() - } else { - "typed_signature=string(i64 closure, string, ...)->string".to_string() - } -} - fn typed_closure_signature_note(ret: &str, reps: &[crate::codegen::TypedParamRep]) -> String { let first = reps.first().map(|rep| rep.label()).unwrap_or("void"); if reps.len() <= 1 { @@ -48,14 +40,6 @@ fn typed_closure_signature_note(ret: &str, reps: &[crate::codegen::TypedParamRep } } -fn typed_i32_closure_signature_note(arg_count: usize) -> String { - if arg_count <= 1 { - "typed_signature=i32(i64 closure, i32)->i32".to_string() - } else { - "typed_signature=i32(i64 closure, i32, ...)->i32".to_string() - } -} - fn is_async_dispose_symbol_index(index: &Expr) -> bool { let Expr::SymbolFor(symbol_name) = index else { return false; diff --git a/crates/perry-codegen/src/lower_call/func_ref.rs b/crates/perry-codegen/src/lower_call/func_ref.rs index d676137851..bed2e970ef 100644 --- a/crates/perry-codegen/src/lower_call/func_ref.rs +++ b/crates/perry-codegen/src/lower_call/func_ref.rs @@ -45,14 +45,6 @@ fn typed_i1_signature_note(reps: &[crate::codegen::TypedParamRep]) -> String { } } -fn typed_i32_signature_note(arg_count: usize) -> String { - match arg_count { - 0 => "typed_signature=i32()->i32".to_string(), - 1 => "typed_signature=i32(i32)->i32".to_string(), - _ => "typed_signature=i32(i32, ...)->i32".to_string(), - } -} - fn typed_signature_note( ret: &str, reps: &[crate::codegen::TypedParamRep], diff --git a/crates/perry-codegen/src/lower_call/method_override.rs b/crates/perry-codegen/src/lower_call/method_override.rs index 3dcdc5b05d..71641fb163 100644 --- a/crates/perry-codegen/src/lower_call/method_override.rs +++ b/crates/perry-codegen/src/lower_call/method_override.rs @@ -22,22 +22,6 @@ fn typed_i1_method_signature_note(reps: &[crate::codegen::TypedParamRep]) -> Str } } -fn typed_i32_method_signature_note(arg_count: usize) -> String { - if arg_count <= 1 { - "typed_signature=i32(i32)->i32".to_string() - } else { - "typed_signature=i32(i32, ...)->i32".to_string() - } -} - -fn typed_string_method_signature_note(arg_count: usize) -> String { - if arg_count <= 1 { - "typed_signature=string(string)->string".to_string() - } else { - "typed_signature=string(string, ...)->string".to_string() - } -} - fn typed_method_signature_note(ret: &str, reps: &[crate::codegen::TypedParamRep]) -> String { let first = reps.first().map(|rep| rep.label()).unwrap_or("void"); if reps.len() <= 1 { diff --git a/crates/perry-codegen/src/nm_install.rs b/crates/perry-codegen/src/nm_install.rs index fb1686f884..e2a6317b02 100644 --- a/crates/perry-codegen/src/nm_install.rs +++ b/crates/perry-codegen/src/nm_install.rs @@ -66,52 +66,6 @@ pub(crate) fn nm_install_symbol(name: &str) -> Option<&'static str> { } } -/// All dispatch-install symbols + the dynamic fallback — declared so codegen can -/// emit calls to them. -pub(crate) const NM_INSTALL_SYMBOLS: &[&str] = &[ - "js_nm_install_assert", - "js_nm_install_async_hooks", - "js_nm_install_bigint", - "js_nm_install_buffer", - "js_nm_install_bun", - "js_nm_install_bun_ffi", - "js_nm_install_child_process", - "js_nm_install_cluster", - "js_nm_install_console", - "js_nm_install_crypto", - "js_nm_install_dgram", - "js_nm_install_dns", - "js_nm_install_domain", - "js_nm_install_events", - "js_nm_install_fs", - "js_nm_install_http", - "js_nm_install_inspector", - "js_nm_install_module", - "js_nm_install_net", - "js_nm_install_node_pty", - "js_nm_install_os", - "js_nm_install_path", - "js_nm_install_perf", - "js_nm_install_process", - "js_nm_install_punycode", - "js_nm_install_querystring", - "js_nm_install_readline", - "js_nm_install_repl", - "js_nm_install_sea", - "js_nm_install_sqlite", - "js_nm_install_stream", - "js_nm_install_timers", - "js_nm_install_tls", - "js_nm_install_tty", - "js_nm_install_url", - "js_nm_install_util", - "js_nm_install_v8", - "js_nm_install_vm", - "js_nm_install_wasi", - "js_nm_install_zlib", - "js_nm_install_all", -]; - /// Submodule (`node:fs/promises`, `node:stream/web`, …) dispatch-install symbol /// for a sentinel submodule key, or `None` if unknown. Mirrors perry-runtime /// `submod_index`. Emitted at `js_node_submodule_namespace` sites so a submodule's @@ -136,23 +90,3 @@ pub(crate) fn nm_submod_install_symbol(key: &str) -> Option<&'static str> { _ => None, } } - -pub(crate) const NM_SUBMOD_INSTALL_SYMBOLS: &[&str] = &[ - "js_node_submod_install_vm", - "js_node_submod_install_timers", - "js_node_submod_install_timers_promises", - "js_node_submod_install_fs_promises", - "js_node_submod_install_readline_promises", - "js_node_submod_install_stream_promises", - "js_node_submod_install_stream_consumers", - "js_node_submod_install_stream_web", - "js_node_submod_install_hono_jsx_server", - "js_node_submod_install_hono_jsx_streaming", - "js_node_submod_install_sys", - "js_node_submod_install_diagnostics_channel", - "js_node_submod_install_trace_events", - "js_node_submod_install_test", - "js_node_submod_install_test_reporters", - "js_node_submod_install_all", - "js_node_submod_enable_install_all", -]; diff --git a/crates/perry-doc-tests/src/main.rs b/crates/perry-doc-tests/src/main.rs index 5ae18b8f38..7e8511447c 100644 --- a/crates/perry-doc-tests/src/main.rs +++ b/crates/perry-doc-tests/src/main.rs @@ -609,16 +609,6 @@ fn run_one( } } -/// Whether a given `--target` value can be built from this host. Any -/// other combination gets reported as `XCOMPILE_SKIP` with the reason so -/// coverage stays visible without failing the job. Also checks whether -/// the host has the toolchain installed (Xcode, Android NDK) so that -/// local dev boxes don't hit false failures when they're simply missing -/// the mobile SDKs. -fn target_buildable_on_host(target: &str, host: &str) -> bool { - target_buildable_reason(target, host).is_none() -} - /// Reason the target can't be built from this host, or None if it can. fn target_buildable_reason(target: &str, host: &str) -> Option { match target { diff --git a/crates/perry-ext-http/src/agent.rs b/crates/perry-ext-http/src/agent.rs index 7dedb717e7..aa977f7a98 100644 --- a/crates/perry-ext-http/src/agent.rs +++ b/crates/perry-ext-http/src/agent.rs @@ -78,10 +78,6 @@ fn bind_agent_method_value(handle: Handle, name: &'static [u8]) -> f64 { unsafe { js_class_method_bind(instance, name.as_ptr(), name.len()) } } -fn pointer_value(handle: Handle) -> f64 { - f64::from_bits(POINTER_TAG | (handle as u64 & PTR_MASK)) -} - // ------------------------------------------------------------------ // AgentHandle // ------------------------------------------------------------------ diff --git a/crates/perry-ext-net/src/lib.rs b/crates/perry-ext-net/src/lib.rs index c5170279fe..673c75abd9 100644 --- a/crates/perry-ext-net/src/lib.rs +++ b/crates/perry-ext-net/src/lib.rs @@ -221,11 +221,6 @@ pub(crate) mod statics { P.get_or_init(|| Mutex::new(Vec::new())) } - pub fn next_net_id() -> &'static Mutex { - static N: OnceLock> = OnceLock::new(); - N.get_or_init(|| Mutex::new(1)) - } - /// Server registry — `net.createServer(...)` returns a handle here. /// Separate from the socket map: server handles host an accept-loop /// shutdown channel and a bound port; sockets host a per-connection diff --git a/crates/perry-ext-zlib/src/stream.rs b/crates/perry-ext-zlib/src/stream.rs index 7a1b144767..4bb5ce5f80 100644 --- a/crates/perry-ext-zlib/src/stream.rs +++ b/crates/perry-ext-zlib/src/stream.rs @@ -335,6 +335,7 @@ impl CodecState { } } +#[allow(dead_code)] // test scaffolding: default-level wrapper used only by the cfg(test) streaming tests fn make_codec_state(codec: Codec) -> Option { make_codec_state_with_level(codec, Compression::default()) } diff --git a/crates/perry-hir/src/lower/const_fold_fn.rs b/crates/perry-hir/src/lower/const_fold_fn.rs index 516f18d633..7e870ab481 100644 --- a/crates/perry-hir/src/lower/const_fold_fn.rs +++ b/crates/perry-hir/src/lower/const_fold_fn.rs @@ -1443,7 +1443,7 @@ fn extract_fn_expr(module: &ast::Module) -> Option<&ast::FnExpr> { } } -/// Owning arrow analog of [`extract_fn_expr_owned`] — pull the `ArrowExpr` +/// Owning arrow analog of `extract_fn_expr` — pull the `ArrowExpr` /// out of a synthesized `(() => { ... });` module. fn extract_arrow_expr_owned(module: ast::Module) -> Option { let item = module.body.into_iter().next()?; @@ -1460,23 +1460,6 @@ fn extract_arrow_expr_owned(module: ast::Module) -> Option { } } -/// Owning variant of [`extract_fn_expr`] — consumes the module so the caller -/// can mutate the function body before lowering. -fn extract_fn_expr_owned(module: ast::Module) -> Option { - let item = module.body.into_iter().next()?; - let ast::ModuleItem::Stmt(ast::Stmt::Expr(expr_stmt)) = item else { - return None; - }; - let mut e = *expr_stmt.expr; - loop { - match e { - ast::Expr::Paren(p) => e = *p.expr, - ast::Expr::Fn(fn_expr) => return Some(fn_expr), - _ => return None, - } - } -} - /// Build `__perry_cv = ` by cloning a parsed `__perry_cv = undefined` /// assignment template and swapping its right-hand side. Avoids hand-building /// version-sensitive SWC `AssignExpr` nodes. diff --git a/crates/perry-hir/src/lower/context.rs b/crates/perry-hir/src/lower/context.rs index db28174b38..5c0fab436e 100644 --- a/crates/perry-hir/src/lower/context.rs +++ b/crates/perry-hir/src/lower/context.rs @@ -1200,17 +1200,6 @@ impl LoweringContext { } } - /// Current depth of the module-shadow stack (a scope mark). - pub(crate) fn module_shadow_mark(&self) -> usize { - self.module_shadow_stack.len() - } - - /// Restore the module-shadow stack to `mark`, re-exposing modules whose - /// shadowing local bindings went out of scope. - pub(crate) fn truncate_module_shadow(&mut self, mark: usize) { - self.module_shadow_stack.truncate(mark); - } - pub(crate) fn register_builtin_module_alias( &mut self, local_name: String, diff --git a/crates/perry-hir/src/lower/expr_call/intrinsics/eval_strict.rs b/crates/perry-hir/src/lower/expr_call/intrinsics/eval_strict.rs index 01838eba97..bda915e193 100644 --- a/crates/perry-hir/src/lower/expr_call/intrinsics/eval_strict.rs +++ b/crates/perry-hir/src/lower/expr_call/intrinsics/eval_strict.rs @@ -500,37 +500,3 @@ fn eval_module_has_strict_eval_arguments_violation( }; stmts.iter().any(|s| stmt_has_violation(s, top_strict)) } - -fn strict_eval_source_assigns_arguments(source: &str) -> bool { - let bytes = source.as_bytes(); - let needle = b"arguments"; - let mut i = 0usize; - while i + needle.len() <= bytes.len() { - if &bytes[i..i + needle.len()] != needle { - i += 1; - continue; - } - let before_ok = i == 0 || !is_ident_continue(bytes[i - 1]); - let after = i + needle.len(); - let after_ok = after == bytes.len() || !is_ident_continue(bytes[after]); - if before_ok && after_ok { - let mut j = after; - while j < bytes.len() && bytes[j].is_ascii_whitespace() { - j += 1; - } - if j < bytes.len() - && bytes[j] == b'=' - && bytes.get(j + 1).copied() != Some(b'=') - && bytes.get(j + 1).copied() != Some(b'>') - { - return true; - } - } - i = after; - } - false -} - -fn is_ident_continue(byte: u8) -> bool { - byte == b'_' || byte == b'$' || byte.is_ascii_alphanumeric() -} diff --git a/crates/perry-hir/src/lower/fn_ctor_env.rs b/crates/perry-hir/src/lower/fn_ctor_env.rs index 074220ea85..13b742a5ab 100644 --- a/crates/perry-hir/src/lower/fn_ctor_env.rs +++ b/crates/perry-hir/src/lower/fn_ctor_env.rs @@ -44,6 +44,8 @@ pub(crate) enum FnCtorShape { DynCtor(DynFnCtorKind), /// `var f = async function () {};` — a function-literal var, recorded so /// a later `f.constructor` resolves to the right dynamic ctor kind. + #[allow(dead_code)] + // payload retained for the planned `f.constructor` kind resolution; matched only via `_` today FnLiteral(DynFnCtorKind), } diff --git a/crates/perry-hir/src/lower/lowering_context.rs b/crates/perry-hir/src/lower/lowering_context.rs index fdb645a9d2..5cbde54d02 100644 --- a/crates/perry-hir/src/lower/lowering_context.rs +++ b/crates/perry-hir/src/lower/lowering_context.rs @@ -57,9 +57,6 @@ pub(crate) struct PrivateScope { /// synthesize a real class extending the concrete base. #[derive(Debug, Clone)] pub(crate) struct MixinFn { - /// The mixin function's single parameter — the name the returned class - /// `extends`. - pub(crate) param_name: String, /// The returned class EXPRESSION's own name, if it has one (`return class /// Named extends B {}`). `None` for the anonymous form, whose `.name` is /// the empty string per spec — a directly-returned class expression gets diff --git a/crates/perry-hir/src/lower/misc.rs b/crates/perry-hir/src/lower/misc.rs index 92e6d34ebc..ac19171eec 100644 --- a/crates/perry-hir/src/lower/misc.rs +++ b/crates/perry-hir/src/lower/misc.rs @@ -44,27 +44,6 @@ pub(crate) fn stmt_list_starts_with_use_strict_directive(stmts: &[ast::Stmt]) -> false } -pub(crate) fn module_starts_with_use_strict_directive(module: &ast::Module) -> bool { - for item in &module.body { - match item { - ast::ModuleItem::Stmt(stmt) => match is_use_strict_directive_stmt(stmt) { - Some(true) => return true, - Some(false) => continue, - None => return false, - }, - ast::ModuleItem::ModuleDecl(_) => return false, - } - } - false -} - -pub(crate) fn module_has_module_declaration(module: &ast::Module) -> bool { - module - .body - .iter() - .any(|item| matches!(item, ast::ModuleItem::ModuleDecl(_))) -} - /// Map a function's declared return type to a native-instance class when it /// matches a known stdlib pattern. Lets a wrapper function like /// `function openSocket(host, port): Socket { ... }` advertise that calls diff --git a/crates/perry-hir/src/lower/pre_scan.rs b/crates/perry-hir/src/lower/pre_scan.rs index 3aa2d09454..66d1ae75ed 100644 --- a/crates/perry-hir/src/lower/pre_scan.rs +++ b/crates/perry-hir/src/lower/pre_scan.rs @@ -409,7 +409,6 @@ pub(crate) fn pre_scan_mixin_functions(ast_module: &ast::Module, ctx: &mut Lower ctx.mixin_funcs.insert( fn_name, crate::lower::MixinFn { - param_name, class_expr_name: class_expr.ident.as_ref().map(|i| i.sym.to_string()), class_ast: Box::new((*class_expr.class).clone()), }, diff --git a/crates/perry-hir/src/lower_decl/class_captures.rs b/crates/perry-hir/src/lower_decl/class_captures.rs index 19220ab839..6673e4a262 100644 --- a/crates/perry-hir/src/lower_decl/class_captures.rs +++ b/crates/perry-hir/src/lower_decl/class_captures.rs @@ -274,13 +274,6 @@ pub fn synthesize_class_captures( // prologue ids when the closure body references them, and a closure // whose ONLY reference is the appended arg gets the id added to its // captures list below. - fn append_self_new_args_expr( - expr: &mut Expr, - class_name: &str, - cap_args: &[(LocalId, LocalId)], - ) { - append_new_args_expr(expr, class_name, cap_args, false) - } fn append_self_new_args_stmt( stmt: &mut Stmt, class_name: &str, diff --git a/crates/perry-runtime/src/array/species.rs b/crates/perry-runtime/src/array/species.rs index 938b4bda31..08e8011994 100644 --- a/crates/perry-runtime/src/array/species.rs +++ b/crates/perry-runtime/src/array/species.rs @@ -208,14 +208,6 @@ pub(crate) unsafe fn array_species_create_with_capacity( } } -/// `true` when `array_species_create` would take the default fast path — used -/// by callers that only need to *validate* the constructor (throwing on a bad -/// one) while keeping their existing plain-array result building, and want to -/// know whether a custom container must instead be populated element-by-element. -pub(crate) unsafe fn species_is_default(original: f64) -> bool { - matches!(resolve_species(original), SpeciesChoice::Default) -} - /// `true` when a species `result` (NaN-boxed) is an ordinary `ArrayHeader` — /// i.e. the default fast path — so the caller can use direct slot writes. pub(crate) unsafe fn species_result_is_plain_array(result: f64) -> bool { diff --git a/crates/perry-runtime/src/buffer/dataview.rs b/crates/perry-runtime/src/buffer/dataview.rs index 2ffc06d09c..589c48d91d 100644 --- a/crates/perry-runtime/src/buffer/dataview.rs +++ b/crates/perry-runtime/src/buffer/dataview.rs @@ -39,16 +39,6 @@ pub enum DataViewKind { } impl DataViewKind { - #[inline] - fn width(self) -> usize { - match self { - DataViewKind::Int8 | DataViewKind::Uint8 => 1, - DataViewKind::Int16 | DataViewKind::Uint16 => 2, - DataViewKind::Int32 | DataViewKind::Uint32 | DataViewKind::Float32 => 4, - DataViewKind::Float64 | DataViewKind::BigInt64 | DataViewKind::BigUint64 => 8, - } - } - /// Is this a BigInt-valued accessor (`getBigInt64`/`setBigUint64`/…)? Those /// read/write a NaN-boxed BigInt rather than a Number. #[inline] diff --git a/crates/perry-runtime/src/buffer/header.rs b/crates/perry-runtime/src/buffer/header.rs index b93938bb58..9c5d7ef408 100644 --- a/crates/perry-runtime/src/buffer/header.rs +++ b/crates/perry-runtime/src/buffer/header.rs @@ -17,12 +17,6 @@ fn buffer_payload_size(capacity: usize) -> usize { std::mem::size_of::() + capacity } -#[inline] -fn buffer_gc_total_size(capacity: usize) -> usize { - let payload = buffer_payload_size(capacity); - (crate::gc::GC_HEADER_SIZE + payload + 7) & !7 -} - /// Thread-local registry of buffer pointers for instanceof checks. /// Since BufferHeader has the same layout as ArrayHeader (no type_id field), /// we track buffer pointers separately to distinguish them from arrays. diff --git a/crates/perry-runtime/src/collection_iter.rs b/crates/perry-runtime/src/collection_iter.rs index d31cc88430..96712925d1 100644 --- a/crates/perry-runtime/src/collection_iter.rs +++ b/crates/perry-runtime/src/collection_iter.rs @@ -16,19 +16,9 @@ //! `js_set_from_iterable`, `js_weakmap_init_iterable`, `js_weakset_init_iterable`) //! call into here so the throw-vs-empty-vs-consume decision lives in one place. -use crate::array::ArrayHeader; use crate::value::{js_jsvalue_to_string, js_nanbox_get_pointer, JSValue, TAG_NULL, TAG_UNDEFINED}; use std::os::raw::c_int; -/// Outcome of classifying a constructor init argument. -pub(crate) enum InitIter { - /// `null` / `undefined` — treat as empty init, no entries. - Empty, - /// An iterable; the yielded values have been materialized into this - /// (NaN-box-stripped) Array pointer. - Values(*mut ArrayHeader), -} - /// `typeof`-style word for a non-iterable value, used to build the Node /// " is not iterable" message. `null`/`undefined` are handled by the /// caller (they never throw), so they are not produced here. @@ -398,25 +388,3 @@ fn value_display(value: f64) -> String { String::from_utf8_lossy(std::slice::from_raw_parts(data, byte_len)).into_owned() } } - -/// Classify a collection-constructor init argument: -/// - `null`/`undefined` → [`InitIter::Empty`], -/// - any iterable → materialize the yielded values into an Array -/// ([`InitIter::Values`]), -/// - anything else → throw the Node "not iterable" `TypeError`. -/// -/// The returned Array pointer is NaN-box-stripped (a raw `*mut ArrayHeader`). -pub(crate) fn classify_init(value: f64) -> InitIter { - let bits = value.to_bits(); - if bits == TAG_UNDEFINED || bits == TAG_NULL { - return InitIter::Empty; - } - if !is_iterable(value) { - throw_not_iterable(value); - } - // `js_for_of_to_array` returns a NaN-boxed (POINTER_TAG) Array f64 whose - // elements are exactly what `for...of value` would yield. - let arr_f64 = crate::array::js_for_of_to_array(value); - let arr_ptr = js_nanbox_get_pointer(arr_f64) as *mut ArrayHeader; - InitIter::Values(arr_ptr) -} diff --git a/crates/perry-runtime/src/date.rs b/crates/perry-runtime/src/date.rs index 495c6fe3b0..3efb17b699 100644 --- a/crates/perry-runtime/src/date.rs +++ b/crates/perry-runtime/src/date.rs @@ -872,13 +872,6 @@ fn jsvalue_to_number(v: f64) -> f64 { } } -/// True if a NaN-boxed JS value is `undefined`. -#[inline] -fn jsvalue_is_undefined(v: f64) -> bool { - let bits = v.to_bits(); - ((bits >> 48) & 0xFFFF) == 0x7FFC && (bits & 0xFF) == 0x01 -} - /// `Date.prototype.set*` family with optional trailing arguments (#2851). /// /// `field` selects which component the *leading* argument sets: diff --git a/crates/perry-runtime/src/fs/cp.rs b/crates/perry-runtime/src/fs/cp.rs index f25b736a80..633a3bc5ed 100644 --- a/crates/perry-runtime/src/fs/cp.rs +++ b/crates/perry-runtime/src/fs/cp.rs @@ -432,13 +432,6 @@ pub extern "C" fn js_fs_cp_sync_options(from_value: f64, to_value: f64, options_ } } -pub(crate) fn js_fs_cp_async_options(from_value: f64, to_value: f64, options_value: f64) -> i32 { - match js_fs_cp_async_result(from_value, to_value, options_value) { - Ok(()) => 1, - Err(err) => crate::exception::js_throw(err), - } -} - pub(crate) fn js_fs_cp_async_result( from_value: f64, to_value: f64, diff --git a/crates/perry-runtime/src/fs/validate.rs b/crates/perry-runtime/src/fs/validate.rs index 67c78f0e5f..9596770cba 100644 --- a/crates/perry-runtime/src/fs/validate.rs +++ b/crates/perry-runtime/src/fs/validate.rs @@ -627,18 +627,6 @@ pub(crate) fn validate_fs_mode(value: f64) { } } -pub(crate) fn fs_mode_value(value: f64) -> i32 { - validate_fs_mode(value); - let jv = JSValue::from_bits(value.to_bits()); - if is_nullish(jv) { - 0 - } else if jv.is_int32() { - jv.as_int32() - } else { - jv.as_number() as i32 - } -} - /// Validate that `value` is a finite integer in `[min, max]`. On type or /// range failure throws Node's `ERR_INVALID_ARG_TYPE` / `ERR_OUT_OF_RANGE` /// with the same `Received` clause shape Node uses. diff --git a/crates/perry-runtime/src/gc/barrier.rs b/crates/perry-runtime/src/gc/barrier.rs index c83276e943..b590b24aa6 100644 --- a/crates/perry-runtime/src/gc/barrier.rs +++ b/crates/perry-runtime/src/gc/barrier.rs @@ -490,134 +490,6 @@ pub(super) unsafe fn scan_dirty_slot_with_layout( visit_slot(slot, stats); } -pub(super) unsafe fn scan_dirty_slot_range( - slots: *mut u64, - slot_count: usize, - dirty_pages: &crate::fast_hash::PtrHashSet, - stats: &mut RememberedSetTraceStats, - visit_slot: &mut dyn FnMut(*mut u64, &mut RememberedSetTraceStats), -) { - if slots.is_null() || slot_count == 0 || dirty_pages.is_empty() { - return; - } - const PAGE_SHIFT: usize = 12; - const PAGE_SIZE: usize = 1 << PAGE_SHIFT; - - let slots_start = slots as usize; - let Some(slots_bytes) = slot_count.checked_mul(std::mem::size_of::()) else { - return; - }; - let Some(slots_end) = slots_start.checked_add(slots_bytes) else { - return; - }; - let mut ranges = Vec::<(usize, usize)>::new(); - - for &page in dirty_pages { - let page_start = page << PAGE_SHIFT; - let page_end = page_start + PAGE_SIZE; - if page_end <= slots_start || page_start >= slots_end { - continue; - } - stats.dirty_slot_pages_considered += 1; - let start_addr = page_start.max(slots_start); - let end_addr = page_end.min(slots_end); - let start_idx = (start_addr - slots_start).div_ceil(8); - let end_idx = (end_addr - slots_start).div_ceil(8); - if start_idx < end_idx && start_idx < slot_count { - ranges.push((start_idx, end_idx.min(slot_count))); - } - } - - if ranges.is_empty() { - return; - } - ranges.sort_unstable(); - let mut merged = Vec::<(usize, usize)>::with_capacity(ranges.len()); - for (start, end) in ranges { - if let Some((_, last_end)) = merged.last_mut() { - if start <= *last_end { - *last_end = (*last_end).max(end); - continue; - } - } - merged.push((start, end)); - } - - for (start, end) in merged { - stats.dirty_slot_ranges_scanned += 1; - for i in start..end { - stats.dirty_slots_scanned += 1; - let slot = slots.add(i); - crate::arena::old_page_account_dirty_slot(slot as usize); - visit_slot(slot, stats); - } - } -} - -pub(super) unsafe fn scan_dirty_slot_range_with_layout( - range: HeapSlotRange, - layout_kind: HeapChildSlotReadKind, - dirty_pages: &crate::fast_hash::PtrHashSet, - stats: &mut RememberedSetTraceStats, - visit_slot: &mut dyn FnMut(*mut u64, &mut RememberedSetTraceStats), -) { - if range.slots().is_null() || range.slot_count() == 0 || dirty_pages.is_empty() { - return; - } - const PAGE_SHIFT: usize = 12; - const PAGE_SIZE: usize = 1 << PAGE_SHIFT; - - let slots = range.slots(); - let slot_count = range.slot_count(); - let slots_start = slots as usize; - let Some(slots_bytes) = slot_count.checked_mul(std::mem::size_of::()) else { - return; - }; - let Some(slots_end) = slots_start.checked_add(slots_bytes) else { - return; - }; - let mut ranges = Vec::<(usize, usize)>::new(); - for &page in dirty_pages { - let page_start = page << PAGE_SHIFT; - let page_end = page_start + PAGE_SIZE; - let start = slots_start.max(page_start); - let end = slots_end.min(page_end); - if start >= end { - continue; - } - stats.dirty_slot_pages_considered += 1; - let first = (start - slots_start) / std::mem::size_of::(); - let last = (end - slots_start).div_ceil(std::mem::size_of::()); - ranges.push((first.min(slot_count), last.min(slot_count))); - } - - if ranges.is_empty() { - return; - } - ranges.sort_unstable(); - let mut merged = Vec::<(usize, usize)>::with_capacity(ranges.len()); - for (start, end) in ranges { - if let Some((_, last_end)) = merged.last_mut() { - if start <= *last_end { - *last_end = (*last_end).max(end); - continue; - } - } - merged.push((start, end)); - } - - for (start, end) in merged { - stats.dirty_slot_ranges_scanned += 1; - for i in start..end { - stats.dirty_slots_scanned += 1; - let slot = slots.add(i); - record_layout_child_slot_read(layout_kind); - crate::arena::old_page_account_dirty_slot(slot as usize); - visit_slot(slot, stats); - } - } -} - pub(super) unsafe fn scan_dirty_object_slots( header: *mut GcHeader, dirty_pages: &crate::fast_hash::PtrHashSet, diff --git a/crates/perry-runtime/src/gc/cycle.rs b/crates/perry-runtime/src/gc/cycle.rs index 043a4ce62b..e2bfc8c762 100644 --- a/crates/perry-runtime/src/gc/cycle.rs +++ b/crates/perry-runtime/src/gc/cycle.rs @@ -856,6 +856,8 @@ impl AtomicFinalizeCycleState { pub(super) struct GcCycleState { collection_kind: GcCollectionKind, + #[allow(dead_code)] + // captured trigger classification retained alongside collection_kind/progress_kind for cycle diagnostics trigger_kind: GcTriggerKind, progress_kind: GcProgressKind, phase: GcCyclePhase, diff --git a/crates/perry-runtime/src/gc/mod.rs b/crates/perry-runtime/src/gc/mod.rs index 80e80b588a..9ffc97b7e6 100644 --- a/crates/perry-runtime/src/gc/mod.rs +++ b/crates/perry-runtime/src/gc/mod.rs @@ -323,6 +323,7 @@ thread_local! { /// Suppress (or re-enable) lazy `ensure_gc_initialized` on this thread, returning /// the previous value. Used by the GC tests' `ScopedRootScannerRegistryGuard` to /// run collections against a hand-controlled root set. +#[allow(dead_code)] // test scaffolding: used only by ScopedRootScannerRegistryGuard under cfg(test) pub(crate) fn set_auto_gc_init_suppressed(suppressed: bool) -> bool { AUTO_GC_INIT_SUPPRESSED.with(|c| c.replace(suppressed)) } diff --git a/crates/perry-runtime/src/gc/roots.rs b/crates/perry-runtime/src/gc/roots.rs index fae364db35..d879c5eac3 100644 --- a/crates/perry-runtime/src/gc/roots.rs +++ b/crates/perry-runtime/src/gc/roots.rs @@ -180,6 +180,7 @@ thread_local! { /// Set (or clear) this thread's conservative-scan mode override, returning the /// previous value. +#[allow(dead_code)] // test-only scaffolding: GC unit tests (gc/tests) pin the scan mode via this override pub(crate) fn set_conservative_stack_scan_override( mode: Option, ) -> Option { diff --git a/crates/perry-runtime/src/gc/telemetry.rs b/crates/perry-runtime/src/gc/telemetry.rs index 9e3a8fa04d..6cd5afc9c4 100644 --- a/crates/perry-runtime/src/gc/telemetry.rs +++ b/crates/perry-runtime/src/gc/telemetry.rs @@ -92,6 +92,8 @@ pub(super) struct OldYoungEdgeVerifyStats { } impl OldYoungEdgeVerifyStats { + #[allow(dead_code)] + // GC old→young edge-verify telemetry hook; simple companion to record_missing_diag for diagnostic call sites #[inline] pub(super) fn record_missing(&mut self, parent: usize, slot: usize, child: usize) { self.record_missing_diag(parent, slot, child, 0, 0, false, false); diff --git a/crates/perry-runtime/src/gc/trace.rs b/crates/perry-runtime/src/gc/trace.rs index 45cf646cde..bef18bb800 100644 --- a/crates/perry-runtime/src/gc/trace.rs +++ b/crates/perry-runtime/src/gc/trace.rs @@ -754,6 +754,7 @@ pub(super) fn trace_one_worklist_header( } /// Trace from marked objects: follow references iteratively using a worklist. +#[allow(dead_code)] // test scaffolding: exercised only by gc::tests::layout_trace under cfg(test) pub(super) fn trace_marked_objects(valid_ptrs: &ValidPointerSet) { // Same MARK_SEEDS-based approach as the minor variant — root scans // populated `MARK_SEEDS` via `try_mark_value`, no need to walk arena diff --git a/crates/perry-runtime/src/gc/verify.rs b/crates/perry-runtime/src/gc/verify.rs index 81b9157f99..d675d9415c 100644 --- a/crates/perry-runtime/src/gc/verify.rs +++ b/crates/perry-runtime/src/gc/verify.rs @@ -628,6 +628,7 @@ impl MarkInvariantVerifyStats { } #[cold] +#[allow(dead_code)] // GC heap-invariant verifier (PERRY_GC_VERIFY_EVACUATION); driven by verify_marked_heap_no_unmarked_children and its cfg(test) callers in gc/tests/barrier.rs pub(super) fn panic_mark_invariant_verifier_failed(stats: MarkInvariantVerifyStats) -> ! { let missing = stats.first_missing.unwrap_or_default(); panic!( @@ -670,6 +671,7 @@ pub(super) unsafe fn verify_marked_object_child_marks( }); } +#[allow(dead_code)] // GC heap-invariant verifier exercised by cfg(test) suite in gc/tests/barrier.rs pub(super) fn verify_marked_heap_no_unmarked_children() -> MarkInvariantVerifyStats { let mut stats = MarkInvariantVerifyStats::default(); crate::arena::arena_walk_objects(|hp| unsafe { diff --git a/crates/perry-runtime/src/intl.rs b/crates/perry-runtime/src/intl.rs index 83d04b657a..6f6374c0ab 100644 --- a/crates/perry-runtime/src/intl.rs +++ b/crates/perry-runtime/src/intl.rs @@ -458,6 +458,7 @@ fn throw_invalid_language_tag(tag: &str) -> ! { crate::exception::js_throw(js_nanbox_pointer(err as i64)) } +#[allow(dead_code)] // used only in the #[cfg(not(feature = "intl-locale"))] fallback branch fn canonical_locale(tag: &str) -> Option { if tag.is_empty() { return None; diff --git a/crates/perry-runtime/src/intl/date_collator.rs b/crates/perry-runtime/src/intl/date_collator.rs index 2d0e316c85..0758480a27 100644 --- a/crates/perry-runtime/src/intl/date_collator.rs +++ b/crates/perry-runtime/src/intl/date_collator.rs @@ -54,19 +54,6 @@ fn date_arg_to_clipped_ms(value: f64) -> f64 { ms.trunc() } -pub(crate) extern "C" fn date_time_format_format_thunk( - _closure: *const ClosureHeader, - value: f64, -) -> f64 { - let obj = this_intl_object("format", KIND_DATE_TIME); - let temporal_kind = crate::temporal::temporal_kind(value); - if let Some(kind) = temporal_kind { - validate_temporal_dtf_overlap(kind, obj); - } - let ms = date_arg_to_clipped_ms(value); - string_value(&format_ms_with_dtf_obj(obj, ms, temporal_kind)) -} - pub(crate) extern "C" fn date_time_format_bound_format_thunk( closure: *const ClosureHeader, value: f64, @@ -91,13 +78,6 @@ pub(crate) extern "C" fn date_time_format_format_getter_thunk( get_field(obj, KEY_DTF_BOUND_FORMAT) } -/// Fallback path: no DTF object context, produce short UTC date. Still used by -/// some internal callers that pre-date the obj-aware thunks. -pub(crate) fn date_time_format_format_value(value: f64) -> f64 { - let ms = date_arg_to_clipped_ms(value); - string_value(&date_short_utc_from_ms(ms)) -} - pub(crate) extern "C" fn date_time_format_to_parts_thunk( _closure: *const ClosureHeader, value: f64, @@ -696,15 +676,6 @@ fn time_zone_name_display(time_zone: &str, style: &str) -> String { "GMT".to_string() } -/// `M/D/YYYY` short form rendered directly from an integer-millisecond -/// timestamp. Shared by `format`, `formatToParts`, and both range variants so -/// all four stay byte-for-byte consistent. -pub(crate) fn date_short_utc_from_ms(ms: f64) -> String { - let secs = (ms as i64).div_euclid(1000); - let (year, month, day, _, _, _) = crate::date::timestamp_to_components(secs); - format!("{}/{}/{}", month, day, year) -} - pub(crate) fn date_range_parts_from_ms(ms: f64) -> Vec<(&'static str, String)> { let secs = (ms as i64).div_euclid(1000); let (year, month, day, _, _, _) = crate::date::timestamp_to_components(secs); diff --git a/crates/perry-runtime/src/json/reviver.rs b/crates/perry-runtime/src/json/reviver.rs index 0e58d20807..3894f931b2 100644 --- a/crates/perry-runtime/src/json/reviver.rs +++ b/crates/perry-runtime/src/json/reviver.rs @@ -582,10 +582,6 @@ unsafe fn object_child_source( } } -unsafe fn holder_ptr_from_bits(bits: u64) -> *mut crate::ObjectHeader { - (bits & POINTER_MASK) as *mut crate::ObjectHeader -} - unsafe fn delete_property_or_keep( holder_handle: &crate::gc::RuntimeHandle<'_>, key_handle: &crate::gc::RuntimeHandle<'_>, diff --git a/crates/perry-runtime/src/node_stream_constructors/web_adapter.rs b/crates/perry-runtime/src/node_stream_constructors/web_adapter.rs index 1fb410d1a8..fbfd78eeca 100644 --- a/crates/perry-runtime/src/node_stream_constructors/web_adapter.rs +++ b/crates/perry-runtime/src/node_stream_constructors/web_adapter.rs @@ -94,6 +94,7 @@ fn web_readable_close() -> Option { load_web_callback!(WEB_READABLE_CLOSE_PTR, WebReadableCloseFn) } +#[allow(dead_code)] // accessor for the deliberately-registered WEB_READABLE_ERROR_PTR callback (set in register); consumer not yet wired fn web_readable_error() -> Option { load_web_callback!(WEB_READABLE_ERROR_PTR, WebReadableErrorFn) } diff --git a/crates/perry-runtime/src/node_stream_iter_helpers.rs b/crates/perry-runtime/src/node_stream_iter_helpers.rs index 7fa3ef3c59..ac1b503d88 100644 --- a/crates/perry-runtime/src/node_stream_iter_helpers.rs +++ b/crates/perry-runtime/src/node_stream_iter_helpers.rs @@ -142,27 +142,6 @@ pub(super) fn promise_from_capture( crate::value::js_nanbox_get_pointer(f64::from_bits(bits)) as *mut crate::promise::Promise } -/// Abort-listener body: reject the captured Promise with an AbortError. -pub(super) extern "C" fn ns_abort_reject(closure: *const ClosureHeader) -> f64 { - let p = promise_from_capture(closure, 0); - if !p.is_null() { - crate::promise::js_promise_reject(p, abort_error()); - } - f64::from_bits(TAG_UNDEFINED) -} - -/// Deferred-resolve body: fulfill the captured Promise (slot 0) with the -/// captured value (slot 1) on the next microtask — a no-op if an abort -/// already rejected it. -pub(super) extern "C" fn ns_deferred_resolve(closure: *const ClosureHeader) -> f64 { - let p = promise_from_capture(closure, 0); - let value = f64::from_bits(js_closure_get_capture_ptr(closure, 1) as u64); - if !p.is_null() { - crate::promise::js_promise_resolve(p, value); - } - f64::from_bits(TAG_UNDEFINED) -} - pub(super) extern "C" fn ns_stream_abort_listener(closure: *const ClosureHeader) -> f64 { if closure.is_null() { return f64::from_bits(TAG_UNDEFINED); @@ -172,47 +151,6 @@ pub(super) extern "C" fn ns_stream_abort_listener(closure: *const ClosureHeader) f64::from_bits(TAG_UNDEFINED) } -/// Build a pending Promise for a consuming helper running under a -/// not-yet-aborted signal: an abort listener rejects it with an -/// AbortError, while a queued microtask fulfills it with `value` if no -/// abort fires first. This matches Node's async timing — the operation -/// is in flight when a synchronous `controller.abort()` lands before -/// the awaiter resumes. -pub(super) fn deferred_promise(signal: f64, value: f64) -> f64 { - let promise = crate::promise::js_promise_new(); - let promise_box = box_pointer(promise as *const u8); - - if let Some(sig_obj) = object_ptr_from_value(signal) { - let reject_cl = js_closure_alloc(ns_abort_reject as *const u8, 1); - crate::closure::js_closure_set_capture_ptr(reject_cl, 0, promise_box.to_bits() as i64); - crate::url::js_abort_signal_add_listener( - sig_obj, - string_value(b"abort"), - box_pointer(reject_cl as *const u8), - ); - } - - let resolve_cl = js_closure_alloc(ns_deferred_resolve as *const u8, 2); - crate::closure::js_closure_set_capture_ptr(resolve_cl, 0, promise_box.to_bits() as i64); - crate::closure::js_closure_set_capture_ptr(resolve_cl, 1, value.to_bits() as i64); - crate::builtins::js_queue_microtask(resolve_cl as i64); - - promise_box -} - -/// Settle a consuming helper's result under any governing signal: reject -/// now if already aborted, defer if a signal is pending, else resolve. -pub(super) fn settle_consuming(this: f64, opts: f64, value: f64) -> f64 { - if let Some(err) = readable_hidden_error(this) { - return rejected_promise(err); - } - match effective_signal(this, opts) { - Some(sig) if signal_is_aborted(sig) => rejected_promise(abort_error()), - Some(sig) => deferred_promise(sig, value), - None => resolved_promise(value), - } -} - /// Carry a lazy helper's source error and governing signal onto its /// freshly-built result stream so a downstream consuming helper can /// observe an abort or error that happens later in the chain. diff --git a/crates/perry-runtime/src/node_stream_readable_read.rs b/crates/perry-runtime/src/node_stream_readable_read.rs index 2b42e0dd7a..69f71f2a4e 100644 --- a/crates/perry-runtime/src/node_stream_readable_read.rs +++ b/crates/perry-runtime/src/node_stream_readable_read.rs @@ -285,17 +285,3 @@ pub(super) fn read_stream_object_mode_chunk(stream: f64) -> f64 { } chunk } - -pub(super) fn string_chunk_to_buffer(value: f64) -> Option { - let jsval = JSValue::from_bits(value.to_bits()); - if !jsval.is_any_string() { - return None; - } - let ptr = crate::value::js_get_string_pointer_unified(value) as *const crate::StringHeader; - if ptr.is_null() || (ptr as usize) < 0x10000 { - return None; - } - Some(box_pointer( - crate::buffer::js_buffer_from_string(ptr, 0) as *const u8 - )) -} diff --git a/crates/perry-runtime/src/node_stream_readwrite.rs b/crates/perry-runtime/src/node_stream_readwrite.rs index 72bf46a350..92e9130110 100644 --- a/crates/perry-runtime/src/node_stream_readwrite.rs +++ b/crates/perry-runtime/src/node_stream_readwrite.rs @@ -1729,10 +1729,6 @@ pub(crate) fn js_node_stream_is_stub_ended_after_read(stream: f64) -> bool { stream_hidden_ended(stream) } -pub(crate) fn js_node_stream_is_stub_ended(stream: f64) -> bool { - stream_hidden_ended(stream) -} - #[cfg(test)] pub(crate) fn test_set_hidden_error(stream: f64, err: f64) { set_hidden_value(stream, hidden_error_key(), err); diff --git a/crates/perry-runtime/src/node_submodules/stream_promises.rs b/crates/perry-runtime/src/node_submodules/stream_promises.rs index 1d96a3c1f0..12336c96b1 100644 --- a/crates/perry-runtime/src/node_submodules/stream_promises.rs +++ b/crates/perry-runtime/src/node_submodules/stream_promises.rs @@ -19,7 +19,7 @@ use crate::object::{ js_object_alloc, js_object_get_field_by_name_f64, js_object_set_field_by_name, ObjectHeader, }; use crate::string::js_string_from_bytes; -use crate::value::{JSValue, TAG_FALSE}; +use crate::value::JSValue; use std::os::raw::c_int; #[inline] @@ -114,10 +114,6 @@ pub(crate) fn options_signal(options: f64) -> Option { get_object_property(options, b"signal") } -fn option_is_false(options: f64, name: &[u8]) -> bool { - get_object_property(options, name).is_some_and(|value| value.to_bits() == TAG_FALSE) -} - pub(crate) fn signal_aborted(signal: f64) -> bool { get_object_property(signal, b"aborted").is_some_and(|v| crate::value::js_is_truthy(v) != 0) } diff --git a/crates/perry-runtime/src/node_submodules/test.rs b/crates/perry-runtime/src/node_submodules/test.rs index 978f59dbf8..219c40f3d3 100644 --- a/crates/perry-runtime/src/node_submodules/test.rs +++ b/crates/perry-runtime/src/node_submodules/test.rs @@ -1612,11 +1612,6 @@ fn reporter_with_kind(kind: i32, source: f64) -> f64 { readable_from_text(output) } -pub(crate) extern "C" fn thunk_reporter(closure: *const ClosureHeader, source: f64) -> f64 { - let kind = js_closure_get_capture_f64(closure, 0) as i32; - reporter_with_kind(kind, source) -} - pub(crate) extern "C" fn thunk_reporter_spec(_closure: *const ClosureHeader, source: f64) -> f64 { reporter_with_kind(REPORTER_SPEC, source) } diff --git a/crates/perry-runtime/src/node_test.rs b/crates/perry-runtime/src/node_test.rs index 4d4afd5c52..b6d4c7e0da 100644 --- a/crates/perry-runtime/src/node_test.rs +++ b/crates/perry-runtime/src/node_test.rs @@ -56,43 +56,6 @@ extern "C" fn zero0(_closure: *const ClosureHeader) -> f64 { 0.0 } -extern "C" fn mock_fn_thunk( - _closure: *const ClosureHeader, - _implementation: f64, - _options: f64, -) -> f64 { - mock_function_value() -} - -extern "C" fn mock_property_thunk( - _closure: *const ClosureHeader, - _target: f64, - _property: f64, - _value: f64, -) -> f64 { - object_value(crate::object::js_object_alloc(0, 0)) -} - -fn legacy_node_test_mock_fn(_implementation: f64, _options: f64) -> f64 { - mock_function_value() -} - -fn legacy_node_test_mock_property(_target: f64, _property: f64, _value: f64) -> f64 { - object_value(crate::object::js_object_alloc(0, 0)) -} - -fn test_function_value(name: &str) -> f64 { - let value = fn_value(noop3 as *const u8, name, 3); - if matches!(name, "suite" | "describe" | "it") { - let closure_ptr = crate::value::js_nanbox_get_pointer(value) as usize; - for method in ["skip", "todo", "only"] { - let method_value = fn_value(noop3 as *const u8, method, 3); - crate::closure::closure_set_dynamic_prop(closure_ptr, method, method_value); - } - } - value -} - fn mock_context_object() -> *mut ObjectHeader { let obj = crate::object::js_object_alloc(CLASS_ID_MOCK_CONTEXT, 0); let calls = crate::array::js_array_alloc(0); @@ -129,60 +92,6 @@ fn mock_function_value() -> f64 { value } -fn mock_timers_object() -> *mut ObjectHeader { - let obj = crate::object::js_object_alloc(0, 0); - for name in ["enable", "reset", "tick", "runAll", "setTime"] { - set(obj, name, fn_value(noop1 as *const u8, name, 1)); - } - let dispose_fn = fn_value(noop0 as *const u8, "[Symbol.dispose]", 0); - set(obj, "@@__perry_wk_dispose", dispose_fn); - let dispose = crate::symbol::well_known_symbol("dispose"); - if !dispose.is_null() { - let obj_value = object_value(obj); - let symbol_value = f64::from_bits(JSValue::pointer(dispose as *const u8).bits()); - unsafe { - crate::symbol::js_object_set_symbol_property(obj_value, symbol_value, dispose_fn); - } - } - obj -} - -fn mock_tracker_object() -> *mut ObjectHeader { - let obj = crate::object::js_object_alloc(CLASS_ID_MOCK_TRACKER, 0); - set(obj, "fn", fn_value(mock_fn_thunk as *const u8, "fn", 2)); - set(obj, "method", fn_value(noop3 as *const u8, "method", 3)); - set(obj, "getter", fn_value(noop3 as *const u8, "getter", 3)); - set(obj, "setter", fn_value(noop3 as *const u8, "setter", 3)); - set( - obj, - "property", - fn_value(mock_property_thunk as *const u8, "property", 3), - ); - set(obj, "reset", fn_value(noop0 as *const u8, "reset", 0)); - set( - obj, - "restoreAll", - fn_value(noop0 as *const u8, "restoreAll", 0), - ); - set(obj, "timers", object_value(mock_timers_object())); - obj -} - -fn snapshot_object() -> *mut ObjectHeader { - let obj = crate::object::js_object_alloc(0, 0); - set( - obj, - "setDefaultSnapshotSerializers", - fn_value(noop1 as *const u8, "setDefaultSnapshotSerializers", 1), - ); - set( - obj, - "setResolveSnapshotPath", - fn_value(noop1 as *const u8, "setResolveSnapshotPath", 1), - ); - obj -} - pub fn property(property: &str) -> Option { match property { // #3719: `expectFailure` is a current Node `node:test` named export diff --git a/crates/perry-runtime/src/object/assert.rs b/crates/perry-runtime/src/object/assert.rs index f2ba8a5334..43a1b7a3df 100644 --- a/crates/perry-runtime/src/object/assert.rs +++ b/crates/perry-runtime/src/object/assert.rs @@ -485,12 +485,6 @@ fn promise_value_from_ptr(promise: *mut crate::promise::Promise) -> f64 { f64::from_bits(crate::value::JSValue::pointer(promise as *const u8).bits()) } -fn fulfilled_promise(value: f64) -> *mut crate::promise::Promise { - let promise = crate::promise::js_promise_new(); - crate::promise::js_promise_resolve(promise, value); - promise -} - fn rejected_promise(reason: f64) -> *mut crate::promise::Promise { let promise = crate::promise::js_promise_new(); crate::promise::js_promise_reject(promise, reason); diff --git a/crates/perry-runtime/src/object/mod.rs b/crates/perry-runtime/src/object/mod.rs index e15034cd1b..3a3786eb56 100644 --- a/crates/perry-runtime/src/object/mod.rs +++ b/crates/perry-runtime/src/object/mod.rs @@ -67,7 +67,6 @@ pub(crate) use native_module::{class_prototype_ref_id, SYMBOL_BOUND_METHOD_NAME} mod native_module_crypto_key_object; mod native_module_crypto_random; mod native_module_dispatch; -mod native_module_dispatch_crypto; mod native_module_registry; pub(crate) use native_module_registry::js_nm_enable_install_all; pub(crate) use native_module_registry::nm_ctor_lookup; diff --git a/crates/perry-runtime/src/object/native_module/callable_exports.rs b/crates/perry-runtime/src/object/native_module/callable_exports.rs index c0136cb3c5..da5d2e5bc7 100644 --- a/crates/perry-runtime/src/object/native_module/callable_exports.rs +++ b/crates/perry-runtime/src/object/native_module/callable_exports.rs @@ -1557,21 +1557,6 @@ pub(crate) fn timers_promises_parent_namespace() -> f64 { }) } -extern "C" fn util_debuglog_logger_thunk( - _closure: *const crate::closure::ClosureHeader, - _arg: f64, -) -> f64 { - f64::from_bits(crate::value::TAG_UNDEFINED) -} - -pub(crate) fn util_debuglog_logger_value() -> f64 { - let func_ptr = util_debuglog_logger_thunk as *const u8; - crate::closure::js_register_closure_arity(func_ptr, 1); - let closure = crate::closure::js_closure_alloc_singleton(func_ptr); - set_bound_native_closure_name(closure, "debuglog"); - crate::value::js_nanbox_pointer(closure as i64) -} - fn attach_tty_stream_prototype(constructor_value: f64, name: &str) { crate::tty::attach_tty_constructor_prototype(constructor_value, name); } diff --git a/crates/perry-runtime/src/object/native_module_dispatch_crypto.rs b/crates/perry-runtime/src/object/native_module_dispatch_crypto.rs deleted file mode 100644 index 8313c6517f..0000000000 --- a/crates/perry-runtime/src/object/native_module_dispatch_crypto.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Crypto helpers used by native module method dispatch. - -use crate::JSValue; - -fn crypto_dispatch_value_addr(value: f64) -> usize { - let bits = value.to_bits(); - if (bits >> 48) >= 0x7FF8 { - (bits & 0x0000_FFFF_FFFF_FFFF) as usize - } else { - bits as usize - } -} - -fn crypto_random_fill_number_arg(value: f64, name: &str) -> Option { - let js = JSValue::from_bits(value.to_bits()); - if js.is_undefined() { - return None; - } - if !js.is_number() && !js.is_int32() { - let message = format!( - "The \"{}\" argument must be of type number. Received {}", - name, - crate::fs::validate::describe_received(value) - ); - crate::fs::validate::throw_type_error_with_code(&message, "ERR_INVALID_ARG_TYPE"); - } - Some(if js.is_int32() { - js.as_int32() as f64 - } else { - value - }) -} - -fn crypto_random_fill_range(total: usize, offset_bits: f64, size_bits: f64) -> (usize, usize) { - let offset = match crypto_random_fill_number_arg(offset_bits, "offset") { - Some(n) if n.is_finite() && n >= 0.0 && n <= total as f64 => n as usize, - Some(n) => { - let message = format!( - "The value of \"offset\" is out of range. It must be >= 0 && <= {}. Received {}", - total, n - ); - crate::fs::validate::throw_range_error_with_code(&message); - } - None => 0, - }; - let size = match crypto_random_fill_number_arg(size_bits, "size") { - Some(n) if n.is_finite() && n >= 0.0 && n <= i32::MAX as f64 => n as usize, - Some(n) => { - let message = format!( - "The value of \"size\" is out of range. It must be >= 0 && <= 2147483647. Received {}", - n - ); - crate::fs::validate::throw_range_error_with_code(&message); - } - None => total.saturating_sub(offset), - }; - let end = offset.saturating_add(size); - if end > total { - let message = format!( - "The value of \"size + offset\" is out of range. It must be <= {}. Received {}", - total, end - ); - crate::fs::validate::throw_range_error_with_code(&message); - } - (offset, size) -} - -fn crypto_random_fill_invalid_buf(value: f64) -> ! { - let message = format!( - "The \"buf\" argument must be an instance of Buffer, TypedArray, DataView, or ArrayBuffer. Received {}", - crate::fs::validate::describe_received(value) - ); - crate::fs::validate::throw_type_error_with_code(&message, "ERR_INVALID_ARG_TYPE") -} - -pub(super) unsafe fn crypto_random_fill_sync_dispatch( - target: f64, - offset_bits: f64, - size_bits: f64, -) -> f64 { - use rand::RngCore; - - let addr = crypto_dispatch_value_addr(target); - if crate::typedarray::lookup_typed_array_kind(addr).is_some() { - let ta = addr as *mut crate::typedarray::TypedArrayHeader; - if let Some(data) = crate::typedarray::typed_array_bytes_mut(ta) { - let elem_size = (*ta).elem_size as usize; - let len = if elem_size == 0 { - 0 - } else { - data.len() / elem_size - }; - let (start_elem, count_elem) = crypto_random_fill_range(len, offset_bits, size_bits); - let start = start_elem.saturating_mul(elem_size); - let end = start - .saturating_add(count_elem.saturating_mul(elem_size)) - .min(data.len()); - if end > start { - rand::thread_rng().fill_bytes(&mut data[start..end]); - } - return target; - } - crypto_random_fill_invalid_buf(target); - } - if crate::buffer::is_registered_buffer(addr) { - let buf = addr as *mut crate::buffer::BufferHeader; - let total = (*buf).length as usize; - let (start, count) = crypto_random_fill_range(total, offset_bits, size_bits); - if count > 0 { - let data = crate::buffer::buffer_data_mut(buf); - rand::thread_rng().fill_bytes(std::slice::from_raw_parts_mut(data.add(start), count)); - } - return target; - } - crypto_random_fill_invalid_buf(target); -} diff --git a/crates/perry-runtime/src/object/object_ops/define_properties.rs b/crates/perry-runtime/src/object/object_ops/define_properties.rs index 6c3f356434..f48a0807b1 100644 --- a/crates/perry-runtime/src/object/object_ops/define_properties.rs +++ b/crates/perry-runtime/src/object/object_ops/define_properties.rs @@ -103,8 +103,6 @@ pub extern "C" fn js_object_define_properties(target: f64, descriptors: f64) -> target } -const TAG_UNDEFINED_LOCAL: u64 = 0x7FFC_0000_0000_0001; - /// Coerce an arbitrary key value (f64 — usually a STRING_TAG NaN-box) to a /// `*const StringHeader` for use with `js_object_get_field_by_name_f64`. /// Returns null if the value isn't string-like. diff --git a/crates/perry-runtime/src/path.rs b/crates/perry-runtime/src/path.rs index 349ba09a07..4052d236d5 100644 --- a/crates/perry-runtime/src/path.rs +++ b/crates/perry-runtime/src/path.rs @@ -465,6 +465,10 @@ fn join_win32_paths(base: &str, tail: &str) -> String { } } +pub(crate) fn resolve_win32_str(path_str: &str) -> String { + win32_resolve_inner(path_str) +} + fn win32_resolve_inner(path_str: &str) -> String { let split = split_win32(path_str); if split.is_absolute { @@ -497,10 +501,6 @@ fn win32_resolve_inner(path_str: &str) -> String { normalize_win32_str(&path) } -pub(crate) fn resolve_win32_str(path_str: &str) -> String { - win32_resolve_inner(path_str) -} - /// Get directory name from path — Node's `path.posix.dirname`, which is purely /// lexical. The previous implementation delegated to Rust's `Path::parent()`, /// whose OS path semantics normalize components away and disagree with Node diff --git a/crates/perry-runtime/src/promise/keyed_table.rs b/crates/perry-runtime/src/promise/keyed_table.rs index ebf35197f1..9e70bb4906 100644 --- a/crates/perry-runtime/src/promise/keyed_table.rs +++ b/crates/perry-runtime/src/promise/keyed_table.rs @@ -177,6 +177,7 @@ impl PromiseKeyedTable { } #[inline] + #[allow(dead_code)] // used only by #[cfg(test)] assertions in this module pub(super) fn is_empty(&self) -> bool { self.entries.is_empty() } diff --git a/crates/perry-runtime/src/promise/then.rs b/crates/perry-runtime/src/promise/then.rs index 33ff71d78d..1808cab394 100644 --- a/crates/perry-runtime/src/promise/then.rs +++ b/crates/perry-runtime/src/promise/then.rs @@ -925,19 +925,6 @@ fn throw_promise_prototype_incompatible_receiver(method: &str, receiver: f64) -> crate::exception::js_throw(f64::from_bits(err_value)) } -fn promise_prototype_receiver(method: &str) -> *mut Promise { - let receiver = crate::object::js_implicit_this_get(); - if js_value_is_promise(receiver) != 0 { - return crate::value::js_nanbox_get_pointer(receiver) as *mut Promise; - } - // `class X extends Promise` instance: unwrap its hidden backing Promise cell - // so `inst.then/catch(...)` dispatches against the real promise state. - if let Some(backing) = super::subclass::subclass_backing_promise(receiver) { - return backing; - } - throw_promise_prototype_incompatible_receiver(method, receiver) -} - /// ECMA-262 Invoke(receiver, "then", args): read the `then` property and call it. /// Unlike `js_native_call_method`, this reads the own/inherited `then` property /// first (invoking accessor getters) and throws TypeError if it is not callable — @@ -1444,35 +1431,6 @@ pub(crate) extern "C" fn promise_prototype_finally_thunk( call_receiver_then(receiver, &args) } -extern "C" fn promise_then_bound( - closure: *const crate::closure::ClosureHeader, - on_fulfilled: f64, - on_rejected: f64, -) -> f64 { - let p = crate::closure::js_closure_get_capture_ptr(closure, 0) as *mut Promise; - box_promise_ptr(js_promise_then( - p, - arg_to_closure(on_fulfilled), - arg_to_closure(on_rejected), - )) -} - -extern "C" fn promise_catch_bound( - closure: *const crate::closure::ClosureHeader, - on_rejected: f64, -) -> f64 { - let p = crate::closure::js_closure_get_capture_ptr(closure, 0) as *mut Promise; - box_promise_ptr(js_promise_catch(p, arg_to_closure(on_rejected))) -} - -extern "C" fn promise_finally_bound( - closure: *const crate::closure::ClosureHeader, - on_finally: f64, -) -> f64 { - let p = crate::closure::js_closure_get_capture_ptr(closure, 0) as *mut Promise; - box_promise_ptr(js_promise_finally(p, arg_to_closure(on_finally))) -} - /// Return the `Promise.prototype[property]` closure for a promise's /// `then`/`catch`/`finally` value-read, or `None` for any other property. /// Returns the shared prototype method so `p.then === Promise.prototype.then` diff --git a/crates/perry-runtime/src/temporal/dispatch.rs b/crates/perry-runtime/src/temporal/dispatch.rs index 2ab3828ad7..24b9ac7531 100644 --- a/crates/perry-runtime/src/temporal/dispatch.rs +++ b/crates/perry-runtime/src/temporal/dispatch.rs @@ -13,27 +13,6 @@ use crate::value::JSValue; // ---- argument coercion ---------------------------------------------------- -/// `ToNumber(args[i])`, or `NaN` if the argument is absent. -#[inline] -pub(crate) fn num_arg(args: &[f64], i: usize) -> f64 { - match args.get(i) { - Some(&v) => JSValue::from_bits(v.to_bits()).to_number(), - None => f64::NAN, - } -} - -/// `args[i]` coerced to an integer for a Temporal numeric field. Absent / -/// non-finite → 0 (Temporal treats missing duration/time fields as 0). -#[inline] -pub(crate) fn int_arg(args: &[f64], i: usize) -> i64 { - let n = num_arg(args, i); - if n.is_finite() { - n.trunc() as i64 - } else { - 0 - } -} - /// Saturate an integer Temporal time field into a `u8` slot: any value outside /// `0..=u8::MAX` maps to `u8::MAX`. Every `u8` time field's valid maximum is /// below 255, so `temporal_rs`'s range check then rejects it with a RangeError — diff --git a/crates/perry-runtime/src/typedarray/mod.rs b/crates/perry-runtime/src/typedarray/mod.rs index ab04256e01..c7d191117b 100644 --- a/crates/perry-runtime/src/typedarray/mod.rs +++ b/crates/perry-runtime/src/typedarray/mod.rs @@ -9,7 +9,6 @@ //! Pointers are NaN-boxed with POINTER_TAG (0x7FFD) and tracked in //! TYPED_ARRAY_REGISTRY for `instanceof` and console.log formatting. -use std::alloc::Layout; use std::cell::RefCell; use std::ptr; use std::sync::atomic::{AtomicU64, Ordering}; @@ -697,24 +696,12 @@ unsafe fn native_memory_copy_accepts_buffer(addr: usize) -> bool { true } -fn ta_layout(capacity: u32, elem_size: usize) -> Layout { - let total = std::mem::size_of::() + (capacity as usize) * elem_size; - let total = total.max(std::mem::size_of::() + elem_size); - Layout::from_size_align(total, 8).unwrap() -} - #[inline] fn typed_array_payload_size(capacity: u32, elem_size: usize) -> usize { let total = std::mem::size_of::() + (capacity as usize) * elem_size; total.max(std::mem::size_of::() + elem_size) } -#[inline] -fn typed_array_gc_total_size(capacity: u32, elem_size: usize) -> usize { - let payload = typed_array_payload_size(capacity, elem_size); - (crate::gc::GC_HEADER_SIZE + payload + 7) & !7 -} - /// Allocate a zero-filled typed array of `length` elements. pub fn typed_array_alloc(kind: u8, length: u32) -> *mut TypedArrayHeader { let elem_size = elem_size_for_kind(kind); diff --git a/crates/perry-runtime/src/url/mod.rs b/crates/perry-runtime/src/url/mod.rs index dc266dd774..0a4c033d48 100644 --- a/crates/perry-runtime/src/url/mod.rs +++ b/crates/perry-runtime/src/url/mod.rs @@ -146,19 +146,6 @@ pub(crate) fn object_prop_f64(obj: *mut ObjectHeader, key: &str) -> f64 { crate::object::js_object_get_field_by_name_f64(obj, key_ptr) } -/// Read a `*mut StringHeader` (NULL → empty) into a Rust `String`. -pub(crate) fn string_header_to_string(value: *mut crate::StringHeader) -> String { - if value.is_null() { - return String::new(); - } - unsafe { - let len = (*value).byte_len as usize; - let data_ptr = (value as *const u8).add(std::mem::size_of::()); - let slice = std::slice::from_raw_parts(data_ptr, len); - String::from_utf8_lossy(slice).into_owned() - } -} - /// WHATWG host canonicalization via the `url` crate (#3056, #3059). /// /// Perry's URL uses a custom hostname parser that runs only IDNA diff --git a/crates/perry-runtime/src/url/node_compat.rs b/crates/perry-runtime/src/url/node_compat.rs index 7a37cf7b29..31687f92e5 100644 --- a/crates/perry-runtime/src/url/node_compat.rs +++ b/crates/perry-runtime/src/url/node_compat.rs @@ -839,14 +839,6 @@ const LEGACY_URL_KEYS: [&str; 12] = [ "pathname", "path", "href", ]; -fn string_or_null(value: String) -> f64 { - if value.is_empty() { - null_f64() - } else { - create_string_f64(&value) - } -} - fn create_legacy_url_object(values: [f64; 12]) -> *mut ObjectHeader { let obj = js_object_alloc(0, LEGACY_URL_KEYS.len() as u32); let mut keys = js_array_alloc(LEGACY_URL_KEYS.len() as u32); @@ -941,8 +933,8 @@ pub extern "C" fn js_url_legacy_parse( crate::value::js_nanbox_pointer(obj as i64) } -/// `Some("")` is a legitimate value (`file:///a` has `host === ""`), so this is -/// NOT `string_or_null`, which collapses the empty string to null. +/// `Some("")` is a legitimate value (`file:///a` has `host === ""`), so the +/// empty string is preserved rather than collapsed to null. fn opt_string_f64(v: Option) -> f64 { match v { Some(s) => create_string_f64(&s), @@ -950,10 +942,6 @@ fn opt_string_f64(v: Option) -> f64 { } } -fn protocol_null_or_slashes(input: &str, protocol_is_null: bool, host: &str) -> bool { - protocol_is_null || input.starts_with("//") || input.contains("://") || !host.is_empty() -} - /// WHATWG `URL.join` of `to` onto base `from`, or `None` when `from` isn't a /// parseable absolute URL. Cfg-paired: the off twin returns `None` (no `url` /// crate), so the caller falls back to the hand-rolled `resolve_url`. diff --git a/crates/perry-stdlib/src/crypto/sign.rs b/crates/perry-stdlib/src/crypto/sign.rs index a4928ace6b..e5eb04a331 100644 --- a/crates/perry-stdlib/src/crypto/sign.rs +++ b/crates/perry-stdlib/src/crypto/sign.rs @@ -1,21 +1,5 @@ use super::*; -/// Resolve `(start, end)` byte indices from Node-style `offset` / `size` -/// arguments against a buffer of `total` bytes. Out-of-range values are -/// clamped to `[0, total]`. -pub(super) fn resolve_range( - total: usize, - offset: Option, - size: Option, -) -> (usize, usize) { - let start = offset.unwrap_or(0).min(total); - let end = match size { - Some(s) => start.saturating_add(s).min(total), - None => total, - }; - (start, end) -} - /// Create HMAC-SHA256 /// crypto.createHmac('sha256', key).update(data).digest('hex') -> string #[no_mangle] diff --git a/crates/perry-stdlib/src/streams/writable.rs b/crates/perry-stdlib/src/streams/writable.rs index 9ddcdaab30..7cd185bd6c 100644 --- a/crates/perry-stdlib/src/streams/writable.rs +++ b/crates/perry-stdlib/src/streams/writable.rs @@ -258,24 +258,6 @@ fn writable_capture_promise(closure: *const ClosureHeader, idx: u32) -> *mut Pro perry_runtime::closure::js_closure_get_capture_ptr(closure, idx) as *mut Promise } -extern "C" fn writable_write_start_microtask(closure: *const ClosureHeader) -> f64 { - unsafe { - let stream_id = writable_capture_usize(closure, 0); - let writer_id = writable_capture_usize(closure, 1); - let cb = perry_runtime::closure::js_closure_get_capture_ptr(closure, 2); - let chunk_bits = perry_runtime::closure::js_closure_get_capture_ptr(closure, 3) as u64; - let write_promise = writable_capture_promise(closure, 4); - run_writable_write( - stream_id, - writer_id, - cb, - f64::from_bits(chunk_bits), - write_promise, - ); - } - f64::from_bits(TAG_UNDEFINED) -} - extern "C" fn writable_write_fulfilled(closure: *const ClosureHeader, _value: f64) -> f64 { unsafe { let stream_id = writable_capture_usize(closure, 0); diff --git a/crates/perry-stdlib/src/tls.rs b/crates/perry-stdlib/src/tls.rs index 3f9e859469..68197a7170 100644 --- a/crates/perry-stdlib/src/tls.rs +++ b/crates/perry-stdlib/src/tls.rs @@ -142,7 +142,9 @@ struct TlsServerState { struct TlsSocketState { cmd_tx: Option>, + #[allow(dead_code)] // captured socket local address for future localAddress exposure local_addr: Option, + #[allow(dead_code)] // captured socket peer address for future remoteAddress exposure peer_addr: Option, authorized: bool, server_side: bool, diff --git a/crates/perry-stdlib/src/zlib.rs b/crates/perry-stdlib/src/zlib.rs index fdc7f19dd9..9601e52ff5 100644 --- a/crates/perry-stdlib/src/zlib.rs +++ b/crates/perry-stdlib/src/zlib.rs @@ -212,9 +212,9 @@ pub unsafe extern "C" fn js_zlib_deflate_sync(data_bits: i64, opts: f64) -> *mut // dead-strips them from the stdlib archive, breaking the link of any program // that uses zlib (surfaced by Next.js's resume-data-cache `inflateSync` once the // #5437 live-import fix makes that module reachable). `#[used]` keeps them. -struct KeepZlibFfi([*const (); 32]); -// SAFETY: a link-time keepalive anchor only — the pointers are never read or -// dereferenced, so cross-thread sharing of the raw pointers is sound. +struct KeepZlibFfi(#[allow(dead_code)] [*const (); 32]); // link-time keepalive anchor; field never read, only #[used] to retain FFI symbols + // SAFETY: a link-time keepalive anchor only — the pointers are never read or + // dereferenced, so cross-thread sharing of the raw pointers is sound. unsafe impl Sync for KeepZlibFfi {} #[used] static KEEP_ZLIB_FFI: KeepZlibFfi = KeepZlibFfi([ diff --git a/crates/perry-ui-geisterhand/src/server.rs b/crates/perry-ui-geisterhand/src/server.rs index f765d43b6d..e894b40f1e 100644 --- a/crates/perry-ui-geisterhand/src/server.rs +++ b/crates/perry-ui-geisterhand/src/server.rs @@ -31,6 +31,7 @@ extern "C" { // Callback kind constants (must match perry-runtime/src/geisterhand_registry.rs) const CB_ON_CLICK: u8 = 0; const CB_ON_CHANGE: u8 = 1; +#[allow(dead_code)] // kept in lockstep with perry-runtime geisterhand_registry callback-kind enumeration const CB_ON_SUBMIT: u8 = 2; const CB_ON_HOVER: u8 = 3; const CB_ON_DOUBLE_CLICK: u8 = 4; diff --git a/crates/perry-ui-macos/src/audio.rs b/crates/perry-ui-macos/src/audio.rs index f5513f3495..d71e74f7e6 100644 --- a/crates/perry-ui-macos/src/audio.rs +++ b/crates/perry-ui-macos/src/audio.rs @@ -58,10 +58,6 @@ impl AWeightState { sections: [[0.0; 4]; 3], } } - - fn reset(&mut self) { - self.sections = [[0.0; 4]; 3]; - } } // A-weighting filter coefficients for 48000 Hz sample rate. @@ -149,14 +145,6 @@ extern "C" { fn js_array_create() -> i64; } -/// ObjC type encoding for AVAudioPCMBuffer block: -/// void (^)(AVAudioPCMBuffer *, AVAudioTime *) -/// We use raw pointers since we access through msg_send! anyway. -#[repr(C)] -struct AudioBufferList { - _opaque: [u8; 0], -} - // ============================================================================= // Public API // ============================================================================= diff --git a/crates/perry-ui-macos/src/audio_playback.rs b/crates/perry-ui-macos/src/audio_playback.rs index 8eee40de27..a9ac0c89a0 100644 --- a/crates/perry-ui-macos/src/audio_playback.rs +++ b/crates/perry-ui-macos/src/audio_playback.rs @@ -102,6 +102,8 @@ struct VoiceEntry { player_node: Retained, // AVAudioPlayerNode varispeed: Option>, // AVAudioUnitVarispeed (None if fallback) sound_idx: usize, + #[allow(dead_code)] + // carries the sound's bus handle (read from SoundEntry.bus_handle) into the voice; kept so the value chain stays intact bus_handle: f64, is_playing: bool, is_paused: bool, diff --git a/crates/perry-ui-macos/src/geolocation.rs b/crates/perry-ui-macos/src/geolocation.rs index d9fa6decb0..2b856e0c69 100644 --- a/crates/perry-ui-macos/src/geolocation.rs +++ b/crates/perry-ui-macos/src/geolocation.rs @@ -62,7 +62,11 @@ struct WatchEntry { struct PermissionRequest { callback: f64, + #[allow(dead_code)] + // keep-alive owner: retains the CLLocationManager while the async permission request is pending manager: Retained, + #[allow(dead_code)] + // keep-alive owner: retains the delegate so authorization callbacks still fire delegate: Retained, } diff --git a/crates/perry-ui-macos/src/network.rs b/crates/perry-ui-macos/src/network.rs index 0983965a3f..3e24610e38 100644 --- a/crates/perry-ui-macos/src/network.rs +++ b/crates/perry-ui-macos/src/network.rs @@ -52,7 +52,6 @@ const TAG_TRUE: u64 = 0x7FFC_0000_0000_0004; struct Status { connected: bool, kind: &'static str, - initialized: bool, } impl Status { @@ -60,7 +59,6 @@ impl Status { Self { connected: false, kind: "unknown", - initialized: false, } } } @@ -100,7 +98,6 @@ fn classify(path: *mut c_void) -> Status { return Status { connected: false, kind: "none", - initialized: true, }; } let status_code = unsafe { nw_path_get_status(path) }; @@ -108,7 +105,6 @@ fn classify(path: *mut c_void) -> Status { return Status { connected: false, kind: "none", - initialized: true, }; } let kind = if unsafe { nw_path_uses_interface_type(path, NW_INTERFACE_TYPE_WIFI) } { @@ -123,7 +119,6 @@ fn classify(path: *mut c_void) -> Status { Status { connected: true, kind, - initialized: true, } } diff --git a/crates/perry-ui-macos/src/widgets/mod.rs b/crates/perry-ui-macos/src/widgets/mod.rs index d0426b2748..ffbcc7fee4 100644 --- a/crates/perry-ui-macos/src/widgets/mod.rs +++ b/crates/perry-ui-macos/src/widgets/mod.rs @@ -1050,7 +1050,6 @@ pub fn match_parent_width(child_handle: i64) { extern "C" { fn js_closure_call0(closure: *const u8) -> f64; - fn js_closure_call1(closure: *const u8, arg: f64) -> f64; fn js_nanbox_get_pointer(value: f64) -> i64; } diff --git a/crates/perry-ui-macos/src/widgets/table.rs b/crates/perry-ui-macos/src/widgets/table.rs index 30b75cc224..41219ad214 100644 --- a/crates/perry-ui-macos/src/widgets/table.rs +++ b/crates/perry-ui-macos/src/widgets/table.rs @@ -14,6 +14,8 @@ extern "C" { } struct TableEntry { + #[allow(dead_code)] + // owning handle: keeps the AppKit scroll view retained for the entry's lifetime scroll_view: Retained, table_view: Retained, handle: i64, diff --git a/crates/perry-ui-macos/src/widgets/tree_view.rs b/crates/perry-ui-macos/src/widgets/tree_view.rs index eeb91fe1af..e4fe46498e 100644 --- a/crates/perry-ui-macos/src/widgets/tree_view.rs +++ b/crates/perry-ui-macos/src/widgets/tree_view.rs @@ -36,6 +36,7 @@ struct TreeNode { } struct TreeEntry { + #[allow(dead_code)] // keep-alive owner: retains the NSScrollView container for this tree entry scroll_view: Retained, outline_view: Retained, handle: i64, diff --git a/crates/perry/src/commands/compile/object_cache.rs b/crates/perry/src/commands/compile/object_cache.rs index 72395f51e3..ec42aee007 100644 --- a/crates/perry/src/commands/compile/object_cache.rs +++ b/crates/perry/src/commands/compile/object_cache.rs @@ -1048,6 +1048,7 @@ impl ObjectCache { /// reading the object bytes into memory. We still open the file once so /// unreadable cache entries fall back to a fresh compile just like /// `lookup` would. + #[allow(dead_code)] // exercised by #[cfg(test)] object_cache_tests; prod uses lookup_path_with_ffi pub fn lookup_path(&self, key: u64) -> Option { let path = self.path_for(key)?; match fs::File::open(&path).and_then(|f| f.metadata()) { diff --git a/crates/perry/src/commands/compile/resolve.rs b/crates/perry/src/commands/compile/resolve.rs index 48fb62e87d..9e2695d229 100644 --- a/crates/perry/src/commands/compile/resolve.rs +++ b/crates/perry/src/commands/compile/resolve.rs @@ -830,26 +830,6 @@ fn resolve_exports_with_conditions( } } -/// Resolve exports field from package.json for executable module entries. -/// -/// `node` is ranked ABOVE `default` (and above `import`/`module`) because perry -/// compiles a Node target: a package whose `exports` offers a `{ node, default }` -/// conditional pair ships its full Node API under `node` and a reduced -/// browser/edge build under `default`. Picking `default` drops Node-only -/// exports — e.g. `unicorn-magic` exposes `toPath`/`traversePathUp` only in its -/// `node` entry (`./node.js`); resolving `./default.js` left them undefined, so -/// `npm-run-path` (→ execa) failed to LINK (`undefined symbol -/// perry_fn_…unicorn_magic…__toPath`). Matches the `resolve_subpath_import` -/// condition order (chalk's `#supports-color` `{ node, default }`); the two -/// resolvers must agree. -pub(super) fn resolve_exports(exports: &serde_json::Value, subpath: &str) -> Option { - resolve_exports_with_conditions( - exports, - subpath, - &["perry", "node", "import", "module", "default", "require"], - ) -} - /// Node subpath imports (#5039): resolve a `#`-prefixed specifier through the /// importing package's own `package.json` `"imports"` map /// (https://nodejs.org/api/packages.html#imports). chalk 5 loads its vendored @@ -883,7 +863,7 @@ fn resolve_subpath_import(import_source: &str, importer_path: &Path) -> Option

, /// #1681 (Phase 3 of #1677): true when this is the build-time capture /// stage (the `current_exe` subprocess), so `precompile(EXPR)` sites @@ -959,6 +961,8 @@ pub enum SideEffects { Unknown, /// `"sideEffects": ["glob", ...]` — only files matching a glob have side /// effects; others are droppable. Globs are relative to the package dir. + #[allow(dead_code)] + // #2309 PR1: glob list captured for future per-file matching, not yet read Globs(Vec), } From e75d38fb29bbaaeed9cb82a798ce91f43dbf183b Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:15:10 +0200 Subject: [PATCH 05/18] chore(warnings): clear naming, visibility, unreachable and must-use warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four triaged families, rebased onto current main: - non_snake_case: the generated `thunk__` wrappers keep the JS spelling on purpose, so the allow sits on the three thunk macros and the node_submodule thunks rather than on each site. Real Rust names renamed. - private_interfaces / private_bounds: widen the leaked types to `pub(crate)` so the signature matches what callers can already reach. - unreachable_patterns: 32 duplicate match arms. Each was checked against the arm that shadows it — all are literal repeats, none had a different body that the first arm was swallowing. - unreachable_code: two `return js_throw(..)` where `js_throw` returns `!`. - sqlite `Connection::set_limit` returned a discarded `Result`: propagated with `?` in connection.rs, and `let _` in dispatch.rs where the limit id is already validated. - unused_doc_comments: 8 `///` comments on statements, which rustdoc drops. - Four dead bindings whose right-hand side is pure, so the binding goes instead of getting an underscore. Conflicts against main resolved in favour of main: perry-hir switched to `crate::types::Type`, and object/mod.rs moved the transition cache into `RuntimeState`. --- .../perry-codegen/src/collectors/i64_emit.rs | 2 +- crates/perry-codegen/src/ext_registry.rs | 34 +++--- .../perry-ext-http-server/src/http2_server.rs | 1 - crates/perry-ext-http/src/lib.rs | 1 - .../src/destructuring/assignment_expr.rs | 5 - .../src/destructuring/assignment_stmt.rs | 3 - crates/perry-hir/src/js_transform/imports.rs | 2 +- crates/perry-hir/src/stable_hash/expr.rs | 1 - crates/perry-hir/src/walker/expr_mut.rs | 1 - crates/perry-hir/src/walker/expr_ref.rs | 1 - .../perry-runtime/src/builtins/formatting.rs | 32 ++--- .../src/child_process/sync_run.rs | 4 +- crates/perry-runtime/src/dns.rs | 2 +- crates/perry-runtime/src/error.rs | 4 +- crates/perry-runtime/src/fs/fd_sync_ops.rs | 3 +- crates/perry-runtime/src/fs/mod.rs | 3 +- crates/perry-runtime/src/gc/policy.rs | 2 +- crates/perry-runtime/src/gc/telemetry.rs | 2 +- .../src/node_submodules/consumers.rs | 1 + .../src/node_submodules/fs_promises.rs | 8 ++ .../perry-runtime/src/node_submodules/mod.rs | 1 + .../src/node_submodules/stream_promises.rs | 2 + .../src/node_submodules/trace_events.rs | 2 + .../src/object/global_this/array_error.rs | 3 + .../perry-runtime/src/object/native_module.rs | 1 - .../native_module/callable_export_check.rs | 11 -- .../object/native_module/callable_exports.rs | 19 +-- .../src/object/native_module/constants.rs | 38 ------ .../src/object/native_module/module_keys.rs | 110 ------------------ .../native_module_dispatch/dispatch_d_i.rs | 1 - .../native_module_dispatch/dispatch_m_p.rs | 4 - crates/perry-runtime/src/perf_hooks.rs | 4 +- crates/perry-runtime/src/process.rs | 12 +- .../perry-runtime/src/promise/combinators.rs | 2 +- crates/perry-runtime/src/string/intern.rs | 16 +-- crates/perry-stdlib/src/common/dispatch.rs | 22 ++-- crates/perry-stdlib/src/sqlite/connection.rs | 2 +- crates/perry-stdlib/src/sqlite/dispatch.rs | 4 +- .../compile/cjs_wrap/hoist_classes.rs | 7 -- 39 files changed, 94 insertions(+), 279 deletions(-) diff --git a/crates/perry-codegen/src/collectors/i64_emit.rs b/crates/perry-codegen/src/collectors/i64_emit.rs index c3b4681f13..f927f4206c 100644 --- a/crates/perry-codegen/src/collectors/i64_emit.rs +++ b/crates/perry-codegen/src/collectors/i64_emit.rs @@ -32,7 +32,7 @@ pub fn emit_i64_function(llmod: &mut crate::module::LlModule, f: &Function, i64_ cx.f.block_mut(cx.cur).unwrap().ret(I64, "0"); } } -struct I64Cx<'a> { +pub(crate) struct I64Cx<'a> { f: &'a mut crate::function::LlFunction, cur: usize, locals: std::collections::HashMap, diff --git a/crates/perry-codegen/src/ext_registry.rs b/crates/perry-codegen/src/ext_registry.rs index 517da4e9bc..6dfe235743 100644 --- a/crates/perry-codegen/src/ext_registry.rs +++ b/crates/perry-codegen/src/ext_registry.rs @@ -586,23 +586,23 @@ const FFI_REGISTRY: &[(&str, OwnerKind)] = &[ /// optimization horizon worth measuring. static USED_PROVIDERS: Mutex>> = Mutex::new(None); -/// Per-module capture buffer, active only between [`begin_module_capture`] -/// and [`take_module_capture`] on the same thread. -/// -/// Why a thread-local rather than another field on [`USED_PROVIDERS`]: -/// the object cache (`crates/perry/src/commands/compile/object_cache.rs`) -/// needs to know which registry symbols *this one module* emitted, so it -/// can persist them next to the module's cached `.o` and replay them on a -/// later cache hit. [`USED_PROVIDERS`] is process-wide and rayon compiles -/// many modules concurrently, so it cannot attribute a symbol to a module. -/// `perry-codegen` itself never uses rayon and `compile_module` runs start -/// to finish on its caller's worker thread, so a thread-local scoped -/// around that one call captures exactly this module's emissions. -/// -/// We record the matched symbol *names* rather than [`OwnerKind`]s: replay -/// re-runs them through [`record_ffi_call`], so the symbol→owner mapping is -/// always the one in today's table, never a stale routing decision baked -/// into a cache entry written by an older perry. +// Per-module capture buffer, active only between [`begin_module_capture`] +// and [`take_module_capture`] on the same thread. +// +// Why a thread-local rather than another field on [`USED_PROVIDERS`]: +// the object cache (`crates/perry/src/commands/compile/object_cache.rs`) +// needs to know which registry symbols *this one module* emitted, so it +// can persist them next to the module's cached `.o` and replay them on a +// later cache hit. [`USED_PROVIDERS`] is process-wide and rayon compiles +// many modules concurrently, so it cannot attribute a symbol to a module. +// `perry-codegen` itself never uses rayon and `compile_module` runs start +// to finish on its caller's worker thread, so a thread-local scoped +// around that one call captures exactly this module's emissions. +// +// We record the matched symbol *names* rather than [`OwnerKind`]s: replay +// re-runs them through [`record_ffi_call`], so the symbol→owner mapping is +// always the one in today's table, never a stale routing decision baked +// into a cache entry written by an older perry. thread_local! { static MODULE_CAPTURE: RefCell>> = const { RefCell::new(None) }; } diff --git a/crates/perry-ext-http-server/src/http2_server.rs b/crates/perry-ext-http-server/src/http2_server.rs index ace23167e4..9880b2e200 100644 --- a/crates/perry-ext-http-server/src/http2_server.rs +++ b/crates/perry-ext-http-server/src/http2_server.rs @@ -20,7 +20,6 @@ use std::sync::atomic::{AtomicI64, Ordering}; use std::sync::{Arc, Mutex}; use bytes::Bytes; -use http_body_util::BodyExt; use hyper::service::service_fn; use hyper::{body::Incoming, Request}; use hyper_util::rt::{TokioExecutor, TokioIo}; diff --git a/crates/perry-ext-http/src/lib.rs b/crates/perry-ext-http/src/lib.rs index e44d62ca28..6be2e6379c 100644 --- a/crates/perry-ext-http/src/lib.rs +++ b/crates/perry-ext-http/src/lib.rs @@ -105,7 +105,6 @@ use perry_ffi::{ }; use std::collections::HashMap; use std::sync::{Mutex, Once}; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; const STRING_TAG: u64 = 0x7FFF_0000_0000_0000; const POINTER_TAG: u64 = 0x7FFD_0000_0000_0000; diff --git a/crates/perry-hir/src/destructuring/assignment_expr.rs b/crates/perry-hir/src/destructuring/assignment_expr.rs index 6a801db669..a08cd3323e 100644 --- a/crates/perry-hir/src/destructuring/assignment_expr.rs +++ b/crates/perry-hir/src/destructuring/assignment_expr.rs @@ -88,11 +88,6 @@ pub(crate) fn lower_destructuring_assignment( value: Box::new(index_expr), }); } - _ => { - return Err(anyhow!( - "Unsupported member expression in destructuring" - )); - } } } _ => { diff --git a/crates/perry-hir/src/destructuring/assignment_stmt.rs b/crates/perry-hir/src/destructuring/assignment_stmt.rs index b0573cdf36..b9e704ed47 100644 --- a/crates/perry-hir/src/destructuring/assignment_stmt.rs +++ b/crates/perry-hir/src/destructuring/assignment_stmt.rs @@ -471,9 +471,6 @@ fn prepare_assignment_target( None, )) } - _ => Err(anyhow!( - "Unsupported member expression in destructuring assignment" - )), } } _ => Err(anyhow!( diff --git a/crates/perry-hir/src/js_transform/imports.rs b/crates/perry-hir/src/js_transform/imports.rs index ff92d49bd3..dc12b3b38d 100644 --- a/crates/perry-hir/src/js_transform/imports.rs +++ b/crates/perry-hir/src/js_transform/imports.rs @@ -15,7 +15,7 @@ pub struct JsImportInfo { /// Context for tracking JS values during transformation #[derive(Debug, Clone, Default)] -struct JsValueTracker { +pub(crate) struct JsValueTracker { /// LocalIds that hold JS values (from imports or JS function results) js_locals: HashSet, /// Class names that are JS classes (from imports) diff --git a/crates/perry-hir/src/stable_hash/expr.rs b/crates/perry-hir/src/stable_hash/expr.rs index 9684beea9d..5cddce2581 100644 --- a/crates/perry-hir/src/stable_hash/expr.rs +++ b/crates/perry-hir/src/stable_hash/expr.rs @@ -549,7 +549,6 @@ impl SH for Expr { Expr::UrlSearchParamsSort(e) => { tag(h, 703); e.as_ref().hash(h); } Expr::UrlSearchParamsForEach { params, callback, this_arg } => { tag(h, 704); params.as_ref().hash(h); callback.as_ref().hash(h); match this_arg { Some(v) => { tag(h, 1); v.as_ref().hash(h); } None => tag(h, 0), } } Expr::Delete(e) => { tag(h, 381); e.as_ref().hash(h); } - Expr::NewTarget => { tag(h, 12271); } Expr::Closure { func_id, params, return_type, body, captures, mutable_captures, captures_this, captures_new_target, enclosing_class, is_arrow, is_async, is_generator, is_strict, } => { tag(h, 382); func_id.hash(h); params.hash(h); return_type.hash(h); body.hash(h); captures.hash(h); mutable_captures.hash(h); captures_this.hash(h); captures_new_target.hash(h); enclosing_class.hash(h); is_arrow.hash(h); is_async.hash(h); is_generator.hash(h); is_strict.hash(h); } Expr::RegExp { pattern, flags } => { tag(h, 383); pattern.hash(h); flags.hash(h); } Expr::RegExpDynamic { pattern, flags, is_call } => { tag(h, 475); pattern.as_ref().hash(h); if let Some(f_box) = flags { tag(h, 476); f_box.as_ref().hash(h); } else { tag(h, 477); } tag(h, if *is_call { 478 } else { 479 }); } diff --git a/crates/perry-hir/src/walker/expr_mut.rs b/crates/perry-hir/src/walker/expr_mut.rs index 9eab517228..77d9335b8d 100644 --- a/crates/perry-hir/src/walker/expr_mut.rs +++ b/crates/perry-hir/src/walker/expr_mut.rs @@ -28,7 +28,6 @@ where | Expr::NewTarget | Expr::ClassRef(_) | Expr::This - | Expr::NewTarget | Expr::SuperPropertyGet { .. } | Expr::EnumMember { .. } | Expr::StaticFieldGet { .. } diff --git a/crates/perry-hir/src/walker/expr_ref.rs b/crates/perry-hir/src/walker/expr_ref.rs index 98842b2973..7bad53d64e 100644 --- a/crates/perry-hir/src/walker/expr_ref.rs +++ b/crates/perry-hir/src/walker/expr_ref.rs @@ -29,7 +29,6 @@ where | Expr::NewTarget | Expr::ClassRef(_) | Expr::This - | Expr::NewTarget | Expr::SuperPropertyGet { .. } | Expr::EnumMember { .. } | Expr::StaticFieldGet { .. } diff --git a/crates/perry-runtime/src/builtins/formatting.rs b/crates/perry-runtime/src/builtins/formatting.rs index f1ae5ba214..a4cbc6c576 100644 --- a/crates/perry-runtime/src/builtins/formatting.rs +++ b/crates/perry-runtime/src/builtins/formatting.rs @@ -210,11 +210,11 @@ pub(crate) fn format_bigint_literal(val: f64) -> String { } } -/// Per-thread override for the depth at which nested objects/arrays -/// collapse to `[Object]` / `[Array]`. Defaults to Node's `util.inspect` -/// default of 2. The `%o` format specifier raises this temporarily to -/// Node's object-format depth of 4, while `%O` uses the current inspect -/// options unchanged. +// Per-thread override for the depth at which nested objects/arrays +// collapse to `[Object]` / `[Array]`. Defaults to Node's `util.inspect` +// default of 2. The `%o` format specifier raises this temporarily to +// Node's object-format depth of 4, while `%O` uses the current inspect +// options unchanged. thread_local! { static INSPECT_DEPTH_LIMIT: std::cell::Cell = const { std::cell::Cell::new(2) }; } @@ -467,11 +467,11 @@ pub fn function_source_for_func_ptr(func_ptr: usize) -> String { format!("function {name}() {{ [native code] }}") } -/// Per-thread override for the `showHidden` inspect option. Defaults to -/// `false` (Node default): `util.inspect` / `console.log` only show -/// enumerable properties. `console.dir(value, { showHidden: true })` -/// flips this for the duration of the print so non-enumerable props -/// surface in `[bracketed]` form. See #1200. +// Per-thread override for the `showHidden` inspect option. Defaults to +// `false` (Node default): `util.inspect` / `console.log` only show +// enumerable properties. `console.dir(value, { showHidden: true })` +// flips this for the duration of the print so non-enumerable props +// surface in `[bracketed]` form. See #1200. thread_local! { static INSPECT_SHOW_HIDDEN: std::cell::Cell = const { std::cell::Cell::new(false) }; static INSPECT_SHOW_PROXY: std::cell::Cell = const { std::cell::Cell::new(false) }; @@ -517,12 +517,12 @@ impl Drop for InspectShowProxyGuard { } } -/// Per-thread override for the `customInspect` inspect option. Defaults to -/// `true` (Node default for `util.inspect` / `console.log`): when an object -/// has a `[util.inspect.custom]` symbol-keyed method, the hook is invoked -/// and its return value replaces the default object body. `console.dir` -/// flips this to `false` so the symbol surfaces as a property listing. -/// See #1201. +// Per-thread override for the `customInspect` inspect option. Defaults to +// `true` (Node default for `util.inspect` / `console.log`): when an object +// has a `[util.inspect.custom]` symbol-keyed method, the hook is invoked +// and its return value replaces the default object body. `console.dir` +// flips this to `false` so the symbol surfaces as a property listing. +// See #1201. thread_local! { static INSPECT_CUSTOM_INSPECT: std::cell::Cell = const { std::cell::Cell::new(true) }; } diff --git a/crates/perry-runtime/src/child_process/sync_run.rs b/crates/perry-runtime/src/child_process/sync_run.rs index 85587f7e1f..fe20771c72 100644 --- a/crates/perry-runtime/src/child_process/sync_run.rs +++ b/crates/perry-runtime/src/child_process/sync_run.rs @@ -12,7 +12,7 @@ use super::{ const CP_DEFAULT_MAX_BUFFER: usize = 1024 * 1024; /// Options that affect buffered sync execution after the `Command` is built. -pub(super) struct CpRunOptions { +pub(crate) struct CpRunOptions { input: Option>, timeout: Option, kill_signal: i32, @@ -183,7 +183,7 @@ impl CpRunError { } /// Outcome of running a child to completion (buffered). -pub(super) struct CpRun { +pub(crate) struct CpRun { pub(super) stdout: Vec, pub(super) stderr: Vec, pub(super) stdout_piped: bool, diff --git a/crates/perry-runtime/src/dns.rs b/crates/perry-runtime/src/dns.rs index 0d3b6a78db..5453e9f7d5 100644 --- a/crates/perry-runtime/src/dns.rs +++ b/crates/perry-runtime/src/dns.rs @@ -58,7 +58,7 @@ const RESOLVER_RESOLVE_METHODS: &[&str] = &[ const RESOLVER_SERVERS_FIELD: &str = "__dns_servers"; #[derive(Clone, Copy)] -enum RecordKind { +pub(crate) enum RecordKind { A, Aaaa, Any, diff --git a/crates/perry-runtime/src/error.rs b/crates/perry-runtime/src/error.rs index da91d31e9a..6ce61b4123 100644 --- a/crates/perry-runtime/src/error.rs +++ b/crates/perry-runtime/src/error.rs @@ -1051,7 +1051,7 @@ pub extern "C" fn js_global_update(name_value: f64, is_increment: f64, is_prefix let msg = format!("{} is not defined", name); let msg_str = js_string_from_bytes(msg.as_ptr(), msg.len() as u32); let err_ptr = js_referenceerror_new(msg_str); - return crate::exception::js_throw(crate::value::js_nanbox_pointer(err_ptr as i64)); + crate::exception::js_throw(crate::value::js_nanbox_pointer(err_ptr as i64)); } let numeric = unsafe { crate::value::js_to_numeric(old) }; let stepped = unsafe { crate::value::js_numeric_step(numeric, is_increment) }; @@ -1107,7 +1107,7 @@ pub extern "C" fn js_global_assign_existing_or_throw(name_value: f64, value: f64 let msg = format!("{} is not defined", name); let msg_str = js_string_from_bytes(msg.as_ptr(), msg.len() as u32); let err_ptr = js_referenceerror_new(msg_str); - return crate::exception::js_throw(crate::value::js_nanbox_pointer(err_ptr as i64)); + crate::exception::js_throw(crate::value::js_nanbox_pointer(err_ptr as i64)); } let gptr = (gj.bits() & crate::value::POINTER_MASK) as *mut crate::object::ObjectHeader; crate::object::js_object_set_field_by_name(gptr, key, value); diff --git a/crates/perry-runtime/src/fs/fd_sync_ops.rs b/crates/perry-runtime/src/fs/fd_sync_ops.rs index 437fa08536..48f9dd2416 100644 --- a/crates/perry-runtime/src/fs/fd_sync_ops.rs +++ b/crates/perry-runtime/src/fs/fd_sync_ops.rs @@ -1,9 +1,8 @@ use super::*; use std::fs; -use std::io::Write; #[cfg(unix)] -use std::os::unix::fs::{MetadataExt, PermissionsExt}; +use std::os::unix::fs::PermissionsExt; #[cfg(unix)] use std::os::unix::io::AsRawFd; diff --git a/crates/perry-runtime/src/fs/mod.rs b/crates/perry-runtime/src/fs/mod.rs index 6f8422968d..cc87e585c4 100644 --- a/crates/perry-runtime/src/fs/mod.rs +++ b/crates/perry-runtime/src/fs/mod.rs @@ -8,9 +8,8 @@ use std::collections::HashMap as StdHashMap; use std::fs; use std::io::{Read, Seek, SeekFrom, Write}; #[cfg(unix)] -use std::os::unix::fs::{MetadataExt, PermissionsExt}; +use std::os::unix::fs::PermissionsExt; #[cfg(unix)] -use std::os::unix::io::AsRawFd; use std::path::Path; use std::sync::atomic::{AtomicI32, Ordering}; diff --git a/crates/perry-runtime/src/gc/policy.rs b/crates/perry-runtime/src/gc/policy.rs index 64fdd03118..de911bcffa 100644 --- a/crates/perry-runtime/src/gc/policy.rs +++ b/crates/perry-runtime/src/gc/policy.rs @@ -513,7 +513,7 @@ impl GcStepSnapshot { } #[derive(Clone, Copy)] -pub(super) struct GcTriggerSnapshot { +pub(crate) struct GcTriggerSnapshot { pub(super) kind: GcTriggerKind, pub(super) steps_before: Option, } diff --git a/crates/perry-runtime/src/gc/telemetry.rs b/crates/perry-runtime/src/gc/telemetry.rs index 6cd5afc9c4..87a3bc0ffb 100644 --- a/crates/perry-runtime/src/gc/telemetry.rs +++ b/crates/perry-runtime/src/gc/telemetry.rs @@ -1184,7 +1184,7 @@ pub(super) fn take_test_last_gc_trace_json() -> Option { TEST_LAST_GC_TRACE_JSON.with(|slot| slot.borrow_mut().take()) } -pub(super) struct GcCollectOutcome { +pub(crate) struct GcCollectOutcome { pub(super) freed_bytes: u64, pub(super) malloc_swept: bool, pub(super) trace: Option, diff --git a/crates/perry-runtime/src/node_submodules/consumers.rs b/crates/perry-runtime/src/node_submodules/consumers.rs index a2196d4383..d21fe115ce 100644 --- a/crates/perry-runtime/src/node_submodules/consumers.rs +++ b/crates/perry-runtime/src/node_submodules/consumers.rs @@ -613,6 +613,7 @@ pub(crate) extern "C" fn thunk_consumers_buffer( consume_stream(ConsumerKind::Buffer, stream) } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_consumers_arrayBuffer( _closure: *const ClosureHeader, stream: f64, diff --git a/crates/perry-runtime/src/node_submodules/fs_promises.rs b/crates/perry-runtime/src/node_submodules/fs_promises.rs index 1473136f22..aac1cb8876 100644 --- a/crates/perry-runtime/src/node_submodules/fs_promises.rs +++ b/crates/perry-runtime/src/node_submodules/fs_promises.rs @@ -106,6 +106,7 @@ pub extern "C" fn js_fs_promises_mkdir(path: f64, options: f64) -> f64 { thunk_fs_promises_mkdir(std::ptr::null(), path, options) } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_fs_promises_readFile( _closure: *const ClosureHeader, path: f64, @@ -131,6 +132,7 @@ pub(crate) extern "C" fn thunk_fs_promises_open( } } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_fs_promises_writeFile( _closure: *const ClosureHeader, path: f64, @@ -148,6 +150,7 @@ pub(crate) extern "C" fn thunk_fs_promises_writeFile( } } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_fs_promises_appendFile( _closure: *const ClosureHeader, path: f64, @@ -279,6 +282,7 @@ pub(crate) extern "C" fn thunk_fs_promises_rename( promise_from_result_undefined(|| unsafe { crate::fs::js_fs_rename_result(from, to) }) } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_fs_promises_copyFile( _closure: *const ClosureHeader, from: f64, @@ -368,6 +372,7 @@ pub(crate) extern "C" fn thunk_fs_promises_mkdtemp( promise_from_sync_value(|| crate::fs::js_fs_mkdtemp_dispatch(prefix, options)) } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_fs_promises_mkdtempDisposable( _closure: *const ClosureHeader, prefix: f64, @@ -776,6 +781,7 @@ fn readline_promises_create_interface(opts: f64) -> f64 { obj_value } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_readline_createInterface( _closure: *const ClosureHeader, opts: f64, @@ -783,6 +789,7 @@ pub(crate) extern "C" fn thunk_readline_createInterface( readline_promises_create_interface(opts) } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_readline_Interface( _closure: *const ClosureHeader, opts: f64, @@ -955,6 +962,7 @@ pub extern "C" fn js_readline_promises_readline_new(output: f64, options: f64) - obj_value } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_readline_Readline( _closure: *const ClosureHeader, output: f64, diff --git a/crates/perry-runtime/src/node_submodules/mod.rs b/crates/perry-runtime/src/node_submodules/mod.rs index 7614e325c6..cf4b269960 100644 --- a/crates/perry-runtime/src/node_submodules/mod.rs +++ b/crates/perry-runtime/src/node_submodules/mod.rs @@ -93,6 +93,7 @@ struct SubmoduleSpec { macro_rules! thunk { ($name:ident, $msg:expr) => { + #[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn $name( _closure: *const crate::closure::ClosureHeader, _arg: f64, diff --git a/crates/perry-runtime/src/node_submodules/stream_promises.rs b/crates/perry-runtime/src/node_submodules/stream_promises.rs index 12336c96b1..1de33a7384 100644 --- a/crates/perry-runtime/src/node_submodules/stream_promises.rs +++ b/crates/perry-runtime/src/node_submodules/stream_promises.rs @@ -570,6 +570,7 @@ fn catch_stream_promises_throw(call: impl FnOnce()) -> Result<(), f64> { } } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_streamP_pipeline( _closure: *const ClosureHeader, source: f64, @@ -614,6 +615,7 @@ pub(crate) extern "C" fn thunk_streamP_pipeline( promise_value } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_streamP_finished( _closure: *const ClosureHeader, stream: f64, diff --git a/crates/perry-runtime/src/node_submodules/trace_events.rs b/crates/perry-runtime/src/node_submodules/trace_events.rs index c73964cfb6..d201ca943f 100644 --- a/crates/perry-runtime/src/node_submodules/trace_events.rs +++ b/crates/perry-runtime/src/node_submodules/trace_events.rs @@ -326,6 +326,7 @@ fn validate_categories(options_obj: *mut ObjectHeader) -> Vec { result } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_trace_events_createTracing( _closure: *const ClosureHeader, options: f64, @@ -360,6 +361,7 @@ pub(crate) extern "C" fn thunk_trace_events_createTracing( obj_value } +#[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn thunk_trace_events_getEnabledCategories( _closure: *const ClosureHeader, _arg: f64, diff --git a/crates/perry-runtime/src/object/global_this/array_error.rs b/crates/perry-runtime/src/object/global_this/array_error.rs index 240a458050..797eb821ff 100644 --- a/crates/perry-runtime/src/object/global_this/array_error.rs +++ b/crates/perry-runtime/src/object/global_this/array_error.rs @@ -696,6 +696,7 @@ pub(crate) extern "C" fn array_prototype_sort_thunk( /// keeps the closure call convention independent of the spec `.length`. macro_rules! array_proto_arraylike_cb_thunk { ($name:ident, $engine:path) => { + #[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn $name(_c: *const crate::closure::ClosureHeader, rest: f64) -> f64 { let this = crate::object::js_implicit_this_get(); let args = global_this_rest_array_values(rest); @@ -732,6 +733,7 @@ array_proto_arraylike_cb_thunk!( macro_rules! array_proto_arraylike_optarg_thunk { ($name:ident, $engine:path) => { + #[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn $name(_c: *const crate::closure::ClosureHeader, rest: f64) -> f64 { let this = crate::object::js_implicit_this_get(); let args = global_this_rest_array_values(rest); @@ -757,6 +759,7 @@ fn reduce_right_engine(recv: f64, cb: f64, has_init: i32, init: f64) -> f64 { macro_rules! array_proto_arraylike_search_thunk { ($name:ident, $engine:path) => { + #[allow(non_snake_case)] // thunk name mirrors JS API surface pub(crate) extern "C" fn $name(_c: *const crate::closure::ClosureHeader, rest: f64) -> f64 { let this = crate::object::js_implicit_this_get(); let args = global_this_rest_array_values(rest); diff --git a/crates/perry-runtime/src/object/native_module.rs b/crates/perry-runtime/src/object/native_module.rs index 4522678324..e6784c3be1 100644 --- a/crates/perry-runtime/src/object/native_module.rs +++ b/crates/perry-runtime/src/object/native_module.rs @@ -545,7 +545,6 @@ pub(crate) fn cjs_default_export_value(module_name: &str) -> Option { b"process".as_ptr(), "process".len(), )), - "module" => Some(bound_native_callable_export_value("module", "Module")), "async_hooks" | "child_process" | "constants" | "dns" | "dns/promises" | "node-pty" | "os" | "path" | "path.posix" | "path.win32" | "punycode" | "querystring" | "repl" | "sea" | "url" | "util" | "inspector" | "inspector/promises" => { diff --git a/crates/perry-runtime/src/object/native_module/callable_export_check.rs b/crates/perry-runtime/src/object/native_module/callable_export_check.rs index 3febbd4f44..a923b40f55 100644 --- a/crates/perry-runtime/src/object/native_module/callable_export_check.rs +++ b/crates/perry-runtime/src/object/native_module/callable_export_check.rs @@ -151,7 +151,6 @@ pub(crate) fn is_native_module_callable_export(module: &str, prop: &str) -> bool | ("http", "_connectionListener") | ("module", "Module") | ("module", "createRequire") - | ("module", "Module") | ("module", "findPackageJSON") | ("module", "findSourceMap") | ("module", "flushCompileCache") @@ -489,7 +488,6 @@ pub(crate) fn is_native_module_callable_export(module: &str, prop: &str) -> bool | ("fs", "unlinkSync") | ("fs", "utimes") | ("fs", "utimesSync") - | ("fs", "_toUnixTimestamp") | ("fs", "watch") | ("fs", "watchFile") | ("fs", "unwatchFile") @@ -903,15 +901,6 @@ pub(crate) fn is_native_module_callable_export(module: &str, prop: &str) -> bool | ("zlib", "createUnzip") | ("zlib", "createBrotliCompress") | ("zlib", "createBrotliDecompress") - | ("zlib", "Deflate") - | ("zlib", "DeflateRaw") - | ("zlib", "Gzip") - | ("zlib", "Gunzip") - | ("zlib", "Inflate") - | ("zlib", "InflateRaw") - | ("zlib", "Unzip") - | ("zlib", "BrotliCompress") - | ("zlib", "BrotliDecompress") // #2533: node:http/https/http2 server factories read as callable // values so `const createServer = createServerHTTP` (and // `@hono/node-server`'s `options.createServer || createServerHTTP`) diff --git a/crates/perry-runtime/src/object/native_module/callable_exports.rs b/crates/perry-runtime/src/object/native_module/callable_exports.rs index da5d2e5bc7..48ff86f35c 100644 --- a/crates/perry-runtime/src/object/native_module/callable_exports.rs +++ b/crates/perry-runtime/src/object/native_module/callable_exports.rs @@ -522,22 +522,7 @@ fn native_callable_export_arity(module: &str, prop: &str) -> Option { // #4904: http twins of the https entries above. ("http", "request") => Some(0), ("http", "get") => Some(3), - ( - "stream", - "isDestroyed" - | "isDisturbed" - | "isErrored" - | "isReadable" - | "isWritable" - | "getDefaultHighWaterMark" - | "_isArrayBufferView" - | "_isUint8Array" - | "_uint8ArrayToBuffer", - ) => Some(1), - ("stream", "finished") => Some(3), - ("stream", "addAbortSignal" | "destroy" | "setDefaultHighWaterMark") => Some(2), - ("stream", "compose" | "pipeline") => Some(0), - ("stream", "duplexPair") => Some(1), + ("stream", "destroy") => Some(2), // #3712: node:http module-level helper exports. ("http", "validateHeaderName" | "validateHeaderValue") => Some(2), ("http", "setMaxIdleHTTPParsers" | "setGlobalProxyFromEnv") => Some(1), @@ -583,7 +568,6 @@ fn native_callable_export_arity(module: &str, prop: &str) -> Option { ("fs", "Stats") => Some(18), ("fs", "mkdtempDisposableSync") => Some(2), ("fs", "openAsBlob") => Some(1), - ("fs", "_toUnixTimestamp") => Some(1), ("events", "init") => Some(1), ("repl", "Recoverable") => Some(1), ("repl", "REPLServer" | "start") => Some(6), @@ -602,7 +586,6 @@ fn native_callable_export_arity(module: &str, prop: &str) -> Option { ("module", "flushCompileCache") => Some(0), ("module", "getCompileCacheDir") => Some(0), ("module", "getSourceMapsSupport") => Some(0), - ("module", "Module") => Some(0), ("module", "_findPath") => Some(3), ("module", "_initPaths") => Some(0), ("module", "_load") => Some(3), diff --git a/crates/perry-runtime/src/object/native_module/constants.rs b/crates/perry-runtime/src/object/native_module/constants.rs index ecba64d878..e4e14569d7 100644 --- a/crates/perry-runtime/src/object/native_module/constants.rs +++ b/crates/perry-runtime/src/object/native_module/constants.rs @@ -921,39 +921,6 @@ pub(crate) unsafe fn get_native_module_constant( Some(v as f64) }; - let dns_const = |prop: &str| -> Option { - Some(match prop { - "ADDRCONFIG" => 1024.0, - "V4MAPPED" => 2048.0, - "ALL" => 256.0, - "NODATA" => str_val("ENODATA"), - "FORMERR" => str_val("EFORMERR"), - "SERVFAIL" => str_val("ESERVFAIL"), - "NOTFOUND" => str_val("ENOTFOUND"), - "NOTIMP" => str_val("ENOTIMP"), - "REFUSED" => str_val("EREFUSED"), - "BADQUERY" => str_val("EBADQUERY"), - "BADNAME" => str_val("EBADNAME"), - "BADFAMILY" => str_val("EBADFAMILY"), - "BADRESP" => str_val("EBADRESP"), - "CONNREFUSED" => str_val("ECONNREFUSED"), - "TIMEOUT" => str_val("ETIMEOUT"), - "EOF" => str_val("EOF"), - "FILE" => str_val("EFILE"), - "NOMEM" => str_val("ENOMEM"), - "DESTRUCTION" => str_val("EDESTRUCTION"), - "BADSTR" => str_val("EBADSTR"), - "BADFLAGS" => str_val("EBADFLAGS"), - "NONAME" => str_val("ENONAME"), - "BADHINTS" => str_val("EBADHINTS"), - "NOTINITIALIZED" => str_val("ENOTINITIALIZED"), - "LOADIPHLPAPI" => str_val("ELOADIPHLPAPI"), - "ADDRGETNETWORKPARAMS" => str_val("EADDRGETNETWORKPARAMS"), - "CANCELLED" => str_val("ECANCELLED"), - _ => return None, - }) - }; - let sqlite_const = |prop: &str| -> Option { Some(match prop { "SQLITE_CHANGESET_DATA" => 1.0, @@ -1354,10 +1321,6 @@ pub(crate) unsafe fn get_native_module_constant( "Stream" => Some(bound_native_callable_export_value("net", "Socket")), _ => None, }, - "timers" => match property { - "promises" => Some(timers_promises_parent_namespace()), - _ => None, - }, "timers/promises" => match property { "setTimeout" | "setImmediate" | "setInterval" => Some(unsafe { crate::node_submodules::js_node_submodule_namespace_member( @@ -1576,7 +1539,6 @@ pub(crate) unsafe fn get_native_module_constant( }, #[cfg(feature = "mod-http2-constants")] "http2.constants" => crate::node_http2_constants::constant(property), - "dns" => dns_const(property), // node:cluster — primary-side settings and Worker handles are backed // by `crate::cluster`; scheduling/identity constants remain static. "cluster" => crate::cluster::cluster_property(property), diff --git a/crates/perry-runtime/src/object/native_module/module_keys.rs b/crates/perry-runtime/src/object/native_module/module_keys.rs index e33a89213a..864a507a60 100644 --- a/crates/perry-runtime/src/object/native_module/module_keys.rs +++ b/crates/perry-runtime/src/object/native_module/module_keys.rs @@ -1083,103 +1083,6 @@ const INSPECTOR_NETWORK_KEYS: &[&[u8]] = &[ b"webSocketHandshakeResponseReceived", ]; -const FS_NAMESPACE_KEYS: &[&[u8]] = &[ - b"_toUnixTimestamp", - b"access", - b"accessSync", - b"appendFile", - b"appendFileSync", - b"chmod", - b"chmodSync", - b"chown", - b"chownSync", - b"close", - b"closeSync", - b"constants", - b"copyFile", - b"copyFileSync", - b"cp", - b"cpSync", - b"createReadStream", - b"createWriteStream", - b"exists", - b"existsSync", - b"fchmod", - b"fchmodSync", - b"fchown", - b"fchownSync", - b"fdatasync", - b"fdatasyncSync", - b"fstat", - b"fstatSync", - b"fsync", - b"fsyncSync", - b"ftruncate", - b"ftruncateSync", - b"futimes", - b"futimesSync", - b"glob", - b"globSync", - b"lchmod", - b"lchmodSync", - b"lchown", - b"lchownSync", - b"link", - b"linkSync", - b"lstat", - b"lstatSync", - b"lutimes", - b"lutimesSync", - b"mkdir", - b"mkdirSync", - b"mkdtemp", - b"mkdtempSync", - b"open", - b"openSync", - b"opendir", - b"opendirSync", - b"promises", - b"read", - b"readFile", - b"readFileSync", - b"readSync", - b"readdir", - b"readdirSync", - b"readlink", - b"readlinkSync", - b"readv", - b"readvSync", - b"realpath", - b"realpathSync", - b"rename", - b"renameSync", - b"rm", - b"rmSync", - b"rmdir", - b"rmdirSync", - b"stat", - b"statSync", - b"statfs", - b"statfsSync", - b"symlink", - b"symlinkSync", - b"truncate", - b"truncateSync", - b"unlink", - b"unlinkSync", - b"unwatchFile", - b"utimes", - b"utimesSync", - b"watch", - b"watchFile", - b"write", - b"writeFile", - b"writeFileSync", - b"writeSync", - b"writev", - b"writevSync", -]; - const URL_DEFAULT_KEYS: &[&[u8]] = &[ b"Url", b"parse", @@ -1705,7 +1608,6 @@ pub(crate) fn native_module_enumerable_keys(module_name: &str) -> Option<&'stati "path" => Some(PATH_NAMESPACE_KEYS), "path.default" | "path.posix.default" | "path.win32.default" => Some(PATH_DEFAULT_KEYS), "path.posix" | "path.win32" => Some(PATH_NAMESPACE_KEYS), - "fs" => Some(FS_NAMESPACE_KEYS), "constants" => Some(deprecated_constants_namespace_keys()), "constants.default" => Some(deprecated_constants_keys()), "dns" => Some(DNS_NAMESPACE_KEYS), @@ -1919,18 +1821,6 @@ pub(crate) fn native_module_enumerable_keys(module_name: &str) -> Option<&'stati VM_NAMESPACE_KEYS }), "vm.constants" => Some(VM_CONSTANTS_KEYS), - // Plain `timers` was missing — `require('node:timers').setImmediate` - // read undefined (Next.js's fast-set-immediate extension reads and - // patches it at module init). - "timers" => Some(&[ - b"setTimeout", - b"clearTimeout", - b"setInterval", - b"clearInterval", - b"setImmediate", - b"clearImmediate", - b"promises", - ]), "timers/promises" => Some(&[b"setTimeout", b"setImmediate", b"setInterval", b"scheduler"]), "readline/promises" => Some(&[b"Interface", b"Readline", b"createInterface"]), "zlib" => Some(&[b"codes"]), diff --git a/crates/perry-runtime/src/object/native_module_dispatch/dispatch_d_i.rs b/crates/perry-runtime/src/object/native_module_dispatch/dispatch_d_i.rs index 4a66e8b3c0..37e4df6884 100644 --- a/crates/perry-runtime/src/object/native_module_dispatch/dispatch_d_i.rs +++ b/crates/perry-runtime/src/object/native_module_dispatch/dispatch_d_i.rs @@ -289,7 +289,6 @@ pub(crate) unsafe fn nm_dispatch_fs(ctx: &NmCtx, module_name: &str, method_name: ("fs", "utimesSync") => crate::fs::js_fs_utimes_sync(arg(0), arg(1), arg(2)) as f64, ("fs", "lutimesSync") => crate::fs::js_fs_lutimes_sync(arg(0), arg(1), arg(2)) as f64, ("fs", "futimesSync") => crate::fs::js_fs_futimes_sync(arg(0), arg(1), arg(2)) as f64, - ("fs", "_toUnixTimestamp") => crate::fs::js_fs_to_unix_timestamp(arg(0)), ("fs", "readvSync") => crate::fs::js_fs_readv_sync(arg(0), arg(1), arg(2)), ("fs", "writevSync") => crate::fs::js_fs_writev_sync(arg(0), arg(1), arg(2)), ("fs", "statfsSync") => crate::fs::js_fs_statfs_sync_options(arg(0), arg(1)), diff --git a/crates/perry-runtime/src/object/native_module_dispatch/dispatch_m_p.rs b/crates/perry-runtime/src/object/native_module_dispatch/dispatch_m_p.rs index 3c3dc26b93..681d1c45b9 100644 --- a/crates/perry-runtime/src/object/native_module_dispatch/dispatch_m_p.rs +++ b/crates/perry-runtime/src/object/native_module_dispatch/dispatch_m_p.rs @@ -808,10 +808,6 @@ pub(crate) unsafe fn nm_dispatch_process(ctx: &NmCtx, module_name: &str, method_ crate::process::js_process_umask_set(mask) } } - ("process", "emitWarning") => { - crate::process::js_process_emit_warning(arg(0), arg(1), arg(2)); - f64::from_bits(crate::value::TAG_UNDEFINED) - } ("process", "hrtime") => crate::os::js_process_hrtime(arg(0)), ("process", "cpuUsage") => crate::process::js_process_cpu_usage(arg(0)), // ── crypto module ── diff --git a/crates/perry-runtime/src/perf_hooks.rs b/crates/perry-runtime/src/perf_hooks.rs index 1c7a10f25d..b2a98bc30e 100644 --- a/crates/perry-runtime/src/perf_hooks.rs +++ b/crates/perry-runtime/src/perf_hooks.rs @@ -77,7 +77,7 @@ const UV_METRICS_INFO_SHAPE: u32 = 0x7FFF_FF51; const UV_METRICS_INFO_KEYS: &[u8] = b"loopCount\0events\0eventsWaiting\0"; #[derive(Clone)] -struct PerfEntry { +pub(crate) struct PerfEntry { name: String, entry_type: u8, start_time: f64, @@ -1459,7 +1459,7 @@ pub extern "C" fn js_perf_observer_flush_all( /// Build an array from the in-flight observer `list` entries (for the /// `perf_observer_list` namespace methods). -pub unsafe fn current_list_to_array(filter: impl Fn(&PerfEntry) -> bool) -> f64 { +pub(crate) unsafe fn current_list_to_array(filter: impl Fn(&PerfEntry) -> bool) -> f64 { let mut snapshot: Vec = CURRENT_LIST.with(|c| c.borrow().iter().filter(|e| filter(e)).cloned().collect()); sort_entries_by_start_time(&mut snapshot); diff --git a/crates/perry-runtime/src/process.rs b/crates/perry-runtime/src/process.rs index ba995a4b39..1e59489223 100644 --- a/crates/perry-runtime/src/process.rs +++ b/crates/perry-runtime/src/process.rs @@ -736,12 +736,12 @@ pub(crate) static SOURCE_MAPS_GENERATED_CODE: AtomicBool = AtomicBool::new(false pub(crate) static MODULE_COMPILE_CACHE_DIR: std::sync::Mutex> = std::sync::Mutex::new(None); -/// Thread-local cell holding the process title set via `process.title = X` -/// (#1401). `None` means "not assigned yet, fall back to argv[0]". The -/// setter records the value here; on Linux it also calls `prctl(PR_SET_NAME)` -/// so `/proc//comm` reflects the new value. macOS has no per-process -/// analog — the assignment is still observable via subsequent `process.title` -/// reads, matching Node's best-effort semantics. +// Thread-local cell holding the process title set via `process.title = X` +// (#1401). `None` means "not assigned yet, fall back to argv[0]". The +// setter records the value here; on Linux it also calls `prctl(PR_SET_NAME)` +// so `/proc//comm` reflects the new value. macOS has no per-process +// analog — the assignment is still observable via subsequent `process.title` +// reads, matching Node's best-effort semantics. thread_local! { pub(crate) static PROCESS_TITLE: std::cell::RefCell> = const { std::cell::RefCell::new(None) diff --git a/crates/perry-runtime/src/promise/combinators.rs b/crates/perry-runtime/src/promise/combinators.rs index cd829dbcd2..099a46067c 100644 --- a/crates/perry-runtime/src/promise/combinators.rs +++ b/crates/perry-runtime/src/promise/combinators.rs @@ -13,7 +13,7 @@ use super::assimilate::{ }; #[derive(Clone, Copy)] -pub(super) struct PromiseAllState { +pub(crate) struct PromiseAllState { pub result_promise: *mut Promise, pub results_arr: *mut crate::array::ArrayHeader, pub state_arr: *mut crate::array::ArrayHeader, diff --git a/crates/perry-runtime/src/string/intern.rs b/crates/perry-runtime/src/string/intern.rs index 4b6c42e3e9..0a2a1c46cd 100644 --- a/crates/perry-runtime/src/string/intern.rs +++ b/crates/perry-runtime/src/string/intern.rs @@ -17,14 +17,14 @@ pub(crate) const INTERN_TABLE_MASK: usize = INTERN_TABLE_SIZE - 1; /// Maximum byte length for strings eligible for interning. pub(crate) const INTERN_MAX_BYTE_LEN: u32 = 64; -/// Per-thread intern table. -/// -/// Each thread (main + every `perry/thread` worker) has its own arena, so -/// cached `StringHeader*` pointers MUST be per-thread — a string interned -/// from worker A's arena is a use-after-free / cross-arena pointer when -/// read from worker B. The previous design used a single process-wide -/// `static mut`, which both raced under concurrent allocation and risked -/// handing back foreign-arena pointers. +// Per-thread intern table. +// +// Each thread (main + every `perry/thread` worker) has its own arena, so +// cached `StringHeader*` pointers MUST be per-thread — a string interned +// from worker A's arena is a use-after-free / cross-arena pointer when +// read from worker B. The previous design used a single process-wide +// `static mut`, which both raced under concurrent allocation and risked +// handing back foreign-arena pointers. thread_local! { // arm64_32 fix: HEAP-allocate (Box) this ~128KB table instead of inline TLS. // Oversized `#[thread_local]` storage overflows the ILP32 TLS layout and its diff --git a/crates/perry-stdlib/src/common/dispatch.rs b/crates/perry-stdlib/src/common/dispatch.rs index 39c2c254c8..62c9efe736 100644 --- a/crates/perry-stdlib/src/common/dispatch.rs +++ b/crates/perry-stdlib/src/common/dispatch.rs @@ -72,17 +72,17 @@ pub(crate) unsafe fn pack_args_array(args: &[f64]) -> *mut perry_runtime::ArrayH arr_handle.get_raw_mut_ptr::() } -/// Shared `extern "C"` surface of the EventEmitter implementation. Both -/// perry-stdlib (`bundled-events`) and perry-ext-events export these exact -/// symbols, kept byte-identical per #3072. The dispatch arms below call -/// through the linker-resolved symbol instead of `crate::events::*` so that -/// when the well-known flip links perry-ext-events, dynamic dispatch -/// consults the SAME handle registry the constructors used. An in-crate call -/// always hit perry-stdlib's registry and returned `None` for ext-events -/// handles — every dynamic `.on`/`.emit`/`.setMaxListeners` on an emitter -/// silently no-op'd and method-value reads came back `undefined` (#4995). -/// Mirrors the sqlite duplicate-symbol contract noted in -/// `compile/optimized_libs.rs` (#643). +// Shared `extern "C"` surface of the EventEmitter implementation. Both +// perry-stdlib (`bundled-events`) and perry-ext-events export these exact +// symbols, kept byte-identical per #3072. The dispatch arms below call +// through the linker-resolved symbol instead of `crate::events::*` so that +// when the well-known flip links perry-ext-events, dynamic dispatch +// consults the SAME handle registry the constructors used. An in-crate call +// always hit perry-stdlib's registry and returned `None` for ext-events +// handles — every dynamic `.on`/`.emit`/`.setMaxListeners` on an emitter +// silently no-op'd and method-value reads came back `undefined` (#4995). +// Mirrors the sqlite duplicate-symbol contract noted in +// `compile/optimized_libs.rs` (#643). #[cfg(any(feature = "bundled-events", feature = "external-events-construct"))] extern "C" { pub(crate) fn js_event_emitter_is_handle(handle: i64) -> bool; diff --git a/crates/perry-stdlib/src/sqlite/connection.rs b/crates/perry-stdlib/src/sqlite/connection.rs index f8c88aaf8c..c252b7c361 100644 --- a/crates/perry-stdlib/src/sqlite/connection.rs +++ b/crates/perry-stdlib/src/sqlite/connection.rs @@ -46,7 +46,7 @@ pub(crate) fn open_node_sqlite_connection(db: &NodeSqliteDbHandle) -> rusqlite:: ] .get(idx) { - conn.set_limit(*limit, *value); + conn.set_limit(*limit, *value)?; } } } diff --git a/crates/perry-stdlib/src/sqlite/dispatch.rs b/crates/perry-stdlib/src/sqlite/dispatch.rs index e98092d73c..92afeb852e 100644 --- a/crates/perry-stdlib/src/sqlite/dispatch.rs +++ b/crates/perry-stdlib/src/sqlite/dispatch.rs @@ -382,7 +382,9 @@ pub unsafe fn dispatch_node_sqlite_limits_set( }; let new_value = non_negative_i32_value(value_from_f64(value), property_name, true); with_open_node_connection(limits.db_handle, |conn| { - conn.set_limit(limit, new_value); + // limit id is pre-validated by node_sqlite_limit above; deliberately + // discard set_limit's prior-value Result. + let _ = conn.set_limit(limit, new_value); }); true } diff --git a/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs b/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs index 3ff27f67ca..7ee02260e2 100644 --- a/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs +++ b/crates/perry/src/commands/compile/cjs_wrap/hoist_classes.rs @@ -603,13 +603,6 @@ fn collect_pattern_binding_names(bytes: &[u8], start: usize, names: &mut Vec { - // Unreachable in practice (handled above), kept for clarity. - i += 1; - } c if c.is_ascii_alphanumeric() || c == b'_' || c == b'$' || c == b'.' => { // Identifier (or `...rest` after the dots). Read it. let name_start = i; From 3fcd0b202f10d733d6cf43a688637401f66be7f4 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:22:19 +0200 Subject: [PATCH 06/18] =?UTF-8?q?chore(warnings):=20clear=20the=20last=206?= =?UTF-8?q?5=20warnings=20=E2=80=94=20host=20scope=20is=20now=20clean?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - objc2 deprecations: 17 `msg_send!` invocations were missing the comma between arguments, plus one `Retained::cast` swapped for the `cast_unchecked` the sibling widgets already use. - Vacuous glob re-exports: `pub use child::*` where every item in the child is `pub(super)` re-exports nothing, which is what rustc was reporting. Narrowed each to the visibility it actually has — two to `pub(crate)`, six to a plain `use` — instead of silencing the lint. - `native_proof_*` integration tests share one HIR builder toolkit and each file drives a subset, so the allow sits on the file with that reason. - issue_4914_cluster_port_sharing.rs: its only test is gated to non-macOS unix; the helpers and imports now carry the same gate. - `duplex_allow_half_open_defaults_true_and_honors_false_option` had no `#[test]`, so it had never run. Added. - `test_seed_class_parent_closure_root` existed twice, both writing the same `CLASS_PARENT_CLOSURES` static. Deleted the unreachable copy. - `WIDE_KEY_INDEX_CAPACITY` is a leftover of the 4-entry LRU that #6759 C1 replaced with shape records. - crash_log.rs took a shared reference to a `static mut` inside a signal handler; now `&raw const`. - Two dead stores removed (`idx`, `adjusted_args_storage`). The third, `done` in publish, is kept with a comment: rustc is right that the store is never read, and that means the reconnect guard it feeds can never fire — a protocol question, not a lint one. - Four test names de-camel-cased, one duplicated `#[test]` removed. `cargo check --workspace --all-targets` now reports zero warnings for the host-compatible scope. The cross-host UI crates (ios/tvos/watchos/visionos/ android/windows/gtk4) cannot be checked from macOS and are untouched. --- .../src/tests/containers.rs | 1 - .../perry-codegen-arkts/src/tests/widgets.rs | 4 +- .../tests/native_proof_buffer_views.rs | 6 +++ .../tests/native_proof_regressions.rs | 4 ++ crates/perry-runtime/src/array/tests.rs | 2 +- crates/perry-runtime/src/date/parse.rs | 3 +- crates/perry-runtime/src/gc/mod.rs | 2 +- crates/perry-runtime/src/gc/oldgen.rs | 6 +-- crates/perry-runtime/src/node_stream.rs | 16 ++++---- .../src/node_stream_tests_extra.rs | 1 + .../perry-runtime/src/node_submodules/mod.rs | 2 +- .../src/node_submodules/tests.rs | 2 +- .../src/object/class_registry/dispatch.rs | 2 +- .../src/object/class_registry/gc_roots.rs | 5 --- .../src/object/field_get_set/has_property.rs | 1 - crates/perry-ui-macos/src/audio.rs | 10 ++--- crates/perry-ui-macos/src/audio_playback.rs | 40 +++++++++---------- crates/perry-ui-macos/src/crash_log.rs | 2 +- crates/perry-ui-macos/src/widgets/adbanner.rs | 2 +- crates/perry-ui-macos/src/widgets/canvas.rs | 4 +- crates/perry-ui-macos/src/widgets/chart.rs | 2 +- crates/perry-ui-macos/src/widgets/combobox.rs | 2 +- crates/perry-ui-macos/src/widgets/image.rs | 2 +- crates/perry-ui-macos/src/widgets/mod.rs | 4 +- crates/perry-ui-macos/src/widgets/qrcode.rs | 6 +-- crates/perry-ui-macos/src/widgets/webview.rs | 2 +- crates/perry/src/commands/publish/mod.rs | 11 ++++- .../tests/issue_4914_cluster_port_sharing.rs | 4 ++ 28 files changed, 82 insertions(+), 66 deletions(-) diff --git a/crates/perry-codegen-arkts/src/tests/containers.rs b/crates/perry-codegen-arkts/src/tests/containers.rs index 9265f7e1e9..5998d7ed61 100644 --- a/crates/perry-codegen-arkts/src/tests/containers.rs +++ b/crates/perry-codegen-arkts/src/tests/containers.rs @@ -4,7 +4,6 @@ // Section, string + number formatting, and the perry/media drain glue. use super::*; -#[test] // ----- Phase 2 v12: Tabs / Modal / Menu / Grid ----- #[test] fn tabs_emits_tabcontent_per_spec() { diff --git a/crates/perry-codegen-arkts/src/tests/widgets.rs b/crates/perry-codegen-arkts/src/tests/widgets.rs index 7ee39fc1fd..c97a63beff 100644 --- a/crates/perry-codegen-arkts/src/tests/widgets.rs +++ b/crates/perry-codegen-arkts/src/tests/widgets.rs @@ -340,7 +340,7 @@ fn animation_modifier_maps_curve_string_to_curve_enum() { } #[test] -fn shadow_modifier_maps_blur_to_radius_offsets_to_offsetXY() { +fn shadow_modifier_maps_blur_to_radius_offsets_to_offset_xy() { let mut m = empty_module(); m.init.push(app_with_body(nmc( "Text", @@ -518,7 +518,7 @@ fn inline_style_border_combines_color_and_width() { } #[test] -fn text_with_id_string_is_NOT_treated_as_style() { +fn text_with_id_string_is_not_treated_as_style() { // Text("Count: 0", "counter") — second string arg is the reactive // id, NOT a style object. extract_style_object returns None for // String args, so the v3.2 reactive path still wins. diff --git a/crates/perry-codegen/tests/native_proof_buffer_views.rs b/crates/perry-codegen/tests/native_proof_buffer_views.rs index 58463077c1..518bdc1d80 100644 --- a/crates/perry-codegen/tests/native_proof_buffer_views.rs +++ b/crates/perry-codegen/tests/native_proof_buffer_views.rs @@ -1,3 +1,9 @@ +// The `native_proof_*` integration tests share one hand-written HIR builder +// toolkit, and each file drives a different subset of it. Per-file pruning +// would make the next test in this family re-add the builder it needs, so the +// toolkit stays whole. +#![allow(dead_code)] + use perry_codegen::{compile_module, AppMetadata, CompileOptions}; use perry_hir::types::{FunctionType, ObjectType, PropertyInfo, Type}; use perry_hir::{ diff --git a/crates/perry-codegen/tests/native_proof_regressions.rs b/crates/perry-codegen/tests/native_proof_regressions.rs index 3c7d75359d..385bd86bec 100644 --- a/crates/perry-codegen/tests/native_proof_regressions.rs +++ b/crates/perry-codegen/tests/native_proof_regressions.rs @@ -1,3 +1,7 @@ +// See native_proof_buffer_views.rs — shared HIR builder toolkit, each file in +// this family drives a different subset. +#![allow(dead_code)] + use perry_codegen::{compile_module, AppMetadata, CompileOptions}; use perry_hir::types::{ObjectType, PropertyInfo, Type, TypeParam}; use perry_hir::{ diff --git a/crates/perry-runtime/src/array/tests.rs b/crates/perry-runtime/src/array/tests.rs index e413138d41..9f63f59292 100644 --- a/crates/perry-runtime/src/array/tests.rs +++ b/crates/perry-runtime/src/array/tests.rs @@ -1245,7 +1245,7 @@ fn test_array_pop_and_push() { } #[test] -fn test_array_indexOf() { +fn test_array_index_of() { let arr = js_array_alloc(4); js_array_push_f64(arr, 10.0); js_array_push_f64(arr, 20.0); diff --git a/crates/perry-runtime/src/date/parse.rs b/crates/perry-runtime/src/date/parse.rs index 1955def549..c87fc236d8 100644 --- a/crates/perry-runtime/src/date/parse.rs +++ b/crates/perry-runtime/src/date/parse.rs @@ -107,7 +107,6 @@ fn parse_iso8601(s: &str) -> Option { let mut minute: i64 = 0; let mut second: i64 = 0; let mut millis: i64 = 0; - let mut idx = year_end; // Year only ("YYYY" / "±YYYYYY"). if s.len() == year_end { @@ -132,7 +131,7 @@ fn parse_iso8601(s: &str) -> Option { if !(1..=12).contains(&month1) { return None; } - idx = year_end + 3; + let mut idx = year_end + 3; let mut has_day = false; if b.get(idx) == Some(&b'-') { if b.len() < idx + 3 { diff --git a/crates/perry-runtime/src/gc/mod.rs b/crates/perry-runtime/src/gc/mod.rs index 9ffc97b7e6..916101c985 100644 --- a/crates/perry-runtime/src/gc/mod.rs +++ b/crates/perry-runtime/src/gc/mod.rs @@ -41,7 +41,7 @@ pub use policy::*; mod progress; pub use progress::*; mod heap_budget; -pub use heap_budget::*; +pub(crate) use heap_budget::*; mod pressure; pub use pressure::*; mod telemetry; diff --git a/crates/perry-runtime/src/gc/oldgen.rs b/crates/perry-runtime/src/gc/oldgen.rs index 1ffe7c376a..5a19ddb036 100644 --- a/crates/perry-runtime/src/gc/oldgen.rs +++ b/crates/perry-runtime/src/gc/oldgen.rs @@ -197,9 +197,9 @@ pub(super) fn select_old_page_defrag_pages_from_snapshot( selection } -/// gh #6206 test hook: the defrag machinery's unit tests exercise the -/// selection/copy/re-remember mechanics directly and must bypass the -/// production off-gate below. Thread-local so parallel tests don't race. +// gh #6206 test hook: the defrag machinery's unit tests exercise the +// selection/copy/re-remember mechanics directly and must bypass the +// production off-gate below. Thread-local so parallel tests don't race. #[cfg(test)] thread_local! { pub(crate) static OLD_DEFRAG_TEST_OVERRIDE: std::cell::Cell> = diff --git a/crates/perry-runtime/src/node_stream.rs b/crates/perry-runtime/src/node_stream.rs index a02bfd9a2a..703221c709 100644 --- a/crates/perry-runtime/src/node_stream.rs +++ b/crates/perry-runtime/src/node_stream.rs @@ -1723,19 +1723,19 @@ pub extern "C" fn js_node_stream_method_uncork(stream_handle: i64) -> f64 { // `pub(super)` helpers remain crate-internal. #[path = "node_stream_keys.rs"] mod keys; -pub use keys::*; +use keys::*; #[path = "node_stream_dispatch.rs"] mod dispatch; -pub use dispatch::*; +pub(crate) use dispatch::*; #[path = "node_stream_iter_helpers.rs"] mod iter_helpers; -pub use iter_helpers::*; +use iter_helpers::*; #[path = "node_stream_pipeline.rs"] mod pipeline; -pub use pipeline::*; +use pipeline::*; #[path = "node_stream_readwrite.rs"] mod readwrite; @@ -1743,19 +1743,19 @@ pub use readwrite::*; #[path = "node_stream_readable_read.rs"] mod readable_read; -pub use readable_read::*; +use readable_read::*; #[path = "node_stream_duplex_methods.rs"] mod duplex_method_table; -pub use duplex_method_table::*; +use duplex_method_table::*; #[path = "node_stream_compose_live.rs"] mod compose_live; -pub use compose_live::*; +use compose_live::*; #[path = "node_stream_json.rs"] mod json_stream; -pub use json_stream::*; +pub(crate) use json_stream::*; #[path = "node_stream_constructors.rs"] mod constructors; diff --git a/crates/perry-runtime/src/node_stream_tests_extra.rs b/crates/perry-runtime/src/node_stream_tests_extra.rs index 76e49e3ca8..520b19a28c 100644 --- a/crates/perry-runtime/src/node_stream_tests_extra.rs +++ b/crates/perry-runtime/src/node_stream_tests_extra.rs @@ -569,6 +569,7 @@ fn destroyed_readable_drops_late_push_data() { READABLE_DATA_CAPTURED.with(|captured| assert!(captured.borrow().is_empty())); } +#[test] fn duplex_allow_half_open_defaults_true_and_honors_false_option() { let stream = js_node_stream_duplex_new(f64::from_bits(TAG_UNDEFINED)); let handle = raw_ptr_from_value(stream) as i64; diff --git a/crates/perry-runtime/src/node_submodules/mod.rs b/crates/perry-runtime/src/node_submodules/mod.rs index cf4b269960..f7feca3470 100644 --- a/crates/perry-runtime/src/node_submodules/mod.rs +++ b/crates/perry-runtime/src/node_submodules/mod.rs @@ -75,7 +75,7 @@ impl ExportThunk { /// `(submodule_key, export_name)` and falls back to `TAG_TRUE` if no /// matching entry is found (preserving the pre-#841 behavior for any /// future export Perry doesn't yet know about). -struct SubmoduleSpec { +pub(super) struct SubmoduleSpec { /// Stable key — matches the prefix used in the generated FFI symbol /// names (`js_node_submod__export_`). key: &'static str, diff --git a/crates/perry-runtime/src/node_submodules/tests.rs b/crates/perry-runtime/src/node_submodules/tests.rs index c577205e90..6b4e62f2bd 100644 --- a/crates/perry-runtime/src/node_submodules/tests.rs +++ b/crates/perry-runtime/src/node_submodules/tests.rs @@ -84,7 +84,7 @@ fn find_submodule_for_unknown_key_returns_none() { /// expose `tracingChannel` as a callable thunk in the SUBMODULES table /// so the namespace singleton's field is a function (not TAG_TRUE). #[test] -fn diagnostics_channel_exposes_tracingChannel_export() { +fn diagnostics_channel_exposes_tracing_channel_export() { let submod = find_submodule("diagnostics_channel").expect("diagnostics_channel must be in SUBMODULES"); let names: Vec<&str> = submod.exports.iter().map(|e| e.name).collect(); diff --git a/crates/perry-runtime/src/object/class_registry/dispatch.rs b/crates/perry-runtime/src/object/class_registry/dispatch.rs index 2c78272293..bc4869f687 100644 --- a/crates/perry-runtime/src/object/class_registry/dispatch.rs +++ b/crates/perry-runtime/src/object/class_registry/dispatch.rs @@ -249,7 +249,7 @@ pub(crate) unsafe fn call_vtable_method( // `(number).forEach is not a function`. The synthesized-`arguments` slot // holds ALL passed args; a user rest slot holds only args from the rest // position onward (so `method(a, ...rest)` keeps `a` positional). - let mut adjusted_args_storage: Option> = None; + let adjusted_args_storage: Option>; let (call_args_ptr, call_args_len) = if has_synthetic_arguments || has_rest { let visible_params = (param_count as usize).saturating_sub(1); let pack_start = if has_synthetic_arguments { diff --git a/crates/perry-runtime/src/object/class_registry/gc_roots.rs b/crates/perry-runtime/src/object/class_registry/gc_roots.rs index e3e903d2c5..6d1b60d90f 100644 --- a/crates/perry-runtime/src/object/class_registry/gc_roots.rs +++ b/crates/perry-runtime/src/object/class_registry/gc_roots.rs @@ -584,11 +584,6 @@ pub(crate) fn test_class_prototype_object_root_addr(class_id: u32) -> usize { .unwrap_or(0) } -#[cfg(test)] -pub(crate) fn test_seed_class_parent_closure_root(class_id: u32, addr: usize) { - class_parent_closure_root_store(class_id, addr); -} - #[cfg(test)] pub(crate) fn test_class_parent_closure_root_addr(class_id: u32) -> usize { CLASS_PARENT_CLOSURES diff --git a/crates/perry-runtime/src/object/field_get_set/has_property.rs b/crates/perry-runtime/src/object/field_get_set/has_property.rs index 3998ab10f6..0f209b9b7d 100644 --- a/crates/perry-runtime/src/object/field_get_set/has_property.rs +++ b/crates/perry-runtime/src/object/field_get_set/has_property.rs @@ -1274,7 +1274,6 @@ pub(crate) unsafe fn native_module_own_field_by_key( // accelerator, never authoritative — and a scan hit back-fills the map so // interleaved appends stay amortized O(1). pub(crate) const WIDE_KEY_INDEX_MIN_KEYS: usize = 257; -const WIDE_KEY_INDEX_CAPACITY: usize = 4; // #6759 C1: the wide-object key index folded into the shape records // (`object::shapes`, keyed on keys_array identity, unbounded — the old diff --git a/crates/perry-ui-macos/src/audio.rs b/crates/perry-ui-macos/src/audio.rs index d71e74f7e6..50f13a4b83 100644 --- a/crates/perry-ui-macos/src/audio.rs +++ b/crates/perry-ui-macos/src/audio.rs @@ -201,9 +201,9 @@ pub fn start() -> i64 { let buffer_size: u32 = 1024; let _: () = msg_send![ input_node, - installTapOnBus: 0u32 - bufferSize: buffer_size - format: format + installTapOnBus: 0u32, + bufferSize: buffer_size, + format: format, block: &*tap_block ]; @@ -395,8 +395,8 @@ fn write_wav_samples(writer: &mut File, samples: &[f32]) -> std::io::Result<()> // Internal: Audio processing // ============================================================================= -/// EMA (exponential moving average) state. Uses thread_local because the -/// tap block always runs on the same audio thread. +// EMA (exponential moving average) state. Uses thread_local because the +// tap block always runs on the same audio thread. thread_local! { static FILTER_STATE: RefCell = RefCell::new(AWeightState::new()); static EMA_DB: RefCell = const { RefCell::new(0.0) }; diff --git a/crates/perry-ui-macos/src/audio_playback.rs b/crates/perry-ui-macos/src/audio_playback.rs index a9ac0c89a0..4896f7fea3 100644 --- a/crates/perry-ui-macos/src/audio_playback.rs +++ b/crates/perry-ui-macos/src/audio_playback.rs @@ -272,13 +272,13 @@ pub extern "C" fn perry_audio_load_sound(path_ptr: i64, bus: f64, stream: f64) - let ns_name = objc2_foundation::NSString::from_str(name); let ns_ext = objc2_foundation::NSString::from_str(ext); let mut url: *mut AnyObject = - msg_send![bundle, URLForResource: &*ns_name withExtension: &*ns_ext]; + msg_send![bundle, URLForResource: &*ns_name, withExtension: &*ns_ext]; if url.is_null() { let ns_subdir = objc2_foundation::NSString::from_str("sounds"); url = msg_send![ bundle, - URLForResource: &*ns_name - withExtension: &*ns_ext + URLForResource: &*ns_name, + withExtension: &*ns_ext, subdirectory: &*ns_subdir ]; } @@ -332,7 +332,7 @@ pub extern "C" fn perry_audio_load_sound(path_ptr: i64, bus: f64, stream: f64) - let format_ptr: *mut AnyObject = &*format as *const AnyObject as *mut AnyObject; let buffer_raw: *mut AnyObject = msg_send![ buf_alloc, - initWithPCMFormat: format_ptr + initWithPCMFormat: format_ptr, frameCapacity: capacity ]; if buffer_raw.is_null() { @@ -341,7 +341,7 @@ pub extern "C" fn perry_audio_load_sound(path_ptr: i64, bus: f64, stream: f64) - let buffer = Retained::retain(buffer_raw).unwrap(); error = std::ptr::null_mut(); - let read_ok: bool = msg_send![&*file, readIntoBuffer: &*buffer error: &mut error]; + let read_ok: bool = msg_send![&*file, readIntoBuffer: &*buffer, error: &mut error]; if !read_ok || !error.is_null() { eprintln!("[perry/audio] loadSound: read failed: {}", filename); return 0; @@ -494,14 +494,14 @@ pub extern "C" fn perry_audio_play( let _: () = msg_send![&**engine, attachNode: &**vs]; let _: () = msg_send![ &**engine, - connect: &*player_node - to: &**vs + connect: &*player_node, + to: &**vs, format: buf_format ]; let _: () = msg_send![ &**engine, - connect: &**vs - to: bus_node + connect: &**vs, + to: bus_node, format: buf_format ]; } else { @@ -515,8 +515,8 @@ pub extern "C" fn perry_audio_play( }); let _: () = msg_send![ &**engine, - connect: &*player_node - to: bus_node + connect: &*player_node, + to: bus_node, format: buf_format ]; } @@ -548,8 +548,8 @@ pub extern "C" fn perry_audio_play( let cb = make_ended_block(voice_idx); let _: () = msg_send![ &*player_node, - scheduleFile: &**file - atTime: std::ptr::null::() + scheduleFile: &**file, + atTime: std::ptr::null::(), completionHandler: &*cb ]; std::mem::forget(cb); @@ -565,9 +565,9 @@ pub extern "C" fn perry_audio_play( }; let _: () = msg_send![ &*player_node, - scheduleBuffer: &**buffer_ret - atTime: std::ptr::null::() - options: options + scheduleBuffer: &**buffer_ret, + atTime: std::ptr::null::(), + options: options, completionHandler: &*cb ]; std::mem::forget(cb); @@ -674,8 +674,8 @@ fn drain_pending_callbacks() { let cb = make_ended_block(idx); let _: () = msg_send![ &*player_node, - scheduleFile: &*file - atTime: std::ptr::null::() + scheduleFile: &*file, + atTime: std::ptr::null::(), completionHandler: &*cb ]; std::mem::forget(cb); @@ -1051,8 +1051,8 @@ pub extern "C" fn perry_audio_create_bus(name_ptr: i64, parent: f64) -> i64 { let null_fmt: *const AnyObject = std::ptr::null(); let _: () = msg_send![ &**engine, - connect: &*mixer - to: parent_node + connect: &*mixer, + to: parent_node, format: null_fmt ]; true diff --git a/crates/perry-ui-macos/src/crash_log.rs b/crates/perry-ui-macos/src/crash_log.rs index 6bfdcefcc0..c238adcee9 100644 --- a/crates/perry-ui-macos/src/crash_log.rs +++ b/crates/perry-ui-macos/src/crash_log.rs @@ -115,7 +115,7 @@ extern "C" fn signal_handler(sig: libc::c_int) { unsafe { if CRASH_LOG_PATH_LEN > 0 { let fd = libc::open( - CRASH_LOG_PATH_BUF.as_ptr() as *const libc::c_char, + (&raw const CRASH_LOG_PATH_BUF) as *const libc::c_char, libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC, 0o644, ); diff --git a/crates/perry-ui-macos/src/widgets/adbanner.rs b/crates/perry-ui-macos/src/widgets/adbanner.rs index 9f4cf318d4..2326fe93cf 100644 --- a/crates/perry-ui-macos/src/widgets/adbanner.rs +++ b/crates/perry-ui-macos/src/widgets/adbanner.rs @@ -10,7 +10,7 @@ use objc2::msg_send; use objc2::rc::Retained; -use objc2::{AnyThread, MainThreadOnly}; +use objc2::MainThreadOnly; use objc2_app_kit::NSView; use objc2_core_foundation::{CGPoint, CGRect, CGSize}; use objc2_foundation::MainThreadMarker; diff --git a/crates/perry-ui-macos/src/widgets/canvas.rs b/crates/perry-ui-macos/src/widgets/canvas.rs index 16a2715df3..92be12f0b1 100644 --- a/crates/perry-ui-macos/src/widgets/canvas.rs +++ b/crates/perry-ui-macos/src/widgets/canvas.rs @@ -17,7 +17,7 @@ use crate::ffi::CGContextStrokePath; use crate::ffi::CGContextStrokeRect; use objc2::rc::Retained; use objc2::runtime::AnyObject; -use objc2::{define_class, msg_send, AnyThread, DefinedClass, MainThreadOnly}; +use objc2::{define_class, msg_send, DefinedClass, MainThreadOnly}; use objc2_app_kit::NSView; use objc2_core_foundation::{CGPoint, CGRect, CGSize}; use objc2_foundation::MainThreadMarker; @@ -564,7 +564,7 @@ pub fn create(width: f64, height: f64) -> i64 { }); // Cast to NSView for registration - let ns_view: Retained = unsafe { Retained::cast(view) }; + let ns_view: Retained = unsafe { Retained::cast_unchecked(view) }; register_widget(ns_view) } diff --git a/crates/perry-ui-macos/src/widgets/chart.rs b/crates/perry-ui-macos/src/widgets/chart.rs index 54738f8b25..f87d9a5b2d 100644 --- a/crates/perry-ui-macos/src/widgets/chart.rs +++ b/crates/perry-ui-macos/src/widgets/chart.rs @@ -31,7 +31,7 @@ use crate::ffi::CGContextStrokePath; use objc2::msg_send; use objc2::rc::Retained; use objc2::runtime::{AnyClass, AnyObject}; -use objc2::{define_class, AnyThread, DefinedClass, MainThreadOnly}; +use objc2::{define_class, DefinedClass, MainThreadOnly}; use objc2_app_kit::NSView; use objc2_core_foundation::CGFloat; use objc2_foundation::MainThreadMarker; diff --git a/crates/perry-ui-macos/src/widgets/combobox.rs b/crates/perry-ui-macos/src/widgets/combobox.rs index cb04824432..5cd4f84f71 100644 --- a/crates/perry-ui-macos/src/widgets/combobox.rs +++ b/crates/perry-ui-macos/src/widgets/combobox.rs @@ -12,7 +12,7 @@ use crate::ffi::js_string_from_bytes; use objc2::rc::Retained; use objc2::runtime::{AnyClass, AnyObject, Sel}; -use objc2::{define_class, msg_send, AnyThread, DefinedClass, MainThreadOnly}; +use objc2::{define_class, msg_send, AnyThread, DefinedClass}; use objc2_app_kit::NSView; use objc2_foundation::{MainThreadMarker, NSObject, NSString}; use std::cell::RefCell; diff --git a/crates/perry-ui-macos/src/widgets/image.rs b/crates/perry-ui-macos/src/widgets/image.rs index 9dcedadb35..005a114298 100644 --- a/crates/perry-ui-macos/src/widgets/image.rs +++ b/crates/perry-ui-macos/src/widgets/image.rs @@ -1,6 +1,6 @@ use objc2::msg_send; use objc2::rc::Retained; -use objc2::{AnyThread, MainThreadOnly}; +use objc2::MainThreadOnly; use objc2_app_kit::{NSImage, NSImageView, NSView}; use objc2_foundation::{MainThreadMarker, NSString}; diff --git a/crates/perry-ui-macos/src/widgets/mod.rs b/crates/perry-ui-macos/src/widgets/mod.rs index ffbcc7fee4..e11093d8d4 100644 --- a/crates/perry-ui-macos/src/widgets/mod.rs +++ b/crates/perry-ui-macos/src/widgets/mod.rs @@ -211,9 +211,9 @@ pub fn register_external_nsview(nsview_ptr: i64) -> i64 { // Set low content hugging so it stretches in both axes. unsafe { let _: () = - msg_send![&*nsview, setContentHuggingPriority: 1.0f32 forOrientation: 0i64]; // horizontal + msg_send![&*nsview, setContentHuggingPriority: 1.0f32, forOrientation: 0i64]; // horizontal let _: () = - msg_send![&*nsview, setContentHuggingPriority: 1.0f32 forOrientation: 1i64]; + msg_send![&*nsview, setContentHuggingPriority: 1.0f32, forOrientation: 1i64]; // vertical } // Clip to bounds — prevent the view from drawing outside its frame diff --git a/crates/perry-ui-macos/src/widgets/qrcode.rs b/crates/perry-ui-macos/src/widgets/qrcode.rs index 156bd3696b..8df08dc977 100644 --- a/crates/perry-ui-macos/src/widgets/qrcode.rs +++ b/crates/perry-ui-macos/src/widgets/qrcode.rs @@ -1,7 +1,7 @@ use objc2::msg_send; use objc2::rc::Retained; use objc2::runtime::{AnyClass, AnyObject}; -use objc2::{AnyThread, MainThreadOnly}; +use objc2::MainThreadOnly; use objc2_app_kit::{NSImage, NSImageView, NSView}; use objc2_foundation::{MainThreadMarker, NSString}; @@ -120,7 +120,7 @@ unsafe fn generate_qr_image(text: &str, display_size: f64) -> Option Option // closed WebSocket (the hub drops connections while a job sits in the queue) // must RECONNECT + re-subscribe rather than silently end the publish — else // the command exits without ever downloading the artifact (#flaky-publish). + // + // rustc reports the `done = true` in the Complete arm as never read, + // because that arm breaks the loop immediately afterwards, so the two + // `if done { break }` guards on the stream-ended / closed paths can only + // ever see `false`. Whether the flag still buys anything is a protocol + // question, not a lint one — the store stays until that is answered. let mut done = false; // `published` = the hub confirmed a server-side publish (TestFlight / App // Store etc.), where no local artifact is downloaded. @@ -1790,7 +1796,10 @@ async fn run_async(args: PublishArgs, format: OutputFormat, _use_color: bool) -> .. } => { build_success = success; - done = true; + #[allow(unused_assignments)] + { + done = true; + } if let OutputFormat::Text = format { println!(); if success { diff --git a/crates/perry/tests/issue_4914_cluster_port_sharing.rs b/crates/perry/tests/issue_4914_cluster_port_sharing.rs index aeb854f962..8eea8fb5ca 100644 --- a/crates/perry/tests/issue_4914_cluster_port_sharing.rs +++ b/crates/perry/tests/issue_4914_cluster_port_sharing.rs @@ -25,13 +25,17 @@ //! The primary discovers a free port by binding port 0 once and closing it //! (the `listen(0)` shared-ephemeral-port round-trip itself is #4962). +#[cfg(all(unix, not(target_os = "macos")))] use std::path::PathBuf; +#[cfg(all(unix, not(target_os = "macos")))] use std::process::Command; +#[cfg(all(unix, not(target_os = "macos")))] fn perry_bin() -> PathBuf { PathBuf::from(env!("CARGO_BIN_EXE_perry")) } +#[cfg(all(unix, not(target_os = "macos")))] fn compile_and_run(dir: &std::path::Path, source: &str) -> String { let entry = dir.join("main.ts"); let output = dir.join("main_bin"); From 75f4744f350824436bdb574fa80947039e66abba Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:31:46 +0200 Subject: [PATCH 07/18] chore(warnings): clean the reduced-feature scope too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `perry` depends on perry-runtime with `default-features = false`, so `cargo clippy -p perry --bins` — the product leg in CI — compiles a runtime where regex-engine, diagnostics and temporal are off. Eleven items are live under the workspace feature set and dead under that one, and the workspace check never saw them. Each is now gated at the item rather than silenced: - `array_named_props_install_fresh` and `regex::utf16::utf16_index_to_byte` are called only from regex-engine modules; both, and the array re-export, carry that feature (the cross-gate shape regex/utf16.rs already documents). - Four `fs::dir_glob_watch::glob` imports serve regex-engine-gated code and now match the `PathBuf` import next to them. - The two `AllocatorMaintenance*` enums and `TemporalLocaleCtx` are built from `diagnostics` and `temporal` code respectively, so the allow applies only when that feature is off. - publish's `done` allow moved to the function: a statement-level attribute does not affect `unused_assignments`. Four scopes now report zero warnings: `--workspace --all-targets`, `-p perry --bins`, `-p perry-runtime --no-default-features`, and `-p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static`. --- crates/perry-runtime/src/array/header.rs | 1 + crates/perry-runtime/src/array/mod.rs | 12 ++++++++---- .../perry-runtime/src/fs/dir_glob_watch/glob.rs | 4 ++++ crates/perry-runtime/src/gc/telemetry.rs | 2 ++ .../src/intl/date_collator/temporal.rs | 1 + crates/perry-runtime/src/regex/utf16.rs | 1 + crates/perry/src/commands/publish/mod.rs | 16 ++++++---------- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/crates/perry-runtime/src/array/header.rs b/crates/perry-runtime/src/array/header.rs index 91bca4728d..4c45b6fe4b 100644 --- a/crates/perry-runtime/src/array/header.rs +++ b/crates/perry-runtime/src/array/header.rs @@ -341,6 +341,7 @@ pub(crate) unsafe fn array_named_property_set( /// bypassing `js_array_set_string_key`'s guard ladder sound. Keys must not be /// numeric index strings or `"length"` (those live in element storage / /// the header, not this side table). +#[cfg(feature = "regex-engine")] pub(crate) unsafe fn array_named_props_install_fresh( arr: *mut ArrayHeader, entries: &[(&'static str, f64)], diff --git a/crates/perry-runtime/src/array/mod.rs b/crates/perry-runtime/src/array/mod.rs index 705f61e95b..d7e4451ef4 100644 --- a/crates/perry-runtime/src/array/mod.rs +++ b/crates/perry-runtime/src/array/mod.rs @@ -155,10 +155,9 @@ pub(crate) use self::flat_clone::flattenable_array_ptr; pub(crate) use self::header::{ array_byte_size, array_is_frozen, array_is_sealed_or_no_extend, array_named_property_delete, array_named_property_get, array_named_property_get_by_name, array_named_property_has, - array_named_property_names, array_named_property_set, array_named_props_install_fresh, - array_numeric_raw_f64_get, array_numeric_raw_f64_push_inbounds, - array_numeric_raw_f64_set_inbounds, array_object_flags, array_ptr_as_proxy, - canonicalize_array_numeric_store_value, clean_arr_ptr, clean_arr_ptr_mut, + array_named_property_names, array_named_property_set, array_numeric_raw_f64_get, + array_numeric_raw_f64_push_inbounds, array_numeric_raw_f64_set_inbounds, array_object_flags, + array_ptr_as_proxy, canonicalize_array_numeric_store_value, clean_arr_ptr, clean_arr_ptr_mut, clear_array_numeric_layout, clear_array_numeric_layout_ptr, gc_element_slot_range, mark_array_layout_unknown, mark_array_raw_f64_holes_fresh, normalize_array_receiver, note_array_slot, note_array_slot_layout_only, rebuild_array_layout, rebuild_array_layout_exact, @@ -167,5 +166,10 @@ pub(crate) use self::header::{ MIN_ARRAY_CAPACITY, }; +// Sole caller is the regex-engine-gated `regex::exec_array`, so the helper and +// this re-export are gated with it (same cross-gate shape as regex/utf16.rs). +#[cfg(feature = "regex-engine")] +pub(crate) use self::header::array_named_props_install_fresh; + #[cfg(test)] pub(crate) use self::header::{test_seed_template_raw_roots, test_template_raw_roots}; diff --git a/crates/perry-runtime/src/fs/dir_glob_watch/glob.rs b/crates/perry-runtime/src/fs/dir_glob_watch/glob.rs index 16e1eadc4d..3051db49ff 100644 --- a/crates/perry-runtime/src/fs/dir_glob_watch/glob.rs +++ b/crates/perry-runtime/src/fs/dir_glob_watch/glob.rs @@ -7,12 +7,16 @@ use super::string_value; // directly here (we are a grandchild of `fs`); the two private-to-`fs/mod.rs` // helpers are named explicitly so a glob that skips privates can't drop them. +#[cfg(feature = "regex-engine")] use std::collections::BTreeMap; +#[cfg(feature = "regex-engine")] use std::fs; +#[cfg(feature = "regex-engine")] use std::path::Path; #[cfg(feature = "regex-engine")] use std::path::PathBuf; +#[cfg(feature = "regex-engine")] use crate::closure::ClosureHeader; /// Compiled exclude-pattern type for `fs.glob`. Backed by `fancy_regex::Regex`. diff --git a/crates/perry-runtime/src/gc/telemetry.rs b/crates/perry-runtime/src/gc/telemetry.rs index 87a3bc0ffb..7a62888f94 100644 --- a/crates/perry-runtime/src/gc/telemetry.rs +++ b/crates/perry-runtime/src/gc/telemetry.rs @@ -589,6 +589,7 @@ pub(super) struct GcPauseStepTrace { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(not(feature = "diagnostics"), allow(dead_code))] pub(super) enum AllocatorMaintenanceStatus { Skipped, Executed, @@ -608,6 +609,7 @@ impl AllocatorMaintenanceStatus { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(not(feature = "diagnostics"), allow(dead_code))] pub(super) enum AllocatorMaintenanceReason { OrdinaryBudgeted, NotSupported, diff --git a/crates/perry-runtime/src/intl/date_collator/temporal.rs b/crates/perry-runtime/src/intl/date_collator/temporal.rs index e6cba90afa..ec027f9112 100644 --- a/crates/perry-runtime/src/intl/date_collator/temporal.rs +++ b/crates/perry-runtime/src/intl/date_collator/temporal.rs @@ -9,6 +9,7 @@ use super::*; /// Context tag for [`temporal_locale_string`] — which Temporal type is being formatted. /// Controls default options, type-specific TypeError guards, and timezone handling. #[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(not(feature = "temporal"), allow(dead_code))] pub(crate) enum TemporalLocaleCtx { PlainDate, PlainDateTime, diff --git a/crates/perry-runtime/src/regex/utf16.rs b/crates/perry-runtime/src/regex/utf16.rs index c1d2ebdfe1..2c5c0121d4 100644 --- a/crates/perry-runtime/src/regex/utf16.rs +++ b/crates/perry-runtime/src/regex/utf16.rs @@ -13,6 +13,7 @@ //! dependency as #6303.) /// UTF-16 code-unit index -> byte offset. +#[cfg(any(feature = "regex-engine", test))] pub(super) fn utf16_index_to_byte(s: &str, utf16_index: usize) -> usize { if utf16_index == 0 { return 0; diff --git a/crates/perry/src/commands/publish/mod.rs b/crates/perry/src/commands/publish/mod.rs index e6a38c06b2..dfa651ca1e 100644 --- a/crates/perry/src/commands/publish/mod.rs +++ b/crates/perry/src/commands/publish/mod.rs @@ -77,6 +77,7 @@ pub fn run(args: PublishArgs, format: OutputFormat, use_color: bool, _verbose: u result } +#[allow(unused_assignments)] // see the `done` declaration below async fn run_async(args: PublishArgs, format: OutputFormat, _use_color: bool) -> Result<()> { let project_dir = args.project.canonicalize().unwrap_or(args.project.clone()); @@ -1604,12 +1605,10 @@ async fn run_async(args: PublishArgs, format: OutputFormat, _use_color: bool) -> // closed WebSocket (the hub drops connections while a job sits in the queue) // must RECONNECT + re-subscribe rather than silently end the publish — else // the command exits without ever downloading the artifact (#flaky-publish). - // - // rustc reports the `done = true` in the Complete arm as never read, - // because that arm breaks the loop immediately afterwards, so the two - // `if done { break }` guards on the stream-ended / closed paths can only - // ever see `false`. Whether the flag still buys anything is a protocol - // question, not a lint one — the store stays until that is answered. + // rustc reports the `done = true` below as never read: the Complete arm + // breaks immediately, so both `if done { break }` guards only ever see + // `false`. Whether the flag still buys anything is a protocol question, + // not a lint one, so the store stays. let mut done = false; // `published` = the hub confirmed a server-side publish (TestFlight / App // Store etc.), where no local artifact is downloaded. @@ -1796,10 +1795,7 @@ async fn run_async(args: PublishArgs, format: OutputFormat, _use_color: bool) -> .. } => { build_success = success; - #[allow(unused_assignments)] - { - done = true; - } + done = true; if let OutputFormat::Text = format { println!(); if success { From 322f0ca54ce68cb35d7ddc6c5741461ec049b678 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:35:11 +0200 Subject: [PATCH 08/18] ci: gate rustc warnings with -D warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing stopped a PR from adding a warning: `lint` runs only `cargo fmt --check`, and `clippy` exits non-zero only on the deny-level lints in `[workspace.lints]`. The 96 unused imports this branch removed include 49 that reappeared within four days of #6639, from a file split that copied whole import preambles into each new submodule — the gate is what stops that. Two legs, because they compile different code. `perry` depends on perry-runtime with `default-features = false`, so the product leg sees a runtime with regex-engine, diagnostics and temporal off. The workspace leg passes `--all-targets` so test and bench targets count. Separate from the clippy job on purpose: clippy's warn-level lints stay informational, rustc's do not. perry-ui-macos sits in the excluded scope (this runs on ubuntu), so its warnings are not gated here. --- .github/workflows/test.yml | 67 ++++++++++++++++++++++ changelog.d/PRNUM-rust-warnings-to-zero.md | 31 ++++++++++ 2 files changed, 98 insertions(+) create mode 100644 changelog.d/PRNUM-rust-warnings-to-zero.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b2405ffaa..abb532b010 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -230,6 +230,73 @@ jobs: cargo clippy "${cargo_args[@]}" fi + # --------------------------------------------------------------------------- + # rustc warnings gate + # + # `cargo check` with `-D warnings`, so a PR cannot add a rustc warning. This + # is deliberately separate from the clippy job above: clippy's own warn-level + # lints are informational here, while rustc's are not. + # + # Both legs are needed because they compile different code. `perry` depends on + # perry-runtime with `default-features = false`, so the product leg sees a + # runtime with regex-engine, diagnostics and temporal off, where items the + # workspace leg finds live are dead. The workspace leg passes `--all-targets` + # so test and bench targets count too — without it, test-only code drifts. + # + # perry-ui-macos is in the excluded scope (this runs on ubuntu), so its + # warnings are not gated here. + # --------------------------------------------------------------------------- + rustc-warnings: + name: Warnings (${{ matrix.scope }}) + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + scope: [product, host-compatible] + env: + RUSTFLAGS: -D warnings + RUSTC_WRAPPER: sccache + SCCACHE_GHA_ENABLED: "false" + SCCACHE_DIR: ${{ github.workspace }}/.sccache + SCCACHE_CACHE_SIZE: "12G" + CARGO_INCREMENTAL: "0" + steps: + - uses: actions/checkout@v7 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install sccache + uses: mozilla-actions/sccache-action@v0.0.10 + + - name: Cache sccache objects + uses: actions/cache@v6 + with: + path: ${{ github.workspace }}/.sccache + key: sccache-${{ runner.os }}-perry-${{ github.job }}-${{ github.run_id }} + restore-keys: | + sccache-${{ runner.os }}-perry- + + - uses: Swatinem/rust-cache@v2 + with: + shared-key: "${{ runner.os }}-perry" + save-if: ${{ github.ref == 'refs/heads/main' }} + + - name: Check for rustc warnings + run: | + if [[ "${{ matrix.scope }}" == "product" ]]; then + cargo check -p perry --bins + else + mapfile -t excluded < <(python3 scripts/workspace_architecture.py \ + --print-excluded-scope host-compatible) + cargo_args=(--workspace --all-targets) + for package in "${excluded[@]}"; do + cargo_args+=(--exclude "$package") + done + cargo check "${cargo_args[@]}" + fi + # --------------------------------------------------------------------------- # API docs drift gate (#465) # diff --git a/changelog.d/PRNUM-rust-warnings-to-zero.md b/changelog.d/PRNUM-rust-warnings-to-zero.md new file mode 100644 index 0000000000..fe0b932a45 --- /dev/null +++ b/changelog.d/PRNUM-rust-warnings-to-zero.md @@ -0,0 +1,31 @@ +### Fixed + +- **Rust warnings: 492 → 0, and a CI gate so they stay there.** A clean + `cargo check --workspace --all-targets` on `main` emitted 492 warnings + (150 `unused_unsafe`, 121 `dead_code`, 96 `unused_imports`, 31 + `unreachable_patterns`, and eleven smaller families). Nothing in CI gated + them: the `lint` job runs only `cargo fmt --check`, and the `clippy` job + exits non-zero only on deny-level lints. Four scopes now report zero — + `--workspace --all-targets`, `-p perry --bins`, `-p perry-runtime + --no-default-features`, and the four-crate runtime/stdlib build — and a new + `rustc-warnings` job runs `cargo check` with `-D warnings` over the product + and host-compatible scopes. + + Three findings the sweep turned up, each fixed rather than silenced: + + - `js_node_http_res_write` and `js_node_http_res_end` were declared in an + `extern "C"` block in `perry-ext-http-server` for symbols that crate + defines itself. A local declaration of a symbol you also define is never + checked against the definition — the defect class that shipped an ABI + mismatch in #6646. Both signatures matched; the declarations are gone and + the remaining ~62 in that block are tracked separately. + - `duplex_allow_half_open_defaults_true_and_honors_false_option` had no + `#[test]` attribute, so it had never run. + - `test_seed_class_parent_closure_root` existed twice, both writing the same + `CLASS_PARENT_CLOSURES` static. + + Eleven warnings appeared only under the reduced feature set `perry` selects + (`default-features = false` on perry-runtime), where regex-engine, + diagnostics and temporal are off. Those items are gated at the item, not + suppressed. The cross-host UI crates (ios/tvos/watchos/visionos/android/ + windows/gtk4) cannot be checked from a macOS or Linux host and are untouched. From 30091790d78ebd839475adc4d7883d1a9bd2a67a Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 17:53:50 +0200 Subject: [PATCH 09/18] docs(changelog): key the warnings-sweep fragment to #6837 --- ...NUM-rust-warnings-to-zero.md => 6837-rust-warnings-to-zero.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{PRNUM-rust-warnings-to-zero.md => 6837-rust-warnings-to-zero.md} (100%) diff --git a/changelog.d/PRNUM-rust-warnings-to-zero.md b/changelog.d/6837-rust-warnings-to-zero.md similarity index 100% rename from changelog.d/PRNUM-rust-warnings-to-zero.md rename to changelog.d/6837-rust-warnings-to-zero.md From b402ec6726b78a596a25626be42b6eea33d6bbd3 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 18:06:00 +0200 Subject: [PATCH 10/18] chore(warnings): fix float_literal_f32_fallback under rustc 1.97.1 CI runs `dtolnay/rust-toolchain@stable`, which is 1.97.1 on the runners; the local default stable here is 1.97.1's predecessor, 1.95.0, which does not have this lint yet. `length(1.0)` in the TUI layout pass inferred `f32` by fallback rather than by the `From` bound, which rustc is phasing out (rust-lang/rust#154024). Spelling the literal `1.0_f32` says what was already meant. It was the only occurrence. All four scopes re-checked under 1.97.1 report zero warnings. --- crates/perry-runtime/src/tui/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/perry-runtime/src/tui/layout.rs b/crates/perry-runtime/src/tui/layout.rs index 0bd1f11f29..c0ef8712e8 100644 --- a/crates/perry-runtime/src/tui/layout.rs +++ b/crates/perry-runtime/src/tui/layout.rs @@ -74,7 +74,7 @@ fn build_taffy_tree( let style = Style { size: Size { width: length(cols), - height: length(1.0), + height: length(1.0_f32), }, ..Default::default() }; From 50c6d4568bab483bfc307fc7c4e0246bd9842366 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 18:19:51 +0200 Subject: [PATCH 11/18] chore(warnings): silence the four warnings that only appear on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macOS host cannot see these; the first CI run on this branch found them. `commands::sandbox_profile` is the #506 MVP, macOS-only by design — its only caller is inside `#[cfg(target_os = "macos")]`, so off macOS all three of its functions are unreachable. The module declaration now carries the same gate as its caller instead of compiling into a build that can never call it. Verified by flipping both cfgs to a target this host is not, and checking: no errors, no warnings. The Linux linker branch in `platform_cmd.rs` binds `let mut c`, but only the `#[cfg(not(target_os = "linux"))]` cross-compile block mutates it, so building on Linux the `mut` is dead. Scoped allow on the binding, which does apply to `unused_mut` — verified by flipping the target and watching the warning disappear. --- crates/perry/src/commands/compile/link/platform_cmd.rs | 3 +++ crates/perry/src/commands/mod.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/crates/perry/src/commands/compile/link/platform_cmd.rs b/crates/perry/src/commands/compile/link/platform_cmd.rs index fc47379d53..1acbdce425 100644 --- a/crates/perry/src/commands/compile/link/platform_cmd.rs +++ b/crates/perry/src/commands/compile/link/platform_cmd.rs @@ -727,6 +727,9 @@ pub fn select_linker_command( // When cross-compiling from macOS, use clang + ld.lld + a glibc // sysroot pointed to by PERRY_LINUX_SYSROOT (matching the // PERRY_IOS_SYSROOT/PERRY_WINDOWS_SYSROOT builder pattern). + // Only the cross-compile block below mutates `c`; building on Linux + // hands back a bare `cc`. + #[cfg_attr(target_os = "linux", allow(unused_mut))] let mut c = Command::new("cc"); #[cfg(not(target_os = "linux"))] { diff --git a/crates/perry/src/commands/mod.rs b/crates/perry/src/commands/mod.rs index fb506401c7..e1c0e75366 100644 --- a/crates/perry/src/commands/mod.rs +++ b/crates/perry/src/commands/mod.rs @@ -31,6 +31,10 @@ pub mod perry_lock; pub(crate) mod progress; pub mod publish; pub mod run; +// #506 MVP is macOS-only (sandbox-exec profiles); the seccomp and AppContainer +// equivalents are follow-ups. Its only caller is `#[cfg(target_os = "macos")]`, +// so off macOS the whole module is dead. +#[cfg(target_os = "macos")] pub mod sandbox_profile; pub mod sanitize; pub mod setup; From b2825cb5fd22e70b6b5862a586edd34b0057432a Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Sat, 25 Jul 2026 21:08:08 +0200 Subject: [PATCH 12/18] fix(runtime): restore `use std::path::Path` on non-unix targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The import block read: #[cfg(unix)] use std::os::unix::fs::{MetadataExt, PermissionsExt}; #[cfg(unix)] use std::os::unix::io::AsRawFd; use std::path::Path; `cargo fix` deleted the unused `AsRawFd` line and left its `#[cfg(unix)]` behind, which then applied to the `Path` import below it. Every unix host still compiled; Windows failed with four `cannot find type Path` errors. Swept the whole diff for the same shape — an attribute that outlived the item it was written for — and this was the only one. The other new cfg/import adjacencies are deliberate. --- crates/perry-runtime/src/fs/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/perry-runtime/src/fs/mod.rs b/crates/perry-runtime/src/fs/mod.rs index cc87e585c4..f149c8e8d1 100644 --- a/crates/perry-runtime/src/fs/mod.rs +++ b/crates/perry-runtime/src/fs/mod.rs @@ -9,7 +9,6 @@ use std::fs; use std::io::{Read, Seek, SeekFrom, Write}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; -#[cfg(unix)] use std::path::Path; use std::sync::atomic::{AtomicI32, Ordering}; From 36a521c4118ba66f413301bc410a1fb0c17bceb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Wed, 29 Jul 2026 22:39:27 +0200 Subject: [PATCH 13/18] fix: address warnings sweep review --- changelog.d/6837-rust-warnings-to-zero.md | 2 +- crates/perry-ui-macos/src/widgets/qrcode.rs | 6 ++---- crates/perry/src/commands/compile/run_pipeline.rs | 8 ++++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/changelog.d/6837-rust-warnings-to-zero.md b/changelog.d/6837-rust-warnings-to-zero.md index fe0b932a45..28a55b853e 100644 --- a/changelog.d/6837-rust-warnings-to-zero.md +++ b/changelog.d/6837-rust-warnings-to-zero.md @@ -27,5 +27,5 @@ Eleven warnings appeared only under the reduced feature set `perry` selects (`default-features = false` on perry-runtime), where regex-engine, diagnostics and temporal are off. Those items are gated at the item, not - suppressed. The cross-host UI crates (ios/tvos/watchos/visionos/android/ + suppressed. The cross-host UI crates (ios/tvos/watchOS/visionos/android/ windows/gtk4) cannot be checked from a macOS or Linux host and are untouched. diff --git a/crates/perry-ui-macos/src/widgets/qrcode.rs b/crates/perry-ui-macos/src/widgets/qrcode.rs index 8df08dc977..5e8a874046 100644 --- a/crates/perry-ui-macos/src/widgets/qrcode.rs +++ b/crates/perry-ui-macos/src/widgets/qrcode.rs @@ -148,10 +148,8 @@ unsafe fn generate_qr_image(text: &str, display_size: f64) -> Option = Retained::retain(ns_image_raw as *mut NSImage)?; - // Balance the retain (init already gives us +1) - std::mem::forget(Retained::retain(ns_image_raw as *mut NSImage)); + // Adopt the +1 result returned by the alloc/init pair. + let ns_image: Retained = Retained::from_raw(ns_image_raw as *mut NSImage)?; Some(ns_image) } diff --git a/crates/perry/src/commands/compile/run_pipeline.rs b/crates/perry/src/commands/compile/run_pipeline.rs index 1a01246d8e..b08f12a3d5 100644 --- a/crates/perry/src/commands/compile/run_pipeline.rs +++ b/crates/perry/src/commands/compile/run_pipeline.rs @@ -7,6 +7,14 @@ use super::*; +#[cfg(any( + not(feature = "backend-wasm"), + not(feature = "backend-swiftui"), + not(feature = "backend-glance"), + not(feature = "backend-wear-tiles") +))] +use super::helpers::backend_disabled_msg; + use anyhow::{anyhow, bail, Context, Result}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fs; From 34a2516a1368e266f0c625ee5e4f5dda45808da0 Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Wed, 29 Jul 2026 23:31:05 +0200 Subject: [PATCH 14/18] fix(warnings): clean regressions after main sync --- crates/perry-codegen/src/codegen/mod.rs | 2 +- crates/perry-codegen/src/codegen/spec_abi.rs | 7 - crates/perry-codegen/src/collectors/mod.rs | 2 +- .../src/collectors/spec_abi_sites.rs | 1 + crates/perry-codegen/src/loop_purity.rs | 4 +- crates/perry-codegen/src/stmt/loops.rs | 1 - crates/perry-runtime/src/array/from_concat.rs | 9 +- crates/perry-runtime/src/array/generic.rs | 24 +- crates/perry-runtime/src/array/header.rs | 21 +- crates/perry-runtime/src/array/indexing.rs | 27 ++- .../perry-runtime/src/array/iter_methods.rs | 12 +- crates/perry-runtime/src/array/push_pop.rs | 6 +- crates/perry-runtime/src/array/sort.rs | 3 +- crates/perry-runtime/src/bigint/convert.rs | 3 +- crates/perry-runtime/src/box.rs | 42 ++-- crates/perry-runtime/src/buffer/access.rs | 5 +- crates/perry-runtime/src/buffer/dataview.rs | 6 +- crates/perry-runtime/src/buffer/encode.rs | 5 +- crates/perry-runtime/src/buffer/query.rs | 3 +- crates/perry-runtime/src/buffer/u8_codec.rs | 20 +- .../perry-runtime/src/builtins/arithmetic.rs | 14 +- .../src/child_process/validate.rs | 6 +- crates/perry-runtime/src/closure/alloc.rs | 6 +- .../src/closure/dispatch/bound.rs | 5 +- crates/perry-runtime/src/closure/registry.rs | 3 +- crates/perry-runtime/src/closure/unbox.rs | 3 +- .../src/collection_iter_object.rs | 18 +- crates/perry-runtime/src/date.rs | 8 +- crates/perry-runtime/src/disposable.rs | 41 ++-- crates/perry-runtime/src/embedded.rs | 12 +- crates/perry-runtime/src/error.rs | 106 ++++----- crates/perry-runtime/src/event_target.rs | 3 +- crates/perry-runtime/src/fs/validate.rs | 5 +- crates/perry-runtime/src/gc/barrier.rs | 8 +- crates/perry-runtime/src/intl.rs | 10 + crates/perry-runtime/src/iterator_helpers.rs | 3 +- crates/perry-runtime/src/json/parse_api.rs | 3 +- crates/perry-runtime/src/json/raw_json.rs | 6 +- crates/perry-runtime/src/map.rs | 52 +++-- crates/perry-runtime/src/module_require.rs | 12 +- crates/perry-runtime/src/native_abi.rs | 36 ++- crates/perry-runtime/src/node_sea.rs | 15 +- .../src/node_stream_keepalive.rs | 212 ++++++++++++------ .../perry-runtime/src/node_submodules/zlib.rs | 15 +- crates/perry-runtime/src/node_v8.rs | 59 +++-- crates/perry-runtime/src/object/alloc.rs | 3 +- .../src/object/class_constructors.rs | 30 ++- .../src/object/class_registry.rs | 4 +- .../src/object/class_registry/class_meta.rs | 1 + .../src/object/class_registry/registration.rs | 14 +- .../perry-runtime/src/object/descriptors.rs | 7 +- .../perry-runtime/src/object/global_this.rs | 15 ++ .../src/object/global_this/builtin_thunks.rs | 3 +- .../src/object/global_this/fetch_globals.rs | 14 +- crates/perry-runtime/src/object/groupby.rs | 6 +- .../native_call_method/common_methods.rs | 1 - .../perry-runtime/src/object/native_module.rs | 3 +- .../src/object/native_module/constants.rs | 33 --- .../src/object/native_this_alias.rs | 6 +- .../src/object/object_ops/has_own.rs | 3 +- .../perry-runtime/src/object/this_binding.rs | 9 +- .../src/object/typed_array_define.rs | 1 - .../src/object/websocket_global.rs | 1 + crates/perry-runtime/src/object/with_env.rs | 6 +- crates/perry-runtime/src/os.rs | 3 +- crates/perry-runtime/src/path.rs | 6 +- crates/perry-runtime/src/process/env_misc.rs | 77 ++++--- crates/perry-runtime/src/process/ipc.rs | 2 + .../perry-runtime/src/promise/async_step.rs | 3 +- .../perry-runtime/src/promise/combinators.rs | 12 +- .../perry-runtime/src/promise/microtasks.rs | 3 +- crates/perry-runtime/src/promise/mod.rs | 27 ++- crates/perry-runtime/src/promise/rejection.rs | 6 +- crates/perry-runtime/src/proxy.rs | 27 ++- crates/perry-runtime/src/proxy/put_value.rs | 3 +- crates/perry-runtime/src/regex/escape.rs | 5 +- crates/perry-runtime/src/set.rs | 80 ++++--- crates/perry-runtime/src/string/locale.rs | 11 +- crates/perry-runtime/src/string/pad.rs | 5 +- crates/perry-runtime/src/string/raw.rs | 5 +- crates/perry-runtime/src/string/slice_ops.rs | 10 +- .../perry-runtime/src/symbol/constructors.rs | 5 +- crates/perry-runtime/src/symbol/iterator.rs | 3 +- crates/perry-runtime/src/text.rs | 17 +- crates/perry-runtime/src/tls.rs | 18 +- crates/perry-runtime/src/typed_feedback.rs | 9 +- .../src/typed_feedback/guards.rs | 27 ++- .../perry-runtime/src/typed_feedback/tests.rs | 10 +- .../perry-runtime/src/typed_feedback/trace.rs | 99 +++++--- crates/perry-runtime/src/typedarray/access.rs | 16 +- crates/perry-runtime/src/typedarray_props.rs | 3 +- crates/perry-runtime/src/url/abort.rs | 11 +- crates/perry-runtime/src/url/node_compat.rs | 17 +- crates/perry-runtime/src/url/search_params.rs | 3 +- crates/perry-runtime/src/validators.rs | 11 +- crates/perry-runtime/src/value/dyn_index.rs | 9 +- .../perry-runtime/src/value/dynamic_arith.rs | 15 +- crates/perry-runtime/src/value/nanbox.rs | 3 +- crates/perry-runtime/src/yoga.rs | 3 +- .../commands/compile/optimized_libs/tests.rs | 1 - crates/perry/src/commands/compile/resolve.rs | 40 ++-- .../src/commands/compile/resolve/tests.rs | 24 ++ 102 files changed, 1060 insertions(+), 593 deletions(-) diff --git a/crates/perry-codegen/src/codegen/mod.rs b/crates/perry-codegen/src/codegen/mod.rs index df68023ec1..c47678909e 100644 --- a/crates/perry-codegen/src/codegen/mod.rs +++ b/crates/perry-codegen/src/codegen/mod.rs @@ -2184,7 +2184,7 @@ pub fn compile_module(hir: &HirModule, opts: CompileOptions) -> Result> let Some(sites) = spec_facts.call_sites.get(&f.id) else { continue; }; - let mut reject = + let reject = |reason: typed_abi::TypedCloneRejectionReason, records: &mut Vec| { record_typed_clone_rejection( diff --git a/crates/perry-codegen/src/codegen/spec_abi.rs b/crates/perry-codegen/src/codegen/spec_abi.rs index 5d630372c8..fa3a724eac 100644 --- a/crates/perry-codegen/src/codegen/spec_abi.rs +++ b/crates/perry-codegen/src/codegen/spec_abi.rs @@ -84,13 +84,6 @@ pub(crate) struct SpecFnPlan { pub dispatch: SpecDispatch, } -impl SpecFnPlan { - /// Phase-2 budget: exactly ONE specialized entry per function (the - /// dominant tuple). Kept as an explicit constant so raising it later is a - /// knob, not a rewrite. - pub(crate) const MAX_ENTRIES_PER_FUNCTION: usize = 1; -} - /// LLVM parameter type for a rep slot. pub(crate) fn spec_rep_llvm_ty(rep: SpecParamRep) -> LlvmType { match rep { diff --git a/crates/perry-codegen/src/collectors/mod.rs b/crates/perry-codegen/src/collectors/mod.rs index ea5139af86..2a865f1982 100644 --- a/crates/perry-codegen/src/collectors/mod.rs +++ b/crates/perry-codegen/src/collectors/mod.rs @@ -77,7 +77,7 @@ pub(crate) use shadow_slots::{ collect_declared_shadow_slots_in_stmts, collect_shadow_slot_clear_points, }; pub(crate) use spec_abi_sites::{ - collect_spec_abi_facts, local_is_reassigned, reassigned_locals, SpecParamRep, SpecTaBinding, + collect_spec_abi_facts, reassigned_locals, SpecParamRep, SpecTaBinding, }; pub(crate) use this_as_value::{ class_chain_extends_builtin_error, class_chain_has_unmodeled_base, class_uses_this_as_value, diff --git a/crates/perry-codegen/src/collectors/spec_abi_sites.rs b/crates/perry-codegen/src/collectors/spec_abi_sites.rs index 5eb506df12..29a073dc60 100644 --- a/crates/perry-codegen/src/collectors/spec_abi_sites.rs +++ b/crates/perry-codegen/src/collectors/spec_abi_sites.rs @@ -126,6 +126,7 @@ pub(crate) fn reassigned_locals(stmts: &[Stmt]) -> HashSet { } /// Single-id convenience over [`reassigned_locals`]. +#[cfg(test)] pub(crate) fn local_is_reassigned(stmts: &[Stmt], id: u32) -> bool { reassigned_locals(stmts).contains(&id) } diff --git a/crates/perry-codegen/src/loop_purity.rs b/crates/perry-codegen/src/loop_purity.rs index aeace93d48..364d34cb3b 100644 --- a/crates/perry-codegen/src/loop_purity.rs +++ b/crates/perry-codegen/src/loop_purity.rs @@ -121,9 +121,7 @@ fn expr_alloc_free(e: &Expr) -> bool { // Element READS never allocate — they return an existing element / a // number. Recurse so the object and index are themselves alloc-free. Expr::IndexGet { object, index } => expr_alloc_free(object) && expr_alloc_free(index), - Expr::BufferIndexGet { buffer, index } => { - expr_alloc_free(buffer) && expr_alloc_free(index) - } + Expr::BufferIndexGet { buffer, index } => expr_alloc_free(buffer) && expr_alloc_free(index), Expr::Uint8ArrayGet { array, index } => expr_alloc_free(array) && expr_alloc_free(index), // `arr[i]++` / `--`: read-modify-write of an existing numeric slot, no // growth, no allocation. diff --git a/crates/perry-codegen/src/stmt/loops.rs b/crates/perry-codegen/src/stmt/loops.rs index 19896e8a63..73cd6f8942 100644 --- a/crates/perry-codegen/src/stmt/loops.rs +++ b/crates/perry-codegen/src/stmt/loops.rs @@ -2875,7 +2875,6 @@ fn lower_object_array_write_versioned_for( extra_guards.push((g_packed, g_box)); } let preheader_idx = ctx.current_block; - let _preheader_label = ctx.block().label.clone(); // Emit the fallback first. Besides preserving the original semantics, this // creates the ordinary local slots for the nested counter, allowing the diff --git a/crates/perry-runtime/src/array/from_concat.rs b/crates/perry-runtime/src/array/from_concat.rs index 58e01268b3..d936f6011d 100644 --- a/crates/perry-runtime/src/array/from_concat.rs +++ b/crates/perry-runtime/src/array/from_concat.rs @@ -140,7 +140,8 @@ pub extern "C" fn js_array_from_value(boxed: f64) -> *mut ArrayHeader { js_array_clone(ptr_bits as *const ArrayHeader) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_FROM_VALUE: extern "C" fn(f64) -> *mut ArrayHeader = js_array_from_value; /// `Array.from(source, mapFn, thisArg)` — the mapped form. Throws for nullish @@ -165,7 +166,8 @@ pub extern "C" fn js_array_from_mapped( as *mut ArrayHeader } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_FROM_MAPPED: extern "C" fn(f64, f64, f64) -> *mut ArrayHeader = js_array_from_mapped; @@ -282,7 +284,8 @@ pub extern "C" fn js_array_concat_variadic( result } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_CONCAT_VARIADIC: extern "C" fn( *const ArrayHeader, *const f64, diff --git a/crates/perry-runtime/src/array/generic.rs b/crates/perry-runtime/src/array/generic.rs index 38957fae5b..1c9aae9614 100644 --- a/crates/perry-runtime/src/array/generic.rs +++ b/crates/perry-runtime/src/array/generic.rs @@ -1120,7 +1120,8 @@ fn clamp_index(v: f64, len: i64) -> i64 { // Keep the generic entry points anchored against dead-strip in the default // (codegen-only reference) compile path (see #3320 — `#[no_mangle]` alone is // not enough once the bitcode is re-linked). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_CB: [extern "C" fn(f64, f64, f64) -> f64; 9] = [ js_arraylike_forEach, js_arraylike_map, @@ -1132,20 +1133,25 @@ static KEEP_ARRAYLIKE_CB: [extern "C" fn(f64, f64, f64) -> f64; 9] = [ js_arraylike_findLast, js_arraylike_findLastIndex, ]; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_REDUCE: [extern "C" fn(f64, f64, i32, f64) -> f64; 2] = [js_arraylike_reduce, js_arraylike_reduceRight]; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_SEARCH: [extern "C" fn(f64, f64, f64, i32) -> f64; 3] = [ js_arraylike_indexOf, js_arraylike_lastIndexOf, js_arraylike_includes, ]; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_AT: extern "C" fn(f64, f64) -> f64 = js_arraylike_at; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_JOIN: extern "C" fn(f64, f64) -> f64 = js_arraylike_join; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_SLICE: extern "C" fn(f64, f64, i32, f64, i32) -> f64 = js_arraylike_slice; // --------------------------------------------------------------------------- @@ -1636,9 +1642,11 @@ pub extern "C" fn js_arraylike_splice(recv: f64, args_ptr: *const f64, count: i3 object_splice(o, args_ptr, count) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_SORT: extern "C" fn(f64, f64) -> f64 = js_arraylike_sort; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAYLIKE_VARIADIC: [extern "C" fn(f64, *const f64, i32) -> f64; 2] = [js_arraylike_concat, js_arraylike_splice]; diff --git a/crates/perry-runtime/src/array/header.rs b/crates/perry-runtime/src/array/header.rs index 41f59801c7..2e6204ebd8 100644 --- a/crates/perry-runtime/src/array/header.rs +++ b/crates/perry-runtime/src/array/header.rs @@ -171,7 +171,8 @@ pub extern "C" fn js_tagged_template_get_or_init( cooked_handle.get_raw_mut_ptr::() } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TAGGED_TEMPLATE_GET_OR_INIT: extern "C" fn( u64, *mut ArrayHeader, @@ -1485,22 +1486,28 @@ pub extern "C" fn js_array_is_numeric_f64_layout(arr: *const ArrayHeader) -> i32 // These raw numeric-array helpers are called from generated code, so release/LTO // builds may otherwise internalize and strip the `#[no_mangle]` exports. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_NUMERIC_VALUE_TO_RAW_F64: extern "C" fn(f64) -> f64 = js_array_numeric_value_to_raw_f64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_MARK_NUMERIC_F64_LAYOUT: extern "C" fn(*mut ArrayHeader) -> i32 = js_array_mark_numeric_f64_layout; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_CLEAR_NUMERIC_LAYOUT: extern "C" fn(*mut ArrayHeader) = js_array_clear_numeric_layout; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_NOTE_NUMERIC_WRITE: extern "C" fn(*mut ArrayHeader, u64) = js_array_note_numeric_write; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_IS_NUMERIC_F64_LAYOUT: extern "C" fn(*const ArrayHeader) -> i32 = js_array_is_numeric_f64_layout; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_REFRESH_LOCAL_HEAD: extern "C" fn(f64) -> f64 = js_array_refresh_local_head; /// Calculate the byte size for an array with N elements capacity diff --git a/crates/perry-runtime/src/array/indexing.rs b/crates/perry-runtime/src/array/indexing.rs index 3c77eeaaba..4265d69a93 100644 --- a/crates/perry-runtime/src/array/indexing.rs +++ b/crates/perry-runtime/src/array/indexing.rs @@ -440,7 +440,8 @@ pub(crate) unsafe fn keys_array_len_capped_to_capacity(arr: *const ArrayHeader) /// native-region wrappers (`__perry_wrap_*`) and elsewhere, so it must be a /// `#[no_mangle]` C export AND survive dead-stripping even when no Rust caller /// keeps it referenced — mirroring the neighbouring `js_array_push`. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_LENGTH: extern "C" fn(*const ArrayHeader) -> u32 = js_array_length; #[no_mangle] @@ -852,10 +853,12 @@ pub extern "C" fn js_array_numeric_set_f64_unboxed( // These raw numeric-array helpers are called from generated code, so release/LTO // builds may otherwise internalize and strip the `#[no_mangle]` exports. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_NUMERIC_GET_F64_UNBOXED: extern "C" fn(*mut ArrayHeader, u32) -> f64 = js_array_numeric_get_f64_unboxed; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_NUMERIC_SET_F64_UNBOXED: extern "C" fn(*mut ArrayHeader, u32, f64) -> i32 = js_array_numeric_set_f64_unboxed; @@ -1450,27 +1453,33 @@ pub extern "C" fn js_array_numeric_range_add_len(receiver: f64, start: f64, delt array_numeric_range_add_impl(receiver, start, None, delta) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_FILL_F64_CONST_EXTEND: extern "C" fn( *mut ArrayHeader, u32, f64, ) -> *mut ArrayHeader = js_array_fill_f64_const_extend; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_FILL_F64_IOTA_EXTEND: extern "C" fn(*mut ArrayHeader, u32) -> *mut ArrayHeader = js_array_fill_f64_iota_extend; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_FILL_F64_CONST_LEN_EXTEND: extern "C" fn( *mut ArrayHeader, f64, ) -> *mut ArrayHeader = js_array_fill_f64_const_len_extend; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_FILL_F64_IOTA_LEN_EXTEND: extern "C" fn(*mut ArrayHeader) -> *mut ArrayHeader = js_array_fill_f64_iota_len_extend; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_NUMERIC_RANGE_ADD: extern "C" fn(f64, f64, f64, f64) -> i64 = js_array_numeric_range_add; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_NUMERIC_RANGE_ADD_LEN: extern "C" fn(f64, f64, f64) -> i64 = js_array_numeric_range_add_len; diff --git a/crates/perry-runtime/src/array/iter_methods.rs b/crates/perry-runtime/src/array/iter_methods.rs index 19ce7ef947..9159279c5e 100644 --- a/crates/perry-runtime/src/array/iter_methods.rs +++ b/crates/perry-runtime/src/array/iter_methods.rs @@ -1044,7 +1044,8 @@ pub extern "C" fn js_array_join_value( // The feature-gated `#[used]` static pins the symbol for the bitcode-LTO // link (`keepalive-anchors`); the classic link keeps it via the program's // own undefined reference. Same pattern as `node_stream_keepalive.rs`. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_JOIN_VALUE: extern "C" fn( *const ArrayHeader, f64, @@ -1109,7 +1110,8 @@ pub extern "C" fn js_array_to_locale_string( crate::string::js_string_from_bytes(out.as_ptr(), out.len() as u32) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ARRAY_TO_LOCALE_STRING: extern "C" fn( *const ArrayHeader, f64, @@ -1232,7 +1234,8 @@ pub extern "C" fn js_validate_array_callback(cb_boxed: f64) -> i64 { throw_not_a_function(render_callback_typeof(cb_boxed)); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_ARRAY_CALLBACK: extern "C" fn(f64) -> i64 = js_validate_array_callback; /// Validate a `map` callback (#4091). Identical to @@ -1253,6 +1256,7 @@ pub extern "C" fn js_validate_array_map_callback(arr: i64, cb_boxed: f64) -> i64 throw_not_a_function(rendered); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_ARRAY_MAP_CALLBACK: extern "C" fn(i64, f64) -> i64 = js_validate_array_map_callback; diff --git a/crates/perry-runtime/src/array/push_pop.rs b/crates/perry-runtime/src/array/push_pop.rs index 6f58ef1d45..158a777d41 100644 --- a/crates/perry-runtime/src/array/push_pop.rs +++ b/crates/perry-runtime/src/array/push_pop.rs @@ -415,7 +415,8 @@ pub extern "C" fn js_array_numeric_push_f64_unboxed( // This raw numeric-array helper is called from generated code, so release/LTO // builds may otherwise internalize and strip the `#[no_mangle]` export. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_NUMERIC_PUSH_F64_UNBOXED: extern "C" fn( *mut ArrayHeader, f64, @@ -820,6 +821,7 @@ pub extern "C" fn js_array_unshift_variadic( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_UNSHIFT_VARIADIC: extern "C" fn(*mut ArrayHeader, *const f64, u32) -> *mut ArrayHeader = js_array_unshift_variadic; diff --git a/crates/perry-runtime/src/array/sort.rs b/crates/perry-runtime/src/array/sort.rs index 8ac2b33ff0..2522e89eee 100644 --- a/crates/perry-runtime/src/array/sort.rs +++ b/crates/perry-runtime/src/array/sort.rs @@ -597,7 +597,8 @@ pub extern "C" fn js_validate_array_comparator(cmp_boxed: f64) -> i64 { throw_invalid_comparator(cmp_boxed); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_ARRAY_COMPARATOR: extern "C" fn(f64) -> i64 = js_validate_array_comparator; #[cold] diff --git a/crates/perry-runtime/src/bigint/convert.rs b/crates/perry-runtime/src/bigint/convert.rs index 69255958c6..582c163d3a 100644 --- a/crates/perry-runtime/src/bigint/convert.rs +++ b/crates/perry-runtime/src/bigint/convert.rs @@ -65,7 +65,8 @@ pub extern "C" fn js_bigint_from_i128_parts(lo: u64, hi: i64) -> *mut BigIntHead bigint_alloc_with_limbs(limbs) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BIGINT_FROM_I128_PARTS: extern "C" fn(u64, i64) -> *mut BigIntHeader = js_bigint_from_i128_parts; diff --git a/crates/perry-runtime/src/box.rs b/crates/perry-runtime/src/box.rs index 37ad6d0e95..0a32d90262 100644 --- a/crates/perry-runtime/src/box.rs +++ b/crates/perry-runtime/src/box.rs @@ -251,9 +251,11 @@ pub extern "C" fn js_tdz_suppress_end() { /// Keepalive anchors for the auto-optimize whole-program build (generated-code- /// only callees — without these the symbols dead-strip and the app link fails). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TDZ_SUPPRESS_BEGIN: extern "C" fn() = js_tdz_suppress_begin; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TDZ_SUPPRESS_END: extern "C" fn() = js_tdz_suppress_end; /// Compatibility wrapper for legacy f64-lowered boxed locals. @@ -483,29 +485,41 @@ fn is_registered_bool_box_ptr(ptr: *mut BoolBox) -> bool { BOOL_BOX_REGISTRY.with(|r| r.borrow().contains(&(ptr as usize))) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOX_ALLOC_BITS: extern "C" fn(i64) -> *mut Box = js_box_alloc_bits; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOX_GET_BITS: extern "C" fn(*mut Box) -> i64 = js_box_get_bits; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOX_SET_BITS: extern "C" fn(*mut Box, i64) = js_box_set_bits; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOX_ALLOC: extern "C" fn(f64) -> *mut Box = js_box_alloc; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOX_GET: extern "C" fn(*mut Box) -> f64 = js_box_get; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOX_SET: extern "C" fn(*mut Box, f64) = js_box_set; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_I32_BOX_ALLOC: extern "C" fn(i32) -> *mut I32Box = js_i32_box_alloc; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_I32_BOX_GET: extern "C" fn(*mut I32Box) -> i32 = js_i32_box_get; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_I32_BOX_SET: extern "C" fn(*mut I32Box, i32) = js_i32_box_set; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOOL_BOX_ALLOC: extern "C" fn(i32) -> *mut BoolBox = js_bool_box_alloc; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOOL_BOX_GET: extern "C" fn(*mut BoolBox) -> i32 = js_bool_box_get; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BOOL_BOX_SET: extern "C" fn(*mut BoolBox, i32) = js_bool_box_set; #[cfg(test)] diff --git a/crates/perry-runtime/src/buffer/access.rs b/crates/perry-runtime/src/buffer/access.rs index 71a0c2e478..37c88146cb 100644 --- a/crates/perry-runtime/src/buffer/access.rs +++ b/crates/perry-runtime/src/buffer/access.rs @@ -226,9 +226,10 @@ pub extern "C" fn js_buffer_index_get_value(buf_ptr: *const BufferHeader, index: // #6088: force-keep the JS-value buffer index getter under LTO / // auto-optimize. It has zero internal Rust callers — codegen emits the only // call (in `perry-codegen/src/expr/index_get.rs`), so a whole-program bitcode -// link is otherwise free to internalize and dead-strip it. The `#[cfg_attr(feature = "keepalive-anchors", used)]` +// link is otherwise free to internalize and dead-strip it. The `#[used]` // anchor pins it (mirrors `KEEP_JS_TYPED_ARRAY_INDEX_GET_DYNAMIC`). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_BUFFER_INDEX_GET_VALUE: extern "C" fn(*const BufferHeader, i32) -> f64 = js_buffer_index_get_value; diff --git a/crates/perry-runtime/src/buffer/dataview.rs b/crates/perry-runtime/src/buffer/dataview.rs index c2687b9e73..3eaa14ce0f 100644 --- a/crates/perry-runtime/src/buffer/dataview.rs +++ b/crates/perry-runtime/src/buffer/dataview.rs @@ -443,10 +443,12 @@ fn data_view_method_name<'a>(buf: &'a mut [u8; 16], prefix: &str, kind: DataView } // Called from generated code — keep the exports alive under release/LTO. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_DATA_VIEW_GET_DIRECT: extern "C" fn(f64, f64, f64, i32, i32) -> f64 = js_data_view_get_direct; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_DATA_VIEW_SET_DIRECT: extern "C" fn(f64, f64, f64, f64, i32, i32) -> f64 = js_data_view_set_direct; diff --git a/crates/perry-runtime/src/buffer/encode.rs b/crates/perry-runtime/src/buffer/encode.rs index e4a3e8eee6..1f088eb4db 100644 --- a/crates/perry-runtime/src/buffer/encode.rs +++ b/crates/perry-runtime/src/buffer/encode.rs @@ -221,9 +221,10 @@ pub extern "C" fn js_value_to_string_with_encoding_or_radix( /// Keepalive anchor: `js_value_to_string_with_encoding_or_radix` is emitted /// only from generated `.o`, so the auto-optimize whole-program LLVM rebuild -/// would internalize + dead-strip it without a `#[cfg_attr(feature = "keepalive-anchors", used)]` reference (see +/// would internalize + dead-strip it without a `#[used]` reference (see /// project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALUE_TO_STRING_ENCODING_OR_RADIX: extern "C" fn(f64, i32, f64) -> *mut StringHeader = js_value_to_string_with_encoding_or_radix; diff --git a/crates/perry-runtime/src/buffer/query.rs b/crates/perry-runtime/src/buffer/query.rs index 13dc043d1d..2c55fce09a 100644 --- a/crates/perry-runtime/src/buffer/query.rs +++ b/crates/perry-runtime/src/buffer/query.rs @@ -62,7 +62,8 @@ pub unsafe extern "C" fn js_value_buffer_or_typedarray_data( // Referenced only from the prebuilt `perry-ext-http-server` archive, so the // auto-optimize LTO pass would otherwise dead-strip it. Pin it. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_VALUE_BUFFER_OR_TYPEDARRAY_DATA: unsafe extern "C" fn(f64, *mut u32) -> *const u8 = js_value_buffer_or_typedarray_data; diff --git a/crates/perry-runtime/src/buffer/u8_codec.rs b/crates/perry-runtime/src/buffer/u8_codec.rs index 47e80652df..5d25bd9d7e 100644 --- a/crates/perry-runtime/src/buffer/u8_codec.rs +++ b/crates/perry-runtime/src/buffer/u8_codec.rs @@ -560,17 +560,23 @@ pub extern "C" fn js_u8_set_from_hex(addr: i64, str_handle: i64) -> f64 { // Keepalive anchors: these `#[no_mangle]` symbols are only referenced from // generated `.o` files, so the auto-optimize whole-program-LLVM bitcode -// rebuild would dead-strip them without an `#[cfg_attr(feature = "keepalive-anchors", used)]` reference. See +// rebuild would dead-strip them without an `#[used]` reference. See // project_auto_optimize_keepalive_3320. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_U8_TO_BASE64: extern "C" fn(i64, f64) -> *mut StringHeader = js_u8_to_base64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_U8_TO_HEX: extern "C" fn(i64) -> *mut StringHeader = js_u8_to_hex; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_U8_FROM_BASE64: extern "C" fn(i64, f64) -> *mut BufferHeader = js_u8_from_base64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_U8_FROM_HEX: extern "C" fn(i64) -> *mut BufferHeader = js_u8_from_hex; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_U8_SET_FROM_BASE64: extern "C" fn(i64, i64, f64) -> f64 = js_u8_set_from_base64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_U8_SET_FROM_HEX: extern "C" fn(i64, i64) -> f64 = js_u8_set_from_hex; diff --git a/crates/perry-runtime/src/builtins/arithmetic.rs b/crates/perry-runtime/src/builtins/arithmetic.rs index aaf6103d76..1e773466c5 100644 --- a/crates/perry-runtime/src/builtins/arithmetic.rs +++ b/crates/perry-runtime/src/builtins/arithmetic.rs @@ -460,15 +460,19 @@ pub extern "C" fn js_rel_ge(x: f64, y: f64) -> f64 { // The `js_rel_*` helpers are reached only from Perry-emitted LLVM (the relational // fallthrough in codegen), so a bitcode/auto-optimize link can dead-strip them -// and leave `undefined _js_rel_lt …`. Pin them with `#[cfg_attr(feature = "keepalive-anchors", used)]` statics — same +// and leave `undefined _js_rel_lt …`. Pin them with `#[used]` statics — same // pattern as the write-barrier roots in `gc/barrier.rs`. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REL_LT: extern "C" fn(f64, f64) -> f64 = js_rel_lt; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REL_GT: extern "C" fn(f64, f64) -> f64 = js_rel_gt; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REL_LE: extern "C" fn(f64, f64) -> f64 = js_rel_le; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REL_GE: extern "C" fn(f64, f64) -> f64 = js_rel_ge; #[no_mangle] diff --git a/crates/perry-runtime/src/child_process/validate.rs b/crates/perry-runtime/src/child_process/validate.rs index 4c21286860..eb39dd5aaf 100644 --- a/crates/perry-runtime/src/child_process/validate.rs +++ b/crates/perry-runtime/src/child_process/validate.rs @@ -94,8 +94,10 @@ pub extern "C" fn js_child_process_validate_args(value: f64) -> f64 { /// referenced only from generated `.o`, so the bitcode internalizer would /// otherwise drop them there; the classic link keeps them via the program's /// own undefined references and builds without the anchors. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CP_VALIDATE_COMMAND: unsafe extern "C" fn(f64, *const u8, u32) -> f64 = js_child_process_validate_command; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CP_VALIDATE_ARGS: extern "C" fn(f64) -> f64 = js_child_process_validate_args; diff --git a/crates/perry-runtime/src/closure/alloc.rs b/crates/perry-runtime/src/closure/alloc.rs index 6814d72b0f..591793a165 100644 --- a/crates/perry-runtime/src/closure/alloc.rs +++ b/crates/perry-runtime/src/closure/alloc.rs @@ -490,9 +490,11 @@ pub extern "C" fn js_closure_set_capture_ptr(closure: *mut ClosureHeader, index: js_closure_set_capture_bits(closure, index, value as u64); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CLOSURE_GET_CAPTURE_BITS: extern "C" fn(*const ClosureHeader, u32) -> u64 = js_closure_get_capture_bits; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CLOSURE_SET_CAPTURE_BITS: extern "C" fn(*mut ClosureHeader, u32, u64) = js_closure_set_capture_bits; diff --git a/crates/perry-runtime/src/closure/dispatch/bound.rs b/crates/perry-runtime/src/closure/dispatch/bound.rs index 7dab12c3a8..69664b7c2c 100644 --- a/crates/perry-runtime/src/closure/dispatch/bound.rs +++ b/crates/perry-runtime/src/closure/dispatch/bound.rs @@ -485,9 +485,10 @@ pub unsafe extern "C" fn js_function_bind( /// Keepalive anchor for the `js_function_bind` symbol. The auto-optimize /// whole-program LLVM rebuild dead-strips `#[no_mangle]` fns that are only -/// referenced from generated `.o` / other crates; this `#[cfg_attr(feature = "keepalive-anchors", used)]` static +/// referenced from generated `.o` / other crates; this `#[used]` static /// survives the bitcode pipeline. See project_auto_optimize_keepalive_3320. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_FUNCTION_BIND: unsafe extern "C" fn(f64, *const f64, usize) -> f64 = js_function_bind; diff --git a/crates/perry-runtime/src/closure/registry.rs b/crates/perry-runtime/src/closure/registry.rs index d745d35a35..e9d74f9123 100644 --- a/crates/perry-runtime/src/closure/registry.rs +++ b/crates/perry-runtime/src/closure/registry.rs @@ -380,7 +380,8 @@ pub extern "C" fn js_register_closure_strict_function(func_ptr: *const u8) { /// Keepalive anchor for the auto-optimize whole-program build — the strict /// registration is emitted only from generated module-init code. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_REGISTER_CLOSURE_STRICT_FUNCTION: extern "C" fn(*const u8) = js_register_closure_strict_function; diff --git a/crates/perry-runtime/src/closure/unbox.rs b/crates/perry-runtime/src/closure/unbox.rs index ff20a75fa1..c365a0be1e 100644 --- a/crates/perry-runtime/src/closure/unbox.rs +++ b/crates/perry-runtime/src/closure/unbox.rs @@ -58,6 +58,7 @@ pub extern "C" fn js_closure_unbox_callee_checked_rebind(callee: f64, receiver: } /// Keepalive: generated code is the only caller (#6475). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CLOSURE_UNBOX_CALLEE_CHECKED_REBIND: extern "C" fn(f64, f64) -> i64 = js_closure_unbox_callee_checked_rebind; diff --git a/crates/perry-runtime/src/collection_iter_object.rs b/crates/perry-runtime/src/collection_iter_object.rs index fd1e658ac4..b8d1fb295d 100644 --- a/crates/perry-runtime/src/collection_iter_object.rs +++ b/crates/perry-runtime/src/collection_iter_object.rs @@ -138,17 +138,23 @@ pub extern "C" fn js_set_entries_iter_obj(set: *const SetHeader) -> i64 { // Rust callers. The whole-program auto-optimize bitcode link would // otherwise internalize + dead-strip the `#[no_mangle]` exports and break // the default compile path (see project_auto_optimize_keepalive). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_MAP_ENTRIES_ITER: extern "C" fn(*const MapHeader) -> i64 = js_map_entries_iter_obj; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_MAP_KEYS_ITER: extern "C" fn(*const MapHeader) -> i64 = js_map_keys_iter_obj; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_MAP_VALUES_ITER: extern "C" fn(*const MapHeader) -> i64 = js_map_values_iter_obj; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_VALUES_ITER: extern "C" fn(*const SetHeader) -> i64 = js_set_values_iter_obj; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_KEYS_ITER: extern "C" fn(*const SetHeader) -> i64 = js_set_keys_iter_obj; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_ENTRIES_ITER: extern "C" fn(*const SetHeader) -> i64 = js_set_entries_iter_obj; /// Build the `{ value, done }` iterator-result object. Mirrors diff --git a/crates/perry-runtime/src/date.rs b/crates/perry-runtime/src/date.rs index a9cd0d9e98..81f9c11491 100644 --- a/crates/perry-runtime/src/date.rs +++ b/crates/perry-runtime/src/date.rs @@ -790,8 +790,9 @@ pub extern "C" fn js_date_utc(args_ptr: *const f64, argc: i32) -> f64 { /// Keepalive anchor for `js_date_utc` — codegen-only `#[no_mangle]` symbols /// get dead-stripped by the auto-optimize whole-program LLVM bitcode rebuild -/// without a `#[cfg_attr(feature = "keepalive-anchors", used)]` reference (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +/// without a `#[used]` reference (see project_auto_optimize_keepalive_3320). +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_DATE_UTC: extern "C" fn(*const f64, i32) -> f64 = js_date_utc; /// Coerce a NaN-boxed JS value to a number (ECMAScript ToNumber, restricted @@ -1001,7 +1002,8 @@ pub extern "C" fn js_date_apply_setter( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_DATE_APPLY_SETTER: extern "C" fn(f64, i32, i32, *const f64, i32) -> f64 = js_date_apply_setter; diff --git a/crates/perry-runtime/src/disposable.rs b/crates/perry-runtime/src/disposable.rs index e7907dc3a6..effbfb4e72 100644 --- a/crates/perry-runtime/src/disposable.rs +++ b/crates/perry-runtime/src/disposable.rs @@ -498,44 +498,57 @@ pub extern "C" fn js_suppressed_error_new(error: f64, suppressed: f64, message: // Keepalive anchors — these `#[no_mangle]` fns are only ever called from // generated code (the codegen `new` arm + the native-module dispatch table), // so the whole-program-LLVM auto-optimize bitcode rebuild would otherwise -// dead-strip them (see project_auto_optimize_keepalive_3320). `#[cfg_attr(feature = "keepalive-anchors", used)]` +// dead-strip them (see project_auto_optimize_keepalive_3320). `#[used]` // survives the bitcode pipeline. // --------------------------------------------------------------------------- -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_NEW: extern "C" fn() -> *mut ObjectHeader = js_disposable_stack_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ASYNC_DISPOSABLE_STACK_NEW: extern "C" fn() -> *mut ObjectHeader = js_async_disposable_stack_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_DISPOSED: extern "C" fn(*mut ObjectHeader) -> f64 = js_disposable_stack_disposed; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_DEFER: extern "C" fn(*mut ObjectHeader, f64) -> f64 = js_disposable_stack_defer; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_USE: extern "C" fn(*mut ObjectHeader, f64) -> f64 = js_disposable_stack_use; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ASYNC_DISPOSABLE_STACK_USE: extern "C" fn(*mut ObjectHeader, f64) -> f64 = js_async_disposable_stack_use; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_ADOPT: extern "C" fn(*mut ObjectHeader, f64, f64) -> f64 = js_disposable_stack_adopt; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_DISPOSE: extern "C" fn(*mut ObjectHeader) -> f64 = js_disposable_stack_dispose; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_SYMBOL_DISPOSE: extern "C" fn(*mut ObjectHeader) -> f64 = js_disposable_stack_symbol_dispose; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DISPOSABLE_STACK_MOVE: extern "C" fn(*mut ObjectHeader) -> f64 = js_disposable_stack_move; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ASYNC_DISPOSABLE_STACK_DISPOSE_ASYNC: extern "C" fn(*mut ObjectHeader) -> f64 = js_async_disposable_stack_dispose_async; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ASYNC_DISPOSABLE_STACK_SYMBOL_ASYNC_DISPOSE: extern "C" fn(*mut ObjectHeader) -> f64 = js_async_disposable_stack_symbol_async_dispose; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SUPPRESSED_ERROR_NEW: extern "C" fn(f64, f64, f64) -> f64 = js_suppressed_error_new; diff --git a/crates/perry-runtime/src/embedded.rs b/crates/perry-runtime/src/embedded.rs index 4493904869..7dcc6dad38 100644 --- a/crates/perry-runtime/src/embedded.rs +++ b/crates/perry-runtime/src/embedded.rs @@ -265,16 +265,20 @@ pub extern "C" fn js_perry_read_embedded(path_value: f64) -> *mut crate::buffer: // Keep the FFI symbols external under the thin-LTO + `strip=true` release // profile. A `#[no_mangle] pub extern "C"` alone is internalized and -// dead-stripped; only individual `#[cfg_attr(feature = "keepalive-anchors", used)]` typed fn-pointer statics survive +// dead-stripped; only individual `#[used]` typed fn-pointer statics survive // (see the note in `typed_feedback/trace.rs`). `js_register_embedded_asset` is // called only from the generated C constructor, and `js_perry_read_embedded` // only from codegen-emitted callsites — both are invisible to Rust's reachability. #[rustfmt::skip] +#[cfg(feature = "keepalive-anchors")] mod keep_embedded { use super::*; - #[cfg_attr(feature = "keepalive-anchors", used)] static K0: unsafe extern "C" fn(*const u8, usize, *const u8, usize) = js_register_embedded_asset; - #[cfg_attr(feature = "keepalive-anchors", used)] static K1: extern "C" fn(f64) -> *mut crate::buffer::BufferHeader = js_perry_read_embedded; - #[cfg_attr(feature = "keepalive-anchors", used)] static K2: extern "C" fn() -> *mut crate::array::ArrayHeader = js_perry_embedded_files; + #[cfg(feature = "keepalive-anchors")] +#[used] static K0: unsafe extern "C" fn(*const u8, usize, *const u8, usize) = js_register_embedded_asset; + #[cfg(feature = "keepalive-anchors")] +#[used] static K1: extern "C" fn(f64) -> *mut crate::buffer::BufferHeader = js_perry_read_embedded; + #[cfg(feature = "keepalive-anchors")] +#[used] static K2: extern "C" fn() -> *mut crate::array::ArrayHeader = js_perry_embedded_files; } #[cfg(test)] diff --git a/crates/perry-runtime/src/error.rs b/crates/perry-runtime/src/error.rs index f3eb6667ac..2b3a88bec2 100644 --- a/crates/perry-runtime/src/error.rs +++ b/crates/perry-runtime/src/error.rs @@ -121,7 +121,8 @@ pub unsafe extern "C" fn js_set_call_location(file_ptr: *const u8, file_len: usi // Generated-code-only callee: anchor against the auto-optimize LTO dead-strip // (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_CALL_LOCATION: unsafe extern "C" fn(*const u8, usize, u32) = js_set_call_location; @@ -436,8 +437,9 @@ pub unsafe extern "C" fn js_node_system_error_value( // These FFI entries are referenced only from extension archives (linked after // the runtime's bitcode is optimized), so the auto-optimize LTO pass would // otherwise dead-strip them (see project_auto_optimize_keepalive_3320). The -// `#[cfg_attr(feature = "keepalive-anchors", used)]` anchors pin them. -#[cfg_attr(feature = "keepalive-anchors", used)] +// `#[used]` anchors pin them. +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ERROR_VALUE_WITH_CODE: unsafe extern "C" fn( *const u8, usize, @@ -446,7 +448,8 @@ static KEEP_JS_ERROR_VALUE_WITH_CODE: unsafe extern "C" fn( i32, ) -> f64 = js_error_value_with_code; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_NODE_SYSTEM_ERROR_VALUE: unsafe extern "C" fn( *const u8, usize, @@ -457,7 +460,8 @@ static KEEP_JS_NODE_SYSTEM_ERROR_VALUE: unsafe extern "C" fn( f64, ) -> f64 = js_node_system_error_value; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_THROW_ERROR_WITH_CODE: unsafe extern "C" fn( *const u8, usize, @@ -855,7 +859,8 @@ pub extern "C" fn js_throw_eval_syntax_error(message: f64) -> f64 { } // #1561-style force-keep: only generated IR calls this. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_THROW_EVAL_SYNTAX_ERROR: extern "C" fn(f64) -> f64 = js_throw_eval_syntax_error; #[no_mangle] @@ -867,7 +872,8 @@ pub extern "C" fn js_throw_restricted_function_property_assignment() -> f64 { } // #1561-style force-keep: only generated IR calls this. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_THROW_RESTRICTED_FN_PROP_ASSIGN: extern "C" fn() -> f64 = js_throw_restricted_function_property_assignment; @@ -955,7 +961,8 @@ pub extern "C" fn js_throw_reference_error_tdz(name: f64) -> f64 { /// Keepalive anchor for the auto-optimize whole-program build (generated-code- /// and runtime-only callee). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_THROW_REFERENCE_ERROR_TDZ: extern "C" fn(f64) -> f64 = js_throw_reference_error_tdz; #[no_mangle] @@ -965,7 +972,8 @@ pub extern "C" fn js_throw_reference_error_unresolved_get() -> f64 { /// Keepalive anchor for the auto-optimize whole-program build (generated-code ///-only callee; see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_GLOBAL_GET_OR_THROW_UNRESOLVED: extern "C" fn(f64) -> f64 = js_global_get_or_throw_unresolved; @@ -1018,10 +1026,12 @@ pub extern "C" fn js_global_get_or_throw_unresolved(name_value: f64) -> f64 { /// Keepalive anchor for the auto-optimize whole-program build (generated-code ///-only callee; see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_GLOBAL_GET_OPTIONAL: extern "C" fn(f64) -> f64 = js_global_get_optional; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_GLOBAL_UPDATE: extern "C" fn(f64, f64, f64) -> f64 = js_global_update; /// `++x` / `x++` / `--x` / `x--` where `x` resolves to no lexical binding — @@ -1054,21 +1064,17 @@ pub extern "C" fn js_global_update(name_value: f64, is_increment: f64, is_prefix let g = f64::from_bits(g_handle.get_heap_word_u64()); let gptr = (g.to_bits() & crate::value::POINTER_MASK) as *const crate::object::ObjectHeader; if !gptr.is_null() { - let v = unsafe { - crate::object::js_object_get_field_by_name( - gptr, - key_handle.get_raw_const_ptr::(), - ) - }; + let v = crate::object::js_object_get_field_by_name( + gptr, + key_handle.get_raw_const_ptr::(), + ); if !v.is_undefined() - || unsafe { - crate::object::js_object_has_own( - f64::from_bits(g_handle.get_heap_word_u64()), - name_value, - ) - .to_bits() - == crate::value::TAG_TRUE - } + || crate::object::js_object_has_own( + f64::from_bits(g_handle.get_heap_word_u64()), + name_value, + ) + .to_bits() + == crate::value::TAG_TRUE { present = true; } @@ -1094,13 +1100,11 @@ pub extern "C" fn js_global_update(name_value: f64, is_increment: f64, is_prefix let stepped_handle = scope.root_nanbox_f64(stepped); let g = f64::from_bits(g_handle.get_heap_word_u64()); let gptr = (g.to_bits() & crate::value::POINTER_MASK) as *mut crate::object::ObjectHeader; - unsafe { - crate::object::js_object_set_field_by_name( - gptr, - key_handle.get_raw_const_ptr::(), - stepped_handle.get_nanbox_f64(), - ) - }; + crate::object::js_object_set_field_by_name( + gptr, + key_handle.get_raw_const_ptr::(), + stepped_handle.get_nanbox_f64(), + ); let numeric = numeric_handle.get_nanbox_f64(); let stepped = stepped_handle.get_nanbox_f64(); if is_prefix { @@ -1112,7 +1116,8 @@ pub extern "C" fn js_global_update(name_value: f64, is_increment: f64, is_prefix /// Keepalive anchor for the auto-optimize whole-program build (generated-code ///-only callee; see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_GLOBAL_ASSIGN_EXISTING_OR_THROW: extern "C" fn(f64, f64) -> f64 = js_global_assign_existing_or_throw; @@ -1150,21 +1155,17 @@ pub extern "C" fn js_global_assign_existing_or_throw(name_value: f64, value: f64 let g = f64::from_bits(g_handle.get_heap_word_u64()); let gptr = (g.to_bits() & crate::value::POINTER_MASK) as *const crate::object::ObjectHeader; if !gptr.is_null() { - let v = unsafe { - crate::object::js_object_get_field_by_name( - gptr, - key_handle.get_raw_const_ptr::(), - ) - }; + let v = crate::object::js_object_get_field_by_name( + gptr, + key_handle.get_raw_const_ptr::(), + ); if !v.is_undefined() - || unsafe { - crate::object::js_object_has_own( - f64::from_bits(g_handle.get_heap_word_u64()), - name_value, - ) - .to_bits() - == crate::value::TAG_TRUE - } + || crate::object::js_object_has_own( + f64::from_bits(g_handle.get_heap_word_u64()), + name_value, + ) + .to_bits() + == crate::value::TAG_TRUE { present = true; } @@ -1744,22 +1745,25 @@ pub(crate) fn throw_immutable_write(kind: u32, key: &str) -> ! { // #2836/#2838/#2904: keep the codegen-emitted error FFIs alive through the // auto-optimize whole-program-bitcode link. These `#[no_mangle]` fns are -// reachable only from generated `.o`; without `#[cfg_attr(feature = "keepalive-anchors", used)]` anchors the +// reachable only from generated `.o`; without `#[used]` anchors the // internalize+dead-strip pass drops them and the default `perry file.ts -o` // link fails (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ERROR_NEW_KIND_WITH_OPTIONS: extern "C" fn( u32, *mut StringHeader, f64, ) -> *mut ErrorHeader = js_error_new_kind_with_options; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_AGGREGATEERROR_NEW_FULL: extern "C" fn( f64, *mut StringHeader, f64, ) -> *mut ErrorHeader = js_aggregateerror_new_full; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ERROR_IS_ERROR: extern "C" fn(f64) -> f64 = js_error_is_error; #[cfg(test)] diff --git a/crates/perry-runtime/src/event_target.rs b/crates/perry-runtime/src/event_target.rs index edec9ad215..e6b360cb70 100644 --- a/crates/perry-runtime/src/event_target.rs +++ b/crates/perry-runtime/src/event_target.rs @@ -322,7 +322,8 @@ pub extern "C" fn js_event_subclass_init( /// Keepalive anchor for the auto-optimize whole-program build — /// `js_event_subclass_init` is a generated-code-only callee. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_EVENT_SUBCLASS_INIT: extern "C" fn(f64, f64, f64, u32, u32) -> f64 = js_event_subclass_init; diff --git a/crates/perry-runtime/src/fs/validate.rs b/crates/perry-runtime/src/fs/validate.rs index fb8100c79c..02a73ecccf 100644 --- a/crates/perry-runtime/src/fs/validate.rs +++ b/crates/perry-runtime/src/fs/validate.rs @@ -369,12 +369,13 @@ pub unsafe extern "C" fn js_validate_event_listener( throw_type_error_with_code(&message, "ERR_INVALID_ARG_TYPE"); } -/// `#[cfg_attr(feature = "keepalive-anchors", used)]` keepalive so the auto-optimize whole-program-LLVM rebuild does +/// `#[used]` keepalive so the auto-optimize whole-program-LLVM rebuild does /// not dead-strip this codegen-invoked `#[no_mangle]` entry point (see /// project_auto_optimize_keepalive_3320). Called only from generated `.o` /// via the stdlib/ext events validators, so without an anchor the bitcode /// internalizer drops it and the default `perry file.ts -o out` link fails. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_VALIDATE_EVENT_LISTENER: unsafe extern "C" fn(i64, *const u8, u32) -> i64 = js_validate_event_listener; diff --git a/crates/perry-runtime/src/gc/barrier.rs b/crates/perry-runtime/src/gc/barrier.rs index 59e10a71b9..7ce665cb42 100644 --- a/crates/perry-runtime/src/gc/barrier.rs +++ b/crates/perry-runtime/src/gc/barrier.rs @@ -1406,11 +1406,13 @@ pub extern "C" fn js_write_barrier_root_nanbox(value_bits: u64) { // the runtime through whole-program LLVM bitcode and is free to internalize and // dead-strip an unreferenced `#[no_mangle]` symbol — which broke the default // `perry file.ts -o out` link with `undefined _js_write_barrier_root_*`. The -// `#[cfg_attr(feature = "keepalive-anchors", used)]` statics pin retained reference edges so both survive every link mode. +// `#[used]` statics pin retained reference edges so both survive every link mode. // Same pattern as `node_stream_keepalive.rs` / `typedarray.rs`. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_WRITE_BARRIER_ROOT_HEAP_WORD: extern "C" fn(u64) = js_write_barrier_root_heap_word; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_WRITE_BARRIER_ROOT_NANBOX: extern "C" fn(u64) = js_write_barrier_root_nanbox; #[inline] diff --git a/crates/perry-runtime/src/intl.rs b/crates/perry-runtime/src/intl.rs index b88435de5d..6107b0e697 100644 --- a/crates/perry-runtime/src/intl.rs +++ b/crates/perry-runtime/src/intl.rs @@ -5,6 +5,16 @@ //! DateTimeFormat, and Collator, with deterministic formatting for the common //! explicit locale/options combinations used by Perry's Node parity suite. +#![cfg_attr( + not(any( + feature = "intl-namespace", + feature = "intl-locale", + feature = "intl-datetime", + feature = "intl-segmenter" + )), + allow(dead_code, unused_imports) +)] + use crate::array::{js_array_alloc, js_array_get_f64, js_array_length, js_array_push_f64}; use crate::closure::ClosureHeader; use crate::object::{ diff --git a/crates/perry-runtime/src/iterator_helpers.rs b/crates/perry-runtime/src/iterator_helpers.rs index 027df66f44..fbf842a536 100644 --- a/crates/perry-runtime/src/iterator_helpers.rs +++ b/crates/perry-runtime/src/iterator_helpers.rs @@ -179,7 +179,8 @@ pub extern "C" fn js_iterator_from(val_f64: f64) -> f64 { } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ITERATOR_FROM: extern "C" fn(f64) -> f64 = js_iterator_from; /// `.next()` on a helper iterator object. Pulls lazily from the source per the diff --git a/crates/perry-runtime/src/json/parse_api.rs b/crates/perry-runtime/src/json/parse_api.rs index 9da7761e20..5600afc6cd 100644 --- a/crates/perry-runtime/src/json/parse_api.rs +++ b/crates/perry-runtime/src/json/parse_api.rs @@ -22,7 +22,8 @@ pub extern "C" fn js_json_text_to_string(value: f64) -> *mut StringHeader { // Anchor so the auto-optimize bitcode rebuild doesn't dead-strip this // codegen-only `#[no_mangle]` (see KEEP_RAW_JSON in json/raw_json.rs). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JSON_TEXT_TO_STRING: extern "C" fn(f64) -> *mut StringHeader = js_json_text_to_string; // ─── JSON.parse ─────────────────────────────────────────────────────────────── diff --git a/crates/perry-runtime/src/json/raw_json.rs b/crates/perry-runtime/src/json/raw_json.rs index 7ac7558c75..4c52e8c0ea 100644 --- a/crates/perry-runtime/src/json/raw_json.rs +++ b/crates/perry-runtime/src/json/raw_json.rs @@ -169,7 +169,9 @@ fn throw_raw_json_syntax_error() -> ! { // Keepalive anchors: these `#[no_mangle]` entry points are called only from // generated `.o`; the auto-optimize whole-program bitcode rebuild would // otherwise dead-strip them (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_RAW_JSON: unsafe extern "C" fn(f64) -> f64 = js_json_raw_json; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_IS_RAW_JSON: unsafe extern "C" fn(f64) -> f64 = js_json_is_raw_json; diff --git a/crates/perry-runtime/src/map.rs b/crates/perry-runtime/src/map.rs index dde9f27660..9379a702bb 100644 --- a/crates/perry-runtime/src/map.rs +++ b/crates/perry-runtime/src/map.rs @@ -1013,7 +1013,7 @@ const SIDE_TABLE_THRESHOLD: u32 = 8; /// C-ABI: current entries-array index of `key` (SameValueZero), or `-1.0` if /// absent. Used by the delete-safe `for-of` fast path (#6075) to re-derive the /// cursor after a mid-iteration delete compacts the entries array. Only invoked -/// from generated IR, so `#[cfg_attr(feature = "keepalive-anchors", used)]` keeps it linked on the default compile path. +/// from generated IR, so `#[used]` keeps it linked on the default compile path. #[no_mangle] pub extern "C" fn js_map_find_key_index(map_boxed: f64, key: f64) -> f64 { let map = clean_map_ptr(crate::value::js_nanbox_get_pointer(map_boxed) as *const MapHeader); @@ -1022,7 +1022,8 @@ pub extern "C" fn js_map_find_key_index(map_boxed: f64, key: f64) -> f64 { } unsafe { find_key_index(map, normalize_zero(key)) as f64 } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_MAP_FIND_KEY_INDEX: extern "C" fn(f64, f64) -> f64 = js_map_find_key_index; pub(crate) unsafe fn find_key_index(map: *const MapHeader, key: f64) -> i32 { @@ -1616,67 +1617,81 @@ pub extern "C" fn js_map_delete_number_key(map: *mut MapHeader, key: f64) -> i32 // Codegen emits these string-key typed lowering helpers directly from // generated LLVM IR. Keep roots prevent whole-program LTO/dead-strip from // removing the exported symbols when the Rust crate graph has no caller. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_NUMBER: extern "C" fn( *mut MapHeader, *const StringHeader, f64, ) -> *mut MapHeader = js_map_set_string_number; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_NUMBER_KEY: extern "C" fn(*mut MapHeader, f64, f64) -> *mut MapHeader = js_map_set_number_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_KEY: extern "C" fn( *mut MapHeader, *const StringHeader, f64, ) -> *mut MapHeader = js_map_set_string_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_I32: extern "C" fn( *mut MapHeader, *const StringHeader, i32, ) -> *mut MapHeader = js_map_set_string_i32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_U32: extern "C" fn( *mut MapHeader, *const StringHeader, u32, ) -> *mut MapHeader = js_map_set_string_u32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_F32: extern "C" fn( *mut MapHeader, *const StringHeader, f32, ) -> *mut MapHeader = js_map_set_string_f32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_BOOL: extern "C" fn( *mut MapHeader, *const StringHeader, i32, ) -> *mut MapHeader = js_map_set_string_bool; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_SET_STRING_STRING: extern "C" fn( *mut MapHeader, *const StringHeader, *const StringHeader, ) -> *mut MapHeader = js_map_set_string_string; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_GET_STRING_KEY: extern "C" fn(*const MapHeader, *const StringHeader) -> f64 = js_map_get_string_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_GET_NUMBER_KEY: extern "C" fn(*const MapHeader, f64) -> f64 = js_map_get_number_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_HAS_STRING_KEY: extern "C" fn(*const MapHeader, *const StringHeader) -> i32 = js_map_has_string_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_HAS_NUMBER_KEY: extern "C" fn(*const MapHeader, f64) -> i32 = js_map_has_number_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_DELETE_STRING_KEY: extern "C" fn(*mut MapHeader, *const StringHeader) -> i32 = js_map_delete_string_key; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_DELETE_NUMBER_KEY: extern "C" fn(*mut MapHeader, f64) -> i32 = js_map_delete_number_key; @@ -2232,8 +2247,9 @@ pub extern "C" fn js_map_from_iterable(value: f64) -> *mut MapHeader { // `perry-codegen/src/expr/misc_methods.rs`), so it has zero internal Rust // callers. The whole-program auto-optimize bitcode link would otherwise // internalize + dead-strip the `#[no_mangle]` export and break the default -// compile path. The `#[cfg_attr(feature = "keepalive-anchors", used)]` anchor pins it (see project_auto_optimize_keepalive). -#[cfg_attr(feature = "keepalive-anchors", used)] +// compile path. The `#[used]` anchor pins it (see project_auto_optimize_keepalive). +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MAP_FROM_ITERABLE: extern "C" fn(f64) -> *mut MapHeader = js_map_from_iterable; /// `Map.prototype.forEach(callback, thisArg)` — calls `callback` with the diff --git a/crates/perry-runtime/src/module_require.rs b/crates/perry-runtime/src/module_require.rs index d4ec3a9321..0f5609d24f 100644 --- a/crates/perry-runtime/src/module_require.rs +++ b/crates/perry-runtime/src/module_require.rs @@ -492,7 +492,8 @@ pub extern "C" fn js_module_ambient_require() -> f64 { /// Keepalive anchor for the auto-optimize whole-program build (generated-code-only /// callee; see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_AMBIENT_REQUIRE: extern "C" fn() -> f64 = js_module_ambient_require; /// Synchronous ambient `require(spec)` resolution for the #5389 Tier 2 codegen @@ -510,7 +511,8 @@ pub extern "C" fn js_module_ambient_require_apply(spec: f64) -> f64 { /// Keepalive anchor for the auto-optimize whole-program build (generated-code-only /// callee; see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_AMBIENT_REQUIRE_APPLY: extern "C" fn(f64) -> f64 = js_module_ambient_require_apply; @@ -571,7 +573,8 @@ pub extern "C" fn js_module_dynamic_import_fallback(spec: f64) -> f64 { } /// Keepalive anchor (same pattern as the ambient-require anchors above). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_DYNAMIC_IMPORT_FALLBACK: extern "C" fn(f64) -> f64 = js_module_dynamic_import_fallback; @@ -592,7 +595,8 @@ pub extern "C" fn js_module_dynamic_import_deferred(spec: f64, msg: f64) -> f64 } /// Keepalive anchor (same pattern as the ambient-require anchors above). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_DYNAMIC_IMPORT_DEFERRED: extern "C" fn(f64, f64) -> f64 = js_module_dynamic_import_deferred; diff --git a/crates/perry-runtime/src/native_abi.rs b/crates/perry-runtime/src/native_abi.rs index 47023275e6..5bec79bd86 100644 --- a/crates/perry-runtime/src/native_abi.rs +++ b/crates/perry-runtime/src/native_abi.rs @@ -160,36 +160,48 @@ pub extern "C" fn js_typed_string_arg_to_raw(value: f64) -> i64 { // internal typed clone. They have no Rust call sites, so keep explicit // function-pointer references to prevent whole-program LTO/dead-strip from // removing the exported symbols. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_F64_ARG_GUARD: extern "C" fn(f64) -> i32 = js_typed_f64_arg_guard; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_F64_ARG_TO_RAW: extern "C" fn(f64) -> f64 = js_typed_f64_arg_to_raw; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_I32_ARG_GUARD: extern "C" fn(f64) -> i32 = js_typed_i32_arg_guard; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_I32_ARG_TO_RAW: extern "C" fn(f64) -> i32 = js_typed_i32_arg_to_raw; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_I1_ARG_GUARD: extern "C" fn(f64) -> i32 = js_typed_i1_arg_guard; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_I1_ARG_TO_RAW: extern "C" fn(f64) -> i32 = js_typed_i1_arg_to_raw; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_STRING_ARG_GUARD: extern "C" fn(f64) -> i32 = js_typed_string_arg_guard; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_STRING_ARG_TO_RAW: extern "C" fn(f64) -> i64 = js_typed_string_arg_to_raw; // Static-name and static-method lowering emits these by-id wrappers directly // from generated LLVM IR. Keep roots here so LTO cannot strip the symbols just // because the Rust crate graph has no ordinary caller. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_OBJECT_GET_FIELD_BY_PROPERTY_ID_F64: extern "C" fn(*const ObjectHeader, i64) -> f64 = crate::object::js_object_get_field_by_property_id_f64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_OBJECT_SET_FIELD_BY_PROPERTY_ID: extern "C" fn(*mut ObjectHeader, i64, f64) = crate::object::js_object_set_field_by_property_id; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_NATIVE_CALL_METHOD_BY_ID: unsafe extern "C" fn(f64, i64, *const f64, usize) -> f64 = crate::object::js_native_call_method_by_id; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_NATIVE_CALL_METHOD_APPLY_BY_ID: unsafe extern "C" fn(f64, i64, i64) -> f64 = crate::object::js_native_call_method_apply_by_id; diff --git a/crates/perry-runtime/src/node_sea.rs b/crates/perry-runtime/src/node_sea.rs index 206131b4ee..745939bf1b 100644 --- a/crates/perry-runtime/src/node_sea.rs +++ b/crates/perry-runtime/src/node_sea.rs @@ -7,15 +7,20 @@ use crate::value::{JSValue, TAG_FALSE}; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SEA_IS_SEA: extern "C" fn() -> f64 = js_sea_is_sea; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SEA_GET_ASSET: extern "C" fn(f64, f64) -> f64 = js_sea_get_asset; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SEA_GET_ASSET_AS_BLOB: extern "C" fn(f64, f64) -> f64 = js_sea_get_asset_as_blob; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SEA_GET_RAW_ASSET: extern "C" fn(f64) -> f64 = js_sea_get_raw_asset; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SEA_GET_ASSET_KEYS: extern "C" fn() -> f64 = js_sea_get_asset_keys; fn false_value() -> f64 { diff --git a/crates/perry-runtime/src/node_stream_keepalive.rs b/crates/perry-runtime/src/node_stream_keepalive.rs index 2b3e9599be..a619f40587 100644 --- a/crates/perry-runtime/src/node_stream_keepalive.rs +++ b/crates/perry-runtime/src/node_stream_keepalive.rs @@ -5,183 +5,253 @@ // by any Rust code in the crate graph. The default `.a` staticlib keeps // them via staticlib-export semantics, but the auto-optimize build round- // trips the runtime through whole-program LLVM bitcode and is free to -// internalize and dead-strip an unreferenced symbol. The `#[cfg_attr(feature = "keepalive-anchors", used)]` statics +// internalize and dead-strip an unreferenced symbol. The `#[used]` statics // below pin retained reference edges so every entry point survives all link // modes. See the same pattern in `value/dyn_index.rs` and `process.rs`. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_EMIT: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_emit; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_EMIT_ARGS: extern "C" fn(i64, f64, i64) -> f64 = super::js_node_stream_method_emit_args; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_READ: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_read; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_PUSH: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_push; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_UNSHIFT: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_unshift; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_HWM: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_hwm; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_LENGTH: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_length; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_OBJECT_MODE: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_object_mode; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_READABLE: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_READABLE_ENDED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_ended; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_READABLE_ENCODING: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_encoding; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_WRITABLE_HWM: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_hwm; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_WRITABLE_LENGTH: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_length; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_WRITABLE_NEED_DRAIN: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_need_drain; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_WRITABLE_OBJECT_MODE: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_object_mode; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_ABORTED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_aborted; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_CLOSED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_closed; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_ERRORED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_errored; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_DID_READ: extern "C" fn(i64) -> f64 = super::js_node_stream_method_readable_did_read; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_WRITABLE_CORKED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_corked; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_WRITABLE: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_WRITABLE_ENDED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_ended; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_WRITABLE_FINISHED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_writable_finished; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_ALLOW_HALF_OPEN: extern "C" fn(i64) -> f64 = super::js_node_stream_method_allow_half_open; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_PAUSE: extern "C" fn(i64) -> f64 = super::js_node_stream_method_pause; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_RESUME: extern "C" fn(i64) -> f64 = super::js_node_stream_method_resume; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_SET_ENCODING: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_set_encoding; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_DESTROY: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_destroy; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_DESTROYED: extern "C" fn(i64) -> f64 = super::js_node_stream_method_destroyed; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_WRITE: extern "C" fn(i64, f64, f64, f64) -> f64 = super::js_node_stream_method_write; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_END: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_end; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_END3: extern "C" fn(i64, f64, f64, f64) -> f64 = super::js_node_stream_method_end3; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_CORK: extern "C" fn(i64) -> f64 = super::js_node_stream_method_cork; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_UNCORK: extern "C" fn(i64) -> f64 = super::js_node_stream_method_uncork; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_SET_MAX_LISTENERS: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_set_max_listeners; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_GET_MAX_LISTENERS: extern "C" fn(i64) -> f64 = super::js_node_stream_method_get_max_listeners; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_ON: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_on; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_ONCE: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_once; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_PREPEND_LISTENER: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_prepend_listener; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_PREPEND_ONCE_LISTENER: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_prepend_once_listener; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_OFF: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_off; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_REMOVE_LISTENER: extern "C" fn(i64, f64, f64) -> f64 = super::js_node_stream_method_remove_listener; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_REMOVE_ALL_LISTENERS: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_remove_all_listeners; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_EVENT_NAMES: extern "C" fn(i64) -> i64 = super::js_node_stream_method_event_names; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_LISTENER_COUNT: extern "C" fn(i64, f64) -> f64 = super::js_node_stream_method_listener_count; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_LISTENERS: extern "C" fn(i64, f64) -> i64 = super::js_node_stream_method_listeners; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_METHOD_RAW_LISTENERS: extern "C" fn(i64, f64) -> i64 = super::js_node_stream_method_raw_listeners; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_NEW: extern "C" fn(f64) -> f64 = super::js_node_stream_readable_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_WRITABLE_NEW: extern "C" fn(f64) -> f64 = super::js_node_stream_writable_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_DUPLEX_NEW: extern "C" fn(f64) -> f64 = super::js_node_stream_duplex_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_TRANSFORM_NEW: extern "C" fn(f64) -> f64 = super::js_node_stream_transform_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_PASSTHROUGH_NEW: extern "C" fn(f64) -> f64 = super::js_node_stream_passthrough_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_FROM: extern "C" fn(f64) -> f64 = super::js_node_stream_readable_from; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_READABLE_FROM_OPTIONS: extern "C" fn(f64, f64) -> f64 = super::js_node_stream_readable_from_options; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_DISTURBED: extern "C" fn(f64) -> f64 = super::js_node_stream_is_disturbed; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_ERRORED: extern "C" fn(f64) -> f64 = super::js_node_stream_is_errored; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_READABLE: extern "C" fn(f64) -> f64 = super::js_node_stream_is_readable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_WRITABLE: extern "C" fn(f64) -> f64 = super::js_node_stream_is_writable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_ARRAY_BUFFER_VIEW: extern "C" fn(f64) -> f64 = super::js_node_stream_is_array_buffer_view; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_UINT8_ARRAY: extern "C" fn(f64) -> f64 = super::js_node_stream_is_uint8_array; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_IS_DESTROYED: extern "C" fn(f64) -> f64 = super::js_node_stream_is_destroyed; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_UINT8_ARRAY_TO_BUFFER: extern "C" fn(f64) -> f64 = super::js_node_stream_uint8_array_to_buffer; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_GET_DEFAULT_HWM: extern "C" fn(f64) -> f64 = super::js_node_stream_get_default_hwm; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_SET_DEFAULT_HWM: extern "C" fn(f64, f64) -> f64 = super::js_node_stream_set_default_hwm; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_ADD_ABORT_SIGNAL: extern "C" fn(f64, f64) -> f64 = super::js_node_stream_add_abort_signal; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_COMPOSE: extern "C" fn(*const crate::array::ArrayHeader) -> f64 = super::js_node_stream_compose; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_PIPELINE: extern "C" fn(*const crate::array::ArrayHeader) -> f64 = super::js_node_stream_pipeline; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_DUPLEX_PAIR: extern "C" fn(f64) -> f64 = super::js_node_stream_duplex_pair; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_TO_WEB: extern "C" fn(f64) -> f64 = super::js_node_stream_to_web; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NS_FROM_WEB: extern "C" fn(f64) -> f64 = super::js_node_stream_from_web; diff --git a/crates/perry-runtime/src/node_submodules/zlib.rs b/crates/perry-runtime/src/node_submodules/zlib.rs index f05488bf88..0b90f04a13 100644 --- a/crates/perry-runtime/src/node_submodules/zlib.rs +++ b/crates/perry-runtime/src/node_submodules/zlib.rs @@ -291,13 +291,18 @@ pub extern "C" fn js_zlib_validate_callback(callback: f64) -> i64 { /// bitcode rebuild performed by auto-optimize (see /// `project_auto_optimize_keepalive_3320`). Called only from generated `.o` / /// `perry-ext-zlib`, so without an explicit anchor the dead-stripper drops it. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ZLIB_RESOLVE_LEVEL: extern "C" fn(f64) -> i32 = js_zlib_resolve_level; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ZLIB_VALIDATE_PARAMS: extern "C" fn(f64, f64) -> i32 = js_zlib_validate_params; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ZLIB_VALIDATE_OPTIONS: extern "C" fn(f64, i32) = js_zlib_validate_options; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ZLIB_VALIDATE_BUFFER_ARG: extern "C" fn(i64) = js_zlib_validate_buffer_arg; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ZLIB_VALIDATE_CALLBACK: extern "C" fn(f64) -> i64 = js_zlib_validate_callback; diff --git a/crates/perry-runtime/src/node_v8.rs b/crates/perry-runtime/src/node_v8.rs index 529c03ccc5..a9ba037dc1 100644 --- a/crates/perry-runtime/src/node_v8.rs +++ b/crates/perry-runtime/src/node_v8.rs @@ -33,46 +33,65 @@ use crate::value::JSValue; // Symbol retention: these `#[no_mangle]` entry points are emitted only by // codegen's `node:v8` dispatch — no Rust caller references them, so the // auto-optimize whole-program-LLVM build would dead-strip them without an -// anchor (see node_stream_keepalive.rs). Pin each via a `#[cfg_attr(feature = "keepalive-anchors", used)]` static. -#[cfg_attr(feature = "keepalive-anchors", used)] +// anchor (see node_stream_keepalive.rs). Pin each via a `#[used]` static. +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_SERIALIZE: extern "C" fn(f64) -> f64 = js_v8_serialize; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_DESERIALIZE: extern "C" fn(f64) -> f64 = js_v8_deserialize; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_HEAP_STATS: extern "C" fn() -> f64 = js_v8_get_heap_statistics; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_CODE_STATS: extern "C" fn() -> f64 = js_v8_get_heap_code_statistics; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_SPACE_STATS: extern "C" fn() -> f64 = js_v8_get_heap_space_statistics; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_VERSION_TAG: extern "C" fn() -> f64 = js_v8_cached_data_version_tag; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_GET_HEAP_SNAPSHOT: extern "C" fn(f64) -> f64 = js_v8_get_heap_snapshot; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_WRITE_HEAP_SNAPSHOT: extern "C" fn(f64, f64) -> f64 = js_v8_write_heap_snapshot; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_GC_PROFILER_NEW: extern "C" fn() -> f64 = js_v8_gc_profiler_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_GC_PROFILER_START: extern "C" fn(f64) -> f64 = js_v8_gc_profiler_start; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_GC_PROFILER_STOP: extern "C" fn(f64) -> f64 = js_v8_gc_profiler_stop; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_GC_PROFILER_REPORT: extern "C" fn() -> f64 = js_v8_gc_profiler_report; // #3680: Serializer / Deserializer class constructors. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_SERIALIZER_NEW: extern "C" fn(f64) -> f64 = js_v8_serializer_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_DESERIALIZER_NEW: extern "C" fn(f64) -> f64 = js_v8_deserializer_new; // #3679: lifecycle / diagnostic-control surface. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_NOOP_UNDEFINED: extern "C" fn() -> f64 = js_v8_noop_undefined; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_IS_BUILDING_SNAPSHOT: extern "C" fn() -> f64 = js_v8_is_building_snapshot; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_NAMESPACE: extern "C" fn(*const u8, usize) -> f64 = js_v8_namespace; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_THROW_NOT_BUILDING: extern "C" fn() -> f64 = js_v8_throw_not_building_snapshot; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_V8_PROMISE_HOOK_REGISTER: extern "C" fn() -> f64 = js_v8_promise_hook_register; const TAG_UNDEFINED_BITS: u64 = 0x7FFC_0000_0000_0001; diff --git a/crates/perry-runtime/src/object/alloc.rs b/crates/perry-runtime/src/object/alloc.rs index 425e448881..9648d057d8 100644 --- a/crates/perry-runtime/src/object/alloc.rs +++ b/crates/perry-runtime/src/object/alloc.rs @@ -569,7 +569,8 @@ pub extern "C" fn js_object_alloc_class_dynamic_parent( /// Keepalive anchor — `js_object_alloc_class_dynamic_parent` is a /// generated-code-only callee, so the auto-optimize whole-program build would /// otherwise dead-strip it (see the FFI-symbol-link-break class). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_OBJECT_ALLOC_CLASS_DYNAMIC_PARENT: extern "C" fn( u32, u32, diff --git a/crates/perry-runtime/src/object/class_constructors.rs b/crates/perry-runtime/src/object/class_constructors.rs index 0a1e075215..556840a331 100644 --- a/crates/perry-runtime/src/object/class_constructors.rs +++ b/crates/perry-runtime/src/object/class_constructors.rs @@ -108,7 +108,8 @@ pub extern "C" fn js_register_class_constructor_flags( } /// Keepalive anchor (generated-code-only callee). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_REGISTER_CLASS_CONSTRUCTOR_FLAGS: extern "C" fn(i64, i64, i64) = js_register_class_constructor_flags; @@ -162,7 +163,8 @@ pub unsafe extern "C" fn js_class_register_capture_values( /// Keepalive anchor for the auto-optimize whole-program build — /// `js_class_register_capture_values` is a generated-code-only callee. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CLASS_REGISTER_CAPTURE_VALUES: unsafe extern "C" fn(u32, *const f64, usize) = js_class_register_capture_values; @@ -351,12 +353,15 @@ pub(crate) fn fallback_is_tag_stripped(fallback: f64) -> bool { } /// Keepalive anchors (generated-code-only callees). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CLASS_CAPTURE_VALUE: extern "C" fn(u32, u32) -> f64 = js_class_capture_value; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_CLASS_CAPTURE_VALUE_OR: extern "C" fn(u32, u32, f64) -> f64 = js_class_capture_value_or; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_PARAM_OR_CLASS_CAPTURE_VALUE: extern "C" fn(f64, u32, u32) -> f64 = js_param_or_class_capture_value; @@ -554,7 +559,8 @@ pub unsafe extern "C" fn js_super_construct_apply( } /// Keepalive anchor (generated-code-only callee). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SUPER_CONSTRUCT_APPLY: unsafe extern "C" fn(u32, f64, f64) -> f64 = js_super_construct_apply; @@ -719,7 +725,8 @@ unsafe fn call_displaced_native_base_method( } /// Keepalive anchor (generated-code-only callee). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SUPER_METHOD_CALL_DYNAMIC: unsafe extern "C" fn( u32, *const u8, @@ -776,7 +783,8 @@ pub unsafe extern "C" fn js_super_method_call_dynamic_apply( } /// Keepalive anchor (generated-code-only callee). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SUPER_METHOD_CALL_DYNAMIC_APPLY: unsafe extern "C" fn( u32, *const u8, @@ -932,7 +940,8 @@ pub unsafe extern "C" fn js_array_push_spread_any( } /// Keepalive anchor (generated-code-only callee). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ARRAY_PUSH_SPREAD_ANY: unsafe extern "C" fn( *mut crate::array::ArrayHeader, f64, @@ -1030,7 +1039,8 @@ pub unsafe extern "C" fn js_error_subclass_default_init( } /// Keepalive: generated code is the only caller (#6469). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ERROR_SUBCLASS_DEFAULT_INIT: unsafe extern "C" fn( f64, f64, diff --git a/crates/perry-runtime/src/object/class_registry.rs b/crates/perry-runtime/src/object/class_registry.rs index c90c21ceab..5129b50dc3 100644 --- a/crates/perry-runtime/src/object/class_registry.rs +++ b/crates/perry-runtime/src/object/class_registry.rs @@ -79,6 +79,8 @@ pub use prototype_objects::{js_set_function_prototype, NEXT_SYNTHETIC_CLASS_ID}; // ── class_meta.rs ─────────────────────────────────────────────────────────── #[cfg(test)] pub(crate) use class_meta::test_text_encoding_stream_new_with_constructor; +#[cfg(feature = "global-text")] +pub(crate) use class_meta::text_decoder_bool_option; pub use class_meta::{ class_name_for_id, is_anon_shape_class_id, js_compression_stream_new, js_decompression_stream_new, js_register_anon_shape_class_id, js_register_class_id, @@ -86,7 +88,7 @@ pub use class_meta::{ js_text_encoding_stream_new, ANON_SHAPE_CLASS_IDS, CLASS_NAMES, }; pub(crate) use class_meta::{ - identify_global_builtin_constructor, report_dispatch_miss, text_decoder_bool_option, + identify_global_builtin_constructor, report_dispatch_miss, text_encoding_stream_new_with_constructor, validate_web_compression_stream_format, CLASS_ID_COMPRESSION_STREAM, CLASS_ID_DECOMPRESSION_STREAM, CLASS_ID_TEXT_DECODER_STREAM, CLASS_ID_TEXT_ENCODER_STREAM, diff --git a/crates/perry-runtime/src/object/class_registry/class_meta.rs b/crates/perry-runtime/src/object/class_registry/class_meta.rs index a49ea72750..7a2d5abd6f 100644 --- a/crates/perry-runtime/src/object/class_registry/class_meta.rs +++ b/crates/perry-runtime/src/object/class_registry/class_meta.rs @@ -326,6 +326,7 @@ pub(crate) fn identify_global_builtin_constructor(func_value: f64) -> Option<&'s None } +#[cfg(feature = "global-text")] pub(crate) fn text_decoder_bool_option(options: f64, name: &str) -> f64 { let jsval = crate::value::JSValue::from_bits(options.to_bits()); if !jsval.is_pointer() { diff --git a/crates/perry-runtime/src/object/class_registry/registration.rs b/crates/perry-runtime/src/object/class_registry/registration.rs index 49f10eba1a..8db0b6f8b3 100644 --- a/crates/perry-runtime/src/object/class_registry/registration.rs +++ b/crates/perry-runtime/src/object/class_registry/registration.rs @@ -289,11 +289,13 @@ pub unsafe extern "C" fn js_register_class_static_setter( // These two are only ever called from codegen-emitted module-init IR (no Rust // caller), so the auto-optimize whole-program-LLVM build would dead-strip them -// without an anchor. Pin each via a `#[cfg_attr(feature = "keepalive-anchors", used)]` static (mirrors node_v8.rs). -#[cfg_attr(feature = "keepalive-anchors", used)] +// without an anchor. Pin each via a `#[used]` static (mirrors node_v8.rs). +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REGISTER_STATIC_GETTER: unsafe extern "C" fn(i64, *const u8, i64, i64) = js_register_class_static_getter; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REGISTER_STATIC_SETTER: unsafe extern "C" fn(i64, *const u8, i64, i64) = js_register_class_static_setter; @@ -326,7 +328,8 @@ pub unsafe extern "C" fn js_register_class_method_bind_length( .insert((class_id as u32, name), length as u32); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REGISTER_METHOD_BIND_LENGTH: unsafe extern "C" fn(i64, *const u8, i64, i64) = js_register_class_method_bind_length; @@ -359,7 +362,8 @@ pub unsafe extern "C" fn js_register_class_static_method_bind_length( .insert((class_id as u32, name), length as u32); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REGISTER_STATIC_METHOD_BIND_LENGTH: unsafe extern "C" fn(i64, *const u8, i64, i64) = js_register_class_static_method_bind_length; diff --git a/crates/perry-runtime/src/object/descriptors.rs b/crates/perry-runtime/src/object/descriptors.rs index 67a53b02f2..4b9a50f512 100644 --- a/crates/perry-runtime/src/object/descriptors.rs +++ b/crates/perry-runtime/src/object/descriptors.rs @@ -1079,8 +1079,8 @@ pub extern "C" fn js_object_get_own_property_names(obj_value: f64) -> f64 { if !obj_ptr.is_null() { // Armed ops table (see `nm_namespace_hooks`): namespace key // enumeration links only when a namespace can exist. - if let Some(arr) = super::nm_namespace_ops() - .and_then(|ops| unsafe { (ops.own_keys_array)(obj_ptr) }) + if let Some(arr) = + super::nm_namespace_ops().and_then(|ops| (ops.own_keys_array)(obj_ptr)) { return f64::from_bits((arr as u64) | 0x7FFD_0000_0000_0000); } @@ -1548,7 +1548,8 @@ pub extern "C" fn js_object_create_with_props(proto_value: f64, props_value: f64 result } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_OBJECT_CREATE_WITH_PROPS: extern "C" fn(f64, f64) -> f64 = js_object_create_with_props; /// `Object.getOwnPropertyDescriptor` handling for native-module namespace diff --git a/crates/perry-runtime/src/object/global_this.rs b/crates/perry-runtime/src/object/global_this.rs index 08c130624a..8150ce1c23 100644 --- a/crates/perry-runtime/src/object/global_this.rs +++ b/crates/perry-runtime/src/object/global_this.rs @@ -1,5 +1,20 @@ //! `globalThis` singleton plus built-in constructor/namespace population. +#![cfg_attr( + not(any( + feature = "global-math", + feature = "global-json", + feature = "global-reflect", + feature = "global-atomics", + feature = "global-url", + feature = "global-text", + feature = "global-websocket", + feature = "global-webcrypto", + feature = "global-webfetch" + )), + allow(dead_code, unused_imports) +)] + use super::*; #[path = "global_this_webassembly.rs"] diff --git a/crates/perry-runtime/src/object/global_this/builtin_thunks.rs b/crates/perry-runtime/src/object/global_this/builtin_thunks.rs index d6c80c5163..ff6bd8ea21 100644 --- a/crates/perry-runtime/src/object/global_this/builtin_thunks.rs +++ b/crates/perry-runtime/src/object/global_this/builtin_thunks.rs @@ -503,7 +503,8 @@ extern "C" fn depd_wrapfunction_outer_thunk( fn_v } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_FUNCTION_CTOR_FROM_STRINGS: extern "C" fn(*const f64, usize) -> f64 = js_function_ctor_from_strings; diff --git a/crates/perry-runtime/src/object/global_this/fetch_globals.rs b/crates/perry-runtime/src/object/global_this/fetch_globals.rs index ac0fcf7d47..aea21e48b4 100644 --- a/crates/perry-runtime/src/object/global_this/fetch_globals.rs +++ b/crates/perry-runtime/src/object/global_this/fetch_globals.rs @@ -43,9 +43,10 @@ pub extern "C" fn js_module_top_this() -> f64 { /// Keepalive anchor: `js_module_top_this` is referenced only from /// codegen-generated `.o` files, so the auto-optimize whole-program LLVM -/// rebuild would dead-strip it without this `#[cfg_attr(feature = "keepalive-anchors", used)]` pin (see +/// rebuild would dead-strip it without this `#[used]` pin (see /// project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_TOP_THIS: extern "C" fn() -> f64 = js_module_top_this; /// Issue #611: lazily allocate `globalThis` for computed global access. @@ -488,10 +489,12 @@ pub extern "C" fn js_response_subclass_init(this_box: f64, body: f64, init: f64) // `Expr::SuperCall` Request/Response arm); pin them so the auto-optimize // bitcode rebuild's dead-strip can't drop them (see // project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_REQUEST_SUBCLASS_INIT: extern "C" fn(f64, f64, f64) -> f64 = js_request_subclass_init; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_RESPONSE_SUBCLASS_INIT: extern "C" fn(f64, f64, f64) -> f64 = js_response_subclass_init; @@ -840,7 +843,8 @@ pub unsafe extern "C" fn js_fetch_or_value_super( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_FETCH_OR_VALUE_SUPER: unsafe extern "C" fn(f64, f64, *const f64, usize) -> f64 = js_fetch_or_value_super; diff --git a/crates/perry-runtime/src/object/groupby.rs b/crates/perry-runtime/src/object/groupby.rs index 411669369c..2d1caa41ec 100644 --- a/crates/perry-runtime/src/object/groupby.rs +++ b/crates/perry-runtime/src/object/groupby.rs @@ -136,9 +136,11 @@ pub extern "C" fn js_map_group_by(items_value: f64, callback: f64) -> f64 { /// Keepalive anchors: these `#[no_mangle]` helpers are only called from /// codegen-emitted `.o`. The auto-optimize whole-program LLVM rebuild /// dead-strips unreferenced `#[no_mangle]` symbols (see #3320), so pin them. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_OBJECT_GROUP_BY: extern "C" fn(f64, f64) -> f64 = js_object_group_by; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_MAP_GROUP_BY: extern "C" fn(f64, f64) -> f64 = js_map_group_by; /// Returns true if `value` is a Symbol (registered SymbolHeader pointer). diff --git a/crates/perry-runtime/src/object/native_call_method/common_methods.rs b/crates/perry-runtime/src/object/native_call_method/common_methods.rs index 6600d9539a..f43833aef7 100644 --- a/crates/perry-runtime/src/object/native_call_method/common_methods.rs +++ b/crates/perry-runtime/src/object/native_call_method/common_methods.rs @@ -248,7 +248,6 @@ pub(super) unsafe fn dispatch_common( let key_value = crate::object::js_to_property_key(key_value); let key_value = root_scope.root_nanbox_f64(key_value).get_nanbox_f64(); let object = object_handle.get_nanbox_f64(); - let jsval = JSValue::from_bits(object.to_bits()); // Symbol keys must not be string-coerced — route through the // canonical entry, which consults the SYMBOL_PROPERTIES side // table (mirrors hasOwnProperty's symbol arm). diff --git a/crates/perry-runtime/src/object/native_module.rs b/crates/perry-runtime/src/object/native_module.rs index 176a301c14..71a60986c1 100644 --- a/crates/perry-runtime/src/object/native_module.rs +++ b/crates/perry-runtime/src/object/native_module.rs @@ -1098,7 +1098,8 @@ pub extern "C" fn js_class_method_bind_by_id(instance: f64, method_id: i64) -> f js_class_method_bind(instance, name_ref.ptr, name_ref.len) } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_CLASS_METHOD_BIND_BY_ID: extern "C" fn(f64, i64) -> f64 = js_class_method_bind_by_id; /// Allocate a BOUND_METHOD closure binding `instance` as the receiver for the diff --git a/crates/perry-runtime/src/object/native_module/constants.rs b/crates/perry-runtime/src/object/native_module/constants.rs index 2c4f963e09..8438e0bd9c 100644 --- a/crates/perry-runtime/src/object/native_module/constants.rs +++ b/crates/perry-runtime/src/object/native_module/constants.rs @@ -401,39 +401,6 @@ pub(crate) unsafe fn get_native_module_constant( // Required by axios for its stream wiring. let zlib_const = zlib_const_lookup; - let dns_const = |prop: &str| -> Option { - Some(match prop { - "ADDRCONFIG" => 1024.0, - "V4MAPPED" => 2048.0, - "ALL" => 256.0, - "NODATA" => str_val("ENODATA"), - "FORMERR" => str_val("EFORMERR"), - "SERVFAIL" => str_val("ESERVFAIL"), - "NOTFOUND" => str_val("ENOTFOUND"), - "NOTIMP" => str_val("ENOTIMP"), - "REFUSED" => str_val("EREFUSED"), - "BADQUERY" => str_val("EBADQUERY"), - "BADNAME" => str_val("EBADNAME"), - "BADFAMILY" => str_val("EBADFAMILY"), - "BADRESP" => str_val("EBADRESP"), - "CONNREFUSED" => str_val("ECONNREFUSED"), - "TIMEOUT" => str_val("ETIMEOUT"), - "EOF" => str_val("EOF"), - "FILE" => str_val("EFILE"), - "NOMEM" => str_val("ENOMEM"), - "DESTRUCTION" => str_val("EDESTRUCTION"), - "BADSTR" => str_val("EBADSTR"), - "BADFLAGS" => str_val("EBADFLAGS"), - "NONAME" => str_val("ENONAME"), - "BADHINTS" => str_val("EBADHINTS"), - "NOTINITIALIZED" => str_val("ENOTINITIALIZED"), - "LOADIPHLPAPI" => str_val("ELOADIPHLPAPI"), - "ADDRGETNETWORKPARAMS" => str_val("EADDRGETNETWORKPARAMS"), - "CANCELLED" => str_val("ECANCELLED"), - _ => return None, - }) - }; - let sqlite_const = sqlite_const_lookup; match module_name { diff --git a/crates/perry-runtime/src/object/native_this_alias.rs b/crates/perry-runtime/src/object/native_this_alias.rs index 2f8466de5a..db96bda318 100644 --- a/crates/perry-runtime/src/object/native_this_alias.rs +++ b/crates/perry-runtime/src/object/native_this_alias.rs @@ -290,9 +290,11 @@ pub unsafe extern "C" fn js_https_server_construct_with_this( /// Keepalive anchors: the auto-optimize whole-program LLVM rebuild /// dead-strips `#[no_mangle]` fns referenced only from generated `.o` /// files. See the `KEEP_JS_FUNCTION_BIND` precedent in closure/dispatch.rs. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_HTTP_SERVER_CONSTRUCT_WITH_THIS: unsafe extern "C" fn(f64, f64, f64) -> f64 = js_http_server_construct_with_this; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_HTTPS_SERVER_CONSTRUCT_WITH_THIS: unsafe extern "C" fn(f64, f64, f64) -> f64 = js_https_server_construct_with_this; diff --git a/crates/perry-runtime/src/object/object_ops/has_own.rs b/crates/perry-runtime/src/object/object_ops/has_own.rs index 253b636e25..554066ff51 100644 --- a/crates/perry-runtime/src/object/object_ops/has_own.rs +++ b/crates/perry-runtime/src/object/object_ops/has_own.rs @@ -696,6 +696,7 @@ pub extern "C" fn js_object_property_is_enumerable(obj_value: f64, key_value: f6 } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROPERTY_IS_ENUMERABLE: extern "C" fn(f64, f64) -> f64 = js_object_property_is_enumerable; diff --git a/crates/perry-runtime/src/object/this_binding.rs b/crates/perry-runtime/src/object/this_binding.rs index 6f3c52d9ff..7f854a9735 100644 --- a/crates/perry-runtime/src/object/this_binding.rs +++ b/crates/perry-runtime/src/object/this_binding.rs @@ -70,7 +70,8 @@ pub(crate) fn static_this_disarm() { /// checks on subclass receivers throw (test262 static-private-method- /// subclass-receiver). // #1561-style force-keep: only generated IR calls this. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_STATIC_THIS_ARM_CLASSREF: extern "C" fn(u32) = js_static_this_arm_classref; #[no_mangle] @@ -85,7 +86,8 @@ pub extern "C" fn js_static_this_arm_classref(class_id: u32) { /// class-ref expression and the method resolves on a parent class at compile /// time) right before the direct call. // #1561-style force-keep: only generated IR calls this. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_STATIC_THIS_ARM_VALUE: extern "C" fn(f64) = js_static_this_arm_value; #[no_mangle] @@ -96,7 +98,8 @@ pub extern "C" fn js_static_this_arm_value(value: f64) { /// Static-method prologue `this` resolution: take the armed override if any, /// else the lexical class-ref the codegen passes in. // #1561-style force-keep: only generated IR calls this. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_STATIC_THIS_RESOLVE: extern "C" fn(f64) -> f64 = js_static_this_resolve; #[no_mangle] diff --git a/crates/perry-runtime/src/object/typed_array_define.rs b/crates/perry-runtime/src/object/typed_array_define.rs index 03db375217..69df6f6b6a 100644 --- a/crates/perry-runtime/src/object/typed_array_define.rs +++ b/crates/perry-runtime/src/object/typed_array_define.rs @@ -219,7 +219,6 @@ pub(crate) unsafe fn typed_array_define_own_property( // Symbol / non-string / non-canonical key → ordinary define handles it. return TypedArrayDefineOutcome::NotTypedArray; }; - let addr = addr_handle.get_raw_mut_ptr::() as usize; let descriptor_value = desc_handle.get_nanbox_f64(); // Canonical numeric index → integer-indexed branch. From here every path diff --git a/crates/perry-runtime/src/object/websocket_global.rs b/crates/perry-runtime/src/object/websocket_global.rs index 0ed2c03e1d..2860bc5cfb 100644 --- a/crates/perry-runtime/src/object/websocket_global.rs +++ b/crates/perry-runtime/src/object/websocket_global.rs @@ -45,6 +45,7 @@ pub(super) fn install_constructor_shape( } } +#[cfg(feature = "global-websocket")] pub(super) fn install_proto_methods(proto_obj: *mut ObjectHeader) { use super::global_this::install_proto_method; install_proto_method( diff --git a/crates/perry-runtime/src/object/with_env.rs b/crates/perry-runtime/src/object/with_env.rs index dfd10f3f60..f5e22a9f99 100644 --- a/crates/perry-runtime/src/object/with_env.rs +++ b/crates/perry-runtime/src/object/with_env.rs @@ -124,9 +124,11 @@ pub extern "C" fn js_with_implicit_unset() -> f64 { } // #1561-style force-keep: only generated IR calls these. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_WITH_IMPLICIT_UNSET: extern "C" fn() -> f64 = js_with_implicit_unset; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_WITH_IMPLICIT_READ: extern "C" fn(f64, f64) -> f64 = js_with_implicit_read; /// `name` arrives as a NaN-boxed string (codegen lowers `Expr::String` args diff --git a/crates/perry-runtime/src/os.rs b/crates/perry-runtime/src/os.rs index 0ad783b345..f16bc9e99d 100644 --- a/crates/perry-runtime/src/os.rs +++ b/crates/perry-runtime/src/os.rs @@ -1285,7 +1285,8 @@ fn options_request_buffer(opts_bits: i64) -> bool { read_event_name(enc_ptr).as_deref() == Some("buffer") } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_OS_USER_INFO_OPTIONS: extern "C" fn(i64) -> *mut ObjectHeader = js_os_user_info_options; fn js_os_user_info_impl(buffer_encoding: bool) -> *mut ObjectHeader { diff --git a/crates/perry-runtime/src/path.rs b/crates/perry-runtime/src/path.rs index b3516e76c7..8c03e41e5e 100644 --- a/crates/perry-runtime/src/path.rs +++ b/crates/perry-runtime/src/path.rs @@ -829,10 +829,12 @@ pub extern "C" fn js_path_win32_relative_checked(from_f64: f64, to_f64: f64) -> /// Keepalive anchors: these are emitted only from generated code, so the /// whole-program auto-optimize bitcode pass would otherwise dead-strip them. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PATH_RELATIVE_CHECKED: extern "C" fn(f64, f64) -> *mut StringHeader = js_path_relative_checked; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PATH_WIN32_RELATIVE_CHECKED: extern "C" fn(f64, f64) -> *mut StringHeader = js_path_win32_relative_checked; diff --git a/crates/perry-runtime/src/process/env_misc.rs b/crates/perry-runtime/src/process/env_misc.rs index 295fa3444a..4efe486d2e 100644 --- a/crates/perry-runtime/src/process/env_misc.rs +++ b/crates/perry-runtime/src/process/env_misc.rs @@ -879,7 +879,8 @@ pub extern "C" fn js_process_pending_exit_code() -> i32 { // runtime is `js_process_exit`'s nullish fallback. Anchor the symbol so the // auto-optimize whole-program dead-strip cannot drop it (same guard the // unhandled-rejection reporter uses, #4876). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROCESS_PENDING_EXIT_CODE: extern "C" fn() -> i32 = js_process_pending_exit_code; /// Set an environment variable. Backs `process.env.X = v` (#1344). @@ -957,60 +958,80 @@ pub extern "C" fn js_setenv(name_ptr: *const StringHeader, value: f64) { // trips the runtime through whole-program LLVM bitcode and is free to // internalize + dead-strip an unreferenced symbol — leaving the codegen call // dangling (`Undefined symbols: _js_setenv` at final link, which is exactly -// how #1344's acceptance test still failed on main). The `#[cfg_attr(feature = "keepalive-anchors", used)]` statics +// how #1344's acceptance test still failed on main). The `#[used]` statics // below pin a retained reference edge so both survive every link mode. See // the same pattern in `value/dyn_index.rs`. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SETENV: extern "C" fn(*const StringHeader, f64) = js_setenv; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_REMOVEENV: extern "C" fn(*const StringHeader) = js_removeenv; // #3120: codegen emits `js_module_find_package_json` only from generated `.o`, // so pin a retained reference edge for the auto-optimize whole-program build. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_FIND_PACKAGE_JSON: extern "C" fn(f64, f64) -> f64 = js_module_find_package_json; // node:module helper-state APIs are codegen-emitted from generated `.o`, so pin // retained reference edges for the auto-optimize whole-program build. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_ENABLE_COMPILE_CACHE: extern "C" fn(f64) -> f64 = js_module_enable_compile_cache; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_FLUSH_COMPILE_CACHE: extern "C" fn() -> f64 = js_module_flush_compile_cache; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_GET_COMPILE_CACHE_DIR: extern "C" fn() -> f64 = js_module_get_compile_cache_dir; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_GET_SOURCE_MAPS_SUPPORT: extern "C" fn() -> f64 = js_module_get_source_maps_support; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_SET_SOURCE_MAPS_SUPPORT: extern "C" fn(f64, f64) -> f64 = js_module_set_source_maps_support; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_STRIP_TYPESCRIPT_TYPES: extern "C" fn(f64, f64) -> f64 = js_module_strip_typescript_types; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_REGISTER: extern "C" fn(f64, f64, f64) -> f64 = js_module_register; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_REGISTER_HOOKS: extern "C" fn(f64) -> f64 = js_module_register_hooks; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_DYNAMIC_IMPORT_APPLY_HOOKS: extern "C" fn(f64) -> f64 = js_module_dynamic_import_apply_hooks; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_MODULE_NEW: extern "C" fn(f64) -> f64 = js_module_module_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_FIND_PATH: extern "C" fn(f64, f64, f64) -> f64 = js_module_find_path; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_INIT_PATHS: extern "C" fn() -> f64 = js_module_init_paths; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_LOAD: extern "C" fn(f64, f64, f64) -> f64 = js_module_load; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_NODE_MODULE_PATHS: extern "C" fn(f64) -> f64 = js_module_node_module_paths; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_PRELOAD_MODULES: extern "C" fn(f64) -> f64 = js_module_preload_modules; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_RESOLVE_FILENAME: extern "C" fn(f64, f64, f64, f64) -> f64 = js_module_resolve_filename; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_MODULE_RESOLVE_LOOKUP_PATHS: extern "C" fn(f64, f64) -> f64 = js_module_resolve_lookup_paths; @@ -1759,12 +1780,16 @@ fn read_js_string_lossy(value: f64) -> String { // process native table). Pin retained-reference edges so the auto-optimize // whole-program build doesn't internalize + dead-strip them. Same rationale // as KEEP_JS_SETENV above. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_PROCESS_SOURCE_MAPS_ENABLED: extern "C" fn() -> f64 = js_process_source_maps_enabled; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_PROCESS_SET_SOURCE_MAPS_ENABLED: extern "C" fn(f64) -> f64 = js_process_set_source_maps_enabled; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_PROCESS_REF: extern "C" fn(f64) -> f64 = js_process_ref; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_PROCESS_UNREF: extern "C" fn(f64) -> f64 = js_process_unref; diff --git a/crates/perry-runtime/src/process/ipc.rs b/crates/perry-runtime/src/process/ipc.rs index f133e83118..b090e40a28 100644 --- a/crates/perry-runtime/src/process/ipc.rs +++ b/crates/perry-runtime/src/process/ipc.rs @@ -4,6 +4,8 @@ //! the same inherited Unix fd convention used by its `child_process.fork()` //! parent side and speaks newline-delimited JSON frames for this cut. +#![cfg_attr(not(feature = "proc-ipc"), allow(dead_code))] + use crate::closure::{ js_closure_alloc, js_closure_get_capture_ptr, js_closure_set_capture_ptr, js_native_call_value, js_register_closure_arity, js_register_closure_length, ClosureHeader, diff --git a/crates/perry-runtime/src/promise/async_step.rs b/crates/perry-runtime/src/promise/async_step.rs index bba35fb537..d1574436d8 100644 --- a/crates/perry-runtime/src/promise/async_step.rs +++ b/crates/perry-runtime/src/promise/async_step.rs @@ -676,7 +676,8 @@ pub extern "C" fn js_async_generator_resume( result } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ASYNC_GENERATOR_RESUME: extern "C" fn(f64, f64, f64) -> f64 = js_async_generator_resume; diff --git a/crates/perry-runtime/src/promise/combinators.rs b/crates/perry-runtime/src/promise/combinators.rs index 213fca9487..66263f6f58 100644 --- a/crates/perry-runtime/src/promise/combinators.rs +++ b/crates/perry-runtime/src/promise/combinators.rs @@ -500,14 +500,18 @@ pub extern "C" fn js_promise_any_iterable(value: f64) -> *mut Promise { /// #2822/#3320: keepalive anchors so the whole-program LLVM (auto-optimize) /// build does not dead-strip these codegen-only `#[no_mangle]` entry points. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_ALL_ITERABLE: extern "C" fn(f64) -> *mut Promise = js_promise_all_iterable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_RACE_ITERABLE: extern "C" fn(f64) -> *mut Promise = js_promise_race_iterable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_ALL_SETTLED_ITERABLE: extern "C" fn(f64) -> *mut Promise = js_promise_all_settled_iterable; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_ANY_ITERABLE: extern "C" fn(f64) -> *mut Promise = js_promise_any_iterable; // Queue for scheduled promise resolutions diff --git a/crates/perry-runtime/src/promise/microtasks.rs b/crates/perry-runtime/src/promise/microtasks.rs index 663899f3ad..5a6d8d249b 100644 --- a/crates/perry-runtime/src/promise/microtasks.rs +++ b/crates/perry-runtime/src/promise/microtasks.rs @@ -75,7 +75,8 @@ pub extern "C" fn js_promise_run_microtasks_event_loop() -> i32 { // The entry event loop is generated code, so nothing in the Rust runtime // references this symbol — anchor it like the other codegen-only hooks so the // auto-optimize internalize+dead-strip pass can't drop it (#4876). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_RUN_MICROTASKS_EVENT_LOOP: extern "C" fn() -> i32 = js_promise_run_microtasks_event_loop; diff --git a/crates/perry-runtime/src/promise/mod.rs b/crates/perry-runtime/src/promise/mod.rs index aa4e658954..fb0eca2102 100644 --- a/crates/perry-runtime/src/promise/mod.rs +++ b/crates/perry-runtime/src/promise/mod.rs @@ -450,23 +450,32 @@ pub fn scan_iter_result_root_mut(visitor: &mut crate::gc::RuntimeRootVisitor<'_> } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_SET: extern "C" fn(f64, i32) -> f64 = js_iter_result_set; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_SET_F64: extern "C" fn(f64, i32) -> f64 = js_iter_result_set_f64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_SET_I32: extern "C" fn(i32, i32) -> f64 = js_iter_result_set_i32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_SET_I1: extern "C" fn(i32, i32) -> f64 = js_iter_result_set_i1; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_GET_VALUE: extern "C" fn() -> f64 = js_iter_result_get_value; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_GET_VALUE_F64: extern "C" fn() -> f64 = js_iter_result_get_value_f64; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_GET_VALUE_I32: extern "C" fn() -> i32 = js_iter_result_get_value_i32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_GET_VALUE_I1: extern "C" fn() -> i32 = js_iter_result_get_value_i1; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITER_RESULT_GET_DONE: extern "C" fn() -> f64 = js_iter_result_get_done; /// Promise state diff --git a/crates/perry-runtime/src/promise/rejection.rs b/crates/perry-runtime/src/promise/rejection.rs index 16dae3886c..e3b89a6afe 100644 --- a/crates/perry-runtime/src/promise/rejection.rs +++ b/crates/perry-runtime/src/promise/rejection.rs @@ -96,7 +96,8 @@ pub extern "C" fn js_promise_mark_internally_handled(promise: *mut Promise) { /// Keep the stdlib-facing marker alive through the dead-strip pass on the /// PERRY_NO_AUTO_OPTIMIZE prebuilt-lib link (same pattern as the checkpoint /// hook anchors below). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_MARK_INTERNALLY_HANDLED: extern "C" fn(*mut Promise) = js_promise_mark_internally_handled; @@ -254,7 +255,8 @@ pub extern "C" fn js_promise_report_unhandled_rejections() { // internalize+dead-strip pass would otherwise drop it and that link mode // fails with "undefined symbol". The classic link needs no anchor (see the // error.rs/combinators.rs anchors for the same pattern). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROMISE_REPORT_UNHANDLED_REJECTIONS: extern "C" fn() = js_promise_report_unhandled_rejections; diff --git a/crates/perry-runtime/src/proxy.rs b/crates/perry-runtime/src/proxy.rs index 487ef33d40..733f360c2f 100644 --- a/crates/perry-runtime/src/proxy.rs +++ b/crates/perry-runtime/src/proxy.rs @@ -1845,35 +1845,44 @@ pub extern "C" fn js_proxy_revocable(target: f64, handler: f64) -> f64 { } // #2846: retention anchor for `Proxy.revocable` (codegen-only callsite). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PROXY_REVOCABLE: extern "C" fn(f64, f64) -> f64 = js_proxy_revocable; // #2762: retention anchors for the Reflect-specific extensibility entry points. // These `#[no_mangle]` fns are emitted only by codegen (no Rust caller in the // crate graph), so the auto-optimize whole-program LLVM bitcode rebuild would // otherwise internalize and dead-strip them. See node_stream_keepalive.rs. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_IS_EXTENSIBLE: extern "C" fn(f64) -> f64 = js_reflect_is_extensible; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_PREVENT_EXTENSIONS: extern "C" fn(f64) -> f64 = js_reflect_prevent_extensions; // #2761: retention anchor for `Reflect.setPrototypeOf` (codegen-only callsite). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_SET_PROTOTYPE_OF: extern "C" fn(f64, f64) -> f64 = js_reflect_set_prototype_of; // #2763/#2764/#2766/#2767: retention anchors for the Reflect entry points // whose only callsites are codegen-emitted. `js_reflect_get` gained a third // `receiver` arg (#2766) and must keep its new signature retained. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_GET: extern "C" fn(f64, f64, f64) -> f64 = js_reflect_get; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_GET_OWN_PROPERTY_DESCRIPTOR: extern "C" fn(f64, f64) -> f64 = js_reflect_get_own_property_descriptor; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_HAS: extern "C" fn(f64, f64) -> f64 = js_reflect_has; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_OWN_KEYS: extern "C" fn(f64) -> f64 = js_reflect_own_keys; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REFLECT_APPLY: extern "C" fn(f64, f64, f64) -> f64 = js_reflect_apply; /// Rewrite a `REFLECT_METADATA` key's POINTER-tagged target bits during the diff --git a/crates/perry-runtime/src/proxy/put_value.rs b/crates/perry-runtime/src/proxy/put_value.rs index c2d40bf14d..235ee2c98f 100644 --- a/crates/perry-runtime/src/proxy/put_value.rs +++ b/crates/perry-runtime/src/proxy/put_value.rs @@ -492,7 +492,8 @@ unsafe fn dyn_ic_try_store(target: f64, token: u64, slot: u32, value: f64) -> Op // #6088-style keep: codegen emits the only call; a whole-program bitcode // link would otherwise dead-strip the IC entry. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_PUT_VALUE_SET_DYN_IC: extern "C" fn(*mut [i64; 8], f64, f64, f64, i32) -> f64 = js_put_value_set_dyn_ic; diff --git a/crates/perry-runtime/src/regex/escape.rs b/crates/perry-runtime/src/regex/escape.rs index a2203e544b..e5a2fb8a51 100644 --- a/crates/perry-runtime/src/regex/escape.rs +++ b/crates/perry-runtime/src/regex/escape.rs @@ -138,6 +138,7 @@ pub extern "C" fn js_regexp_escape(input: f64) -> f64 { /// Keepalive anchor: `js_regexp_escape` is only called from codegen-emitted /// `.o`, so the auto-optimize whole-program LLVM rebuild would dead-strip it -/// without this `#[cfg_attr(feature = "keepalive-anchors", used)]` reference (see #3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +/// without this `#[used]` reference (see #3320). +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_REGEXP_ESCAPE: extern "C" fn(f64) -> f64 = js_regexp_escape; diff --git a/crates/perry-runtime/src/set.rs b/crates/perry-runtime/src/set.rs index df7412c4e3..c32108d788 100644 --- a/crates/perry-runtime/src/set.rs +++ b/crates/perry-runtime/src/set.rs @@ -716,7 +716,7 @@ fn jsvalue_eq(a: f64, b: f64) -> bool { /// Uses the O(1) hash index side-table. /// C-ABI: current elements-array index of `value` (SameValueZero), or `-1.0` if /// absent. Companion to `js_map_find_key_index` for the delete-safe Set `for-of` -/// fast path (#6075). Only invoked from generated IR, so `#[cfg_attr(feature = "keepalive-anchors", used)]` keeps it. +/// fast path (#6075). Only invoked from generated IR, so `#[used]` keeps it. #[no_mangle] pub extern "C" fn js_set_find_value_index(set_boxed: f64, value: f64) -> f64 { let set = clean_set_ptr(crate::value::js_nanbox_get_pointer(set_boxed) as *const SetHeader); @@ -725,7 +725,8 @@ pub extern "C" fn js_set_find_value_index(set_boxed: f64, value: f64) -> f64 { } unsafe { find_value_index(set, normalize_zero(value)) as f64 } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_FIND_VALUE_INDEX: extern "C" fn(f64, f64) -> f64 = js_set_find_value_index; pub(crate) unsafe fn find_value_index(set: *const SetHeader, value: f64) -> i32 { @@ -1178,47 +1179,65 @@ pub extern "C" fn js_set_delete_bool(set: *mut SetHeader, value: i32) -> i32 { // Codegen emits these string-key typed lowering helpers directly from // generated LLVM IR. Keep roots prevent whole-program LTO/dead-strip from // removing the exported symbols when the Rust crate graph has no caller. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_ADD_STRING: extern "C" fn( *mut SetHeader, *const StringHeader, ) -> *mut SetHeader = js_set_add_string; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_ADD_NUMBER: extern "C" fn(*mut SetHeader, f64) -> *mut SetHeader = js_set_add_number; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_HAS_STRING: extern "C" fn(*const SetHeader, *const StringHeader) -> i32 = js_set_has_string; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_HAS_NUMBER: extern "C" fn(*const SetHeader, f64) -> i32 = js_set_has_number; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_DELETE_STRING: extern "C" fn(*mut SetHeader, *const StringHeader) -> i32 = js_set_delete_string; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_DELETE_NUMBER: extern "C" fn(*mut SetHeader, f64) -> i32 = js_set_delete_number; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_ADD_I32: extern "C" fn(*mut SetHeader, i32) -> *mut SetHeader = js_set_add_i32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_HAS_I32: extern "C" fn(*const SetHeader, i32) -> i32 = js_set_has_i32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_DELETE_I32: extern "C" fn(*mut SetHeader, i32) -> i32 = js_set_delete_i32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_ADD_U32: extern "C" fn(*mut SetHeader, u32) -> *mut SetHeader = js_set_add_u32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_HAS_U32: extern "C" fn(*const SetHeader, u32) -> i32 = js_set_has_u32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_DELETE_U32: extern "C" fn(*mut SetHeader, u32) -> i32 = js_set_delete_u32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_ADD_F32: extern "C" fn(*mut SetHeader, f32) -> *mut SetHeader = js_set_add_f32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_HAS_F32: extern "C" fn(*const SetHeader, f32) -> i32 = js_set_has_f32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_DELETE_F32: extern "C" fn(*mut SetHeader, f32) -> i32 = js_set_delete_f32; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_ADD_BOOL: extern "C" fn(*mut SetHeader, i32) -> *mut SetHeader = js_set_add_bool; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_HAS_BOOL: extern "C" fn(*const SetHeader, i32) -> i32 = js_set_has_bool; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SET_DELETE_BOOL: extern "C" fn(*mut SetHeader, i32) -> i32 = js_set_delete_bool; /// Clear all elements from the set @@ -1803,22 +1822,29 @@ pub extern "C" fn js_set_is_disjoint_from(set: *const SetHeader, other: f64) -> // #2872: keepalive anchors so the auto-optimize whole-program-LLVM-bitcode // rebuild doesn't dead-strip these codegen-only `#[no_mangle]` entry points // (see project_auto_optimize_keepalive_3320 / PR #3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_UNION: extern "C" fn(*const SetHeader, f64) -> *mut SetHeader = js_set_union; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_INTERSECTION: extern "C" fn(*const SetHeader, f64) -> *mut SetHeader = js_set_intersection; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_DIFFERENCE: extern "C" fn(*const SetHeader, f64) -> *mut SetHeader = js_set_difference; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_SYMDIFF: extern "C" fn(*const SetHeader, f64) -> *mut SetHeader = js_set_symmetric_difference; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_IS_SUBSET: extern "C" fn(*const SetHeader, f64) -> i32 = js_set_is_subset_of; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_IS_SUPERSET: extern "C" fn(*const SetHeader, f64) -> i32 = js_set_is_superset_of; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SET_IS_DISJOINT: extern "C" fn(*const SetHeader, f64) -> i32 = js_set_is_disjoint_from; #[cfg(test)] diff --git a/crates/perry-runtime/src/string/locale.rs b/crates/perry-runtime/src/string/locale.rs index 0cbeb7e54c..45fbe12a19 100644 --- a/crates/perry-runtime/src/string/locale.rs +++ b/crates/perry-runtime/src/string/locale.rs @@ -410,16 +410,19 @@ pub extern "C" fn js_string_validate_collator_args(locales: f64, options: f64) { crate::intl::validate_locale_compare(locales, options); } -// `#[cfg_attr(feature = "keepalive-anchors", used)]` keepalive anchors: these `#[no_mangle]` entry points are reached +// `#[used]` keepalive anchors: these `#[no_mangle]` entry points are reached // only from generated `.o`, so the whole-program auto-optimize bitcode rebuild // would otherwise dead-strip them (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_LOCALE_LOWER: extern "C" fn(*const StringHeader, f64) -> *mut StringHeader = js_string_to_locale_lower_case; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_LOCALE_UPPER: extern "C" fn(*const StringHeader, f64) -> *mut StringHeader = js_string_to_locale_upper_case; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_COLLATOR_ARGS: extern "C" fn(f64, f64) = js_string_validate_collator_args; #[cfg(test)] diff --git a/crates/perry-runtime/src/string/pad.rs b/crates/perry-runtime/src/string/pad.rs index c7240e298f..4cd20a6325 100644 --- a/crates/perry-runtime/src/string/pad.rs +++ b/crates/perry-runtime/src/string/pad.rs @@ -27,10 +27,11 @@ pub extern "C" fn js_string_pad_fill(value: f64) -> *mut StringHeader { crate::builtins::js_string_coerce(value) } -// `#[cfg_attr(feature = "keepalive-anchors", used)]` keepalive: `js_string_pad_fill` is reached only from generated +// `#[used]` keepalive: `js_string_pad_fill` is reached only from generated // `.o`, so the whole-program auto-optimize bitcode rebuild would dead-strip it // without an anchor (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_PAD_FILL: extern "C" fn(f64) -> *mut StringHeader = js_string_pad_fill; /// Maximum string length Perry/V8 supports as a single `String`. This diff --git a/crates/perry-runtime/src/string/raw.rs b/crates/perry-runtime/src/string/raw.rs index 8204beb9fb..f35ffc48f2 100644 --- a/crates/perry-runtime/src/string/raw.rs +++ b/crates/perry-runtime/src/string/raw.rs @@ -114,6 +114,7 @@ fn throw_raw_type_error() -> ! { /// Keepalive anchor — `js_string_raw` is emitted only by generated code /// (the `String.raw(...)` call lowering), so the auto-optimize whole-program /// LLVM rebuild would otherwise dead-strip this `#[no_mangle]` symbol and -/// break linking (see PR #3320 / the `#[cfg_attr(feature = "keepalive-anchors", used)]` keepalive pattern). -#[cfg_attr(feature = "keepalive-anchors", used)] +/// break linking (see PR #3320 / the `#[used]` keepalive pattern). +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_STRING_RAW: extern "C" fn(f64, f64) -> *mut StringHeader = js_string_raw; diff --git a/crates/perry-runtime/src/string/slice_ops.rs b/crates/perry-runtime/src/string/slice_ops.rs index 960fde3c3a..3463f27127 100644 --- a/crates/perry-runtime/src/string/slice_ops.rs +++ b/crates/perry-runtime/src/string/slice_ops.rs @@ -178,10 +178,11 @@ pub extern "C" fn js_string_substr( ) } -// `#[cfg_attr(feature = "keepalive-anchors", used)]` keepalive: `js_string_substr` is reached only from generated `.o`, +// `#[used]` keepalive: `js_string_substr` is reached only from generated `.o`, // so the whole-program auto-optimize bitcode rebuild would dead-strip it // without an anchor (see project_auto_optimize_keepalive_3320). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_SUBSTR: extern "C" fn(*const StringHeader, f64, f64) -> *mut StringHeader = js_string_substr; @@ -524,10 +525,11 @@ pub extern "C" fn js_string_position_to_index(pos_f64: f64) -> i32 { } } -// `#[cfg_attr(feature = "keepalive-anchors", used)]` keepalive: `js_string_position_to_index` is reached only from +// `#[used]` keepalive: `js_string_position_to_index` is reached only from // generated `.o`, so the auto-optimize whole-program bitcode pass would // otherwise dead-strip it. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_POSITION_TO_INDEX: extern "C" fn(f64) -> i32 = js_string_position_to_index; /// Find the last index of a substring (-1 if not found). diff --git a/crates/perry-runtime/src/symbol/constructors.rs b/crates/perry-runtime/src/symbol/constructors.rs index adf6b58a82..e1da5b1eb0 100644 --- a/crates/perry-runtime/src/symbol/constructors.rs +++ b/crates/perry-runtime/src/symbol/constructors.rs @@ -179,8 +179,9 @@ fn is_well_known_symbol_member_name(name: &str) -> bool { // #1561-style force-keep: `js_symbol_computed_member` has no internal Rust // callers — only generated IR (perry-hir lowers `Symbol[key]` to a call to it), // so LTO / whole-program-bitcode link modes are free to internalize and -// dead-strip it. The `#[cfg_attr(feature = "keepalive-anchors", used)]` reference edge keeps the export alive. -#[cfg_attr(feature = "keepalive-anchors", used)] +// dead-strip it. The `#[used]` reference edge keeps the export alive. +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SYMBOL_COMPUTED_MEMBER: unsafe extern "C" fn(f64, f64) -> f64 = js_symbol_computed_member; diff --git a/crates/perry-runtime/src/symbol/iterator.rs b/crates/perry-runtime/src/symbol/iterator.rs index 54259d1c67..730fa74919 100644 --- a/crates/perry-runtime/src/symbol/iterator.rs +++ b/crates/perry-runtime/src/symbol/iterator.rs @@ -151,7 +151,8 @@ pub(crate) fn class_ref_resolves_iterator(val_f64: f64) -> bool { /// / guarded `__iter.return()` call in this validator. Returns the result /// unchanged when it is an object. // #1561-style force-keep: only generated IR calls this. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_ITERATOR_RESULT_VALIDATE: extern "C" fn(f64) -> f64 = js_iterator_result_validate; #[no_mangle] diff --git a/crates/perry-runtime/src/text.rs b/crates/perry-runtime/src/text.rs index 62f705c9be..d382dc7cbf 100644 --- a/crates/perry-runtime/src/text.rs +++ b/crates/perry-runtime/src/text.rs @@ -602,18 +602,23 @@ fn throw_invalid_encoded_data(encoding: &str) -> ! { /// Keepalive anchors — these `#[no_mangle]` fns are only called from /// generated `.o`, so the auto-optimize whole-program bitcode rebuild -/// would dead-strip them without `#[cfg_attr(feature = "keepalive-anchors", used)]` retention (see +/// would dead-strip them without `#[used]` retention (see /// [[project_auto_optimize_keepalive_3320]]). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TEXT_DECODER_NEW: extern "C" fn(f64, f64, f64) -> i64 = js_text_decoder_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TEXT_DECODER_DECODE: extern "C" fn(f64, f64) -> i64 = js_text_decoder_decode_llvm; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TEXT_DECODER_ENCODING: extern "C" fn(f64) -> *mut StringHeader = js_text_decoder_encoding; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TEXT_DECODER_FATAL: extern "C" fn(f64) -> f64 = js_text_decoder_fatal; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TEXT_DECODER_IGNORE_BOM: extern "C" fn(f64) -> f64 = js_text_decoder_ignore_bom; /// TextDecoder / TextEncoder registry-handle property surface for VALUE diff --git a/crates/perry-runtime/src/tls.rs b/crates/perry-runtime/src/tls.rs index 43ee85a141..5bd0c4be52 100644 --- a/crates/perry-runtime/src/tls.rs +++ b/crates/perry-runtime/src/tls.rs @@ -567,18 +567,24 @@ pub extern "C" fn js_tls_check_server_identity(hostname: f64, cert: f64) -> f64 // Keep-alive anchors so the auto-optimize bitcode rebuild does not dead-strip // these codegen-emitted `#[no_mangle]` runtime helpers (referenced from the // native dispatch table in perry-codegen). -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TLS_GET_CIPHERS: extern "C" fn() -> f64 = js_tls_get_ciphers; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TLS_GET_CA_CERTIFICATES: extern "C" fn(f64) -> f64 = js_tls_get_ca_certificates; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TLS_SET_DEFAULT_CA_CERTIFICATES: extern "C" fn(f64) -> f64 = js_tls_set_default_ca_certificates; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TLS_CREATE_SECURE_CONTEXT: extern "C" fn(f64) -> f64 = js_tls_create_secure_context; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TLS_SECURE_CONTEXT_NEW: extern "C" fn(f64) -> f64 = js_tls_secure_context_new; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TLS_CHECK_SERVER_IDENTITY: extern "C" fn(f64, f64) -> f64 = js_tls_check_server_identity; diff --git a/crates/perry-runtime/src/typed_feedback.rs b/crates/perry-runtime/src/typed_feedback.rs index eadb460c23..a2a8d83bc4 100644 --- a/crates/perry-runtime/src/typed_feedback.rs +++ b/crates/perry-runtime/src/typed_feedback.rs @@ -1994,7 +1994,8 @@ pub extern "C" fn js_typed_feedback_packed_f64_range_loop_guard( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_FEEDBACK_PACKED_F64_RANGE_LOOP_GUARD: extern "C" fn( u64, f64, @@ -2035,7 +2036,8 @@ pub extern "C" fn js_typed_feedback_packed_i32_array_loop_guard( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_FEEDBACK_PACKED_I32_ARRAY_LOOP_GUARD: extern "C" fn(u64, f64) -> i32 = js_typed_feedback_packed_i32_array_loop_guard; @@ -2072,7 +2074,8 @@ pub extern "C" fn js_typed_feedback_packed_u32_array_loop_guard( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_FEEDBACK_PACKED_U32_ARRAY_LOOP_GUARD: extern "C" fn(u64, f64) -> i32 = js_typed_feedback_packed_u32_array_loop_guard; diff --git a/crates/perry-runtime/src/typed_feedback/guards.rs b/crates/perry-runtime/src/typed_feedback/guards.rs index 39bbbae1e9..dc757e4694 100644 --- a/crates/perry-runtime/src/typed_feedback/guards.rs +++ b/crates/perry-runtime/src/typed_feedback/guards.rs @@ -1036,21 +1036,30 @@ pub extern "C" fn js_typed_feedback_closure_direct_call_guard( // whole-program thin-LTO + `strip=true` build internalizes + dead-strips them // — dangling the codegen call at final link (`Undefined symbols: // _js_typed_feedback_class_field_set_guard` for any class-field program). -// `typed_feedback.rs`'s `#[cfg_attr(feature = "keepalive-anchors", used)]` block covers the helpers defined there; +// `typed_feedback.rs`'s `#[used]` block covers the helpers defined there; // these typed fn-pointer statics extend the same `@llvm.used` retention to the // guard helpers defined here. (A `usize`/`*const()` cast does NOT survive // thin-LTO — only individual typed fn-pointer statics keep the symbol // external.) The statics must mirror each guard's exact signature, so keep // them in sync if a guard's parameter list changes. #[rustfmt::skip] +#[cfg(feature = "keepalive-anchors")] mod keep_guard_symbols { use super::*; - #[cfg_attr(feature = "keepalive-anchors", used)] static G0: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, i32) -> i32 = js_typed_feedback_class_field_get_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static G1: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, f64, i32) -> i32 = js_typed_feedback_class_field_set_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static G1C: extern "C" fn(u64, u64, u64, f64) = js_class_field_set_fallback; - #[cfg_attr(feature = "keepalive-anchors", used)] static G1D: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, f64, i32) = js_class_field_set_ic; - #[cfg_attr(feature = "keepalive-anchors", used)] static G1E: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, i32) -> f64 = js_class_field_get_ic; - #[cfg_attr(feature = "keepalive-anchors", used)] static G2: unsafe extern "C" fn(u64, f64, u32, *const ArrayHeader, *const i8, usize, *const u8) -> i32 = js_typed_feedback_method_direct_call_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static G3: extern "C" fn(u64, f64, *const u8, u32, u32) -> i32 = js_typed_feedback_closure_direct_call_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static G4: unsafe extern "C" fn(f64, u32, *const ArrayHeader) -> i32 = js_method_direct_shape_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static G0: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, i32) -> i32 = js_typed_feedback_class_field_get_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static G1: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, f64, i32) -> i32 = js_typed_feedback_class_field_set_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static G1C: extern "C" fn(u64, u64, u64, f64) = js_class_field_set_fallback; + #[cfg(feature = "keepalive-anchors")] +#[used] static G1D: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, f64, i32) = js_class_field_set_ic; + #[cfg(feature = "keepalive-anchors")] +#[used] static G1E: extern "C" fn(u64, f64, u32, *const ArrayHeader, *const crate::StringHeader, u32, i32) -> f64 = js_class_field_get_ic; + #[cfg(feature = "keepalive-anchors")] +#[used] static G2: unsafe extern "C" fn(u64, f64, u32, *const ArrayHeader, *const i8, usize, *const u8) -> i32 = js_typed_feedback_method_direct_call_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static G3: extern "C" fn(u64, f64, *const u8, u32, u32) -> i32 = js_typed_feedback_closure_direct_call_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static G4: unsafe extern "C" fn(f64, u32, *const ArrayHeader) -> i32 = js_method_direct_shape_guard; } diff --git a/crates/perry-runtime/src/typed_feedback/tests.rs b/crates/perry-runtime/src/typed_feedback/tests.rs index dee670913c..cddc80e03d 100644 --- a/crates/perry-runtime/src/typed_feedback/tests.rs +++ b/crates/perry-runtime/src/typed_feedback/tests.rs @@ -995,15 +995,15 @@ fn assert_lto_keepalive_anchor(src: &str, static_name: &str, signature: &str, ta let static_pos = src .find(static_name) .unwrap_or_else(|| panic!("missing keepalive static {static_name} for {target}")); - // Lookback must cover the full gated attribute line above the static - // (`#[cfg_attr(feature = "keepalive-anchors", used)]` + newline). + // Lookback must cover both gated keepalive attributes above the static. let start = static_pos.saturating_sub(96); let end = (static_pos + 512).min(src.len()); let window = &src[start..end]; assert!( - window.contains(r#"#[cfg_attr(feature = "keepalive-anchors", used)]"#), - "keepalive static {static_name} for {target} lacks the feature-gated #[used] \ - (cfg_attr keepalive-anchors) attribute" + window.contains(r#"#[cfg(feature = "keepalive-anchors")]"#) + && window.contains(r#"#[used]"#), + "keepalive static {static_name} for {target} lacks the keepalive-anchors \ + gate and #[used] attribute" ); assert!( window.contains(signature), diff --git a/crates/perry-runtime/src/typed_feedback/trace.rs b/crates/perry-runtime/src/typed_feedback/trace.rs index 4597834d1a..3e4a07661b 100644 --- a/crates/perry-runtime/src/typed_feedback/trace.rs +++ b/crates/perry-runtime/src/typed_feedback/trace.rs @@ -352,7 +352,7 @@ pub extern "C" fn js_typed_feedback_maybe_dump_trace() { // symbol, leaving the codegen call dangling (`Undefined symbols: // _js_typed_feedback_native_call_method` etc. at final link — which is exactly // how an instrumented async program failed to link under auto-optimize). The -// `#[cfg_attr(feature = "keepalive-anchors", used)]` typed fn-pointer statics below take the address of each helper, +// `#[used]` typed fn-pointer statics below take the address of each helper, // landing the functions themselves in `@llvm.used` so thin-LTO keeps them // external (not internalized) and the linker's `-dead_strip` honors them — the // same proven retention mechanism as `value/dyn_index.rs` / `process.rs` @@ -362,42 +362,75 @@ pub extern "C" fn js_typed_feedback_maybe_dump_trace() { // array forms were verified failing under auto-optimize). Function-pointer // types are `Sync`, so no wrapper is needed. #[rustfmt::skip] +#[cfg(feature = "keepalive-anchors")] mod keep_typed_feedback { use super::*; use crate::typed_feedback::guards::{ js_typed_feedback_native_call_method_apply_by_id, js_typed_feedback_native_call_method_by_id, }; - #[cfg_attr(feature = "keepalive-anchors", used)] static K00: extern "C" fn(u64, u32, *const u8, usize, *const u8, usize, *const u8, usize, *const u8, usize, *const u8, usize, *const u8, usize) = js_typed_feedback_register_site; - #[cfg_attr(feature = "keepalive-anchors", used)] static K01: extern "C" fn(u64) = js_typed_feedback_record_guard_pass; - #[cfg_attr(feature = "keepalive-anchors", used)] static K02: extern "C" fn(u64) = js_typed_feedback_record_guard_fail; - #[cfg_attr(feature = "keepalive-anchors", used)] static K03: extern "C" fn(u64) = js_typed_feedback_record_fallback_call; - #[cfg_attr(feature = "keepalive-anchors", used)] static K04: extern "C" fn(u64, *const ObjectHeader, *const crate::StringHeader) = js_typed_feedback_observe_property_get; - #[cfg_attr(feature = "keepalive-anchors", used)] static K05: extern "C" fn(u64, *mut ObjectHeader, *const crate::StringHeader) = js_typed_feedback_observe_property_set; - #[cfg_attr(feature = "keepalive-anchors", used)] static K06: extern "C" fn(u64, *const ObjectHeader, *const crate::StringHeader) -> f64 = js_typed_feedback_object_get_field_by_name_f64; - #[cfg_attr(feature = "keepalive-anchors", used)] static K07: extern "C" fn(u64, *mut ObjectHeader, *const crate::StringHeader, f64) = js_typed_feedback_object_set_field_by_name; - #[cfg_attr(feature = "keepalive-anchors", used)] static K08: extern "C" fn(u64, *mut ObjectHeader, *const crate::StringHeader, f64) = js_typed_feedback_object_set_field_by_name_fast; - #[cfg_attr(feature = "keepalive-anchors", used)] static K09: unsafe extern "C" fn(u64, f64, *const i8, usize, *const f64, usize) -> f64 = js_typed_feedback_native_call_method; - #[cfg_attr(feature = "keepalive-anchors", used)] static K10: unsafe extern "C" fn(u64, f64, *const i8, usize, i64) -> f64 = js_typed_feedback_native_call_method_apply; - #[cfg_attr(feature = "keepalive-anchors", used)] static K11: extern "C" fn(u64, *const ArrayHeader, u32) -> f64 = js_typed_feedback_array_get_f64; - #[cfg_attr(feature = "keepalive-anchors", used)] static K12: extern "C" fn(u64, f64, i32, i32) -> i32 = js_typed_feedback_plain_array_index_get_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K13: extern "C" fn(u64, f64, i32, i32) -> i32 = js_typed_feedback_numeric_array_index_get_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K14: extern "C" fn(u64, f64) -> i32 = js_typed_feedback_packed_f64_array_loop_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K15: extern "C" fn(u64, f64) -> i32 = js_typed_feedback_packed_u32_array_loop_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K16: extern "C" fn(u64, f64, f64) -> f64 = js_typed_feedback_array_index_get_fallback_boxed; - #[cfg_attr(feature = "keepalive-anchors", used)] static K17: extern "C" fn(u64, *mut ArrayHeader, u32, f64) = js_typed_feedback_array_set_f64; - #[cfg_attr(feature = "keepalive-anchors", used)] static K18: extern "C" fn(u64, *mut ArrayHeader, u32, f64) -> *mut ArrayHeader = js_typed_feedback_array_set_f64_extend; - #[cfg_attr(feature = "keepalive-anchors", used)] static K19: extern "C" fn(u64, f64, i32, f64, i32) -> i32 = js_typed_feedback_plain_array_index_set_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K20: extern "C" fn(u64, f64, i32, f64, i32) -> i32 = js_typed_feedback_numeric_array_index_set_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K21: extern "C" fn(u64, f64, f64) -> i32 = js_typed_feedback_numeric_array_push_guard; - #[cfg_attr(feature = "keepalive-anchors", used)] static K22: extern "C" fn(u64, f64, f64, f64) -> f64 = js_typed_feedback_array_index_set_fallback_boxed; - #[cfg_attr(feature = "keepalive-anchors", used)] static K23: extern "C" fn(u64, *const ArrayHeader, u32) = js_typed_feedback_observe_array_element; - #[cfg_attr(feature = "keepalive-anchors", used)] static K24: extern "C" fn(u64, *mut ArrayHeader, *const crate::StringHeader, f64) -> *mut ArrayHeader = js_typed_feedback_array_set_string_key; - #[cfg_attr(feature = "keepalive-anchors", used)] static K25: extern "C" fn(u64, *mut ArrayHeader, f64, f64) -> *mut ArrayHeader = js_typed_feedback_array_set_index_or_string; - #[cfg_attr(feature = "keepalive-anchors", used)] static K26: extern "C" fn(u64, i64, f64, f64) = js_typed_feedback_object_set_index_polymorphic; - #[cfg_attr(feature = "keepalive-anchors", used)] static K27: extern "C" fn(u64, *mut ObjectHeader, u32, *const crate::StringHeader, f64) = js_typed_feedback_object_set_unboxed_f64_field; - #[cfg_attr(feature = "keepalive-anchors", used)] static K28: extern "C" fn(u64, f64) -> f64 = js_typed_feedback_observe_helper_return; - #[cfg_attr(feature = "keepalive-anchors", used)] static K29: extern "C" fn() = js_typed_feedback_maybe_dump_trace; - #[cfg_attr(feature = "keepalive-anchors", used)] static K30: unsafe extern "C" fn(u64, f64, i64, *const f64, usize) -> f64 = js_typed_feedback_native_call_method_by_id; - #[cfg_attr(feature = "keepalive-anchors", used)] static K31: unsafe extern "C" fn(u64, f64, i64, i64) -> f64 = js_typed_feedback_native_call_method_apply_by_id; + #[cfg(feature = "keepalive-anchors")] +#[used] static K00: extern "C" fn(u64, u32, *const u8, usize, *const u8, usize, *const u8, usize, *const u8, usize, *const u8, usize, *const u8, usize) = js_typed_feedback_register_site; + #[cfg(feature = "keepalive-anchors")] +#[used] static K01: extern "C" fn(u64) = js_typed_feedback_record_guard_pass; + #[cfg(feature = "keepalive-anchors")] +#[used] static K02: extern "C" fn(u64) = js_typed_feedback_record_guard_fail; + #[cfg(feature = "keepalive-anchors")] +#[used] static K03: extern "C" fn(u64) = js_typed_feedback_record_fallback_call; + #[cfg(feature = "keepalive-anchors")] +#[used] static K04: extern "C" fn(u64, *const ObjectHeader, *const crate::StringHeader) = js_typed_feedback_observe_property_get; + #[cfg(feature = "keepalive-anchors")] +#[used] static K05: extern "C" fn(u64, *mut ObjectHeader, *const crate::StringHeader) = js_typed_feedback_observe_property_set; + #[cfg(feature = "keepalive-anchors")] +#[used] static K06: extern "C" fn(u64, *const ObjectHeader, *const crate::StringHeader) -> f64 = js_typed_feedback_object_get_field_by_name_f64; + #[cfg(feature = "keepalive-anchors")] +#[used] static K07: extern "C" fn(u64, *mut ObjectHeader, *const crate::StringHeader, f64) = js_typed_feedback_object_set_field_by_name; + #[cfg(feature = "keepalive-anchors")] +#[used] static K08: extern "C" fn(u64, *mut ObjectHeader, *const crate::StringHeader, f64) = js_typed_feedback_object_set_field_by_name_fast; + #[cfg(feature = "keepalive-anchors")] +#[used] static K09: unsafe extern "C" fn(u64, f64, *const i8, usize, *const f64, usize) -> f64 = js_typed_feedback_native_call_method; + #[cfg(feature = "keepalive-anchors")] +#[used] static K10: unsafe extern "C" fn(u64, f64, *const i8, usize, i64) -> f64 = js_typed_feedback_native_call_method_apply; + #[cfg(feature = "keepalive-anchors")] +#[used] static K11: extern "C" fn(u64, *const ArrayHeader, u32) -> f64 = js_typed_feedback_array_get_f64; + #[cfg(feature = "keepalive-anchors")] +#[used] static K12: extern "C" fn(u64, f64, i32, i32) -> i32 = js_typed_feedback_plain_array_index_get_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K13: extern "C" fn(u64, f64, i32, i32) -> i32 = js_typed_feedback_numeric_array_index_get_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K14: extern "C" fn(u64, f64) -> i32 = js_typed_feedback_packed_f64_array_loop_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K15: extern "C" fn(u64, f64) -> i32 = js_typed_feedback_packed_u32_array_loop_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K16: extern "C" fn(u64, f64, f64) -> f64 = js_typed_feedback_array_index_get_fallback_boxed; + #[cfg(feature = "keepalive-anchors")] +#[used] static K17: extern "C" fn(u64, *mut ArrayHeader, u32, f64) = js_typed_feedback_array_set_f64; + #[cfg(feature = "keepalive-anchors")] +#[used] static K18: extern "C" fn(u64, *mut ArrayHeader, u32, f64) -> *mut ArrayHeader = js_typed_feedback_array_set_f64_extend; + #[cfg(feature = "keepalive-anchors")] +#[used] static K19: extern "C" fn(u64, f64, i32, f64, i32) -> i32 = js_typed_feedback_plain_array_index_set_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K20: extern "C" fn(u64, f64, i32, f64, i32) -> i32 = js_typed_feedback_numeric_array_index_set_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K21: extern "C" fn(u64, f64, f64) -> i32 = js_typed_feedback_numeric_array_push_guard; + #[cfg(feature = "keepalive-anchors")] +#[used] static K22: extern "C" fn(u64, f64, f64, f64) -> f64 = js_typed_feedback_array_index_set_fallback_boxed; + #[cfg(feature = "keepalive-anchors")] +#[used] static K23: extern "C" fn(u64, *const ArrayHeader, u32) = js_typed_feedback_observe_array_element; + #[cfg(feature = "keepalive-anchors")] +#[used] static K24: extern "C" fn(u64, *mut ArrayHeader, *const crate::StringHeader, f64) -> *mut ArrayHeader = js_typed_feedback_array_set_string_key; + #[cfg(feature = "keepalive-anchors")] +#[used] static K25: extern "C" fn(u64, *mut ArrayHeader, f64, f64) -> *mut ArrayHeader = js_typed_feedback_array_set_index_or_string; + #[cfg(feature = "keepalive-anchors")] +#[used] static K26: extern "C" fn(u64, i64, f64, f64) = js_typed_feedback_object_set_index_polymorphic; + #[cfg(feature = "keepalive-anchors")] +#[used] static K27: extern "C" fn(u64, *mut ObjectHeader, u32, *const crate::StringHeader, f64) = js_typed_feedback_object_set_unboxed_f64_field; + #[cfg(feature = "keepalive-anchors")] +#[used] static K28: extern "C" fn(u64, f64) -> f64 = js_typed_feedback_observe_helper_return; + #[cfg(feature = "keepalive-anchors")] +#[used] static K29: extern "C" fn() = js_typed_feedback_maybe_dump_trace; + #[cfg(feature = "keepalive-anchors")] +#[used] static K30: unsafe extern "C" fn(u64, f64, i64, *const f64, usize) -> f64 = js_typed_feedback_native_call_method_by_id; + #[cfg(feature = "keepalive-anchors")] +#[used] static K31: unsafe extern "C" fn(u64, f64, i64, i64) -> f64 = js_typed_feedback_native_call_method_apply_by_id; } diff --git a/crates/perry-runtime/src/typedarray/access.rs b/crates/perry-runtime/src/typedarray/access.rs index d46968c323..4d2af8d797 100644 --- a/crates/perry-runtime/src/typedarray/access.rs +++ b/crates/perry-runtime/src/typedarray/access.rs @@ -86,8 +86,9 @@ pub extern "C" fn js_typed_array_read_int32(ta: *const TypedArrayHeader, index: // Codegen-only export: the inline checked-i32 read emits the call in // `perry-codegen/src/expr/i32_fast_path.rs`; a whole-program bitcode link is // otherwise free to internalize and dead-strip it (it has no internal Rust -// caller). The `#[cfg_attr(feature = "keepalive-anchors", used)]` anchor pins it, mirroring the getter above. -#[cfg_attr(feature = "keepalive-anchors", used)] +// caller). The `#[used]` anchor pins it, mirroring the getter above. +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_ARRAY_READ_INT32: extern "C" fn(*const TypedArrayHeader, i32) -> i32 = js_typed_array_read_int32; @@ -120,7 +121,8 @@ pub extern "C" fn js_typed_array_read_f64(ta: *const TypedArrayHeader, index: i3 } // Codegen-only export (see the i32 sibling above): pin under whole-program LTO. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_ARRAY_READ_F64: extern "C" fn(*const TypedArrayHeader, i32) -> f64 = js_typed_array_read_f64; @@ -149,8 +151,9 @@ pub extern "C" fn js_typed_array_index_get_dynamic(ta: *const TypedArrayHeader, // `js_dyn_index_get`, this export has zero internal Rust callers — it is only // invoked from generated LLVM IR (codegen emits the call in // `perry-codegen/src/expr/index_get.rs`), so a whole-program bitcode link is -// free to internalize and dead-strip it. The `#[cfg_attr(feature = "keepalive-anchors", used)]` anchor pins it. -#[cfg_attr(feature = "keepalive-anchors", used)] +// free to internalize and dead-strip it. The `#[used]` anchor pins it. +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_ARRAY_INDEX_GET_DYNAMIC: extern "C" fn(*const TypedArrayHeader, f64) -> f64 = js_typed_array_index_get_dynamic; @@ -561,7 +564,8 @@ pub extern "C" fn js_uint8array_index_get_value( // #6088: force-keep the JS-value Uint8Array index getter under LTO / // auto-optimize — it has zero internal Rust callers (codegen emits the only // call), so a whole-program bitcode link is otherwise free to dead-strip it. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_UINT8ARRAY_INDEX_GET_VALUE: extern "C" fn(*const TypedArrayHeader, i32) -> f64 = js_uint8array_index_get_value; diff --git a/crates/perry-runtime/src/typedarray_props.rs b/crates/perry-runtime/src/typedarray_props.rs index ddbea5d240..d15f041761 100644 --- a/crates/perry-runtime/src/typedarray_props.rs +++ b/crates/perry-runtime/src/typedarray_props.rs @@ -747,7 +747,8 @@ pub extern "C" fn js_typed_array_index_set_dynamic( } } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_TYPED_ARRAY_INDEX_SET_DYNAMIC: extern "C" fn( *mut TypedArrayHeader, f64, diff --git a/crates/perry-runtime/src/url/abort.rs b/crates/perry-runtime/src/url/abort.rs index c5952d7946..7fd7c364c9 100644 --- a/crates/perry-runtime/src/url/abort.rs +++ b/crates/perry-runtime/src/url/abort.rs @@ -635,13 +635,16 @@ pub extern "C" fn js_abort_signal_any( // #2582: keepalive anchors so the auto-optimize whole-program LLVM bitcode // rebuild doesn't internalize + dead-strip these codegen-only `#[no_mangle]` // entry points (see project_auto_optimize_keepalive_3320). These are only -// referenced from generated `.o`, so without `#[cfg_attr(feature = "keepalive-anchors", used)]` they vanish. -#[cfg_attr(feature = "keepalive-anchors", used)] +// referenced from generated `.o`, so without `#[used]` they vanish. +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ABORT_SIGNAL_ABORT: extern "C" fn(f64) -> *mut ObjectHeader = js_abort_signal_abort; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ABORT_SIGNAL_ANY: extern "C" fn(*mut crate::array::ArrayHeader) -> *mut ObjectHeader = js_abort_signal_any; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_ABORT_SIGNAL_THROW_IF_ABORTED: extern "C" fn(*mut ObjectHeader) -> f64 = js_abort_signal_throw_if_aborted; diff --git a/crates/perry-runtime/src/url/node_compat.rs b/crates/perry-runtime/src/url/node_compat.rs index 31687f92e5..57320c16d7 100644 --- a/crates/perry-runtime/src/url/node_compat.rs +++ b/crates/perry-runtime/src/url/node_compat.rs @@ -840,12 +840,21 @@ const LEGACY_URL_KEYS: [&str; 12] = [ ]; fn create_legacy_url_object(values: [f64; 12]) -> *mut ObjectHeader { - let obj = js_object_alloc(0, LEGACY_URL_KEYS.len() as u32); - let mut keys = js_array_alloc(LEGACY_URL_KEYS.len() as u32); + let scope = crate::gc::RuntimeHandleScope::new(); + let value_handles = scope.root_nanbox_f64_slice(&values); + let obj_handle = scope.root_raw_mut_ptr(js_object_alloc(0, LEGACY_URL_KEYS.len() as u32)); + let keys_handle = scope.root_raw_mut_ptr(js_array_alloc(LEGACY_URL_KEYS.len() as u32)); for (index, key) in LEGACY_URL_KEYS.iter().enumerate() { - keys = js_array_push_f64(keys, create_string_f64(key)); - js_object_set_field_f64(obj, index as u32, values[index]); + let keys = keys_handle.get_raw_mut_ptr::(); + keys_handle.set_raw_mut_ptr(js_array_push_f64(keys, create_string_f64(key))); + js_object_set_field_f64( + obj_handle.get_raw_mut_ptr::(), + index as u32, + value_handles[index].get_nanbox_f64(), + ); } + let obj = obj_handle.get_raw_mut_ptr::(); + let keys = keys_handle.get_raw_mut_ptr::(); js_object_set_keys(obj, keys); obj } diff --git a/crates/perry-runtime/src/url/search_params.rs b/crates/perry-runtime/src/url/search_params.rs index 8fcedfcf7a..dcad2ff909 100644 --- a/crates/perry-runtime/src/url/search_params.rs +++ b/crates/perry-runtime/src/url/search_params.rs @@ -127,7 +127,8 @@ pub extern "C" fn js_url_search_params_subclass_init(this: f64, init: f64) -> f6 /// Reached only from codegen-emitted IR (the `Expr::SuperCall` URLSearchParams /// arm); pin it so the auto-optimize bitcode rebuild's dead-strip can't drop it. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_URL_SEARCH_PARAMS_SUBCLASS_INIT: extern "C" fn(f64, f64) -> f64 = js_url_search_params_subclass_init; diff --git a/crates/perry-runtime/src/validators.rs b/crates/perry-runtime/src/validators.rs index 9bb5cb3ff6..b4f3ccb698 100644 --- a/crates/perry-runtime/src/validators.rs +++ b/crates/perry-runtime/src/validators.rs @@ -338,7 +338,7 @@ pub fn validate_port(value: f64, name: &str) -> u16 { // hard segfault rather than node's catchable `TypeError`. These helpers take // the *original* NaN-boxed value (as `f64`) plus the argument name, so codegen // can emit a `call void` validation BEFORE the unbox, throwing node's typed -// error instead of crashing. The `#[cfg_attr(feature = "keepalive-anchors", used)]` anchors below keep them alive +// error instead of crashing. The `#[used]` anchors below keep them alive // through the auto-optimize whole-program rebuild (the bitcode internalizer // drops `#[no_mangle]` symbols only referenced from generated `.o`). // ============================================================================ @@ -423,12 +423,15 @@ pub unsafe extern "C" fn js_runtime_validate_integer_arg( validate_integer(value, &name, min, max); } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_STRING_ARG: unsafe extern "C" fn(f64, *const u8, u32) = js_runtime_validate_string_arg; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_CRYPTO_KEY_ARG: unsafe extern "C" fn(f64, *const u8, u32) = js_runtime_validate_crypto_key_arg; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_VALIDATE_INTEGER_ARG: unsafe extern "C" fn(f64, *const u8, u32, f64, f64) = js_runtime_validate_integer_arg; diff --git a/crates/perry-runtime/src/value/dyn_index.rs b/crates/perry-runtime/src/value/dyn_index.rs index 2a8fe80f6c..1b8b0ec287 100644 --- a/crates/perry-runtime/src/value/dyn_index.rs +++ b/crates/perry-runtime/src/value/dyn_index.rs @@ -641,9 +641,12 @@ pub extern "C" fn js_is_undefined_or_bare_nan(value: f64) -> i32 { // link keeps these exports via the program's own undefined references, so // the anchors compile out there. Function-pointer types are `Sync`, so no // wrapper is needed. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_DYN_INDEX_GET: extern "C" fn(f64, f64) -> f64 = js_dyn_index_get; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_DYN_INDEX_SET: extern "C" fn(f64, f64, f64) -> f64 = js_dyn_index_set; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_IS_UNDEFINED_OR_BARE_NAN: extern "C" fn(f64) -> i32 = js_is_undefined_or_bare_nan; diff --git a/crates/perry-runtime/src/value/dynamic_arith.rs b/crates/perry-runtime/src/value/dynamic_arith.rs index 90cde483be..061d39f8d2 100644 --- a/crates/perry-runtime/src/value/dynamic_arith.rs +++ b/crates/perry-runtime/src/value/dynamic_arith.rs @@ -913,15 +913,20 @@ pub unsafe extern "C" fn js_dynamic_ushr(a: f64, b: f64) -> f64 { (ai >> bi) as f64 } -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DYNAMIC_POW: unsafe extern "C" fn(f64, f64) -> f64 = js_dynamic_pow; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DYNAMIC_USHR: unsafe extern "C" fn(f64, f64) -> f64 = js_dynamic_ushr; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_DYNAMIC_BITNOT: unsafe extern "C" fn(f64) -> f64 = js_dynamic_bitnot; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_TO_NUMERIC: unsafe extern "C" fn(f64) -> f64 = js_to_numeric; -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_NUMERIC_STEP: unsafe extern "C" fn(f64, i32) -> f64 = js_numeric_step; #[cfg(test)] diff --git a/crates/perry-runtime/src/value/nanbox.rs b/crates/perry-runtime/src/value/nanbox.rs index 95e873c6b4..38e9828b34 100644 --- a/crates/perry-runtime/src/value/nanbox.rs +++ b/crates/perry-runtime/src/value/nanbox.rs @@ -351,7 +351,8 @@ pub extern "C" fn js_switch_strict_equals(a: f64, b: f64) -> i32 { // #1561-style force-keep: only generated IR calls this — see // value/dyn_index.rs for the rationale. -#[cfg_attr(feature = "keepalive-anchors", used)] +#[cfg(feature = "keepalive-anchors")] +#[used] static KEEP_JS_SWITCH_STRICT_EQUALS: extern "C" fn(f64, f64) -> i32 = js_switch_strict_equals; /// Check if a NaN-boxed f64 value represents a string. diff --git a/crates/perry-runtime/src/yoga.rs b/crates/perry-runtime/src/yoga.rs index 52b48cd4cc..78dde43e57 100644 --- a/crates/perry-runtime/src/yoga.rs +++ b/crates/perry-runtime/src/yoga.rs @@ -719,7 +719,8 @@ pub extern "C" fn js_yoga_get_computed_edge(id: f64, kind: f64, edge: f64) -> f6 // Typed statics (coercion, not a const ptr→int cast). macro_rules! keep { ($n:ident : $t:ty = $f:ident) => { - #[cfg_attr(feature = "keepalive-anchors", used)] + #[cfg(feature = "keepalive-anchors")] + #[used] static $n: $t = $f; }; } diff --git a/crates/perry/src/commands/compile/optimized_libs/tests.rs b/crates/perry/src/commands/compile/optimized_libs/tests.rs index 59db29d9d7..7845a4f65b 100644 --- a/crates/perry/src/commands/compile/optimized_libs/tests.rs +++ b/crates/perry/src/commands/compile/optimized_libs/tests.rs @@ -1,7 +1,6 @@ use super::no_auto::build_missing_prebuilt_ext_lib; use super::*; use std::path::Path; -use std::sync::{Mutex, OnceLock}; use crate::commands::stdlib_features::{compute_required_features, features_to_cargo_arg}; use crate::OutputFormat; diff --git a/crates/perry/src/commands/compile/resolve.rs b/crates/perry/src/commands/compile/resolve.rs index 9e2695d229..e8acfe9577 100644 --- a/crates/perry/src/commands/compile/resolve.rs +++ b/crates/perry/src/commands/compile/resolve.rs @@ -900,22 +900,30 @@ pub(super) fn resolve_exports_candidates( collect(entry, subpath, out); return; } - for (key, entry) in map.iter() { - if key.contains('*') { - let parts: Vec<&str> = key.splitn(2, '*').collect(); - if parts.len() == 2 { - let (prefix, suffix) = (parts[0], parts[1]); - if subpath.starts_with(prefix) && subpath.ends_with(suffix) { - let matched = &subpath[prefix.len()..subpath.len() - suffix.len()]; - let mut templates = Vec::new(); - collect(entry, subpath, &mut templates); - for template in templates { - let resolved = template.replace('*', matched); - if !out.contains(&resolved) { - out.push(resolved); - } - } - } + let mut patterns: Vec<_> = map + .iter() + .filter_map(|(key, entry)| { + let (prefix, suffix) = key.split_once('*')?; + let end = subpath.len().checked_sub(suffix.len())?; + (subpath.starts_with(prefix) + && subpath.ends_with(suffix) + && prefix.len() <= end) + .then_some((prefix, suffix, end, entry)) + }) + .collect(); + patterns.sort_by(|a, b| { + b.0.len() + .cmp(&a.0.len()) + .then_with(|| (b.0.len() + b.1.len()).cmp(&(a.0.len() + a.1.len()))) + }); + for (prefix, _, end, entry) in patterns { + let matched = &subpath[prefix.len()..end]; + let mut templates = Vec::new(); + collect(entry, subpath, &mut templates); + for template in templates { + let resolved = template.replace('*', matched); + if !out.contains(&resolved) { + out.push(resolved); } } } diff --git a/crates/perry/src/commands/compile/resolve/tests.rs b/crates/perry/src/commands/compile/resolve/tests.rs index 26f5254f7f..47b9e05cd6 100644 --- a/crates/perry/src/commands/compile/resolve/tests.rs +++ b/crates/perry/src/commands/compile/resolve/tests.rs @@ -1820,6 +1820,30 @@ mod exports_candidates_tests { ); } + #[test] + fn wildcard_candidates_reject_overlapping_bounds() { + let exports: serde_json::Value = serde_json::json!({ + "./long*long": "./wrong/*.js" + }); + assert!(resolve_exports_candidates(&exports, "./long").is_empty()); + } + + #[test] + fn wildcard_candidates_prefer_the_most_specific_pattern() { + let exports: serde_json::Value = serde_json::json!({ + "./*": "./broad/*.js", + "./features/*": "./specific/*.js" + }); + let candidates = resolve_exports_candidates(&exports, "./features/a"); + assert_eq!( + candidates, + vec![ + "./specific/a.js".to_string(), + "./broad/features/a.js".to_string() + ] + ); + } + /// #5237 — a Node "exports" *fallback array* (an ordered list of targets, /// here a conditions-object followed by a plain string) must expand to its /// inner targets. Before the fix the array form produced no candidates at From f0978de68d552bdab1fd19174862ab41d8dea68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Thu, 30 Jul 2026 04:12:22 +0200 Subject: [PATCH 15/18] fix(workspace): restore container compose default build --- Cargo.toml | 1 + changelog.d/6837-rust-warnings-to-zero.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 88408d9d85..3adf804c6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,6 +84,7 @@ members = [ # Build each platform package explicitly for its applicable target. default-members = [ "crates/perry", + "crates/perry-container-compose", ] # Aggressive release optimizations for small, fast binaries diff --git a/changelog.d/6837-rust-warnings-to-zero.md b/changelog.d/6837-rust-warnings-to-zero.md index 28a55b853e..332c075af5 100644 --- a/changelog.d/6837-rust-warnings-to-zero.md +++ b/changelog.d/6837-rust-warnings-to-zero.md @@ -29,3 +29,7 @@ diagnostics and temporal are off. Those items are gated at the item, not suppressed. The cross-host UI crates (ios/tvos/watchOS/visionos/android/ windows/gtk4) cannot be checked from a macOS or Linux host and are untouched. + +- Restore `perry-container-compose` to the workspace default build set. This + keeps the container feature's auto-optimized archive available and satisfies + the workspace invariant exercised by the hermetic test tier. From 88f591bed932b881042a6457247f98234ecc277e Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Thu, 30 Jul 2026 08:25:06 +0200 Subject: [PATCH 16/18] fix(gc): poll after allocating loop controls --- crates/perry-codegen/src/stmt/loops.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/crates/perry-codegen/src/stmt/loops.rs b/crates/perry-codegen/src/stmt/loops.rs index 990ca06872..1c308e4cf4 100644 --- a/crates/perry-codegen/src/stmt/loops.rs +++ b/crates/perry-codegen/src/stmt/loops.rs @@ -5079,6 +5079,7 @@ fn lower_for_after_init_with_i32_bound( if let Some(cond_expr) = condition { let cv = lower_expr(ctx, cond_expr)?; let i1 = lower_truthy(ctx, &cv, cond_expr); + emit_gc_loop_safepoint(ctx, &[], &[cond_expr]); ctx.block().cond_br(&i1, &body_label, &exit_label); } else { ctx.block().br(&body_label); @@ -5091,6 +5092,7 @@ fn lower_for_after_init_with_i32_bound( if let Some(cond_expr) = condition { let cv = lower_expr(ctx, cond_expr)?; let i1 = lower_truthy(ctx, &cv, cond_expr); + emit_gc_loop_safepoint(ctx, &[], &[cond_expr]); ctx.block().cond_br(&i1, &body_label, &exit_label); } else { // `for (;;)` — unconditional jump into the body. May be an @@ -5140,8 +5142,7 @@ fn lower_for_after_init_with_i32_bound( ctx.block().asm_sideeffect_barrier(); } if !ctx.block().is_terminated() { - let controls: Vec<&perry_hir::Expr> = condition.into_iter().chain(update).collect(); - emit_gc_loop_safepoint(ctx, body, &controls); + emit_gc_loop_safepoint(ctx, body, &[]); ctx.block().br(&update_label); } @@ -5149,6 +5150,7 @@ fn lower_for_after_init_with_i32_bound( ctx.current_block = update_idx; if let Some(update_expr) = update { let _ = lower_expr(ctx, update_expr)?; + emit_gc_loop_safepoint(ctx, &[], &[update_expr]); } // #6072: a loop-private i32 counter is invisible to the `Update` lowering // (it is not in `ctx.i32_counter_slots`), so advance it here. The classifier @@ -5238,11 +5240,12 @@ fn moving_safepoint_polls_enabled() -> bool { }) } -/// Emit a `js_gc_loop_safepoint()` poll at a loop back-edge. Call this AFTER -/// `clear_loop_body_shadow_slots` and only where the block is not terminated: -/// at that point the loop-body expression has completed, so every live heap -/// value is a named local on the shadow stack (no unspilled register temps) — -/// a precise-root safepoint where a deferred copying minor can MOVE survivors. +/// Emit a `js_gc_loop_safepoint()` after an allocating loop segment has +/// completed and only where the block is not terminated. Body calls must run +/// after `clear_loop_body_shadow_slots`; control calls run after their result +/// has been reduced or discarded. At either point every live heap value is a +/// named local on the shadow stack (no unspilled register temps) — a precise +/// root safepoint where a deferred copying minor can MOVE survivors. /// /// COVERAGE (Phase 2, follow-up): currently wired into the generic `while`, /// `do..while`, and `for` back-edges. The specialized/versioned `for`-loop @@ -7009,6 +7012,7 @@ pub(crate) fn lower_while( ctx.current_block = cond_idx; let cv = lower_expr(ctx, condition)?; let i1 = lower_truthy(ctx, &cv, condition); + emit_gc_loop_safepoint(ctx, &[], &[condition]); ctx.block().cond_br(&i1, &body_label, &exit_label); // For while-loops, continue jumps back to the cond block. @@ -7046,7 +7050,7 @@ pub(crate) fn lower_while( ctx.block().asm_sideeffect_barrier(); } if !ctx.block().is_terminated() { - emit_gc_loop_safepoint(ctx, body, &[condition]); + emit_gc_loop_safepoint(ctx, body, &[]); ctx.block().br(&cond_label); } ctx.active_region_id = previous_region_id; @@ -7104,13 +7108,14 @@ pub(crate) fn lower_do_while( ctx.block().asm_sideeffect_barrier(); } if !ctx.block().is_terminated() { - emit_gc_loop_safepoint(ctx, body, &[condition]); + emit_gc_loop_safepoint(ctx, body, &[]); ctx.block().br(&cond_label); } ctx.current_block = cond_idx; let cv = lower_expr(ctx, condition)?; let i1 = lower_truthy(ctx, &cv, condition); + emit_gc_loop_safepoint(ctx, &[], &[condition]); ctx.block().cond_br(&i1, &body_label, &exit_label); ctx.active_region_id = previous_region_id; From a2f6abb0af7290e26c2c06b4808e98ce227c52bb Mon Sep 17 00:00:00 2001 From: TheHypnoo Date: Thu, 30 Jul 2026 08:30:05 +0200 Subject: [PATCH 17/18] fix(warnings): remove redundant iterator unsafe block --- crates/perry-runtime/src/array/iter_object.rs | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/crates/perry-runtime/src/array/iter_object.rs b/crates/perry-runtime/src/array/iter_object.rs index 9f6ef39baf..06dbd9caef 100644 --- a/crates/perry-runtime/src/array/iter_object.rs +++ b/crates/perry-runtime/src/array/iter_object.rs @@ -88,24 +88,22 @@ pub fn array_values_iter_null_done( if arr_ptr.is_null() { return f64::from_bits(TAG_UNDEFINED); } - unsafe { - let obj = js_object_alloc(ARRAY_ITERATOR_CLASS_ID, 5); - js_object_set_field( - obj, - 0, - JSValue::from_bits(js_nanbox_pointer(arr_ptr as i64).to_bits()), - ); - js_object_set_field(obj, 1, JSValue::number(0.0)); - js_object_set_field(obj, 2, JSValue::number(KIND_VALUES_NULL_DONE as f64)); - js_object_set_field( - obj, - 3, - JSValue::pointer(iteration_epoch as *const _ as *const u8), - ); - js_object_set_field(obj, 4, JSValue::number(epoch as f64)); - crate::object::attach_iterator_prototype(obj, ARRAY_ITERATOR_CLASS_ID); - js_nanbox_pointer(obj as i64) - } + let obj = js_object_alloc(ARRAY_ITERATOR_CLASS_ID, 5); + js_object_set_field( + obj, + 0, + JSValue::from_bits(js_nanbox_pointer(arr_ptr as i64).to_bits()), + ); + js_object_set_field(obj, 1, JSValue::number(0.0)); + js_object_set_field(obj, 2, JSValue::number(KIND_VALUES_NULL_DONE as f64)); + js_object_set_field( + obj, + 3, + JSValue::pointer(iteration_epoch as *const _ as *const u8), + ); + js_object_set_field(obj, 4, JSValue::number(epoch as f64)); + crate::object::attach_iterator_prototype(obj, ARRAY_ITERATOR_CLASS_ID); + js_nanbox_pointer(obj as i64) } /// `arr.keys()` iterator — yields each index `0..length`. From 040b35eea5df131bd1f4fbea66594ad04356510b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Thu, 30 Jul 2026 08:39:19 +0200 Subject: [PATCH 18/18] fix(warnings): remove redundant iterator unsafe block --- crates/perry-runtime/src/array/iter_object.rs | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/crates/perry-runtime/src/array/iter_object.rs b/crates/perry-runtime/src/array/iter_object.rs index 9f6ef39baf..06dbd9caef 100644 --- a/crates/perry-runtime/src/array/iter_object.rs +++ b/crates/perry-runtime/src/array/iter_object.rs @@ -88,24 +88,22 @@ pub fn array_values_iter_null_done( if arr_ptr.is_null() { return f64::from_bits(TAG_UNDEFINED); } - unsafe { - let obj = js_object_alloc(ARRAY_ITERATOR_CLASS_ID, 5); - js_object_set_field( - obj, - 0, - JSValue::from_bits(js_nanbox_pointer(arr_ptr as i64).to_bits()), - ); - js_object_set_field(obj, 1, JSValue::number(0.0)); - js_object_set_field(obj, 2, JSValue::number(KIND_VALUES_NULL_DONE as f64)); - js_object_set_field( - obj, - 3, - JSValue::pointer(iteration_epoch as *const _ as *const u8), - ); - js_object_set_field(obj, 4, JSValue::number(epoch as f64)); - crate::object::attach_iterator_prototype(obj, ARRAY_ITERATOR_CLASS_ID); - js_nanbox_pointer(obj as i64) - } + let obj = js_object_alloc(ARRAY_ITERATOR_CLASS_ID, 5); + js_object_set_field( + obj, + 0, + JSValue::from_bits(js_nanbox_pointer(arr_ptr as i64).to_bits()), + ); + js_object_set_field(obj, 1, JSValue::number(0.0)); + js_object_set_field(obj, 2, JSValue::number(KIND_VALUES_NULL_DONE as f64)); + js_object_set_field( + obj, + 3, + JSValue::pointer(iteration_epoch as *const _ as *const u8), + ); + js_object_set_field(obj, 4, JSValue::number(epoch as f64)); + crate::object::attach_iterator_prototype(obj, ARRAY_ITERATOR_CLASS_ID); + js_nanbox_pointer(obj as i64) } /// `arr.keys()` iterator — yields each index `0..length`.