diff --git a/lib/cli/src/store.rs b/lib/cli/src/store.rs index 4c66641b481..2c322ac6de1 100644 --- a/lib/cli/src/store.rs +++ b/lib/cli/src/store.rs @@ -212,18 +212,19 @@ impl CompilerOptions { // Converts a kind into a filename, that we will use to dump // the contents of the IR object file to. fn types_to_signature(types: &[Type]) -> String { - types.iter().map(|ty| { - match ty { + types + .iter() + .map(|ty| match ty { Type::I32 => "i".to_string(), Type::I64 => "I".to_string(), Type::F32 => "f".to_string(), Type::F64 => "F".to_string(), Type::V128 => "v".to_string(), - _ => { - unimplemented!("Function type not yet supported for generated signatures in debugging"); - } - } - }).collect::>().join("") + Type::ExternRef => "e".to_string(), + Type::FuncRef => "r".to_string(), + }) + .collect::>() + .join("") } // Converts a kind into a filename, that we will use to dump // the contents of the IR object file to. diff --git a/lib/compiler-cranelift/src/func_environ.rs b/lib/compiler-cranelift/src/func_environ.rs index 56323c2e8ca..503b20c6a0a 100644 --- a/lib/compiler-cranelift/src/func_environ.rs +++ b/lib/compiler-cranelift/src/func_environ.rs @@ -575,7 +575,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { ( sig, local_memory_index.index(), - VMBuiltinFunctionIndex::get_local_memory_copy_index(), + VMBuiltinFunctionIndex::get_memory_copy_index(), ) } else { ( diff --git a/lib/compiler-llvm/src/abi/aarch64_systemv.rs b/lib/compiler-llvm/src/abi/aarch64_systemv.rs index 4f6ac76a8ad..e1512acbcee 100644 --- a/lib/compiler-llvm/src/abi/aarch64_systemv.rs +++ b/lib/compiler-llvm/src/abi/aarch64_systemv.rs @@ -140,8 +140,7 @@ impl Abi for Aarch64SystemV { Type::I32 | Type::F32 => 32, Type::I64 | Type::F64 => 64, Type::V128 => 128, - Type::ExternRef => unimplemented!("externref in the llvm backend"), - Type::FuncRef => unimplemented!("funcref in the llvm backend"), + Type::ExternRef | Type::FuncRef => 64, /* pointer */ }) .collect::>(); match sig_returns_bitwidths.as_slice() { @@ -285,8 +284,10 @@ impl Abi for Aarch64SystemV { assert!(value.get_type() == intrinsics.i128_ty.as_basic_type_enum()); value } - Type::ExternRef => unimplemented!("externref in the llvm backend"), - Type::FuncRef => unimplemented!("funcref in the llvm backend"), + Type::ExternRef | Type::FuncRef => { + assert!(value.get_type() == intrinsics.funcref_ty.as_basic_type_enum()); + value + } } }; @@ -322,8 +323,7 @@ impl Abi for Aarch64SystemV { Type::I32 | Type::F32 => 32, Type::I64 | Type::F64 => 64, Type::V128 => 128, - Type::ExternRef => unimplemented!("externref in the llvm backend"), - Type::FuncRef => unimplemented!("funcref in the llvm backend"), + Type::ExternRef | Type::FuncRef => 64, /* pointer */ }) .collect::>(); diff --git a/lib/compiler-llvm/src/abi/x86_64_systemv.rs b/lib/compiler-llvm/src/abi/x86_64_systemv.rs index 84691d5d2d2..abf48b8ce69 100644 --- a/lib/compiler-llvm/src/abi/x86_64_systemv.rs +++ b/lib/compiler-llvm/src/abi/x86_64_systemv.rs @@ -92,8 +92,7 @@ impl Abi for X86_64SystemV { Type::I32 | Type::F32 => 32, Type::I64 | Type::F64 => 64, Type::V128 => 128, - Type::ExternRef => unimplemented!("externref in the llvm backend"), - Type::FuncRef => unimplemented!("funcref in the llvm backend"), + Type::ExternRef | Type::FuncRef => 64, /* pointer */ }) .collect::>(); @@ -316,26 +315,7 @@ impl Abi for X86_64SystemV { ); builder.build_bitcast(value, intrinsics.f32_ty, "") } - Type::I64 => { - assert!( - value.get_type() == intrinsics.i64_ty.as_basic_type_enum() - || value.get_type() == intrinsics.f64_ty.as_basic_type_enum() - ); - builder.build_bitcast(value, intrinsics.i64_ty, "") - } - Type::F64 => { - assert!( - value.get_type() == intrinsics.i64_ty.as_basic_type_enum() - || value.get_type() == intrinsics.f64_ty.as_basic_type_enum() - ); - builder.build_bitcast(value, intrinsics.f64_ty, "") - } - Type::V128 => { - assert!(value.get_type() == intrinsics.i128_ty.as_basic_type_enum()); - value - } - Type::ExternRef => unimplemented!("externref in the llvm backend"), - Type::FuncRef => unimplemented!("funcref in the llvm backend"), + _ => panic!("should only be called to repack 32-bit values"), } }; @@ -365,8 +345,7 @@ impl Abi for X86_64SystemV { Type::I32 | Type::F32 => 32, Type::I64 | Type::F64 => 64, Type::V128 => 128, - Type::ExternRef => unimplemented!("externref in the llvm backend"), - Type::FuncRef => unimplemented!("funcref in the llvm backend"), + Type::ExternRef | Type::FuncRef => 64, /* pointer */ }) .collect::>(); @@ -475,15 +454,12 @@ impl Abi for X86_64SystemV { .results() .iter() .map(|ty| match ty { - Type::I32 | Type::F32 => Ok(32), - Type::I64 | Type::F64 => Ok(64), - Type::V128 => Ok(128), - ty => Err(CompileError::Codegen(format!( - "is_sret: unimplemented wasmer_types type {:?}", - ty - ))), + Type::I32 | Type::F32 => 32, + Type::I64 | Type::F64 => 64, + Type::V128 => 128, + Type::ExternRef | Type::FuncRef => 64, /* pointer */ }) - .collect::, _>>()?; + .collect::>(); Ok(!matches!( func_sig_returns_bitwidths.as_slice(), diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 1c118203a3a..97e926fb5ed 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -54,15 +54,65 @@ where { // TODO: use perfect hash function? let mut libcalls = HashMap::new(); - libcalls.insert("wasmer_raise_trap".to_string(), LibCall::RaiseTrap); - libcalls.insert("truncf".to_string(), LibCall::TruncF32); - libcalls.insert("trunc".to_string(), LibCall::TruncF64); libcalls.insert("ceilf".to_string(), LibCall::CeilF32); libcalls.insert("ceil".to_string(), LibCall::CeilF64); libcalls.insert("floorf".to_string(), LibCall::FloorF32); libcalls.insert("floor".to_string(), LibCall::FloorF64); libcalls.insert("nearbyintf".to_string(), LibCall::NearestF32); libcalls.insert("nearbyint".to_string(), LibCall::NearestF64); + libcalls.insert("truncf".to_string(), LibCall::TruncF32); + libcalls.insert("trunc".to_string(), LibCall::TruncF64); + libcalls.insert("wasmer_f32_ceil".to_string(), LibCall::CeilF32); + libcalls.insert("wasmer_f64_ceil".to_string(), LibCall::CeilF64); + libcalls.insert("wasmer_f32_floor".to_string(), LibCall::FloorF32); + libcalls.insert("wasmer_f64_floor".to_string(), LibCall::FloorF64); + libcalls.insert("wasmer_f32_nearest".to_string(), LibCall::NearestF32); + libcalls.insert("wasmer_f64_nearest".to_string(), LibCall::NearestF64); + libcalls.insert("wasmer_f32_trunc".to_string(), LibCall::TruncF32); + libcalls.insert("wasmer_f64_trunc".to_string(), LibCall::TruncF64); + libcalls.insert("wasmer_memory32_size".to_string(), LibCall::Memory32Size); + libcalls.insert( + "wasmer_imported_memory32_size".to_string(), + LibCall::ImportedMemory32Size, + ); + libcalls.insert("wasmer_table_copy".to_string(), LibCall::TableCopy); + libcalls.insert("wasmer_table_init".to_string(), LibCall::TableInit); + libcalls.insert("wasmer_table_fill".to_string(), LibCall::TableFill); + libcalls.insert("wasmer_table_size".to_string(), LibCall::TableSize); + libcalls.insert( + "wasmer_imported_table_size".to_string(), + LibCall::ImportedTableSize, + ); + libcalls.insert("wasmer_table_get".to_string(), LibCall::TableGet); + libcalls.insert( + "wasmer_imported_table_get".to_string(), + LibCall::ImportedTableGet, + ); + libcalls.insert("wasmer_table_set".to_string(), LibCall::TableSet); + libcalls.insert( + "wasmer_imported_table_set".to_string(), + LibCall::ImportedTableSet, + ); + libcalls.insert("wasmer_table_grow".to_string(), LibCall::TableGrow); + libcalls.insert( + "wasmer_imported_table_grow".to_string(), + LibCall::ImportedTableGrow, + ); + libcalls.insert("wasmer_func_ref".to_string(), LibCall::FuncRef); + libcalls.insert("wasmer_elem_drop".to_string(), LibCall::ElemDrop); + libcalls.insert("wasmer_memory32_copy".to_string(), LibCall::Memory32Copy); + libcalls.insert( + "wasmer_imported_memory32_copy".to_string(), + LibCall::ImportedMemory32Copy, + ); + libcalls.insert("wasmer_memory32_fill".to_string(), LibCall::Memory32Fill); + libcalls.insert( + "wasmer_imported_memory32_fill".to_string(), + LibCall::ImportedMemory32Fill, + ); + libcalls.insert("wasmer_memory32_init".to_string(), LibCall::Memory32Init); + libcalls.insert("wasmer_data_drop".to_string(), LibCall::DataDrop); + libcalls.insert("wasmer_raise_trap".to_string(), LibCall::RaiseTrap); libcalls.insert("wasmer_probestack".to_string(), LibCall::Probestack); let elf = goblin::elf::Elf::parse(&contents).map_err(map_goblin_err)?; diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 4f1c1d9f0fe..614bc7a9fcb 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -9344,6 +9344,215 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly); self.state.push1(size.try_as_basic_value().left().unwrap()); } + /*************************** + * Reference types. + * https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md + ***************************/ + Operator::RefNull { ty } => { + let ty = wptype_to_type(ty).map_err(to_compile_error)?; + let ty = type_to_llvm(self.intrinsics, ty)?; + self.state.push1(ty.const_zero()); + } + Operator::RefIsNull => { + let value = self.state.pop1()?.into_pointer_value(); + let is_null = self.builder.build_is_null(value, ""); + let is_null = self + .builder + .build_int_z_extend(is_null, self.intrinsics.i32_ty, ""); + self.state.push1(is_null); + } + Operator::RefFunc { function_index } => { + let index = self + .intrinsics + .i32_ty + .const_int(function_index.into(), false) + .as_basic_value_enum(); + let value = self + .builder + .build_call(self.intrinsics.func_ref, &[self.ctx.basic(), index], "") + .try_as_basic_value() + .left() + .unwrap(); + self.state.push1(value); + } + Operator::TableGet { table } => { + let table_index = self + .intrinsics + .i32_ty + .const_int(table.into(), false) + .as_basic_value_enum(); + let elem = self.state.pop1()?; + let table_get = if let Some(_) = self + .wasm_module + .local_table_index(TableIndex::from_u32(table)) + { + self.intrinsics.table_get + } else { + self.intrinsics.imported_table_get + }; + let value = self + .builder + .build_call(table_get, &[self.ctx.basic(), table_index, elem], "") + .try_as_basic_value() + .left() + .unwrap(); + let value = self.builder.build_bitcast( + value, + type_to_llvm( + self.intrinsics, + self.wasm_module + .tables + .get(TableIndex::from_u32(table)) + .unwrap() + .ty, + )?, + "", + ); + self.state.push1(value); + } + Operator::TableSet { table } => { + let table_index = self + .intrinsics + .i32_ty + .const_int(table.into(), false) + .as_basic_value_enum(); + let (elem, value) = self.state.pop2()?; + let value = self + .builder + .build_bitcast(value, self.intrinsics.anyref_ty, ""); + let table_set = if let Some(_) = self + .wasm_module + .local_table_index(TableIndex::from_u32(table)) + { + self.intrinsics.table_set + } else { + self.intrinsics.imported_table_set + }; + self.builder.build_call( + table_set, + &[self.ctx.basic(), table_index, elem, value], + "", + ); + } + Operator::TableCopy { + dst_table, + src_table, + } => { + let (dst, src, len) = self.state.pop3()?; + let dst_table = self + .intrinsics + .i32_ty + .const_int(dst_table as u64, false) + .as_basic_value_enum(); + let src_table = self + .intrinsics + .i32_ty + .const_int(src_table as u64, false) + .as_basic_value_enum(); + self.builder.build_call( + self.intrinsics.table_copy, + &[self.ctx.basic(), dst_table, src_table, dst, src, len], + "", + ); + } + Operator::TableInit { segment, table } => { + let (dst, src, len) = self.state.pop3()?; + let segment = self + .intrinsics + .i32_ty + .const_int(segment as u64, false) + .as_basic_value_enum(); + let table = self + .intrinsics + .i32_ty + .const_int(table as u64, false) + .as_basic_value_enum(); + self.builder.build_call( + self.intrinsics.table_init, + &[self.ctx.basic(), table, segment, dst, src, len], + "", + ); + } + Operator::ElemDrop { segment } => { + let segment = self + .intrinsics + .i32_ty + .const_int(segment as u64, false) + .as_basic_value_enum(); + self.builder.build_call( + self.intrinsics.elem_drop, + &[self.ctx.basic(), segment], + "", + ); + } + Operator::TableFill { table } => { + let table = self + .intrinsics + .i32_ty + .const_int(table as u64, false) + .as_basic_value_enum(); + let (start, elem, len) = self.state.pop3()?; + let elem = self + .builder + .build_bitcast(elem, self.intrinsics.anyref_ty, ""); + self.builder.build_call( + self.intrinsics.table_fill, + &[self.ctx.basic(), table, start, elem, len], + "", + ); + } + Operator::TableGrow { table } => { + let (elem, delta) = self.state.pop2()?; + let elem = self + .builder + .build_bitcast(elem, self.intrinsics.anyref_ty, ""); + let (table_grow, table_index) = if let Some(local_table_index) = self + .wasm_module + .local_table_index(TableIndex::from_u32(table)) + { + (self.intrinsics.table_grow, local_table_index.as_u32()) + } else { + (self.intrinsics.imported_table_grow, table) + }; + let table_index = self + .intrinsics + .i32_ty + .const_int(table_index as u64, false) + .as_basic_value_enum(); + let size = self + .builder + .build_call( + table_grow, + &[self.ctx.basic(), elem, delta, table_index], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + self.state.push1(size); + } + Operator::TableSize { table } => { + let (table_size, table_index) = if let Some(local_table_index) = self + .wasm_module + .local_table_index(TableIndex::from_u32(table)) + { + (self.intrinsics.table_size, local_table_index.as_u32()) + } else { + (self.intrinsics.imported_table_size, table) + }; + let table_index = self + .intrinsics + .i32_ty + .const_int(table_index as u64, false) + .as_basic_value_enum(); + let size = self + .builder + .build_call(table_size, &[self.ctx.basic(), table_index], "") + .try_as_basic_value() + .left() + .unwrap(); + self.state.push1(size); + } _ => { return Err(CompileError::Codegen(format!( "Operator {:?} unimplemented", diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index ee7fee18661..6d0fd5e49b2 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -39,10 +39,8 @@ pub fn type_to_llvm_ptr<'ctx>( Type::F32 => Ok(intrinsics.f32_ptr_ty), Type::F64 => Ok(intrinsics.f64_ptr_ty), Type::V128 => Ok(intrinsics.i128_ptr_ty), - ty => Err(CompileError::Codegen(format!( - "type_to_llvm: unimplemented wasmer_types type {:?}", - ty - ))), + Type::FuncRef => Ok(intrinsics.funcref_ty.ptr_type(AddressSpace::Generic)), + Type::ExternRef => Ok(intrinsics.externref_ty.ptr_type(AddressSpace::Generic)), } } @@ -56,10 +54,8 @@ pub fn type_to_llvm<'ctx>( Type::F32 => Ok(intrinsics.f32_ty.as_basic_type_enum()), Type::F64 => Ok(intrinsics.f64_ty.as_basic_type_enum()), Type::V128 => Ok(intrinsics.i128_ty.as_basic_type_enum()), - ty => Err(CompileError::Codegen(format!( - "type_to_llvm: unimplemented wasmer_types type {:?}", - ty - ))), + Type::FuncRef => Ok(intrinsics.funcref_ty.as_basic_type_enum()), + Type::ExternRef => Ok(intrinsics.externref_ty.as_basic_type_enum()), } } @@ -145,10 +141,12 @@ pub struct Intrinsics<'ctx> { pub f32_ptr_ty: PointerType<'ctx>, pub f64_ptr_ty: PointerType<'ctx>, - pub funcref_ty: PointerType<'ctx>, - pub anyfunc_ty: StructType<'ctx>, + pub funcref_ty: PointerType<'ctx>, + pub externref_ty: PointerType<'ctx>, + pub anyref_ty: PointerType<'ctx>, + pub i1_zero: IntValue<'ctx>, pub i8_zero: IntValue<'ctx>, pub i32_zero: IntValue<'ctx>, @@ -169,11 +167,25 @@ pub struct Intrinsics<'ctx> { pub trap_unaligned_atomic: BasicValueEnum<'ctx>, pub trap_table_access_oob: BasicValueEnum<'ctx>, - // VM intrinsics. - pub throw_trap: FunctionValue<'ctx>, - pub experimental_stackmap: FunctionValue<'ctx>, + // VM libcalls. + pub table_copy: FunctionValue<'ctx>, + pub table_init: FunctionValue<'ctx>, + pub table_fill: FunctionValue<'ctx>, + pub table_size: FunctionValue<'ctx>, + pub imported_table_size: FunctionValue<'ctx>, + pub table_get: FunctionValue<'ctx>, + pub imported_table_get: FunctionValue<'ctx>, + pub table_set: FunctionValue<'ctx>, + pub imported_table_set: FunctionValue<'ctx>, + pub table_grow: FunctionValue<'ctx>, + pub imported_table_grow: FunctionValue<'ctx>, + pub func_ref: FunctionValue<'ctx>, + pub elem_drop: FunctionValue<'ctx>, + pub throw_trap: FunctionValue<'ctx>, + + // VM builtins. pub vmfunction_import_ptr_ty: PointerType<'ctx>, pub vmfunction_import_body_element: u32, pub vmfunction_import_vmctx_element: u32, @@ -187,6 +199,7 @@ pub struct Intrinsics<'ctx> { pub memory32_size_ptr_ty: PointerType<'ctx>, pub imported_memory32_size_ptr_ty: PointerType<'ctx>, + // Pointer to the VM. pub ctx_ptr_ty: PointerType<'ctx>, } @@ -254,6 +267,8 @@ impl<'ctx> Intrinsics<'ctx> { false, ); let funcref_ty = anyfunc_ty.ptr_type(AddressSpace::Generic); + let externref_ty = funcref_ty; + let anyref_ty = i8_ptr_ty; let ret_i8x16_take_i8x16_i8x16 = i8x16_ty.fn_type(&[i8x16_ty_basic, i8x16_ty_basic], false); let ret_i16x8_take_i16x8_i16x8 = i16x8_ty.fn_type(&[i16x8_ty_basic, i16x8_ty_basic], false); @@ -403,6 +418,8 @@ impl<'ctx> Intrinsics<'ctx> { anyfunc_ty, funcref_ty, + externref_ty, + anyref_ty, i1_zero, i8_zero, @@ -442,12 +459,6 @@ impl<'ctx> Intrinsics<'ctx> { .const_int(TrapCode::TableAccessOutOfBounds as _, false) .as_basic_value_enum(), - // VM intrinsics. - throw_trap: module.add_function( - "wasmer_raise_trap", - void_ty.fn_type(&[i32_ty_basic], false), - None, - ), experimental_stackmap: module.add_function( "llvm.experimental.stackmap", void_ty.fn_type( @@ -460,6 +471,145 @@ impl<'ctx> Intrinsics<'ctx> { None, ), + // VM libcalls. + table_copy: module.add_function( + "wasmer_table_copy", + void_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + i32_ty_basic, + i32_ty_basic, + i32_ty_basic, + ], + false, + ), + None, + ), + table_init: module.add_function( + "wasmer_table_init", + void_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + i32_ty_basic, + i32_ty_basic, + i32_ty_basic, + ], + false, + ), + None, + ), + table_fill: module.add_function( + "wasmer_table_fill", + void_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + anyref_ty.as_basic_type_enum(), + i32_ty_basic, + ], + false, + ), + None, + ), + table_size: module.add_function( + "wasmer_table_size", + i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false), + None, + ), + imported_table_size: module.add_function( + "wasmer_imported_table_size", + i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false), + None, + ), + table_get: module.add_function( + "wasmer_table_get", + anyref_ty.fn_type( + &[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic], + false, + ), + None, + ), + imported_table_get: module.add_function( + "wasmer_imported_table_get", + anyref_ty.fn_type( + &[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic], + false, + ), + None, + ), + table_set: module.add_function( + "wasmer_table_set", + void_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + anyref_ty.as_basic_type_enum(), + ], + false, + ), + None, + ), + imported_table_set: module.add_function( + "wasmer_imported_table_set", + void_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + anyref_ty.as_basic_type_enum(), + ], + false, + ), + None, + ), + table_grow: module.add_function( + "wasmer_table_grow", + i32_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + ], + false, + ), + None, + ), + imported_table_grow: module.add_function( + "wasmer_imported_table_grow", + i32_ty.fn_type( + &[ + ctx_ptr_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), + i32_ty_basic, + i32_ty_basic, + ], + false, + ), + None, + ), + func_ref: module.add_function( + "wasmer_func_ref", + funcref_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false), + None, + ), + elem_drop: module.add_function( + "wasmer_elem_drop", + void_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false), + None, + ), + throw_trap: module.add_function( + "wasmer_raise_trap", + void_ty.fn_type(&[i32_ty_basic], false), + None, + ), + vmfunction_import_ptr_ty: context .struct_type(&[i8_ptr_ty_basic, i8_ptr_ty_basic], false) .ptr_type(AddressSpace::Generic), @@ -495,13 +645,14 @@ impl<'ctx> Intrinsics<'ctx> { ctx_ptr_ty, }; - // TODO: mark vmctx args as nofree, align 16, dereferenceable(?) - let noreturn = context.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 0); intrinsics .throw_trap .add_attribute(AttributeLoc::Function, noreturn); + intrinsics + .func_ref + .add_attribute(AttributeLoc::Function, intrinsics.readonly); intrinsics } diff --git a/lib/compiler-llvm/src/translator/state.rs b/lib/compiler-llvm/src/translator/state.rs index b1562183e52..e3046a09d09 100644 --- a/lib/compiler-llvm/src/translator/state.rs +++ b/lib/compiler-llvm/src/translator/state.rs @@ -315,6 +315,22 @@ impl<'ctx> State<'ctx> { Ok((v1, v2)) } + pub fn pop3( + &mut self, + ) -> Result< + ( + BasicValueEnum<'ctx>, + BasicValueEnum<'ctx>, + BasicValueEnum<'ctx>, + ), + CompileError, + > { + let v3 = self.pop1()?; + let v2 = self.pop1()?; + let v1 = self.pop1()?; + Ok((v1, v2, v3)) + } + pub fn pop3_extra( &mut self, ) -> Result< diff --git a/lib/vm/src/libcalls.rs b/lib/vm/src/libcalls.rs index ecbc6479cae..c458fb57616 100644 --- a/lib/vm/src/libcalls.rs +++ b/lib/vm/src/libcalls.rs @@ -142,6 +142,7 @@ pub extern "C" fn wasmer_f64_nearest(x: f64) -> f64 { /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_memory32_grow( vmctx: *mut VMContext, delta: u32, @@ -161,6 +162,7 @@ pub unsafe extern "C" fn wasmer_memory32_grow( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_imported_memory32_grow( vmctx: *mut VMContext, delta: u32, @@ -180,6 +182,7 @@ pub unsafe extern "C" fn wasmer_imported_memory32_grow( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 { let instance = (&*vmctx).instance(); let memory_index = LocalMemoryIndex::from_u32(memory_index); @@ -192,6 +195,7 @@ pub unsafe extern "C" fn wasmer_memory32_size(vmctx: *mut VMContext, memory_inde /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_imported_memory32_size( vmctx: *mut VMContext, memory_index: u32, @@ -207,6 +211,7 @@ pub unsafe extern "C" fn wasmer_imported_memory32_size( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_copy( vmctx: *mut VMContext, dst_table_index: u32, @@ -233,6 +238,7 @@ pub unsafe extern "C" fn wasmer_table_copy( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_init( vmctx: *mut VMContext, table_index: u32, @@ -257,6 +263,7 @@ pub unsafe extern "C" fn wasmer_table_init( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_fill( vmctx: *mut VMContext, table_index: u32, @@ -285,6 +292,7 @@ pub unsafe extern "C" fn wasmer_table_fill( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 { let instance = (&*vmctx).instance(); let table_index = LocalTableIndex::from_u32(table_index); @@ -297,6 +305,7 @@ pub unsafe extern "C" fn wasmer_table_size(vmctx: *mut VMContext, table_index: u /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_imported_table_size( vmctx: *mut VMContext, table_index: u32, @@ -312,6 +321,7 @@ pub unsafe extern "C" fn wasmer_imported_table_size( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_get( vmctx: *mut VMContext, table_index: u32, @@ -332,6 +342,7 @@ pub unsafe extern "C" fn wasmer_table_get( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_imported_table_get( vmctx: *mut VMContext, table_index: u32, @@ -352,6 +363,7 @@ pub unsafe extern "C" fn wasmer_imported_table_get( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_set( vmctx: *mut VMContext, table_index: u32, @@ -385,6 +397,7 @@ pub unsafe extern "C" fn wasmer_table_set( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_imported_table_set( vmctx: *mut VMContext, table_index: u32, @@ -412,6 +425,7 @@ pub unsafe extern "C" fn wasmer_imported_table_set( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_table_grow( vmctx: *mut VMContext, init_value: TableElement, @@ -437,6 +451,7 @@ pub unsafe extern "C" fn wasmer_table_grow( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_imported_table_grow( vmctx: *mut VMContext, init_value: TableElement, @@ -461,6 +476,7 @@ pub unsafe extern "C" fn wasmer_imported_table_grow( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_func_ref(vmctx: *mut VMContext, function_index: u32) -> VMFuncRef { let instance = (&*vmctx).instance(); let function_index = FunctionIndex::from_u32(function_index); @@ -473,6 +489,7 @@ pub unsafe extern "C" fn wasmer_func_ref(vmctx: *mut VMContext, function_index: /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_elem_drop(vmctx: *mut VMContext, elem_index: u32) { let elem_index = ElemIndex::from_u32(elem_index); let instance = (&*vmctx).instance(); @@ -484,7 +501,8 @@ pub unsafe extern "C" fn wasmer_elem_drop(vmctx: *mut VMContext, elem_index: u32 /// # Safety /// /// `vmctx` must be valid and not null. -pub unsafe extern "C" fn wasmer_local_memory_copy( +#[no_mangle] +pub unsafe extern "C" fn wasmer_memory32_copy( vmctx: *mut VMContext, memory_index: u32, dst: u32, @@ -506,7 +524,8 @@ pub unsafe extern "C" fn wasmer_local_memory_copy( /// # Safety /// /// `vmctx` must be valid and not null. -pub unsafe extern "C" fn wasmer_imported_memory_copy( +#[no_mangle] +pub unsafe extern "C" fn wasmer_imported_memory32_copy( vmctx: *mut VMContext, memory_index: u32, dst: u32, @@ -528,7 +547,8 @@ pub unsafe extern "C" fn wasmer_imported_memory_copy( /// # Safety /// /// `vmctx` must be valid and not null. -pub unsafe extern "C" fn wasmer_memory_fill( +#[no_mangle] +pub unsafe extern "C" fn wasmer_memory32_fill( vmctx: *mut VMContext, memory_index: u32, dst: u32, @@ -550,7 +570,8 @@ pub unsafe extern "C" fn wasmer_memory_fill( /// # Safety /// /// `vmctx` must be valid and not null. -pub unsafe extern "C" fn wasmer_imported_memory_fill( +#[no_mangle] +pub unsafe extern "C" fn wasmer_imported_memory32_fill( vmctx: *mut VMContext, memory_index: u32, dst: u32, @@ -572,7 +593,8 @@ pub unsafe extern "C" fn wasmer_imported_memory_fill( /// # Safety /// /// `vmctx` must be valid and not null. -pub unsafe extern "C" fn wasmer_memory_init( +#[no_mangle] +pub unsafe extern "C" fn wasmer_memory32_init( vmctx: *mut VMContext, memory_index: u32, data_index: u32, @@ -596,6 +618,7 @@ pub unsafe extern "C" fn wasmer_memory_init( /// # Safety /// /// `vmctx` must be valid and not null. +#[no_mangle] pub unsafe extern "C" fn wasmer_data_drop(vmctx: *mut VMContext, data_index: u32) { let data_index = DataIndex::from_u32(data_index); let instance = (&*vmctx).instance(); @@ -646,18 +669,81 @@ pub enum LibCall { /// nearest.f64 NearestF64, - /// probe for stack overflow. These are emitted for functions which need - /// when the `enable_probestack` setting is true. - Probestack, - - /// A custom trap - RaiseTrap, - /// trunc.f32 TruncF32, - /// frunc.f64 + /// trunc.f64 TruncF64, + + /// memory.size for local functions + Memory32Size, + + /// memory.size for imported functions + ImportedMemory32Size, + + /// table.copy + TableCopy, + + /// table.init + TableInit, + + /// table.fill + TableFill, + + /// table.size for local tables + TableSize, + + /// table.size for imported tables + ImportedTableSize, + + /// table.get for local tables + TableGet, + + /// table.get for imported tables + ImportedTableGet, + + /// table.set for local tables + TableSet, + + /// table.set for imported tables + ImportedTableSet, + + /// table.grow for local tables + TableGrow, + + /// table.grow for imported tables + ImportedTableGrow, + + /// ref.func + FuncRef, + + /// elem.drop + ElemDrop, + + /// memory.copy for local memories + Memory32Copy, + + /// memory.copy for imported memories + ImportedMemory32Copy, + + /// memory.fill for local memories + Memory32Fill, + + /// memory.fill for imported memories + ImportedMemory32Fill, + + /// memory.init + Memory32Init, + + /// data.drop + DataDrop, + + /// A custom trap + RaiseTrap, + + /// probe for stack overflow. These are emitted for functions which need + /// when the `enable_probestack` setting is true. + Probestack, } impl LibCall { @@ -670,10 +756,31 @@ impl LibCall { Self::FloorF64 => wasmer_f64_floor as usize, Self::NearestF32 => wasmer_f32_nearest as usize, Self::NearestF64 => wasmer_f64_nearest as usize, - Self::Probestack => wasmer_probestack as usize, - Self::RaiseTrap => wasmer_raise_trap as usize, Self::TruncF32 => wasmer_f32_trunc as usize, Self::TruncF64 => wasmer_f64_trunc as usize, + Self::Memory32Size => wasmer_memory32_size as usize, + Self::ImportedMemory32Size => wasmer_imported_memory32_size as usize, + Self::TableCopy => wasmer_table_copy as usize, + Self::TableInit => wasmer_table_init as usize, + Self::TableFill => wasmer_table_fill as usize, + Self::TableSize => wasmer_table_size as usize, + Self::ImportedTableSize => wasmer_imported_table_size as usize, + Self::TableGet => wasmer_table_get as usize, + Self::ImportedTableGet => wasmer_imported_table_get as usize, + Self::TableSet => wasmer_table_set as usize, + Self::ImportedTableSet => wasmer_imported_table_set as usize, + Self::TableGrow => wasmer_table_grow as usize, + Self::ImportedTableGrow => wasmer_imported_table_grow as usize, + Self::FuncRef => wasmer_func_ref as usize, + Self::ElemDrop => wasmer_elem_drop as usize, + Self::Memory32Copy => wasmer_memory32_copy as usize, + Self::ImportedMemory32Copy => wasmer_imported_memory32_copy as usize, + Self::Memory32Fill => wasmer_memory32_fill as usize, + Self::ImportedMemory32Fill => wasmer_memory32_fill as usize, + Self::Memory32Init => wasmer_memory32_init as usize, + Self::DataDrop => wasmer_data_drop as usize, + Self::Probestack => wasmer_probestack as usize, + Self::RaiseTrap => wasmer_raise_trap as usize, } } @@ -686,15 +793,36 @@ impl LibCall { Self::FloorF64 => "wasmer_f64_floor", Self::NearestF32 => "wasmer_f32_nearest", Self::NearestF64 => "wasmer_f64_nearest", + Self::TruncF32 => "wasmer_f32_trunc", + Self::TruncF64 => "wasmer_f64_trunc", + Self::Memory32Size => "wasmer_memory32_size", + Self::ImportedMemory32Size => "wasmer_imported_memory32_size", + Self::TableCopy => "wasmer_table_copy", + Self::TableInit => "wasmer_table_init", + Self::TableFill => "wasmer_table_fill", + Self::TableSize => "wasmer_table_size", + Self::ImportedTableSize => "wasmer_imported_table_size", + Self::TableGet => "wasmer_table_get", + Self::ImportedTableGet => "wasmer_imported_table_get", + Self::TableSet => "wasmer_table_set", + Self::ImportedTableSet => "wasmer_imported_table_set", + Self::TableGrow => "wasmer_table_grow", + Self::ImportedTableGrow => "wasmer_imported_table_grow", + Self::FuncRef => "wasmer_func_ref", + Self::ElemDrop => "wasmer_elem_drop", + Self::Memory32Copy => "wasmer_memory32_copy", + Self::ImportedMemory32Copy => "wasmer_imported_memory32_copy", + Self::Memory32Fill => "wasmer_memory32_fill", + Self::ImportedMemory32Fill => "wasmer_imported_memory32_fill", + Self::Memory32Init => "wasmer_memory32_init", + Self::DataDrop => "wasmer_data_drop", + Self::RaiseTrap => "wasmer_raise_trap", // We have to do this because macOS requires a leading `_` and it's not // a normal function, it's a static variable, so we have to do it manually. #[cfg(target_os = "macos")] Self::Probestack => "_wasmer_probestack", #[cfg(not(target_os = "macos"))] Self::Probestack => "wasmer_probestack", - Self::RaiseTrap => "wasmer_raise_trap", - Self::TruncF32 => "wasmer_f32_trunc", - Self::TruncF64 => "wasmer_f64_trunc", } } } diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index 3c876e725e5..8fc1c529234 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -890,7 +890,7 @@ impl VMBuiltinFunctionIndex { Self(6) } /// Returns an index for wasm's `memory.copy` for locally defined memories. - pub const fn get_local_memory_copy_index() -> Self { + pub const fn get_memory_copy_index() -> Self { Self(7) } /// Returns an index for wasm's `memory.copy` for imported memories. @@ -1003,16 +1003,16 @@ impl VMBuiltinFunctionsArray { ptrs[VMBuiltinFunctionIndex::get_elem_drop_index().index() as usize] = wasmer_elem_drop as usize; - ptrs[VMBuiltinFunctionIndex::get_local_memory_copy_index().index() as usize] = - wasmer_local_memory_copy as usize; + ptrs[VMBuiltinFunctionIndex::get_memory_copy_index().index() as usize] = + wasmer_memory32_copy as usize; ptrs[VMBuiltinFunctionIndex::get_imported_memory_copy_index().index() as usize] = - wasmer_imported_memory_copy as usize; + wasmer_imported_memory32_copy as usize; ptrs[VMBuiltinFunctionIndex::get_memory_fill_index().index() as usize] = - wasmer_memory_fill as usize; + wasmer_memory32_fill as usize; ptrs[VMBuiltinFunctionIndex::get_imported_memory_fill_index().index() as usize] = - wasmer_imported_memory_fill as usize; + wasmer_imported_memory32_fill as usize; ptrs[VMBuiltinFunctionIndex::get_memory_init_index().index() as usize] = - wasmer_memory_init as usize; + wasmer_memory32_init as usize; ptrs[VMBuiltinFunctionIndex::get_data_drop_index().index() as usize] = wasmer_data_drop as usize; ptrs[VMBuiltinFunctionIndex::get_raise_trap_index().index() as usize] = diff --git a/tests/ignores.txt b/tests/ignores.txt index fc6419620bd..02403d67fd4 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -34,20 +34,6 @@ cranelift::spec::simd::simd_i8x16_sat_arith on aarch64 cranelift::spec::simd::simd_lane on aarch64 cranelift::spec::skip_stack_guard_page on aarch64 -## Reference types spectests -# Used to disable tests during development; these ignores should not ship -llvm::spec::ref_func -llvm::spec::ref_is_null -llvm::spec::ref_null -llvm::spec::table_copy -llvm::spec::table_fill -llvm::spec::table_get -llvm::spec::table_grow -llvm::spec::table_init -llvm::spec::table_set -llvm::spec::table_size -llvm::spec::table_sub - # SIMD changes # due to breaking changes in the SIMD proposal, we have to disable these spec tests # note we've not pulled in the updated spec tests yet, so expect more breakage