inkwell/
memory_buffer.rs

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