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 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] 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 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] 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] 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] 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] 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