use crate::ir::AllocPolicy;
pub struct WasmAllocPolicy;
impl AllocPolicy for WasmAllocPolicy {
fn builtin_allocates(&self, name: &str) -> bool {
!is_pure_non_alloc_builtin(name)
}
fn constructor_allocates(&self, _name: &str, has_payload: bool) -> bool {
has_payload
}
}
fn is_pure_non_alloc_builtin(name: &str) -> bool {
matches!(
name,
"Int.abs"
| "Int.min"
| "Int.max"
| "Int.toFloat"
| "Float.abs"
| "Float.floor"
| "Float.ceil"
| "Float.round"
| "Float.min"
| "Float.max"
| "Float.sin"
| "Float.cos"
| "Float.sqrt"
| "Float.pow"
| "Float.atan2"
| "Float.pi"
| "Float.fromInt"
| "Char.toCode"
| "String.len"
| "String.byteLength"
| "String.startsWith"
| "String.endsWith"
| "String.contains"
| "List.len"
| "List.contains"
| "Vector.len"
| "Map.size"
| "Map.contains"
| "Set.size"
| "Set.contains"
| "Bool.and"
| "Bool.or"
| "Bool.not"
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pure_math_is_non_alloc() {
let p = WasmAllocPolicy;
assert!(!p.builtin_allocates("Float.sin"));
assert!(!p.builtin_allocates("Float.sqrt"));
assert!(!p.builtin_allocates("Int.abs"));
assert!(!p.builtin_allocates("Int.toFloat"));
}
#[test]
fn allocating_builtins_flagged() {
let p = WasmAllocPolicy;
assert!(p.builtin_allocates("String.fromInt"));
assert!(p.builtin_allocates("List.prepend"));
assert!(p.builtin_allocates("Map.set"));
assert!(p.builtin_allocates("Map.get"));
assert!(p.builtin_allocates("String.charAt"));
}
#[test]
fn constructors_with_payload_allocate() {
let p = WasmAllocPolicy;
assert!(p.constructor_allocates("Option.Some", true));
assert!(p.constructor_allocates("Result.Ok", true));
assert!(p.constructor_allocates("Shape.Circle", true));
assert!(!p.constructor_allocates("Option.None", false));
}
#[test]
fn unknown_builtin_is_conservatively_allocating() {
let p = WasmAllocPolicy;
assert!(p.builtin_allocates("Future.weird_op"));
}
}