From e9f4656919a789341d873e7e42e6a8495d4d6a01 Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 18 May 2021 16:47:17 -0700 Subject: [PATCH] Optimized AlignedMemory (#168) --- src/aligned_memory.rs | 83 ++++++++++++++++++++++++++----------------- src/call_frames.rs | 3 +- src/elf.rs | 6 ++-- src/jit.rs | 2 +- 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/aligned_memory.rs b/src/aligned_memory.rs index b801425e..e11d09d5 100644 --- a/src/aligned_memory.rs +++ b/src/aligned_memory.rs @@ -3,70 +3,93 @@ /// Provides u8 slices at a specified alignment #[derive(Clone, Debug, PartialEq)] pub struct AlignedMemory { - len: usize, + max_len: usize, align_offset: usize, - write_index: usize, mem: Vec, } impl AlignedMemory { - /// Return a new AlignedMem type - pub fn new(len: usize, align: usize) -> Self { - let mem = vec![0u8; len + align]; + fn get_mem(max_len: usize, align: usize) -> (Vec, usize) { + let mut mem: Vec = Vec::with_capacity(max_len + align); + mem.push(0); let align_offset = mem.as_ptr().align_offset(align); + mem.resize(align_offset, 0); + (mem, align_offset) + } + /// Return a new AlignedMemory type + pub fn new(max_len: usize, align: usize) -> Self { + let (mem, align_offset) = Self::get_mem(max_len, align); + Self { + max_len, + align_offset, + mem, + } + } + /// Return a pre-filled AlignedMemory type + pub fn new_with_size(len: usize, align: usize) -> Self { + let (mut mem, align_offset) = Self::get_mem(len, align); + mem.resize(align_offset + len, 0); Self { - len, + max_len: len, + align_offset, + mem, + } + } + /// Return a pre-filled AlignedMemory type + pub fn new_with_data(data: &[u8], align: usize) -> Self { + let max_len = data.len(); + let (mut mem, align_offset) = Self::get_mem(max_len, align); + mem.extend_from_slice(data); + Self { + max_len, align_offset, mem, - write_index: align_offset, } } /// Get the length of the data pub fn len(&self) -> usize { - self.len + self.mem.len() - self.align_offset } /// Is the memory empty pub fn is_empty(&self) -> bool { - self.len == 0 + self.mem.len() - self.align_offset == 0 } /// Get the current write index pub fn write_index(&self) -> usize { - self.write_index + self.mem.len() } /// Get an aligned slice pub fn as_slice(&self) -> &[u8] { - &self.mem[self.align_offset..self.align_offset + self.len] + let start = self.align_offset; + let end = self.mem.len(); + &self.mem[start..end] } /// Get an aligned mutable slice pub fn as_slice_mut(&mut self) -> &mut [u8] { - &mut self.mem[self.align_offset..self.align_offset + self.len] + let start = self.align_offset; + let end = self.mem.len(); + &mut self.mem[start..end] } - /// Fill memory with value starting at the write_index - pub fn fill(&mut self, num: usize, value: u8) -> std::io::Result<()> { - if self.write_index + num > self.align_offset + self.len() { + /// resize memory with value starting at the write_index + pub fn resize(&mut self, num: usize, value: u8) -> std::io::Result<()> { + if self.mem.len() + num > self.align_offset + self.max_len { return Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, - "aligned memory fill failed", + "aligned memory resize failed", )); } - if value != 0 { - for i in 0..num { - self.mem[self.write_index + i] = value; - } - } - self.write_index += num; + self.mem.resize(self.mem.len() + num, value); Ok(()) } } impl std::io::Write for AlignedMemory { fn write(&mut self, buf: &[u8]) -> std::io::Result { - if self.write_index + buf.len() > self.align_offset + self.len() { + if self.mem.len() + buf.len() > self.align_offset + self.max_len { return Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, "aligned memory write failed", )); } - self.mem[self.write_index..self.write_index + buf.len()].copy_from_slice(buf); - self.write_index += buf.len(); + self.mem.extend_from_slice(buf); Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { @@ -81,10 +104,6 @@ mod tests { fn do_test(align: usize) { let mut aligned_memory = AlignedMemory::new(10, align); - assert!(!aligned_memory.is_empty()); - assert_eq!(aligned_memory.len(), 10); - assert_eq!(aligned_memory.as_slice().len(), 10); - assert_eq!(aligned_memory.as_slice_mut().len(), 10); assert_eq!(aligned_memory.write(&[42u8; 1]).unwrap(), 1); assert_eq!(aligned_memory.write(&[42u8; 9]).unwrap(), 9); @@ -97,11 +116,11 @@ mod tests { assert_eq!(aligned_memory.as_slice(), &[84u8; 10]); let mut aligned_memory = AlignedMemory::new(10, align); - aligned_memory.fill(5, 0).unwrap(); - aligned_memory.fill(2, 1).unwrap(); + aligned_memory.resize(5, 0).unwrap(); + aligned_memory.resize(2, 1).unwrap(); assert_eq!(aligned_memory.write(&[2u8; 3]).unwrap(), 3); assert_eq!(aligned_memory.as_slice(), &[0, 0, 0, 0, 0, 1, 1, 2, 2, 2]); - aligned_memory.fill(1, 3).unwrap_err(); + aligned_memory.resize(1, 3).unwrap_err(); aligned_memory.write(&[4u8; 1]).unwrap_err(); assert_eq!(aligned_memory.as_slice(), &[0, 0, 0, 0, 0, 1, 1, 2, 2, 2]); } diff --git a/src/call_frames.rs b/src/call_frames.rs index adb704ff..69b35189 100644 --- a/src/call_frames.rs +++ b/src/call_frames.rs @@ -29,7 +29,8 @@ pub struct CallFrames { impl CallFrames { /// New call frame, depth indicates maximum call depth pub fn new(depth: usize, frame_size: usize) -> Self { - let stack = AlignedMemory::new(depth * frame_size, HOST_ALIGN); + let mut stack = AlignedMemory::new(depth * frame_size, HOST_ALIGN); + stack.resize(depth * frame_size, 0).unwrap(); let region = MemoryRegion::new_from_slice(stack.as_slice(), MM_STACK_START, frame_size as u64, true); let mut frames = CallFrames { diff --git a/src/elf.rs b/src/elf.rs index 4e0e9b09..468cc97b 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -326,8 +326,7 @@ impl Executable for EBpfElf EBpfElf { /// Create from raw text section bytes (list of instructions) pub fn new_from_text_bytes(config: Config, text_bytes: &[u8]) -> Self { - let mut elf_bytes = AlignedMemory::new(text_bytes.len(), ebpf::HOST_ALIGN); - elf_bytes.as_slice_mut().copy_from_slice(text_bytes); + let elf_bytes = AlignedMemory::new_with_data(text_bytes, ebpf::HOST_ALIGN); Self { config, elf_bytes, @@ -350,8 +349,7 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EBpfElf { /// Fully loads an ELF, including validation and relocation pub fn load(config: Config, bytes: &[u8]) -> Result { let elf = Elf::parse(bytes)?; - let mut elf_bytes = AlignedMemory::new(bytes.len(), ebpf::HOST_ALIGN); - elf_bytes.as_slice_mut().copy_from_slice(bytes); + let mut elf_bytes = AlignedMemory::new_with_data(bytes, ebpf::HOST_ALIGN); Self::validate(&elf, &elf_bytes.as_slice())?; diff --git a/src/jit.rs b/src/jit.rs index 2a07b79a..8a64deea 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -56,7 +56,7 @@ impl JitProgramSections { } #[cfg(not(windows))] unsafe { - let mut raw: *mut libc::c_void = std::mem::MaybeUninit::uninit().assume_init(); + let mut raw: *mut libc::c_void = std::ptr::null_mut(); libc::posix_memalign(&mut raw, PAGE_SIZE, _pc_loc_table_size + _code_size); std::ptr::write_bytes(raw, 0x00, _pc_loc_table_size); std::ptr::write_bytes(raw.add(_pc_loc_table_size), 0xcc, _code_size); // Populate with debugger traps