From edb04175434f9f75dbb5b47e6b50ceef305de455 Mon Sep 17 00:00:00 2001 From: Haled Odat Date: Thu, 30 Mar 2023 06:58:28 +0000 Subject: [PATCH] Shrink size of `IndexedProperties` (#2757) Most objects don't have indexed properties, and those who have, have dense properties, this PR uses `ThinVec` to reduce the size of dense properties. It changes the following: - Trim `16` bytes from `IndexedProperties`, this reduces all objects size --- Cargo.lock | 1 + boa_engine/Cargo.toml | 2 +- boa_engine/src/builtins/array/mod.rs | 3 ++- boa_engine/src/object/property_map.rs | 17 +++++++++-------- boa_gc/Cargo.toml | 6 ++++++ boa_gc/src/trace.rs | 13 +++++++++++++ 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f49c8c3aef..0ad6019274 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -438,6 +438,7 @@ version = "0.16.0" dependencies = [ "boa_macros", "boa_profiler", + "thin-vec", ] [[package]] diff --git a/boa_engine/Cargo.toml b/boa_engine/Cargo.toml index 1e3196513f..751960c146 100644 --- a/boa_engine/Cargo.toml +++ b/boa_engine/Cargo.toml @@ -41,7 +41,7 @@ console = [] [dependencies] boa_interner.workspace = true -boa_gc.workspace = true +boa_gc = { workspace = true, features = [ "thinvec" ] } boa_profiler.workspace = true boa_macros.workspace = true boa_ast.workspace = true diff --git a/boa_engine/src/builtins/array/mod.rs b/boa_engine/src/builtins/array/mod.rs index bfea05fe98..793d4d8d72 100644 --- a/boa_engine/src/builtins/array/mod.rs +++ b/boa_engine/src/builtins/array/mod.rs @@ -11,6 +11,7 @@ use boa_macros::utf16; use boa_profiler::Profiler; +use thin_vec::ThinVec; use crate::{ builtins::iterable::{if_abrupt_close_iterator, IteratorHint}, @@ -284,7 +285,7 @@ impl Array { // b. Set n to n + 1. // // NOTE: This deviates from the spec, but it should have the same behaviour. - let elements: Vec<_> = elements.into_iter().collect(); + let elements: ThinVec<_> = elements.into_iter().collect(); let length = elements.len(); array .borrow_mut() diff --git a/boa_engine/src/object/property_map.rs b/boa_engine/src/object/property_map.rs index 67b2ec08de..d9923f8ef1 100644 --- a/boa_engine/src/object/property_map.rs +++ b/boa_engine/src/object/property_map.rs @@ -4,6 +4,7 @@ use boa_gc::{custom_trace, Finalize, Trace}; use indexmap::IndexMap; use rustc_hash::{FxHashMap, FxHasher}; use std::{collections::hash_map, hash::BuildHasherDefault, iter::FusedIterator}; +use thin_vec::ThinVec; /// Type alias to make it easier to work with the string properties on the global object. pub(crate) type GlobalPropertyMap = @@ -44,20 +45,20 @@ enum IndexedProperties { /// the value field and construct the data property descriptor on demand. /// /// This storage method is used by default. - Dense(Vec), + Dense(ThinVec), /// Sparse storage this storage is used as a backup if the element keys are not continuous or the property descriptors /// are not data descriptors with with a value field, writable field set to `true`, configurable field set to `true`, enumerable field set to `true`. /// /// This method uses more space, since we also have to store the property descriptors, not just the value. /// It is also slower because we need to to a hash lookup. - Sparse(FxHashMap), + Sparse(Box>), } impl Default for IndexedProperties { #[inline] fn default() -> Self { - Self::Dense(Vec::new()) + Self::Dense(ThinVec::new()) } } @@ -78,7 +79,7 @@ impl IndexedProperties { } /// Helper function for converting from a dense storage type to sparse storage type. - fn convert_dense_to_sparse(vec: &mut Vec) -> FxHashMap { + fn convert_dense_to_sparse(vec: &mut ThinVec) -> FxHashMap { let data = std::mem::take(vec); data.into_iter() @@ -143,7 +144,7 @@ impl IndexedProperties { // Slow path: converting to sparse storage. let mut map = Self::convert_dense_to_sparse(vec); let old_property = map.insert(key, property); - *self = Self::Sparse(map); + *self = Self::Sparse(Box::new(map)); old_property } @@ -182,7 +183,7 @@ impl IndexedProperties { // Slow Path: conversion to sparse storage. let mut map = Self::convert_dense_to_sparse(vec); let old_property = map.remove(&key); - *self = Self::Sparse(map); + *self = Self::Sparse(Box::new(map)); old_property } @@ -277,12 +278,12 @@ impl PropertyMap { } /// Overrides all the indexed properties, setting it to dense storage. - pub(crate) fn override_indexed_properties(&mut self, properties: Vec) { + pub(crate) fn override_indexed_properties(&mut self, properties: ThinVec) { self.indexed_properties = IndexedProperties::Dense(properties); } /// Returns the vec of dense indexed properties if they exist. - pub(crate) const fn dense_indexed_properties(&self) -> Option<&Vec> { + pub(crate) const fn dense_indexed_properties(&self) -> Option<&ThinVec> { if let IndexedProperties::Dense(properties) = &self.indexed_properties { Some(properties) } else { diff --git a/boa_gc/Cargo.toml b/boa_gc/Cargo.toml index 39f1afa64c..74565960e0 100644 --- a/boa_gc/Cargo.toml +++ b/boa_gc/Cargo.toml @@ -10,6 +10,12 @@ license.workspace = true repository.workspace = true rust-version.workspace = true +[features] +# Enable default implementatio of trace and finalize thin-vec crate +thinvec = ["thin-vec"] + [dependencies] boa_profiler.workspace = true boa_macros.workspace = true + +thin-vec = { version = "0.2.12", optional = true } \ No newline at end of file diff --git a/boa_gc/src/trace.rs b/boa_gc/src/trace.rs index f839ba7b79..464cd989d6 100644 --- a/boa_gc/src/trace.rs +++ b/boa_gc/src/trace.rs @@ -308,6 +308,19 @@ unsafe impl Trace for Vec { }); } +#[cfg(feature = "thin-vec")] +impl Finalize for thin_vec::ThinVec {} + +#[cfg(feature = "thin-vec")] +// SAFETY: All the inner elements of the `Vec` are correctly marked. +unsafe impl Trace for thin_vec::ThinVec { + custom_trace!(this, { + for e in this { + mark(e); + } + }); +} + impl Finalize for Option {} // SAFETY: The inner value of the `Option` is correctly marked. unsafe impl Trace for Option {