Every heap ref carries its heap tag, generation checks always on, rooted async values. Splash isolates get a domain table and curated minimal preludes; system modules under `mod` expand lazily on first touch. No wall-clock script caps: isolation and force-stop instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
84 lines
3.7 KiB
Rust
84 lines
3.7 KiB
Rust
//! The module census keeps every module whose definitions a used module
|
|
//! names, so a web build cut by it still registers all it evaluates.
|
|
use makepad_script::*;
|
|
|
|
fn test_vm() -> ScriptVm<'static> {
|
|
let host = Box::leak(Box::new(ScriptVmHost::new(0i32, ())));
|
|
ScriptVm {
|
|
host: host.host_context(),
|
|
bx: Box::new(ScriptVmBase::new()),
|
|
}
|
|
}
|
|
|
|
fn script(module_path: &str, file: &str, code: &str) -> ScriptMod {
|
|
ScriptMod::new("", &module_path, &file, 0, 0, &code, &[])
|
|
}
|
|
|
|
fn register(vm: &mut ScriptVm, module_path: &'static str, code: &str) {
|
|
vm.census_begin(module_path);
|
|
vm.eval(script(module_path, module_path, code));
|
|
vm.census_end();
|
|
}
|
|
|
|
#[test]
|
|
fn a_spread_definition_is_used_by_the_module_that_spreads_it() {
|
|
let vm = &mut test_vm();
|
|
vm.new_module(id!(cz));
|
|
makepad_script_census::census_record(vm);
|
|
// `vector` is only ever spread by `svg` (its fields are copied at
|
|
// registration: no heap edge leads to it); `unused` nobody names.
|
|
register(vm, "t::vector", "mod.cz.Vector = {fill: 1}");
|
|
register(vm, "t::svg", "mod.cz.Svg = {stroke: 2, ..mod.cz.Vector}");
|
|
register(vm, "t::unused", "mod.cz.Unused = {x: 3}");
|
|
// The app holds an Svg.
|
|
let app = vm.eval(script("app", "app", "let held = mod.cz.Svg{stroke: 4}\nheld"));
|
|
if let Some(obj) = app.as_object() {
|
|
std::mem::forget(vm.bx.heap.new_object_ref(obj));
|
|
}
|
|
let used = makepad_script_census::census_used(vm).expect("recording");
|
|
assert!(used.used.contains_key("t::svg"), "{used:?}");
|
|
assert!(used.used.contains_key("t::vector"), "a spread definition must stay: {used:?}");
|
|
assert!(!used.used.contains_key("t::unused"), "{used:?}");
|
|
}
|
|
|
|
#[test]
|
|
fn the_app_crate_is_a_root_with_everything_it_names() {
|
|
let vm = &mut test_vm();
|
|
vm.new_module(id!(cz));
|
|
makepad_script_census::census_record(vm);
|
|
register(vm, "lib::window", "mod.cz.Window = {title: 1}");
|
|
register(vm, "lib::unused", "mod.cz.Unused = {x: 3}");
|
|
// The app registers its UI inside its own script_mod, and Rust holds it
|
|
// from there on: no walk from the app's objects starts at it.
|
|
vm.census_begin("app");
|
|
let ui = vm.eval(script("app", "app", "mod.cz.Ui = mod.cz.Window{title: 2}\nmod.cz.Ui"));
|
|
if let Some(obj) = ui.as_object() {
|
|
std::mem::forget(vm.bx.heap.new_object_ref(obj));
|
|
}
|
|
vm.census_end();
|
|
let used = makepad_script_census::census_used_from(vm, &["app"]).expect("recording");
|
|
assert!(used.used.contains_key("app"), "{used:?}");
|
|
assert!(used.used.contains_key("lib::window"), "what the app names is used: {used:?}");
|
|
assert!(!used.used.contains_key("lib::unused"), "{used:?}");
|
|
}
|
|
|
|
#[test]
|
|
fn a_registration_that_patches_a_used_definition_is_used() {
|
|
let vm = &mut test_vm();
|
|
vm.new_module(id!(cz));
|
|
makepad_script_census::census_record(vm);
|
|
// `hardware` sets no name of its own: it replaces a field of `sampling`'s
|
|
// definition (render's hardware shadow sampling), and `shader` spreads it.
|
|
register(vm, "t::sampling", "mod.cz.Sampling = {map: {kind: 1}}");
|
|
register(vm, "t::hardware", "mod.cz.Sampling.map = {kind: 2}");
|
|
register(vm, "t::shader", "mod.cz.Shader = {..mod.cz.Sampling}");
|
|
register(vm, "t::unused", "mod.cz.Unused = {x: 3}");
|
|
let app = vm.eval(script("app", "app", "let held = mod.cz.Shader{}\nheld"));
|
|
if let Some(obj) = app.as_object() {
|
|
std::mem::forget(vm.bx.heap.new_object_ref(obj));
|
|
}
|
|
let used = makepad_script_census::census_used(vm).expect("recording");
|
|
assert!(used.used.contains_key("t::sampling"), "{used:?}");
|
|
assert!(used.used.contains_key("t::hardware"), "a patch of a used definition must stay: {used:?}");
|
|
assert!(!used.used.contains_key("t::unused"), "{used:?}");
|
|
}
|