From ed14ab8c02e6c96e67053764da1f012df3ad7f74 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:26:37 +0200 Subject: [PATCH] gpui: Introduce stacker to address stack overflows with deep layout trees (#35813) Co-authored-by: Anthony Eid Co-authored-by: Lukas Wirth Co-authored-by: Ben Kunkle Release Notes: - N/A Co-authored-by: Anthony Eid Co-authored-by: Lukas Wirth Co-authored-by: Ben Kunkle --- Cargo.lock | 35 +++++++++++++++++++++++++++++++++ Cargo.toml | 1 + crates/gpui/Cargo.toml | 1 + crates/gpui/src/elements/div.rs | 9 +++++++-- crates/gpui/src/taffy.rs | 15 +++++++++++--- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c05839ef3..2ef91c79c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7482,6 +7482,7 @@ dependencies = [ "slotmap", "smallvec", "smol", + "stacksafe", "strum 0.27.1", "sum_tree", "taffy", @@ -15541,6 +15542,40 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "stacker" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + +[[package]] +name = "stacksafe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9c1172965d317e87ddb6d364a040d958b40a1db82b6ef97da26253a8b3d090" +dependencies = [ + "stacker", + "stacksafe-macro", +] + +[[package]] +name = "stacksafe-macro" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172175341049678163e979d9107ca3508046d4d2a7c6682bee46ac541b17db69" +dependencies = [ + "proc-macro-error2", + "quote", + "syn 2.0.101", +] + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index b61eb3c260..f326090b51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -590,6 +590,7 @@ simplelog = "0.12.2" smallvec = { version = "1.6", features = ["union"] } smol = "2.0" sqlformat = "0.2" +stacksafe = "0.1" streaming-iterator = "0.1" strsim = "0.11" strum = { version = "0.27.0", features = ["derive"] } diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 6be8c5fd1f..9f5b66087d 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -119,6 +119,7 @@ serde_json.workspace = true slotmap = "1.0.6" smallvec.workspace = true smol.workspace = true +stacksafe.workspace = true strum.workspace = true sum_tree.workspace = true taffy = "=0.9.0" diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 78114b7ecf..f553bf55f6 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -27,6 +27,7 @@ use crate::{ use collections::HashMap; use refineable::Refineable; use smallvec::SmallVec; +use stacksafe::{StackSafe, stacksafe}; use std::{ any::{Any, TypeId}, cell::RefCell, @@ -1195,7 +1196,7 @@ pub fn div() -> Div { /// A [`Div`] element, the all-in-one element for building complex UIs in GPUI pub struct Div { interactivity: Interactivity, - children: SmallVec<[AnyElement; 2]>, + children: SmallVec<[StackSafe; 2]>, prepaint_listener: Option>, &mut Window, &mut App) + 'static>>, image_cache: Option>, } @@ -1256,7 +1257,8 @@ impl InteractiveElement for Div { impl ParentElement for Div { fn extend(&mut self, elements: impl IntoIterator) { - self.children.extend(elements) + self.children + .extend(elements.into_iter().map(StackSafe::new)) } } @@ -1272,6 +1274,7 @@ impl Element for Div { self.interactivity.source_location() } + #[stacksafe] fn request_layout( &mut self, global_id: Option<&GlobalElementId>, @@ -1307,6 +1310,7 @@ impl Element for Div { (layout_id, DivFrameState { child_layout_ids }) } + #[stacksafe] fn prepaint( &mut self, global_id: Option<&GlobalElementId>, @@ -1376,6 +1380,7 @@ impl Element for Div { ) } + #[stacksafe] fn paint( &mut self, global_id: Option<&GlobalElementId>, diff --git a/crates/gpui/src/taffy.rs b/crates/gpui/src/taffy.rs index ee21ecd8c4..f78d6b30c7 100644 --- a/crates/gpui/src/taffy.rs +++ b/crates/gpui/src/taffy.rs @@ -3,6 +3,7 @@ use crate::{ }; use collections::{FxHashMap, FxHashSet}; use smallvec::SmallVec; +use stacksafe::{StackSafe, stacksafe}; use std::{fmt::Debug, ops::Range}; use taffy::{ TaffyTree, TraversePartialTree as _, @@ -11,8 +12,15 @@ use taffy::{ tree::NodeId, }; -type NodeMeasureFn = Box< - dyn FnMut(Size>, Size, &mut Window, &mut App) -> Size, +type NodeMeasureFn = StackSafe< + Box< + dyn FnMut( + Size>, + Size, + &mut Window, + &mut App, + ) -> Size, + >, >; struct NodeContext { @@ -88,7 +96,7 @@ impl TaffyLayoutEngine { .new_leaf_with_context( taffy_style, NodeContext { - measure: Box::new(measure), + measure: StackSafe::new(Box::new(measure)), }, ) .expect(EXPECT_MESSAGE) @@ -143,6 +151,7 @@ impl TaffyLayoutEngine { Ok(edges) } + #[stacksafe] pub fn compute_layout( &mut self, id: LayoutId,