Skip to content

Commit c225138

Browse files
committed
feat(simd): full SIMD execution, validation improvements, GC type parsing
- Implement all 200+ SIMD V128 instructions (integer, float, bitwise, comparison, conversion, lane ops, memory ops, shuffle) - Add alignment validation for memory and SIMD load/store instructions - Add index range validation for function/table/memory/global references - Add export index validation and element/data segment index checks - Fix GC reference type parsing in table, local, global, element decoders - Support all GC heap types (anyref, eqref, i31ref, structref, arrayref, nullfuncref, nullexternref, encoded ref types) WAST: 117 files passing (+52), 59,855 assertions (+22,712) Pass rate: 91.2% (was 56.6%)
1 parent f85d2b2 commit c225138

File tree

13 files changed

+4291
-184
lines changed

13 files changed

+4291
-184
lines changed

wrt-build-core/src/wast_validator.rs

Lines changed: 259 additions & 40 deletions
Large diffs are not rendered by default.

wrt-decoder/src/streaming_decoder.rs

Lines changed: 77 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -807,12 +807,9 @@ impl<'a> StreamingDecoder<'a> {
807807
},
808808
0x01 => {
809809
// Table import - need to parse table type
810-
// ref_type (1 byte) + limits (flags + min, optional max)
811-
if offset >= data.len() {
812-
return Err(Error::parse_error("Unexpected end of table import"));
813-
}
814-
let ref_type_byte = data[offset];
815-
offset += 1;
810+
// ref_type (may be multi-byte for GC types) + limits (flags + min, optional max)
811+
let (ref_value_type, new_offset) = self.parse_value_type(data, offset)?;
812+
offset = new_offset;
816813

817814
// Parse limits
818815
if offset >= data.len() {
@@ -848,12 +845,10 @@ impl<'a> StreamingDecoder<'a> {
848845
use wrt_format::module::{Import, ImportDesc};
849846
use wrt_foundation::types::{Limits, RefType, TableType};
850847

851-
// Convert ref_type byte to RefType
852-
let ref_type = match ref_type_byte {
853-
0x70 => RefType::Funcref,
854-
0x6F => RefType::Externref,
855-
_ => RefType::Funcref, // Default for unknown
856-
};
848+
// Convert parsed ValueType to RefType
849+
let ref_type = RefType::try_from(ref_value_type).map_err(|_| {
850+
Error::parse_error("Unknown table element type in import")
851+
})?;
857852

858853
let limits = Limits { min, max };
859854

@@ -978,12 +973,13 @@ impl<'a> StreamingDecoder<'a> {
978973
},
979974
0x03 => {
980975
// Global import - need to parse global type
981-
// value_type (1 byte) + mutability (1 byte)
982-
if offset + 1 >= data.len() {
976+
// value_type (may be multi-byte for GC types) + mutability (1 byte)
977+
let (value_type, new_offset) = self.parse_value_type(data, offset)?;
978+
offset = new_offset;
979+
980+
if offset >= data.len() {
983981
return Err(Error::parse_error("Unexpected end of global import"));
984982
}
985-
let value_type_byte = data[offset];
986-
offset += 1;
987983
let mutability_byte = data[offset];
988984
offset += 1;
989985

@@ -992,19 +988,6 @@ impl<'a> StreamingDecoder<'a> {
992988
return Err(Error::parse_error("malformed mutability"));
993989
}
994990

995-
// Parse value type
996-
let value_type = match value_type_byte {
997-
0x7F => wrt_foundation::ValueType::I32,
998-
0x7E => wrt_foundation::ValueType::I64,
999-
0x7D => wrt_foundation::ValueType::F32,
1000-
0x7C => wrt_foundation::ValueType::F64,
1001-
0x7B => wrt_foundation::ValueType::V128,
1002-
0x70 => wrt_foundation::ValueType::FuncRef,
1003-
0x6F => wrt_foundation::ValueType::ExternRef,
1004-
0x69 => wrt_foundation::ValueType::ExnRef,
1005-
_ => return Err(Error::parse_error("Invalid global import value type")),
1006-
};
1007-
1008991
#[cfg(feature = "tracing")]
1009992
trace!(import_index = i, value_type = ?value_type, mutable = (mutability_byte != 0), "import: global");
1010993

@@ -1162,22 +1145,13 @@ impl<'a> StreamingDecoder<'a> {
11621145
offset += 1;
11631146
}
11641147

1165-
// Now parse the ref_type
1166-
if offset >= data.len() {
1167-
return Err(Error::parse_error(
1168-
"Unexpected end of table section (ref_type)",
1169-
));
1170-
}
1171-
let ref_type_byte = data[offset];
1172-
offset += 1;
1148+
// Now parse the ref_type using the full GC-aware parser
1149+
let (value_type, new_offset) = self.parse_value_type(data, offset)?;
1150+
offset = new_offset;
11731151

1174-
let element_type = match ref_type_byte {
1175-
0x70 => RefType::Funcref, // funcref
1176-
0x6F => RefType::Externref, // externref
1177-
_ => {
1178-
return Err(Error::parse_error("Unknown table element type"));
1179-
},
1180-
};
1152+
let element_type = RefType::try_from(value_type).map_err(|_| {
1153+
Error::parse_error("Unknown table element type")
1154+
})?;
11811155

11821156
// Parse limits (flags + min, optional max)
11831157
if offset >= data.len() {
@@ -1742,13 +1716,11 @@ impl<'a> StreamingDecoder<'a> {
17421716
},
17431717
1 => {
17441718
// Passive, element type, expressions
1745-
let elem_type = data[offset];
1746-
offset += 1;
1747-
let ref_type = match elem_type {
1748-
0x70 => wrt_format::types::RefType::Funcref,
1749-
0x6F => wrt_format::types::RefType::Externref,
1750-
_ => wrt_format::types::RefType::Funcref,
1751-
};
1719+
let (vt, new_offset) = self.parse_value_type(data, offset)?;
1720+
offset = new_offset;
1721+
let ref_type = wrt_format::types::RefType::try_from(vt).map_err(|_| {
1722+
Error::parse_error("Invalid element segment reference type")
1723+
})?;
17521724
#[cfg(feature = "tracing")]
17531725
trace!(elem_idx = elem_idx, ref_type = ?ref_type, "element: passive");
17541726
(PureElementMode::Passive, Vec::new(), ref_type)
@@ -1789,13 +1761,11 @@ impl<'a> StreamingDecoder<'a> {
17891761
},
17901762
3 => {
17911763
// Declarative, element type, expressions
1792-
let elem_type = data[offset];
1793-
offset += 1;
1794-
let ref_type = match elem_type {
1795-
0x70 => wrt_format::types::RefType::Funcref,
1796-
0x6F => wrt_format::types::RefType::Externref,
1797-
_ => wrt_format::types::RefType::Funcref,
1798-
};
1764+
let (vt, new_offset) = self.parse_value_type(data, offset)?;
1765+
offset = new_offset;
1766+
let ref_type = wrt_format::types::RefType::try_from(vt).map_err(|_| {
1767+
Error::parse_error("Invalid element segment reference type")
1768+
})?;
17991769
#[cfg(feature = "tracing")]
18001770
trace!(elem_idx = elem_idx, ref_type = ?ref_type, "element: declarative");
18011771
(PureElementMode::Declared, Vec::new(), ref_type)
@@ -1825,13 +1795,11 @@ impl<'a> StreamingDecoder<'a> {
18251795
},
18261796
5 => {
18271797
// Passive, expressions with type
1828-
let ref_type_byte = data[offset];
1829-
offset += 1;
1830-
let ref_type = match ref_type_byte {
1831-
0x70 => wrt_format::types::RefType::Funcref,
1832-
0x6F => wrt_format::types::RefType::Externref,
1833-
_ => wrt_format::types::RefType::Funcref,
1834-
};
1798+
let (vt, new_offset) = self.parse_value_type(data, offset)?;
1799+
offset = new_offset;
1800+
let ref_type = wrt_format::types::RefType::try_from(vt).map_err(|_| {
1801+
Error::parse_error("Invalid element segment reference type")
1802+
})?;
18351803
#[cfg(feature = "tracing")]
18361804
trace!(elem_idx = elem_idx, ref_type = ?ref_type, "element: passive with type");
18371805
(PureElementMode::Passive, Vec::new(), ref_type)
@@ -1848,18 +1816,11 @@ impl<'a> StreamingDecoder<'a> {
18481816
let offset_expr_bytes: Vec<u8> = data[expr_start..offset].to_vec();
18491817

18501818
// Parse ref_type (comes after offset expression, before items)
1851-
if offset >= data.len() {
1852-
return Err(Error::parse_error(
1853-
"Unexpected end of element segment (ref_type)",
1854-
));
1855-
}
1856-
let ref_type_byte = data[offset];
1857-
offset += 1;
1858-
let ref_type = match ref_type_byte {
1859-
0x70 => wrt_format::types::RefType::Funcref,
1860-
0x6F => wrt_format::types::RefType::Externref,
1861-
_ => wrt_format::types::RefType::Funcref,
1862-
};
1819+
let (vt, new_offset) = self.parse_value_type(data, offset)?;
1820+
offset = new_offset;
1821+
let ref_type = wrt_format::types::RefType::try_from(vt).map_err(|_| {
1822+
Error::parse_error("Invalid element segment reference type")
1823+
})?;
18631824

18641825
#[cfg(feature = "tracing")]
18651826
trace!(elem_idx = elem_idx, table_index = table_index, offset_expr_len = offset_expr_bytes.len(), ref_type = ?ref_type, "element: active with expressions");
@@ -1875,13 +1836,11 @@ impl<'a> StreamingDecoder<'a> {
18751836
},
18761837
7 => {
18771838
// Declarative, expressions with type
1878-
let ref_type_byte = data[offset];
1879-
offset += 1;
1880-
let ref_type = match ref_type_byte {
1881-
0x70 => wrt_format::types::RefType::Funcref,
1882-
0x6F => wrt_format::types::RefType::Externref,
1883-
_ => wrt_format::types::RefType::Funcref,
1884-
};
1839+
let (vt, new_offset) = self.parse_value_type(data, offset)?;
1840+
offset = new_offset;
1841+
let ref_type = wrt_format::types::RefType::try_from(vt).map_err(|_| {
1842+
Error::parse_error("Invalid element segment reference type")
1843+
})?;
18851844
#[cfg(feature = "tracing")]
18861845
trace!(elem_idx = elem_idx, ref_type = ?ref_type, "element: declarative with type");
18871846
(PureElementMode::Declared, Vec::new(), ref_type)
@@ -2050,34 +2009,40 @@ impl<'a> StreamingDecoder<'a> {
20502009

20512010
// Code section index i corresponds to module-defined function at index (num_imports + i)
20522011
let func_index = num_imports + i as usize;
2053-
if let Some(func) = self.module.functions.get_mut(func_index) {
2054-
// Parse local variable declarations
2055-
for _ in 0..local_count {
2056-
let (count, bytes) = read_leb128_u32(&data[body_start..body_end], body_offset)?;
2057-
body_offset += bytes;
20582012

2059-
if body_offset >= body_size as usize {
2060-
return Err(Error::parse_error("Unexpected end of function body"));
2061-
}
2013+
// Parse local variable declarations first (requires &self for parse_value_type)
2014+
// We collect locals into a temporary vec to avoid borrow conflicts with self.module
2015+
let mut parsed_locals: Vec<(u32, wrt_foundation::types::ValueType)> = Vec::new();
2016+
let mut total_locals_count: usize = 0;
2017+
for _ in 0..local_count {
2018+
let (count, bytes) = read_leb128_u32(&data[body_start..body_end], body_offset)?;
2019+
body_offset += bytes;
20622020

2063-
let value_type = data[body_start + body_offset];
2064-
body_offset += 1;
2065-
2066-
// Convert to ValueType and add to locals
2067-
let vt = match value_type {
2068-
0x7F => wrt_foundation::types::ValueType::I32,
2069-
0x7E => wrt_foundation::types::ValueType::I64,
2070-
0x7D => wrt_foundation::types::ValueType::F32,
2071-
0x7C => wrt_foundation::types::ValueType::F64,
2072-
0x7B => wrt_foundation::types::ValueType::V128,
2073-
0x70 => wrt_foundation::types::ValueType::FuncRef,
2074-
0x6F => wrt_foundation::types::ValueType::ExternRef,
2075-
0x69 => wrt_foundation::types::ValueType::ExnRef,
2076-
_ => return Err(Error::parse_error("Invalid local type")),
2077-
};
2021+
if body_offset >= body_size as usize {
2022+
return Err(Error::parse_error("Unexpected end of function body"));
2023+
}
2024+
2025+
// Use the full GC-aware value type parser for local types
2026+
let (vt, new_abs_offset) =
2027+
self.parse_value_type(data, body_start + body_offset)?;
2028+
body_offset = new_abs_offset - body_start;
20782029

2079-
// Validate total locals against platform limits before allocation
2080-
let new_total = func.locals.len() + count as usize;
2030+
// Validate total locals against platform limits before allocation
2031+
total_locals_count += count as usize;
2032+
if total_locals_count > limits::MAX_FUNCTION_LOCALS {
2033+
return Err(Error::parse_error(
2034+
"Function exceeds maximum local count for platform",
2035+
));
2036+
}
2037+
2038+
parsed_locals.push((count, vt));
2039+
}
2040+
2041+
// Now apply the parsed locals to the function (requires &mut self.module)
2042+
if let Some(func) = self.module.functions.get_mut(func_index) {
2043+
for (count, vt) in &parsed_locals {
2044+
// Validate total locals including existing ones
2045+
let new_total = func.locals.len() + *count as usize;
20812046
if new_total > limits::MAX_FUNCTION_LOCALS {
20822047
return Err(Error::parse_error(
20832048
"Function exceeds maximum local count for platform",
@@ -2089,12 +2054,12 @@ impl<'a> StreamingDecoder<'a> {
20892054
AllocationPhase::Decode,
20902055
"streaming_decoder:func_locals",
20912056
"locals",
2092-
count as usize
2057+
*count as usize
20932058
);
20942059

20952060
// Add 'count' locals of this type
2096-
for _ in 0..count {
2097-
func.locals.push(vt);
2061+
for _ in 0..*count {
2062+
func.locals.push(*vt);
20982063
}
20992064
}
21002065

wrt-format/src/binary.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,11 +2301,9 @@ pub mod with_alloc {
23012301
})?;
23022302
offset += 1;
23032303
let value_type = ValueType::from_binary(rt_byte)?;
2304-
element_type = match value_type {
2305-
ValueType::FuncRef => RefType::Funcref,
2306-
ValueType::ExternRef => RefType::Externref,
2307-
_ => return Err(parse_error("Invalid ref type for element")),
2308-
};
2304+
element_type = RefType::try_from(value_type).map_err(|_| {
2305+
parse_error("Invalid ref type for element")
2306+
})?;
23092307

23102308
let (exprs_vec, next_offset) = read_vector(bytes, offset, parse_init_expr)
23112309
.map_err(|e| {
@@ -2354,11 +2352,9 @@ pub mod with_alloc {
23542352
})?;
23552353
offset += 1;
23562354
let value_type = ValueType::from_binary(rt_byte)?;
2357-
element_type = match value_type {
2358-
ValueType::FuncRef => RefType::Funcref,
2359-
ValueType::ExternRef => RefType::Externref,
2360-
_ => return Err(parse_error("Invalid ref type for element")),
2361-
};
2355+
element_type = RefType::try_from(value_type).map_err(|_| {
2356+
parse_error("Invalid ref type for element")
2357+
})?;
23622358

23632359
let (exprs_vec, next_offset) = read_vector(bytes, offset, parse_init_expr)
23642360
.map_err(|e| {
@@ -2395,11 +2391,9 @@ pub mod with_alloc {
23952391
})?;
23962392
offset += 1;
23972393
let value_type = ValueType::from_binary(rt_byte)?;
2398-
element_type = match value_type {
2399-
ValueType::FuncRef => RefType::Funcref,
2400-
ValueType::ExternRef => RefType::Externref,
2401-
_ => return Err(parse_error("Invalid ref type for element")),
2402-
};
2394+
element_type = RefType::try_from(value_type).map_err(|_| {
2395+
parse_error("Invalid ref type for element")
2396+
})?;
24032397

24042398
let (exprs_vec, next_offset) = read_vector(bytes, offset, parse_init_expr)
24052399
.map_err(|e| {

wrt-format/src/pure_format_types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ impl wrt_foundation::traits::ToBytes for PureElementSegment {
568568
let element_type_byte = match self.element_type {
569569
crate::types::RefType::Funcref => 0u8,
570570
crate::types::RefType::Externref => 1u8,
571+
crate::types::RefType::Gc(_) => 1u8, // GC ref types serialize as externref for binary format
571572
};
572573
writer.write_all(&[element_type_byte])?;
573574
self.mode.to_bytes_with_provider(writer, provider)?;

wrt-foundation/src/conversion.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub fn ref_type_to_val_type(ref_type: RefType) -> CoreValueType {
4343
match ref_type {
4444
RefType::Funcref => CoreValueType::FuncRef,
4545
RefType::Externref => CoreValueType::ExternRef,
46+
RefType::Gc(gc) => gc.to_value_type(),
4647
}
4748
}
4849

0 commit comments

Comments
 (0)