diff --git a/D87019-thin-vec-big-endian.diff b/D87019-thin-vec-big-endian.diff new file mode 100644 index 0000000..bc8589b --- /dev/null +++ b/D87019-thin-vec-big-endian.diff @@ -0,0 +1,767 @@ +diff -up firefox-78.1.0/Cargo.lock.D87019-thin-vec-big-endian.diff firefox-78.1.0/Cargo.lock +--- firefox-78.1.0/Cargo.lock.D87019-thin-vec-big-endian.diff 2020-07-22 19:56:54.000000000 +0200 ++++ firefox-78.1.0/Cargo.lock 2020-08-17 17:04:24.133598583 +0200 +@@ -4792,12 +4792,9 @@ checksum = "8eaa81235c7058867fa8c0e7314f + + [[package]] + name = "thin-vec" +-version = "0.1.0" ++version = "0.2.1" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "73fdf4b84c65a85168477b7fb6c498e0716bc9487fba24623389ea7f51708044" +-dependencies = [ +- "libc", +-] ++checksum = "dcc760ada4a9f56fc6d0e81bd143984ebc7bb1b875a6891aa2fa613ca7394fc0" + + [[package]] + name = "thiserror" +diff -up firefox-78.1.0/gfx/webrender_bindings/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/gfx/webrender_bindings/Cargo.toml +--- firefox-78.1.0/gfx/webrender_bindings/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-08-17 17:04:24.133598583 +0200 ++++ firefox-78.1.0/gfx/webrender_bindings/Cargo.toml 2020-08-17 17:05:26.984805590 +0200 +@@ -20,7 +20,7 @@ nsstring = { path = "../../xpcom/rust/ns + bincode = "1.0" + uuid = { version = "0.8", features = ["v4"] } + fxhash = "0.2.1" +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + swgl = { path = "../wr/swgl" } + + [dependencies.webrender] +diff -up firefox-78.1.0/intl/l10n/rust/fluent-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/intl/l10n/rust/fluent-ffi/Cargo.toml +--- firefox-78.1.0/intl/l10n/rust/fluent-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:20.000000000 +0200 ++++ firefox-78.1.0/intl/l10n/rust/fluent-ffi/Cargo.toml 2020-08-17 17:04:24.134598587 +0200 +@@ -10,4 +10,4 @@ fluent-pseudo = "0.2" + intl-memoizer = "0.4" + unic-langid = "0.8" + nsstring = { path = "../../../../xpcom/rust/nsstring" } +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } +diff -up firefox-78.1.0/intl/locale/rust/fluent-langneg-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/intl/locale/rust/fluent-langneg-ffi/Cargo.toml +--- firefox-78.1.0/intl/locale/rust/fluent-langneg-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:20.000000000 +0200 ++++ firefox-78.1.0/intl/locale/rust/fluent-langneg-ffi/Cargo.toml 2020-08-17 17:04:24.134598587 +0200 +@@ -9,7 +9,7 @@ edition = "2018" + nserror = { path = "../../../../xpcom/rust/nserror" } + nsstring = { path = "../../../../xpcom/rust/nsstring" } + xpcom = { path = "../../../../xpcom/rust/xpcom" } +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + fluent-langneg = { version = "0.12.1", features = ["cldr"] } + unic-langid = "0.8" + unic-langid-ffi = { path = "../unic-langid-ffi" } +diff -up firefox-78.1.0/intl/locale/rust/unic-langid-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/intl/locale/rust/unic-langid-ffi/Cargo.toml +--- firefox-78.1.0/intl/locale/rust/unic-langid-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:20.000000000 +0200 ++++ firefox-78.1.0/intl/locale/rust/unic-langid-ffi/Cargo.toml 2020-08-17 17:04:24.134598587 +0200 +@@ -9,5 +9,5 @@ edition = "2018" + nserror = { path = "../../../../xpcom/rust/nserror" } + nsstring = { path = "../../../../xpcom/rust/nsstring" } + xpcom = { path = "../../../../xpcom/rust/xpcom" } +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + unic-langid = { version = "0.8", features = ["likelysubtags"] } +diff -up firefox-78.1.0/netwerk/socket/neqo_glue/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/netwerk/socket/neqo_glue/Cargo.toml +--- firefox-78.1.0/netwerk/socket/neqo_glue/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-08-17 17:04:24.134598587 +0200 ++++ firefox-78.1.0/netwerk/socket/neqo_glue/Cargo.toml 2020-08-17 17:05:10.352750807 +0200 +@@ -14,7 +14,7 @@ neqo-common = { tag = "v0.2.4", git = "h + nserror = { path = "../../../xpcom/rust/nserror" } + nsstring = { path = "../../../xpcom/rust/nsstring" } + xpcom = { path = "../../../xpcom/rust/xpcom" } +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + + [dependencies.neqo-crypto] + tag = "v0.2.4" +diff -up firefox-78.1.0/security/manager/ssl/cert_storage/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/security/manager/ssl/cert_storage/Cargo.toml +--- firefox-78.1.0/security/manager/ssl/cert_storage/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 19:56:55.000000000 +0200 ++++ firefox-78.1.0/security/manager/ssl/cert_storage/Cargo.toml 2020-08-17 17:04:24.134598587 +0200 +@@ -18,6 +18,6 @@ rust_cascade = "0.6.0" + sha2 = "^0.8" + storage_variant = { path = "../../../../storage/variant" } + tempfile = "3" +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + time = "0.1" + xpcom = { path = "../../../../xpcom/rust/xpcom" } +diff -up firefox-78.1.0/services/fxaccounts/rust-bridge/firefox-accounts-bridge/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/services/fxaccounts/rust-bridge/firefox-accounts-bridge/Cargo.toml +--- firefox-78.1.0/services/fxaccounts/rust-bridge/firefox-accounts-bridge/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-08-17 17:04:24.134598587 +0200 ++++ firefox-78.1.0/services/fxaccounts/rust-bridge/firefox-accounts-bridge/Cargo.toml 2020-08-17 17:04:52.432691786 +0200 +@@ -20,5 +20,5 @@ nserror = { path = "../../../../xpcom/ru + nsstring = { path = "../../../../xpcom/rust/nsstring" } + xpcom = { path = "../../../../xpcom/rust/xpcom" } + storage_variant = { path = "../../../../storage/variant" } +-thin-vec = { version = "0.1", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + fxa-client = { git = "https://github.com/mozilla/application-services", rev = "61dcc364ac0d6d0816ab88a494bbf20d824b009b", features = ["gecko"] } +diff -up firefox-78.1.0/services/sync/golden_gate/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/services/sync/golden_gate/Cargo.toml +--- firefox-78.1.0/services/sync/golden_gate/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:24.000000000 +0200 ++++ firefox-78.1.0/services/sync/golden_gate/Cargo.toml 2020-08-17 17:04:24.134598587 +0200 +@@ -19,5 +19,5 @@ sync15-traits = { git = "https://github. + xpcom = { path = "../../../xpcom/rust/xpcom" } + + [dependencies.thin-vec] +-version = "0.1.0" ++version = "0.2.1" + features = ["gecko-ffi"] +diff -up firefox-78.1.0/third_party/rust/thin-vec/.cargo-checksum.json.D87019-thin-vec-big-endian.diff firefox-78.1.0/third_party/rust/thin-vec/.cargo-checksum.json +--- firefox-78.1.0/third_party/rust/thin-vec/.cargo-checksum.json.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:29.000000000 +0200 ++++ firefox-78.1.0/third_party/rust/thin-vec/.cargo-checksum.json 2020-08-17 17:04:24.134598587 +0200 +@@ -1 +1 @@ +-{"files":{"Cargo.toml":"fb96cad605ae48215811808c1cc1b9a50248f2b14542058094b23983e2f8d8a0","README.md":"c26d7101e3031e7dd8890ce938e50cad7a1e6adf7fc2f2b0d3c36b03afe68c0b","src/heap.rs":"fe84a4ff433568d5713685456d87597ac5dcdb9d5190061a3da8074240ba1bc3","src/lib.rs":"ce36db8e3464dddade7c1ddbe3ee1f5e525af5be492ea51a0d8a0776c1adfc28","src/range.rs":"bac59bcb6230367a39c7e28ac15263e4526f966cd8c72015873017f17c115aaa"},"package":"73fdf4b84c65a85168477b7fb6c498e0716bc9487fba24623389ea7f51708044"} +\ No newline at end of file ++{"files":{"Cargo.toml":"754c05523d17eb7591c3ea2c9294e47c05fbb257fed04b78546fb2ec7cafa8b4","README.md":"c26d7101e3031e7dd8890ce938e50cad7a1e6adf7fc2f2b0d3c36b03afe68c0b","src/lib.rs":"627c6094c3f0286dba25bc73f5672c06c5061c25b01c513d213cbdda100673a2"},"package":"dcc760ada4a9f56fc6d0e81bd143984ebc7bb1b875a6891aa2fa613ca7394fc0"} +\ No newline at end of file +diff -up firefox-78.1.0/third_party/rust/thin-vec/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/third_party/rust/thin-vec/Cargo.toml +--- firefox-78.1.0/third_party/rust/thin-vec/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:29.000000000 +0200 ++++ firefox-78.1.0/third_party/rust/thin-vec/Cargo.toml 2020-08-17 17:04:24.135598590 +0200 +@@ -3,7 +3,7 @@ + # When uploading crates to the registry Cargo will automatically + # "normalize" Cargo.toml files for maximal compatibility + # with all versions of Cargo and also rewrite `path` dependencies +-# to registry (e.g. crates.io) dependencies ++# to registry (e.g., crates.io) dependencies + # + # If you believe there's an error in this file please file an + # issue against the rust-lang/cargo repository. If you're +@@ -11,16 +11,17 @@ + # will likely look very different (and much more reasonable) + + [package] ++edition = "2018" + name = "thin-vec" +-version = "0.1.0" ++version = "0.2.1" + authors = ["Alexis Beingessner "] + description = "a vec that takes up less space on the stack" + homepage = "https://github.com/gankro/thin-vec" + readme = "README.md" + license = "MIT/Apache-2.0" + repository = "https://github.com/gankro/thin-vec" +-[dependencies.libc] +-version = "0.2" ++ ++[dependencies] + + [features] + default = [] +diff -up firefox-78.1.0/third_party/rust/thin-vec/src/heap.rs.D87019-thin-vec-big-endian.diff firefox-78.1.0/third_party/rust/thin-vec/src/heap.rs +diff -up firefox-78.1.0/third_party/rust/thin-vec/src/lib.rs.D87019-thin-vec-big-endian.diff firefox-78.1.0/third_party/rust/thin-vec/src/lib.rs +--- firefox-78.1.0/third_party/rust/thin-vec/src/lib.rs.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:28.000000000 +0200 ++++ firefox-78.1.0/third_party/rust/thin-vec/src/lib.rs 2020-08-17 17:04:24.135598590 +0200 +@@ -1,50 +1,252 @@ +-mod range; ++//! ThinVec is exactly the same as Vec, except that it stores its `len` and `capacity` in the buffer ++//! it allocates. ++//! ++//! This makes the memory footprint of ThinVecs lower; notably in cases where space is reserved for ++//! a non-existence ThinVec. So `Vec>` and `Option>::None` will waste less ++//! space. Being pointer-sized also means it can be passed/stored in registers. ++//! ++//! Of course, any actually constructed ThinVec will theoretically have a bigger allocation, but ++//! the fuzzy nature of allocators means that might not actually be the case. ++//! ++//! Properties of Vec that are preserved: ++//! * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton) ++//! * reallocation can be done in place ++//! * `size_of::>()` == `size_of::>>()` ++//! ++//! Properties of Vec that aren't preserved: ++//! * `ThinVec` can't ever be zero-cost roundtripped to a `Box<[T]>`, `String`, or `*mut T` ++//! * `from_raw_parts` doesn't exist ++//! * ThinVec currently doesn't bother to not-allocate for Zero Sized Types (e.g. `ThinVec<()>`), ++//! but it could be done if someone cared enough to implement it. ++//! ++//! ++//! ++//! # Gecko FFI ++//! ++//! If you enable the gecko-ffi feature, ThinVec will verbatim bridge with the nsTArray type in ++//! Gecko (Firefox). That is, ThinVec and nsTArray have identical layouts *but not ABIs*, ++//! so nsTArrays/ThinVecs an be natively manipulated by C++ and Rust, and ownership can be ++//! transferred across the FFI boundary (**IF YOU ARE CAREFUL, SEE BELOW!!**). ++//! ++//! While this feature is handy, it is also inherently dangerous to use because Rust and C++ do not ++//! know about eachother. Specifically, this can be an issue with non-POD types (types which ++//! have destructors, move constructors, or are `!Copy`). ++//! ++//! ## Do Not Pass By Value ++//! ++//! The biggest thing to keep in mind is that **FFI functions cannot pass ThinVec/nsTArray ++//! by-value**. That is, these are busted APIs: ++//! ++//! ```rust,ignore ++//! // BAD WRONG ++//! extern fn process_data(data: ThinVec) { ... } ++//! // BAD WRONG ++//! extern fn get_data() -> ThinVec { ... } ++//! ``` ++//! ++//! You must instead pass by-reference: ++//! ++//! ```rust ++//! # use thin_vec::*; ++//! # use std::mem; ++//! ++//! // Read-only access, ok! ++//! extern fn process_data(data: &ThinVec) { ++//! for val in data { ++//! println!("{}", val); ++//! } ++//! } ++//! ++//! // Replace with empty instance to take ownership, ok! ++//! extern fn consume_data(data: &mut ThinVec) { ++//! let owned = mem::replace(data, ThinVec::new()); ++//! mem::drop(owned); ++//! } ++//! ++//! // Mutate input, ok! ++//! extern fn add_data(dataset: &mut ThinVec) { ++//! dataset.push(37); ++//! dataset.push(12); ++//! } ++//! ++//! // Return via out-param, usually ok! ++//! // ++//! // WARNING: output must be initialized! (Empty nsTArrays are free, so just do it!) ++//! extern fn get_data(output: &mut ThinVec) { ++//! *output = thin_vec![1, 2, 3, 4, 5]; ++//! } ++//! ``` ++//! ++//! Ignorable Explanation For Those Who Really Want To Know Why: ++//! ++//! > The fundamental issue is that Rust and C++ can't currently communicate about destructors, and ++//! > the semantics of C++ require destructors of function arguments to be run when the function ++//! > returns. Whether the callee or caller is responsible for this is also platform-specific, so ++//! > trying to hack around it manually would be messy. ++//! > ++//! > Also a type having a destructor changes its C++ ABI, because that type must actually exist ++//! > in memory (unlike a trivial struct, which is often passed in registers). We don't currently ++//! > have a way to communicate to Rust that this is happening, so even if we worked out the ++//! > destructor issue with say, MaybeUninit, it would still be a non-starter without some RFCs ++//! > to add explicit rustc support. ++//! > ++//! > Realistically, the best answer here is to have a "heavier" bindgen that can secretly ++//! > generate FFI glue so we can pass things "by value" and have it generate by-reference code ++//! > behind our back (like the cxx crate does). This would muddy up debugging/searchfox though. ++//! ++//! ## Types Should Be Trivially Relocatable ++//! ++//! Types in Rust are always trivially relocatable (unless suitably borrowed/[pinned][]/hidden). ++//! This means all Rust types are legal to relocate with a bitwise copy, you cannot provide ++//! copy or move constructors to execute when this happens, and the old location won't have its ++//! destructor run. This will cause problems for types which have a significant location ++//! (types that intrusively point into themselves or have their location registered with a service). ++//! ++//! While relocations are generally predictable if you're very careful, **you should avoid using ++//! types with significant locations with Rust FFI**. ++//! ++//! Specifically, ThinVec will trivially relocate its contents whenever it needs to reallocate its ++//! buffer to change its capacity. This is the default reallocation strategy for nsTArray, and is ++//! suitable for the vast majority of types. Just be aware of this limitation! ++//! ++//! ## Auto Arrays Are Dangerous ++//! ++//! ThinVec has *some* support for handling auto arrays which store their buffer on the stack, ++//! but this isn't well tested. ++//! ++//! Regardless of how much support we provide, Rust won't be aware of the buffer's limited lifetime, ++//! so standard auto array safety caveats apply about returning/storing them! ThinVec won't ever ++//! produce an auto array on its own, so this is only an issue for transferring an nsTArray into ++//! Rust. ++//! ++//! ## Other Issues ++//! ++//! Standard FFI caveats also apply: ++//! ++//! * Rust is more strict about POD types being initialized (use MaybeUninit if you must) ++//! * `ThinVec` has no idea if the C++ version of `T` has move/copy/assign/delete overloads ++//! * `nsTArray` has no idea if the Rust version of `T` has a Drop/Clone impl ++//! * C++ can do all sorts of unsound things that Rust can't catch ++//! * C++ and Rust don't agree on how zero-sized/empty types should be handled ++//! ++//! The gecko-ffi feature will not work if you aren't linking with code that has nsTArray ++//! defined. Specifically, we must share the symbol for nsTArray's empty singleton. You will get ++//! linking errors if that isn't defined. ++//! ++//! The gecko-ffi feature also limits ThinVec to the legacy behaviors of nsTArray. Most notably, ++//! nsTArray has a maximum capacity of i32::MAX (~2.1 billion items). Probably not an issue. ++//! Probably. ++//! ++//! [pinned]: https://doc.rust-lang.org/std/pin/index.html + + use std::{fmt, io, ptr, mem, slice}; + use std::collections::Bound; + use std::iter::FromIterator; + use std::slice::IterMut; +-use std::ops::{Deref, DerefMut}; ++use std::ops::{Deref, DerefMut, RangeBounds}; + use std::marker::PhantomData; ++use std::alloc::*; + use std::cmp::*; + use std::hash::*; + use std::borrow::*; +-use range::RangeArgument; + use std::ptr::NonNull; + +-// Heap shimming because reasons. This doesn't unfortunately match the heap api +-// right now because reasons. +-mod heap; ++use impl_details::*; + +-#[cfg(not(feature = "gecko-ffi"))] +-type SizeType = usize; +-#[cfg(feature = "gecko-ffi")] +-type SizeType = u32; +- +-#[cfg(feature = "gecko-ffi")] +-const AUTO_MASK: u32 = 1 << 31; +-#[cfg(feature = "gecko-ffi")] +-const CAP_MASK: u32 = !AUTO_MASK; ++// modules: a simple way to cfg a whole bunch of impl details at once + + #[cfg(not(feature = "gecko-ffi"))] +-const MAX_CAP: usize = !0; +-#[cfg(feature = "gecko-ffi")] +-const MAX_CAP: usize = i32::max_value() as usize; ++mod impl_details { ++ pub type SizeType = usize; ++ pub const MAX_CAP: usize = !0; + +-#[cfg(not(feature = "gecko-ffi"))] +-#[inline(always)] +-fn assert_size(x: usize) -> SizeType { x } ++ #[inline(always)] ++ pub fn assert_size(x: usize) -> SizeType { x } ++} + + #[cfg(feature = "gecko-ffi")] +-#[inline] +-fn assert_size(x: usize) -> SizeType { +- if x > MAX_CAP as usize { +- panic!("nsTArray size may not exceed the capacity of a 32-bit sized int"); ++mod impl_details { ++ // Support for briding a gecko nsTArray verbatim into a ThinVec. ++ // ++ // ThinVec can't see copy/move/delete implementations ++ // from C++ ++ // ++ // The actual layout of an nsTArray is: ++ // ++ // ```cpp ++ // struct { ++ // uint32_t mLength; ++ // uint32_t mCapacity: 31; ++ // uint32_t mIsAutoArray: 1; ++ // } ++ // ``` ++ // ++ // Rust doesn't natively support bit-fields, so we manually mask ++ // and shift the bit. When the "auto" bit is set, the header and buffer ++ // are actually on the stack, meaning the ThinVec pointer-to-header ++ // is essentially an "owned borrow", and therefore dangerous to handle. ++ // There are no safety guards for this situation. ++ // ++ // On little-endian platforms, the auto bit will be the high-bit of ++ // our capacity u32. On big-endian platforms, it will be the low bit. ++ // Hence we need some platform-specific CFGs for the necessary masking/shifting. ++ // ++ // ThinVec won't ever construct an auto array. They only happen when ++ // bridging from C++. This means we don't need to ever set/preserve the bit. ++ // We just need to be able to read and handle it if it happens to be there. ++ // ++ // Handling the auto bit mostly just means not freeing/reallocating the buffer. ++ ++ pub type SizeType = u32; ++ ++ pub const MAX_CAP: usize = i32::max_value() as usize; ++ ++ // Little endian: the auto bit is the high bit, and the capacity is ++ // verbatim. So we just need to mask off the high bit. Note that ++ // this masking is unnecessary when packing, because assert_size ++ // guards against the high bit being set. ++ #[cfg(target_endian = "little")] ++ pub fn pack_capacity(cap: SizeType) -> SizeType { ++ cap as SizeType ++ } ++ #[cfg(target_endian = "little")] ++ pub fn unpack_capacity(cap: SizeType) -> usize { ++ (cap as usize) & !(1 << 31) ++ } ++ #[cfg(target_endian = "little")] ++ pub fn is_auto(cap: SizeType) -> bool { ++ (cap & (1 << 31)) != 0 ++ } ++ ++ // Big endian: the auto bit is the low bit, and the capacity is ++ // shifted up one bit. Masking out the auto bit is unnecessary, ++ // as rust shifts always shift in 0's for unsigned integers. ++ #[cfg(target_endian = "big")] ++ pub fn pack_capacity(cap: SizeType) -> SizeType { ++ (cap as SizeType) << 1 ++ } ++ #[cfg(target_endian = "big")] ++ pub fn unpack_capacity(cap: SizeType) -> usize { ++ (cap >> 1) as usize ++ } ++ #[cfg(target_endian = "big")] ++ pub fn is_auto(cap: SizeType) -> bool { ++ (cap & 1) != 0 ++ } ++ ++ #[inline] ++ pub fn assert_size(x: usize) -> SizeType { ++ if x > MAX_CAP as usize { ++ panic!("nsTArray size may not exceed the capacity of a 32-bit sized int"); ++ } ++ x as SizeType + } +- x as SizeType ++ + } + +-/// The header of a ThinVec ++/// The header of a ThinVec. ++/// ++/// The _cap can be a bitfield, so use accessors to avoid trouble. + #[repr(C)] + struct Header { + _len: SizeType, +@@ -56,38 +258,10 @@ impl Header { + self._len as usize + } + +- #[cfg(feature = "gecko-ffi")] +- fn cap(&self) -> usize { +- (self._cap & CAP_MASK) as usize +- } +- +- #[cfg(not(feature = "gecko-ffi"))] +- fn cap(&self) -> usize { +- self._cap as usize +- } +- + fn set_len(&mut self, len: usize) { + self._len = assert_size(len); + } + +- #[cfg(feature = "gecko-ffi")] +- fn set_cap(&mut self, cap: usize) { +- debug_assert!(cap & (CAP_MASK as usize) == cap); +- // FIXME: this is busted because it reads uninit memory +- // debug_assert!(!self.uses_stack_allocated_buffer()); +- self._cap = assert_size(cap) & CAP_MASK; +- } +- +- #[cfg(feature = "gecko-ffi")] +- fn uses_stack_allocated_buffer(&self) -> bool { +- self._cap & AUTO_MASK != 0 +- } +- +- #[cfg(not(feature = "gecko-ffi"))] +- fn set_cap(&mut self, cap: usize) { +- self._cap = assert_size(cap); +- } +- + fn data(&self) -> *mut T { + let header_size = mem::size_of::
(); + let padding = padding::(); +@@ -105,6 +279,41 @@ impl Header { + } + } + ++ ++#[cfg(feature = "gecko-ffi")] ++impl Header { ++ fn cap(&self) -> usize { ++ unpack_capacity(self._cap) ++ } ++ ++ fn set_cap(&mut self, cap: usize) { ++ // debug check that our packing is working ++ debug_assert_eq!(unpack_capacity(pack_capacity(cap as SizeType)), cap); ++ // FIXME: this assert is busted because it reads uninit memory ++ // debug_assert!(!self.uses_stack_allocated_buffer()); ++ ++ // NOTE: this always stores a cleared auto bit, because set_cap ++ // is only invoked by Rust, and Rust doesn't create auto arrays. ++ self._cap = pack_capacity(assert_size(cap)); ++ } ++ ++ fn uses_stack_allocated_buffer(&self) -> bool { ++ is_auto(self._cap) ++ } ++} ++ ++#[cfg(not(feature = "gecko-ffi"))] ++impl Header { ++ fn cap(&self) -> usize { ++ self._cap as usize ++ } ++ ++ fn set_cap(&mut self, cap: usize) { ++ self._cap = assert_size(cap); ++ } ++} ++ ++ + /// Singleton that all empty collections share. + /// Note: can't store non-zero ZSTs, we allocate in that case. We could + /// optimize everything to not do that (basically, make ptr == len and branch +@@ -121,9 +330,7 @@ extern { + + // TODO: overflow checks everywhere + +-// Utils +- +-fn oom() -> ! { std::process::abort() } ++// Utils for computing layouts of allocations + + fn alloc_size(cap: usize) -> usize { + // Compute "real" header size with pointer math +@@ -156,15 +363,22 @@ fn alloc_align() -> usize { + max(mem::align_of::(), mem::align_of::
()) + } + +-fn header_with_capacity(cap: usize) -> NonNull
{ +- debug_assert!(cap > 0); ++fn layout(cap: usize) -> Layout { + unsafe { +- let header = heap::allocate( ++ Layout::from_size_align_unchecked( + alloc_size::(cap), + alloc_align::(), +- ) as *mut Header; ++ ) ++ } ++} + +- if header.is_null() { oom() } ++fn header_with_capacity(cap: usize) -> NonNull
{ ++ debug_assert!(cap > 0); ++ unsafe { ++ let layout = layout::(cap); ++ let header = alloc(layout) as *mut Header; ++ ++ if header.is_null() { handle_alloc_error(layout) } + + // "Infinite" capacity for zero-sized types: + (*header).set_cap(if mem::size_of::() == 0 { MAX_CAP } else { cap }); +@@ -176,28 +390,8 @@ fn header_with_capacity(cap: usize) - + + + +-/// ThinVec is exactly the same as Vec, except that it stores its `len` and `capacity` in the buffer +-/// it allocates. +-/// +-/// This makes the memory footprint of ThinVecs lower; notably in cases where space is reserved for +-/// a non-existence ThinVec. So `Vec>` and `Option>::None` will waste less +-/// space. Being pointer-sized also means it can be passed/stored in registers. +-/// +-/// Of course, any actually constructed ThinVec will theoretically have a bigger allocation, but +-/// the fuzzy nature of allocators means that might not actually be the case. +-/// +-/// Properties of Vec that are preserved: +-/// * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton) +-/// * reallocation can be done in place +-/// * `size_of::>()` == `size_of::>>()` +-/// * NOTE: This is only possible when the `unstable` feature is used. +-/// +-/// Properties of Vec that aren't preserved: +-/// * `ThinVec` can't ever be zero-cost roundtripped to a `Box<[T]>`, `String`, or `*mut T` +-/// * `from_raw_parts` doesn't exist +-/// * ThinVec currently doesn't bother to not-allocate for Zero Sized Types (e.g. `ThinVec<()>`), +-/// but it could be done if someone cared enough to implement it. +-#[cfg_attr(feature = "gecko-ffi", repr(C))] ++/// See the crate's top level documentation for a description of this type. ++#[repr(C)] + pub struct ThinVec { + ptr: NonNull
, + boo: PhantomData, +@@ -627,15 +821,15 @@ impl ThinVec { + } + + pub fn drain(&mut self, range: R) -> Drain +- where R: RangeArgument ++ where R: RangeBounds + { + let len = self.len(); +- let start = match range.start() { ++ let start = match range.start_bound() { + Bound::Included(&n) => n, + Bound::Excluded(&n) => n + 1, + Bound::Unbounded => 0, + }; +- let end = match range.end() { ++ let end = match range.end_bound() { + Bound::Included(&n) => n + 1, + Bound::Excluded(&n) => n, + Bound::Unbounded => len, +@@ -666,9 +860,10 @@ impl ThinVec { + + unsafe fn deallocate(&mut self) { + if self.has_allocation() { +- heap::deallocate(self.ptr() as *mut u8, +- alloc_size::(self.capacity()), +- alloc_align::()); ++ dealloc( ++ self.ptr() as *mut u8, ++ layout::(self.capacity()), ++ ) + } + } + +@@ -678,15 +873,36 @@ impl ThinVec { + debug_assert!(new_cap > 0); + if self.has_allocation() { + let old_cap = self.capacity(); +- let ptr = heap::reallocate(self.ptr() as *mut u8, +- alloc_size::(old_cap), +- alloc_size::(new_cap), +- alloc_align::()) as *mut Header; +- if ptr.is_null() { oom() } ++ let ptr = realloc( ++ self.ptr() as *mut u8, ++ layout::(old_cap), ++ alloc_size::(new_cap), ++ ) as *mut Header; ++ ++ if ptr.is_null() { handle_alloc_error(layout::(new_cap)) } + (*ptr).set_cap(new_cap); + self.ptr = NonNull::new_unchecked(ptr); + } else { +- self.ptr = header_with_capacity::(new_cap); ++ let mut new_header = header_with_capacity::(new_cap); ++ ++ // If we get here and have a non-zero len, then we must be handling ++ // a gecko auto array, and we have items in a stack buffer. We shouldn't ++ // free it, but we should memcopy the contents out of it and mark it as empty. ++ // ++ // T is assumed to be trivially relocatable, as this is ~required ++ // for Rust compatibility anyway. Furthermore, we assume C++ won't try ++ // to unconditionally destroy the contents of the stack allocated buffer ++ // (i.e. it's obfuscated behind a union). ++ // ++ // In effect, we are partially reimplementing the auto array move constructor ++ // by leaving behind a valid empty instance. ++ let len = self.len(); ++ if cfg!(feature = "gecko-ffi") && len > 0 { ++ new_header.as_mut().data::().copy_from_nonoverlapping(self.data_raw(), len); ++ self.set_len(0); ++ } ++ ++ self.ptr = new_header; + } + } + +@@ -1087,10 +1303,7 @@ mod tests { + use std::mem::size_of; + assert_eq!(size_of::>(), size_of::<&u8>()); + +- // We don't perform the null-pointer optimization on stable rust. +- if cfg!(feature = "unstable") { +- assert_eq!(size_of::>>(), size_of::<&u8>()); +- } ++ assert_eq!(size_of::>>(), size_of::<&u8>()); + } + + #[test] +@@ -1725,7 +1938,6 @@ mod std_tests { + assert_eq!(v, &[(), ()]); + } + +-/* TODO: support inclusive ranges + #[test] + fn test_drain_inclusive_range() { + let mut v = thin_vec!['a', 'b', 'c', 'd', 'e']; +@@ -1755,6 +1967,7 @@ mod std_tests { + } + + #[test] ++ #[cfg(not(feature = "gecko-ffi"))] + fn test_drain_max_vec_size() { + let mut v = ThinVec::<()>::with_capacity(usize::max_value()); + unsafe { v.set_len(usize::max_value()); } +@@ -1775,7 +1988,6 @@ mod std_tests { + let mut v = thin_vec![1, 2, 3, 4, 5]; + v.drain(5..=5); + } +-*/ + + /* TODO: implement splice? + #[test] +@@ -2181,7 +2393,7 @@ mod std_tests { + assert!(v.capacity() >= 33) + } + +-/* TODO: implement try_reserve ++/* TODO: implement try_reserve + #[test] + fn test_try_reserve() { + +diff -up firefox-78.1.0/third_party/rust/thin-vec/src/range.rs.D87019-thin-vec-big-endian.diff firefox-78.1.0/third_party/rust/thin-vec/src/range.rs +diff -up firefox-78.1.0/toolkit/components/cascade_bloom_filter/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/toolkit/components/cascade_bloom_filter/Cargo.toml +--- firefox-78.1.0/toolkit/components/cascade_bloom_filter/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:29.000000000 +0200 ++++ firefox-78.1.0/toolkit/components/cascade_bloom_filter/Cargo.toml 2020-08-17 17:04:24.135598590 +0200 +@@ -8,5 +8,5 @@ nserror = { path = "../../../xpcom/rust/ + nsstring = { path = "../../../xpcom/rust/nsstring" } + rental = "0.5.5" + rust_cascade = "0.6.0" +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + xpcom = { path = "../../../xpcom/rust/xpcom" } +diff -up firefox-78.1.0/toolkit/components/extensions/storage/webext_storage_bridge/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/toolkit/components/extensions/storage/webext_storage_bridge/Cargo.toml +--- firefox-78.1.0/toolkit/components/extensions/storage/webext_storage_bridge/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:30.000000000 +0200 ++++ firefox-78.1.0/toolkit/components/extensions/storage/webext_storage_bridge/Cargo.toml 2020-08-17 17:04:24.135598590 +0200 +@@ -13,7 +13,7 @@ moz_task = { path = "../../../../../xpco + nserror = { path = "../../../../../xpcom/rust/nserror" } + nsstring = { path = "../../../../../xpcom/rust/nsstring" } + once_cell = "1" +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + xpcom = { path = "../../../../../xpcom/rust/xpcom" } + serde = "1" + serde_json = "1" +diff -up firefox-78.1.0/toolkit/components/kvstore/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/toolkit/components/kvstore/Cargo.toml +--- firefox-78.1.0/toolkit/components/kvstore/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:30.000000000 +0200 ++++ firefox-78.1.0/toolkit/components/kvstore/Cargo.toml 2020-08-17 17:04:24.135598590 +0200 +@@ -18,7 +18,7 @@ rkv = "0.10.2" + storage_variant = { path = "../../../storage/variant" } + xpcom = { path = "../../../xpcom/rust/xpcom" } + tempfile = "3" +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } + + # Get rid of failure's dependency on backtrace. Eventually + # backtrace will move into Rust core, but we don't need it here. +diff -up firefox-78.1.0/toolkit/components/places/bookmark_sync/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/toolkit/components/places/bookmark_sync/Cargo.toml +--- firefox-78.1.0/toolkit/components/places/bookmark_sync/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:30.000000000 +0200 ++++ firefox-78.1.0/toolkit/components/places/bookmark_sync/Cargo.toml 2020-08-17 17:04:24.135598590 +0200 +@@ -19,5 +19,5 @@ url = "2.0" + xpcom = { path = "../../../../xpcom/rust/xpcom" } + + [dependencies.thin-vec] +-version = "0.1.0" ++version = "0.2.1" + features = ["gecko-ffi"] +diff -up firefox-78.1.0/tools/profiler/rust-helper/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/tools/profiler/rust-helper/Cargo.toml +--- firefox-78.1.0/tools/profiler/rust-helper/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:30.000000000 +0200 ++++ firefox-78.1.0/tools/profiler/rust-helper/Cargo.toml 2020-08-17 17:04:24.135598590 +0200 +@@ -23,7 +23,7 @@ features = ["endian_fd", "elf32", "elf64 + default-features = false + + [dependencies.thin-vec] +-version = "0.1.0" ++version = "0.2.1" + features = ["gecko-ffi"] + + [features] +diff -up firefox-78.1.0/xpcom/rust/xpcom/Cargo.toml.D87019-thin-vec-big-endian.diff firefox-78.1.0/xpcom/rust/xpcom/Cargo.toml +--- firefox-78.1.0/xpcom/rust/xpcom/Cargo.toml.D87019-thin-vec-big-endian.diff 2020-07-22 17:56:30.000000000 +0200 ++++ firefox-78.1.0/xpcom/rust/xpcom/Cargo.toml 2020-08-17 17:04:24.136598593 +0200 +@@ -9,4 +9,4 @@ nsstring = { path = "../nsstring" } + nserror = { path = "../nserror" } + threadbound = "0.1" + xpcom_macros = { path = "xpcom_macros" } +-thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } ++thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }