tin_lang/
module.rs

1//! Definitions for compiled modules.
2use std::collections;
3use std::fmt;
4use std::mem;
5use std::ops;
6
7use cranelift_module;
8use cranelift_simplejit;
9
10/// A compiled module, the result of an invocation of `Compiler::compile`.
11pub struct Module {
12    compiled: cranelift_module::Module<cranelift_simplejit::SimpleJITBackend>,
13    function_ids: collections::HashMap<String, cranelift_module::FuncId>,
14}
15
16/// A function that is exported from a [`Module`].
17pub trait Function {
18    /// Creates a new function from a raw pointer to generated machine code.
19    ///
20    /// # Unsafety
21    ///
22    /// This is probably as unsafe as it gets, since the passed-in pointer will be treated as a
23    /// pointer to arbitrary machine code.  The pointer *must* come from a trusted source.
24    unsafe fn from_ptr(ptr: *const u8) -> Self;
25}
26
27macro_rules! define_function {
28    ($name:ident, $doc:expr, $ret:ident) => { define_function!($name, $doc, $ret,); };
29    ($name:ident, $doc:expr, $ret:ident, $($arg:ident),*) => {
30        #[doc=$doc]
31        pub struct $name<$ret, $($arg),*>(extern "C" fn($($arg),*) -> $ret);
32
33        impl<$ret, $($arg),*> ops::Deref for $name<$ret, $($arg),*> {
34            type Target = extern "C" fn($($arg),*) -> $ret;
35
36            fn deref(&self) -> &Self::Target {
37                &self.0
38            }
39        }
40
41        impl<$ret, $($arg),*> Function for $name<$ret, $($arg),*> {
42            unsafe fn from_ptr(ptr: *const u8) -> Self {
43                $name(mem::transmute(ptr))
44            }
45        }
46
47        impl<$ret, $($arg),*> fmt::Debug for $name<$ret, $($arg),*> {
48            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49                f.debug_struct(stringify!($name)).finish()
50            }
51        }
52    };
53}
54
55define_function!(Function0, "A function taking 0 arguments", R);
56define_function!(Function1, "A function taking 1 arguments", R, A1);
57define_function!(Function2, "A function taking 2 arguments", R, A1, A2);
58define_function!(Function3, "A function taking 3 arguments", R, A1, A2, A3);
59define_function!(
60    Function4,
61    "A function taking 4 arguments",
62    R,
63    A1,
64    A2,
65    A3,
66    A4
67);
68define_function!(
69    Function5,
70    "A function taking 5 arguments",
71    R,
72    A1,
73    A2,
74    A3,
75    A4,
76    A5
77);
78define_function!(
79    Function6,
80    "A function taking 6 arguments",
81    R,
82    A1,
83    A2,
84    A3,
85    A4,
86    A5,
87    A6
88);
89
90impl Module {
91    pub(crate) fn new(
92        compiled: cranelift_module::Module<cranelift_simplejit::SimpleJITBackend>,
93        function_ids: collections::HashMap<String, cranelift_module::FuncId>,
94    ) -> Self {
95        Module {
96            compiled,
97            function_ids,
98        }
99    }
100
101    /// Fetches the specified function with the specified signature.
102    ///
103    /// Returns `None` if the signature does not match the compiled function.
104    pub fn function<F>(&mut self, name: &str) -> Option<F>
105    where
106        F: Function,
107    {
108        if let Some(id) = self.function_ids.get(name) {
109            // TODO: type check
110            Some(unsafe { F::from_ptr(self.compiled.get_finalized_function(*id)) })
111        } else {
112            None
113        }
114    }
115}
116
117impl fmt::Debug for Module {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        f.debug_struct("Module").finish()
120    }
121}