33use crate :: generators:: gc_ops:: types:: StackType ;
44use crate :: generators:: gc_ops:: {
55 limits:: GcOpsLimits ,
6- types:: { CompositeType , RecGroupId , TypeId , Types } ,
6+ types:: { CompositeType , RecGroupId , StructField , TypeId , Types } ,
77} ;
88use mutatis:: Generate ;
99use serde:: { Deserialize , Serialize } ;
@@ -24,6 +24,21 @@ fn pick_type_index(indices: &[u32], raw: u32) -> Option<u32> {
2424 }
2525}
2626
27+ /// Returns the element field if the indexed type is an array
28+ fn array_element < ' a > (
29+ types : & ' a Types ,
30+ encoding_order : & [ TypeId ] ,
31+ type_index : u32 ,
32+ ) -> Option < & ' a StructField > {
33+ encoding_order
34+ . get ( usize:: try_from ( type_index) . unwrap ( ) )
35+ . and_then ( |tid| types. type_defs . get ( tid) )
36+ . and_then ( |def| match & def. composite_type {
37+ CompositeType :: Array ( at) => Some ( & at. element ) ,
38+ CompositeType :: Struct ( _) => None ,
39+ } )
40+ }
41+
2742/// The base offsets and indices for various Wasm entities within
2843/// their index spaces in the the encoded Wasm binary.
2944#[ derive( Clone , Copy ) ]
@@ -35,6 +50,7 @@ struct WasmEncodingBases {
3550 i31_local_idx : u32 ,
3651 array_local_idx : u32 ,
3752 typed_local_base : u32 ,
53+ typed_local2_base : u32 ,
3854 struct_global_idx : u32 ,
3955 eq_global_idx : u32 ,
4056 i31_global_idx : u32 ,
@@ -482,15 +498,18 @@ impl GcOps {
482498 ) ) ;
483499
484500 let typed_local_base: u32 = array_local_idx + 1 ;
485- for i in 0 ..concrete_count {
486- let concrete = struct_type_base + i;
487- local_decls. push ( (
488- 1 ,
489- ValType :: Ref ( RefType {
490- nullable : true ,
491- heap_type : wasm_encoder:: HeapType :: Concrete ( concrete) ,
492- } ) ,
493- ) ) ;
501+ let typed_local2_base: u32 = typed_local_base + concrete_count;
502+ for _ in 0 ..2 {
503+ for i in 0 ..concrete_count {
504+ let concrete = struct_type_base + i;
505+ local_decls. push ( (
506+ 1 ,
507+ ValType :: Ref ( RefType {
508+ nullable : true ,
509+ heap_type : wasm_encoder:: HeapType :: Concrete ( concrete) ,
510+ } ) ,
511+ ) ) ;
512+ }
494513 }
495514
496515 let storage_bases = WasmEncodingBases {
@@ -501,6 +520,7 @@ impl GcOps {
501520 i31_local_idx,
502521 array_local_idx,
503522 typed_local_base,
523+ typed_local2_base,
504524 struct_global_idx,
505525 eq_global_idx,
506526 i31_global_idx,
@@ -697,6 +717,13 @@ macro_rules! for_each_gc_op {
697717 } ) ]
698718 StructNew { type_index: u32 } ,
699719
720+ #[ operands( [ ] ) ]
721+ #[ results( [ Struct ( Some ( type_index) ) ] ) ]
722+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
723+ type_index = pick_type_index( struct_type_indices, type_index) ?;
724+ } ) ]
725+ StructNewDefault { type_index: u32 } ,
726+
700727 #[ operands( [ Some ( Struct ( None ) ) ] ) ]
701728 #[ results( [ ] ) ]
702729 TakeStructCall ,
@@ -874,6 +901,13 @@ macro_rules! for_each_gc_op {
874901 } ) ]
875902 StructGet { type_index: u32 , field_index: u32 } ,
876903
904+ #[ operands( [ Some ( Struct ( Some ( type_index) ) ) ] ) ]
905+ #[ results( [ ] ) ]
906+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
907+ type_index = pick_type_index( struct_type_indices, type_index) ?;
908+ } ) ]
909+ StructGetU { type_index: u32 , field_index: u32 } ,
910+
877911 #[ operands( [ Some ( Struct ( Some ( type_index) ) ) ] ) ]
878912 #[ results( [ ] ) ]
879913 #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
@@ -954,13 +988,28 @@ macro_rules! for_each_gc_op {
954988 #[ results( [ Eq ] ) ]
955989 I31RefAsEq ,
956990
991+ #[ operands( [ ] ) ]
992+ #[ results( [ Array ( Some ( type_index) ) ] ) ]
993+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
994+ type_index = pick_type_index( array_type_indices, type_index) ?;
995+ } ) ]
996+ ArrayNewDefault { type_index: u32 } ,
997+
957998 #[ operands( [ ] ) ]
958999 #[ results( [ Array ( Some ( type_index) ) ] ) ]
9591000 #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
9601001 type_index = pick_type_index( array_type_indices, type_index) ?;
9611002 } ) ]
9621003 ArrayNew { type_index: u32 } ,
9631004
1005+ #[ operands( [ ] ) ]
1006+ #[ results( [ Array ( Some ( type_index) ) ] ) ]
1007+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
1008+ n = n % ( limits. array_length + 1 ) ;
1009+ type_index = pick_type_index( array_type_indices, type_index) ?;
1010+ } ) ]
1011+ ArrayNewFixed { type_index: u32 , n: u32 } ,
1012+
9641013 #[ operands( [ ] ) ]
9651014 #[ results( [ Array ( None ) ] ) ]
9661015 NullArray ,
@@ -1092,6 +1141,14 @@ macro_rules! for_each_gc_op {
10921141 } ) ]
10931142 ArrayGet { type_index: u32 , index: u32 } ,
10941143
1144+ #[ operands( [ Some ( Array ( Some ( type_index) ) ) ] ) ]
1145+ #[ results( [ ] ) ]
1146+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
1147+ index = index % ( limits. array_length + 1 ) ;
1148+ type_index = pick_type_index( array_type_indices, type_index) ?;
1149+ } ) ]
1150+ ArrayGetU { type_index: u32 , index: u32 } ,
1151+
10951152 #[ operands( [ Some ( Array ( Some ( type_index) ) ) ] ) ]
10961153 #[ results( [ ] ) ]
10971154 #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
@@ -1100,6 +1157,25 @@ macro_rules! for_each_gc_op {
11001157 } ) ]
11011158 ArraySet { type_index: u32 , index: u32 } ,
11021159
1160+ #[ operands( [ Some ( Array ( Some ( type_index) ) ) ] ) ]
1161+ #[ results( [ ] ) ]
1162+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
1163+ offset = offset % ( limits. array_length + 1 ) ;
1164+ len = len % ( limits. array_length - offset + 2 ) ;
1165+ type_index = pick_type_index( array_type_indices, type_index) ?;
1166+ } ) ]
1167+ ArrayFill { type_index: u32 , offset: u32 , len: u32 } ,
1168+
1169+ #[ operands( [ Some ( Array ( Some ( type_index) ) ) , Some ( Array ( Some ( type_index) ) ) ] ) ]
1170+ #[ results( [ ] ) ]
1171+ #[ fixup( |limits, num_types, struct_type_indices, array_type_indices| {
1172+ dst_offset = dst_offset % ( limits. array_length + 1 ) ;
1173+ src_offset = src_offset % ( limits. array_length + 1 ) ;
1174+ len = len % ( limits. array_length - dst_offset. max( src_offset) + 2 ) ;
1175+ type_index = pick_type_index( array_type_indices, type_index) ?;
1176+ } ) ]
1177+ ArrayCopy { type_index: u32 , dst_offset: u32 , src_offset: u32 , len: u32 } ,
1178+
11031179 #[ operands( [ Some ( Array ( None ) ) ] ) ]
11041180 #[ results( [ ] ) ]
11051181 ArrayLen ,
@@ -1394,7 +1470,12 @@ impl GcOp {
13941470 }
13951471 func. instruction ( & Instruction :: StructNew ( encoding_bases. struct_type_base + x) ) ;
13961472 }
1397- Self :: ArrayNew { type_index : x } => {
1473+ Self :: StructNewDefault { type_index : x } => {
1474+ func. instruction ( & Instruction :: StructNewDefault (
1475+ encoding_bases. struct_type_base + x,
1476+ ) ) ;
1477+ }
1478+ Self :: ArrayNewDefault { type_index : x } => {
13981479 // Create a default-initialized array of a fixed length so most
13991480 // subsequent indexed accesses are in-bounds.
14001481 func. instruction ( & Instruction :: I32Const (
@@ -1404,6 +1485,30 @@ impl GcOp {
14041485 encoding_bases. struct_type_base + x,
14051486 ) ) ;
14061487 }
1488+ Self :: ArrayNew { type_index : x } => {
1489+ if let Some ( element) = array_element ( types, encoding_order, x) {
1490+ element
1491+ . field_type
1492+ . emit_default_const ( func, type_ids_to_index) ;
1493+ }
1494+ func. instruction ( & Instruction :: I32Const (
1495+ encoding_bases. array_length . cast_signed ( ) ,
1496+ ) ) ;
1497+ func. instruction ( & Instruction :: ArrayNew ( encoding_bases. struct_type_base + x) ) ;
1498+ }
1499+ Self :: ArrayNewFixed { type_index : x, n } => {
1500+ if let Some ( element) = array_element ( types, encoding_order, x) {
1501+ for _ in 0 ..n {
1502+ element
1503+ . field_type
1504+ . emit_default_const ( func, type_ids_to_index) ;
1505+ }
1506+ }
1507+ func. instruction ( & Instruction :: ArrayNewFixed {
1508+ array_type_index : encoding_bases. struct_type_base + x,
1509+ array_size : n,
1510+ } ) ;
1511+ }
14071512 Self :: TakeStructCall => {
14081513 func. instruction ( & Instruction :: Call ( take_structref_idx) ) ;
14091514 }
@@ -1561,6 +1666,10 @@ impl GcOp {
15611666 Self :: StructGet {
15621667 type_index,
15631668 field_index,
1669+ }
1670+ | Self :: StructGetU {
1671+ type_index,
1672+ field_index,
15641673 } => {
15651674 let wasm_type = encoding_bases. struct_type_base + type_index;
15661675 let fields = encoding_order
@@ -1582,10 +1691,17 @@ impl GcOp {
15821691 func. instruction ( & Instruction :: LocalGet ( typed_local) ) ;
15831692 let idx = field_index % u32:: try_from ( fields. len ( ) ) . unwrap ( ) ;
15841693 if fields[ usize:: try_from ( idx) . unwrap ( ) ] . field_type . is_packed ( ) {
1585- func. instruction ( & Instruction :: StructGetS {
1586- struct_type_index : wasm_type,
1587- field_index : idx,
1588- } ) ;
1694+ if matches ! ( self , Self :: StructGetU { .. } ) {
1695+ func. instruction ( & Instruction :: StructGetU {
1696+ struct_type_index : wasm_type,
1697+ field_index : idx,
1698+ } ) ;
1699+ } else {
1700+ func. instruction ( & Instruction :: StructGetS {
1701+ struct_type_index : wasm_type,
1702+ field_index : idx,
1703+ } ) ;
1704+ }
15891705 } else {
15901706 func. instruction ( & Instruction :: StructGet {
15911707 struct_type_index : wasm_type,
@@ -1767,7 +1883,7 @@ impl GcOp {
17671883 func. instruction ( & Instruction :: LocalGet ( encoding_bases. array_local_idx ) ) ;
17681884 func. instruction ( & Instruction :: TableSet ( encoding_bases. array_table_idx ) ) ;
17691885 }
1770- Self :: ArrayGet { type_index, index } => {
1886+ Self :: ArrayGet { type_index, index } | Self :: ArrayGetU { type_index , index } => {
17711887 let wasm_type = encoding_bases. struct_type_base + type_index;
17721888 let typed_local = encoding_bases. typed_local_base + type_index;
17731889 let element = encoding_order
@@ -1789,7 +1905,11 @@ impl GcOp {
17891905 func. instruction ( & Instruction :: LocalGet ( typed_local) ) ;
17901906 func. instruction ( & Instruction :: I32Const ( index. cast_signed ( ) ) ) ;
17911907 if element. field_type . is_packed ( ) {
1792- func. instruction ( & Instruction :: ArrayGetS ( wasm_type) ) ;
1908+ if matches ! ( self , Self :: ArrayGetU { .. } ) {
1909+ func. instruction ( & Instruction :: ArrayGetU ( wasm_type) ) ;
1910+ } else {
1911+ func. instruction ( & Instruction :: ArrayGetS ( wasm_type) ) ;
1912+ }
17931913 } else {
17941914 func. instruction ( & Instruction :: ArrayGet ( wasm_type) ) ;
17951915 }
@@ -1834,6 +1954,70 @@ impl GcOp {
18341954 }
18351955 }
18361956 }
1957+ Self :: ArrayFill {
1958+ type_index,
1959+ offset,
1960+ len,
1961+ } => {
1962+ let wasm_type = encoding_bases. struct_type_base + type_index;
1963+ let typed_local = encoding_bases. typed_local_base + type_index;
1964+ match array_element ( types, encoding_order, type_index) {
1965+ Some ( element) if element. mutable => {
1966+ func. instruction ( & Instruction :: LocalTee ( typed_local) ) ;
1967+ func. instruction ( & Instruction :: RefIsNull ) ;
1968+ func. instruction ( & Instruction :: If ( wasm_encoder:: BlockType :: Empty ) ) ;
1969+ func. instruction ( & Instruction :: Else ) ;
1970+ func. instruction ( & Instruction :: LocalGet ( typed_local) ) ;
1971+ func. instruction ( & Instruction :: I32Const ( offset. cast_signed ( ) ) ) ;
1972+ element
1973+ . field_type
1974+ . emit_default_const ( func, type_ids_to_index) ;
1975+ func. instruction ( & Instruction :: I32Const ( len. cast_signed ( ) ) ) ;
1976+ func. instruction ( & Instruction :: ArrayFill ( wasm_type) ) ;
1977+ func. instruction ( & Instruction :: End ) ;
1978+ }
1979+ _ => {
1980+ func. instruction ( & Instruction :: Drop ) ;
1981+ }
1982+ }
1983+ }
1984+ Self :: ArrayCopy {
1985+ type_index,
1986+ dst_offset,
1987+ src_offset,
1988+ len,
1989+ } => {
1990+ let wasm_type = encoding_bases. struct_type_base + type_index;
1991+ let dst_local = encoding_bases. typed_local_base + type_index;
1992+ let src_local = encoding_bases. typed_local2_base + type_index;
1993+ match array_element ( types, encoding_order, type_index) {
1994+ Some ( element) if element. mutable => {
1995+ func. instruction ( & Instruction :: LocalSet ( src_local) ) ;
1996+ func. instruction ( & Instruction :: LocalSet ( dst_local) ) ;
1997+ func. instruction ( & Instruction :: LocalGet ( dst_local) ) ;
1998+ func. instruction ( & Instruction :: RefIsNull ) ;
1999+ func. instruction ( & Instruction :: LocalGet ( src_local) ) ;
2000+ func. instruction ( & Instruction :: RefIsNull ) ;
2001+ func. instruction ( & Instruction :: I32Or ) ;
2002+ func. instruction ( & Instruction :: If ( wasm_encoder:: BlockType :: Empty ) ) ;
2003+ func. instruction ( & Instruction :: Else ) ;
2004+ func. instruction ( & Instruction :: LocalGet ( dst_local) ) ;
2005+ func. instruction ( & Instruction :: I32Const ( dst_offset. cast_signed ( ) ) ) ;
2006+ func. instruction ( & Instruction :: LocalGet ( src_local) ) ;
2007+ func. instruction ( & Instruction :: I32Const ( src_offset. cast_signed ( ) ) ) ;
2008+ func. instruction ( & Instruction :: I32Const ( len. cast_signed ( ) ) ) ;
2009+ func. instruction ( & Instruction :: ArrayCopy {
2010+ array_type_index_dst : wasm_type,
2011+ array_type_index_src : wasm_type,
2012+ } ) ;
2013+ func. instruction ( & Instruction :: End ) ;
2014+ }
2015+ _ => {
2016+ func. instruction ( & Instruction :: Drop ) ;
2017+ func. instruction ( & Instruction :: Drop ) ;
2018+ }
2019+ }
2020+ }
18372021 Self :: ArrayLen => {
18382022 // array.len traps on null, so guard; the length is not tracked.
18392023 func. instruction ( & Instruction :: LocalTee ( encoding_bases. array_local_idx ) ) ;
0 commit comments