Bug 1738926 Part 1: Check if sublayers need to be rebuilt. r=mstange
[gecko.git] / mozglue / static / rust / lib.rs
blob2ac10993130bb41983b21e901126e269a20c1e87
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #![cfg_attr(feature = "oom_with_hook", feature(alloc_error_hook))]
7 use arrayvec::{Array, ArrayString};
8 use std::cmp;
9 use std::ops::Deref;
10 use std::os::raw::c_char;
11 use std::os::raw::c_int;
12 use std::panic;
14 #[link(name = "wrappers")]
15 extern "C" {
16     // We can't use MOZ_Crash directly because it may be weakly linked
17     // and rust can't handle that.
18     fn RustMozCrash(filename: *const c_char, line: c_int, reason: *const c_char) -> !;
21 /// Truncate a string at the closest unicode character boundary
22 /// ```
23 /// assert_eq!(str_truncate_valid("éà", 3), "é");
24 /// assert_eq!(str_truncate_valid("éà", 4), "éè");
25 /// ```
26 fn str_truncate_valid(s: &str, mut mid: usize) -> &str {
27     loop {
28         if let Some(res) = s.get(..mid) {
29             return res;
30         }
31         mid -= 1;
32     }
35 /// Similar to ArrayString, but with terminating nul character.
36 #[derive(Debug, PartialEq)]
37 struct ArrayCString<A: Array<Item = u8> + Copy> {
38     inner: ArrayString<A>,
41 impl<S: AsRef<str>, A: Array<Item = u8> + Copy> From<S> for ArrayCString<A> {
42     /// Contrary to ArrayString::from, truncates at the closest unicode
43     /// character boundary.
44     /// ```
45     /// assert_eq!(ArrayCString::<[_; 4]>::from("éà"),
46     ///            ArrayCString::<[_; 4]>::from("é"));
47     /// assert_eq!(&*ArrayCString::<[_; 4]>::from("éà"), "é\0");
48     /// ```
49     fn from(s: S) -> Self {
50         let s = s.as_ref();
51         let len = cmp::min(s.len(), A::CAPACITY - 1);
52         let mut result = Self {
53             inner: ArrayString::from(str_truncate_valid(s, len)).unwrap(),
54         };
55         result.inner.push('\0');
56         result
57     }
60 impl<A: Array<Item = u8> + Copy> Deref for ArrayCString<A> {
61     type Target = str;
63     fn deref(&self) -> &str {
64         self.inner.as_str()
65     }
68 fn panic_hook(info: &panic::PanicInfo) {
69     // Try to handle &str/String payloads, which should handle 99% of cases.
70     let payload = info.payload();
71     let message = if let Some(s) = payload.downcast_ref::<&str>() {
72         s
73     } else if let Some(s) = payload.downcast_ref::<String>() {
74         s.as_str()
75     } else {
76         // Not the most helpful thing, but seems unlikely to happen
77         // in practice.
78         "Unhandled rust panic payload!"
79     };
80     let (filename, line) = if let Some(loc) = info.location() {
81         (loc.file(), loc.line())
82     } else {
83         ("unknown.rs", 0)
84     };
85     // Copy the message and filename to the stack in order to safely add
86     // a terminating nul character (since rust strings don't come with one
87     // and RustMozCrash wants one).
88     let message = ArrayCString::<[_; 512]>::from(message);
89     let filename = ArrayCString::<[_; 512]>::from(filename);
90     unsafe {
91         RustMozCrash(
92             filename.as_ptr() as *const c_char,
93             line as c_int,
94             message.as_ptr() as *const c_char,
95         );
96     }
99 /// Configure a panic hook to redirect rust panics to MFBT's MOZ_Crash.
100 #[no_mangle]
101 pub extern "C" fn install_rust_panic_hook() {
102     panic::set_hook(Box::new(panic_hook));
105 #[cfg(feature = "oom_with_hook")]
106 mod oom_hook {
107     use std::alloc::{set_alloc_error_hook, Layout};
109     extern "C" {
110         fn RustHandleOOM(size: usize) -> !;
111     }
113     pub fn hook(layout: Layout) {
114         unsafe {
115             RustHandleOOM(layout.size());
116         }
117     }
119     pub fn install() {
120         set_alloc_error_hook(hook);
121     }
124 #[no_mangle]
125 pub extern "C" fn install_rust_oom_hook() {
126     #[cfg(feature = "oom_with_hook")]
127     oom_hook::install();
130 #[cfg(feature = "moz_memory")]
131 mod moz_memory {
132     use std::alloc::{GlobalAlloc, Layout};
133     use std::os::raw::c_void;
135     extern "C" {
136         fn malloc(size: usize) -> *mut c_void;
138         fn free(ptr: *mut c_void);
140         fn calloc(nmemb: usize, size: usize) -> *mut c_void;
142         fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
144         #[cfg(windows)]
145         fn _aligned_malloc(size: usize, align: usize) -> *mut c_void;
147         #[cfg(not(windows))]
148         fn memalign(align: usize, size: usize) -> *mut c_void;
149     }
151     #[cfg(windows)]
152     unsafe fn memalign(align: usize, size: usize) -> *mut c_void {
153         _aligned_malloc(size, align)
154     }
156     pub struct GeckoAlloc;
158     #[inline(always)]
159     fn need_memalign(layout: Layout) -> bool {
160         // mozjemalloc guarantees a minimum alignment of 16 for all sizes, except
161         // for size classes below 16 (4 and 8).
162         layout.align() > layout.size() || layout.align() > 16
163     }
165     unsafe impl GlobalAlloc for GeckoAlloc {
166         unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
167             if need_memalign(layout) {
168                 memalign(layout.align(), layout.size()) as *mut u8
169             } else {
170                 malloc(layout.size()) as *mut u8
171             }
172         }
174         unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
175             free(ptr as *mut c_void)
176         }
178         unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
179             if need_memalign(layout) {
180                 let ptr = self.alloc(layout);
181                 if !ptr.is_null() {
182                     std::ptr::write_bytes(ptr, 0, layout.size());
183                 }
184                 ptr
185             } else {
186                 calloc(1, layout.size()) as *mut u8
187             }
188         }
190         unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
191             let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
192             if need_memalign(new_layout) {
193                 let new_ptr = self.alloc(new_layout);
194                 if !new_ptr.is_null() {
195                     let size = std::cmp::min(layout.size(), new_size);
196                     std::ptr::copy_nonoverlapping(ptr, new_ptr, size);
197                     self.dealloc(ptr, layout);
198                 }
199                 new_ptr
200             } else {
201                 realloc(ptr as *mut c_void, new_size) as *mut u8
202             }
203         }
204     }
207 #[cfg(feature = "moz_memory")]
208 #[global_allocator]
209 static A: moz_memory::GeckoAlloc = moz_memory::GeckoAlloc;