From b14afa13425223b5aa81fb0178952f7b386f3b44 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 1 Mar 2021 11:53:12 -0800 Subject: [PATCH 1/4] Implement all reference types instructions in compiler-llvm. Remove spectest ignores for reference types tests on llvm. Extend llvm ABIs to pass externref and funcref. Expose all libcalls through the Libcalls enum. Add support for all libcalls to llvm object_file.rs, even libcalls that we aren't using. Add missing no_mangle to libcalls. Change 'memory' to 'memory32' in libcalls in preparation for the memory64 proposal. Remove 'local' from 'wasmer_local_memory_copy' in libcalls to fit naming convention. Add mangling of externref and funcref for llvm-debug-dir. Mark 'wasmer_func_ref' readonly. --- lib/cli/src/store.rs | 15 +- lib/compiler-cranelift/src/func_environ.rs | 2 +- lib/compiler-llvm/src/abi/aarch64_systemv.rs | 12 +- lib/compiler-llvm/src/abi/x86_64_systemv.rs | 40 +--- lib/compiler-llvm/src/object_file.rs | 56 +++++- lib/compiler-llvm/src/translator/code.rs | 186 ++++++++++++++++++ .../src/translator/intrinsics.rs | 183 +++++++++++++++-- lib/compiler-llvm/src/translator/state.rs | 16 ++ lib/vm/src/libcalls.rs | 164 +++++++++++++-- lib/vm/src/vmcontext.rs | 14 +- tests/ignores.txt | 14 -- 11 files changed, 595 insertions(+), 107 deletions(-) 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..59a0ed5143c 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -9344,6 +9344,192 @@ 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 { .. } => { + self.state.push1(self.intrinsics.funcref_ty.const_null()); + } + 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(); + 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 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()?; + 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 (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..0e81255d3ad 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.funcref_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.funcref_ty.as_basic_type_enum()), } } @@ -169,11 +165,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 +197,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>, } @@ -442,12 +453,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 +465,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, + funcref_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", + funcref_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", + i8_ptr_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, + funcref_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, + funcref_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(), + funcref_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(), + funcref_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(&[i8_ptr_ty_basic, i32_ty_basic], false), + None, + ), + elem_drop: module.add_function( + "wasmer_elem_drop", + void_ty.fn_type(&[i8_ptr_ty_basic, 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 +639,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 From 7d9dd4d349b3f5f3a74caee7714e4a3cf793fc35 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 1 Mar 2021 12:17:38 -0800 Subject: [PATCH 2/4] Correct the type of vmctx on these functions. --- lib/compiler-llvm/src/translator/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index 0e81255d3ad..99a9f418317 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -590,12 +590,12 @@ impl<'ctx> Intrinsics<'ctx> { ), func_ref: module.add_function( "wasmer_func_ref", - funcref_ty.fn_type(&[i8_ptr_ty_basic, i32_ty_basic], false), + 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(&[i8_ptr_ty_basic, i32_ty_basic], false), + void_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false), None, ), throw_trap: module.add_function( From 3c6168d0bb4940f1b87007efa2338a967875072a Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 1 Mar 2021 13:22:56 -0800 Subject: [PATCH 3/4] Split funcref and externref into separate LLVM types, add anyref_ty. --- lib/compiler-llvm/src/translator/code.rs | 21 ++++++++++++++ .../src/translator/intrinsics.rs | 28 +++++++++++-------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 59a0ed5143c..54d1c961dfc 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -9394,6 +9394,18 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .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 } => { @@ -9403,6 +9415,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .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)) @@ -9475,6 +9490,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .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], @@ -9483,6 +9501,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } 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)) diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index 99a9f418317..6d0fd5e49b2 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -40,7 +40,7 @@ pub fn type_to_llvm_ptr<'ctx>( Type::F64 => Ok(intrinsics.f64_ptr_ty), Type::V128 => Ok(intrinsics.i128_ptr_ty), Type::FuncRef => Ok(intrinsics.funcref_ty.ptr_type(AddressSpace::Generic)), - Type::ExternRef => Ok(intrinsics.funcref_ty.ptr_type(AddressSpace::Generic)), + Type::ExternRef => Ok(intrinsics.externref_ty.ptr_type(AddressSpace::Generic)), } } @@ -55,7 +55,7 @@ pub fn type_to_llvm<'ctx>( Type::F64 => Ok(intrinsics.f64_ty.as_basic_type_enum()), Type::V128 => Ok(intrinsics.i128_ty.as_basic_type_enum()), Type::FuncRef => Ok(intrinsics.funcref_ty.as_basic_type_enum()), - Type::ExternRef => Ok(intrinsics.funcref_ty.as_basic_type_enum()), + Type::ExternRef => Ok(intrinsics.externref_ty.as_basic_type_enum()), } } @@ -141,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>, @@ -265,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); @@ -414,6 +418,8 @@ impl<'ctx> Intrinsics<'ctx> { anyfunc_ty, funcref_ty, + externref_ty, + anyref_ty, i1_zero, i8_zero, @@ -503,7 +509,7 @@ impl<'ctx> Intrinsics<'ctx> { ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic, - funcref_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), i32_ty_basic, ], false, @@ -522,7 +528,7 @@ impl<'ctx> Intrinsics<'ctx> { ), table_get: module.add_function( "wasmer_table_get", - funcref_ty.fn_type( + anyref_ty.fn_type( &[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic], false, ), @@ -530,7 +536,7 @@ impl<'ctx> Intrinsics<'ctx> { ), imported_table_get: module.add_function( "wasmer_imported_table_get", - i8_ptr_ty.fn_type( + anyref_ty.fn_type( &[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic], false, ), @@ -543,7 +549,7 @@ impl<'ctx> Intrinsics<'ctx> { ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic, - funcref_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), ], false, ), @@ -556,7 +562,7 @@ impl<'ctx> Intrinsics<'ctx> { ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic, - funcref_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), ], false, ), @@ -567,7 +573,7 @@ impl<'ctx> Intrinsics<'ctx> { i32_ty.fn_type( &[ ctx_ptr_ty.as_basic_type_enum(), - funcref_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic, ], @@ -580,7 +586,7 @@ impl<'ctx> Intrinsics<'ctx> { i32_ty.fn_type( &[ ctx_ptr_ty.as_basic_type_enum(), - funcref_ty.as_basic_type_enum(), + anyref_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic, ], From 40f40bb7d45d0045cb0c16418c7e9992745fe813 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 1 Mar 2021 13:40:04 -0800 Subject: [PATCH 4/4] RefNull may return any reference type. --- lib/compiler-llvm/src/translator/code.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 54d1c961dfc..614bc7a9fcb 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -9348,8 +9348,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { * Reference types. * https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md ***************************/ - Operator::RefNull { .. } => { - self.state.push1(self.intrinsics.funcref_ty.const_null()); + 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();