Remove unnecessary CString allocation when loading functions (#379)

CString::new needs to perform an allocation to own the `&'static str`
and append a NULL byte to it. We can instead perform this "allocation"
in the generator and emit a byte-string literal with trailing NULL byte
that can immediately be used by the function loader.
This commit is contained in:
Marijn Suijten 2021-03-01 10:05:13 +01:00 committed by GitHub
parent 9881d98182
commit a053c6aecc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 1558 additions and 1383 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -80,7 +80,7 @@ named!(cfloat<&str, f32>,
terminated!(nom::number::complete::float, char!('f')) terminated!(nom::number::complete::float, char!('f'))
); );
fn khronos_link<S: Display>(name: &S) -> Literal { fn khronos_link<S: Display + ?Sized>(name: &S) -> Literal {
Literal::string(&format!( Literal::string(&format!(
"<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{name}.html>", "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{name}.html>",
name = name name = name
@ -849,17 +849,18 @@ fn generate_function_pointers<'a>(
.map(|cmd| function_name(&cmd.name)) .map(|cmd| function_name(&cmd.name))
.collect(); .collect();
let names_ref = &names; let names_ref = &names;
let names_ref1 = &names;
let names_ref2 = &names;
let names_ref3 = &names;
let raw_names: Vec<_> = commands let raw_names: Vec<_> = commands
.iter() .iter()
.map(|cmd| format_ident!("{}", function_name_raw(cmd.name.as_str()).as_str())) .map(|cmd| {
let byt = std::ffi::CString::new(function_name_raw(cmd.name.as_str())).unwrap();
Literal::byte_string(byt.to_bytes_with_nul())
})
.collect(); .collect();
let raw_names_ref = &raw_names; let raw_names_ref = &raw_names;
let names_left = &names; let khronos_links: Vec<_> = commands
let names_right = &names; .iter()
let khronos_links: Vec<_> = raw_names.iter().map(|name| khronos_link(name)).collect(); .map(|cmd| khronos_link(&function_name_raw(cmd.name.as_str())))
.collect();
let params: Vec<Vec<(Ident, TokenStream)>> = commands let params: Vec<Vec<(Ident, TokenStream)>> = commands
.iter() .iter()
@ -965,7 +966,7 @@ fn generate_function_pointers<'a>(
impl ::std::clone::Clone for #ident { impl ::std::clone::Clone for #ident {
fn clone(&self) -> Self { fn clone(&self) -> Self {
#ident{ #ident{
#(#names_left: self.#names_right,)* #(#names: self.#names,)*
} }
} }
} }
@ -977,14 +978,13 @@ fn generate_function_pointers<'a>(
#( #(
#names_ref: unsafe { #names_ref: unsafe {
extern "system" fn #names_ref1 (#expanded_params_unused) #return_types_ref { extern "system" fn #names_ref (#expanded_params_unused) #return_types_ref {
panic!(concat!("Unable to load ", stringify!(#names_ref2))) panic!(concat!("Unable to load ", stringify!(#names_ref)))
} }
let raw_name = stringify!(#raw_names_ref); let cname = ::std::ffi::CStr::from_bytes_with_nul_unchecked(#raw_names_ref);
let cname = ::std::ffi::CString::new(raw_name).unwrap(); let val = _f(cname);
let val = _f(&cname);
if val.is_null(){ if val.is_null(){
#names_ref3 #names_ref
} }
else{ else{
::std::mem::transmute(val) ::std::mem::transmute(val)
@ -996,7 +996,7 @@ fn generate_function_pointers<'a>(
#( #(
#[doc = #khronos_links] #[doc = #khronos_links]
pub unsafe fn #names_ref(&self, #expanded_params_ref) #return_types_ref { pub unsafe fn #names_ref(&self, #expanded_params_ref) #return_types_ref {
(self.#names_left)(#(#params_names,)*) (self.#names)(#(#params_names,)*)
} }
)* )*
} }