feat: slice large intrinsic layout trees between node calls
This commit is contained in:
@@ -524,3 +524,6 @@ New viewport targets now coalesce pending refresh work. The runtime cancels only
|
||||
|
||||
|
||||
Cancellation checkpoints own explicit VM roots until restored or released. Initial presentations may have no mount dictionary; cancellation restores that absence too. Saved metadata values retain object-valued attributes. A pending refresh can restart while keeping already completed window drafts; no onMount/onUnmount callback is replayed merely because the viewport target changed. Mount-owned tasks are cancelled immediately before an actual onUnmount callback, never during abandoned preparation.
|
||||
|
||||
|
||||
Large intrinsic layout trees (more than 64 occurrences) now use the resumable per-occurrence driver too. Native measurement caches remain active, and a single native callback remains atomic; VM instruction boundaries between nodes allow the worker to yield and replace an obsolete viewport. Small intrinsic trees retain the allocation-free native fast path. Structural extraction, driver preparation, settling checks and final paint/projection still run atomically; this is not a wall-clock preemption guarantee.
|
||||
|
||||
@@ -179,3 +179,6 @@ New viewport targets now coalesce pending refresh work. The runtime cancels only
|
||||
|
||||
|
||||
Cancellation checkpoints own explicit VM roots until restored or released. Initial presentations may have no mount dictionary; cancellation restores that absence too. Saved metadata values retain object-valued attributes. A pending refresh can restart while keeping already completed window drafts; no onMount/onUnmount callback is replayed merely because the viewport target changed. Mount-owned tasks are cancelled immediately before an actual onUnmount callback, never during abandoned preparation.
|
||||
|
||||
|
||||
source_layout uses the same resumable node driver for trees over 64 occurrences even when measure/arrange are intrinsic. Small intrinsic trees retain LayoutRuntime::frame. The larger path keeps LayoutRuntime measurement caches and yields between node calls; structural extraction, bytecode preparation, a single node, settling and paint remain atomic.
|
||||
|
||||
@@ -18,6 +18,10 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
// Small native trees keep the allocation-free fast path. Larger trees use the
|
||||
// same per-occurrence VM driver so even intrinsic work can yield between nodes.
|
||||
const NATIVE_FAST_PATH_MAX_NODES: usize = 64;
|
||||
|
||||
fn invalid(message: &'static str) -> VmError {
|
||||
VmError::InvalidArgument(message)
|
||||
}
|
||||
@@ -769,7 +773,7 @@ pub fn start(
|
||||
let live: HashSet<_> = mounts.iter().copied().collect();
|
||||
cache.entries.retain(|mount, _| live.contains(mount));
|
||||
// Preserve the existing native measurement cache and avoid VM/result
|
||||
// allocation for trees without custom layout methods. Contexts already exist.
|
||||
// allocation for small trees without custom layout methods. Contexts already exist.
|
||||
let mut custom = false;
|
||||
for weak in &mounts {
|
||||
let mount = vm
|
||||
@@ -803,7 +807,7 @@ pub fn start(
|
||||
}
|
||||
// Flex allocation can change text wrapping and ancestor measurements even
|
||||
// when every protocol method is native. Use the same settling driver.
|
||||
if !custom {
|
||||
if !custom && nodes.len() <= NATIVE_FAST_PATH_MAX_NODES {
|
||||
cache.clear();
|
||||
let mut native = runtime.frame(&root)?;
|
||||
// Only the structural pass consumes a published version.
|
||||
|
||||
Reference in New Issue
Block a user