///| A committed structural mask proves which aliased producer bodies need a
///|
/// scan. Unknown callers retain the full reference refresh.
fn dae_current_boundary_graph_refresh(
graph : DaeCurrentBoundaryGraph,
mod_ : @lib.Module,
topology_walk_visits~ : Array[Int32]? = None,
forced_changed_defs~ : Array[Bool]? = None,
) -> Unit {
if dae_try_refresh_current_boundary_graph_incremental(
graph,
mod_,
forced_changed_defs~,
) {
return
}
dae_current_boundary_graph_refresh_full(graph, mod_, topology_walk_visits~)
}
///| Reuse immutable stable call paths for unchanged callers. The fused scanner
///| still computes current aggregate calls and topology from every body, with
///| callsite/path collection enabled only for changed or explicitly forced
///|
/// callers. This preserves its exact nested-trap and inactive-tail rules.
fn dae_try_refresh_current_boundary_graph_incremental(
graph : DaeCurrentBoundaryGraph,
mod_ : @lib.Module,
forced_changed_defs~ : Array[Bool]? = None,
) -> Bool {
let previous = graph.snapshot
let defined = dae_defined_func_count(mod_)
let imported = dae_imported_func_count(mod_)
let total = imported + defined
let forced = match forced_changed_defs {
Some(mask) if mask.length() == defined => mask
_ => return false
}
if imported != previous.imported ||
defined != previous.defined ||
total != previous.total ||
graph.mod_.import_sec != mod_.import_sec ||
previous.funcs.length() != defined ||
previous.function_types.length() != total ||
previous.function_infos.length() != total ||
graph.function_epochs.length() != defined {
return false
}
let funcs = match mod_.code_sec {
Some(@lib.CodeSec(funcs)) if funcs.length() == defined => funcs
None if defined == 0 => []
_ => return false
}
let type_indices = dae_collect_func_type_indices(mod_)
if type_indices.length() != total {
return false
}
let function_types = dae_snapshot_function_types(mod_, type_indices)
let body_changed = Array::make(defined, false)
let signature_changed = Array::make(defined, false)
let rescanned = Array::make(defined, false)
for def_idx in 0..= 0 &&
callsite.caller_def < rescanned.length() &&
rescanned[callsite.caller_def]
})
let calls = if incoming_changed {
dae_merge_rebased_stable_calls(before.calls, refreshed.calls, rescanned)
} else {
before.calls
}
let dropped = if incoming_changed {
calls.filter(fn(callsite) { callsite.dropped })
} else {
before.dropped_calls
}
let def_idx = func_abs - imported
let own_body_rescanned = def_idx >= 0 &&
def_idx < rescanned.length() &&
rescanned[def_idx]
// Fresh wrappers retain old snapshot ownership. Full refresh also resets
// each per-function analysis cache, including bodies that did not change.
function_infos.push({
stale: true,
unused_params: [],
calls,
dropped_calls: dropped,
has_tail_calls: if own_body_rescanned {
refreshed.has_tail_calls
} else {
before.has_tail_calls
},
tail_callees: if own_body_rescanned {
refreshed.tail_callees
} else {
before.tail_callees
},
loop_type_indices: if own_body_rescanned {
refreshed.loop_type_indices
} else {
before.loop_type_indices
},
has_adjacent_local_set_get: if own_body_rescanned {
refreshed.has_adjacent_local_set_get
} else {
before.has_adjacent_local_set_get
},
has_unseen_calls: escaped[func_abs],
})
}
let call_facts : DaeCurrentCallFacts = {
direct_calls,
tail_calls,
direct_callers,
dropped_calls,
escaped,
}
let parameter_loop_free = dae_parameter_loop_admission(
mod_, imported, defined, function_infos,
)
let mut changed = false
for def_idx in 0..