@@ -796,6 +796,8 @@ where
796796 }
797797 }
798798
799+ /// Returns the corresponding function type for the `func` item located at
800+ /// `function_index`.
799801 fn type_of_function ( & self , function_index : u32 ) -> Result < & ' resources FuncType > {
800802 match self . resources . type_of_function ( function_index) {
801803 Some ( f) => Ok ( f) ,
@@ -808,18 +810,11 @@ where
808810 }
809811 }
810812
811- /// Validates a `call` instruction, ensuring that the function index is
812- /// in-bounds and the right types are on the stack to call the function.
813- fn check_call ( & mut self , function_index : u32 ) -> Result < ( ) > {
814- let ty = self . type_of_function ( function_index) ?;
815- self . check_call_ty ( ty)
816- }
817-
818- fn check_call_type_index ( & mut self , type_index : u32 ) -> Result < ( ) > {
819- let ty = self . func_type_at ( type_index) ?;
820- self . check_call_ty ( ty)
821- }
822-
813+ /// Checks a call-style instruction which will be invoking the function `ty`
814+ /// specified.
815+ ///
816+ /// This will pop parameters from the operand stack for the function's
817+ /// parameters and then push the results of the function on the stack.
823818 fn check_call_ty ( & mut self , ty : & FuncType ) -> Result < ( ) > {
824819 for & ty in ty. params ( ) . iter ( ) . rev ( ) {
825820 debug_assert_type_indices_are_ids ( ty) ;
@@ -832,8 +827,53 @@ where
832827 Ok ( ( ) )
833828 }
834829
835- /// Validates a call to an indirect function, very similar to `check_call`.
836- fn check_call_indirect ( & mut self , index : u32 , table_index : u32 ) -> Result < ( ) > {
830+ /// Similar to `check_call_ty` except used for tail-call instructions.
831+ fn check_return_call_ty ( & mut self , ty : & FuncType ) -> Result < ( ) > {
832+ self . check_func_type_same_results ( ty) ?;
833+ self . check_call_ty ( ty) ?;
834+ self . check_return ( )
835+ }
836+
837+ /// Checks the immediate `type_index` of a `call_ref`-style instruction
838+ /// (also `return_call_ref`).
839+ ///
840+ /// This will validate that the value on the stack is a `(ref type_index)`
841+ /// or a subtype. This will then return the corresponding function type used
842+ /// for this call (to be used with `check_call_ty` or
843+ /// `check_return_call_ty`).
844+ fn check_call_ref_ty ( & mut self , type_index : u32 ) -> Result < & ' resources FuncType > {
845+ let unpacked_index = UnpackedIndex :: Module ( type_index) ;
846+ let mut hty = HeapType :: Concrete ( unpacked_index) ;
847+ self . resources . check_heap_type ( & mut hty, self . offset ) ?;
848+ // If `None` is popped then that means a "bottom" type was popped which
849+ // is always considered equivalent to the `hty` tag.
850+ if let Some ( rt) = self . pop_ref ( ) ? {
851+ let expected = RefType :: new ( true , hty) . expect ( "hty should be previously validated" ) ;
852+ let expected = ValType :: Ref ( expected) ;
853+ if !self . resources . is_subtype ( ValType :: Ref ( rt) , expected) {
854+ bail ! (
855+ self . offset,
856+ "type mismatch: funcref on stack does not match specified type" ,
857+ ) ;
858+ }
859+ }
860+ self . func_type_at ( type_index)
861+ }
862+
863+ /// Validates the immediate operands of a `call_indirect` or
864+ /// `return_call_indirect` instruction.
865+ ///
866+ /// This will validate that `table_index` is valid and a funcref table. It
867+ /// will additionally pop the index argument which is used to index into the
868+ /// table.
869+ ///
870+ /// The return value of this function is the function type behind
871+ /// `type_index` which must then be passedt o `check_{call,return_call}_ty`.
872+ fn check_call_indirect_ty (
873+ & mut self ,
874+ type_index : u32 ,
875+ table_index : u32 ,
876+ ) -> Result < & ' resources FuncType > {
837877 let tab = self . check_table_index ( table_index) ?;
838878 if !self
839879 . resources
@@ -844,15 +884,8 @@ where
844884 "indirect calls must go through a table with type <= funcref" ,
845885 ) ;
846886 }
847- let ty = self . func_type_at ( index) ?;
848887 self . pop_operand ( Some ( tab. index_type ( ) ) ) ?;
849- for ty in ty. clone ( ) . params ( ) . iter ( ) . rev ( ) {
850- self . pop_operand ( Some ( * ty) ) ?;
851- }
852- for ty in ty. results ( ) {
853- self . push_operand ( * ty) ?;
854- }
855- Ok ( ( ) )
888+ self . func_type_at ( type_index)
856889 }
857890
858891 /// Validates a `return` instruction, popping types from the operand
@@ -868,20 +901,6 @@ where
868901 Ok ( ( ) )
869902 }
870903
871- /// Check that the function at the given index has the same result types as
872- /// the current function's results.
873- fn check_func_same_results ( & self , function_index : u32 ) -> Result < ( ) > {
874- let ty = self . type_of_function ( function_index) ?;
875- self . check_func_type_same_results ( ty)
876- }
877-
878- /// Check that the type at the given index has the same result types as the
879- /// current function's results.
880- fn check_func_type_index_same_results ( & self , type_index : u32 ) -> Result < ( ) > {
881- let ty = self . func_type_at ( type_index) ?;
882- self . check_func_type_same_results ( ty)
883- }
884-
885904 /// Check that the given type has the same result types as the current
886905 /// function's results.
887906 fn check_func_type_same_results ( & self , callee_ty : & FuncType ) -> Result < ( ) > {
@@ -1551,47 +1570,33 @@ where
15511570 Ok ( ( ) )
15521571 }
15531572 fn visit_call ( & mut self , function_index : u32 ) -> Self :: Output {
1554- self . check_call ( function_index) ?;
1573+ let ty = self . type_of_function ( function_index) ?;
1574+ self . check_call_ty ( ty) ?;
15551575 Ok ( ( ) )
15561576 }
15571577 fn visit_return_call ( & mut self , function_index : u32 ) -> Self :: Output {
1558- self . check_call ( function_index) ?;
1559- self . check_return ( ) ?;
1560- self . check_func_same_results ( function_index) ?;
1578+ let ty = self . type_of_function ( function_index) ?;
1579+ self . check_return_call_ty ( ty) ?;
15611580 Ok ( ( ) )
15621581 }
15631582 fn visit_call_ref ( & mut self , type_index : u32 ) -> Self :: Output {
1564- let unpacked_index = UnpackedIndex :: Module ( type_index) ;
1565- let mut hty = HeapType :: Concrete ( unpacked_index) ;
1566- self . resources . check_heap_type ( & mut hty, self . offset ) ?;
1567- // If `None` is popped then that means a "bottom" type was popped which
1568- // is always considered equivalent to the `hty` tag.
1569- if let Some ( rt) = self . pop_ref ( ) ? {
1570- let expected = RefType :: new ( true , hty) . expect ( "hty should be previously validated" ) ;
1571- let expected = ValType :: Ref ( expected) ;
1572- if !self . resources . is_subtype ( ValType :: Ref ( rt) , expected) {
1573- bail ! (
1574- self . offset,
1575- "type mismatch: funcref on stack does not match specified type" ,
1576- ) ;
1577- }
1578- }
1579- self . check_call_type_index ( type_index)
1583+ let ty = self . check_call_ref_ty ( type_index) ?;
1584+ self . check_call_ty ( ty) ?;
1585+ Ok ( ( ) )
15801586 }
15811587 fn visit_return_call_ref ( & mut self , type_index : u32 ) -> Self :: Output {
1582- self . visit_call_ref ( type_index) ?;
1583- self . check_return ( ) ?;
1584- self . check_func_type_index_same_results ( type_index) ?;
1588+ let ty = self . check_call_ref_ty ( type_index) ?;
1589+ self . check_return_call_ty ( ty) ?;
15851590 Ok ( ( ) )
15861591 }
1587- fn visit_call_indirect ( & mut self , index : u32 , table_index : u32 ) -> Self :: Output {
1588- self . check_call_indirect ( index, table_index) ?;
1592+ fn visit_call_indirect ( & mut self , type_index : u32 , table_index : u32 ) -> Self :: Output {
1593+ let ty = self . check_call_indirect_ty ( type_index, table_index) ?;
1594+ self . check_call_ty ( ty) ?;
15891595 Ok ( ( ) )
15901596 }
15911597 fn visit_return_call_indirect ( & mut self , type_index : u32 , table_index : u32 ) -> Self :: Output {
1592- self . check_call_indirect ( type_index, table_index) ?;
1593- self . check_return ( ) ?;
1594- self . check_func_type_index_same_results ( type_index) ?;
1598+ let ty = self . check_call_indirect_ty ( type_index, table_index) ?;
1599+ self . check_return_call_ty ( ty) ?;
15951600 Ok ( ( ) )
15961601 }
15971602 fn visit_drop ( & mut self ) -> Self :: Output {
0 commit comments