llvm_plugin_inkwell/
memory_buffer.rs

1use llvm_sys::core::{
2    LLVMCreateMemoryBufferWithContentsOfFile, LLVMCreateMemoryBufferWithMemoryRange,
3    LLVMCreateMemoryBufferWithMemoryRangeCopy, LLVMCreateMemoryBufferWithSTDIN, LLVMDisposeMemoryBuffer,
4    LLVMGetBufferSize, LLVMGetBufferStart,
5};
6use llvm_sys::object::LLVMCreateObjectFile;
7use llvm_sys::prelude::LLVMMemoryBufferRef;
8
9use crate::object_file::ObjectFile;
10use crate::support::{to_c_str, LLVMString};
11
12use std::mem::{forget, MaybeUninit};
13use std::path::Path;
14use std::ptr;
15use std::slice;
16
17#[derive(Debug)]
18pub struct MemoryBuffer {
19    pub(crate) memory_buffer: LLVMMemoryBufferRef,
20}
21
22impl MemoryBuffer {
23    pub unsafe fn new(memory_buffer: LLVMMemoryBufferRef) -> Self {
24        assert!(!memory_buffer.is_null());
25
26        MemoryBuffer { memory_buffer }
27    }
28
29    pub fn as_mut_ptr(&self) -> LLVMMemoryBufferRef {
30        self.memory_buffer
31    }
32
33    pub fn create_from_file(path: &Path) -> Result<Self, LLVMString> {
34        let path = to_c_str(path.to_str().expect("Did not find a valid Unicode path string"));
35        let mut memory_buffer = ptr::null_mut();
36        let mut err_string = MaybeUninit::uninit();
37
38        let return_code = unsafe {
39            LLVMCreateMemoryBufferWithContentsOfFile(
40                path.as_ptr() as *const ::libc::c_char,
41                &mut memory_buffer,
42                err_string.as_mut_ptr(),
43            )
44        };
45
46        // TODO: Verify 1 is error code (LLVM can be inconsistent)
47        if return_code == 1 {
48            unsafe {
49                return Err(LLVMString::new(err_string.assume_init()));
50            }
51        }
52
53        unsafe { Ok(MemoryBuffer::new(memory_buffer)) }
54    }
55
56    pub fn create_from_stdin() -> Result<Self, LLVMString> {
57        let mut memory_buffer = ptr::null_mut();
58        let mut err_string = MaybeUninit::uninit();
59
60        let return_code = unsafe { LLVMCreateMemoryBufferWithSTDIN(&mut memory_buffer, err_string.as_mut_ptr()) };
61
62        // TODO: Verify 1 is error code (LLVM can be inconsistent)
63        if return_code == 1 {
64            unsafe {
65                return Err(LLVMString::new(err_string.assume_init()));
66            }
67        }
68
69        unsafe { Ok(MemoryBuffer::new(memory_buffer)) }
70    }
71
72    /// This function is likely slightly cheaper than `create_from_memory_range_copy` since it intentionally
73    /// leaks data to LLVM so that it doesn't have to reallocate. `create_from_memory_range_copy` may be removed
74    /// in the future
75    pub fn create_from_memory_range(input: &[u8], name: &str) -> Self {
76        let name_c_string = to_c_str(name);
77
78        let memory_buffer = unsafe {
79            LLVMCreateMemoryBufferWithMemoryRange(
80                input.as_ptr() as *const ::libc::c_char,
81                input.len(),
82                name_c_string.as_ptr(),
83                false as i32,
84            )
85        };
86
87        unsafe { MemoryBuffer::new(memory_buffer) }
88    }
89
90    /// This will create a new `MemoryBuffer` from the given input.
91    ///
92    /// This function is likely slightly more expensive than `create_from_memory_range` since it does not leak
93    /// data to LLVM, forcing LLVM to make a copy. This function may be removed in the future in favor of
94    /// `create_from_memory_range`
95    pub fn create_from_memory_range_copy(input: &[u8], name: &str) -> Self {
96        let name_c_string = to_c_str(name);
97
98        let memory_buffer = unsafe {
99            LLVMCreateMemoryBufferWithMemoryRangeCopy(
100                input.as_ptr() as *const ::libc::c_char,
101                input.len(),
102                name_c_string.as_ptr(),
103            )
104        };
105
106        unsafe { MemoryBuffer::new(memory_buffer) }
107    }
108
109    /// Gets a byte slice of this `MemoryBuffer`.
110    pub fn as_slice(&self) -> &[u8] {
111        unsafe {
112            let start = LLVMGetBufferStart(self.memory_buffer);
113
114            slice::from_raw_parts(start as *const _, self.get_size())
115        }
116    }
117
118    /// Gets the byte size of this `MemoryBuffer`.
119    pub fn get_size(&self) -> usize {
120        unsafe { LLVMGetBufferSize(self.memory_buffer) }
121    }
122
123    /// Convert this `MemoryBuffer` into an `ObjectFile`. LLVM does not currently
124    /// provide any way to determine the cause of error if conversion fails.
125    pub fn create_object_file(self) -> Result<ObjectFile, ()> {
126        let object_file = unsafe { LLVMCreateObjectFile(self.memory_buffer) };
127
128        forget(self);
129
130        if object_file.is_null() {
131            return Err(());
132        }
133
134        unsafe { Ok(ObjectFile::new(object_file)) }
135    }
136}
137
138impl Drop for MemoryBuffer {
139    fn drop(&mut self) {
140        unsafe {
141            LLVMDisposeMemoryBuffer(self.memory_buffer);
142        }
143    }
144}