slint/internal/compiler/passes/lower_absolute_coordinates.rs
Milian Wolff 0f6c3a4fd7 Use SmolStr in more places of the compiler infrastructure
This removes a lot of allocations and speeds up the compiler step
a bit. Sadly, this patch is very invasive as it touches a lot of
files. That said, each individual hunk is pretty trivial.

For a non-trivial real-world example, the impact is significant,
we get rid of ~29% of all allocations and improve the runtime by
about 4.8% (measured until the viewer loop would start).

Before:
```
Benchmark 1: ./target/release/slint-viewer ../slint-perf/app.slint
  Time (mean ± σ):     664.2 ms ±   6.7 ms    [User: 589.2 ms, System: 74.0 ms]
  Range (min … max):   659.0 ms … 682.4 ms    10 runs

        allocations:            4886888
        temporary allocations:  857508
```

After:
```
Benchmark 1: ./target/release/slint-viewer ../slint-perf/app.slint
  Time (mean ± σ):     639.5 ms ±  17.8 ms    [User: 556.9 ms, System: 76.2 ms]
  Range (min … max):   621.4 ms … 666.5 ms    10 runs

        allocations:            3544318
        temporary allocations:  495685
```
2024-10-17 18:04:58 +02:00

83 lines
3.2 KiB
Rust

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
//! This pass creates bindings to "absolute-y" and "absolute-y" properties
//! that can be used to compute the window-absolute coordinates of elements.
use std::cell::RefCell;
use std::rc::Rc;
use crate::expression_tree::{BuiltinFunction, Expression};
use crate::namedreference::NamedReference;
use crate::object_tree::{
recurse_elem_including_sub_components_no_borrow, visit_all_named_references_in_element,
Component,
};
pub fn lower_absolute_coordinates(component: &Rc<Component>) {
let mut to_materialize = std::collections::HashSet::new();
recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {
visit_all_named_references_in_element(elem, |nr| {
if nr.name() == "absolute-position" {
to_materialize.insert(nr.clone());
}
});
});
let point_type = match BuiltinFunction::ItemAbsolutePosition.ty() {
crate::langtype::Type::Function { return_type, .. } => return_type.as_ref().clone(),
_ => unreachable!(),
};
for nr in to_materialize {
let elem = nr.element();
// Create a binding for the `absolute-position` property. The
// materialize properties pass is going to create the actual property later.
let parent_position_var = Box::new(Expression::ReadLocalVariable {
name: "parent_position".into(),
ty: point_type.clone(),
});
let binding = Expression::CodeBlock(vec![
Expression::StoreLocalVariable {
name: "parent_position".into(),
value: Expression::FunctionCall {
function: Box::new(Expression::BuiltinFunctionReference(
BuiltinFunction::ItemAbsolutePosition,
None,
)),
arguments: vec![Expression::ElementReference(Rc::downgrade(&elem))],
source_location: None,
}
.into(),
},
Expression::Struct {
ty: point_type.clone(),
values: IntoIterator::into_iter(["x", "y"])
.map(|coord| {
(
coord.into(),
Expression::BinaryExpression {
lhs: Expression::StructFieldAccess {
base: parent_position_var.clone(),
name: coord.into(),
}
.into(),
rhs: Expression::PropertyReference(NamedReference::new(
&elem, coord,
))
.into(),
op: '+',
},
)
})
.collect(),
},
]);
elem.borrow_mut().bindings.insert(nr.name().into(), RefCell::new(binding.into()));
}
}