Bug 1550554 - Implement ArcSlice::default(). r=heycam
☠☠ backed out by 283b94c196a1 ☠ ☠
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 07 May 2019 17:37:26 +0200
changeset 535980 45f171b26e95c6c7d12302743129ec5ccf5ac7e4
parent 535979 2e4b263c9410ca3e9e2077552c0afa30f688e749
child 535981 57f2362aa538b3374290652fe8605d05104c140f
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1550554
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1550554 - Implement ArcSlice::default(). r=heycam Share a singleton to avoid allocating for empty lists. Differential Revision: https://phabricator.services.mozilla.com/D30543
Cargo.lock
servo/components/style_traits/Cargo.toml
servo/components/style_traits/arc_slice.rs
servo/components/style_traits/lib.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2813,16 +2813,17 @@ dependencies = [
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.21.0",
  "servo_arc 0.1.1",
  "to_shmem 0.0.1",
  "to_shmem_derive 0.0.1",
 ]
 
--- a/servo/components/style_traits/Cargo.toml
+++ b/servo/components/style_traits/Cargo.toml
@@ -13,16 +13,17 @@ path = "lib.rs"
 servo = ["serde", "servo_atoms", "cssparser/serde", "webrender_api", "servo_url"]
 gecko = []
 
 [dependencies]
 app_units = "0.7"
 cssparser = "0.25"
 bitflags = "1.0"
 euclid = "0.19"
+lazy_static = "1"
 malloc_size_of = { path = "../malloc_size_of" }
 malloc_size_of_derive = "0.1"
 selectors = { path = "../selectors" }
 serde = {version = "1.0", optional = true}
 webrender_api = {git = "https://github.com/servo/webrender", optional = true}
 servo_atoms = {path = "../atoms", optional = true}
 servo_arc = { path = "../servo_arc" }
 servo_url = { path = "../url", optional = true }
--- a/servo/components/style_traits/arc_slice.rs
+++ b/servo/components/style_traits/arc_slice.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! A thin atomically-reference-counted slice.
 
 use servo_arc::ThinArc;
-use std::mem;
+use std::{iter, mem};
 use std::ops::Deref;
 use std::ptr::NonNull;
 
 /// A canary that we stash in ArcSlices.
 ///
 /// Given we cannot use a zero-sized-type for the header, since well, C++
 /// doesn't have zsts, and we want to use cbindgen for this type, we may as well
 /// assert some sanity at runtime.
@@ -29,38 +29,62 @@ impl<T> Deref for ArcSlice<T> {
 
     #[inline]
     fn deref(&self) -> &Self::Target {
         debug_assert_eq!(self.0.header.header, ARC_SLICE_CANARY);
         &self.0.slice
     }
 }
 
-/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
-/// The type of the pointer is a bit of a lie, we just want to preserve the type
-/// but these pointers cannot be constructed outside of this crate, so we're
-/// good.
-#[repr(C)]
-pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
+lazy_static! {
+    // ThinArc doesn't support alignments greater than align_of::<u64>.
+    static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
+        ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
+    };
+}
+
+impl<T> Default for ArcSlice<T> {
+    #[allow(unsafe_code)]
+    fn default() -> Self {
+        debug_assert!(
+            mem::align_of::<T>() <= mem::align_of::<u64>(),
+            "Need to increase the alignment of EMPTY_ARC_SLICE"
+        );
+        unsafe {
+            let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
+            mem::transmute(empty)
+        }
+    }
+}
 
 impl<T> ArcSlice<T> {
     /// Creates an Arc for a slice using the given iterator to generate the
     /// slice.
     #[inline]
     pub fn from_iter<I>(items: I) -> Self
     where
         I: Iterator<Item = T> + ExactSizeIterator,
     {
+        if items.len() == 0 {
+            return Self::default();
+        }
         ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
     }
 
     /// Creates a value that can be passed via FFI, and forgets this value
     /// altogether.
     #[inline]
     #[allow(unsafe_code)]
     pub fn forget(self) -> ForgottenArcSlicePtr<T> {
         let ret = unsafe {
             ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.ptr() as *const _ as *mut _))
         };
         mem::forget(self);
         ret
     }
 }
+
+/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
+/// The type of the pointer is a bit of a lie, we just want to preserve the type
+/// but these pointers cannot be constructed outside of this crate, so we're
+/// good.
+#[repr(C)]
+pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
--- a/servo/components/style_traits/lib.rs
+++ b/servo/components/style_traits/lib.rs
@@ -11,16 +11,18 @@
 #![deny(unsafe_code, missing_docs)]
 
 extern crate app_units;
 #[macro_use]
 extern crate bitflags;
 #[macro_use]
 extern crate cssparser;
 extern crate euclid;
+#[macro_use]
+extern crate lazy_static;
 extern crate malloc_size_of;
 #[macro_use]
 extern crate malloc_size_of_derive;
 extern crate selectors;
 #[cfg(feature = "servo")]
 #[macro_use]
 extern crate serde;
 extern crate servo_arc;