@@ -10,6 +10,7 @@ use crate::{
1010 executor:: handler:: {
1111 state:: DoneReason ,
1212 utils:: {
13+ exec_copy_span,
1314 exec_copy_span_asc,
1415 exec_copy_span_des,
1516 extract_mem0,
@@ -29,7 +30,7 @@ use crate::{
2930 ir:: { Slot , SlotSpan } ,
3031 TrapCode ,
3132} ;
32- use core:: ptr:: NonNull ;
33+ use core:: { cmp , ptr:: NonNull } ;
3334
3435unsafe fn decode_op < Op : ir:: Decode > ( ip : Ip ) -> ( Ip , Op ) {
3536 let ip = match cfg ! ( feature = "compact" ) {
@@ -429,6 +430,57 @@ pub fn memory_grow(
429430 dispatch ! ( state, ip, sp, mem0, mem0_len, instance)
430431}
431432
433+ /// Fetches the branch table index value and normalizes it to clamp between `0..len_targets`.
434+ fn fetch_branch_table_target ( sp : Sp , index : Slot , len_targets : u32 ) -> usize {
435+ let index: u32 = get_value ( index, sp) ;
436+ let max_index = len_targets - 1 ;
437+ cmp:: min ( index, max_index) as usize
438+ }
439+
440+ pub fn branch_table (
441+ state : & mut VmState ,
442+ ip : Ip ,
443+ sp : Sp ,
444+ mem0 : Mem0Ptr ,
445+ mem0_len : Mem0Len ,
446+ instance : NonNull < InstanceEntity > ,
447+ ) -> Done {
448+ let ( ip, crate :: ir:: decode:: BranchTable { len_targets, index } ) = unsafe { decode_op ( ip) } ;
449+ let chosen_target = fetch_branch_table_target ( sp, index, len_targets) ;
450+ let target_offset = 4 * chosen_target;
451+ let ip = unsafe { ip. add ( target_offset) } ;
452+ let ( _, offset) = unsafe { ip. decode :: < ir:: BranchOffset > ( ) } ;
453+ let ip = offset_ip ( ip, offset) ;
454+ dispatch ! ( state, ip, sp, mem0, mem0_len, instance)
455+ }
456+
457+ pub fn branch_table_span (
458+ state : & mut VmState ,
459+ ip : Ip ,
460+ sp : Sp ,
461+ mem0 : Mem0Ptr ,
462+ mem0_len : Mem0Len ,
463+ instance : NonNull < InstanceEntity > ,
464+ ) -> Done {
465+ let (
466+ ip,
467+ crate :: ir:: decode:: BranchTableSpan {
468+ len_targets,
469+ index,
470+ values,
471+ len_values,
472+ } ,
473+ ) = unsafe { decode_op ( ip) } ;
474+ let chosen_target = fetch_branch_table_target ( sp, index, len_targets) ;
475+ let target_offset = 6 * chosen_target;
476+ let ip = unsafe { ip. add ( target_offset) } ;
477+ let ( _, ir:: BranchTableTarget { results, offset } ) =
478+ unsafe { ip. decode :: < ir:: BranchTableTarget > ( ) } ;
479+ exec_copy_span ( sp, results, values, len_values) ; // TODO: maybe provide 2 `br_table_span` operation variants if possible
480+ let ip = offset_ip ( ip, offset) ;
481+ dispatch ! ( state, ip, sp, mem0, mem0_len, instance)
482+ }
483+
432484macro_rules! handler_unary {
433485 ( $( fn $handler: ident( $op: ident) = $eval: expr ) ;* $( ; ) ? ) => {
434486 $(
0 commit comments