// Licensing scope: see ../../LICENSE and this directory's LICENSE and NOTICE.
// Potentially incorporated Binaryen expression retains Apache-2.0 terms.
// Original Starshine contributions use the scoped MIT grant in ../../LICENSE.
// Modified for Starshine through 2026: implementation and validation use
// Starshine's representations and APIs; this is not an unchanged upstream file.
// Conservative notice retention does not establish copying or independence.
///|
priv struct InlBodyMeasureCache {
mut measurements : Array[(Bool, Bool, Bool, Bool, Int32)?]
mut bodies : Array[Array[@lib.Instruction]?]
flat_only : Bool
}
///|
fn InlBodyMeasureCache::new(
count : Int32,
flat_only~ : Bool = false,
) -> InlBodyMeasureCache {
{
measurements: Array::make(count, None),
bodies: Array::make(count, None),
flat_only,
}
}
///|
fn InlBodyMeasureCache::measure(
self : InlBodyMeasureCache,
index : Int32,
body : Array[@lib.Instruction],
visits~ : Array[Int32]? = None,
) -> (Bool, Bool, Bool, Bool, Int32) {
if index < 0 || index >= self.measurements.length() {
return inl_measure_body(body, visits~)
}
match self.measurements[index] {
Some(facts) if self.bodies[index] is Some(previous) &&
physical_equal(previous, body) => facts
_ => {
let facts = inl_measure_body(body, visits~)
// Raw optimizing cleanup may own and change nested arrays. Until those
// ownership contracts are complete, only retain flat bodies in that mode.
if self.flat_only &&
body.any(fn(instr) {
match instr {
@lib.Block(_, _)
| @lib.Loop(_, _)
| @lib.If(_, _, _)
| @lib.Try(_, _, _, _)
| @lib.TryTable(_, _, _) => true
_ => false
}
}) {
self.measurements[index] = None
self.bodies[index] = None
return facts
}
self.measurements[index] = Some(facts)
self.bodies[index] = Some(body)
facts
}
}
}
///|
fn InlBodyMeasureCache::remap(
self : InlBodyMeasureCache,
touched : Array[Bool],
final_to_prior : Array[Int32],
) -> Unit {
let previous = self.measurements
let previous_bodies = self.bodies
self.measurements = final_to_prior.map(fn(prior) {
if prior >= 0 &&
prior < previous.length() &&
(prior >= touched.length() || !touched[prior]) {
previous[prior]
} else {
None
}
})
self.bodies = final_to_prior.map(fn(prior) {
if prior >= 0 &&
prior < previous_bodies.length() &&
(prior >= touched.length() || !touched[prior]) {
previous_bodies[prior]
} else {
None
}
})
}