diff --git a/res/cases/v1/const.wasm b/res/cases/v1/const.wasm index 95d7dc3..6253ea0 100644 Binary files a/res/cases/v1/const.wasm and b/res/cases/v1/const.wasm differ diff --git a/res/cases/v1/const.wast b/res/cases/v1/const.wast index 188fb26..06ce729 100644 --- a/res/cases/v1/const.wast +++ b/res/cases/v1/const.wast @@ -7,6 +7,12 @@ i32.const 8192 i32.const 16384 i32.const 32767 + i32.const -1024 + i32.const -2048 + i32.const -4096 + i32.const -8192 + i32.const -16384 + i32.const -32768 return ) ) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index e9f8dfb..1fa3788 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -23,7 +23,7 @@ pub use self::import_entry::{ImportEntry, MemoryType, TableType, GlobalType, Ext pub use self::export_entry::{ExportEntry, Internal}; pub use self::global_entry::GlobalEntry; pub use self::primitives::{ - VarUint32, VarUint7, VarUint1, VarInt7, Uint32, + VarUint32, VarUint7, VarUint1, VarInt7, Uint32, VarInt32, VarInt64, Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, }; pub use self::types::{Type, ValueType, BlockType, FunctionType}; diff --git a/src/elements/module.rs b/src/elements/module.rs index 9f89df1..cf87296 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -245,7 +245,7 @@ mod integration_tests { let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized"); let func = &module.code_section().expect("Code section to exist").bodies()[0]; - assert_eq!(func.code().elements().len(), 8); + assert_eq!(func.code().elements().len(), 14); assert_eq!(I32Const(1024), func.code().elements()[0]); assert_eq!(I32Const(2048), func.code().elements()[1]); @@ -253,5 +253,11 @@ mod integration_tests { assert_eq!(I32Const(8192), func.code().elements()[3]); assert_eq!(I32Const(16384), func.code().elements()[4]); assert_eq!(I32Const(32767), func.code().elements()[5]); + assert_eq!(I32Const(-1024), func.code().elements()[6]); + assert_eq!(I32Const(-2048), func.code().elements()[7]); + assert_eq!(I32Const(-4096), func.code().elements()[8]); + assert_eq!(I32Const(-8192), func.code().elements()[9]); + assert_eq!(I32Const(-16384), func.code().elements()[10]); + assert_eq!(I32Const(-32768), func.code().elements()[11]); } } \ No newline at end of file diff --git a/src/elements/ops.rs b/src/elements/ops.rs index 3d1079c..d216302 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -2,7 +2,8 @@ use std::io; use super::{ Serialize, Deserialize, Error, VarUint7, VarUint1, VarUint32, CountedList, BlockType, - Uint32, VarUint64, Uint64, CountedListWriter + Uint32, VarUint64, Uint64, CountedListWriter, + VarInt32, VarInt64, }; /// Collection of opcodes (usually inside a block section). @@ -428,8 +429,8 @@ impl Deserialize for Opcode { 0x3f => CurrentMemory(VarUint1::deserialize(reader)?.into()), 0x40 => GrowMemory(VarUint1::deserialize(reader)?.into()), - 0x41 => I32Const(VarUint32::deserialize(reader)?.into()), - 0x42 => I64Const(VarUint64::deserialize(reader)?.into()), + 0x41 => I32Const(VarInt32::deserialize(reader)?.into()), + 0x42 => I64Const(VarInt64::deserialize(reader)?.into()), 0x43 => F32Const(Uint32::deserialize(reader)?.into()), 0x44 => F64Const(Uint64::deserialize(reader)?.into()), 0x45 => I32Eqz, @@ -741,10 +742,10 @@ impl Serialize for Opcode { VarUint1::from(flag).serialize(writer)?; }), I32Const(def) => op!(writer, 0x41, { - VarUint32::from(def).serialize(writer)?; + VarInt32::from(def).serialize(writer)?; }), I64Const(def) => op!(writer, 0x42, { - VarUint64::from(def).serialize(writer)?; + VarInt64::from(def).serialize(writer)?; }), F32Const(def) => op!(writer, 0x43, { Uint32::from(def).serialize(writer)?; diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index 69a3045..39b590b 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -206,7 +206,7 @@ impl Serialize for VarInt7 { } } -/// 32-bit signed integer, encoded in LEB128 (always 1 byte length) +/// 32-bit signed integer, encoded in LEB128 (can be 1-5 bytes length) #[derive(Copy, Clone)] pub struct VarInt32(i32); @@ -236,7 +236,7 @@ impl Deserialize for VarInt32 { res |= ((b & 0x7f) as i32) << shift; shift += 7; if (b >> 7) == 0 { - if b & 0b0100_0000 == 0b0100_0000 { + if shift < 32 && b & 0b0100_0000 == 0b0100_0000 { res |= - (1 << shift); } break; @@ -269,6 +269,69 @@ impl Serialize for VarInt32 { } } +/// 64-bit signed integer, encoded in LEB128 (can be 1-9 bytes length) +#[derive(Copy, Clone)] +pub struct VarInt64(i64); + +impl From for i64 { + fn from(v: VarInt64) -> i64 { + v.0 + } +} + +impl From for VarInt64 { + fn from(v: i64) -> VarInt64 { + VarInt64(v) + } +} + +impl Deserialize for VarInt64 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0i64; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + reader.read_exact(&mut u8buf)?; + let b = u8buf[0]; + + res |= ((b & 0x7f) as i64) << shift; + shift += 7; + if (b >> 7) == 0 { + if shift < 64 && b & 0b0100_0000 == 0b0100_0000 { + res |= - (1 << shift); + } + break; + } + } + Ok(VarInt64(res)) + } +} + +impl Serialize for VarInt64 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + let mut more = true; + while more { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { + more = false + } else { + buf[0] |= 0b1000_0000 + } + + writer.write_all(&buf[..])?; + } + + Ok(()) + } +} + /// 32-bit unsigned integer, encoded in little endian #[derive(Copy, Clone)] pub struct Uint32(u32); @@ -554,6 +617,11 @@ mod tests { varint32_serde_test(vec![0x80, 0xc0, 0x00], 8192); } + #[test] + fn varint32_neg_8192() { + varint32_serde_test(vec![0x80, 0x40], -8192); + } + #[test] fn counted_list() { let payload = vec![