mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 20:58:28 +00:00
Move header file generation logic
WIP, still need to get the length of the metadat object, but otherwise everything should be working.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2229,6 +2229,7 @@ dependencies = [
|
||||
"wasmer-engine-native",
|
||||
"wasmer-engine-object-file",
|
||||
"wasmer-types",
|
||||
"wasmer-vm",
|
||||
"wasmer-wasi",
|
||||
"wasmer-wasi-experimental-io-devices",
|
||||
"wasmer-wast",
|
||||
|
||||
@@ -35,6 +35,7 @@ wasmer-engine-object-file = { version = "1.0.0-alpha01.0", path = "../engine-obj
|
||||
wasmer-wasi = { version = "1.0.0-alpha01.0", path = "../wasi", optional = true }
|
||||
wasmer-wasi-experimental-io-devices = { version = "1.0.0-alpha01.0", path = "../wasi-experimental-io-devices", optional = true }
|
||||
wasmer-wast = { version = "1.0.0-alpha01.0", path = "../../tests/lib/wast", optional = true }
|
||||
wasmer-vm = { version = "1.0.0-alpha01.0", path = "../vm" }
|
||||
wasmer-cache = { version = "1.0.0-alpha01.0", path = "../cache", optional = true }
|
||||
wasmer-types = { version = "1.0.0-alpha01.0", path = "../wasmer-types" }
|
||||
atty = "0.2"
|
||||
|
||||
@@ -106,10 +106,11 @@ impl Compile {
|
||||
|
||||
#[cfg(feature = "object-file")]
|
||||
if engine_type == EngineType::ObjectFile {
|
||||
use wasmer_engine_object_file::ObjectFileArtifact;
|
||||
let symbol_registry = module.artifact().symbol_registry();
|
||||
let module_info = module.info();
|
||||
let header_file_src =
|
||||
crate::header_file_generation::generate_header_file(module_info, symbol_registry);
|
||||
|
||||
if let Some(obj_file) = module.artifact().downcast_ref::<ObjectFileArtifact>() {
|
||||
let header_file_src = obj_file.generate_header_file();
|
||||
let header_path = self.header_path.as_ref().cloned().unwrap_or_else(|| {
|
||||
let mut hp = PathBuf::from(
|
||||
self.path
|
||||
@@ -133,10 +134,6 @@ impl Compile {
|
||||
"✔ Header file generated successfully at `{}`.",
|
||||
header_path.display(),
|
||||
);
|
||||
} else {
|
||||
// TODO: handle error
|
||||
panic!("Downcast failed!")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
456
lib/cli/src/header_file_generation/mod.rs
Normal file
456
lib/cli/src/header_file_generation/mod.rs
Normal file
@@ -0,0 +1,456 @@
|
||||
//! A convenient little abstraction for building up C expressions and generating
|
||||
//! simple C code.
|
||||
|
||||
/// A Type in the C language.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CType {
|
||||
/// C `void` type.
|
||||
Void,
|
||||
/// A pointer to some other type.
|
||||
PointerTo {
|
||||
/// Whether the pointer is `const`.
|
||||
is_const: bool,
|
||||
/// The type that the pointer points to.
|
||||
inner: Box<CType>,
|
||||
},
|
||||
/// C 8 bit unsigned integer type.
|
||||
U8,
|
||||
/// C 16 bit unsigned integer type.
|
||||
U16,
|
||||
/// C 32 bit unsigned integer type.
|
||||
U32,
|
||||
/// C 64 bit unsigned integer type.
|
||||
U64,
|
||||
/// C pointer sized unsigned integer type.
|
||||
USize,
|
||||
/// C 8 bit signed integer type.
|
||||
I8,
|
||||
/// C 16 bit signed integer type.
|
||||
I16,
|
||||
/// C 32 bit signed integer type.
|
||||
I32,
|
||||
/// C 64 bit signed integer type.
|
||||
I64,
|
||||
/// C pointer sized signed integer type.
|
||||
ISize,
|
||||
/// A function or function pointer.
|
||||
Function {
|
||||
/// The arguments the function takes.
|
||||
arguments: Vec<CType>,
|
||||
/// The return value if it has one
|
||||
///
|
||||
/// None is equivalent to Some(Box(Ctype::Void)).
|
||||
return_value: Option<Box<CType>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl CType {
|
||||
/// Convenience function to get a mutable void pointer type.
|
||||
pub fn void_ptr() -> Self {
|
||||
CType::PointerTo {
|
||||
is_const: false,
|
||||
inner: Box::new(CType::Void),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function to get a const void pointer type.
|
||||
#[allow(dead_code)]
|
||||
pub fn const_void_ptr() -> Self {
|
||||
CType::PointerTo {
|
||||
is_const: false,
|
||||
inner: Box::new(CType::Void),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the C source code for a type into the given `String`.
|
||||
fn generate_c(&self, w: &mut String) {
|
||||
match &self {
|
||||
Self::Void => {
|
||||
w.push_str("void");
|
||||
}
|
||||
Self::PointerTo { is_const, inner } => {
|
||||
if *is_const {
|
||||
w.push_str("const ");
|
||||
}
|
||||
inner.generate_c(w);
|
||||
w.push_str("*");
|
||||
}
|
||||
Self::U8 => {
|
||||
w.push_str("unsigned char");
|
||||
}
|
||||
Self::U16 => {
|
||||
w.push_str("unsigned short");
|
||||
}
|
||||
Self::U32 => {
|
||||
w.push_str("unsigned int");
|
||||
}
|
||||
Self::U64 => {
|
||||
w.push_str("unsigned long long");
|
||||
}
|
||||
Self::USize => {
|
||||
w.push_str("unsigned size_t");
|
||||
}
|
||||
Self::I8 => {
|
||||
w.push_str("char");
|
||||
}
|
||||
Self::I16 => {
|
||||
w.push_str("short");
|
||||
}
|
||||
Self::I32 => {
|
||||
w.push_str("int");
|
||||
}
|
||||
Self::I64 => {
|
||||
w.push_str("long long");
|
||||
}
|
||||
Self::ISize => {
|
||||
w.push_str("size_t");
|
||||
}
|
||||
Self::Function {
|
||||
arguments,
|
||||
return_value,
|
||||
} => {
|
||||
// function with no, name, assume it's a function pointer
|
||||
let ret: CType = return_value
|
||||
.as_ref()
|
||||
.map(|i: &Box<CType>| (&**i).clone())
|
||||
.unwrap_or_default();
|
||||
ret.generate_c(w);
|
||||
w.push(' ');
|
||||
w.push_str("(*)");
|
||||
w.push('(');
|
||||
if arguments.len() > 1 {
|
||||
for arg in &arguments[..arguments.len() - 1] {
|
||||
arg.generate_c(w);
|
||||
w.push_str(", ");
|
||||
}
|
||||
arguments.last().unwrap().generate_c(w);
|
||||
} else if arguments.len() == 1 {
|
||||
arguments[0].generate_c(w);
|
||||
}
|
||||
w.push(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the C source code for a type with a nameinto the given `String`.
|
||||
fn generate_c_with_name(&self, name: &String, w: &mut String) {
|
||||
match &self {
|
||||
Self::PointerTo { .. }
|
||||
| Self::Void
|
||||
| Self::U8
|
||||
| Self::U16
|
||||
| Self::U32
|
||||
| Self::U64
|
||||
| Self::USize
|
||||
| Self::I8
|
||||
| Self::I16
|
||||
| Self::I32
|
||||
| Self::I64
|
||||
| Self::ISize => {
|
||||
self.generate_c(w);
|
||||
w.push(' ');
|
||||
w.push_str(name);
|
||||
}
|
||||
Self::Function {
|
||||
arguments,
|
||||
return_value,
|
||||
} => {
|
||||
let ret: CType = return_value
|
||||
.as_ref()
|
||||
.map(|i: &Box<CType>| (&**i).clone())
|
||||
.unwrap_or_default();
|
||||
ret.generate_c(w);
|
||||
w.push(' ');
|
||||
w.push_str(&name);
|
||||
w.push('(');
|
||||
if arguments.len() > 1 {
|
||||
for arg in &arguments[..arguments.len() - 1] {
|
||||
arg.generate_c(w);
|
||||
w.push_str(", ");
|
||||
}
|
||||
arguments.last().unwrap().generate_c(w);
|
||||
} else if arguments.len() == 1 {
|
||||
arguments[0].generate_c(w);
|
||||
}
|
||||
w.push(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CType {
|
||||
fn default() -> CType {
|
||||
CType::Void
|
||||
}
|
||||
}
|
||||
|
||||
/// A statement in the C programming language. This may not be exact to what an
|
||||
/// AST would look like or what the C standard says about the C language, it's
|
||||
/// simply a structed way to organize data for generating C code.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CStatement {
|
||||
/// A declaration of some kind.
|
||||
Declaration {
|
||||
/// The name of the thing being declared.
|
||||
name: String,
|
||||
/// Whether the thing being declared is an array.
|
||||
// TODO: probably make this part of CType
|
||||
array: bool,
|
||||
/// Whether the thing being declared is `extern`.
|
||||
is_extern: bool,
|
||||
/// Whether the thing being declared is `const`.
|
||||
is_const: bool,
|
||||
/// The type of the thing being declared.
|
||||
ctype: CType,
|
||||
/// The definition of the thing being declared.
|
||||
///
|
||||
/// This is useful for initializing constant arrays, for example.
|
||||
definition: Option<Box<CStatement>>,
|
||||
},
|
||||
/// A literal array of CStatements.
|
||||
LiteralArray {
|
||||
/// The contents of the array.
|
||||
items: Vec<CStatement>,
|
||||
},
|
||||
|
||||
/// A literal constant value, passed through directly as a string.
|
||||
LiteralConstant {
|
||||
/// The raw value acting as a constant.
|
||||
value: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl CStatement {
|
||||
/// Generate C source code for the given CStatement.
|
||||
fn generate_c(&self, w: &mut String) {
|
||||
match &self {
|
||||
Self::Declaration {
|
||||
name,
|
||||
array,
|
||||
is_extern,
|
||||
is_const,
|
||||
ctype,
|
||||
definition,
|
||||
} => {
|
||||
if *is_const {
|
||||
w.push_str("const ");
|
||||
}
|
||||
if *is_extern {
|
||||
w.push_str("extern ");
|
||||
}
|
||||
ctype.generate_c_with_name(name, w);
|
||||
// TODO: array should be part of the type
|
||||
if *array {
|
||||
w.push_str("[]");
|
||||
}
|
||||
if let Some(def) = definition {
|
||||
w.push_str(" = ");
|
||||
def.generate_c(w);
|
||||
}
|
||||
w.push(';');
|
||||
w.push('\n');
|
||||
}
|
||||
Self::LiteralArray { items } => {
|
||||
w.push('{');
|
||||
if !items.is_empty() {
|
||||
w.push('\n');
|
||||
}
|
||||
for item in items {
|
||||
w.push('\t');
|
||||
item.generate_c(w);
|
||||
w.push(',');
|
||||
w.push('\n');
|
||||
}
|
||||
w.push('}');
|
||||
}
|
||||
Self::LiteralConstant { value } => {
|
||||
w.push_str(&value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate C source code from some `CStatements` into a String.
|
||||
// TODO: add config section
|
||||
pub fn generate_c(statements: &[CStatement]) -> String {
|
||||
let mut out = String::new();
|
||||
for statement in statements {
|
||||
statement.generate_c(&mut out);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
// TODO: split the bottom part into its own file
|
||||
|
||||
use wasmer_compiler::{Symbol, SymbolRegistry};
|
||||
use wasmer_vm::ModuleInfo;
|
||||
|
||||
/// Generate the header file that goes with the generated object file.
|
||||
pub fn generate_header_file(
|
||||
module_info: &ModuleInfo,
|
||||
symbol_registry: &dyn SymbolRegistry,
|
||||
) -> String {
|
||||
let mut c_statements = vec![];
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "module_bytes_len".to_string(),
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::U32,
|
||||
definition: Some(Box::new(CStatement::LiteralConstant {
|
||||
value: "0".to_string(), //todo!("get the metadata length from somewhere"), //format!("{}", self.metadata_length),
|
||||
})),
|
||||
});
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "WASMER_METADATA".to_string(),
|
||||
array: true,
|
||||
is_extern: true,
|
||||
is_const: true,
|
||||
ctype: CType::U8,
|
||||
definition: None,
|
||||
});
|
||||
for (function_local_index, _sig_index) in
|
||||
module_info
|
||||
.functions
|
||||
.iter()
|
||||
.filter_map(|(f_index, sig_index)| {
|
||||
Some((module_info.local_func_index(f_index)?, sig_index))
|
||||
})
|
||||
{
|
||||
let function_name =
|
||||
symbol_registry.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
||||
// TODO: figure out the signature here too
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: function_name.clone(),
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: false,
|
||||
ctype: CType::Function {
|
||||
arguments: vec![CType::Void],
|
||||
return_value: None,
|
||||
},
|
||||
definition: None,
|
||||
});
|
||||
}
|
||||
|
||||
// function pointer array
|
||||
{
|
||||
let mut function_pointer_array_statements = vec![];
|
||||
for (function_local_index, _sig_index) in
|
||||
module_info
|
||||
.functions
|
||||
.iter()
|
||||
.filter_map(|(f_index, sig_index)| {
|
||||
Some((module_info.local_func_index(f_index)?, sig_index))
|
||||
})
|
||||
{
|
||||
let function_name =
|
||||
symbol_registry.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
||||
// TODO: figure out the signature here too
|
||||
|
||||
function_pointer_array_statements.push(CStatement::LiteralConstant {
|
||||
value: function_name.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "function_pointers".to_string(),
|
||||
array: true,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::void_ptr(),
|
||||
definition: Some(Box::new(CStatement::LiteralArray {
|
||||
items: function_pointer_array_statements,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
for (sig_index, _func_type) in module_info.signatures.iter() {
|
||||
let function_name =
|
||||
symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index));
|
||||
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: function_name.clone(),
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: false,
|
||||
ctype: CType::Function {
|
||||
arguments: vec![CType::void_ptr(), CType::void_ptr(), CType::void_ptr()],
|
||||
return_value: None,
|
||||
},
|
||||
definition: None,
|
||||
});
|
||||
}
|
||||
|
||||
// function trampolines
|
||||
{
|
||||
let mut function_trampoline_statements = vec![];
|
||||
for (sig_index, _vm_shared_index) in module_info.signatures.iter() {
|
||||
let function_name =
|
||||
symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index));
|
||||
function_trampoline_statements.push(CStatement::LiteralConstant {
|
||||
value: function_name,
|
||||
});
|
||||
}
|
||||
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "function_trampolines".to_string(),
|
||||
array: true,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::void_ptr(),
|
||||
definition: Some(Box::new(CStatement::LiteralArray {
|
||||
items: function_trampoline_statements,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
for func_index in module_info
|
||||
.functions
|
||||
.keys()
|
||||
.take(module_info.num_imported_functions)
|
||||
{
|
||||
let function_name =
|
||||
symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
|
||||
// TODO: figure out the signature here
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: function_name,
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: false,
|
||||
ctype: CType::Function {
|
||||
arguments: vec![CType::void_ptr(), CType::void_ptr(), CType::void_ptr()],
|
||||
return_value: None,
|
||||
},
|
||||
definition: None,
|
||||
});
|
||||
}
|
||||
|
||||
// dynamic function trampoline pointer array
|
||||
{
|
||||
let mut dynamic_function_trampoline_statements = vec![];
|
||||
for func_index in module_info
|
||||
.functions
|
||||
.keys()
|
||||
.take(module_info.num_imported_functions)
|
||||
{
|
||||
let function_name =
|
||||
symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
|
||||
dynamic_function_trampoline_statements.push(CStatement::LiteralConstant {
|
||||
value: function_name,
|
||||
});
|
||||
}
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "dynamic_function_trampoline_pointers".to_string(),
|
||||
array: true,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::void_ptr(),
|
||||
definition: Some(Box::new(CStatement::LiteralArray {
|
||||
items: dynamic_function_trampoline_statements,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
generate_c(&c_statements)
|
||||
}
|
||||
@@ -20,6 +20,7 @@ pub mod commands;
|
||||
pub mod common;
|
||||
#[macro_use]
|
||||
pub mod error;
|
||||
pub mod header_file_generation;
|
||||
#[cfg(feature = "debug")]
|
||||
pub mod logging;
|
||||
pub mod store;
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::serialize::SerializableCompilation;
|
||||
use crate::serialize::SerializableModule;
|
||||
use crate::unwind::UnwindRegistry;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use wasmer_compiler::{CompileError, Features, Triple};
|
||||
use wasmer_compiler::{CompileError, Features, SymbolRegistry, Triple};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment};
|
||||
use wasmer_engine::{
|
||||
@@ -303,4 +303,8 @@ impl Artifact for JITArtifact {
|
||||
serialized.extend(bytes);
|
||||
Ok(serialized)
|
||||
}
|
||||
|
||||
fn symbol_registry(&self) -> &dyn SymbolRegistry {
|
||||
unimplemented!("TODO: figure out why engine JIT doesn't have a SymbolRegistry")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,4 +598,8 @@ impl Artifact for NativeArtifact {
|
||||
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
Ok(std::fs::read(&self.sharedobject_path)?)
|
||||
}
|
||||
|
||||
fn symbol_registry(&self) -> &dyn SymbolRegistry {
|
||||
&self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,174 +237,6 @@ impl ObjectFileArtifact {
|
||||
Self::from_parts_crosscompiled(&mut *engine_inner, metadata, obj_bytes, metadata_length)
|
||||
}
|
||||
|
||||
/// Generate the header file that goes with the generated object file.
|
||||
pub fn generate_header_file(&self) -> String {
|
||||
use crate::header::*;
|
||||
let mut c_statements = vec![];
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "module_bytes_len".to_string(),
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::U32,
|
||||
definition: Some(Box::new(CStatement::LiteralConstant {
|
||||
value: format!("{}", self.metadata_length),
|
||||
})),
|
||||
});
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "WASMER_METADATA".to_string(),
|
||||
array: true,
|
||||
is_extern: true,
|
||||
is_const: true,
|
||||
ctype: CType::U8,
|
||||
definition: None,
|
||||
});
|
||||
for (function_local_index, _function_len) in self.metadata.function_body_lengths.iter() {
|
||||
let function_name = self
|
||||
.metadata
|
||||
.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
||||
// TODO: figure out the signature here too
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: function_name.clone(),
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: false,
|
||||
ctype: CType::Function {
|
||||
arguments: vec![CType::Void],
|
||||
return_value: None,
|
||||
},
|
||||
definition: None,
|
||||
});
|
||||
}
|
||||
|
||||
// function pointer array
|
||||
{
|
||||
let mut function_pointer_array_statements = vec![];
|
||||
for (function_local_index, _function_len) in self.metadata.function_body_lengths.iter()
|
||||
{
|
||||
let function_name = self
|
||||
.metadata
|
||||
.symbol_to_name(Symbol::LocalFunction(function_local_index));
|
||||
// TODO: figure out the signature here too
|
||||
|
||||
function_pointer_array_statements.push(CStatement::LiteralConstant {
|
||||
value: function_name.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "function_pointers".to_string(),
|
||||
array: true,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::void_ptr(),
|
||||
definition: Some(Box::new(CStatement::LiteralArray {
|
||||
items: function_pointer_array_statements,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
for (sig_index, _func_type) in self.metadata.compile_info.module.signatures.iter() {
|
||||
let function_name = self
|
||||
.metadata
|
||||
.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index));
|
||||
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: function_name.clone(),
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: false,
|
||||
ctype: CType::Function {
|
||||
arguments: vec![CType::void_ptr(), CType::void_ptr(), CType::void_ptr()],
|
||||
return_value: None,
|
||||
},
|
||||
definition: None,
|
||||
});
|
||||
}
|
||||
|
||||
// function trampolines
|
||||
{
|
||||
let mut function_trampoline_statements = vec![];
|
||||
for (sig_index, _vm_shared_index) in self.metadata.compile_info.module.signatures.iter()
|
||||
{
|
||||
let function_name = self
|
||||
.metadata
|
||||
.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index));
|
||||
function_trampoline_statements.push(CStatement::LiteralConstant {
|
||||
value: function_name,
|
||||
});
|
||||
}
|
||||
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "function_trampolines".to_string(),
|
||||
array: true,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::void_ptr(),
|
||||
definition: Some(Box::new(CStatement::LiteralArray {
|
||||
items: function_trampoline_statements,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
for func_index in self
|
||||
.metadata
|
||||
.compile_info
|
||||
.module
|
||||
.functions
|
||||
.keys()
|
||||
.take(self.metadata.compile_info.module.num_imported_functions)
|
||||
{
|
||||
let function_name = self
|
||||
.metadata
|
||||
.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
|
||||
// TODO: figure out the signature here
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: function_name,
|
||||
array: false,
|
||||
is_extern: false,
|
||||
is_const: false,
|
||||
ctype: CType::Function {
|
||||
arguments: vec![CType::void_ptr(), CType::void_ptr(), CType::void_ptr()],
|
||||
return_value: None,
|
||||
},
|
||||
definition: None,
|
||||
});
|
||||
}
|
||||
|
||||
// dynamic function trampoline pointer array
|
||||
{
|
||||
let mut dynamic_function_trampoline_statements = vec![];
|
||||
for func_index in self
|
||||
.metadata
|
||||
.compile_info
|
||||
.module
|
||||
.functions
|
||||
.keys()
|
||||
.take(self.metadata.compile_info.module.num_imported_functions)
|
||||
{
|
||||
let function_name = self
|
||||
.metadata
|
||||
.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
|
||||
dynamic_function_trampoline_statements.push(CStatement::LiteralConstant {
|
||||
value: function_name,
|
||||
});
|
||||
}
|
||||
c_statements.push(CStatement::Declaration {
|
||||
name: "dynamic_function_trampoline_pointers".to_string(),
|
||||
array: true,
|
||||
is_extern: false,
|
||||
is_const: true,
|
||||
ctype: CType::void_ptr(),
|
||||
definition: Some(Box::new(CStatement::LiteralArray {
|
||||
items: dynamic_function_trampoline_statements,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
generate_c(&c_statements)
|
||||
}
|
||||
|
||||
/// Get the default extension when serializing this artifact
|
||||
pub fn get_default_extension(triple: &Triple) -> &'static str {
|
||||
match triple.operating_system {
|
||||
@@ -640,4 +472,8 @@ impl Artifact for ObjectFileArtifact {
|
||||
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
Ok(self.module_bytes.clone())
|
||||
}
|
||||
|
||||
fn symbol_registry(&self) -> &dyn SymbolRegistry {
|
||||
&self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CType {
|
||||
Void,
|
||||
PointerTo {
|
||||
is_const: bool,
|
||||
inner: Box<CType>,
|
||||
},
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
USize,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
ISize,
|
||||
Function {
|
||||
arguments: Vec<CType>,
|
||||
return_value: Option<Box<CType>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl CType {
|
||||
pub fn void_ptr() -> Self {
|
||||
CType::PointerTo {
|
||||
is_const: false,
|
||||
inner: Box::new(CType::Void),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn const_void_ptr() -> Self {
|
||||
CType::PointerTo {
|
||||
is_const: false,
|
||||
inner: Box::new(CType::Void),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_c(&self, w: &mut String) {
|
||||
match &self {
|
||||
Self::Void => {
|
||||
w.push_str("void");
|
||||
}
|
||||
Self::PointerTo { is_const, inner } => {
|
||||
if *is_const {
|
||||
w.push_str("const ");
|
||||
}
|
||||
inner.generate_c(w);
|
||||
w.push_str("*");
|
||||
}
|
||||
Self::U8 => {
|
||||
w.push_str("unsigned char");
|
||||
}
|
||||
Self::U16 => {
|
||||
w.push_str("unsigned short");
|
||||
}
|
||||
Self::U32 => {
|
||||
w.push_str("unsigned int");
|
||||
}
|
||||
Self::U64 => {
|
||||
w.push_str("unsigned long long");
|
||||
}
|
||||
Self::USize => {
|
||||
w.push_str("unsigned size_t");
|
||||
}
|
||||
Self::I8 => {
|
||||
w.push_str("char");
|
||||
}
|
||||
Self::I16 => {
|
||||
w.push_str("short");
|
||||
}
|
||||
Self::I32 => {
|
||||
w.push_str("int");
|
||||
}
|
||||
Self::I64 => {
|
||||
w.push_str("long long");
|
||||
}
|
||||
Self::ISize => {
|
||||
w.push_str("size_t");
|
||||
}
|
||||
Self::Function {
|
||||
arguments,
|
||||
return_value,
|
||||
} => {
|
||||
// function with no, name, assume it's a function pointer
|
||||
let ret: CType = return_value
|
||||
.as_ref()
|
||||
.map(|i: &Box<CType>| (&**i).clone())
|
||||
.unwrap_or_default();
|
||||
ret.generate_c(w);
|
||||
w.push(' ');
|
||||
w.push_str("(*)");
|
||||
w.push('(');
|
||||
if arguments.len() > 1 {
|
||||
for arg in &arguments[..arguments.len() - 1] {
|
||||
arg.generate_c(w);
|
||||
w.push_str(", ");
|
||||
}
|
||||
arguments.last().unwrap().generate_c(w);
|
||||
} else if arguments.len() == 1 {
|
||||
arguments[0].generate_c(w);
|
||||
}
|
||||
w.push(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_c_with_name(&self, name: &String, w: &mut String) {
|
||||
match &self {
|
||||
Self::PointerTo { .. }
|
||||
| Self::Void
|
||||
| Self::U8
|
||||
| Self::U16
|
||||
| Self::U32
|
||||
| Self::U64
|
||||
| Self::USize
|
||||
| Self::I8
|
||||
| Self::I16
|
||||
| Self::I32
|
||||
| Self::I64
|
||||
| Self::ISize => {
|
||||
self.generate_c(w);
|
||||
w.push(' ');
|
||||
w.push_str(name);
|
||||
}
|
||||
Self::Function {
|
||||
arguments,
|
||||
return_value,
|
||||
} => {
|
||||
let ret: CType = return_value
|
||||
.as_ref()
|
||||
.map(|i: &Box<CType>| (&**i).clone())
|
||||
.unwrap_or_default();
|
||||
ret.generate_c(w);
|
||||
w.push(' ');
|
||||
w.push_str(&name);
|
||||
w.push('(');
|
||||
if arguments.len() > 1 {
|
||||
for arg in &arguments[..arguments.len() - 1] {
|
||||
arg.generate_c(w);
|
||||
w.push_str(", ");
|
||||
}
|
||||
arguments.last().unwrap().generate_c(w);
|
||||
} else if arguments.len() == 1 {
|
||||
arguments[0].generate_c(w);
|
||||
}
|
||||
w.push(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CType {
|
||||
fn default() -> CType {
|
||||
CType::Void
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CStatement {
|
||||
Declaration {
|
||||
name: String,
|
||||
array: bool,
|
||||
is_extern: bool,
|
||||
is_const: bool,
|
||||
ctype: CType,
|
||||
definition: Option<Box<CStatement>>,
|
||||
},
|
||||
LiteralArray {
|
||||
items: Vec<CStatement>,
|
||||
},
|
||||
LiteralConstant {
|
||||
value: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl CStatement {
|
||||
fn generate_c(&self, w: &mut String) {
|
||||
match &self {
|
||||
Self::Declaration {
|
||||
name,
|
||||
array,
|
||||
is_extern,
|
||||
is_const,
|
||||
ctype,
|
||||
definition,
|
||||
} => {
|
||||
if *is_const {
|
||||
w.push_str("const ");
|
||||
}
|
||||
if *is_extern {
|
||||
w.push_str("extern ");
|
||||
}
|
||||
ctype.generate_c_with_name(name, w);
|
||||
// TODO: array should be part of the type
|
||||
if *array {
|
||||
w.push_str("[]");
|
||||
}
|
||||
if let Some(def) = definition {
|
||||
w.push_str(" = ");
|
||||
def.generate_c(w);
|
||||
}
|
||||
w.push(';');
|
||||
w.push('\n');
|
||||
}
|
||||
Self::LiteralArray { items } => {
|
||||
w.push('{');
|
||||
if !items.is_empty() {
|
||||
w.push('\n');
|
||||
}
|
||||
for item in items {
|
||||
w.push('\t');
|
||||
item.generate_c(w);
|
||||
w.push(',');
|
||||
w.push('\n');
|
||||
}
|
||||
w.push('}');
|
||||
}
|
||||
Self::LiteralConstant { value } => {
|
||||
w.push_str(&value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add config section
|
||||
pub fn generate_c(statements: &[CStatement]) -> String {
|
||||
let mut out = String::new();
|
||||
for statement in statements {
|
||||
statement.generate_c(&mut out);
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
mod artifact;
|
||||
mod builder;
|
||||
mod engine;
|
||||
pub(crate) mod header;
|
||||
mod serialize;
|
||||
|
||||
pub use crate::artifact::ObjectFileArtifact;
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::any::Any;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::Features;
|
||||
use wasmer_compiler::{Features, SymbolRegistry};
|
||||
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
|
||||
use wasmer_types::{
|
||||
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer,
|
||||
@@ -21,7 +21,7 @@ use wasmer_vm::{
|
||||
/// The `Artifact` contains the compiled data for a given
|
||||
/// module as well as extra information needed to run the
|
||||
/// module at runtime, such as [`ModuleInfo`] and [`Features`].
|
||||
pub trait Artifact: Send + Sync + 'static + Upcastable {
|
||||
pub trait Artifact: Send + Sync {
|
||||
/// Return a reference-counted pointer to the module
|
||||
fn module(&self) -> Arc<ModuleInfo>;
|
||||
|
||||
@@ -148,41 +148,7 @@ pub trait Artifact: Send + Sync + 'static + Upcastable {
|
||||
.finish_instantiation(is_bulk_memory, &data_initializers)
|
||||
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of `Upcastable` taken from https://users.rust-lang.org/t/why-does-downcasting-not-work-for-subtraits/33286/7 .
|
||||
/// Trait needed to get downcasting from `Artifact` to work.
|
||||
pub trait Upcastable {
|
||||
fn upcast_any_ref(self: &'_ Self) -> &'_ dyn Any;
|
||||
fn upcast_any_mut(self: &'_ mut Self) -> &'_ mut dyn Any;
|
||||
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any>;
|
||||
}
|
||||
|
||||
impl<T: Any + 'static> Upcastable for T {
|
||||
#[inline]
|
||||
fn upcast_any_ref(self: &'_ Self) -> &'_ dyn Any {
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
fn upcast_any_mut(self: &'_ mut Self) -> &'_ mut dyn Any {
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl dyn Artifact + 'static {
|
||||
/// Downcast a reference to an `Artifact` into a specific implementor.
|
||||
#[inline]
|
||||
pub fn downcast_ref<T: 'static>(self: &'_ Self) -> Option<&'_ T> {
|
||||
self.upcast_any_ref().downcast_ref::<T>()
|
||||
}
|
||||
|
||||
/// Downcast a mutable reference to an `Artifact` into a specific implementor.
|
||||
#[inline]
|
||||
pub fn downcast_mut<T: 'static>(self: &'_ mut Self) -> Option<&'_ mut T> {
|
||||
self.upcast_any_mut().downcast_mut::<T>()
|
||||
}
|
||||
/// Get the `SymbolRegistry` used to generate the names used in the Artifact.
|
||||
fn symbol_registry(&self) -> &dyn SymbolRegistry;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user