Skip to content
This repository was archived by the owner on Aug 25, 2025. It is now read-only.

Commit c12a134

Browse files
authored
Merge pull request #38 from ZackPierce/static_array_backed
Fixed-sized backend for use with atypical targets
2 parents 36294af + e48f6bd commit c12a134

File tree

14 files changed

+184
-44
lines changed

14 files changed

+184
-44
lines changed

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ Where we need help:
141141

142142
## Team
143143

144-
| [<img alt="fitzgen" src="https://avatars2.githubusercontent.com/u/74571?s=117&v=4" width="117">](https://github.com/fitzgen) | [<img alt="pepyakin" src="https://avatars0.githubusercontent.com/u/2205845?s=117&v=4" width="117">](https://github.com/pepyakin) | [<img alt="DrGoldfire" src="https://avatars3.githubusercontent.com/u/1772277?s=117&v=4" width="117">](https://github.com/DrGoldfire) |
145-
|:---:|:---:|:---:|
146-
| [`fitzgen`](https://github.com/fitzgen) | [`pepyakin`](https://github.com/pepyakin) | [`DrGoldfire`](https://github.com/DrGoldfire) |
144+
| [<img alt="fitzgen" src="https://avatars2.githubusercontent.com/u/74571?s=117&v=4" width="117">](https://github.com/fitzgen) | [<img alt="pepyakin" src="https://avatars0.githubusercontent.com/u/2205845?s=117&v=4" width="117">](https://github.com/pepyakin) | [<img alt="DrGoldfire" src="https://avatars3.githubusercontent.com/u/1772277?s=117&v=4" width="117">](https://github.com/DrGoldfire) | [<img alt="ZackPierce" src="https://avatars0.githubusercontent.com/u/387703?s=400&v=4" width="117">](https://github.com/ZackPierce) |
145+
|:---:|:---:|:---:|:---:|
146+
| [`fitzgen`](https://github.com/fitzgen) | [`pepyakin`](https://github.com/pepyakin) | [`DrGoldfire`](https://github.com/DrGoldfire) | [`ZackPierce`](https://github.com/ZackPierce)
147147

148148
Larger, more nuanced decisions about design, architecture, breaking changes,
149149
trade offs, etc are made by team consensus. In other words, decisions on things

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
110110
runtime overhead. It is useful when debugging a use-after-free or `wee_alloc`
111111
itself.
112112

113+
- **static_array_backend**: Force the use of an OS-independent fixed-size (16 MB)
114+
backing implementation. Suitable for deploying to non-WASM/Unix/Windows
115+
`#![no_std]` environments, such as on embedded devices with esoteric or effectively
116+
absent operating systems.
117+
113118
### Implementation Notes and Constraints
114119

115120
- `wee_alloc` imposes two words of overhead on each allocation for maintaining

example/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ extern "C" fn panic_fmt(_args: ::core::fmt::Arguments, _file: &'static str, _lin
2525
}
2626
}
2727

28+
// Need to provide a tiny `oom` lang-item implementation for
29+
// `#![no_std]`.
30+
#[lang = "oom"]
31+
extern "C" fn oom() -> ! {
32+
unsafe {
33+
::core::intrinsics::abort();
34+
}
35+
}
36+
2837
// Now, use the allocator via `alloc` types! ///////////////////////////////////
2938

3039
use alloc::boxed::Box;

test.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ time cargo test --release --features "extra_assertions size_classes"
1515
time cargo test --release --features "extra_assertions"
1616
time cargo test --release --features "size_classes"
1717
time cargo test --release
18+
19+
time cargo test --release --features "static_array_backend extra_assertions size_classes"
20+
time cargo test --release --features "static_array_backend extra_assertions"
21+
time cargo test --release --features "static_array_backend size_classes"
22+
time cargo test --release --features "static_array_backend"
1823
cd -

test/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.1.0"
77
rand = "0.4.2"
88
quickcheck = "0.6.0"
99
histo = "0.1.0"
10+
cfg-if = "0.1.2"
1011

1112
[dependencies.wee_alloc]
1213
path = "../wee_alloc"
@@ -16,3 +17,4 @@ features = ["use_std_for_test_debugging"]
1617
[features]
1718
size_classes = ["wee_alloc/size_classes"]
1819
extra_assertions = ["wee_alloc/extra_assertions"]
20+
static_array_backend = ["wee_alloc/static_array_backend"]

test/benches/bench.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::io;
88
use wee_alloc_test::*;
99

1010
macro_rules! bench_trace {
11-
( $name:ident, $trace:expr ) => {
11+
($name:ident, $trace:expr) => {
1212
#[bench]
1313
#[cfg(not(feature = "extra_assertions"))]
1414
fn $name(b: &mut test::Bencher) {
@@ -18,7 +18,10 @@ macro_rules! bench_trace {
1818
let stdout = io::stdout();
1919
let _stdout = stdout.lock();
2020

21-
println!("################## {} ##################", stringify!($name));
21+
println!(
22+
"################## {} ##################",
23+
stringify!($name)
24+
);
2225
println!("#");
2326
println!("# Allocations by log2(Size)");
2427
println!("#");
@@ -34,15 +37,18 @@ macro_rules! bench_trace {
3437
operations.run_with_allocator(a);
3538
});
3639
}
37-
}
40+
};
3841
}
3942

4043
bench_trace!(bench_trace_cpp_demangle, "../traces/cpp-demangle.trace");
4144
bench_trace!(bench_trace_dogfood, "../traces/dogfood.trace");
4245
bench_trace!(bench_trace_ffmpeg, "../traces/ffmpeg.trace");
4346
bench_trace!(bench_trace_find, "../traces/find.trace");
4447
bench_trace!(bench_trace_gcc_hello, "../traces/gcc-hello.trace");
45-
bench_trace!(bench_trace_grep_random_data, "../traces/grep-random-data.trace");
48+
bench_trace!(
49+
bench_trace_grep_random_data,
50+
"../traces/grep-random-data.trace"
51+
);
4652
bench_trace!(bench_trace_grep_recursive, "../traces/grep-recursive.trace");
4753
bench_trace!(bench_trace_ls, "../traces/ls.trace");
4854
bench_trace!(bench_trace_source_map, "../traces/source-map.trace");

test/src/lib.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ extern crate alloc;
44
extern crate histo;
55
#[macro_use]
66
extern crate quickcheck;
7+
#[macro_use]
8+
extern crate cfg_if;
79
extern crate rand;
810
extern crate wee_alloc;
911

@@ -257,10 +259,10 @@ impl Operations {
257259
let handle2 = thread::spawn(move || ops2.run_with_allocator(&WEE));
258260
let handle3 = thread::spawn(move || ops3.run_with_allocator(&WEE));
259261

260-
handle0.join().unwrap();
261-
handle1.join().unwrap();
262-
handle2.join().unwrap();
263-
handle3.join().unwrap();
262+
handle0.join().expect("Thread 0 Failed");
263+
handle1.join().expect("Thread 1 Failed");
264+
handle2.join().expect("Thread 2 Failed");
265+
handle3.join().expect("Thread 3 Failed");
264266
}
265267

266268
pub fn run_with_allocator<A: Alloc>(&self, mut a: A) {
@@ -344,12 +346,17 @@ macro_rules! run_quickchecks {
344346
// with each other.
345347
run_quickchecks!(quickchecks_0);
346348
run_quickchecks!(quickchecks_1);
347-
run_quickchecks!(quickchecks_2);
348-
run_quickchecks!(quickchecks_3);
349-
run_quickchecks!(quickchecks_4);
350-
run_quickchecks!(quickchecks_5);
351-
run_quickchecks!(quickchecks_6);
352-
run_quickchecks!(quickchecks_7);
349+
// Limit the extent of the stress testing for the limited-size static backend
350+
cfg_if! {
351+
if #[cfg(not(feature = "static_array_backend"))] {
352+
run_quickchecks!(quickchecks_2);
353+
run_quickchecks!(quickchecks_3);
354+
run_quickchecks!(quickchecks_4);
355+
run_quickchecks!(quickchecks_5);
356+
run_quickchecks!(quickchecks_6);
357+
run_quickchecks!(quickchecks_7);
358+
}
359+
}
353360

354361
#[test]
355362
fn multi_threaded_quickchecks() {
@@ -389,7 +396,10 @@ test_trace!(test_trace_dogfood, "../traces/dogfood.trace");
389396
test_trace!(test_trace_ffmpeg, "../traces/ffmpeg.trace");
390397
test_trace!(test_trace_find, "../traces/find.trace");
391398
test_trace!(test_trace_gcc_hello, "../traces/gcc-hello.trace");
392-
test_trace!(test_trace_grep_random_data, "../traces/grep-random-data.trace");
399+
test_trace!(
400+
test_trace_grep_random_data,
401+
"../traces/grep-random-data.trace"
402+
);
393403
test_trace!(test_trace_grep_recursive, "../traces/grep-recursive.trace");
394404
test_trace!(test_trace_ls, "../traces/ls.trace");
395405
test_trace!(test_trace_source_map, "../traces/source-map.trace");
@@ -408,13 +418,7 @@ fn regression_test_1() {
408418

409419
#[test]
410420
fn regression_test_2() {
411-
Operations(vec![
412-
Alloc(168),
413-
Free(0),
414-
Alloc(0),
415-
Alloc(168),
416-
Free(2),
417-
]).run_single_threaded();
421+
Operations(vec![Alloc(168), Free(0), Alloc(0), Alloc(168), Free(2)]).run_single_threaded();
418422
}
419423

420424
#[test]
@@ -472,15 +476,17 @@ fn smoke() {
472476
let mut a = &wee_alloc::WeeAlloc::INIT;
473477
unsafe {
474478
let layout = Layout::new::<u8>();
475-
let ptr = a.alloc(layout.clone()).unwrap();
479+
let ptr = a.alloc(layout.clone())
480+
.expect("Should be able to alloc a fresh Layout clone");
476481
{
477482
let ptr = ptr.as_ptr() as *mut u8;
478483
*ptr = 9;
479484
assert_eq!(*ptr, 9);
480485
}
481486
a.dealloc(ptr, layout.clone());
482487

483-
let ptr = a.alloc(layout.clone()).unwrap();
488+
let ptr = a.alloc(layout.clone())
489+
.expect("Should be able to alloc from a second clone");
484490
{
485491
let ptr = ptr.as_ptr() as *mut u8;
486492
*ptr = 10;
@@ -490,9 +496,10 @@ fn smoke() {
490496
}
491497
}
492498

493-
// This takes too long with our extra assertion checks enabled.
499+
// This takes too long with our extra assertion checks enabled,
500+
// and the fixed-sized static array backend is too small.
494501
#[test]
495-
#[cfg(not(feature = "extra_assertions"))]
502+
#[cfg(not(any(feature = "extra_assertions", feature = "static_array_backend")))]
496503
fn stress() {
497504
use rand::Rng;
498505
use std::cmp;

wee_alloc/Cargo.toml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
[package]
2-
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
3-
categories = ["memory-management", "web-programming", "no-std", "wasm"]
2+
authors = [
3+
"Nick Fitzgerald <fitzgen@gmail.com>",
4+
"Sergey Pepyakin <s.pepyakin@gmail.com>",
5+
"Matt Howell <mjhowell@gmail.com>",
6+
"Zack Pierce <zachary.pierce@gmail.com>",
7+
]
8+
categories = ["memory-management", "web-programming", "no-std", "wasm", "embedded"]
49
description = "wee_alloc: The Wasm-Enabled, Elfin Allocator"
510
license = "MPL-2.0"
611
name = "wee_alloc"
@@ -20,6 +25,9 @@ extra_assertions = []
2025
# Enable size classes for amortized *O(1)* small allocations.
2126
size_classes = []
2227

28+
# Enable fixed-sized, OS-independent backing memory implementation
29+
static_array_backend = []
30+
2331
# This is for internal use only.
2432
use_std_for_test_debugging = []
2533

@@ -28,6 +36,11 @@ memory_units = "0.4.0"
2836
cfg-if = "0.1.2"
2937
unreachable = "1.0.0"
3038

39+
[dependencies.spin]
40+
version = "0.4"
41+
default-features = false
42+
features = ["const_fn"]
43+
3144
[target.'cfg(all(unix, not(target_arch = "wasm32")))'.dependencies.libc]
3245
default-features = false
3346
version = "0.2"

wee_alloc/src/imp_static_array.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use const_init::ConstInit;
2+
use core::alloc::{AllocErr, Opaque};
3+
#[cfg(feature = "extra_assertions")]
4+
use core::cell::Cell;
5+
use core::ptr::NonNull;
6+
use memory_units::{Bytes, Pages};
7+
use spin::Mutex;
8+
9+
const SCRATCH_LEN_BYTES: usize = 1024 * 1024 * 32;
10+
static mut SCRATCH_HEAP: [u8; SCRATCH_LEN_BYTES] = [0; SCRATCH_LEN_BYTES];
11+
static mut OFFSET: Mutex<usize> = Mutex::new(0);
12+
13+
pub(crate) unsafe fn alloc_pages(pages: Pages) -> Result<NonNull<Opaque>, AllocErr> {
14+
let bytes: Bytes = pages.into();
15+
let mut offset = OFFSET.lock();
16+
let end = bytes.0 + *offset;
17+
if end < SCRATCH_LEN_BYTES {
18+
let ptr = SCRATCH_HEAP[*offset..end].as_mut_ptr() as *mut u8 as *mut Opaque;
19+
*offset = end;
20+
NonNull::new(ptr).ok_or_else(|| AllocErr)
21+
} else {
22+
Err(AllocErr)
23+
}
24+
}
25+
26+
pub(crate) struct Exclusive<T> {
27+
inner: Mutex<T>,
28+
29+
#[cfg(feature = "extra_assertions")]
30+
in_use: Cell<bool>,
31+
}
32+
33+
impl<T: ConstInit> ConstInit for Exclusive<T> {
34+
const INIT: Self = Exclusive {
35+
inner: Mutex::new(T::INIT),
36+
37+
#[cfg(feature = "extra_assertions")]
38+
in_use: Cell::new(false),
39+
};
40+
}
41+
42+
extra_only! {
43+
fn assert_not_in_use<T>(excl: &Exclusive<T>) {
44+
assert!(!excl.in_use.get(), "`Exclusive<T>` is not re-entrant");
45+
}
46+
}
47+
48+
extra_only! {
49+
fn set_in_use<T>(excl: &Exclusive<T>) {
50+
excl.in_use.set(true);
51+
}
52+
}
53+
54+
extra_only! {
55+
fn set_not_in_use<T>(excl: &Exclusive<T>) {
56+
excl.in_use.set(false);
57+
}
58+
}
59+
60+
impl<T> Exclusive<T> {
61+
/// Get exclusive, mutable access to the inner value.
62+
///
63+
/// # Safety
64+
///
65+
/// It is the callers' responsibility to ensure that `f` does not re-enter
66+
/// this method for this `Exclusive` instance.
67+
//
68+
// XXX: If we don't mark this function inline, then it won't be, and the
69+
// code size also blows up by about 200 bytes.
70+
#[inline]
71+
pub(crate) unsafe fn with_exclusive_access<'a, F, U>(&'a self, f: F) -> U
72+
where
73+
for<'x> F: FnOnce(&'x mut T) -> U,
74+
{
75+
let mut guard = self.inner.lock();
76+
assert_not_in_use(self);
77+
set_in_use(self);
78+
let result = f(&mut guard);
79+
set_not_in_use(self);
80+
result
81+
}
82+
}

wee_alloc/src/imp_unix.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl<T> Exclusive<T> {
5050
#[inline]
5151
pub(crate) unsafe fn with_exclusive_access<'a, F, U>(&'a self, f: F) -> U
5252
where
53-
F: FnOnce(&'a mut T) -> U,
53+
for<'x> F: FnOnce(&'x mut T) -> U,
5454
{
5555
let code = libc::pthread_mutex_lock(&mut *self.lock.get());
5656
extra_assert_eq!(code, 0, "pthread_mutex_lock should run OK");

0 commit comments

Comments
 (0)