From 2330a30fbf15b44fcc6619a64c1bd819737ac9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 3 Oct 2026 22:21:06 +0000 Subject: [PATCH 1/2] perf(codegen): a store emits the class-setter arm only for a name a compiled class declares as a setter --- .../PENDING-regfix-accessor-arm-names.md | 7 ++ crates/perry-codegen/src/codegen/closure.rs | 1 + .../src/codegen/emission_order_tests.rs | 1 + crates/perry-codegen/src/codegen/entry.rs | 2 + .../perry-codegen/src/codegen/entry/tests.rs | 1 + crates/perry-codegen/src/codegen/function.rs | 1 + .../codegen/imported_global_order_tests.rs | 1 + crates/perry-codegen/src/codegen/method.rs | 1 + .../src/codegen/method_static.rs | 1 + crates/perry-codegen/src/codegen/mod.rs | 7 +- .../src/codegen/number_exactness_tests.rs | 1 + crates/perry-codegen/src/codegen/opts.rs | 72 +++++++++++++++++++ .../collectors/proven_this_routing_tests.rs | 1 + .../src/expr/array_push_guard_tests.rs | 1 + .../src/expr/call_spread_short_tests.rs | 1 + .../src/expr/class_field_barrier_tests.rs | 1 + .../class_method_arguments_object_tests.rs | 1 + .../src/expr/conforming_layout_note_tests.rs | 1 + crates/perry-codegen/src/expr/mod.rs | 10 +++ .../src/expr/property_get/tests.rs | 47 ++++++++++++ .../src/expr/put_value_store_ic.rs | 7 +- crates/perry-codegen/src/lib.rs | 4 +- .../src/lower_call/alloc_hot_tests.rs | 1 + .../src/lower_call/typed_shape_bake_tests.rs | 1 + .../src/native_root_coverage/mod.rs | 1 + .../src/stmt/boxed_slot_no_root_tests.rs | 1 + .../src/stmt/class_field_loop_tests.rs | 1 + .../src/stmt/element_shape_loop_tests.rs | 1 + .../src/stmt/prealloc_module_global_tests.rs | 1 + .../src/temp_root_coverage/mod.rs | 1 + .../src/type_analysis/numeric/tests.rs | 1 + .../tests/app_window_config_options.rs | 1 + .../tests/argless_builtin_extra_args.rs | 1 + .../tests/class_field_store_pointer_test.rs | 1 + .../perry-codegen/tests/class_keys_gc_root.rs | 1 + .../tests/constructor_recursion.rs | 1 + .../tests/crypto_hash_chain_lowering.rs | 1 + .../tests/destructure_call_location.rs | 1 + .../tests/i64_spec_ternary_recursion.rs | 1 + .../tests/ios_platform_api_lowering.rs | 1 + .../tests/large_object_barriers.rs | 1 + .../tests/loop_safepoint_purity.rs | 1 + .../tests/macos_bundle_chdir_gate.rs | 1 + .../tests/native_proof_buffer_views.rs | 1 + .../tests/native_proof_regressions.rs | 1 + .../tests/node_test_mock_property_presence.rs | 1 + .../tests/perry_builtin_name_collision.rs | 1 + .../tests/release_boxes_lowering.rs | 1 + .../tests/scalar_replaced_slot_roots.rs | 1 + .../tests/shadow_slot_hygiene.rs | 1 + .../tests/static_symbol_hygiene.rs | 1 + .../tests/temp_root_operand_temporaries.rs | 1 + crates/perry-codegen/tests/typed_feedback.rs | 1 + .../tests/typed_shape_descriptor.rs | 1 + .../tests/typed_shape_descriptors.rs | 1 + .../src/commands/compile/object_cache.rs | 10 +++ .../object_cache/object_cache_tests.rs | 1 + .../src/commands/compile/run_pipeline.rs | 8 +++ 58 files changed, 215 insertions(+), 7 deletions(-) create mode 100644 changelog.d/PENDING-regfix-accessor-arm-names.md diff --git a/changelog.d/PENDING-regfix-accessor-arm-names.md b/changelog.d/PENDING-regfix-accessor-arm-names.md new file mode 100644 index 0000000000..aba2826827 --- /dev/null +++ b/changelog.d/PENDING-regfix-accessor-arm-names.md @@ -0,0 +1,7 @@ +A static-key store site emits the class-setter arm (#10498) only for a property +name that some compiled class of the program declares as a setter. The runtime +admits an entry only for a declared accessor, so every other store carried an +arm it could never take and ran it on every miss. The driver collects the +names over all modules and passes them to codegen; they are part of the object +cache key. Key-add cells lose 13 instructions per operation, and the compiled +tsc workload drops 1.1 MB. diff --git a/crates/perry-codegen/src/codegen/closure.rs b/crates/perry-codegen/src/codegen/closure.rs index 0ffe47a1e7..6ea3685804 100644 --- a/crates/perry-codegen/src/codegen/closure.rs +++ b/crates/perry-codegen/src/codegen/closure.rs @@ -1223,6 +1223,7 @@ pub(super) fn compile_closure( imported_vars: &cross_module.imported_vars, imported_object_literals: &cross_module.imported_object_literals, short_spread_method_candidates: &cross_module.short_spread_method_candidates, + program_class_accessor_names: cross_module.program_class_accessor_names.as_deref(), object_literal_method_candidates: &cross_module.object_literal_method_candidates, compile_time_constants: native_facts.compile_time_constants(), target_triple: &cross_module.target_triple, diff --git a/crates/perry-codegen/src/codegen/emission_order_tests.rs b/crates/perry-codegen/src/codegen/emission_order_tests.rs index 1f9480fe8b..0f73c21af7 100644 --- a/crates/perry-codegen/src/codegen/emission_order_tests.rs +++ b/crates/perry-codegen/src/codegen/emission_order_tests.rs @@ -92,6 +92,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/codegen/entry.rs b/crates/perry-codegen/src/codegen/entry.rs index 94f4711445..6e27c8fb0a 100644 --- a/crates/perry-codegen/src/codegen/entry.rs +++ b/crates/perry-codegen/src/codegen/entry.rs @@ -841,6 +841,7 @@ pub(super) fn compile_module_entry( imported_vars: &cross_module.imported_vars, imported_object_literals: &cross_module.imported_object_literals, short_spread_method_candidates: &cross_module.short_spread_method_candidates, + program_class_accessor_names: cross_module.program_class_accessor_names.as_deref(), object_literal_method_candidates: &cross_module.object_literal_method_candidates, compile_time_constants: main_native_facts.compile_time_constants(), target_triple: &cross_module.target_triple, @@ -1714,6 +1715,7 @@ pub(super) fn compile_module_entry( imported_vars: &cross_module.imported_vars, imported_object_literals: &cross_module.imported_object_literals, short_spread_method_candidates: &cross_module.short_spread_method_candidates, + program_class_accessor_names: cross_module.program_class_accessor_names.as_deref(), object_literal_method_candidates: &cross_module.object_literal_method_candidates, compile_time_constants: init_native_facts.compile_time_constants(), target_triple: &cross_module.target_triple, diff --git a/crates/perry-codegen/src/codegen/entry/tests.rs b/crates/perry-codegen/src/codegen/entry/tests.rs index b7fb7052cf..094a150c5a 100644 --- a/crates/perry-codegen/src/codegen/entry/tests.rs +++ b/crates/perry-codegen/src/codegen/entry/tests.rs @@ -27,6 +27,7 @@ fn entry_opts(output_type: &str) -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/codegen/function.rs b/crates/perry-codegen/src/codegen/function.rs index 71e76369cf..ad2e04660a 100644 --- a/crates/perry-codegen/src/codegen/function.rs +++ b/crates/perry-codegen/src/codegen/function.rs @@ -1363,6 +1363,7 @@ pub(super) fn compile_function( imported_vars: &cross_module.imported_vars, imported_object_literals: &cross_module.imported_object_literals, short_spread_method_candidates: &cross_module.short_spread_method_candidates, + program_class_accessor_names: cross_module.program_class_accessor_names.as_deref(), object_literal_method_candidates: &cross_module.object_literal_method_candidates, compile_time_constants: native_facts.compile_time_constants(), target_triple: &cross_module.target_triple, diff --git a/crates/perry-codegen/src/codegen/imported_global_order_tests.rs b/crates/perry-codegen/src/codegen/imported_global_order_tests.rs index 6f7f170d55..77cab4022a 100644 --- a/crates/perry-codegen/src/codegen/imported_global_order_tests.rs +++ b/crates/perry-codegen/src/codegen/imported_global_order_tests.rs @@ -61,6 +61,7 @@ fn emit(classes: bool, objects: bool) -> String { let opts = CompileOptions { emit_ir_only: true, short_spread_method_candidates: Arc::new(short), + program_class_accessor_names: Default::default(), object_literal_method_candidates: Arc::new(object), ..Default::default() }; diff --git a/crates/perry-codegen/src/codegen/method.rs b/crates/perry-codegen/src/codegen/method.rs index 88fecf49a7..43997c5646 100644 --- a/crates/perry-codegen/src/codegen/method.rs +++ b/crates/perry-codegen/src/codegen/method.rs @@ -712,6 +712,7 @@ pub(super) fn compile_method( imported_vars: &cross_module.imported_vars, imported_object_literals: &cross_module.imported_object_literals, short_spread_method_candidates: &cross_module.short_spread_method_candidates, + program_class_accessor_names: cross_module.program_class_accessor_names.as_deref(), object_literal_method_candidates: &cross_module.object_literal_method_candidates, compile_time_constants: native_facts.compile_time_constants(), target_triple: &cross_module.target_triple, diff --git a/crates/perry-codegen/src/codegen/method_static.rs b/crates/perry-codegen/src/codegen/method_static.rs index d75e79b6b4..d0a721b429 100644 --- a/crates/perry-codegen/src/codegen/method_static.rs +++ b/crates/perry-codegen/src/codegen/method_static.rs @@ -391,6 +391,7 @@ pub(in crate::codegen) fn compile_static_method( imported_vars: &cross_module.imported_vars, imported_object_literals: &cross_module.imported_object_literals, short_spread_method_candidates: &cross_module.short_spread_method_candidates, + program_class_accessor_names: cross_module.program_class_accessor_names.as_deref(), object_literal_method_candidates: &cross_module.object_literal_method_candidates, compile_time_constants: native_facts.compile_time_constants(), target_triple: &cross_module.target_triple, diff --git a/crates/perry-codegen/src/codegen/mod.rs b/crates/perry-codegen/src/codegen/mod.rs index 68d86af161..3edfaecbc6 100644 --- a/crates/perry-codegen/src/codegen/mod.rs +++ b/crates/perry-codegen/src/codegen/mod.rs @@ -286,9 +286,9 @@ pub(crate) use helpers::{ }; pub use opts::{ namespace_member_class_key, namespace_member_func_key, namespace_member_var_key, AppMetadata, - CompileOptions, ExportedObjectLiteralCapability, FpContractMode, ImportedClass, - ImportedObjectLiteral, ImportedObjectLiteralMethod, NamespaceEntry, NamespaceEntryKind, - ObjectLiteralMethodCandidate, ShortSpreadMethodCandidate, + ClassAccessorNames, CompileOptions, ExportedObjectLiteralCapability, FpContractMode, + ImportedClass, ImportedObjectLiteral, ImportedObjectLiteralMethod, NamespaceEntry, + NamespaceEntryKind, ObjectLiteralMethodCandidate, ShortSpreadMethodCandidate, }; pub(crate) use opts::{CrossModuleCtx, ImportedCtor}; pub(crate) use param_guard::scalar_descriptor_rep; @@ -2609,6 +2609,7 @@ fn compile_module_impl( namespace_member_origin_names: opts.namespace_member_origin_names, imported_async_funcs: opts.imported_async_funcs, short_spread_method_candidates: Arc::clone(&opts.short_spread_method_candidates), + program_class_accessor_names: opts.program_class_accessor_names.clone(), object_literal_method_candidates: Arc::clone(&opts.object_literal_method_candidates), local_async_funcs, local_generator_funcs, diff --git a/crates/perry-codegen/src/codegen/number_exactness_tests.rs b/crates/perry-codegen/src/codegen/number_exactness_tests.rs index 723fb8b85c..585e880415 100644 --- a/crates/perry-codegen/src/codegen/number_exactness_tests.rs +++ b/crates/perry-codegen/src/codegen/number_exactness_tests.rs @@ -51,6 +51,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/codegen/opts.rs b/crates/perry-codegen/src/codegen/opts.rs index 480d0b316f..ccf51ce98e 100644 --- a/crates/perry-codegen/src/codegen/opts.rs +++ b/crates/perry-codegen/src/codegen/opts.rs @@ -120,6 +120,71 @@ pub fn namespace_member_func_key(namespace: &str, member: &str) -> String { format!("\0perry_namespace_func\0{namespace}\0{member}") } +/// The property names the program's compiled classes declare as accessors +/// (`get k()` / `set k(v)`), across every module (#10498). +/// +/// A store site's class-setter arm can only ever take an entry for a name some +/// compiled class declares as a setter: the runtime admits an entry only when +/// the receiver's class chain declares the accessor +/// (`class_chain_has_instance_accessor`). A store whose name no class declares +/// therefore emits no arm; it misses to the runtime as before the arm existed, +/// which still asks the same entry first. The getters are collected alongside. +#[derive(Debug, Clone, Default)] +pub struct ClassAccessorNames { + getters: std::collections::HashSet, + setters: std::collections::HashSet, +} + +impl ClassAccessorNames { + /// The accessor names declared by the classes of `modules` (instance and + /// static alike: a superset only costs an arm). + pub fn collect<'m>(modules: impl IntoIterator) -> Self { + let mut names = Self::default(); + for module in modules { + for class in &module.classes { + names + .getters + .extend(class.getters.iter().map(|(name, _)| name.clone())); + names + .setters + .extend(class.setters.iter().map(|(name, _)| name.clone())); + } + } + names + } + + /// The names given, for a caller that already knows them. + pub fn from_names(getters: G, setters: S) -> Self + where + G: IntoIterator, + S: IntoIterator, + { + Self { + getters: getters.into_iter().collect(), + setters: setters.into_iter().collect(), + } + } + + /// May a compiled class declare a getter named `name`? + pub fn may_get(&self, name: &str) -> bool { + self.getters.contains(name) + } + + /// May a compiled class declare a setter named `name`? + pub fn may_set(&self, name: &str) -> bool { + self.setters.contains(name) + } + + /// A stable rendering for the object-cache key. + pub fn cache_key(&self) -> String { + let mut getters: Vec<&str> = self.getters.iter().map(String::as_str).collect(); + let mut setters: Vec<&str> = self.setters.iter().map(String::as_str).collect(); + getters.sort_unstable(); + setters.sort_unstable(); + format!("get:{}|set:{}", getters.join(","), setters.join(",")) + } +} + /// Options controlling code generation for a single module. #[derive(Debug, Clone, Default)] pub struct CompileOptions { @@ -296,6 +361,11 @@ pub struct CompileOptions { /// reverse-flow metadata: the calling module need not import the producer. pub object_literal_method_candidates: std::sync::Arc>>, + /// The whole program's class accessor names ([`ClassAccessorNames`]), + /// which decide where the class-setter arms are emitted. `None` (a + /// standalone or test compile that did not collect them) emits the arm + /// at every store site. + pub program_class_accessor_names: Option>, /// Imported enum member lists, keyed by the local name under which /// the enum is visible in this module. pub imported_enums: Vec<(String, Vec<(String, perry_hir::EnumValue)>)>, @@ -859,6 +929,8 @@ pub(crate) struct CrossModuleCtx { std::sync::Arc>>, pub object_literal_method_candidates: std::sync::Arc>>, + /// See `CompileOptions::program_class_accessor_names`. + pub program_class_accessor_names: Option>, /// FuncIds of locally-defined async functions in this module. Populated /// from `hir.functions.is_async`. Used by `is_promise_expr` to refine /// `let p = asyncFn();` to `Promise(_)` so subsequent `p.then(cb)` diff --git a/crates/perry-codegen/src/collectors/proven_this_routing_tests.rs b/crates/perry-codegen/src/collectors/proven_this_routing_tests.rs index 29b2b74b1c..ee697d4413 100644 --- a/crates/perry-codegen/src/collectors/proven_this_routing_tests.rs +++ b/crates/perry-codegen/src/collectors/proven_this_routing_tests.rs @@ -62,6 +62,7 @@ fn ir_opts(is_entry: bool) -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/expr/array_push_guard_tests.rs b/crates/perry-codegen/src/expr/array_push_guard_tests.rs index e376515618..1398d68321 100644 --- a/crates/perry-codegen/src/expr/array_push_guard_tests.rs +++ b/crates/perry-codegen/src/expr/array_push_guard_tests.rs @@ -66,6 +66,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/expr/call_spread_short_tests.rs b/crates/perry-codegen/src/expr/call_spread_short_tests.rs index fdf9f58f16..cbab52b3e5 100644 --- a/crates/perry-codegen/src/expr/call_spread_short_tests.rs +++ b/crates/perry-codegen/src/expr/call_spread_short_tests.rs @@ -128,6 +128,7 @@ fn emit_reverse_dependency_consumer() -> String { let opts = crate::CompileOptions { emit_ir_only: true, short_spread_method_candidates: std::sync::Arc::new(by_method), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), ..Default::default() }; diff --git a/crates/perry-codegen/src/expr/class_field_barrier_tests.rs b/crates/perry-codegen/src/expr/class_field_barrier_tests.rs index 647d62062a..e24df3d9f3 100644 --- a/crates/perry-codegen/src/expr/class_field_barrier_tests.rs +++ b/crates/perry-codegen/src/expr/class_field_barrier_tests.rs @@ -84,6 +84,7 @@ pub(super) fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/expr/class_method_arguments_object_tests.rs b/crates/perry-codegen/src/expr/class_method_arguments_object_tests.rs index 7adec8f974..224d0d7b02 100644 --- a/crates/perry-codegen/src/expr/class_method_arguments_object_tests.rs +++ b/crates/perry-codegen/src/expr/class_method_arguments_object_tests.rs @@ -78,6 +78,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/expr/conforming_layout_note_tests.rs b/crates/perry-codegen/src/expr/conforming_layout_note_tests.rs index bf93d877aa..5c9b918c46 100644 --- a/crates/perry-codegen/src/expr/conforming_layout_note_tests.rs +++ b/crates/perry-codegen/src/expr/conforming_layout_note_tests.rs @@ -33,6 +33,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/expr/mod.rs b/crates/perry-codegen/src/expr/mod.rs index 30d3b8c3be..56ed8c6583 100644 --- a/crates/perry-codegen/src/expr/mod.rs +++ b/crates/perry-codegen/src/expr/mod.rs @@ -871,6 +871,9 @@ pub(crate) struct FnCtx<'a> { /// calls. See `CompileOptions::object_literal_method_candidates`. pub object_literal_method_candidates: &'a std::collections::HashMap>, + /// The whole program's class accessor names. See + /// `CompileOptions::program_class_accessor_names`. + pub program_class_accessor_names: Option<&'a crate::ClassAccessorNames>, /// FFI manifest: `name -> (params, return)` from `package.json` /// `nativeLibrary.functions`. Descriptors use the shared native-library /// ABI vocabulary. `lower_call` consults @@ -2675,6 +2678,13 @@ mod inline_cache_name_tests { } impl<'a> FnCtx<'a> { + /// May some compiled class of the program declare a setter named `name`? + /// Where this is false a store site emits no class-setter arm. + pub(crate) fn program_may_declare_setter(&self, name: &str) -> bool { + self.program_class_accessor_names + .is_none_or(|names| names.may_set(name)) + } + /// Is `e` the `this` of a STATIC class member — i.e. a receiver that holds /// the class CONSTRUCTOR (an INT32 class ref) rather than an instance? /// diff --git a/crates/perry-codegen/src/expr/property_get/tests.rs b/crates/perry-codegen/src/expr/property_get/tests.rs index 60c0fb6829..95806a76d9 100644 --- a/crates/perry-codegen/src/expr/property_get/tests.rs +++ b/crates/perry-codegen/src/expr/property_get/tests.rs @@ -44,6 +44,7 @@ fn ir_opts(debug_locations: bool, module_source: Option<&str>) -> CompileOptions constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), @@ -1832,3 +1833,49 @@ fn the_generic_slow_read_is_called_only_after_the_front_declines() { #[path = "array_length_tests.rs"] mod array_length; + +/// The #10498 class-setter arm only where a compiled class of the program +/// declares a setter of the store's name: the runtime admits an entry only for +/// a declared accessor (`class_chain_has_instance_accessor`), so any other +/// site's arm is code that can never be taken and work on every miss. The +/// read site's getter arm is not gated. +#[test] +fn class_setter_arms_are_emitted_only_for_declared_setter_names() { + use crate::ClassAccessorNames; + fn module_storing(property: &str) -> Module { + let mut m = module_reading(property); + m.init.push(Stmt::Expr(Expr::PropertySet { + object: Box::new(Expr::LocalGet(1)), + property: property.to_string(), + value: Box::new(Expr::Number(1.0)), + })); + m + } + let emit = |names: Option| { + let mut opts = ir_opts(false, None); + opts.program_class_accessor_names = names.map(std::sync::Arc::new); + String::from_utf8(compile_module(&module_storing("price"), opts).unwrap()) + .expect("LLVM IR should be UTF-8") + }; + let read_arm = "pic.acc.empty"; + let store_arm = "put.pic.acc"; + // Names not collected (a standalone compile): the store keeps its arm. + let unknown = emit(None); + assert!(unknown.contains(store_arm), "{unknown}"); + // No class declares a setter `price` (a getter alone does not count). + let getter_only = emit(Some(ClassAccessorNames::from_names( + ["price".to_string()], + ["total".to_string()], + ))); + assert!(!getter_only.contains(store_arm), "{getter_only}"); + assert!( + getter_only.contains(read_arm), + "the read arm is not gated:\n{getter_only}" + ); + // A declared setter keeps the store arm. + let setter = emit(Some(ClassAccessorNames::from_names( + Vec::new(), + ["price".to_string()], + ))); + assert!(setter.contains(store_arm), "{setter}"); +} diff --git a/crates/perry-codegen/src/expr/put_value_store_ic.rs b/crates/perry-codegen/src/expr/put_value_store_ic.rs index 31659ae3ae..d5bd1f3747 100644 --- a/crates/perry-codegen/src/expr/put_value_store_ic.rs +++ b/crates/perry-codegen/src/expr/put_value_store_ic.rs @@ -313,8 +313,11 @@ pub(crate) fn emit_static_store_ic( // #10498: a store to a key the receiver inherits as a compiled class // setter calls it inline (`setter_arm`), ahead of the key-add memo and the // ways. 64-bit targets only: the entry is a record of 8-byte words. - let setter_entry = setter_arm_target(ctx.target_triple) - .then(|| ctx.new_block(&format!("{STORE_IC_STEM}.acc"))); + // Only for a name some compiled class of the program declares as a setter: + // no other site can ever take an entry. + let setter_entry = (setter_arm_target(ctx.target_triple) + && ctx.program_may_declare_setter(property)) + .then(|| ctx.new_block(&format!("{STORE_IC_STEM}.acc"))); let shape_miss = setter_entry .map(|idx| ctx.block_label(idx)) .unwrap_or_else(|| add_label.clone()); diff --git a/crates/perry-codegen/src/lib.rs b/crates/perry-codegen/src/lib.rs index 8a71959f96..3bee5be153 100644 --- a/crates/perry-codegen/src/lib.rs +++ b/crates/perry-codegen/src/lib.rs @@ -92,8 +92,8 @@ pub use codegen::{ decode_static_seed, encode_static_seed, module_birth_shapes, namespace_member_class_key, namespace_member_func_key, namespace_member_var_key, resolve_target_triple, short_spread_method_capabilities, take_module_static_seeds, user_function_symbol, AppMetadata, - BirthProto, BirthShape, CompileOptions, ConstFnBirth, ConstructorContracts, CtorAbi, - DefinedClassShape, ExportedObjectLiteralCapability, FpContractMode, ImportedClass, + BirthProto, BirthShape, ClassAccessorNames, CompileOptions, ConstFnBirth, ConstructorContracts, + CtorAbi, DefinedClassShape, ExportedObjectLiteralCapability, FpContractMode, ImportedClass, ImportedObjectLiteral, ImportedObjectLiteralMethod, ModuleBirth, NamespaceEntry, NamespaceEntryKind, ObjectLiteralMethodCandidate, ProgramClassShapeIds, ResolvedConstructorContracts, ShortSpreadMethodCandidate, TypedMasks, STATIC_SEED_FORMAT, diff --git a/crates/perry-codegen/src/lower_call/alloc_hot_tests.rs b/crates/perry-codegen/src/lower_call/alloc_hot_tests.rs index b972689e2d..f3d6496d21 100644 --- a/crates/perry-codegen/src/lower_call/alloc_hot_tests.rs +++ b/crates/perry-codegen/src/lower_call/alloc_hot_tests.rs @@ -81,6 +81,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/lower_call/typed_shape_bake_tests.rs b/crates/perry-codegen/src/lower_call/typed_shape_bake_tests.rs index 2eca37b443..295e6f112b 100644 --- a/crates/perry-codegen/src/lower_call/typed_shape_bake_tests.rs +++ b/crates/perry-codegen/src/lower_call/typed_shape_bake_tests.rs @@ -51,6 +51,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/native_root_coverage/mod.rs b/crates/perry-codegen/src/native_root_coverage/mod.rs index fc18b2bc1f..003fcd44ee 100644 --- a/crates/perry-codegen/src/native_root_coverage/mod.rs +++ b/crates/perry-codegen/src/native_root_coverage/mod.rs @@ -140,6 +140,7 @@ pub(crate) fn ir_opts(target: &str, is_entry: bool) -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/stmt/boxed_slot_no_root_tests.rs b/crates/perry-codegen/src/stmt/boxed_slot_no_root_tests.rs index 2e77a2ab1d..de3c94b29d 100644 --- a/crates/perry-codegen/src/stmt/boxed_slot_no_root_tests.rs +++ b/crates/perry-codegen/src/stmt/boxed_slot_no_root_tests.rs @@ -30,6 +30,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/stmt/class_field_loop_tests.rs b/crates/perry-codegen/src/stmt/class_field_loop_tests.rs index ec3955dd67..35f8fe8910 100644 --- a/crates/perry-codegen/src/stmt/class_field_loop_tests.rs +++ b/crates/perry-codegen/src/stmt/class_field_loop_tests.rs @@ -37,6 +37,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/stmt/element_shape_loop_tests.rs b/crates/perry-codegen/src/stmt/element_shape_loop_tests.rs index d1b10db7c6..99d7e534a8 100644 --- a/crates/perry-codegen/src/stmt/element_shape_loop_tests.rs +++ b/crates/perry-codegen/src/stmt/element_shape_loop_tests.rs @@ -47,6 +47,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/stmt/prealloc_module_global_tests.rs b/crates/perry-codegen/src/stmt/prealloc_module_global_tests.rs index e6ce415fc7..7cc0bc550a 100644 --- a/crates/perry-codegen/src/stmt/prealloc_module_global_tests.rs +++ b/crates/perry-codegen/src/stmt/prealloc_module_global_tests.rs @@ -65,6 +65,7 @@ pub(super) fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/temp_root_coverage/mod.rs b/crates/perry-codegen/src/temp_root_coverage/mod.rs index 7602425808..002d1e7e96 100644 --- a/crates/perry-codegen/src/temp_root_coverage/mod.rs +++ b/crates/perry-codegen/src/temp_root_coverage/mod.rs @@ -75,6 +75,7 @@ pub(crate) fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/src/type_analysis/numeric/tests.rs b/crates/perry-codegen/src/type_analysis/numeric/tests.rs index a3a72c1bc9..6f447446c7 100644 --- a/crates/perry-codegen/src/type_analysis/numeric/tests.rs +++ b/crates/perry-codegen/src/type_analysis/numeric/tests.rs @@ -37,6 +37,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/app_window_config_options.rs b/crates/perry-codegen/tests/app_window_config_options.rs index 12f1277fa4..9853319493 100644 --- a/crates/perry-codegen/tests/app_window_config_options.rs +++ b/crates/perry-codegen/tests/app_window_config_options.rs @@ -37,6 +37,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/argless_builtin_extra_args.rs b/crates/perry-codegen/tests/argless_builtin_extra_args.rs index 8437a8197d..7a79570a16 100644 --- a/crates/perry-codegen/tests/argless_builtin_extra_args.rs +++ b/crates/perry-codegen/tests/argless_builtin_extra_args.rs @@ -34,6 +34,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/class_field_store_pointer_test.rs b/crates/perry-codegen/tests/class_field_store_pointer_test.rs index 668351ac23..7b722a4a41 100644 --- a/crates/perry-codegen/tests/class_field_store_pointer_test.rs +++ b/crates/perry-codegen/tests/class_field_store_pointer_test.rs @@ -43,6 +43,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/class_keys_gc_root.rs b/crates/perry-codegen/tests/class_keys_gc_root.rs index 77cd00058c..9126797f19 100644 --- a/crates/perry-codegen/tests/class_keys_gc_root.rs +++ b/crates/perry-codegen/tests/class_keys_gc_root.rs @@ -52,6 +52,7 @@ fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/constructor_recursion.rs b/crates/perry-codegen/tests/constructor_recursion.rs index 1f6115cbce..6cb2de9793 100644 --- a/crates/perry-codegen/tests/constructor_recursion.rs +++ b/crates/perry-codegen/tests/constructor_recursion.rs @@ -27,6 +27,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/crypto_hash_chain_lowering.rs b/crates/perry-codegen/tests/crypto_hash_chain_lowering.rs index 48e16c60a0..b054a586dd 100644 --- a/crates/perry-codegen/tests/crypto_hash_chain_lowering.rs +++ b/crates/perry-codegen/tests/crypto_hash_chain_lowering.rs @@ -43,6 +43,7 @@ fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/destructure_call_location.rs b/crates/perry-codegen/tests/destructure_call_location.rs index dee330223e..26a37485a1 100644 --- a/crates/perry-codegen/tests/destructure_call_location.rs +++ b/crates/perry-codegen/tests/destructure_call_location.rs @@ -44,6 +44,7 @@ fn base_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/i64_spec_ternary_recursion.rs b/crates/perry-codegen/tests/i64_spec_ternary_recursion.rs index 2dfee805e2..7295b1689c 100644 --- a/crates/perry-codegen/tests/i64_spec_ternary_recursion.rs +++ b/crates/perry-codegen/tests/i64_spec_ternary_recursion.rs @@ -44,6 +44,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/ios_platform_api_lowering.rs b/crates/perry-codegen/tests/ios_platform_api_lowering.rs index c1d75fe544..a6853b9e16 100644 --- a/crates/perry-codegen/tests/ios_platform_api_lowering.rs +++ b/crates/perry-codegen/tests/ios_platform_api_lowering.rs @@ -29,6 +29,7 @@ fn options(target: Option<&str>) -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: Default::default(), diff --git a/crates/perry-codegen/tests/large_object_barriers.rs b/crates/perry-codegen/tests/large_object_barriers.rs index 788ced5edf..8d524d89f6 100644 --- a/crates/perry-codegen/tests/large_object_barriers.rs +++ b/crates/perry-codegen/tests/large_object_barriers.rs @@ -27,6 +27,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/loop_safepoint_purity.rs b/crates/perry-codegen/tests/loop_safepoint_purity.rs index 155e24f8cd..bc6c6bfbd5 100644 --- a/crates/perry-codegen/tests/loop_safepoint_purity.rs +++ b/crates/perry-codegen/tests/loop_safepoint_purity.rs @@ -65,6 +65,7 @@ fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/macos_bundle_chdir_gate.rs b/crates/perry-codegen/tests/macos_bundle_chdir_gate.rs index fff40deeee..f2a88dd086 100644 --- a/crates/perry-codegen/tests/macos_bundle_chdir_gate.rs +++ b/crates/perry-codegen/tests/macos_bundle_chdir_gate.rs @@ -33,6 +33,7 @@ fn entry_opts(target: Option<&str>) -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/native_proof_buffer_views.rs b/crates/perry-codegen/tests/native_proof_buffer_views.rs index 3a59f7fe5f..514361e3ff 100644 --- a/crates/perry-codegen/tests/native_proof_buffer_views.rs +++ b/crates/perry-codegen/tests/native_proof_buffer_views.rs @@ -58,6 +58,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/native_proof_regressions.rs b/crates/perry-codegen/tests/native_proof_regressions.rs index f9b9e1641e..3db6b65462 100644 --- a/crates/perry-codegen/tests/native_proof_regressions.rs +++ b/crates/perry-codegen/tests/native_proof_regressions.rs @@ -65,6 +65,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/node_test_mock_property_presence.rs b/crates/perry-codegen/tests/node_test_mock_property_presence.rs index 591f5b7cd6..507dca868a 100644 --- a/crates/perry-codegen/tests/node_test_mock_property_presence.rs +++ b/crates/perry-codegen/tests/node_test_mock_property_presence.rs @@ -30,6 +30,7 @@ fn ir_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/perry_builtin_name_collision.rs b/crates/perry-codegen/tests/perry_builtin_name_collision.rs index 97d7a3ff6a..b7efe7d5b2 100644 --- a/crates/perry-codegen/tests/perry_builtin_name_collision.rs +++ b/crates/perry-codegen/tests/perry_builtin_name_collision.rs @@ -45,6 +45,7 @@ fn base_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/release_boxes_lowering.rs b/crates/perry-codegen/tests/release_boxes_lowering.rs index 5375a4a629..37e64eccce 100644 --- a/crates/perry-codegen/tests/release_boxes_lowering.rs +++ b/crates/perry-codegen/tests/release_boxes_lowering.rs @@ -44,6 +44,7 @@ fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/scalar_replaced_slot_roots.rs b/crates/perry-codegen/tests/scalar_replaced_slot_roots.rs index 4378725e0d..9e51f30d21 100644 --- a/crates/perry-codegen/tests/scalar_replaced_slot_roots.rs +++ b/crates/perry-codegen/tests/scalar_replaced_slot_roots.rs @@ -84,6 +84,7 @@ fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/shadow_slot_hygiene.rs b/crates/perry-codegen/tests/shadow_slot_hygiene.rs index 3084bb1fba..c84eb69d3c 100644 --- a/crates/perry-codegen/tests/shadow_slot_hygiene.rs +++ b/crates/perry-codegen/tests/shadow_slot_hygiene.rs @@ -57,6 +57,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/static_symbol_hygiene.rs b/crates/perry-codegen/tests/static_symbol_hygiene.rs index 4cb7caca5b..e6495a8bfe 100644 --- a/crates/perry-codegen/tests/static_symbol_hygiene.rs +++ b/crates/perry-codegen/tests/static_symbol_hygiene.rs @@ -27,6 +27,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/temp_root_operand_temporaries.rs b/crates/perry-codegen/tests/temp_root_operand_temporaries.rs index 1a529af4a5..dd64df9b56 100644 --- a/crates/perry-codegen/tests/temp_root_operand_temporaries.rs +++ b/crates/perry-codegen/tests/temp_root_operand_temporaries.rs @@ -85,6 +85,7 @@ fn entry_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/typed_feedback.rs b/crates/perry-codegen/tests/typed_feedback.rs index cb1e9eda17..7c46979529 100644 --- a/crates/perry-codegen/tests/typed_feedback.rs +++ b/crates/perry-codegen/tests/typed_feedback.rs @@ -111,6 +111,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/typed_shape_descriptor.rs b/crates/perry-codegen/tests/typed_shape_descriptor.rs index 53b88b8b83..2106238463 100644 --- a/crates/perry-codegen/tests/typed_shape_descriptor.rs +++ b/crates/perry-codegen/tests/typed_shape_descriptor.rs @@ -27,6 +27,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry-codegen/tests/typed_shape_descriptors.rs b/crates/perry-codegen/tests/typed_shape_descriptors.rs index 5594fc8e70..c7d24fba5d 100644 --- a/crates/perry-codegen/tests/typed_shape_descriptors.rs +++ b/crates/perry-codegen/tests/typed_shape_descriptors.rs @@ -30,6 +30,7 @@ fn empty_opts() -> CompileOptions { constructor_param_counts: Default::default(), imported_classes: Vec::new(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry/src/commands/compile/object_cache.rs b/crates/perry/src/commands/compile/object_cache.rs index 0ee606c85f..e896fbc208 100644 --- a/crates/perry/src/commands/compile/object_cache.rs +++ b/crates/perry/src/commands/compile/object_cache.rs @@ -887,6 +887,16 @@ fn compute_object_cache_key_with_env( h.field("short_spread_method_candidates", &value); } + // #10498: other modules' class accessors decide which of this module's + // sites carry an accessor arm. + h.field( + "program_class_accessor_names", + &opts + .program_class_accessor_names + .as_deref() + .map_or_else(|| "*".to_string(), |names| names.cache_key()), + ); + // #8775 reverse-flow object candidates likewise affect modules that do // not import the producer and therefore are not covered by the imported // class/object fingerprint above. diff --git a/crates/perry/src/commands/compile/object_cache/object_cache_tests.rs b/crates/perry/src/commands/compile/object_cache/object_cache_tests.rs index 9997f21b30..f406c96c8d 100644 --- a/crates/perry/src/commands/compile/object_cache/object_cache_tests.rs +++ b/crates/perry/src/commands/compile/object_cache/object_cache_tests.rs @@ -36,6 +36,7 @@ fn empty_opts() -> CompileOptions { imported_classes: Vec::new(), constructor_param_counts: Default::default(), short_spread_method_candidates: std::sync::Arc::default(), + program_class_accessor_names: Default::default(), object_literal_method_candidates: std::sync::Arc::default(), imported_enums: Vec::new(), imported_async_funcs: std::collections::HashSet::new(), diff --git a/crates/perry/src/commands/compile/run_pipeline.rs b/crates/perry/src/commands/compile/run_pipeline.rs index 8f4ce14d55..d01f43be25 100644 --- a/crates/perry/src/commands/compile/run_pipeline.rs +++ b/crates/perry/src/commands/compile/run_pipeline.rs @@ -3359,6 +3359,11 @@ pub fn run_with_parse_cache( candidates.dedup_by(|a, b| a.class_id == b.class_id && a.target == b.target); } let short_spread_method_candidates = std::sync::Arc::new(short_spread_method_candidates); + // #10498: the accessor names every compiled class declares decide which + // sites carry a class-accessor arm. + let program_class_accessor_names = std::sync::Arc::new( + perry_codegen::ClassAccessorNames::collect(ctx.native_modules.values()), + ); // #8775: a generic library module can receive an exported adapter object // through a parameter without importing its defining module. Publish the // producer's exact immutable object/method facts to every codegen job so a @@ -5637,6 +5642,9 @@ pub fn run_with_parse_cache( static_shape_ids: Vec::new(), program_class_shape_ids: Default::default(), short_spread_method_candidates: std::sync::Arc::clone(&short_spread_method_candidates), + program_class_accessor_names: Some(std::sync::Arc::clone( + &program_class_accessor_names, + )), object_literal_method_candidates: std::sync::Arc::clone( &object_literal_method_candidates, ), From 66d9c57bff0312a160a5d166c93f5a0fd999e4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sun, 4 Oct 2026 00:12:17 +0000 Subject: [PATCH 2/2] changelog: key the fragment to PR 11859 --- ...x-accessor-arm-names.md => 11859-regfix-accessor-arm-names.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{PENDING-regfix-accessor-arm-names.md => 11859-regfix-accessor-arm-names.md} (100%) diff --git a/changelog.d/PENDING-regfix-accessor-arm-names.md b/changelog.d/11859-regfix-accessor-arm-names.md similarity index 100% rename from changelog.d/PENDING-regfix-accessor-arm-names.md rename to changelog.d/11859-regfix-accessor-arm-names.md