blob: 6d8178320febd8071cf342d6d2edc39afd0d5ed2 [file] [log] [blame]
use std::assert_matches::assert_matches;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr::NonNull;
use rustc_data_structures::small_c_str::SmallCStr;
use crate::errors::LlvmError;
use crate::llvm;
/// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
/// Not cloneable as there is no clone function for llvm::TargetMachine.
#[repr(transparent)]
pub struct OwnedTargetMachine {
tm_unique: NonNull<llvm::TargetMachine>,
phantom: PhantomData<llvm::TargetMachine>,
}
impl OwnedTargetMachine {
pub(crate) fn new(
triple: &CStr,
cpu: &CStr,
features: &CStr,
abi: &CStr,
model: llvm::CodeModel,
reloc: llvm::RelocModel,
level: llvm::CodeGenOptLevel,
float_abi: llvm::FloatAbi,
function_sections: bool,
data_sections: bool,
unique_section_names: bool,
trap_unreachable: bool,
singlethread: bool,
verbose_asm: bool,
emit_stack_size_section: bool,
relax_elf_relocations: bool,
use_init_array: bool,
split_dwarf_file: &CStr,
output_obj_file: &CStr,
debug_info_compression: &CStr,
use_emulated_tls: bool,
args_cstr_buff: &[u8],
use_wasm_eh: bool,
) -> Result<Self, LlvmError<'static>> {
// The argument list is passed as the concatenation of one or more C strings.
// This implies that there must be a last byte, and it must be 0.
assert_matches!(args_cstr_buff, [.., b'\0'], "the last byte must be a NUL terminator");
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
let tm_ptr = unsafe {
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(),
cpu.as_ptr(),
features.as_ptr(),
abi.as_ptr(),
model,
reloc,
level,
float_abi,
function_sections,
data_sections,
unique_section_names,
trap_unreachable,
singlethread,
verbose_asm,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
split_dwarf_file.as_ptr(),
output_obj_file.as_ptr(),
debug_info_compression.as_ptr(),
use_emulated_tls,
args_cstr_buff.as_ptr(),
args_cstr_buff.len(),
use_wasm_eh,
)
};
NonNull::new(tm_ptr)
.map(|tm_unique| Self { tm_unique, phantom: PhantomData })
.ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
}
/// Returns inner `llvm::TargetMachine` type.
///
/// This could be a `Deref` implementation, but `llvm::TargetMachine` is an extern type and
/// `Deref::Target: ?Sized`.
pub fn raw(&self) -> &llvm::TargetMachine {
// SAFETY: constructing ensures we have a valid pointer created by
// llvm::LLVMRustCreateTargetMachine.
unsafe { self.tm_unique.as_ref() }
}
}
impl Drop for OwnedTargetMachine {
fn drop(&mut self) {
// SAFETY: constructing ensures we have a valid pointer created by
// llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no
// double free or use after free.
unsafe {
llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr());
}
}
}