From 693b210638278daa4bfafb226fce35465e44d089 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 23 Mar 2020 14:32:26 +0100 Subject: [PATCH 01/15] fix(interface-types) Stack pops items in the same order than Wasm invocation rule. --- lib/interface-types/src/interpreter/stack.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/interface-types/src/interpreter/stack.rs b/lib/interface-types/src/interpreter/stack.rs index 7877da573..7d39b9f91 100644 --- a/lib/interface-types/src/interpreter/stack.rs +++ b/lib/interface-types/src/interpreter/stack.rs @@ -22,8 +22,8 @@ pub trait Stackable { /// Removes `n` elements from the end of the stack, `None` if the /// stack doesn't contain enough elements. - /// Returned items are ordered by FIFO: the last element comes - /// first in the list. + /// Returned items are in reverse order: the last element comes + /// last in the list. fn pop(&mut self, n: usize) -> Option>; } @@ -78,7 +78,6 @@ where let items = self .inner .drain(self.inner.len() - n..) - .rev() .collect::>(); assert!(items.len() == n); @@ -121,9 +120,9 @@ mod tests { stack.push(6); assert_eq!(stack.pop(1), Some(vec![6])); - assert_eq!(stack.pop(2), Some(vec![5, 4])); + assert_eq!(stack.pop(2), Some(vec![4, 5])); assert_eq!(stack.pop(4), None); // not enough items - assert_eq!(stack.pop(3), Some(vec![3, 2, 1])); + assert_eq!(stack.pop(3), Some(vec![1, 2, 3])); assert_eq!(stack.pop1(), None); assert_eq!(stack.is_empty(), true); } From a1f0a556e58a5d77c798262d00825fb7f202f41b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 23 Mar 2020 14:34:57 +0100 Subject: [PATCH 02/15] fix(interface-types) Use same stack order than Wasm invocation rule. --- .../src/interpreter/instructions/call_core.rs | 8 +++--- .../instructions/memory_to_string.rs | 26 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/interface-types/src/interpreter/instructions/call_core.rs b/lib/interface-types/src/interpreter/instructions/call_core.rs index 77486498f..5a3da2124 100644 --- a/lib/interface-types/src/interpreter/instructions/call_core.rs +++ b/lib/interface-types/src/interpreter/instructions/call_core.rs @@ -70,8 +70,8 @@ mod tests { test_executable_instruction!( test_call_core = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::CallCore { function_index: 42 }, ], invocation_inputs: [ @@ -113,8 +113,8 @@ mod tests { test_executable_instruction!( test_call_core__invalid_types_in_the_stack = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::CallCore { function_index: 42 }, ], invocation_inputs: [ @@ -129,8 +129,8 @@ mod tests { test_executable_instruction!( test_call_core__failure_when_calling = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::CallCore { function_index: 42 }, ], invocation_inputs: [ @@ -160,8 +160,8 @@ mod tests { test_executable_instruction!( test_call_core__void = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::CallCore { function_index: 42 }, ], invocation_inputs: [ diff --git a/lib/interface-types/src/interpreter/instructions/memory_to_string.rs b/lib/interface-types/src/interpreter/instructions/memory_to_string.rs index e30b70ce0..8e9902ca1 100644 --- a/lib/interface-types/src/interpreter/instructions/memory_to_string.rs +++ b/lib/interface-types/src/interpreter/instructions/memory_to_string.rs @@ -27,8 +27,8 @@ executable_instruction!( ) })?; - let length = to_native::(&inputs[0], instruction)? as usize; - let pointer = to_native::(&inputs[1], instruction)? as usize; + let pointer = to_native::(&inputs[0], instruction)? as usize; + let length = to_native::(&inputs[1], instruction)? as usize; let memory_view = memory.view(); if length == 0 { @@ -67,15 +67,15 @@ mod tests { test_executable_instruction!( test_memory_to_string = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::MemoryToString, ], invocation_inputs: [ - InterfaceValue::I32(13), - // ^^^^^^^ length InterfaceValue::I32(0), // ^^^^^^ pointer + InterfaceValue::I32(13), + // ^^^^^^^ length ], instance: Instance { memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), @@ -87,8 +87,8 @@ mod tests { test_executable_instruction!( test_memory_to_string__empty_string = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::MemoryToString, ], invocation_inputs: [ @@ -105,15 +105,15 @@ mod tests { test_executable_instruction!( test_memory_to_string__read_out_of_memory = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::MemoryToString, ], invocation_inputs: [ - InterfaceValue::I32(13), - // ^^^^^^^ length is too long InterfaceValue::I32(0), // ^^^^^^ pointer + InterfaceValue::I32(13), + // ^^^^^^^ length is too long ], instance: Instance { memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), @@ -125,15 +125,15 @@ mod tests { test_executable_instruction!( test_memory_to_string__invalid_encoding = instructions: [ - Instruction::ArgumentGet { index: 1 }, Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, Instruction::MemoryToString, ], invocation_inputs: [ - InterfaceValue::I32(4), - // ^^^^^^ length is too long InterfaceValue::I32(0), // ^^^^^^ pointer + InterfaceValue::I32(4), + // ^^^^^^ length is too long ], instance: Instance { memory: Memory::new(vec![0, 159, 146, 150].iter().map(|b| Cell::new(*b)).collect::>>()), @@ -150,8 +150,8 @@ mod tests { // ^^^^^^^^^^^^^^ `memory-to-string` expects 2 values on the stack, only one is present. ], invocation_inputs: [ - InterfaceValue::I32(13), InterfaceValue::I32(0), + InterfaceValue::I32(13), ], instance: Instance::new(), error: r#"`memory-to-string` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#, From 50201a5e0ba20792798b892350e563a1a3403b9d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 12:43:57 +0100 Subject: [PATCH 03/15] feat(interface-types) Implement `[siu](NN|MM).from_*` instructions. Basically the `x-to-y` instructions have been renamed `y.from_x`. This patch updates the instruction. The binary representation isn't specified yet, so it's just arbitrary values. --- lib/interface-types/src/decoders/binary.rs | 225 ++++---- lib/interface-types/src/decoders/wat.rs | 497 ++++++++---------- lib/interface-types/src/encoders/binary.rs | 225 ++++---- lib/interface-types/src/encoders/wat.rs | 213 ++++---- .../src/interpreter/instruction.rs | 149 +++--- .../instructions/lowering_lifting.rs | 400 +++++++------- lib/interface-types/src/interpreter/mod.rs | 97 ++-- 7 files changed, 832 insertions(+), 974 deletions(-) diff --git a/lib/interface-types/src/decoders/binary.rs b/lib/interface-types/src/decoders/binary.rs index 9dc0f8c7b..367551d60 100644 --- a/lib/interface-types/src/decoders/binary.rs +++ b/lib/interface-types/src/decoders/binary.rs @@ -174,9 +174,42 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( ) } - 0x03 => (input, Instruction::MemoryToString), + 0x02 => (input, Instruction::S8FromI32), + 0x03 => (input, Instruction::S8FromI64), + 0x04 => (input, Instruction::S16FromI32), + 0x05 => (input, Instruction::S16FromI64), + 0x06 => (input, Instruction::S32FromI32), + 0x07 => (input, Instruction::S32FromI64), + 0x08 => (input, Instruction::S64FromI32), + 0x09 => (input, Instruction::S64FromI64), + 0x0a => (input, Instruction::I32FromS8), + 0x0b => (input, Instruction::I32FromS16), + 0x0c => (input, Instruction::I32FromS32), + 0x0d => (input, Instruction::I32FromS64), + 0x0e => (input, Instruction::I64FromS8), + 0x0f => (input, Instruction::I64FromS16), + 0x10 => (input, Instruction::I64FromS32), + 0x11 => (input, Instruction::I64FromS64), + 0x12 => (input, Instruction::U8FromI32), + 0x13 => (input, Instruction::U8FromI64), + 0x14 => (input, Instruction::U16FromI32), + 0x15 => (input, Instruction::U16FromI64), + 0x16 => (input, Instruction::U32FromI32), + 0x17 => (input, Instruction::U32FromI64), + 0x18 => (input, Instruction::U64FromI32), + 0x19 => (input, Instruction::U64FromI64), + 0x1a => (input, Instruction::I32FromU8), + 0x1b => (input, Instruction::I32FromU16), + 0x1c => (input, Instruction::I32FromU32), + 0x1d => (input, Instruction::I32FromU64), + 0x1e => (input, Instruction::I64FromU8), + 0x1f => (input, Instruction::I64FromU16), + 0x20 => (input, Instruction::I64FromU32), + 0x21 => (input, Instruction::I64FromU64), - 0x04 => { + 0x22 => (input, Instruction::MemoryToString), + + 0x23 => { consume!((input, argument_0) = uleb(input)?); ( input, @@ -186,46 +219,6 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( ) } - 0x07 => (input, Instruction::I32ToS8), - 0x08 => (input, Instruction::I32ToS8X), - 0x09 => (input, Instruction::I32ToU8), - 0x0a => (input, Instruction::I32ToS16), - 0x0b => (input, Instruction::I32ToS16X), - 0x0c => (input, Instruction::I32ToU16), - 0x0d => (input, Instruction::I32ToS32), - 0x0e => (input, Instruction::I32ToU32), - 0x0f => (input, Instruction::I32ToS64), - 0x10 => (input, Instruction::I32ToU64), - 0x11 => (input, Instruction::I64ToS8), - 0x12 => (input, Instruction::I64ToS8X), - 0x13 => (input, Instruction::I64ToU8), - 0x14 => (input, Instruction::I64ToS16), - 0x15 => (input, Instruction::I64ToS16X), - 0x16 => (input, Instruction::I64ToU16), - 0x17 => (input, Instruction::I64ToS32), - 0x18 => (input, Instruction::I64ToS32X), - 0x19 => (input, Instruction::I64ToU32), - 0x1a => (input, Instruction::I64ToS64), - 0x1b => (input, Instruction::I64ToU64), - 0x1c => (input, Instruction::S8ToI32), - 0x1d => (input, Instruction::U8ToI32), - 0x1e => (input, Instruction::S16ToI32), - 0x1f => (input, Instruction::U16ToI32), - 0x20 => (input, Instruction::S32ToI32), - 0x21 => (input, Instruction::U32ToI32), - 0x22 => (input, Instruction::S64ToI32), - 0x23 => (input, Instruction::S64ToI32X), - 0x24 => (input, Instruction::U64ToI32), - 0x25 => (input, Instruction::U64ToI32X), - 0x26 => (input, Instruction::S8ToI64), - 0x27 => (input, Instruction::U8ToI64), - 0x28 => (input, Instruction::S16ToI64), - 0x29 => (input, Instruction::U16ToI64), - 0x2a => (input, Instruction::S32ToI64), - 0x2b => (input, Instruction::U32ToI64), - 0x2c => (input, Instruction::S64ToI64), - 0x2d => (input, Instruction::U64ToI64), - _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }) } @@ -627,50 +620,43 @@ mod tests { #[test] fn test_instructions() { let input = &[ - 0x2b, // list of 43 items + 0x24, // list of 36 items 0x00, 0x01, // ArgumentGet { index: 1 } 0x01, 0x01, // CallCore { function_index: 1 } - 0x03, // MemoryToString - 0x04, 0x01, // StringToMemory { allocator_index: 1 } - 0x07, // I32ToS8 - 0x08, // I32ToS8X - 0x09, // I32ToU8 - 0x0a, // I32ToS16 - 0x0b, // I32ToS16X - 0x0c, // I32ToU16 - 0x0d, // I32ToS32 - 0x0e, // I32ToU32 - 0x0f, // I32ToS64 - 0x10, // I32ToU64 - 0x11, // I64ToS8 - 0x12, // I64ToS8X - 0x13, // I64ToU8 - 0x14, // I64ToS16 - 0x15, // I64ToS16X - 0x16, // I64ToU16 - 0x17, // I64ToS32 - 0x18, // I64ToS32X - 0x19, // I64ToU32 - 0x1a, // I64ToS64 - 0x1b, // I64ToU64 - 0x1c, // S8ToI32 - 0x1d, // U8ToI32 - 0x1e, // S16ToI32 - 0x1f, // U16ToI32 - 0x20, // S32ToI32 - 0x21, // U32ToI32 - 0x22, // S64ToI32 - 0x23, // S64ToI32X - 0x24, // U64ToI32 - 0x25, // U64ToI32X - 0x26, // S8ToI64 - 0x27, // U8ToI64 - 0x28, // S16ToI64 - 0x29, // U16ToI64 - 0x2a, // S32ToI64 - 0x2b, // U32ToI64 - 0x2c, // S64ToI64 - 0x2d, // U64ToI64 + 0x02, // S8FromI32 + 0x03, // S8FromI64 + 0x04, // S16FromI32 + 0x05, // S16FromI64 + 0x06, // S32FromI32 + 0x07, // S32FromI64 + 0x08, // S64FromI32 + 0x09, // S64FromI64 + 0x0a, // I32FromS8 + 0x0b, // I32FromS16 + 0x0c, // I32FromS32 + 0x0d, // I32FromS64 + 0x0e, // I64FromS8 + 0x0f, // I64FromS16 + 0x10, // I64FromS32 + 0x11, // I64FromS64 + 0x12, // U8FromI32 + 0x13, // U8FromI64 + 0x14, // U16FromI32 + 0x15, // U16FromI64 + 0x16, // U32FromI32 + 0x17, // U32FromI64 + 0x18, // U64FromI32 + 0x19, // U64FromI64 + 0x1a, // I32FromU8 + 0x1b, // I32FromU16 + 0x1c, // I32FromU32 + 0x1d, // I32FromU64 + 0x1e, // I64FromU8 + 0x1f, // I64FromU16 + 0x20, // I64FromU32 + 0x21, // I64FromU64 + 0x22, // MemoryToString + 0x23, 0x01, // StringToMemory { allocator_index: 1 } 0x0a, ]; let output = Ok(( @@ -678,47 +664,40 @@ mod tests { vec![ Instruction::ArgumentGet { index: 1 }, Instruction::CallCore { function_index: 1 }, + Instruction::S8FromI32, + Instruction::S8FromI64, + Instruction::S16FromI32, + Instruction::S16FromI64, + Instruction::S32FromI32, + Instruction::S32FromI64, + Instruction::S64FromI32, + Instruction::S64FromI64, + Instruction::I32FromS8, + Instruction::I32FromS16, + Instruction::I32FromS32, + Instruction::I32FromS64, + Instruction::I64FromS8, + Instruction::I64FromS16, + Instruction::I64FromS32, + Instruction::I64FromS64, + Instruction::U8FromI32, + Instruction::U8FromI64, + Instruction::U16FromI32, + Instruction::U16FromI64, + Instruction::U32FromI32, + Instruction::U32FromI64, + Instruction::U64FromI32, + Instruction::U64FromI64, + Instruction::I32FromU8, + Instruction::I32FromU16, + Instruction::I32FromU32, + Instruction::I32FromU64, + Instruction::I64FromU8, + Instruction::I64FromU16, + Instruction::I64FromU32, + Instruction::I64FromU64, Instruction::MemoryToString, Instruction::StringToMemory { allocator_index: 1 }, - Instruction::I32ToS8, - Instruction::I32ToS8X, - Instruction::I32ToU8, - Instruction::I32ToS16, - Instruction::I32ToS16X, - Instruction::I32ToU16, - Instruction::I32ToS32, - Instruction::I32ToU32, - Instruction::I32ToS64, - Instruction::I32ToU64, - Instruction::I64ToS8, - Instruction::I64ToS8X, - Instruction::I64ToU8, - Instruction::I64ToS16, - Instruction::I64ToS16X, - Instruction::I64ToU16, - Instruction::I64ToS32, - Instruction::I64ToS32X, - Instruction::I64ToU32, - Instruction::I64ToS64, - Instruction::I64ToU64, - Instruction::S8ToI32, - Instruction::U8ToI32, - Instruction::S16ToI32, - Instruction::U16ToI32, - Instruction::S32ToI32, - Instruction::U32ToI32, - Instruction::S64ToI32, - Instruction::S64ToI32X, - Instruction::U64ToI32, - Instruction::U64ToI32X, - Instruction::S8ToI64, - Instruction::U8ToI64, - Instruction::S16ToI64, - Instruction::U16ToI64, - Instruction::S32ToI64, - Instruction::U32ToI64, - Instruction::S64ToI64, - Instruction::U64ToI64, ], )); diff --git a/lib/interface-types/src/decoders/wat.rs b/lib/interface-types/src/decoders/wat.rs index 809b5e5a6..656673b47 100644 --- a/lib/interface-types/src/decoders/wat.rs +++ b/lib/interface-types/src/decoders/wat.rs @@ -28,47 +28,40 @@ mod keyword { // Instructions. custom_keyword!(argument_get = "arg.get"); custom_keyword!(call_core = "call-core"); + custom_keyword!(s8_from_i32 = "s8.from_i32"); + custom_keyword!(s8_from_i64 = "s8.from_i64"); + custom_keyword!(s16_from_i32 = "s16.from_i32"); + custom_keyword!(s16_from_i64 = "s16.from_i64"); + custom_keyword!(s32_from_i32 = "s32.from_i32"); + custom_keyword!(s32_from_i64 = "s32.from_i64"); + custom_keyword!(s64_from_i32 = "s64.from_i32"); + custom_keyword!(s64_from_i64 = "s64.from_i64"); + custom_keyword!(i32_from_s8 = "i32.from_s8"); + custom_keyword!(i32_from_s16 = "i32.from_s16"); + custom_keyword!(i32_from_s32 = "i32.from_s32"); + custom_keyword!(i32_from_s64 = "i32.from_s64"); + custom_keyword!(i64_from_s8 = "i64.from_s8"); + custom_keyword!(i64_from_s16 = "i64.from_s16"); + custom_keyword!(i64_from_s32 = "i64.from_s32"); + custom_keyword!(i64_from_s64 = "i64.from_s64"); + custom_keyword!(u8_from_i32 = "u8.from_i32"); + custom_keyword!(u8_from_i64 = "u8.from_i64"); + custom_keyword!(u16_from_i32 = "u16.from_i32"); + custom_keyword!(u16_from_i64 = "u16.from_i64"); + custom_keyword!(u32_from_i32 = "u32.from_i32"); + custom_keyword!(u32_from_i64 = "u32.from_i64"); + custom_keyword!(u64_from_i32 = "u64.from_i32"); + custom_keyword!(u64_from_i64 = "u64.from_i64"); + custom_keyword!(i32_from_u8 = "i32.from_u8"); + custom_keyword!(i32_from_u16 = "i32.from_u16"); + custom_keyword!(i32_from_u32 = "i32.from_u32"); + custom_keyword!(i32_from_u64 = "i32.from_u64"); + custom_keyword!(i64_from_u8 = "i64.from_u8"); + custom_keyword!(i64_from_u16 = "i64.from_u16"); + custom_keyword!(i64_from_u32 = "i64.from_u32"); + custom_keyword!(i64_from_u64 = "i64.from_u64"); custom_keyword!(memory_to_string = "memory-to-string"); custom_keyword!(string_to_memory = "string-to-memory"); - custom_keyword!(i32_to_s8 = "i32-to-s8"); - custom_keyword!(i32_to_s8x = "i32-to-s8x"); - custom_keyword!(i32_to_u8 = "i32-to-u8"); - custom_keyword!(i32_to_s16 = "i32-to-s16"); - custom_keyword!(i32_to_s16x = "i32-to-s16x"); - custom_keyword!(i32_to_u16 = "i32-to-u16"); - custom_keyword!(i32_to_s32 = "i32-to-s32"); - custom_keyword!(i32_to_u32 = "i32-to-u32"); - custom_keyword!(i32_to_s64 = "i32-to-s64"); - custom_keyword!(i32_to_u64 = "i32-to-u64"); - custom_keyword!(i64_to_s8 = "i64-to-s8"); - custom_keyword!(i64_to_s8x = "i64-to-s8x"); - custom_keyword!(i64_to_u8 = "i64-to-u8"); - custom_keyword!(i64_to_s16 = "i64-to-s16"); - custom_keyword!(i64_to_s16x = "i64-to-s16x"); - custom_keyword!(i64_to_u16 = "i64-to-u16"); - custom_keyword!(i64_to_s32 = "i64-to-s32"); - custom_keyword!(i64_to_s32x = "i64-to-s32x"); - custom_keyword!(i64_to_u32 = "i64-to-u32"); - custom_keyword!(i64_to_s64 = "i64-to-s64"); - custom_keyword!(i64_to_u64 = "i64-to-u64"); - custom_keyword!(s8_to_i32 = "s8-to-i32"); - custom_keyword!(u8_to_i32 = "u8-to-i32"); - custom_keyword!(s16_to_i32 = "s16-to-i32"); - custom_keyword!(u16_to_i32 = "u16-to-i32"); - custom_keyword!(s32_to_i32 = "s32-to-i32"); - custom_keyword!(u32_to_i32 = "u32-to-i32"); - custom_keyword!(s64_to_i32 = "s64-to-i32"); - custom_keyword!(s64_to_i32x = "s64-to-i32x"); - custom_keyword!(u64_to_i32 = "u64-to-i32"); - custom_keyword!(u64_to_i32x = "u64-to-i32x"); - custom_keyword!(s8_to_i64 = "s8-to-i64"); - custom_keyword!(u8_to_i64 = "u8-to-i64"); - custom_keyword!(s16_to_i64 = "s16-to-i64"); - custom_keyword!(u16_to_i64 = "u16-to-i64"); - custom_keyword!(s32_to_i64 = "s32-to-i64"); - custom_keyword!(u32_to_i64 = "u32-to-i64"); - custom_keyword!(s64_to_i64 = "s64-to-i64"); - custom_keyword!(u64_to_i64 = "u64-to-i64"); } impl Parse<'_> for InterfaceType { @@ -154,6 +147,134 @@ impl<'a> Parse<'a> for Instruction { Ok(Instruction::CallCore { function_index: parser.parse::()? as usize, }) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S8FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S8FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S16FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S16FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S32FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S32FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S64FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::S64FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromS8) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromS16) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromS32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromS64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromS8) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromS16) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromS32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromS64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U8FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U8FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U16FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U16FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U32FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U32FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U64FromI32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::U64FromI64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromU8) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromU16) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromU32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I32FromU64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromU8) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromU16) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromU32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::I64FromU64) } else if lookahead.peek::() { parser.parse::()?; @@ -164,162 +285,6 @@ impl<'a> Parse<'a> for Instruction { Ok(Instruction::StringToMemory { allocator_index: parser.parse()?, }) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToS8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToS8X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToU8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToS16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToS16X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToU16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToS32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToU32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToS64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32ToU64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS8X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToU8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS16X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToU16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS32X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToU32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToS64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64ToU64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S8ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U8ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S16ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U16ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S32ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U32ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S64ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S64ToI32X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U64ToI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U64ToI32X) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S8ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U8ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S16ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U16ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S32ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U32ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S64ToI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U64ToI64) } else { Err(lookahead.error()) } @@ -667,94 +632,80 @@ mod tests { let inputs = vec![ "arg.get 7", "call-core 7", + "s8.from_i32", + "s8.from_i64", + "s16.from_i32", + "s16.from_i64", + "s32.from_i32", + "s32.from_i64", + "s64.from_i32", + "s64.from_i64", + "i32.from_s8", + "i32.from_s16", + "i32.from_s32", + "i32.from_s64", + "i64.from_s8", + "i64.from_s16", + "i64.from_s32", + "i64.from_s64", + "u8.from_i32", + "u8.from_i64", + "u16.from_i32", + "u16.from_i64", + "u32.from_i32", + "u32.from_i64", + "u64.from_i32", + "u64.from_i64", + "i32.from_u8", + "i32.from_u16", + "i32.from_u32", + "i32.from_u64", + "i64.from_u8", + "i64.from_u16", + "i64.from_u32", + "i64.from_u64", "memory-to-string", "string-to-memory 42", - "i32-to-s8", - "i32-to-s8x", - "i32-to-u8", - "i32-to-s16", - "i32-to-s16x", - "i32-to-u16", - "i32-to-s32", - "i32-to-u32", - "i32-to-s64", - "i32-to-u64", - "i64-to-s8", - "i64-to-s8x", - "i64-to-u8", - "i64-to-s16", - "i64-to-s16x", - "i64-to-u16", - "i64-to-s32", - "i64-to-s32x", - "i64-to-u32", - "i64-to-s64", - "i64-to-u64", - "s8-to-i32", - "u8-to-i32", - "s16-to-i32", - "u16-to-i32", - "s32-to-i32", - "u32-to-i32", - "s64-to-i32", - "s64-to-i32x", - "u64-to-i32", - "u64-to-i32x", - "s8-to-i64", - "u8-to-i64", - "s16-to-i64", - "u16-to-i64", - "s32-to-i64", - "u32-to-i64", - "s64-to-i64", - "u64-to-i64", ]; let outputs = vec![ Instruction::ArgumentGet { index: 7 }, Instruction::CallCore { function_index: 7 }, + Instruction::S8FromI32, + Instruction::S8FromI64, + Instruction::S16FromI32, + Instruction::S16FromI64, + Instruction::S32FromI32, + Instruction::S32FromI64, + Instruction::S64FromI32, + Instruction::S64FromI64, + Instruction::I32FromS8, + Instruction::I32FromS16, + Instruction::I32FromS32, + Instruction::I32FromS64, + Instruction::I64FromS8, + Instruction::I64FromS16, + Instruction::I64FromS32, + Instruction::I64FromS64, + Instruction::U8FromI32, + Instruction::U8FromI64, + Instruction::U16FromI32, + Instruction::U16FromI64, + Instruction::U32FromI32, + Instruction::U32FromI64, + Instruction::U64FromI32, + Instruction::U64FromI64, + Instruction::I32FromU8, + Instruction::I32FromU16, + Instruction::I32FromU32, + Instruction::I32FromU64, + Instruction::I64FromU8, + Instruction::I64FromU16, + Instruction::I64FromU32, + Instruction::I64FromU64, Instruction::MemoryToString, Instruction::StringToMemory { allocator_index: 42, }, - Instruction::I32ToS8, - Instruction::I32ToS8X, - Instruction::I32ToU8, - Instruction::I32ToS16, - Instruction::I32ToS16X, - Instruction::I32ToU16, - Instruction::I32ToS32, - Instruction::I32ToU32, - Instruction::I32ToS64, - Instruction::I32ToU64, - Instruction::I64ToS8, - Instruction::I64ToS8X, - Instruction::I64ToU8, - Instruction::I64ToS16, - Instruction::I64ToS16X, - Instruction::I64ToU16, - Instruction::I64ToS32, - Instruction::I64ToS32X, - Instruction::I64ToU32, - Instruction::I64ToS64, - Instruction::I64ToU64, - Instruction::S8ToI32, - Instruction::U8ToI32, - Instruction::S16ToI32, - Instruction::U16ToI32, - Instruction::S32ToI32, - Instruction::U32ToI32, - Instruction::S64ToI32, - Instruction::S64ToI32X, - Instruction::U64ToI32, - Instruction::U64ToI32X, - Instruction::S8ToI64, - Instruction::U8ToI64, - Instruction::S16ToI64, - Instruction::U16ToI64, - Instruction::S32ToI64, - Instruction::U32ToI64, - Instruction::S64ToI64, - Instruction::U64ToI64, ]; assert_eq!(inputs.len(), outputs.len()); diff --git a/lib/interface-types/src/encoders/binary.rs b/lib/interface-types/src/encoders/binary.rs index cd322232d..9a89e3e8c 100644 --- a/lib/interface-types/src/encoders/binary.rs +++ b/lib/interface-types/src/encoders/binary.rs @@ -260,52 +260,45 @@ where (*function_index as u64).to_bytes(writer)?; } - Instruction::MemoryToString => 0x03_u8.to_bytes(writer)?, + Instruction::S8FromI32 => 0x02_u8.to_bytes(writer)?, + Instruction::S8FromI64 => 0x03_u8.to_bytes(writer)?, + Instruction::S16FromI32 => 0x04_u8.to_bytes(writer)?, + Instruction::S16FromI64 => 0x05_u8.to_bytes(writer)?, + Instruction::S32FromI32 => 0x06_u8.to_bytes(writer)?, + Instruction::S32FromI64 => 0x07_u8.to_bytes(writer)?, + Instruction::S64FromI32 => 0x08_u8.to_bytes(writer)?, + Instruction::S64FromI64 => 0x09_u8.to_bytes(writer)?, + Instruction::I32FromS8 => 0x0a_u8.to_bytes(writer)?, + Instruction::I32FromS16 => 0x0b_u8.to_bytes(writer)?, + Instruction::I32FromS32 => 0x0c_u8.to_bytes(writer)?, + Instruction::I32FromS64 => 0x0d_u8.to_bytes(writer)?, + Instruction::I64FromS8 => 0x0e_u8.to_bytes(writer)?, + Instruction::I64FromS16 => 0x0f_u8.to_bytes(writer)?, + Instruction::I64FromS32 => 0x10_u8.to_bytes(writer)?, + Instruction::I64FromS64 => 0x11_u8.to_bytes(writer)?, + Instruction::U8FromI32 => 0x12_u8.to_bytes(writer)?, + Instruction::U8FromI64 => 0x13_u8.to_bytes(writer)?, + Instruction::U16FromI32 => 0x14_u8.to_bytes(writer)?, + Instruction::U16FromI64 => 0x15_u8.to_bytes(writer)?, + Instruction::U32FromI32 => 0x16_u8.to_bytes(writer)?, + Instruction::U32FromI64 => 0x17_u8.to_bytes(writer)?, + Instruction::U64FromI32 => 0x18_u8.to_bytes(writer)?, + Instruction::U64FromI64 => 0x19_u8.to_bytes(writer)?, + Instruction::I32FromU8 => 0x1a_u8.to_bytes(writer)?, + Instruction::I32FromU16 => 0x1b_u8.to_bytes(writer)?, + Instruction::I32FromU32 => 0x1c_u8.to_bytes(writer)?, + Instruction::I32FromU64 => 0x1d_u8.to_bytes(writer)?, + Instruction::I64FromU8 => 0x1e_u8.to_bytes(writer)?, + Instruction::I64FromU16 => 0x1f_u8.to_bytes(writer)?, + Instruction::I64FromU32 => 0x20_u8.to_bytes(writer)?, + Instruction::I64FromU64 => 0x21_u8.to_bytes(writer)?, + + Instruction::MemoryToString => 0x22_u8.to_bytes(writer)?, Instruction::StringToMemory { allocator_index } => { - 0x04_u8.to_bytes(writer)?; + 0x23_u8.to_bytes(writer)?; (*allocator_index as u64).to_bytes(writer)?; } - - Instruction::I32ToS8 => 0x07_u8.to_bytes(writer)?, - Instruction::I32ToS8X => 0x08_u8.to_bytes(writer)?, - Instruction::I32ToU8 => 0x09_u8.to_bytes(writer)?, - Instruction::I32ToS16 => 0x0a_u8.to_bytes(writer)?, - Instruction::I32ToS16X => 0x0b_u8.to_bytes(writer)?, - Instruction::I32ToU16 => 0x0c_u8.to_bytes(writer)?, - Instruction::I32ToS32 => 0x0d_u8.to_bytes(writer)?, - Instruction::I32ToU32 => 0x0e_u8.to_bytes(writer)?, - Instruction::I32ToS64 => 0x0f_u8.to_bytes(writer)?, - Instruction::I32ToU64 => 0x10_u8.to_bytes(writer)?, - Instruction::I64ToS8 => 0x11_u8.to_bytes(writer)?, - Instruction::I64ToS8X => 0x12_u8.to_bytes(writer)?, - Instruction::I64ToU8 => 0x13_u8.to_bytes(writer)?, - Instruction::I64ToS16 => 0x14_u8.to_bytes(writer)?, - Instruction::I64ToS16X => 0x15_u8.to_bytes(writer)?, - Instruction::I64ToU16 => 0x16_u8.to_bytes(writer)?, - Instruction::I64ToS32 => 0x17_u8.to_bytes(writer)?, - Instruction::I64ToS32X => 0x18_u8.to_bytes(writer)?, - Instruction::I64ToU32 => 0x19_u8.to_bytes(writer)?, - Instruction::I64ToS64 => 0x1a_u8.to_bytes(writer)?, - Instruction::I64ToU64 => 0x1b_u8.to_bytes(writer)?, - Instruction::S8ToI32 => 0x1c_u8.to_bytes(writer)?, - Instruction::U8ToI32 => 0x1d_u8.to_bytes(writer)?, - Instruction::S16ToI32 => 0x1e_u8.to_bytes(writer)?, - Instruction::U16ToI32 => 0x1f_u8.to_bytes(writer)?, - Instruction::S32ToI32 => 0x20_u8.to_bytes(writer)?, - Instruction::U32ToI32 => 0x21_u8.to_bytes(writer)?, - Instruction::S64ToI32 => 0x22_u8.to_bytes(writer)?, - Instruction::S64ToI32X => 0x23_u8.to_bytes(writer)?, - Instruction::U64ToI32 => 0x24_u8.to_bytes(writer)?, - Instruction::U64ToI32X => 0x25_u8.to_bytes(writer)?, - Instruction::S8ToI64 => 0x26_u8.to_bytes(writer)?, - Instruction::U8ToI64 => 0x27_u8.to_bytes(writer)?, - Instruction::S16ToI64 => 0x28_u8.to_bytes(writer)?, - Instruction::U16ToI64 => 0x29_u8.to_bytes(writer)?, - Instruction::S32ToI64 => 0x2a_u8.to_bytes(writer)?, - Instruction::U32ToI64 => 0x2b_u8.to_bytes(writer)?, - Instruction::S64ToI64 => 0x2c_u8.to_bytes(writer)?, - Instruction::U64ToI64 => 0x2d_u8.to_bytes(writer)?, } Ok(()) @@ -550,93 +543,79 @@ mod tests { vec![ Instruction::ArgumentGet { index: 1 }, Instruction::CallCore { function_index: 1 }, + Instruction::S8FromI32, + Instruction::S8FromI64, + Instruction::S16FromI32, + Instruction::S16FromI64, + Instruction::S32FromI32, + Instruction::S32FromI64, + Instruction::S64FromI32, + Instruction::S64FromI64, + Instruction::I32FromS8, + Instruction::I32FromS16, + Instruction::I32FromS32, + Instruction::I32FromS64, + Instruction::I64FromS8, + Instruction::I64FromS16, + Instruction::I64FromS32, + Instruction::I64FromS64, + Instruction::U8FromI32, + Instruction::U8FromI64, + Instruction::U16FromI32, + Instruction::U16FromI64, + Instruction::U32FromI32, + Instruction::U32FromI64, + Instruction::U64FromI32, + Instruction::U64FromI64, + Instruction::I32FromU8, + Instruction::I32FromU16, + Instruction::I32FromU32, + Instruction::I32FromU64, + Instruction::I64FromU8, + Instruction::I64FromU16, + Instruction::I64FromU32, + Instruction::I64FromU64, Instruction::MemoryToString, Instruction::StringToMemory { allocator_index: 1 }, - Instruction::I32ToS8, - Instruction::I32ToS8X, - Instruction::I32ToU8, - Instruction::I32ToS16, - Instruction::I32ToS16X, - Instruction::I32ToU16, - Instruction::I32ToS32, - Instruction::I32ToU32, - Instruction::I32ToS64, - Instruction::I32ToU64, - Instruction::I64ToS8, - Instruction::I64ToS8X, - Instruction::I64ToU8, - Instruction::I64ToS16, - Instruction::I64ToS16X, - Instruction::I64ToU16, - Instruction::I64ToS32, - Instruction::I64ToS32X, - Instruction::I64ToU32, - Instruction::I64ToS64, - Instruction::I64ToU64, - Instruction::S8ToI32, - Instruction::U8ToI32, - Instruction::S16ToI32, - Instruction::U16ToI32, - Instruction::S32ToI32, - Instruction::U32ToI32, - Instruction::S64ToI32, - Instruction::S64ToI32X, - Instruction::U64ToI32, - Instruction::U64ToI32X, - Instruction::S8ToI64, - Instruction::U8ToI64, - Instruction::S16ToI64, - Instruction::U16ToI64, - Instruction::S32ToI64, - Instruction::U32ToI64, - Instruction::S64ToI64, - Instruction::U64ToI64, ], &[ - 0x2b, // list of 43 items + 0x24, // list of 36 items 0x00, 0x01, // ArgumentGet { index: 1 } 0x01, 0x01, // CallCore { function_index: 1 } - 0x03, // MemoryToString - 0x04, 0x01, // StringToMemory { allocator_index: 1 } - 0x07, // I32ToS8 - 0x08, // I32ToS8X - 0x09, // I32ToU8 - 0x0a, // I32ToS16 - 0x0b, // I32ToS16X - 0x0c, // I32ToU16 - 0x0d, // I32ToS32 - 0x0e, // I32ToU32 - 0x0f, // I32ToS64 - 0x10, // I32ToU64 - 0x11, // I64ToS8 - 0x12, // I64ToS8X - 0x13, // I64ToU8 - 0x14, // I64ToS16 - 0x15, // I64ToS16X - 0x16, // I64ToU16 - 0x17, // I64ToS32 - 0x18, // I64ToS32X - 0x19, // I64ToU32 - 0x1a, // I64ToS64 - 0x1b, // I64ToU64 - 0x1c, // S8ToI32 - 0x1d, // U8ToI32 - 0x1e, // S16ToI32 - 0x1f, // U16ToI32 - 0x20, // S32ToI32 - 0x21, // U32ToI32 - 0x22, // S64ToI32 - 0x23, // S64ToI32X - 0x24, // U64ToI32 - 0x25, // U64ToI32X - 0x26, // S8ToI64 - 0x27, // U8ToI64 - 0x28, // S16ToI64 - 0x29, // U16ToI64 - 0x2a, // S32ToI64 - 0x2b, // U32ToI64 - 0x2c, // S64ToI64 - 0x2d, // U64ToI64 + 0x02, // S8FromI32 + 0x03, // S8FromI64 + 0x04, // S16FromI32 + 0x05, // S16FromI64 + 0x06, // S32FromI32 + 0x07, // S32FromI64 + 0x08, // S64FromI32 + 0x09, // S64FromI64 + 0x0a, // I32FromS8 + 0x0b, // I32FromS16 + 0x0c, // I32FromS32 + 0x0d, // I32FromS64 + 0x0e, // I64FromS8 + 0x0f, // I64FromS16 + 0x10, // I64FromS32 + 0x11, // I64FromS64 + 0x12, // U8FromI32 + 0x13, // U8FromI64 + 0x14, // U16FromI32 + 0x15, // U16FromI64 + 0x16, // U32FromI32 + 0x17, // U32FromI64 + 0x18, // U64FromI32 + 0x19, // U64FromI64 + 0x1a, // I32FromU8 + 0x1b, // I32FromU16 + 0x1c, // I32FromU32 + 0x1d, // I32FromU64 + 0x1e, // I64FromU8 + 0x1f, // I64FromU16 + 0x20, // I64FromU32 + 0x21, // I64FromU64 + 0x22, // MemoryToString + 0x23, 0x01, // StringToMemory { allocator_index: 1 } ] ); } diff --git a/lib/interface-types/src/encoders/wat.rs b/lib/interface-types/src/encoders/wat.rs index 74a9d1a15..eb292013b 100644 --- a/lib/interface-types/src/encoders/wat.rs +++ b/lib/interface-types/src/encoders/wat.rs @@ -85,49 +85,42 @@ impl ToString for &Instruction { match self { Instruction::ArgumentGet { index } => format!("arg.get {}", index), Instruction::CallCore { function_index } => format!("call-core {}", function_index), + Instruction::S8FromI32 => "s8.from_i32".into(), + Instruction::S8FromI64 => "s8.from_i64".into(), + Instruction::S16FromI32 => "s16.from_i32".into(), + Instruction::S16FromI64 => "s16.from_i64".into(), + Instruction::S32FromI32 => "s32.from_i32".into(), + Instruction::S32FromI64 => "s32.from_i64".into(), + Instruction::S64FromI32 => "s64.from_i32".into(), + Instruction::S64FromI64 => "s64.from_i64".into(), + Instruction::I32FromS8 => "i32.from_s8".into(), + Instruction::I32FromS16 => "i32.from_s16".into(), + Instruction::I32FromS32 => "i32.from_s32".into(), + Instruction::I32FromS64 => "i32.from_s64".into(), + Instruction::I64FromS8 => "i64.from_s8".into(), + Instruction::I64FromS16 => "i64.from_s16".into(), + Instruction::I64FromS32 => "i64.from_s32".into(), + Instruction::I64FromS64 => "i64.from_s64".into(), + Instruction::U8FromI32 => "u8.from_i32".into(), + Instruction::U8FromI64 => "u8.from_i64".into(), + Instruction::U16FromI32 => "u16.from_i32".into(), + Instruction::U16FromI64 => "u16.from_i64".into(), + Instruction::U32FromI32 => "u32.from_i32".into(), + Instruction::U32FromI64 => "u32.from_i64".into(), + Instruction::U64FromI32 => "u64.from_i32".into(), + Instruction::U64FromI64 => "u64.from_i64".into(), + Instruction::I32FromU8 => "i32.from_u8".into(), + Instruction::I32FromU16 => "i32.from_u16".into(), + Instruction::I32FromU32 => "i32.from_u32".into(), + Instruction::I32FromU64 => "i32.from_u64".into(), + Instruction::I64FromU8 => "i64.from_u8".into(), + Instruction::I64FromU16 => "i64.from_u16".into(), + Instruction::I64FromU32 => "i64.from_u32".into(), + Instruction::I64FromU64 => "i64.from_u64".into(), Instruction::MemoryToString => "memory-to-string".into(), Instruction::StringToMemory { allocator_index } => { format!(r#"string-to-memory {}"#, allocator_index) } - Instruction::I32ToS8 => "i32-to-s8".into(), - Instruction::I32ToS8X => "i32-to-s8x".into(), - Instruction::I32ToU8 => "i32-to-u8".into(), - Instruction::I32ToS16 => "i32-to-s16".into(), - Instruction::I32ToS16X => "i32-to-s16x".into(), - Instruction::I32ToU16 => "i32-to-u16".into(), - Instruction::I32ToS32 => "i32-to-s32".into(), - Instruction::I32ToU32 => "i32-to-u32".into(), - Instruction::I32ToS64 => "i32-to-s64".into(), - Instruction::I32ToU64 => "i32-to-u64".into(), - Instruction::I64ToS8 => "i64-to-s8".into(), - Instruction::I64ToS8X => "i64-to-s8x".into(), - Instruction::I64ToU8 => "i64-to-u8".into(), - Instruction::I64ToS16 => "i64-to-s16".into(), - Instruction::I64ToS16X => "i64-to-s16x".into(), - Instruction::I64ToU16 => "i64-to-u16".into(), - Instruction::I64ToS32 => "i64-to-s32".into(), - Instruction::I64ToS32X => "i64-to-s32x".into(), - Instruction::I64ToU32 => "i64-to-u32".into(), - Instruction::I64ToS64 => "i64-to-s64".into(), - Instruction::I64ToU64 => "i64-to-u64".into(), - Instruction::S8ToI32 => "s8-to-i32".into(), - Instruction::U8ToI32 => "u8-to-i32".into(), - Instruction::S16ToI32 => "s16-to-i32".into(), - Instruction::U16ToI32 => "u16-to-i32".into(), - Instruction::S32ToI32 => "s32-to-i32".into(), - Instruction::U32ToI32 => "u32-to-i32".into(), - Instruction::S64ToI32 => "s64-to-i32".into(), - Instruction::S64ToI32X => "s64-to-i32x".into(), - Instruction::U64ToI32 => "u64-to-i32".into(), - Instruction::U64ToI32X => "u64-to-i32x".into(), - Instruction::S8ToI64 => "s8-to-i64".into(), - Instruction::U8ToI64 => "u8-to-i64".into(), - Instruction::S16ToI64 => "s16-to-i64".into(), - Instruction::U16ToI64 => "u16-to-i64".into(), - Instruction::S32ToI64 => "s32-to-i64".into(), - Instruction::U32ToI64 => "u32-to-i64".into(), - Instruction::S64ToI64 => "s64-to-i64".into(), - Instruction::U64ToI64 => "u64-to-i64".into(), } } } @@ -361,95 +354,81 @@ mod tests { let inputs: Vec = vec![ (&Instruction::ArgumentGet { index: 7 }).to_string(), (&Instruction::CallCore { function_index: 7 }).to_string(), + (&Instruction::S8FromI32).to_string(), + (&Instruction::S8FromI64).to_string(), + (&Instruction::S16FromI32).to_string(), + (&Instruction::S16FromI64).to_string(), + (&Instruction::S32FromI32).to_string(), + (&Instruction::S32FromI64).to_string(), + (&Instruction::S64FromI32).to_string(), + (&Instruction::S64FromI64).to_string(), + (&Instruction::I32FromS8).to_string(), + (&Instruction::I32FromS16).to_string(), + (&Instruction::I32FromS32).to_string(), + (&Instruction::I32FromS64).to_string(), + (&Instruction::I64FromS8).to_string(), + (&Instruction::I64FromS16).to_string(), + (&Instruction::I64FromS32).to_string(), + (&Instruction::I64FromS64).to_string(), + (&Instruction::U8FromI32).to_string(), + (&Instruction::U8FromI64).to_string(), + (&Instruction::U16FromI32).to_string(), + (&Instruction::U16FromI64).to_string(), + (&Instruction::U32FromI32).to_string(), + (&Instruction::U32FromI64).to_string(), + (&Instruction::U64FromI32).to_string(), + (&Instruction::U64FromI64).to_string(), + (&Instruction::I32FromU8).to_string(), + (&Instruction::I32FromU16).to_string(), + (&Instruction::I32FromU32).to_string(), + (&Instruction::I32FromU64).to_string(), + (&Instruction::I64FromU8).to_string(), + (&Instruction::I64FromU16).to_string(), + (&Instruction::I64FromU32).to_string(), + (&Instruction::I64FromU64).to_string(), (&Instruction::MemoryToString).to_string(), (&Instruction::StringToMemory { allocator_index: 42, }) .to_string(), - (&Instruction::I32ToS8).to_string(), - (&Instruction::I32ToS8X).to_string(), - (&Instruction::I32ToU8).to_string(), - (&Instruction::I32ToS16).to_string(), - (&Instruction::I32ToS16X).to_string(), - (&Instruction::I32ToU16).to_string(), - (&Instruction::I32ToS32).to_string(), - (&Instruction::I32ToU32).to_string(), - (&Instruction::I32ToS64).to_string(), - (&Instruction::I32ToU64).to_string(), - (&Instruction::I64ToS8).to_string(), - (&Instruction::I64ToS8X).to_string(), - (&Instruction::I64ToU8).to_string(), - (&Instruction::I64ToS16).to_string(), - (&Instruction::I64ToS16X).to_string(), - (&Instruction::I64ToU16).to_string(), - (&Instruction::I64ToS32).to_string(), - (&Instruction::I64ToS32X).to_string(), - (&Instruction::I64ToU32).to_string(), - (&Instruction::I64ToS64).to_string(), - (&Instruction::I64ToU64).to_string(), - (&Instruction::S8ToI32).to_string(), - (&Instruction::U8ToI32).to_string(), - (&Instruction::S16ToI32).to_string(), - (&Instruction::U16ToI32).to_string(), - (&Instruction::S32ToI32).to_string(), - (&Instruction::U32ToI32).to_string(), - (&Instruction::S64ToI32).to_string(), - (&Instruction::S64ToI32X).to_string(), - (&Instruction::U64ToI32).to_string(), - (&Instruction::U64ToI32X).to_string(), - (&Instruction::S8ToI64).to_string(), - (&Instruction::U8ToI64).to_string(), - (&Instruction::S16ToI64).to_string(), - (&Instruction::U16ToI64).to_string(), - (&Instruction::S32ToI64).to_string(), - (&Instruction::U32ToI64).to_string(), - (&Instruction::S64ToI64).to_string(), - (&Instruction::U64ToI64).to_string(), ]; let outputs = vec![ "arg.get 7", "call-core 7", + "s8.from_i32", + "s8.from_i64", + "s16.from_i32", + "s16.from_i64", + "s32.from_i32", + "s32.from_i64", + "s64.from_i32", + "s64.from_i64", + "i32.from_s8", + "i32.from_s16", + "i32.from_s32", + "i32.from_s64", + "i64.from_s8", + "i64.from_s16", + "i64.from_s32", + "i64.from_s64", + "u8.from_i32", + "u8.from_i64", + "u16.from_i32", + "u16.from_i64", + "u32.from_i32", + "u32.from_i64", + "u64.from_i32", + "u64.from_i64", + "i32.from_u8", + "i32.from_u16", + "i32.from_u32", + "i32.from_u64", + "i64.from_u8", + "i64.from_u16", + "i64.from_u32", + "i64.from_u64", "memory-to-string", "string-to-memory 42", - "i32-to-s8", - "i32-to-s8x", - "i32-to-u8", - "i32-to-s16", - "i32-to-s16x", - "i32-to-u16", - "i32-to-s32", - "i32-to-u32", - "i32-to-s64", - "i32-to-u64", - "i64-to-s8", - "i64-to-s8x", - "i64-to-u8", - "i64-to-s16", - "i64-to-s16x", - "i64-to-u16", - "i64-to-s32", - "i64-to-s32x", - "i64-to-u32", - "i64-to-s64", - "i64-to-u64", - "s8-to-i32", - "u8-to-i32", - "s16-to-i32", - "u16-to-i32", - "s32-to-i32", - "u32-to-i32", - "s64-to-i32", - "s64-to-i32x", - "u64-to-i32", - "u64-to-i32x", - "s8-to-i64", - "u8-to-i64", - "s16-to-i64", - "u16-to-i64", - "s32-to-i64", - "u32-to-i64", - "s64-to-i64", - "u64-to-i64", ]; assert_eq!(inputs, outputs); diff --git a/lib/interface-types/src/interpreter/instruction.rs b/lib/interface-types/src/interpreter/instruction.rs index 425cdad5c..89959f3a1 100644 --- a/lib/interface-types/src/interpreter/instruction.rs +++ b/lib/interface-types/src/interpreter/instruction.rs @@ -24,120 +24,99 @@ pub enum Instruction { allocator_index: u32, }, - /// The `i32-to-s8,` instruction. - I32ToS8, + /// The `s8.from_i32` instruction. + S8FromI32, - /// The `i32-to-s8x,` instruction. - I32ToS8X, + /// The `s8.from_i64` instruction. + S8FromI64, - /// The `i32-to-u8,` instruction. - I32ToU8, + /// The `s16.from_i32` instruction. + S16FromI32, - /// The `i32-to-s16,` instruction. - I32ToS16, + /// The `s16.from_i64` instruction. + S16FromI64, - /// The `i32-to-s16x,` instruction. - I32ToS16X, + /// The `s32.from_i32` instruction. + S32FromI32, - /// The `i32-to-u16,` instruction. - I32ToU16, + /// The `s32.from_i64` instruction. + S32FromI64, - /// The `i32-to-s32,` instruction. - I32ToS32, + /// The `s64.from_i32` instruction. + S64FromI32, - /// The `i32-to-u32,` instruction. - I32ToU32, + /// The `s64.from_i64` instruction. + S64FromI64, - /// The `i32-to-s64,` instruction. - I32ToS64, + /// The `i32.from_s8` instruction. + I32FromS8, - /// The `i32-to-u64,` instruction. - I32ToU64, + /// The `i32.from_s16` instruction. + I32FromS16, - /// The `i64-to-s8,` instruction. - I64ToS8, + /// The `i32.from_s32` instruction. + I32FromS32, - /// The `i64-to-s8x,` instruction. - I64ToS8X, + /// The `i32.from_s64` instruction. + I32FromS64, - /// The `i64-to-u8,` instruction. - I64ToU8, + /// The `i64.from_s8` instruction. + I64FromS8, - /// The `i64-to-s16,` instruction. - I64ToS16, + /// The `i64.from_s16` instruction. + I64FromS16, - /// The `i64-to-s16x,` instruction. - I64ToS16X, + /// The `i64.from_s32` instruction. + I64FromS32, - /// The `i64-to-u16,` instruction. - I64ToU16, + /// The `i64.from_s64` instruction. + I64FromS64, - /// The `i64-to-s32,` instruction. - I64ToS32, + /// The `u8.from_i32` instruction. + U8FromI32, - /// The `i64-to-s32x,` instruction. - I64ToS32X, + /// The `u8.from_i64` instruction. + U8FromI64, - /// The `i64-to-u32,` instruction. - I64ToU32, + /// The `u16.from_i32` instruction. + U16FromI32, - /// The `i64-to-s64,` instruction. - I64ToS64, + /// The `u16.from_i64` instruction. + U16FromI64, - /// The `i64-to-u64,` instruction. - I64ToU64, + /// The `u32.from_i32` instruction. + U32FromI32, - /// The `s8-to-i32,` instruction. - S8ToI32, + /// The `u32.from_i64` instruction. + U32FromI64, - /// The `u8-to-i32,` instruction. - U8ToI32, + /// The `u64.from_i32` instruction. + U64FromI32, - /// The `s16-to-i32,` instruction. - S16ToI32, + /// The `u64.from_i64` instruction. + U64FromI64, - /// The `u16-to-i32,` instruction. - U16ToI32, + /// The `i32.from_u8` instruction. + I32FromU8, - /// The `s32-to-i32,` instruction. - S32ToI32, + /// The `i32.from_u16` instruction. + I32FromU16, - /// The `u32-to-i32,` instruction. - U32ToI32, + /// The `i32.from_u32` instruction. + I32FromU32, - /// The `s64-to-i32,` instruction. - S64ToI32, + /// The `i32.from_u64` instruction. + I32FromU64, - /// The `s64-to-i32x,` instruction. - S64ToI32X, + /// The `i64.from_u8` instruction. + I64FromU8, - /// The `u64-to-i32,` instruction. - U64ToI32, + /// The `i64.from_u16` instruction. + I64FromU16, - /// The `u64-to-i32x,` instruction. - U64ToI32X, + /// The `i64.from_u32` instruction. + I64FromU32, - /// The `s8-to-i64,` instruction. - S8ToI64, - - /// The `u8-to-i64,` instruction. - U8ToI64, - - /// The `s16-to-i64,` instruction. - S16ToI64, - - /// The `u16-to-i64,` instruction. - U16ToI64, - - /// The `s32-to-i64,` instruction. - S32ToI64, - - /// The `u32-to-i64,` instruction. - U32ToI64, - - /// The `s64-to-i64,` instruction. - S64ToI64, - - /// The `u64-to-i64,` instruction. - U64ToI64, + /// The `i64.from_u64` instruction. + I64FromU64, } diff --git a/lib/interface-types/src/interpreter/instructions/lowering_lifting.rs b/lib/interface-types/src/interpreter/instructions/lowering_lifting.rs index d3903e660..ad2d38c2f 100644 --- a/lib/interface-types/src/interpreter/instructions/lowering_lifting.rs +++ b/lib/interface-types/src/interpreter/instructions/lowering_lifting.rs @@ -6,7 +6,7 @@ use crate::{ use std::convert::TryInto; macro_rules! lowering_lifting { - ($instruction_function_name:ident, $instruction_name:expr, $from_variant:ident, $to_variant:ident) => { + ($instruction_function_name:ident, $instruction_name:expr, $to_variant:ident, $from_variant:ident) => { executable_instruction!( $instruction_function_name(instruction: Instruction) -> _ { move |runtime| -> _ { @@ -52,316 +52,316 @@ macro_rules! lowering_lifting { }; } -lowering_lifting!(i32_to_s8, "i32-to-s8", I32, S8); -lowering_lifting!(i32_to_u8, "i32-to-u8", I32, U8); -lowering_lifting!(i32_to_s16, "i32-to-s16", I32, S16); -lowering_lifting!(i32_to_u16, "i32-to-u16", I32, U16); -lowering_lifting!(i32_to_s32, "i32-to-s32", I32, S32); -lowering_lifting!(i32_to_u32, "i32-to-u32", I32, U32); -lowering_lifting!(i32_to_s64, "i32-to-s64", I32, S64); -lowering_lifting!(i32_to_u64, "i32-to-u64", I32, U64); -lowering_lifting!(i64_to_s8, "i64-to-s8", I64, S8); -lowering_lifting!(i64_to_u8, "i64-to-u8", I64, U8); -lowering_lifting!(i64_to_s16, "i64-to-s16", I64, S16); -lowering_lifting!(i64_to_u16, "i64-to-u16", I64, U16); -lowering_lifting!(i64_to_s32, "i64-to-s32", I64, S32); -lowering_lifting!(i64_to_u32, "i64-to-u32", I64, U32); -lowering_lifting!(i64_to_s64, "i64-to-s64", I64, S64); -lowering_lifting!(i64_to_u64, "i64-to-u64", I64, U64); -lowering_lifting!(s8_to_i32, "s8-to-i32", S8, I32); -lowering_lifting!(u8_to_i32, "u8-to-i32", U8, I32); -lowering_lifting!(s16_to_i32, "s16-to-i32", S16, I32); -lowering_lifting!(u16_to_i32, "u16-to-i32", U16, I32); -lowering_lifting!(s32_to_i32, "s32-to-i32", S32, I32); -lowering_lifting!(u32_to_i32, "u32-to-i32", U32, I32); -lowering_lifting!(s64_to_i32, "s64-to-i32", S64, I32); -lowering_lifting!(u64_to_i32, "u64-to-i32", U64, I32); -lowering_lifting!(s8_to_i64, "s8-to-i64", S8, I64); -lowering_lifting!(u8_to_i64, "u8-to-i64", U8, I64); -lowering_lifting!(s16_to_i64, "s16-to-i64", S16, I64); -lowering_lifting!(u16_to_i64, "u16-to-i64", U16, I64); -lowering_lifting!(s32_to_i64, "s32-to-i64", S32, I64); -lowering_lifting!(u32_to_i64, "u32-to-i64", U32, I64); -lowering_lifting!(s64_to_i64, "s64-to-i64", S64, I64); -lowering_lifting!(u64_to_i64, "u64-to-i64", U64, I64); +lowering_lifting!(s8_from_i32, "s8.from_i32", S8, I32); +lowering_lifting!(s8_from_i64, "s8.from_i64", S8, I64); +lowering_lifting!(s16_from_i32, "s16.from_i32", S16, I32); +lowering_lifting!(s16_from_i64, "s16.from_i64", S16, I64); +lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32); +lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64); +lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32); +lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64); +lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8); +lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16); +lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32); +lowering_lifting!(i32_from_s64, "i32.from_s64", I32, S64); +lowering_lifting!(i64_from_s8, "i64.from_s8", I64, S8); +lowering_lifting!(i64_from_s16, "i64.from_s16", I64, S16); +lowering_lifting!(i64_from_s32, "i64.from_s32", I64, S32); +lowering_lifting!(i64_from_s64, "i64.from_s64", I64, S64); +lowering_lifting!(u8_from_i32, "u8.from_i32", U8, I32); +lowering_lifting!(u8_from_i64, "u8.from_i64", U8, I64); +lowering_lifting!(u16_from_i32, "u16.from_i32", U16, I32); +lowering_lifting!(u16_from_i64, "u16.from_i64", U16, I64); +lowering_lifting!(u32_from_i32, "u32.from_i32", U32, I32); +lowering_lifting!(u32_from_i64, "u32.from_i64", U32, I64); +lowering_lifting!(u64_from_i32, "u64.from_i32", U64, I32); +lowering_lifting!(u64_from_i64, "u64.from_i64", U64, I64); +lowering_lifting!(i32_from_u8, "i32.from_u8", I32, U8); +lowering_lifting!(i32_from_u16, "i32.from_u16", I32, U16); +lowering_lifting!(i32_from_u32, "i32.from_u32", I32, U32); +lowering_lifting!(i32_from_u64, "i32.from_u64", I32, U64); +lowering_lifting!(i64_from_u8, "i64.from_u8", I64, U8); +lowering_lifting!(i64_from_u16, "i64.from_u16", I64, U16); +lowering_lifting!(i64_from_u32, "i64.from_u32", I64, U32); +lowering_lifting!(i64_from_u64, "i64.from_u64", I64, U64); #[cfg(test)] mod tests { - test_executable_instruction!( - test_i32_to_s8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS8], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S8(42)], - ); - test_executable_instruction!( test_convert_fails = - instructions: [Instruction::ArgumentGet { index: 0}, Instruction::I32ToS8], + instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32], invocation_inputs: [InterfaceValue::I32(128)], instance: Instance::new(), - error: "`i32-to-s8` failed to cast `I32` to `S8`" + error: "`s8.from_i32` failed to cast `I32` to `S8`" ); test_executable_instruction!( test_type_mismatch = - instructions: [Instruction::ArgumentGet { index: 0}, Instruction::I32ToS8], + instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32], invocation_inputs: [InterfaceValue::I64(42)], instance: Instance::new(), - error: "`i32-to-s8` read a value of type `I64` from the stack, but the type `I32` was expected" + error: "`s8.from_i32` read a value of type `I64` from the stack, but the type `I32` was expected" ); test_executable_instruction!( test_no_value_on_the_stack = - instructions: [Instruction::I32ToS8], + instructions: [Instruction::S8FromI32], invocation_inputs: [InterfaceValue::I32(42)], instance: Instance::new(), - error: "`i32-to-s8` needed to read `1` value(s) from the stack, but it doesn't contain enough data" + error: "`s8.from_i32` needed to read `1` value(s) from the stack, but it doesn't contain enough data" ); test_executable_instruction!( - test_i32_to_u8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU8], + test_s8_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI32], invocation_inputs: [InterfaceValue::I32(42)], instance: Instance::new(), - stack: [InterfaceValue::U8(42)], + stack: [InterfaceValue::S8(42)], ); test_executable_instruction!( - test_i32_to_s16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS16], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S16(42)], - ); - - test_executable_instruction!( - test_i32_to_u16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU16], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U16(42)], - ); - - test_executable_instruction!( - test_i32_to_s32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S32(42)], - ); - - test_executable_instruction!( - test_i32_to_u32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U32(42)], - ); - - test_executable_instruction!( - test_i32_to_s64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS64], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S64(42)], - ); - - test_executable_instruction!( - test_i32_to_u64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU64], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U64(42)], - ); - - test_executable_instruction!( - test_i64_to_s8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS8], + test_s8_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI64], invocation_inputs: [InterfaceValue::I64(42)], instance: Instance::new(), stack: [InterfaceValue::S8(42)], ); test_executable_instruction!( - test_i64_to_u8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU8], - invocation_inputs: [InterfaceValue::I64(42)], + test_s16_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI32], + invocation_inputs: [InterfaceValue::I32(42)], instance: Instance::new(), - stack: [InterfaceValue::U8(42)], + stack: [InterfaceValue::S16(42)], ); test_executable_instruction!( - test_i64_to_s16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS16], + test_s16_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI64], invocation_inputs: [InterfaceValue::I64(42)], instance: Instance::new(), stack: [InterfaceValue::S16(42)], ); test_executable_instruction!( - test_i64_to_u16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU16], - invocation_inputs: [InterfaceValue::I64(42)], + test_s32_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI32], + invocation_inputs: [InterfaceValue::I32(42)], instance: Instance::new(), - stack: [InterfaceValue::U16(42)], + stack: [InterfaceValue::S32(42)], ); test_executable_instruction!( - test_i64_to_s32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS32], + test_s32_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI64], invocation_inputs: [InterfaceValue::I64(42)], instance: Instance::new(), stack: [InterfaceValue::S32(42)], ); test_executable_instruction!( - test_i64_to_u32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU32], - invocation_inputs: [InterfaceValue::I64(42)], + test_s64_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI32], + invocation_inputs: [InterfaceValue::I32(42)], instance: Instance::new(), - stack: [InterfaceValue::U32(42)], + stack: [InterfaceValue::S64(42)], ); test_executable_instruction!( - test_i64_to_s64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS64], + test_s64_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI64], invocation_inputs: [InterfaceValue::I64(42)], instance: Instance::new(), stack: [InterfaceValue::S64(42)], ); test_executable_instruction!( - test_i64_to_u64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::U64(42)], - ); - - test_executable_instruction!( - test_s8_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8ToI32], + test_i32_from_s8 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS8], invocation_inputs: [InterfaceValue::S8(42)], instance: Instance::new(), stack: [InterfaceValue::I32(42)], ); test_executable_instruction!( - test_u8_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8ToI32], - invocation_inputs: [InterfaceValue::U8(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_s16_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16ToI32], + test_i32_from_s16 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS16], invocation_inputs: [InterfaceValue::S16(42)], instance: Instance::new(), stack: [InterfaceValue::I32(42)], ); test_executable_instruction!( - test_u16_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16ToI32], - invocation_inputs: [InterfaceValue::U16(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_s32_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32ToI32], + test_i32_from_s32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS32], invocation_inputs: [InterfaceValue::S32(42)], instance: Instance::new(), stack: [InterfaceValue::I32(42)], ); test_executable_instruction!( - test_u32_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32ToI32], - invocation_inputs: [InterfaceValue::U32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_s64_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64ToI32], + test_i32_from_s64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS64], invocation_inputs: [InterfaceValue::S64(42)], instance: Instance::new(), stack: [InterfaceValue::I32(42)], ); test_executable_instruction!( - test_u64_to_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64ToI32], + test_i64_from_s8 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS8], + invocation_inputs: [InterfaceValue::S8(42)], + instance: Instance::new(), + stack: [InterfaceValue::I64(42)], + ); + + test_executable_instruction!( + test_i64_from_s16 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS16], + invocation_inputs: [InterfaceValue::S16(42)], + instance: Instance::new(), + stack: [InterfaceValue::I64(42)], + ); + + test_executable_instruction!( + test_i64_from_s32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS32], + invocation_inputs: [InterfaceValue::S32(42)], + instance: Instance::new(), + stack: [InterfaceValue::I64(42)], + ); + + test_executable_instruction!( + test_i64_from_s64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS64], + invocation_inputs: [InterfaceValue::S64(42)], + instance: Instance::new(), + stack: [InterfaceValue::I64(42)], + ); + + test_executable_instruction!( + test_u8_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI32], + invocation_inputs: [InterfaceValue::I32(42)], + instance: Instance::new(), + stack: [InterfaceValue::U8(42)], + ); + + test_executable_instruction!( + test_u8_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI64], + invocation_inputs: [InterfaceValue::I64(42)], + instance: Instance::new(), + stack: [InterfaceValue::U8(42)], + ); + + test_executable_instruction!( + test_u16_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI32], + invocation_inputs: [InterfaceValue::I32(42)], + instance: Instance::new(), + stack: [InterfaceValue::U16(42)], + ); + + test_executable_instruction!( + test_u16_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI64], + invocation_inputs: [InterfaceValue::I64(42)], + instance: Instance::new(), + stack: [InterfaceValue::U16(42)], + ); + + test_executable_instruction!( + test_u32_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI32], + invocation_inputs: [InterfaceValue::I32(42)], + instance: Instance::new(), + stack: [InterfaceValue::U32(42)], + ); + + test_executable_instruction!( + test_u32_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI64], + invocation_inputs: [InterfaceValue::I64(42)], + instance: Instance::new(), + stack: [InterfaceValue::U32(42)], + ); + + test_executable_instruction!( + test_u64_from_i32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI32], + invocation_inputs: [InterfaceValue::I32(42)], + instance: Instance::new(), + stack: [InterfaceValue::U64(42)], + ); + + test_executable_instruction!( + test_u64_from_i64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI64], + invocation_inputs: [InterfaceValue::I64(42)], + instance: Instance::new(), + stack: [InterfaceValue::U64(42)], + ); + + test_executable_instruction!( + test_i32_from_u8 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU8], + invocation_inputs: [InterfaceValue::U8(42)], + instance: Instance::new(), + stack: [InterfaceValue::I32(42)], + ); + + test_executable_instruction!( + test_i32_from_u16 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU16], + invocation_inputs: [InterfaceValue::U16(42)], + instance: Instance::new(), + stack: [InterfaceValue::I32(42)], + ); + + test_executable_instruction!( + test_i32_from_u32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU32], + invocation_inputs: [InterfaceValue::U32(42)], + instance: Instance::new(), + stack: [InterfaceValue::I32(42)], + ); + + test_executable_instruction!( + test_i32_from_u64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU64], invocation_inputs: [InterfaceValue::U64(42)], instance: Instance::new(), stack: [InterfaceValue::I32(42)], ); test_executable_instruction!( - test_s8_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8ToI64], - invocation_inputs: [InterfaceValue::S8(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_u8_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8ToI64], + test_i64_from_u8 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU8], invocation_inputs: [InterfaceValue::U8(42)], instance: Instance::new(), stack: [InterfaceValue::I64(42)], ); test_executable_instruction!( - test_s16_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16ToI64], - invocation_inputs: [InterfaceValue::S16(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_u16_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16ToI64], + test_i64_from_u16 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU16], invocation_inputs: [InterfaceValue::U16(42)], instance: Instance::new(), stack: [InterfaceValue::I64(42)], ); test_executable_instruction!( - test_s32_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32ToI64], - invocation_inputs: [InterfaceValue::S32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_u32_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32ToI64], + test_i64_from_u32 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU32], invocation_inputs: [InterfaceValue::U32(42)], instance: Instance::new(), stack: [InterfaceValue::I64(42)], ); test_executable_instruction!( - test_s64_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64ToI64], - invocation_inputs: [InterfaceValue::S64(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_u64_to_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64ToI64], + test_i64_from_u64 = + instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU64], invocation_inputs: [InterfaceValue::U64(42)], instance: Instance::new(), stack: [InterfaceValue::I64(42)], diff --git a/lib/interface-types/src/interpreter/mod.rs b/lib/interface-types/src/interpreter/mod.rs index d5f01056b..f2a9c4427 100644 --- a/lib/interface-types/src/interpreter/mod.rs +++ b/lib/interface-types/src/interpreter/mod.rs @@ -188,60 +188,51 @@ where fn try_from(instructions: &Vec) -> Result { let executable_instructions = instructions .iter() - .map(|instruction| { - match instruction { - Instruction::ArgumentGet { index } => { - instructions::argument_get(*index, *instruction) - } - Instruction::CallCore { function_index } => { - instructions::call_core(*function_index, *instruction) - } - Instruction::MemoryToString => instructions::memory_to_string(*instruction), - Instruction::StringToMemory { allocator_index } => { - instructions::string_to_memory(*allocator_index, *instruction) - } + .map(|instruction| match instruction { + Instruction::ArgumentGet { index } => { + instructions::argument_get(*index, *instruction) + } - Instruction::I32ToS8 => instructions::i32_to_s8(*instruction), - //Instruction::I32ToS8X - Instruction::I32ToU8 => instructions::i32_to_u8(*instruction), - Instruction::I32ToS16 => instructions::i32_to_s16(*instruction), - //Instruction::I32ToS16X - Instruction::I32ToU16 => instructions::i32_to_u16(*instruction), - Instruction::I32ToS32 => instructions::i32_to_s32(*instruction), - Instruction::I32ToU32 => instructions::i32_to_u32(*instruction), - Instruction::I32ToS64 => instructions::i32_to_s64(*instruction), - Instruction::I32ToU64 => instructions::i32_to_u64(*instruction), - Instruction::I64ToS8 => instructions::i64_to_s8(*instruction), - //Instruction::I64ToS8X - Instruction::I64ToU8 => instructions::i64_to_u8(*instruction), - Instruction::I64ToS16 => instructions::i64_to_s16(*instruction), - //Instruction::I64ToS16X - Instruction::I64ToU16 => instructions::i64_to_u16(*instruction), - Instruction::I64ToS32 => instructions::i64_to_s32(*instruction), - Instruction::I64ToU32 => instructions::i64_to_u32(*instruction), - Instruction::I64ToS64 => instructions::i64_to_s64(*instruction), - Instruction::I64ToU64 => instructions::i64_to_u64(*instruction), - Instruction::S8ToI32 => instructions::s8_to_i32(*instruction), - Instruction::U8ToI32 => instructions::u8_to_i32(*instruction), - Instruction::S16ToI32 => instructions::s16_to_i32(*instruction), - Instruction::U16ToI32 => instructions::u16_to_i32(*instruction), - Instruction::S32ToI32 => instructions::s32_to_i32(*instruction), - Instruction::U32ToI32 => instructions::u32_to_i32(*instruction), - Instruction::S64ToI32 | Instruction::S64ToI32X => { - instructions::s64_to_i32(*instruction) - } - Instruction::U64ToI32 | Instruction::U64ToI32X => { - instructions::u64_to_i32(*instruction) - } - Instruction::S8ToI64 => instructions::s8_to_i64(*instruction), - Instruction::U8ToI64 => instructions::u8_to_i64(*instruction), - Instruction::S16ToI64 => instructions::s16_to_i64(*instruction), - Instruction::U16ToI64 => instructions::u16_to_i64(*instruction), - Instruction::S32ToI64 => instructions::s32_to_i64(*instruction), - Instruction::U32ToI64 => instructions::u32_to_i64(*instruction), - Instruction::S64ToI64 => instructions::s64_to_i64(*instruction), - Instruction::U64ToI64 => instructions::u64_to_i64(*instruction), - _ => unimplemented!(), + Instruction::CallCore { function_index } => { + instructions::call_core(*function_index, *instruction) + } + + Instruction::S8FromI32 => instructions::s8_from_i32(*instruction), + Instruction::S8FromI64 => instructions::s8_from_i64(*instruction), + Instruction::S16FromI32 => instructions::s16_from_i32(*instruction), + Instruction::S16FromI64 => instructions::s16_from_i64(*instruction), + Instruction::S32FromI32 => instructions::s32_from_i32(*instruction), + Instruction::S32FromI64 => instructions::s32_from_i64(*instruction), + Instruction::S64FromI32 => instructions::s64_from_i32(*instruction), + Instruction::S64FromI64 => instructions::s64_from_i64(*instruction), + Instruction::I32FromS8 => instructions::i32_from_s8(*instruction), + Instruction::I32FromS16 => instructions::i32_from_s16(*instruction), + Instruction::I32FromS32 => instructions::i32_from_s32(*instruction), + Instruction::I32FromS64 => instructions::i32_from_s64(*instruction), + Instruction::I64FromS8 => instructions::i64_from_s8(*instruction), + Instruction::I64FromS16 => instructions::i64_from_s16(*instruction), + Instruction::I64FromS32 => instructions::i64_from_s32(*instruction), + Instruction::I64FromS64 => instructions::i64_from_s64(*instruction), + Instruction::U8FromI32 => instructions::u8_from_i32(*instruction), + Instruction::U8FromI64 => instructions::u8_from_i64(*instruction), + Instruction::U16FromI32 => instructions::u16_from_i32(*instruction), + Instruction::U16FromI64 => instructions::u16_from_i64(*instruction), + Instruction::U32FromI32 => instructions::u32_from_i32(*instruction), + Instruction::U32FromI64 => instructions::u32_from_i64(*instruction), + Instruction::U64FromI32 => instructions::u64_from_i32(*instruction), + Instruction::U64FromI64 => instructions::u64_from_i64(*instruction), + Instruction::I32FromU8 => instructions::i32_from_u8(*instruction), + Instruction::I32FromU16 => instructions::i32_from_u16(*instruction), + Instruction::I32FromU32 => instructions::i32_from_u32(*instruction), + Instruction::I32FromU64 => instructions::i32_from_u64(*instruction), + Instruction::I64FromU8 => instructions::i64_from_u8(*instruction), + Instruction::I64FromU16 => instructions::i64_from_u16(*instruction), + Instruction::I64FromU32 => instructions::i64_from_u32(*instruction), + Instruction::I64FromU64 => instructions::i64_from_u64(*instruction), + + Instruction::MemoryToString => instructions::memory_to_string(*instruction), + Instruction::StringToMemory { allocator_index } => { + instructions::string_to_memory(*allocator_index, *instruction) } }) .collect(); From cd58af26335702f25b1096b226ab06d526b555c6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 12:47:39 +0100 Subject: [PATCH 04/15] doc(interface-types) Update supported instructions. --- lib/interface-types/README.md | 71 ++++++++++++++++------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/lib/interface-types/README.md b/lib/interface-types/README.md index 3e7ccdf76..66e812b57 100644 --- a/lib/interface-types/README.md +++ b/lib/interface-types/README.md @@ -52,46 +52,39 @@ Here is the instructions that are implemented: |-|-|-|-|-|-| | `arg.get` | ✅ | ✅ | ✅ | ✅ | ✅ | | `call-core` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s8.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s8.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s16.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s16.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s32.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s32.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s64.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `s64.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_s8` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_s16` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_s32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_s64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_s8` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_s16` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_s32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_s64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u8.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u8.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u16.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u16.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u32.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u32.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u64.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `u64.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_u8` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_u16` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_u32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i32.from_u64` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_u8` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_u16` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_u32` | ✅ | ✅ | ✅ | ✅ | ✅ | +| `i64.from_u64` | ✅ | ✅ | ✅ | ✅ | ✅ | | `memory-to-string` | ✅ | ✅ | ✅ | ✅ | ✅ | | `string-to-memory` | ✅ | ✅ | ✅ | ✅ | ✅ | | `call-adapter` | ❌ | ❌ | ❌ | ❌ | ❌ | | `defer-call-core` | ❌ | ❌ | ❌ | ❌ | ❌ | -| `i32-to-s8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-s8x` | ✅ | ✅ | ✅ | ✅ | ❌ | -| `i32-to-u8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-s16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-s16x` | ✅ | ✅ | ✅ | ✅ | ❌ | -| `i32-to-u16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-s32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-u32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-s64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32-to-u64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s8x` | ✅ | ✅ | ✅ | ✅ | ❌ | -| `i64-to-u8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s16x` | ✅ | ✅ | ✅ | ✅ | ❌ | -| `i64-to-u16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s32x` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-u32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-s64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64-to-u64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s8-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u8-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s16-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u16-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s32-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u32-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s64-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s64-to-i32x` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u64-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u64-to-i32x` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s8-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u8-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s16-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u16-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s32-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u32-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s64-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u64-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ | From 6fcd45bce329dcd0c08c12bc04eabd0bb81cd515 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 12:48:33 +0100 Subject: [PATCH 05/15] doc(interface-types) Add links to WIT instructions. --- lib/interface-types/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/interface-types/README.md b/lib/interface-types/README.md index 66e812b57..e6a303099 100644 --- a/lib/interface-types/README.md +++ b/lib/interface-types/README.md @@ -41,12 +41,13 @@ binary. ## Instructions -Very basically, WebAssembly Interface Types defines a set of -instructions, used by adapters to transform the data between -WebAssembly core and the outside world ([learn +Very basically, WebAssembly Interface Types defines a [set of +instructions](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/working-notes/Instructions.md), +used by adapters to transform the data between WebAssembly core and +the outside world ([learn mode](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)). -Here is the instructions that are implemented: +Here is the instructions that are implemented by this crate: | Instruction | WAT encoder | Binary encoder | WAT decoder | Binary decoder | Interpreter | |-|-|-|-|-|-| From afbeb5d2303c977c14455d37d2ec98e13f7e18a0 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 13:10:21 +0100 Subject: [PATCH 06/15] feat(interface-types) Rename `lowering_lifting` module to `numbers`. --- lib/interface-types/src/interpreter/instructions/mod.rs | 4 ++-- .../instructions/{lowering_lifting.rs => numbers.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename lib/interface-types/src/interpreter/instructions/{lowering_lifting.rs => numbers.rs} (100%) diff --git a/lib/interface-types/src/interpreter/instructions/mod.rs b/lib/interface-types/src/interpreter/instructions/mod.rs index 4400cf002..34a5dbdae 100644 --- a/lib/interface-types/src/interpreter/instructions/mod.rs +++ b/lib/interface-types/src/interpreter/instructions/mod.rs @@ -1,7 +1,7 @@ mod argument_get; mod call_core; -mod lowering_lifting; mod memory_to_string; +mod numbers; mod string_to_memory; use crate::{ @@ -13,8 +13,8 @@ use crate::{ }; pub(crate) use argument_get::argument_get; pub(crate) use call_core::call_core; -pub(crate) use lowering_lifting::*; pub(crate) use memory_to_string::memory_to_string; +pub(crate) use numbers::*; use std::convert::TryFrom; pub(crate) use string_to_memory::string_to_memory; diff --git a/lib/interface-types/src/interpreter/instructions/lowering_lifting.rs b/lib/interface-types/src/interpreter/instructions/numbers.rs similarity index 100% rename from lib/interface-types/src/interpreter/instructions/lowering_lifting.rs rename to lib/interface-types/src/interpreter/instructions/numbers.rs From ec7aebe7e15ca42943899f292870e4ca8ca2ea39 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 13:25:06 +0100 Subject: [PATCH 07/15] feat(interface-types) Implement the `string.(lift|lower)_memory` instructions. The `string.lift_memory` instruction replaces `memory-to-string`, and `string.lower_memory` replaces `string-to-memory`. --- lib/interface-types/src/decoders/binary.rs | 12 +- lib/interface-types/src/decoders/wat.rs | 24 +- lib/interface-types/src/encoders/binary.rs | 12 +- lib/interface-types/src/encoders/wat.rs | 14 +- .../src/interpreter/instruction.rs | 18 +- .../instructions/memory_to_string.rs | 159 --------- .../src/interpreter/instructions/mod.rs | 6 +- .../instructions/string_to_memory.rs | 175 ---------- .../src/interpreter/instructions/strings.rs | 326 ++++++++++++++++++ lib/interface-types/src/interpreter/mod.rs | 6 +- 10 files changed, 371 insertions(+), 381 deletions(-) delete mode 100644 lib/interface-types/src/interpreter/instructions/memory_to_string.rs delete mode 100644 lib/interface-types/src/interpreter/instructions/string_to_memory.rs create mode 100644 lib/interface-types/src/interpreter/instructions/strings.rs diff --git a/lib/interface-types/src/decoders/binary.rs b/lib/interface-types/src/decoders/binary.rs index 367551d60..2661d6f84 100644 --- a/lib/interface-types/src/decoders/binary.rs +++ b/lib/interface-types/src/decoders/binary.rs @@ -207,13 +207,13 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( 0x20 => (input, Instruction::I64FromU32), 0x21 => (input, Instruction::I64FromU64), - 0x22 => (input, Instruction::MemoryToString), + 0x22 => (input, Instruction::StringLiftMemory), 0x23 => { consume!((input, argument_0) = uleb(input)?); ( input, - Instruction::StringToMemory { + Instruction::StringLowerMemory { allocator_index: argument_0 as u32, }, ) @@ -655,8 +655,8 @@ mod tests { 0x1f, // I64FromU16 0x20, // I64FromU32 0x21, // I64FromU64 - 0x22, // MemoryToString - 0x23, 0x01, // StringToMemory { allocator_index: 1 } + 0x22, // StringLiftMemory + 0x23, 0x01, // StringLowerMemory { allocator_index: 1 } 0x0a, ]; let output = Ok(( @@ -696,8 +696,8 @@ mod tests { Instruction::I64FromU16, Instruction::I64FromU32, Instruction::I64FromU64, - Instruction::MemoryToString, - Instruction::StringToMemory { allocator_index: 1 }, + Instruction::StringLiftMemory, + Instruction::StringLowerMemory { allocator_index: 1 }, ], )); diff --git a/lib/interface-types/src/decoders/wat.rs b/lib/interface-types/src/decoders/wat.rs index 656673b47..a3469ea55 100644 --- a/lib/interface-types/src/decoders/wat.rs +++ b/lib/interface-types/src/decoders/wat.rs @@ -60,8 +60,8 @@ mod keyword { custom_keyword!(i64_from_u16 = "i64.from_u16"); custom_keyword!(i64_from_u32 = "i64.from_u32"); custom_keyword!(i64_from_u64 = "i64.from_u64"); - custom_keyword!(memory_to_string = "memory-to-string"); - custom_keyword!(string_to_memory = "string-to-memory"); + custom_keyword!(string_lift_memory = "string.lift_memory"); + custom_keyword!(string_lower_memory = "string.lower_memory"); } impl Parse<'_> for InterfaceType { @@ -275,14 +275,14 @@ impl<'a> Parse<'a> for Instruction { parser.parse::()?; Ok(Instruction::I64FromU64) - } else if lookahead.peek::() { - parser.parse::()?; + } else if lookahead.peek::() { + parser.parse::()?; - Ok(Instruction::MemoryToString) - } else if lookahead.peek::() { - parser.parse::()?; + Ok(Instruction::StringLiftMemory) + } else if lookahead.peek::() { + parser.parse::()?; - Ok(Instruction::StringToMemory { + Ok(Instruction::StringLowerMemory { allocator_index: parser.parse()?, }) } else { @@ -664,8 +664,8 @@ mod tests { "i64.from_u16", "i64.from_u32", "i64.from_u64", - "memory-to-string", - "string-to-memory 42", + "string.lift_memory", + "string.lower_memory 42", ]; let outputs = vec![ Instruction::ArgumentGet { index: 7 }, @@ -702,8 +702,8 @@ mod tests { Instruction::I64FromU16, Instruction::I64FromU32, Instruction::I64FromU64, - Instruction::MemoryToString, - Instruction::StringToMemory { + Instruction::StringLiftMemory, + Instruction::StringLowerMemory { allocator_index: 42, }, ]; diff --git a/lib/interface-types/src/encoders/binary.rs b/lib/interface-types/src/encoders/binary.rs index 9a89e3e8c..aece560e3 100644 --- a/lib/interface-types/src/encoders/binary.rs +++ b/lib/interface-types/src/encoders/binary.rs @@ -293,9 +293,9 @@ where Instruction::I64FromU32 => 0x20_u8.to_bytes(writer)?, Instruction::I64FromU64 => 0x21_u8.to_bytes(writer)?, - Instruction::MemoryToString => 0x22_u8.to_bytes(writer)?, + Instruction::StringLiftMemory => 0x22_u8.to_bytes(writer)?, - Instruction::StringToMemory { allocator_index } => { + Instruction::StringLowerMemory { allocator_index } => { 0x23_u8.to_bytes(writer)?; (*allocator_index as u64).to_bytes(writer)?; } @@ -575,8 +575,8 @@ mod tests { Instruction::I64FromU16, Instruction::I64FromU32, Instruction::I64FromU64, - Instruction::MemoryToString, - Instruction::StringToMemory { allocator_index: 1 }, + Instruction::StringLiftMemory, + Instruction::StringLowerMemory { allocator_index: 1 }, ], &[ 0x24, // list of 36 items @@ -614,8 +614,8 @@ mod tests { 0x1f, // I64FromU16 0x20, // I64FromU32 0x21, // I64FromU64 - 0x22, // MemoryToString - 0x23, 0x01, // StringToMemory { allocator_index: 1 } + 0x22, // StringLiftMemory + 0x23, 0x01, // StringLowerMemory { allocator_index: 1 } ] ); } diff --git a/lib/interface-types/src/encoders/wat.rs b/lib/interface-types/src/encoders/wat.rs index eb292013b..49142257d 100644 --- a/lib/interface-types/src/encoders/wat.rs +++ b/lib/interface-types/src/encoders/wat.rs @@ -117,9 +117,9 @@ impl ToString for &Instruction { Instruction::I64FromU16 => "i64.from_u16".into(), Instruction::I64FromU32 => "i64.from_u32".into(), Instruction::I64FromU64 => "i64.from_u64".into(), - Instruction::MemoryToString => "memory-to-string".into(), - Instruction::StringToMemory { allocator_index } => { - format!(r#"string-to-memory {}"#, allocator_index) + Instruction::StringLiftMemory => "string.lift_memory".into(), + Instruction::StringLowerMemory { allocator_index } => { + format!(r#"string.lower_memory {}"#, allocator_index) } } } @@ -386,8 +386,8 @@ mod tests { (&Instruction::I64FromU16).to_string(), (&Instruction::I64FromU32).to_string(), (&Instruction::I64FromU64).to_string(), - (&Instruction::MemoryToString).to_string(), - (&Instruction::StringToMemory { + (&Instruction::StringLiftMemory).to_string(), + (&Instruction::StringLowerMemory { allocator_index: 42, }) .to_string(), @@ -427,8 +427,8 @@ mod tests { "i64.from_u16", "i64.from_u32", "i64.from_u64", - "memory-to-string", - "string-to-memory 42", + "string.lift_memory", + "string.lower_memory 42", ]; assert_eq!(inputs, outputs); diff --git a/lib/interface-types/src/interpreter/instruction.rs b/lib/interface-types/src/interpreter/instruction.rs index 89959f3a1..0ef4c945e 100644 --- a/lib/interface-types/src/interpreter/instruction.rs +++ b/lib/interface-types/src/interpreter/instruction.rs @@ -15,15 +15,6 @@ pub enum Instruction { function_index: usize, }, - /// The `memory-to-string` instruction. - MemoryToString, - - /// The `string-to-memory` instruction. - StringToMemory { - /// The allocator function index. - allocator_index: u32, - }, - /// The `s8.from_i32` instruction. S8FromI32, @@ -119,4 +110,13 @@ pub enum Instruction { /// The `i64.from_u64` instruction. I64FromU64, + + /// The `string.lift_memory` instruction. + StringLiftMemory, + + /// The `string.lower_memory` instruction. + StringLowerMemory { + /// The allocator function index. + allocator_index: u32, + }, } diff --git a/lib/interface-types/src/interpreter/instructions/memory_to_string.rs b/lib/interface-types/src/interpreter/instructions/memory_to_string.rs deleted file mode 100644 index 8e9902ca1..000000000 --- a/lib/interface-types/src/interpreter/instructions/memory_to_string.rs +++ /dev/null @@ -1,159 +0,0 @@ -use super::to_native; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::{wasm::values::InterfaceValue, Instruction}, -}; -use std::cell::Cell; - -executable_instruction!( - memory_to_string(instruction: Instruction) -> _ { - move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 2 }, - ) - })?; - - let memory_index: u32 = 0; - - let memory = runtime - .wasm_instance - .memory(memory_index as usize) - .ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })?; - - let pointer = to_native::(&inputs[0], instruction)? as usize; - let length = to_native::(&inputs[1], instruction)? as usize; - let memory_view = memory.view(); - - if length == 0 { - runtime.stack.push(InterfaceValue::String("".into())); - - return Ok(()) - } - - if memory_view.len() <= pointer + length - 1 { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::MemoryOutOfBoundsAccess { - index: pointer + length, - length: memory_view.len(), - }, - )); - } - - let data: Vec = (&memory_view[pointer..=pointer + length - 1]) - .iter() - .map(Cell::get) - .collect(); - - let string = String::from_utf8(data) - .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?; - - runtime.stack.push(InterfaceValue::String(string)); - - Ok(()) - } - } -); - -#[cfg(test)] -mod tests { - test_executable_instruction!( - test_memory_to_string = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::MemoryToString, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(13), - // ^^^^^^^ length - ], - instance: Instance { - memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), - ..Default::default() - }, - stack: [InterfaceValue::String("Hello, World!".into())], - ); - - test_executable_instruction!( - test_memory_to_string__empty_string = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::MemoryToString, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - InterfaceValue::I32(0), - ], - instance: Instance { - memory: Memory::new(vec![]), - ..Default::default() - }, - stack: [InterfaceValue::String("".into())], - ); - - test_executable_instruction!( - test_memory_to_string__read_out_of_memory = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::MemoryToString, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(13), - // ^^^^^^^ length is too long - ], - instance: Instance { - memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), - ..Default::default() - }, - error: r#"`memory-to-string` read out of the memory bounds (index 13 > memory length 6)"#, - ); - - test_executable_instruction!( - test_memory_to_string__invalid_encoding = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::MemoryToString, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(4), - // ^^^^^^ length is too long - ], - instance: Instance { - memory: Memory::new(vec![0, 159, 146, 150].iter().map(|b| Cell::new(*b)).collect::>>()), - ..Default::default() - }, - error: r#"`memory-to-string` invalid utf-8 sequence of 1 bytes from index 1"#, - ); - - test_executable_instruction!( - test_memory_to_string__stack_is_too_small = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::MemoryToString, - // ^^^^^^^^^^^^^^ `memory-to-string` expects 2 values on the stack, only one is present. - ], - invocation_inputs: [ - InterfaceValue::I32(0), - InterfaceValue::I32(13), - ], - instance: Instance::new(), - error: r#"`memory-to-string` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#, - ); -} diff --git a/lib/interface-types/src/interpreter/instructions/mod.rs b/lib/interface-types/src/interpreter/instructions/mod.rs index 34a5dbdae..9d7f07227 100644 --- a/lib/interface-types/src/interpreter/instructions/mod.rs +++ b/lib/interface-types/src/interpreter/instructions/mod.rs @@ -1,8 +1,7 @@ mod argument_get; mod call_core; -mod memory_to_string; mod numbers; -mod string_to_memory; +mod strings; use crate::{ errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError}, @@ -13,10 +12,9 @@ use crate::{ }; pub(crate) use argument_get::argument_get; pub(crate) use call_core::call_core; -pub(crate) use memory_to_string::memory_to_string; pub(crate) use numbers::*; use std::convert::TryFrom; -pub(crate) use string_to_memory::string_to_memory; +pub(crate) use strings::*; /// Just a short helper to map the error of a cast from an /// `InterfaceValue` to a native value. diff --git a/lib/interface-types/src/interpreter/instructions/string_to_memory.rs b/lib/interface-types/src/interpreter/instructions/string_to_memory.rs deleted file mode 100644 index a4341a7c3..000000000 --- a/lib/interface-types/src/interpreter/instructions/string_to_memory.rs +++ /dev/null @@ -1,175 +0,0 @@ -use super::to_native; -use crate::{ - ast::InterfaceType, - errors::{InstructionError, InstructionErrorKind}, - interpreter::{ - wasm::{ - structures::{FunctionIndex, TypedIndex}, - values::InterfaceValue, - }, - Instruction, - }, -}; - -executable_instruction!( - string_to_memory(allocator_index: u32, instruction: Instruction) -> _ { - move |runtime| -> _ { - let instance = &mut runtime.wasm_instance; - let index = FunctionIndex::new(allocator_index as usize); - - let allocator = instance.local_or_import(index).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportIsMissing { function_index: allocator_index }, - ) - })?; - - if allocator.inputs() != [InterfaceType::I32] || allocator.outputs() != [InterfaceType::I32] { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportSignatureMismatch { - function_index: allocator_index, - expected: (vec![InterfaceType::I32], vec![InterfaceType::I32]), - received: (allocator.inputs().to_vec(), allocator.outputs().to_vec()) - } - )) - } - - let string = runtime.stack.pop1().ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 1 } - ) - })?; - - let string: String = to_native(&string, instruction)?; - let string_bytes = string.as_bytes(); - let string_length = string_bytes.len() as i32; - - let outputs = allocator.call(&[InterfaceValue::I32(string_length)]).map_err(|_| { - InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportCall { function_index: allocator_index }, - ) - })?; - let string_pointer: i32 = to_native(&outputs[0], instruction)?; - - let memory_index: u32 = 0; - let memory_view = instance - .memory(memory_index as usize) - .ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::MemoryIsMissing { memory_index } - ) - })? - .view(); - - for (nth, byte) in string_bytes.iter().enumerate() { - memory_view[string_pointer as usize + nth].set(*byte); - } - - runtime.stack.push(InterfaceValue::I32(string_pointer)); - runtime.stack.push(InterfaceValue::I32(string_length)); - - Ok(()) - } - } -); - -#[cfg(test)] -mod tests { - test_executable_instruction!( - test_string_to_memory = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringToMemory { allocator_index: 43 }, - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: Instance::new(), - stack: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(13), - // ^^^^^^^ length - ] - ); - - test_executable_instruction!( - test_string_to_memory__roundtrip_with_memory_to_string = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringToMemory { allocator_index: 43 }, - Instruction::MemoryToString, - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: Instance::new(), - stack: [InterfaceValue::String("Hello, World!".into())], - ); - - test_executable_instruction!( - test_string_to_memory__allocator_does_not_exist = - instructions: [Instruction::StringToMemory { allocator_index: 43 }], - invocation_inputs: [], - instance: Instance { ..Default::default() }, - error: r#"`string-to-memory 43` the local or import function `43` doesn't exist"#, - ); - - test_executable_instruction!( - test_string_to_memory__stack_is_too_small = - instructions: [ - Instruction::StringToMemory { allocator_index: 43 } - // ^^ `43` expects 1 value on the stack, none is present - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: Instance::new(), - error: r#"`string-to-memory 43` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#, - ); - - test_executable_instruction!( - test_string_to_memory__failure_when_calling_the_allocator = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringToMemory { allocator_index: 153 } - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: { - let mut instance = Instance::new(); - instance.locals_or_imports.insert( - 153, - LocalImport { - inputs: vec![InterfaceType::I32], - outputs: vec![InterfaceType::I32], - function: |_| Err(()), - // ^^^^^^^ function fails - }, - ); - - instance - }, - error: r#"`string-to-memory 153` failed while calling the local or import function `153`"#, - ); - - test_executable_instruction!( - test_string_to_memory__invalid_allocator_signature = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringToMemory { allocator_index: 153 } - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: { - let mut instance = Instance::new(); - instance.locals_or_imports.insert( - 153, - LocalImport { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![], - function: |_| Err(()), - }, - ); - - instance - }, - error: r#"`string-to-memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#, - ); -} diff --git a/lib/interface-types/src/interpreter/instructions/strings.rs b/lib/interface-types/src/interpreter/instructions/strings.rs new file mode 100644 index 000000000..a64547bbf --- /dev/null +++ b/lib/interface-types/src/interpreter/instructions/strings.rs @@ -0,0 +1,326 @@ +use super::to_native; +use crate::{ + ast::InterfaceType, + errors::{InstructionError, InstructionErrorKind}, + interpreter::{ + wasm::{ + structures::{FunctionIndex, TypedIndex}, + values::InterfaceValue, + }, + Instruction, + }, +}; +use std::cell::Cell; + +executable_instruction!( + string_lift_memory(instruction: Instruction) -> _ { + move |runtime| -> _ { + let inputs = runtime.stack.pop(2).ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::StackIsTooSmall { needed: 2 }, + ) + })?; + + let memory_index: u32 = 0; + + let memory = runtime + .wasm_instance + .memory(memory_index as usize) + .ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::MemoryIsMissing { memory_index }, + ) + })?; + + let pointer = to_native::(&inputs[0], instruction)? as usize; + let length = to_native::(&inputs[1], instruction)? as usize; + let memory_view = memory.view(); + + if length == 0 { + runtime.stack.push(InterfaceValue::String("".into())); + + return Ok(()) + } + + if memory_view.len() <= pointer + length - 1 { + return Err(InstructionError::new( + instruction, + InstructionErrorKind::MemoryOutOfBoundsAccess { + index: pointer + length, + length: memory_view.len(), + }, + )); + } + + let data: Vec = (&memory_view[pointer..=pointer + length - 1]) + .iter() + .map(Cell::get) + .collect(); + + let string = String::from_utf8(data) + .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?; + + runtime.stack.push(InterfaceValue::String(string)); + + Ok(()) + } + } +); + +executable_instruction!( + string_lower_memory(allocator_index: u32, instruction: Instruction) -> _ { + move |runtime| -> _ { + let instance = &mut runtime.wasm_instance; + let index = FunctionIndex::new(allocator_index as usize); + + let allocator = instance.local_or_import(index).ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::LocalOrImportIsMissing { function_index: allocator_index }, + ) + })?; + + if allocator.inputs() != [InterfaceType::I32] || allocator.outputs() != [InterfaceType::I32] { + return Err(InstructionError::new( + instruction, + InstructionErrorKind::LocalOrImportSignatureMismatch { + function_index: allocator_index, + expected: (vec![InterfaceType::I32], vec![InterfaceType::I32]), + received: (allocator.inputs().to_vec(), allocator.outputs().to_vec()) + } + )) + } + + let string = runtime.stack.pop1().ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ) + })?; + + let string: String = to_native(&string, instruction)?; + let string_bytes = string.as_bytes(); + let string_length = string_bytes.len() as i32; + + let outputs = allocator.call(&[InterfaceValue::I32(string_length)]).map_err(|_| { + InstructionError::new( + instruction, + InstructionErrorKind::LocalOrImportCall { function_index: allocator_index }, + ) + })?; + let string_pointer: i32 = to_native(&outputs[0], instruction)?; + + let memory_index: u32 = 0; + let memory_view = instance + .memory(memory_index as usize) + .ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::MemoryIsMissing { memory_index } + ) + })? + .view(); + + for (nth, byte) in string_bytes.iter().enumerate() { + memory_view[string_pointer as usize + nth].set(*byte); + } + + runtime.stack.push(InterfaceValue::I32(string_pointer)); + runtime.stack.push(InterfaceValue::I32(string_length)); + + Ok(()) + } + } +); + +#[cfg(test)] +mod tests { + test_executable_instruction!( + test_string_lift_memory = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, + Instruction::StringLiftMemory, + ], + invocation_inputs: [ + InterfaceValue::I32(0), + // ^^^^^^ pointer + InterfaceValue::I32(13), + // ^^^^^^^ length + ], + instance: Instance { + memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), + ..Default::default() + }, + stack: [InterfaceValue::String("Hello, World!".into())], + ); + + test_executable_instruction!( + test_string_lift_memory__empty_string = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, + Instruction::StringLiftMemory, + ], + invocation_inputs: [ + InterfaceValue::I32(0), + InterfaceValue::I32(0), + ], + instance: Instance { + memory: Memory::new(vec![]), + ..Default::default() + }, + stack: [InterfaceValue::String("".into())], + ); + + test_executable_instruction!( + test_string_lift_memory__read_out_of_memory = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, + Instruction::StringLiftMemory, + ], + invocation_inputs: [ + InterfaceValue::I32(0), + // ^^^^^^ pointer + InterfaceValue::I32(13), + // ^^^^^^^ length is too long + ], + instance: Instance { + memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), + ..Default::default() + }, + error: r#"`string.lift_memory` read out of the memory bounds (index 13 > memory length 6)"#, + ); + + test_executable_instruction!( + test_string_lift_memory__invalid_encoding = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::ArgumentGet { index: 1 }, + Instruction::StringLiftMemory, + ], + invocation_inputs: [ + InterfaceValue::I32(0), + // ^^^^^^ pointer + InterfaceValue::I32(4), + // ^^^^^^ length is too long + ], + instance: Instance { + memory: Memory::new(vec![0, 159, 146, 150].iter().map(|b| Cell::new(*b)).collect::>>()), + ..Default::default() + }, + error: r#"`string.lift_memory` invalid utf-8 sequence of 1 bytes from index 1"#, + ); + + test_executable_instruction!( + test_string_lift_memory__stack_is_too_small = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringLiftMemory, + // ^^^^^^^^^^^^^^^^ `string.lift_memory` expects 2 values on the stack, only one is present. + ], + invocation_inputs: [ + InterfaceValue::I32(0), + InterfaceValue::I32(13), + ], + instance: Instance::new(), + error: r#"`string.lift_memory` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#, + ); + + test_executable_instruction!( + test_string_memory = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringLowerMemory { allocator_index: 43 }, + ], + invocation_inputs: [InterfaceValue::String("Hello, World!".into())], + instance: Instance::new(), + stack: [ + InterfaceValue::I32(0), + // ^^^^^^ pointer + InterfaceValue::I32(13), + // ^^^^^^^ length + ] + ); + + test_executable_instruction!( + test_string_memory__roundtrip_with_memory_to_string = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringLowerMemory { allocator_index: 43 }, + Instruction::StringLiftMemory, + ], + invocation_inputs: [InterfaceValue::String("Hello, World!".into())], + instance: Instance::new(), + stack: [InterfaceValue::String("Hello, World!".into())], + ); + + test_executable_instruction!( + test_string_memory__allocator_does_not_exist = + instructions: [Instruction::StringLowerMemory { allocator_index: 43 }], + invocation_inputs: [], + instance: Instance { ..Default::default() }, + error: r#"`string.lower_memory 43` the local or import function `43` doesn't exist"#, + ); + + test_executable_instruction!( + test_string_memory__stack_is_too_small = + instructions: [ + Instruction::StringLowerMemory { allocator_index: 43 } + // ^^ `43` expects 1 value on the stack, none is present + ], + invocation_inputs: [InterfaceValue::String("Hello, World!".into())], + instance: Instance::new(), + error: r#"`string.lower_memory 43` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#, + ); + + test_executable_instruction!( + test_string_memory__failure_when_calling_the_allocator = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringLowerMemory { allocator_index: 153 } + ], + invocation_inputs: [InterfaceValue::String("Hello, World!".into())], + instance: { + let mut instance = Instance::new(); + instance.locals_or_imports.insert( + 153, + LocalImport { + inputs: vec![InterfaceType::I32], + outputs: vec![InterfaceType::I32], + function: |_| Err(()), + // ^^^^^^^ function fails + }, + ); + + instance + }, + error: r#"`string.lower_memory 153` failed while calling the local or import function `153`"#, + ); + + test_executable_instruction!( + test_string_memory__invalid_allocator_signature = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringLowerMemory { allocator_index: 153 } + ], + invocation_inputs: [InterfaceValue::String("Hello, World!".into())], + instance: { + let mut instance = Instance::new(); + instance.locals_or_imports.insert( + 153, + LocalImport { + inputs: vec![InterfaceType::I32, InterfaceType::I32], + outputs: vec![], + function: |_| Err(()), + }, + ); + + instance + }, + error: r#"`string.lower_memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#, + ); +} diff --git a/lib/interface-types/src/interpreter/mod.rs b/lib/interface-types/src/interpreter/mod.rs index f2a9c4427..560928f25 100644 --- a/lib/interface-types/src/interpreter/mod.rs +++ b/lib/interface-types/src/interpreter/mod.rs @@ -230,9 +230,9 @@ where Instruction::I64FromU32 => instructions::i64_from_u32(*instruction), Instruction::I64FromU64 => instructions::i64_from_u64(*instruction), - Instruction::MemoryToString => instructions::memory_to_string(*instruction), - Instruction::StringToMemory { allocator_index } => { - instructions::string_to_memory(*allocator_index, *instruction) + Instruction::StringLiftMemory => instructions::string_lift_memory(*instruction), + Instruction::StringLowerMemory { allocator_index } => { + instructions::string_lower_memory(*allocator_index, *instruction) } }) .collect(); From 7f2273b32b1db622dfd548bc6b36a2abbe1e6008 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 13:29:38 +0100 Subject: [PATCH 08/15] doc(interface-types) Add `string.*` instructions. --- lib/interface-types/README.md | 80 +++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/interface-types/README.md b/lib/interface-types/README.md index e6a303099..29f3fabbb 100644 --- a/lib/interface-types/README.md +++ b/lib/interface-types/README.md @@ -49,43 +49,43 @@ mode](https://github.com/WebAssembly/interface-types/blob/master/proposals/inter Here is the instructions that are implemented by this crate: -| Instruction | WAT encoder | Binary encoder | WAT decoder | Binary decoder | Interpreter | -|-|-|-|-|-|-| -| `arg.get` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `call-core` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s8.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s8.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s16.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s16.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s32.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s32.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s64.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `s64.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_s8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_s16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_s32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_s64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_s8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_s16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_s32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_s64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u8.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u8.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u16.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u16.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u32.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u32.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u64.from_i32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `u64.from_i64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_u8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_u16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_u32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i32.from_u64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_u8` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_u16` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_u32` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `i64.from_u64` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `memory-to-string` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `string-to-memory` | ✅ | ✅ | ✅ | ✅ | ✅ | -| `call-adapter` | ❌ | ❌ | ❌ | ❌ | ❌ | -| `defer-call-core` | ❌ | ❌ | ❌ | ❌ | ❌ | +| Instruction | WAT encoder/decoder | Binary encoder/decoder | Interpreter | Comment | +|-|-|-|-|-| +| `arg.get` | ✅ | ✅ | ✅ | | +| `call-core` | ✅ | ✅ | ✅ | | +| `s8.from_i32` | ✅ | ✅ | ✅ | | +| `s8.from_i64` | ✅ | ✅ | ✅ | | +| `s16.from_i32` | ✅ | ✅ | ✅ | | +| `s16.from_i64` | ✅ | ✅ | ✅ | | +| `s32.from_i32` | ✅ | ✅ | ✅ | | +| `s32.from_i64` | ✅ | ✅ | ✅ | | +| `s64.from_i32` | ✅ | ✅ | ✅ | | +| `s64.from_i64` | ✅ | ✅ | ✅ | | +| `i32.from_s8` | ✅ | ✅ | ✅ | | +| `i32.from_s16` | ✅ | ✅ | ✅ | | +| `i32.from_s32` | ✅ | ✅ | ✅ | | +| `i32.from_s64` | ✅ | ✅ | ✅ | | +| `i64.from_s8` | ✅ | ✅ | ✅ | | +| `i64.from_s16` | ✅ | ✅ | ✅ | | +| `i64.from_s32` | ✅ | ✅ | ✅ | | +| `i64.from_s64` | ✅ | ✅ | ✅ | | +| `u8.from_i32` | ✅ | ✅ | ✅ | | +| `u8.from_i64` | ✅ | ✅ | ✅ | | +| `u16.from_i32` | ✅ | ✅ | ✅ | | +| `u16.from_i64` | ✅ | ✅ | ✅ | | +| `u32.from_i32` | ✅ | ✅ | ✅ | | +| `u32.from_i64` | ✅ | ✅ | ✅ | | +| `u64.from_i32` | ✅ | ✅ | ✅ | | +| `u64.from_i64` | ✅ | ✅ | ✅ | | +| `i32.from_u8` | ✅ | ✅ | ✅ | | +| `i32.from_u16` | ✅ | ✅ | ✅ | | +| `i32.from_u32` | ✅ | ✅ | ✅ | | +| `i32.from_u64` | ✅ | ✅ | ✅ | | +| `i64.from_u8` | ✅ | ✅ | ✅ | | +| `i64.from_u16` | ✅ | ✅ | ✅ | | +| `i64.from_u32` | ✅ | ✅ | ✅ | | +| `i64.from_u64` | ✅ | ✅ | ✅ | | +| `string.lift_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed | +| `string.lower_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed | +| `call-adapter` | ❌ | ❌ | ❌ | | +| `defer-call-core` | ❌ | ❌ | ❌ | | From daef7b0bfdf4e645649202382c69ce268f2f1af1 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 15:32:54 +0100 Subject: [PATCH 09/15] feat(interface-types) Add the `Stackable::peek1` method. This method allows to peek the last item on the stack (if any) by reference. --- lib/interface-types/src/interpreter/stack.rs | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/interface-types/src/interpreter/stack.rs b/lib/interface-types/src/interpreter/stack.rs index 7d39b9f91..321fcf4d2 100644 --- a/lib/interface-types/src/interpreter/stack.rs +++ b/lib/interface-types/src/interpreter/stack.rs @@ -25,6 +25,10 @@ pub trait Stackable { /// Returned items are in reverse order: the last element comes /// last in the list. fn pop(&mut self, n: usize) -> Option>; + + /// Peek the last item of the stack and returns a reference to it, + /// `None` if the stack is empty. + fn peek1(&self) -> Option<&Self::Item>; } /// A stack implementation of the `Stackable` trait, based on a vector. @@ -85,6 +89,14 @@ where Some(items) } } + + fn peek1(&self) -> Option<&Self::Item> { + if self.inner.is_empty() { + None + } else { + Some(&self.inner[self.inner.len() - 1]) + } + } } #[cfg(test)] @@ -126,4 +138,13 @@ mod tests { assert_eq!(stack.pop1(), None); assert_eq!(stack.is_empty(), true); } + + #[test] + fn test_peek1() { + let mut stack = Stack::new(); + stack.push(1); + stack.push(2); + + assert_eq!(stack.peek1(), Some(&2)); + } } From 38f62392ffa16adc66799362369a3cae0b8b4db6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 15:33:42 +0100 Subject: [PATCH 10/15] feat(interface-types) Implement the `string.size` instruction. --- lib/interface-types/src/decoders/binary.rs | 6 +- lib/interface-types/src/decoders/wat.rs | 7 +++ lib/interface-types/src/encoders/binary.rs | 6 +- lib/interface-types/src/encoders/wat.rs | 3 + .../src/interpreter/instruction.rs | 3 + .../src/interpreter/instructions/strings.rs | 60 +++++++++++++++++++ lib/interface-types/src/interpreter/mod.rs | 1 + 7 files changed, 84 insertions(+), 2 deletions(-) diff --git a/lib/interface-types/src/decoders/binary.rs b/lib/interface-types/src/decoders/binary.rs index 2661d6f84..f1f7f7712 100644 --- a/lib/interface-types/src/decoders/binary.rs +++ b/lib/interface-types/src/decoders/binary.rs @@ -219,6 +219,8 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( ) } + 0x24 => (input, Instruction::StringSize), + _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }) } @@ -620,7 +622,7 @@ mod tests { #[test] fn test_instructions() { let input = &[ - 0x24, // list of 36 items + 0x25, // list of 37 items 0x00, 0x01, // ArgumentGet { index: 1 } 0x01, 0x01, // CallCore { function_index: 1 } 0x02, // S8FromI32 @@ -657,6 +659,7 @@ mod tests { 0x21, // I64FromU64 0x22, // StringLiftMemory 0x23, 0x01, // StringLowerMemory { allocator_index: 1 } + 0x24, // StringSize 0x0a, ]; let output = Ok(( @@ -698,6 +701,7 @@ mod tests { Instruction::I64FromU64, Instruction::StringLiftMemory, Instruction::StringLowerMemory { allocator_index: 1 }, + Instruction::StringSize, ], )); diff --git a/lib/interface-types/src/decoders/wat.rs b/lib/interface-types/src/decoders/wat.rs index a3469ea55..3e41d513b 100644 --- a/lib/interface-types/src/decoders/wat.rs +++ b/lib/interface-types/src/decoders/wat.rs @@ -62,6 +62,7 @@ mod keyword { custom_keyword!(i64_from_u64 = "i64.from_u64"); custom_keyword!(string_lift_memory = "string.lift_memory"); custom_keyword!(string_lower_memory = "string.lower_memory"); + custom_keyword!(string_size = "string.size"); } impl Parse<'_> for InterfaceType { @@ -285,6 +286,10 @@ impl<'a> Parse<'a> for Instruction { Ok(Instruction::StringLowerMemory { allocator_index: parser.parse()?, }) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::StringSize) } else { Err(lookahead.error()) } @@ -666,6 +671,7 @@ mod tests { "i64.from_u64", "string.lift_memory", "string.lower_memory 42", + "string.size", ]; let outputs = vec![ Instruction::ArgumentGet { index: 7 }, @@ -706,6 +712,7 @@ mod tests { Instruction::StringLowerMemory { allocator_index: 42, }, + Instruction::StringSize, ]; assert_eq!(inputs.len(), outputs.len()); diff --git a/lib/interface-types/src/encoders/binary.rs b/lib/interface-types/src/encoders/binary.rs index aece560e3..7a2466952 100644 --- a/lib/interface-types/src/encoders/binary.rs +++ b/lib/interface-types/src/encoders/binary.rs @@ -299,6 +299,8 @@ where 0x23_u8.to_bytes(writer)?; (*allocator_index as u64).to_bytes(writer)?; } + + Instruction::StringSize => 0x24_u8.to_bytes(writer)?, } Ok(()) @@ -577,9 +579,10 @@ mod tests { Instruction::I64FromU64, Instruction::StringLiftMemory, Instruction::StringLowerMemory { allocator_index: 1 }, + Instruction::StringSize, ], &[ - 0x24, // list of 36 items + 0x25, // list of 37 items 0x00, 0x01, // ArgumentGet { index: 1 } 0x01, 0x01, // CallCore { function_index: 1 } 0x02, // S8FromI32 @@ -616,6 +619,7 @@ mod tests { 0x21, // I64FromU64 0x22, // StringLiftMemory 0x23, 0x01, // StringLowerMemory { allocator_index: 1 } + 0x24, // StringSize ] ); } diff --git a/lib/interface-types/src/encoders/wat.rs b/lib/interface-types/src/encoders/wat.rs index 49142257d..7856e59b2 100644 --- a/lib/interface-types/src/encoders/wat.rs +++ b/lib/interface-types/src/encoders/wat.rs @@ -121,6 +121,7 @@ impl ToString for &Instruction { Instruction::StringLowerMemory { allocator_index } => { format!(r#"string.lower_memory {}"#, allocator_index) } + Instruction::StringSize => "string.size".into(), } } } @@ -391,6 +392,7 @@ mod tests { allocator_index: 42, }) .to_string(), + (&Instruction::StringSize).to_string(), ]; let outputs = vec![ "arg.get 7", @@ -429,6 +431,7 @@ mod tests { "i64.from_u64", "string.lift_memory", "string.lower_memory 42", + "string.size", ]; assert_eq!(inputs, outputs); diff --git a/lib/interface-types/src/interpreter/instruction.rs b/lib/interface-types/src/interpreter/instruction.rs index 0ef4c945e..712a6ea58 100644 --- a/lib/interface-types/src/interpreter/instruction.rs +++ b/lib/interface-types/src/interpreter/instruction.rs @@ -119,4 +119,7 @@ pub enum Instruction { /// The allocator function index. allocator_index: u32, }, + + /// The `string.size` instruction. + StringSize, } diff --git a/lib/interface-types/src/interpreter/instructions/strings.rs b/lib/interface-types/src/interpreter/instructions/strings.rs index a64547bbf..011cac951 100644 --- a/lib/interface-types/src/interpreter/instructions/strings.rs +++ b/lib/interface-types/src/interpreter/instructions/strings.rs @@ -135,6 +135,34 @@ executable_instruction!( } ); +executable_instruction!( + string_size(instruction: Instruction) -> _ { + move |runtime| -> _ { + let value = runtime.stack.peek1().ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::StackIsTooSmall { needed: 1 }, + ) + })?; + + if let InterfaceValue::String(string) = value { + let length = string.len() as i32; + runtime.stack.push(InterfaceValue::I32(length)); + + Ok(()) + } else { + Err(InstructionError::new( + instruction, + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: InterfaceType::String, + received_type: value.into(), + } + )) + } + } + } +); + #[cfg(test)] mod tests { test_executable_instruction!( @@ -323,4 +351,36 @@ mod tests { }, error: r#"`string.lower_memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#, ); + + test_executable_instruction!( + test_string_size = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringSize, + ], + invocation_inputs: [InterfaceValue::String("Hello, World!".into())], + instance: Instance::new(), + stack: [InterfaceValue::String("Hello, World!".into()), InterfaceValue::I32(13)], + ); + + test_executable_instruction!( + test_string_size__stack_is_too_small = + instructions: [ + Instruction::StringSize, + ], + invocation_inputs: [], + instance: Instance::new(), + error: r#"`string.size` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#, + ); + + test_executable_instruction!( + test_string_size__invalid_value_on_the_stack = + instructions: [ + Instruction::ArgumentGet { index: 0 }, + Instruction::StringSize, + ], + invocation_inputs: [InterfaceValue::I32(42)], + instance: Instance::new(), + error: r#"`string.size` read a value of type `I32` from the stack, but the type `String` was expected"#, + ); } diff --git a/lib/interface-types/src/interpreter/mod.rs b/lib/interface-types/src/interpreter/mod.rs index 560928f25..22252aea7 100644 --- a/lib/interface-types/src/interpreter/mod.rs +++ b/lib/interface-types/src/interpreter/mod.rs @@ -234,6 +234,7 @@ where Instruction::StringLowerMemory { allocator_index } => { instructions::string_lower_memory(*allocator_index, *instruction) } + Instruction::StringSize => instructions::string_size(*instruction), }) .collect(); From ffe7f765a2db78496ead37083d3b09b415973754 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 15:35:01 +0100 Subject: [PATCH 11/15] doc(interface-types) Add `strign.size` in the list of supported instructions. --- lib/interface-types/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/interface-types/README.md b/lib/interface-types/README.md index 29f3fabbb..f680523d6 100644 --- a/lib/interface-types/README.md +++ b/lib/interface-types/README.md @@ -87,5 +87,6 @@ Here is the instructions that are implemented by this crate: | `i64.from_u64` | ✅ | ✅ | ✅ | | | `string.lift_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed | | `string.lower_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed | +| `string.size` | ✅ | ✅ | ✅ | `#encoding` is not supported but UTF-8 is assumed | | `call-adapter` | ❌ | ❌ | ❌ | | | `defer-call-core` | ❌ | ❌ | ❌ | | From b251d6d7b47b2c4a6a06f0575b846515c9789fd6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 24 Mar 2020 15:42:40 +0100 Subject: [PATCH 12/15] doc(changelog) Add #1329. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 581789f4f..9d2ad58b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1329](https://github.com/wasmerio/wasmer/pull/1329) New numbers and strings instructions for WIT - [#1320](https://github.com/wasmerio/wasmer/pull/1320) Change `custom_sections` field in `ModuleInfo` to be more standards compliant by allowing multiple custom sections with the same name. To get the old behavior with the new API, you can add `.last().unwrap()` to accesses. For example, `module_info.custom_sections["custom_section_name"].last().unwrap()`. - [#1303](https://github.com/wasmerio/wasmer/pull/1303) NaN canonicalization for singlepass backend. - [#1305](https://github.com/wasmerio/wasmer/pull/1305) Handle panics from DynamicFunc. From 403e14bc1ecbc0f77a77926e16d9d0f56f2b5982 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 24 Mar 2020 14:47:00 -0700 Subject: [PATCH 13/15] Add `CompilerConifg` opt to disable IR verification in debug mode --- CHANGELOG.md | 1 + lib/clif-backend/src/lib.rs | 16 +++++++++++----- lib/clif-backend/src/trampoline.rs | 16 ++++++++-------- lib/runtime-core/src/backend.rs | 6 ++++++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55f36466f..6f6856366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1332](https://github.com/wasmerio/wasmer/pull/1332) Add option to `CompilerConfig` to force compiler IR verification off even when `debug_assertions` are enabled. This can be used to make debug builds faster, which may be important if you're creating a library that wraps Wasmer and depend on the speed of debug builds. - [#1320](https://github.com/wasmerio/wasmer/pull/1320) Change `custom_sections` field in `ModuleInfo` to be more standards compliant by allowing multiple custom sections with the same name. To get the old behavior with the new API, you can add `.last().unwrap()` to accesses. For example, `module_info.custom_sections["custom_section_name"].last().unwrap()`. - [#1303](https://github.com/wasmerio/wasmer/pull/1303) NaN canonicalization for singlepass backend. - [#1292](https://github.com/wasmerio/wasmer/pull/1292) Experimental Support for Android (x86_64 and AArch64) diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index c4fb65736..02bf479aa 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -43,16 +43,22 @@ fn get_isa(config: Option<&CompilerConfig>) -> Box { builder.set("opt_level", "speed_and_size").unwrap(); builder.set("enable_jump_tables", "false").unwrap(); - if cfg!(test) || cfg!(debug_assertions) { - builder.set("enable_verifier", "true").unwrap(); - } else { - builder.set("enable_verifier", "false").unwrap(); - } + let enable_verifier: bool; if let Some(config) = config { if config.nan_canonicalization { builder.set("enable_nan_canonicalization", "true").unwrap(); } + enable_verifier = !config.disable_debug_mode_verification; + } else { + // Set defaults if no config found. + enable_verifier = true; + } + + if (cfg!(test) || cfg!(debug_assertions)) && enable_verifier { + builder.set("enable_verifier", "true").unwrap(); + } else { + builder.set("enable_verifier", "false").unwrap(); } let flags = settings::Flags::new(builder); diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index 6b6c5d7ea..b792f95c2 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -86,7 +86,7 @@ impl Trampolines { let sig_index = module.func_assoc[*exported_func_index]; let func_sig = &module.signatures[sig_index]; - let trampoline_func = generate_func(&func_sig); + let trampoline_func = generate_func(isa, &func_sig); ctx.func = trampoline_func; @@ -150,13 +150,13 @@ impl Trampolines { /// This function generates a trampoline for the specific signature /// passed into it. -fn generate_func(func_sig: &FuncSig) -> ir::Function { - let trampoline_sig = generate_trampoline_signature(); +fn generate_func(isa: &dyn isa::TargetIsa, func_sig: &FuncSig) -> ir::Function { + let trampoline_sig = generate_trampoline_signature(isa); let mut func = ir::Function::with_name_signature(ir::ExternalName::testcase("trampln"), trampoline_sig); - let export_sig_ref = func.import_signature(generate_export_signature(func_sig)); + let export_sig_ref = func.import_signature(generate_export_signature(isa, func_sig)); let entry_ebb = func.dfg.make_block(); let vmctx_ptr = func.dfg.append_block_param(entry_ebb, ir::types::I64); @@ -211,8 +211,8 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type { } } -fn generate_trampoline_signature() -> ir::Signature { - let call_convention = super::get_isa(None).default_call_conv(); +fn generate_trampoline_signature(isa: &dyn isa::TargetIsa) -> ir::Signature { + let call_convention = isa.default_call_conv(); let mut sig = ir::Signature::new(call_convention); let ptr_param = ir::AbiParam { @@ -227,8 +227,8 @@ fn generate_trampoline_signature() -> ir::Signature { sig } -fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature { - let call_convention = super::get_isa(None).default_call_conv(); +fn generate_export_signature(isa: &dyn isa::TargetIsa, func_sig: &FuncSig) -> ir::Signature { + let call_convention = isa.default_call_conv(); let mut export_clif_sig = ir::Signature::new(call_convention); let func_sig_iter = func_sig.params().iter().map(|wasm_ty| ir::AbiParam { diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index eabe526d8..2b0f54c4f 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -136,6 +136,12 @@ pub struct CompilerConfig { /// Enabling this makes execution deterministic but increases runtime overhead. pub nan_canonicalization: bool, + /// Turns off verification that is done by default when `debug_assertions` are enabled + /// (for example in 'debug' builds). Enabling this flag will make compilation faster at the + /// cost of not detecting bugs in the compiler. The verification steps that this flag + /// disables are disabled by default in 'release' builds. + pub disable_debug_mode_verification: bool, + pub features: Features, // Target info. Presently only supported by LLVM. From ce1b1f67cf9180ab59bed6b9dc70df08c4b70c60 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 24 Mar 2020 15:46:58 -0700 Subject: [PATCH 14/15] Update opt name in CompilerConfig, enable IR verification in spectests --- lib/clif-backend/src/lib.rs | 8 ++++--- lib/runtime-core/src/backend.rs | 37 +++++++++++++++++++++++++++------ lib/spectests/tests/spectest.rs | 5 +++++ 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 02bf479aa..59d3416ba 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -49,13 +49,15 @@ fn get_isa(config: Option<&CompilerConfig>) -> Box { if config.nan_canonicalization { builder.set("enable_nan_canonicalization", "true").unwrap(); } - enable_verifier = !config.disable_debug_mode_verification; + enable_verifier = config.enable_verification; } else { // Set defaults if no config found. - enable_verifier = true; + // NOTE: cfg(test) probably does nothing when not running `cargo test` + // on this crate + enable_verifier = cfg!(test) || cfg!(debug_assertions); } - if (cfg!(test) || cfg!(debug_assertions)) && enable_verifier { + if enable_verifier { builder.set("enable_verifier", "true").unwrap(); } else { builder.set("enable_verifier", "false").unwrap(); diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 2b0f54c4f..c6235475d 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -106,7 +106,7 @@ impl BackendCompilerConfig { } /// Configuration data for the compiler -#[derive(Debug, Default)] +#[derive(Debug)] pub struct CompilerConfig { /// Symbol information generated from emscripten; used for more detailed debug messages pub symbol_map: Option>, @@ -136,11 +136,12 @@ pub struct CompilerConfig { /// Enabling this makes execution deterministic but increases runtime overhead. pub nan_canonicalization: bool, - /// Turns off verification that is done by default when `debug_assertions` are enabled - /// (for example in 'debug' builds). Enabling this flag will make compilation faster at the - /// cost of not detecting bugs in the compiler. The verification steps that this flag - /// disables are disabled by default in 'release' builds. - pub disable_debug_mode_verification: bool, + /// Turns on verification that is done by default when `debug_assertions` are enabled + /// (for example in 'debug' builds). Disabling this flag will make compilation faster + /// in debug mode at the cost of not detecting bugs in the compiler. + /// + /// These verifications are disabled by default in 'release' builds. + pub enable_verification: bool, pub features: Features, @@ -154,6 +155,30 @@ pub struct CompilerConfig { pub generate_debug_info: bool, } +impl Default for CompilerConfig { + fn default() -> Self { + Self { + symbol_map: Default::default(), + memory_bound_check_mode: Default::default(), + enforce_stack_check: Default::default(), + track_state: Default::default(), + full_preemption: Default::default(), + nan_canonicalization: Default::default(), + features: Default::default(), + triple: Default::default(), + cpu_name: Default::default(), + cpu_features: Default::default(), + backend_specific_config: Default::default(), + generate_debug_info: Default::default(), + + // Default verification to 'on' when testing or running in debug mode. + // NOTE: cfg(test) probably does nothing when not running `cargo test` + // on this crate + enable_verification: cfg!(test) || cfg!(debug_assertions), + } + } +} + impl CompilerConfig { /// Use this to check if we should be generating debug information. /// This function takes into account the features that runtime-core was diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index c3d1ecce7..1748816ed 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -337,6 +337,7 @@ mod tests { threads: true, }, nan_canonicalization: true, + enable_verification: true, ..Default::default() }; let module = compile_with_config(&module.into_vec(), config) @@ -776,6 +777,7 @@ mod tests { threads: true, }, nan_canonicalization: true, + enable_verification: true, ..Default::default() }; compile_with_config(&module.into_vec(), config) @@ -829,6 +831,7 @@ mod tests { threads: true, }, nan_canonicalization: true, + enable_verification: true, ..Default::default() }; compile_with_config(&module.into_vec(), config) @@ -881,6 +884,7 @@ mod tests { threads: true, }, nan_canonicalization: true, + enable_verification: true, ..Default::default() }; let module = compile_with_config(&module.into_vec(), config) @@ -977,6 +981,7 @@ mod tests { threads: true, }, nan_canonicalization: true, + enable_verification: true, ..Default::default() }; let module = compile_with_config(&module.into_vec(), config) From 697da669a1dc2d80e79a98e575bcb5a89813af56 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 24 Mar 2020 16:00:32 -0700 Subject: [PATCH 15/15] Minor code update, move conditional block inwards --- lib/clif-backend/src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 59d3416ba..5740c2742 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -57,11 +57,12 @@ fn get_isa(config: Option<&CompilerConfig>) -> Box { enable_verifier = cfg!(test) || cfg!(debug_assertions); } - if enable_verifier { - builder.set("enable_verifier", "true").unwrap(); - } else { - builder.set("enable_verifier", "false").unwrap(); - } + builder + .set( + "enable_verifier", + if enable_verifier { "true" } else { "false" }, + ) + .unwrap(); let flags = settings::Flags::new(builder); debug_assert_eq!(flags.opt_level(), settings::OptLevel::SpeedAndSize);