Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/perry-codegen/src/codegen/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ pub(super) fn compile_closure(
module_globals,
classes,
&cross_module.compile_time_constants,
&cross_module.module_dispatch,
);

let mut ctx = FnCtx {
Expand Down
2 changes: 2 additions & 0 deletions crates/perry-codegen/src/codegen/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ pub(super) fn compile_module_entry(
module_globals,
classes,
&cross_module.compile_time_constants,
&cross_module.module_dispatch,
);
let mut init_local_types: HashMap<u32, perry_types::Type> = HashMap::new();
crate::boxed_vars::collect_let_types_in_stmts(&hir.init, &mut init_local_types);
Expand Down Expand Up @@ -1090,6 +1091,7 @@ pub(super) fn compile_module_entry(
module_globals,
classes,
&cross_module.compile_time_constants,
&cross_module.module_dispatch,
);
let mut ctx = FnCtx {
func: init_fn,
Expand Down
1 change: 1 addition & 0 deletions crates/perry-codegen/src/codegen/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ pub(super) fn compile_function(
module_globals,
classes,
&cross_module.compile_time_constants,
&cross_module.module_dispatch,
);

let mut ctx = FnCtx {
Expand Down
2 changes: 2 additions & 0 deletions crates/perry-codegen/src/codegen/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ pub(super) fn compile_method(
module_globals,
classes,
&cross_module.compile_time_constants,
&cross_module.module_dispatch,
);

let mut ctx = FnCtx {
Expand Down Expand Up @@ -1289,6 +1290,7 @@ pub(super) fn compile_static_method(
module_globals,
classes,
&cross_module.compile_time_constants,
&cross_module.module_dispatch,
);

let mut ctx = FnCtx {
Expand Down
1 change: 1 addition & 0 deletions crates/perry-codegen/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,7 @@ pub fn compile_module(hir: &HirModule, opts: CompileOptions) -> Result<Vec<u8>>
compile_time_constants,
target_triple: triple.clone(),
app_metadata: opts.app_metadata.clone(),
module_dispatch: crate::collectors::collect_module_dispatch_facts(hir),
clamp3_functions: hir
.functions
.iter()
Expand Down
6 changes: 6 additions & 0 deletions crates/perry-codegen/src/codegen/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,12 @@ pub(crate) struct CrossModuleCtx {
pub target_triple: String,
/// App metadata backing compile-time `perry/system` introspection APIs.
pub app_metadata: AppMetadata,
/// Issue #5872: module-wide record of the prototype mutations that can
/// change what `obj.method` resolves to. Scalar replacement consults this
/// before it lets a summarized method call keep its receiver off the heap —
/// the mutation usually lives in a *different* function (or a constructor,
/// or a field initializer) than the `new`, so a per-function walk misses it.
pub module_dispatch: crate::collectors::ModuleDispatchFacts,
/// Functions with a 3-param clamp pattern: fid → true. Call sites
/// emit `@llvm.smax.i32` + `@llvm.smin.i32` instead of a function call.
pub clamp3_functions: std::collections::HashSet<u32>,
Expand Down
19 changes: 19 additions & 0 deletions crates/perry-codegen/src/collectors/escape_news.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub fn collect_non_escaping_news(
boxed_vars: &HashSet<u32>,
module_globals: &std::collections::HashMap<u32, String>,
classes: &std::collections::HashMap<String, &perry_hir::Class>,
module_dispatch: &super::ModuleDispatchFacts,
) -> std::collections::HashMap<u32, String> {
// Pass 1: find candidates — Let bindings of New that aren't boxed/global.
let mut candidates: std::collections::HashMap<u32, String> = std::collections::HashMap::new();
Expand Down Expand Up @@ -51,6 +52,24 @@ pub fn collect_non_escaping_news(
}
}

// Pass 4 (issue #5872): a method call only keeps its receiver scalar-
// replaced when `simple_scalar_method_summary` accepts it (see the
// `Expr::Call` arm of `check_escapes_in_expr`). The summary proves the
// method *body* is a numeric read of `this.<field>` — it does NOT prove
// that `obj.method` still RESOLVES to that class method. An own-property
// write (`(obj as any).getValue = () => 99`) or a prototype mutation
// (`C.prototype.getValue = fn`, possibly from another function or from the
// constructor) replaces the target, and the inlined field read then returns
// the wrong value. Escape those receivers so they take the ordinary
// heap-allocate + dispatch path.
super::mark_unstable_scalar_method_receivers(
stmts,
&candidates,
classes,
module_dispatch,
&mut escaped,
);

candidates.retain(|id, _| !escaped.contains(id));
candidates
}
Expand Down
17 changes: 15 additions & 2 deletions crates/perry-codegen/src/collectors/hir_facts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ pub(crate) fn collect_type_facts(
module_globals: &HashMap<u32, String>,
classes: &HashMap<String, &perry_hir::Class>,
compile_time_constants: &HashMap<u32, f64>,
module_dispatch: &super::ModuleDispatchFacts,
) -> TypeFacts {
let integer_locals = super::integer_locals::collect_integer_locals(
stmts,
Expand All @@ -313,8 +314,13 @@ pub(crate) fn collect_type_facts(
clamp_fn_ids,
);
let known_noalias_buffer_locals = collect_known_noalias_buffer_locals(stmts);
let non_escaping_news =
super::escape_news::collect_non_escaping_news(stmts, boxed_vars, module_globals, classes);
let non_escaping_news = super::escape_news::collect_non_escaping_news(
stmts,
boxed_vars,
module_globals,
classes,
module_dispatch,
);
let non_escaping_new_used_fields =
super::escape_news::collect_non_escaping_new_used_fields(stmts, &non_escaping_news);
let non_escaping_arrays =
Expand Down Expand Up @@ -392,6 +398,7 @@ pub(crate) fn collect_native_region_fact_graph(
module_globals: &HashMap<u32, String>,
classes: &HashMap<String, &perry_hir::Class>,
compile_time_constants: &HashMap<u32, f64>,
module_dispatch: &super::ModuleDispatchFacts,
) -> NativeRegionFactGraph {
collect_type_facts(
stmts,
Expand All @@ -403,6 +410,7 @@ pub(crate) fn collect_native_region_fact_graph(
module_globals,
classes,
compile_time_constants,
module_dispatch,
)
}

Expand All @@ -424,6 +432,9 @@ pub(crate) fn collect_hir_facts(
&HashMap::new(),
&HashMap::new(),
&HashMap::new(),
// No class table here, so no scalar-method summary can apply; the
// conservative default keeps it that way if one ever could.
&super::ModuleDispatchFacts::default(),
)
}

Expand Down Expand Up @@ -1630,6 +1641,7 @@ mod tests {
&HashMap::new(),
&HashMap::new(),
&constants,
&crate::collectors::ModuleDispatchFacts::default(),
);

assert!(graph.known_noalias_buffer_locals().contains(&1));
Expand Down Expand Up @@ -1719,6 +1731,7 @@ mod tests {
&HashMap::new(),
&HashMap::new(),
&HashMap::new(),
&crate::collectors::ModuleDispatchFacts::default(),
);

assert!(graph.integer_locals().contains(&1));
Expand Down
4 changes: 4 additions & 0 deletions crates/perry-codegen/src/collectors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod local_refs;
mod mutation;
mod pointer_locals;
mod refs;
mod scalar_method_dispatch;
mod scalar_methods;
mod shadow_slots;
mod this_as_value;
Expand Down Expand Up @@ -74,6 +75,9 @@ pub(crate) use pointer_locals::collect_pointer_typed_locals;
pub(crate) use refs::{
collect_let_ids, collect_ref_ids_in_expr, collect_ref_ids_in_stmts, is_clamp_call,
};
pub(crate) use scalar_method_dispatch::{
collect_module_dispatch_facts, mark_unstable_scalar_method_receivers, ModuleDispatchFacts,
};
pub(crate) use scalar_methods::simple_scalar_method_summary;
pub(crate) use shadow_slots::{
collect_declared_shadow_slots_in_stmts, collect_shadow_slot_clear_points,
Expand Down
Loading
Loading