Use a 64K static for zeroed scratch space in upb

The actual construction of the zeroed block is now entirely safe.
This will be accessed in nearly every program using protobuf.
Using a static in .bss has much less overhead than an atomically-constructed
dynamic allocation and is far more predictable for space-constrained systems.

In the future, if dynamic allocation is kept, it should use std::sync::OnceLock
instead of the much less safe Once combined with `static mut`.

PiperOrigin-RevId: 609635555
pull/15924/head
Alyssa Haroldsen 1 year ago committed by Copybara-Service
parent 8afaae52d8
commit 4395d97f66
  1. 34
      rust/upb.rs

@ -19,14 +19,16 @@ use std::cell::UnsafeCell;
use std::ffi::c_int;
use std::fmt;
use std::marker::PhantomData;
use std::mem::{size_of, ManuallyDrop, MaybeUninit};
use std::mem::{align_of, size_of, ManuallyDrop, MaybeUninit};
use std::ops::Deref;
use std::ptr::{self, NonNull};
use std::slice;
use std::sync::{Once, OnceLock};
use std::sync::OnceLock;
/// See `upb/port/def.inc`.
const UPB_MALLOC_ALIGN: usize = 8;
const _CHECK_UPB_MALLOC_ALIGN_AT_LEAST_POINTER_ALIGNED: () =
assert!(UPB_MALLOC_ALIGN >= align_of::<*const ()>());
/// A wrapper over a `upb_Arena`.
///
@ -148,37 +150,23 @@ impl Drop for Arena {
}
}
static mut INTERNAL_PTR: Option<RawMessage> = None;
static INIT: Once = Once::new();
// The scratch size of 64 KiB matches the maximum supported size that a
// upb_Message can possibly be.
// TODO: Allow dynamic sized ScratchSpace.
/// The scratch size of 64 KiB matches the maximum supported size that a
/// upb_Message can possibly be.
const UPB_SCRATCH_SPACE_BYTES: usize = 65_536;
const ALIGN: usize = 32;
/// Holds a zero-initialized block of memory for use by upb.
///
/// By default, if a message is not set in cpp, a default message is created.
/// upb departs from this and returns a null ptr. However, since contiguous
/// chunks of memory filled with zeroes are legit messages from upb's point of
/// view, we can allocate a large block and refer to that when dealing
/// with readonly access.
pub struct ScratchSpace;
#[repr(C, align(8))] // align to UPB_MALLOC_ALIGN = 8
pub struct ScratchSpace([u8; UPB_SCRATCH_SPACE_BYTES]);
impl ScratchSpace {
pub fn zeroed_block(_private: Private) -> RawMessage {
unsafe {
INIT.call_once(|| {
let layout =
std::alloc::Layout::from_size_align(UPB_SCRATCH_SPACE_BYTES, ALIGN).unwrap();
let Some(ptr) =
crate::__internal::RawMessage::new(std::alloc::alloc_zeroed(layout).cast())
else {
std::alloc::handle_alloc_error(layout)
};
INTERNAL_PTR = Some(ptr)
});
INTERNAL_PTR.unwrap()
}
static ZEROED_BLOCK: ScratchSpace = ScratchSpace([0; UPB_SCRATCH_SPACE_BYTES]);
NonNull::from(&ZEROED_BLOCK).cast()
}
}

Loading…
Cancel
Save