llr: Don't generate unused globals

Global for which none of the properties are used can be omitted in the
generated code.
This commit is contained in:
Olivier Goffart 2024-07-03 21:10:05 +02:00
parent 6687995c36
commit 14593a55e1
4 changed files with 81 additions and 9 deletions

View file

@ -831,7 +831,7 @@ pub fn generate(
for glob in &llr.globals { for glob in &llr.globals {
let ty = if glob.is_builtin { let ty = if glob.is_builtin {
format!("slint::cbindgen_private::{}", glob.name) format!("slint::cbindgen_private::{}", glob.name)
} else { } else if glob.must_generate() {
generate_global(&mut file, &conditional_includes, glob, &llr); generate_global(&mut file, &conditional_includes, glob, &llr);
file.definitions.extend(glob.aliases.iter().map(|name| { file.definitions.extend(glob.aliases.iter().map(|name| {
Declaration::TypeAlias(TypeAlias { Declaration::TypeAlias(TypeAlias {
@ -840,6 +840,8 @@ pub fn generate(
}) })
})); }));
ident(&glob.name) ident(&glob.name)
} else {
continue;
}; };
globals_struct.members.push(( globals_struct.members.push((
@ -954,12 +956,12 @@ fn generate_public_component(
}), }),
)); ));
for glob in unit.globals.iter().filter(|glob| !glob.is_builtin) { for glob in unit.globals.iter().filter(|glob| glob.must_generate()) {
component_struct.friends.push(ident(&glob.name)); component_struct.friends.push(ident(&glob.name));
} }
let mut global_accessor_function_body = Vec::new(); let mut global_accessor_function_body = Vec::new();
for glob in unit.globals.iter().filter(|glob| glob.exported && !glob.is_builtin) { for glob in unit.globals.iter().filter(|glob| glob.exported && glob.must_generate()) {
let accessor_statement = format!( let accessor_statement = format!(
"{0}if constexpr(std::is_same_v<T, {1}>) {{ return *m_globals.global_{1}.get(); }}", "{0}if constexpr(std::is_same_v<T, {1}>) {{ return *m_globals.global_{1}.get(); }}",
if global_accessor_function_body.is_empty() { "" } else { "else " }, if global_accessor_function_body.is_empty() { "" } else { "else " },

View file

@ -181,8 +181,11 @@ pub fn generate(doc: &Document, compiler_config: &CompilerConfiguration) -> Toke
env!("CARGO_PKG_VERSION_PATCH"), env!("CARGO_PKG_VERSION_PATCH"),
); );
let globals = let globals = llr
llr.globals.iter().filter(|glob| !glob.is_builtin).map(|glob| generate_global(glob, &llr)); .globals
.iter()
.filter(|glob| glob.must_generate())
.map(|glob| generate_global(glob, &llr));
let shared_globals = generate_shared_globals(&llr); let shared_globals = generate_shared_globals(&llr);
let globals_ids = llr.globals.iter().filter(|glob| glob.exported).flat_map(|glob| { let globals_ids = llr.globals.iter().filter(|glob| glob.exported).flat_map(|glob| {
std::iter::once(ident(&glob.name)).chain(glob.aliases.iter().map(|x| ident(x))) std::iter::once(ident(&glob.name)).chain(glob.aliases.iter().map(|x| ident(x)))
@ -310,12 +313,20 @@ fn generate_public_component(
} }
fn generate_shared_globals(llr: &llr::CompilationUnit) -> TokenStream { fn generate_shared_globals(llr: &llr::CompilationUnit) -> TokenStream {
let global_names = let global_names = llr
llr.globals.iter().map(|g| format_ident!("global_{}", ident(&g.name))).collect::<Vec<_>>(); .globals
let global_types = llr.globals.iter().map(global_inner_name).collect::<Vec<_>>(); .iter()
.filter(|g| g.is_builtin || g.must_generate())
.map(|g| format_ident!("global_{}", ident(&g.name)))
.collect::<Vec<_>>();
let global_types = llr
.globals
.iter()
.filter(|g| g.is_builtin || g.must_generate())
.map(global_inner_name)
.collect::<Vec<_>>();
quote! { quote! {
#[allow(dead_code)] // FIXME: some global are unused because of optimization, we should then remove them completely
struct SharedGlobals { struct SharedGlobals {
#(#global_names : ::core::pin::Pin<sp::Rc<#global_types>>,)* #(#global_names : ::core::pin::Pin<sp::Rc<#global_types>>,)*
window_adapter : sp::OnceCell<sp::WindowAdapterRc>, window_adapter : sp::OnceCell<sp::WindowAdapterRc>,

View file

@ -73,6 +73,15 @@ pub struct GlobalComponent {
pub prop_analysis: Vec<crate::object_tree::PropertyAnalysis>, pub prop_analysis: Vec<crate::object_tree::PropertyAnalysis>,
} }
impl GlobalComponent {
pub fn must_generate(&self) -> bool {
!self.is_builtin
&& (self.exported
|| !self.functions.is_empty()
|| self.properties.iter().any(|p| p.use_count.get() > 0))
}
}
/// a Reference to a property, in the context of a SubComponent /// a Reference to a property, in the context of a SubComponent
#[derive(Clone, Debug, Hash, PartialEq, Eq)] #[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum PropertyReference { pub enum PropertyReference {

View file

@ -30,6 +30,11 @@ struct PrettyPrinter<'a> {
impl<'a> PrettyPrinter<'a> { impl<'a> PrettyPrinter<'a> {
fn print_root(&mut self, root: &CompilationUnit) -> Result { fn print_root(&mut self, root: &CompilationUnit) -> Result {
for g in &root.globals {
if !g.is_builtin {
self.print_global(root, g)?;
}
}
for c in &root.sub_components { for c in &root.sub_components {
self.print_component(root, c, None)? self.print_component(root, c, None)?
} }
@ -111,6 +116,51 @@ impl<'a> PrettyPrinter<'a> {
writeln!(self.writer, "}}") writeln!(self.writer, "}}")
} }
fn print_global(&mut self, root: &CompilationUnit, global: &super::GlobalComponent) -> Result {
let ctx = EvaluationContext::new_global(root, global, ());
if global.exported {
write!(self.writer, "export ")?;
}
let aliases = global.aliases.join(",");
let aliases = if aliases.is_empty() { String::new() } else { format!(" /*{aliases}*/") };
writeln!(self.writer, "global {} {{{aliases}", global.name)?;
self.indentation += 1;
for ((p, init), is_const) in
std::iter::zip(&global.properties, &global.init_values).zip(&global.const_properties)
{
self.indent()?;
let init = init.as_ref().map_or(String::new(), |init| {
format!(
": {}{}",
DisplayExpression(&init.expression.borrow(), &ctx,),
if init.is_constant { "/*const*/" } else { "" }
)
});
writeln!(
self.writer,
"property <{}> {}{init}; //use={}{}",
p.ty,
p.name,
p.use_count.get(),
if *is_const { " const" } else { "" }
)?;
}
for f in &global.functions {
self.indent()?;
writeln!(
self.writer,
"function {} ({}) -> {} {{ {} }}; ",
f.name,
f.args.iter().map(ToString::to_string).join(", "),
f.ret_ty,
DisplayExpression(&f.code, &ctx)
)?;
}
self.indentation -= 1;
self.indent()?;
writeln!(self.writer, "}}")
}
fn indent(&mut self) -> Result { fn indent(&mut self) -> Result {
for _ in 0..self.indentation { for _ in 0..self.indentation {
self.writer.write_str(" ")?; self.writer.write_str(" ")?;