@@ -561,10 +561,7 @@ impl<'store> Executor<'store> {
561561 fn throw_exception ( & mut self , exception : ValueRef , protected_ip : usize ) -> ExecResult < ExecFlow > {
562562 match self . dispatch_exception ( exception, protected_ip) ? {
563563 Some ( landing_pad) => Ok ( ExecFlow :: next ( landing_pad) ) ,
564- None => match self . store . root_exception ( exception) {
565- Ok ( exception) => Err ( Error :: Exception ( exception) . into ( ) ) ,
566- Err ( error) => Err ( error. into ( ) ) ,
567- } ,
564+ None => Err ( Error :: Exception ( self . store . root_exception ( exception) ?) . into ( ) ) ,
568565 }
569566 }
570567
@@ -734,6 +731,7 @@ impl<'store> Executor<'store> {
734731 let type_addr = operand. a ( ) ;
735732 let table_addr = operand. b ( ) ;
736733 self . charge_call_fuel ( FUEL_COST_CALL_TOTAL ) ;
734+
737735 // verify that the table is of the right type, this should be validated by the parser already
738736 let table_addr = self . module . resolve_table_addr ( table_addr) ;
739737 let table_idx = self . pop_table_operand ( self . store . state . get_table ( table_addr) . kind . arch ( ) ) ?;
@@ -1100,14 +1098,13 @@ impl<'store> Executor<'store> {
11001098 let type_index = operand. a ( ) ;
11011099 let len = operand. b ( ) ;
11021100 let type_addr = self . module . resolve_type_addr ( type_index) ;
1103- let storage =
1104- self . store . state . get_type ( type_addr) . as_array ( ) . expect ( "validated array.new_fixed type" ) . field . storage ;
1101+ let arr_type = self . store . state . get_type ( type_addr) . as_array ( ) . expect ( "validated array.new_fixed type" ) ;
11051102 let len = len as usize ;
11061103 self . store . state . gc . check_allocation ( len, self . store . state . gc_type_has_references ( type_addr) ) ?;
11071104 let mut values = Vec :: new ( ) ;
11081105 cold_err ! ( values. try_reserve_exact( len) ) . map_err ( |_| Trap :: OutOfMemory ) ?;
11091106 for _ in 0 ..len {
1110- values. push ( pop_value ( & mut self . store . value_stack , storage) ) ;
1107+ values. push ( pop_value ( & mut self . store . value_stack , arr_type . field . storage ) ) ;
11111108 }
11121109 values. reverse ( ) ;
11131110 self . push_gc_object ( type_addr, values)
@@ -1257,8 +1254,8 @@ impl<'store> Executor<'store> {
12571254 let object = self . store . state . gc_object ( reference, type_addr) ?;
12581255 let object_len = self . store . state . gc . get_handle ( object) . expect ( "validated array" ) . values . len ( ) ;
12591256 dst. checked_add ( len) . filter ( |end| * end <= object_len) . ok_or ( Trap :: ArrayOutOfBounds ) ?;
1260- let items =
1261- self . store . state . elements [ self . module . resolve_elem_addr ( elem_index ) as usize ] . items_range ( src, len) ?;
1257+ let elem_addr = self . module . resolve_elem_addr ( elem_index ) ;
1258+ let items = self . store . state . elements [ elem_addr as usize ] . items_range ( src, len) ?;
12621259 let mut values = Vec :: new ( ) ;
12631260 cold_err ! ( values. try_reserve_exact( len) ) . map_err ( |_| Trap :: OutOfMemory ) ?;
12641261 values. extend ( items. iter ( ) . copied ( ) . map ( RuntimeValue :: ValueRef ) ) ;
@@ -1267,11 +1264,9 @@ impl<'store> Executor<'store> {
12671264 }
12681265
12691266 fn exec_memory_size ( & mut self , addr : u32 ) -> Result < ( ) , Trap > {
1270- let mem_addr = self . mem_addr ( addr) ;
1271- let ( arch, pages) = self . store . state . memory_size ( mem_addr) ;
1272- match arch {
1273- MemoryArch :: I64 => i64:: stack_push ( & mut self . store . value_stack , pages as i64 ) ,
1274- MemoryArch :: I32 => i32:: stack_push ( & mut self . store . value_stack , pages as i32 ) ,
1267+ match self . store . state . memory_size ( self . mem_addr ( addr) ) {
1268+ ( MemoryArch :: I64 , pages) => i64:: stack_push ( & mut self . store . value_stack , pages as i64 ) ,
1269+ ( MemoryArch :: I32 , pages) => i32:: stack_push ( & mut self . store . value_stack , pages as i32 ) ,
12751270 }
12761271 }
12771272
@@ -1441,24 +1436,65 @@ impl<'store> Executor<'store> {
14411436 }
14421437 }
14431438
1439+ fn exec_atomic_wait ( & mut self , arg : Operand128Idx < MemoryOperand > , op : AtomicWaitOp ) -> Result < ( ) , Trap > {
1440+ let timeout = if op == AtomicWaitOp :: Notify { 0 } else { i64:: stack_pop ( & mut self . store . value_stack ) } ;
1441+ let value = match op {
1442+ AtomicWaitOp :: Wait64 => u64:: stack_pop ( & mut self . store . value_stack ) ,
1443+ _ => u32:: stack_pop ( & mut self . store . value_stack ) as u64 ,
1444+ } ;
1445+ let memory = arg. resolve ( & self . func . data ) ;
1446+ let mem_addr = self . mem_addr ( memory. memory ( ) ) ;
1447+ let width = if op == AtomicWaitOp :: Wait64 { 8 } else { 4 } ;
1448+ let addr = crate :: store:: with_memory!( self . store. state, mem_addr, |mem, kind| {
1449+ let base = self . store. value_stack. pop_memory_operand( kind. arch( ) ) ?;
1450+ let addr = cold_err!( mem. effective_addr:: <1 >( base, memory. offset( ) ) ) ?;
1451+ if addr % width != 0 {
1452+ return cold!( Err ( Trap :: UnalignedAtomic ) ) ;
1453+ }
1454+
1455+ if op != AtomicWaitOp :: Notify && !kind. shared( ) {
1456+ return cold!( Err ( Trap :: Other ( "atomic wait requires shared memory" ) ) ) ;
1457+ }
1458+
1459+ // Check the entire access even for notify and even when no waiter exists.
1460+ if mem. checked_range( addr, width) . is_none( ) {
1461+ return cold!( Err ( Trap :: MemoryOutOfBounds { offset: addr, len: width, max: mem. len( ) } ) ) ;
1462+ }
1463+
1464+ Ok ( addr)
1465+ } ) ?;
1466+
1467+ #[ cfg( not( feature = "std" ) ) ]
1468+ let _ = ( timeout, value, addr) ;
1469+
1470+ #[ cfg( feature = "std" ) ]
1471+ if mem_addr & crate :: store:: SHARED_MEM_BIT != 0 {
1472+ let shared = & self . store . state . shared_memories [ ( mem_addr & !crate :: store:: SHARED_MEM_BIT ) as usize ] ;
1473+ let result = match op {
1474+ AtomicWaitOp :: Notify => shared. notify ( addr, value as u32 ) ,
1475+ AtomicWaitOp :: Wait32 => shared. wait :: < 4 > ( addr, value, timeout) ?,
1476+ AtomicWaitOp :: Wait64 => shared. wait :: < 8 > ( addr, value, timeout) ?,
1477+ } ;
1478+ return u32:: stack_push ( & mut self . store . value_stack , result) ;
1479+ }
1480+
1481+ u32:: stack_push ( & mut self . store . value_stack , 0 )
1482+ }
1483+
14441484 fn exec_atomic_width < const N : usize > ( & mut self , arg : AtomicArg ) -> Result < ( ) , Trap > {
14451485 let op = arg. op ( ) ;
1446- let value = if op == AtomicOp :: Load {
1447- 0
1448- } else if arg. is_64 ( ) {
1449- u64:: stack_pop ( & mut self . store . value_stack )
1450- } else {
1451- u32:: stack_pop ( & mut self . store . value_stack ) as u64
1486+ let value = match op {
1487+ AtomicOp :: Load => 0 ,
1488+ _ if arg. is_64 ( ) => u64:: stack_pop ( & mut self . store . value_stack ) ,
1489+ _ => u32:: stack_pop ( & mut self . store . value_stack ) as u64 ,
14521490 } ;
1453- let expected = if op == AtomicOp :: Cmpxchg {
1454- if arg. is_64 ( ) {
1455- u64:: stack_pop ( & mut self . store . value_stack )
1456- } else {
1457- u32:: stack_pop ( & mut self . store . value_stack ) as u64
1458- }
1459- } else {
1460- 0
1491+
1492+ let expected = match op {
1493+ AtomicOp :: Cmpxchg if arg. is_64 ( ) => u64:: stack_pop ( & mut self . store . value_stack ) ,
1494+ AtomicOp :: Cmpxchg => u32:: stack_pop ( & mut self . store . value_stack ) as u64 ,
1495+ _ => 0 ,
14611496 } ;
1497+
14621498 let memory = arg. memory . resolve ( & self . func . data ) ;
14631499 let mem_addr = self . mem_addr ( memory. memory ( ) ) ;
14641500 crate :: store:: with_memory!( self . store. state, mem_addr, |mem, kind| {
@@ -1493,10 +1529,10 @@ impl<'store> Executor<'store> {
14931529 bytes. copy_from_slice( & next. to_le_bytes( ) [ ..N ] ) ;
14941530 cold_err!( mem. write_fixed:: <N >( addr, & bytes) ) ?;
14951531 }
1496- if arg . is_64 ( ) {
1497- u64 :: stack_push ( & mut self . store . value_stack , old ) ? ;
1498- } else {
1499- u32 :: stack_push( & mut self . store. value_stack, old as u32 ) ?;
1532+
1533+ match arg . is_64 ( ) {
1534+ true => u64 :: stack_push ( & mut self . store . value_stack , old ) ? ,
1535+ false => u32 :: stack_push( & mut self . store. value_stack, old as u32 ) ?,
15001536 }
15011537 Ok ( ( ) )
15021538 } )
@@ -1580,19 +1616,16 @@ impl<'store> Executor<'store> {
15801616
15811617 fn exec_table_init ( & mut self , index : Operand64Idx < ( u32 , u32 ) > ) -> Result < ( ) , Trap > {
15821618 let operand = index. resolve ( & self . func . data ) ;
1583- let elem_index = operand. a ( ) ;
1584- let table_index = operand. b ( ) ;
15851619 let size = self . pop_table_operand ( MemoryArch :: I32 ) ?; // n
15861620 let offset = self . pop_table_operand ( MemoryArch :: I32 ) ?; // s
1587- let table_addr = self . module . resolve_table_addr ( table_index ) ;
1621+ let table_addr = self . module . resolve_table_addr ( operand . b ( ) ) ;
15881622 let dst = self . pop_table_operand ( self . store . state . get_table ( table_addr) . kind . arch ( ) ) ?; // d
1589- let elem_addr = self . module . resolve_elem_addr ( elem_index ) as usize ;
1623+ let elem_addr = self . module . resolve_elem_addr ( operand . a ( ) ) as usize ;
15901624 let elem = self . store . state . elements . get ( elem_addr) . ok_or_else ( || Trap :: Other ( "element not found" ) ) ?;
15911625 let items = elem. items_range ( offset, size) ?;
15921626
1593- let table =
1594- self . store . state . tables . get_mut ( table_addr as usize ) . ok_or_else ( || Trap :: Other ( "table not found" ) ) ?;
1595- table. init ( dst, items)
1627+ let table = self . store . state . tables . get_mut ( table_addr as usize ) ;
1628+ table. ok_or_else ( || Trap :: Other ( "table not found" ) ) ?. init ( dst, items)
15961629 }
15971630
15981631 fn exec_table_grow ( & mut self , table_index : u32 ) -> Result < ( ) , Trap > {
0 commit comments