1 use cranelift_codegen::ir::*;
2 use cranelift_codegen::isa::{CallConv, OwnedTargetIsa};
3 use cranelift_codegen::settings::{self, Configurable};
4 use cranelift_codegen::{Context, ir::types::I16};
5 use cranelift_entity::EntityRef;
6 use cranelift_frontend::*;
7 use cranelift_jit::*;
8 use cranelift_module::*;
9 
isa() -> Option<OwnedTargetIsa>10 fn isa() -> Option<OwnedTargetIsa> {
11     let mut flag_builder = settings::builder();
12     flag_builder.set("use_colocated_libcalls", "false").unwrap();
13     // FIXME set back to true once the x64 backend supports it.
14     flag_builder.set("is_pic", "false").unwrap();
15     let isa_builder = cranelift_native::builder().ok()?;
16     isa_builder.finish(settings::Flags::new(flag_builder)).ok()
17 }
18 
19 #[test]
error_on_incompatible_sig_in_declare_function()20 fn error_on_incompatible_sig_in_declare_function() {
21     let Some(isa) = isa() else {
22         return;
23     };
24     let mut module = JITModule::new(JITBuilder::with_isa(isa, default_libcall_names()));
25 
26     let mut sig = Signature {
27         params: vec![AbiParam::new(types::I64)],
28         returns: vec![],
29         call_conv: CallConv::SystemV,
30     };
31     module
32         .declare_function("abc", Linkage::Local, &sig)
33         .unwrap();
34     sig.params[0] = AbiParam::new(types::I32);
35     module
36         .declare_function("abc", Linkage::Local, &sig)
37         .err()
38         .unwrap(); // Make sure this is an error
39 }
40 
define_simple_function(module: &mut JITModule) -> Result<FuncId, ModuleError>41 fn define_simple_function(module: &mut JITModule) -> Result<FuncId, ModuleError> {
42     let sig = Signature {
43         params: vec![],
44         returns: vec![],
45         call_conv: CallConv::SystemV,
46     };
47 
48     let func_id = module.declare_function("abc", Linkage::Local, &sig)?;
49 
50     let mut ctx = Context::new();
51     ctx.func = Function::with_name_signature(UserFuncName::user(0, func_id.as_u32()), sig);
52     let mut func_ctx = FunctionBuilderContext::new();
53     {
54         let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
55         let block = bcx.create_block();
56         bcx.switch_to_block(block);
57         bcx.ins().return_(&[]);
58     }
59 
60     module.define_function(func_id, &mut ctx)?;
61 
62     Ok(func_id)
63 }
64 
65 #[test]
panic_on_define_after_finalize()66 fn panic_on_define_after_finalize() {
67     let Some(isa) = isa() else {
68         return;
69     };
70     let mut module = JITModule::new(JITBuilder::with_isa(isa, default_libcall_names()));
71 
72     define_simple_function(&mut module).unwrap();
73     define_simple_function(&mut module).err().unwrap();
74 }
75 
76 #[test]
switch_error()77 fn switch_error() {
78     use cranelift_codegen::settings;
79 
80     let sig = Signature {
81         params: vec![AbiParam::new(types::I32)],
82         returns: vec![AbiParam::new(types::I32)],
83         call_conv: CallConv::SystemV,
84     };
85 
86     let mut func = Function::with_name_signature(UserFuncName::default(), sig);
87 
88     let mut func_ctx = FunctionBuilderContext::new();
89     {
90         let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut func, &mut func_ctx);
91         let start = bcx.create_block();
92         let bb0 = bcx.create_block();
93         let bb1 = bcx.create_block();
94         let bb2 = bcx.create_block();
95         let bb3 = bcx.create_block();
96         println!("{start} {bb0} {bb1} {bb2} {bb3}");
97 
98         bcx.declare_var(types::I32);
99         bcx.declare_var(types::I32);
100         let in_val = bcx.append_block_param(start, types::I32);
101         bcx.switch_to_block(start);
102         bcx.def_var(Variable::new(0), in_val);
103         bcx.ins().jump(bb0, &[]);
104 
105         bcx.switch_to_block(bb0);
106         let discr = bcx.use_var(Variable::new(0));
107         let mut switch = cranelift_frontend::Switch::new();
108         for &(index, bb) in &[
109             (9, bb1),
110             (13, bb1),
111             (10, bb1),
112             (92, bb1),
113             (39, bb1),
114             (34, bb1),
115         ] {
116             switch.set_entry(index, bb);
117         }
118         switch.emit(&mut bcx, discr, bb2);
119 
120         bcx.switch_to_block(bb1);
121         let v = bcx.use_var(Variable::new(0));
122         bcx.def_var(Variable::new(1), v);
123         bcx.ins().jump(bb3, &[]);
124 
125         bcx.switch_to_block(bb2);
126         let v = bcx.use_var(Variable::new(0));
127         bcx.def_var(Variable::new(1), v);
128         bcx.ins().jump(bb3, &[]);
129 
130         bcx.switch_to_block(bb3);
131         let r = bcx.use_var(Variable::new(1));
132         bcx.ins().return_(&[r]);
133 
134         bcx.seal_all_blocks();
135         bcx.finalize();
136     }
137 
138     let flags = settings::Flags::new(settings::builder());
139     match cranelift_codegen::verify_function(&func, &flags) {
140         Ok(_) => {}
141         Err(err) => {
142             let pretty_error =
143                 cranelift_codegen::print_errors::pretty_verifier_error(&func, None, err);
144             panic!("pretty_error:\n{pretty_error}");
145         }
146     }
147 }
148 
149 #[test]
libcall_function()150 fn libcall_function() {
151     let Some(isa) = isa() else {
152         return;
153     };
154     let mut module = JITModule::new(JITBuilder::with_isa(isa, default_libcall_names()));
155 
156     let sig = Signature {
157         params: vec![],
158         returns: vec![],
159         call_conv: CallConv::SystemV,
160     };
161 
162     let func_id = module
163         .declare_function("function", Linkage::Local, &sig)
164         .unwrap();
165 
166     let mut ctx = Context::new();
167     ctx.func = Function::with_name_signature(UserFuncName::user(0, func_id.as_u32()), sig);
168 
169     let mut func_ctx = FunctionBuilderContext::new();
170     {
171         let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
172         let block = bcx.create_block();
173         bcx.switch_to_block(block);
174 
175         let int = module.target_config().pointer_type();
176         let zero = bcx.ins().iconst(I16, 0);
177         let size = bcx.ins().iconst(int, 10);
178 
179         let mut signature = module.make_signature();
180         signature.params.push(AbiParam::new(int));
181         signature.returns.push(AbiParam::new(int));
182         let callee = module
183             .declare_function("malloc", Linkage::Import, &signature)
184             .expect("declare malloc function");
185         let local_callee = module.declare_func_in_func(callee, &mut bcx.func);
186         let argument_exprs = vec![size];
187         let call = bcx.ins().call(local_callee, &argument_exprs);
188         let buffer = bcx.inst_results(call)[0];
189 
190         bcx.call_memset(module.target_config(), buffer, zero, size);
191 
192         bcx.ins().return_(&[]);
193     }
194 
195     module
196         .define_function_with_control_plane(func_id, &mut ctx, &mut Default::default())
197         .unwrap();
198 
199     module.finalize_definitions().unwrap();
200 }
201 
202 // This used to cause UB. See https://github.com/bytecodealliance/wasmtime/issues/7918.
203 #[test]
empty_data_object()204 fn empty_data_object() {
205     let Some(isa) = isa() else {
206         return;
207     };
208     let mut module = JITModule::new(JITBuilder::with_isa(isa, default_libcall_names()));
209 
210     let data_id = module
211         .declare_data("empty", Linkage::Export, false, false)
212         .unwrap();
213 
214     let mut data = DataDescription::new();
215     data.define(Box::new([]));
216     module.define_data(data_id, &data).unwrap();
217 }
218