From ed358dea0c42faca6333dae7410c5102b7a9d804 Mon Sep 17 00:00:00 2001 From: Haled Odat Date: Tue, 28 Mar 2023 02:56:10 +0000 Subject: [PATCH] Shrink objects by using `ThinVec`s (#2752) The fields like `[[PrivateElements]]` are hardly used but they occupy `24` bytes (on 64-bit arch.) the `ThinVec` type stores the `len` and `cap` right before the elements (like our `JsString` implementation) and only a pointer is kept (if not used it does not allocate!), was going to use this in #2723 , since it uses a `Vec` as a dense storage, but the PR is already too big. It changes the following: - Shrink object from `328` to `288` bytes (40 bytes reduction) - Add the `thin_vec` lightweight crate (single file) --- Cargo.lock | 7 +++++++ boa_engine/Cargo.toml | 1 + boa_engine/src/builtins/function/mod.rs | 9 ++++++--- boa_engine/src/object/jsobject.rs | 3 ++- boa_engine/src/object/mod.rs | 5 +++-- boa_engine/src/vm/code_block.rs | 5 +++-- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c46d54e5e..77ea5b6531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,6 +373,7 @@ dependencies = [ "sys-locale", "tap", "textwrap 0.16.0", + "thin-vec", "thiserror", "unicode-normalization", "writeable", @@ -3984,6 +3985,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thin-vec" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" + [[package]] name = "thiserror" version = "1.0.40" diff --git a/boa_engine/Cargo.toml b/boa_engine/Cargo.toml index 0d9e121427..fbf0539b0b 100644 --- a/boa_engine/Cargo.toml +++ b/boa_engine/Cargo.toml @@ -68,6 +68,7 @@ thiserror = "1.0.40" dashmap = "5.4.0" num_enum = "0.5.11" pollster = "0.3.0" +thin-vec = "0.2.12" # intl deps boa_icu_provider = { workspace = true, optional = true } diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index 3299939550..ca45f2206e 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -36,6 +36,7 @@ use boa_gc::{self, custom_trace, Finalize, Gc, Trace}; use boa_interner::Sym; use boa_parser::{Parser, Source}; use boa_profiler::Profiler; +use thin_vec::ThinVec; use std::fmt; @@ -172,10 +173,10 @@ pub enum Function { home_object: Option, /// The `[[Fields]]` internal slot. - fields: Vec, + fields: ThinVec, /// The `[[PrivateMethods]]` internal slot. - private_methods: Vec<(PrivateName, PrivateElement)>, + private_methods: ThinVec<(PrivateName, PrivateElement)>, /// The class object that this function is associated with. class_object: Option, @@ -238,7 +239,9 @@ unsafe impl Trace for Function { mark(code); mark(environments); mark(home_object); - mark(fields); + for elem in fields { + mark(elem); + } for (_, elem) in private_methods { mark(elem); } diff --git a/boa_engine/src/object/jsobject.rs b/boa_engine/src/object/jsobject.rs index f1dd101062..ca4f497a2f 100644 --- a/boa_engine/src/object/jsobject.rs +++ b/boa_engine/src/object/jsobject.rs @@ -19,6 +19,7 @@ use std::{ fmt::{self, Debug, Display}, result::Result as StdResult, }; +use thin_vec::ThinVec; /// A wrapper type for an immutably borrowed type T. pub type Ref<'a, T> = boa_gc::GcRef<'a, T>; @@ -74,7 +75,7 @@ impl JsObject { prototype: prototype.into(), extensible: true, properties: PropertyMap::default(), - private_elements: Vec::new(), + private_elements: ThinVec::new(), })), } } diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 86bfef4b7c..a104a46673 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -6,6 +6,7 @@ use boa_ast::function::PrivateName; pub use jsobject::{RecursionLimiter, Ref, RefMut}; pub use operations::IntegrityLevel; pub use property_map::*; +use thin_vec::ThinVec; use self::internal_methods::{ arguments::ARGUMENTS_EXOTIC_INTERNAL_METHODS, @@ -128,7 +129,7 @@ pub struct Object { /// Whether it can have new properties added to it. extensible: bool, /// The `[[PrivateElements]]` internal slot. - private_elements: Vec<(PrivateName, PrivateElement)>, + private_elements: ThinVec<(PrivateName, PrivateElement)>, } unsafe impl Trace for Object { @@ -782,7 +783,7 @@ impl Default for Object { properties: PropertyMap::default(), prototype: None, extensible: true, - private_elements: Vec::default(), + private_elements: ThinVec::default(), } } } diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 5710892055..ec3ce4bf88 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -29,6 +29,7 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; use boa_interner::Sym; use boa_profiler::Profiler; use std::{collections::VecDeque, mem::size_of}; +use thin_vec::ThinVec; #[cfg(any(feature = "trace", feature = "flowgraph"))] use crate::vm::Opcode; @@ -597,8 +598,8 @@ pub(crate) fn create_function_object( environments: context.realm.environments.clone(), constructor_kind: ConstructorKind::Base, home_object: None, - fields: Vec::new(), - private_methods: Vec::new(), + fields: ThinVec::new(), + private_methods: ThinVec::new(), class_object: None, } };