Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 23 additions & 31 deletions library/proc_macro/src/bridge/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
//! as it is difficult to depend on crates from within `proc_macro`, due to it
//! being built at the same time as `std`.
use std::cell::{Cell, RefCell};
use std::mem::MaybeUninit;
use std::ops::Range;
use std::{cmp, ptr, slice, str};
use std::{cmp, ptr, slice};

// The arenas start with PAGE-sized chunks, and then each new chunk is twice as
// big as its predecessor, up until we reach HUGE_PAGE-sized chunks, whereupon
Expand All @@ -26,27 +25,22 @@ const HUGE_PAGE: usize = 2 * 1024 * 1024;
/// This arena doesn't have support for allocating anything other than byte
/// slices, as that is all that is necessary.
pub(crate) struct Arena {
start: Cell<*mut MaybeUninit<u8>>,
end: Cell<*mut MaybeUninit<u8>>,
chunks: RefCell<Vec<Box<[MaybeUninit<u8>]>>>,
start: *mut MaybeUninit<u8>,
end: *mut MaybeUninit<u8>,
chunks: Vec<Box<[MaybeUninit<u8>]>>,
}

impl Arena {
pub(crate) fn new() -> Self {
Arena {
start: Cell::new(ptr::null_mut()),
end: Cell::new(ptr::null_mut()),
chunks: RefCell::new(Vec::new()),
}
Arena { start: ptr::null_mut(), end: ptr::null_mut(), chunks: Vec::new() }
}

/// Add a new chunk with at least `additional` free bytes.
#[inline(never)]
#[cold]
fn grow(&self, additional: usize) {
let mut chunks = self.chunks.borrow_mut();
fn grow(&mut self, additional: usize) {
let mut new_cap;
if let Some(last_chunk) = chunks.last_mut() {
if let Some(last_chunk) = self.chunks.last_mut() {
// If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
Expand All @@ -60,48 +54,46 @@ impl Arena {

let mut chunk = Box::new_uninit_slice(new_cap);
let Range { start, end } = chunk.as_mut_ptr_range();
self.start.set(start);
self.end.set(end);
chunks.push(chunk);
self.start = start;
self.end = end;
self.chunks.push(chunk);
}

/// Allocates a byte slice with specified size from the current memory
/// chunk. Returns `None` if there is no free space left to satisfy the
/// request.
#[allow(clippy::mut_from_ref)]
fn alloc_raw_without_grow(&self, bytes: usize) -> Option<&mut [MaybeUninit<u8>]> {
let start = self.start.get().addr();
let old_end = self.end.get();
fn alloc_raw_without_grow(&mut self, bytes: usize) -> Option<&mut [MaybeUninit<u8>]> {
let start = self.start.addr();
let old_end = self.end;
let end = old_end.addr();

let new_end = end.checked_sub(bytes)?;
if start <= new_end {
let new_end = old_end.with_addr(new_end);
self.end.set(new_end);
self.end = new_end;
// SAFETY: `bytes` bytes starting at `new_end` were just reserved.
Some(unsafe { slice::from_raw_parts_mut(new_end, bytes) })
} else {
None
}
}

fn alloc_raw(&self, bytes: usize) -> &mut [MaybeUninit<u8>] {
fn alloc_raw(&mut self, bytes: usize) -> &mut [MaybeUninit<u8>] {
if bytes == 0 {
return &mut [];
}

loop {
if let Some(a) = self.alloc_raw_without_grow(bytes) {
break a;
}
// No free space left. Allocate a new chunk to satisfy the request.
// On failure the grow will panic or abort.
self.grow(bytes);
if let Some(a) = self.alloc_raw_without_grow(bytes) {
// SAFETY: the lifetime is extended here, but then constrained again in `alloc_str`.
return unsafe { &mut *(a as *mut _) };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to remove the internal mutability without this change?
I'm not sure how it's related to the rest of the commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unsafe is unfortunately needed to avoid an error[E0499]: cannot borrow *self as mutable more than once at a time. (This would be fixed with -Zpolonius.)
I removed the loop because grow will always produce enough space to hold the data, so it seemed a bit clearer to me this way (with the old code, I thought at first that grow might need to be called many times).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep the cells then.

The loop can still be refactored to if let or unwrap_or_else though.

}
// No free space left. Allocate a new chunk to satisfy the request.
// On failure the grow will panic or abort.
self.grow(bytes);
self.alloc_raw_without_grow(bytes).unwrap()
}

#[allow(clippy::mut_from_ref)] // arena allocator
pub(crate) fn alloc_str<'a>(&'a self, string: &str) -> &'a mut str {
pub(crate) fn alloc_str<'a>(&'a mut self, string: &str) -> &'a mut str {
let alloc = self.alloc_raw(string.len());
let bytes = alloc.write_copy_of_slice(string.as_bytes());

Expand Down
2 changes: 1 addition & 1 deletion library/proc_macro/src/bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ mod symbol;

use buffer::Buffer;
pub use rpc::PanicMessage;
use rpc::{Decode, DecodeMut, Encode, Reader, Writer};
use rpc::{DecodeMut, Encode, Reader, Writer};

/// Configuration for establishing an active connection between a server and a
/// client. The server creates the bridge config (`run_server` in `server.rs`),
Expand Down
7 changes: 1 addition & 6 deletions library/proc_macro/src/bridge/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use std::any::Any;
use std::io::Write;
use std::num::NonZero;
use std::str;

pub(super) type Writer = super::buffer::Buffer;

Expand All @@ -13,10 +12,6 @@ pub(super) trait Encode<S>: Sized {

pub(super) type Reader<'a> = &'a [u8];

pub(super) trait Decode<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s S) -> Self;
}

pub(super) trait DecodeMut<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self;
}
Expand All @@ -31,7 +26,7 @@ macro_rules! rpc_encode_decode {

impl<S> DecodeMut<'_, '_, S> for $ty {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
const N: usize = ::std::mem::size_of::<$ty>();
const N: usize = size_of::<$ty>();

let mut bytes = [0; N];
bytes.copy_from_slice(&r[..N]);
Expand Down
4 changes: 2 additions & 2 deletions library/proc_macro/src/bridge/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ macro_rules! define_server_handles {
}
}

impl<'s, S: Types> Decode<'_, 's, HandleStore<MarkedTypes<S>>>
impl<'s, S: Types> DecodeMut<'_, 's, HandleStore<MarkedTypes<S>>>
for &'s Marked<S::$oty, client::$oty>
{
fn decode(r: &mut Reader<'_>, s: &'s HandleStore<MarkedTypes<S>>) -> Self {
fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore<MarkedTypes<S>>) -> Self {
&s.$oty[handle::Handle::decode(r, &mut ())]
}
}
Expand Down
1 change: 0 additions & 1 deletion library/proc_macro/src/bridge/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

use std::cell::RefCell;
use std::num::NonZero;
use std::str;

use super::*;

Expand Down
Loading