@@ -113,12 +113,9 @@ impl<'m> BranchTableApi<'m> for &mut Vec<BranchTableEntry> {
113
113
) -> CheckResult {
114
114
let delta_ip = delta ( source, target, |x| x. parser . as_ptr ( ) as isize ) ?;
115
115
let delta_stp = delta ( source, target, |x| x. branch_table as isize ) ?;
116
- let val_cnt = u32:: try_from ( target. result ) . map_err ( |_| {
117
- #[ cfg( feature = "debug" ) ]
118
- eprintln ! ( "side-table val_cnt overflow {0}" , target. result) ;
119
- unsupported ( if_debug ! ( Unsupported :: SideTable ) )
120
- } ) ?;
121
- let pop_cnt = pop_cnt ( source, target) ?;
116
+ let val_cnt = u32:: try_from ( target. values ) . map_err ( |_| side_table_unsupported ( ) ) ?;
117
+ let pop_cnt = source. stack . checked_sub ( target. stack ) . ok_or_else ( invalid) ?;
118
+ let pop_cnt = u32:: try_from ( pop_cnt) . map_err ( |_| side_table_unsupported ( ) ) ?;
122
119
debug_assert ! ( self [ source. branch_table] . is_invalid( ) ) ;
123
120
self [ source. branch_table ] =
124
121
BranchTableEntry :: new ( BranchTableEntryView { delta_ip, delta_stp, val_cnt, pop_cnt } ) ?;
@@ -181,37 +178,25 @@ impl ValidMode for Verify {
181
178
182
179
impl < ' m > BranchesApi < ' m > for Option < SideTableBranch < ' m > > {
183
180
fn push_branch ( & mut self , branch : SideTableBranch < ' m > ) -> CheckResult {
184
- // TODO(dev/fast-interp): This should be `is_none_or(|x| x == branch)` once pop_cnt is
185
- // figured out.
186
- check ( self . replace ( branch) . is_none_or ( |x| {
187
- x. parser == branch. parser
188
- && x. branch_table == branch. branch_table
189
- && x. result == branch. result
190
- } ) )
181
+ check ( self . replace ( branch) . is_none_or ( |x| x == branch) )
191
182
}
192
183
}
193
184
194
185
impl < ' m > BranchTableApi < ' m > for MetadataView < ' m > {
195
186
fn stitch_branch (
196
187
& mut self , source : SideTableBranch < ' m > , target : SideTableBranch < ' m > ,
197
188
) -> CheckResult {
198
- // TODO(dev/fast-interp): This should be `source == target)` once pop_cnt is figured out.
199
- check (
200
- source. parser == target. parser
201
- && source. result == target. result
202
- && source. branch_table == target. branch_table
203
- && source. stack <= target. stack ,
204
- )
189
+ check ( source == target)
205
190
}
206
191
207
192
fn patch_branch ( & self , mut source : SideTableBranch < ' m > ) -> Result < SideTableBranch < ' m > , Error > {
208
193
let entry = self . metadata . branch_table ( ) [ source. branch_table ] . view ( ) ;
194
+ // TODO(dev/fast-interp): We want a safe version of offset_front.
209
195
source. parser = offset_front ( source. parser , entry. delta_ip as isize ) ;
210
- // TODO(dev/fast-interp): This should wrapping_add_signed for performance and
211
- // strict_add_signed for debugging/safety.
212
- source. branch_table = source. branch_table . saturating_add_signed ( entry. delta_stp as isize ) ;
213
- source. result = entry. val_cnt as usize ;
196
+ source. branch_table =
197
+ source. branch_table . checked_add_signed ( entry. delta_stp as isize ) . ok_or_else ( invalid) ?;
214
198
source. stack -= entry. pop_cnt as usize ;
199
+ source. values = entry. val_cnt as usize ;
215
200
Ok ( source)
216
201
}
217
202
@@ -619,8 +604,10 @@ struct Expr<'a, 'm, M: ValidMode> {
619
604
struct SideTableBranch < ' m > {
620
605
parser : & ' m [ u8 ] ,
621
606
branch_table : usize ,
607
+ /// Function stack length (including branch values).
622
608
stack : usize ,
623
- result : usize , // unused (zero) for source branches
609
+ /// Branch values (only for target branches, zero for source branches).
610
+ values : usize ,
624
611
}
625
612
626
613
#[ derive( Debug , Default ) ]
@@ -632,7 +619,7 @@ struct Label<'m, M: ValidMode> {
632
619
polymorphic : bool ,
633
620
stack : Vec < OpdType > ,
634
621
branches : M :: Branches < ' m > ,
635
- /// Total stack length of the labels in this function up to this label.
622
+ /// Function stack length up to this label (excluding branch values) .
636
623
prev_stack : usize ,
637
624
}
638
625
@@ -641,7 +628,7 @@ enum LabelKind<'m> {
641
628
#[ default]
642
629
Block ,
643
630
Loop ( SideTableBranch < ' m > ) ,
644
- If ( SideTableBranch < ' m > ) ,
631
+ If ( Option < SideTableBranch < ' m > > ) ,
645
632
}
646
633
647
634
impl < ' a , ' m , M : ValidMode > Expr < ' a , ' m , M > {
@@ -722,6 +709,8 @@ impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
722
709
let type_ = self . blocktype ( & b) ?;
723
710
let mut target = self . branch_target ( type_. params . len ( ) ) ;
724
711
target. parser = saved;
712
+ target. stack +=
713
+ self . stack ( ) . len ( ) . checked_sub ( target. values ) . ok_or_else ( invalid) ?;
725
714
self . push_label ( type_, LabelKind :: Loop ( target) ) ?
726
715
}
727
716
If ( b) => {
@@ -730,25 +719,24 @@ impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
730
719
self . push_label ( self . blocktype ( & b) ?, LabelKind :: If ( branch) ) ?;
731
720
}
732
721
Else => {
722
+ self . br_label ( 0 ) ?;
723
+ let FuncType { params, results } = self . label ( ) . type_ ;
724
+ self . pops ( results) ?;
725
+ check ( self . stack ( ) . is_empty ( ) ) ?;
726
+ self . label ( ) . polymorphic = false ;
727
+ self . pushs ( params) ;
733
728
match core:: mem:: replace ( & mut self . label ( ) . kind , LabelKind :: Block ) {
734
- LabelKind :: If ( source) => {
729
+ LabelKind :: If ( None ) => ( ) ,
730
+ LabelKind :: If ( Some ( source) ) => {
735
731
let source = M :: BranchTable :: patch_branch (
736
732
self . branch_table . as_ref ( ) . unwrap ( ) ,
737
733
source,
738
734
) ?;
739
- let result = self . label ( ) . type_ . results . len ( ) ;
740
- let mut target = self . branch_target ( result) ;
741
- target. branch_table += 1 ;
735
+ let target = self . branch_target ( params. len ( ) ) ;
742
736
self . branch_table . as_mut ( ) . unwrap ( ) . stitch_branch ( source, target) ?;
743
737
}
744
738
_ => Err ( invalid ( ) ) ?,
745
739
}
746
- let FuncType { params, results } = self . label ( ) . type_ ;
747
- self . pops ( results) ?;
748
- check ( self . stack ( ) . is_empty ( ) ) ?;
749
- self . label ( ) . polymorphic = false ;
750
- self . pushs ( params) ;
751
- self . br_label ( 0 ) ?;
752
740
}
753
741
End => unreachable ! ( ) ,
754
742
Br ( l) => {
@@ -1011,10 +999,12 @@ impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
1011
999
let label = self . label ( ) ;
1012
1000
if let LabelKind :: If ( source) = label. kind {
1013
1001
check ( label. type_ . params == label. type_ . results ) ?;
1014
- let source = self . branch_table . as_ref ( ) . unwrap ( ) . patch_branch ( source) ?;
1015
- // SAFETY: This function is only called after parsing an End instruction.
1016
- target. parser = offset_front ( target. parser , -1 ) ;
1017
- self . branch_table . as_mut ( ) . unwrap ( ) . stitch_branch ( source, target) ?;
1002
+ if let Some ( source) = source {
1003
+ let source = self . branch_table . as_ref ( ) . unwrap ( ) . patch_branch ( source) ?;
1004
+ // SAFETY: This function is only called after parsing an End instruction.
1005
+ target. parser = offset_front ( target. parser , -1 ) ;
1006
+ self . branch_table . as_mut ( ) . unwrap ( ) . stitch_branch ( source, target) ?;
1007
+ }
1018
1008
}
1019
1009
}
1020
1010
let results = self . label ( ) . type_ . results ;
@@ -1030,35 +1020,42 @@ impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
1030
1020
let l = l as usize ;
1031
1021
let n = self . labels . len ( ) ;
1032
1022
check ( l < n) ?;
1033
- let source = self . branch_source ( ) ;
1034
- let source = self . branch_table . as_ref ( ) . unwrap ( ) . patch_branch ( source) ?;
1023
+ let source = match self . branch_source ( ) {
1024
+ None => None ,
1025
+ Some ( x) => Some ( self . branch_table . as_ref ( ) . unwrap ( ) . patch_branch ( x) ?) ,
1026
+ } ;
1035
1027
let label = & mut self . labels [ n - l - 1 ] ;
1036
1028
Ok ( match label. kind {
1037
1029
LabelKind :: Block | LabelKind :: If ( _) => {
1038
- label. branches . push_branch ( source) ?;
1030
+ if let Some ( source) = source {
1031
+ label. branches . push_branch ( source) ?;
1032
+ }
1039
1033
label. type_ . results
1040
1034
}
1041
1035
LabelKind :: Loop ( target) => {
1042
- self . branch_table . as_mut ( ) . unwrap ( ) . stitch_branch ( source, target) ?;
1036
+ if let Some ( source) = source {
1037
+ self . branch_table . as_mut ( ) . unwrap ( ) . stitch_branch ( source, target) ?;
1038
+ }
1043
1039
label. type_ . params
1044
1040
}
1045
1041
} )
1046
1042
}
1047
1043
1048
- fn branch_source ( & mut self ) -> SideTableBranch < ' m > {
1044
+ fn branch_source ( & mut self ) -> Option < SideTableBranch < ' m > > {
1045
+ if self . label ( ) . polymorphic {
1046
+ // We don't need a branch table entry for unreachable code.
1047
+ return None ;
1048
+ }
1049
1049
let mut branch = self . branch ( ) ;
1050
1050
branch. stack += self . stack ( ) . len ( ) ;
1051
1051
self . branch_table . as_mut ( ) . unwrap ( ) . allocate_branch ( ) ;
1052
- branch
1052
+ Some ( branch)
1053
1053
}
1054
1054
1055
- fn branch_target ( & self , result : usize ) -> SideTableBranch < ' m > {
1055
+ fn branch_target ( & self , values : usize ) -> SideTableBranch < ' m > {
1056
1056
let mut branch = self . branch ( ) ;
1057
- branch. result = result;
1058
- // TODO(dev/fast-interp): Figure out if there are not cases (like Loop or Else) where we
1059
- // want to add `self.stack().len()`. Also adding result here should purely be a convention
1060
- // with pop_cnt, and we should be able to do the opposite choice (to be considered).
1061
- branch. stack += result;
1057
+ branch. stack += values;
1058
+ branch. values = values;
1062
1059
branch
1063
1060
}
1064
1061
@@ -1067,7 +1064,7 @@ impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
1067
1064
parser : self . parser . save ( ) ,
1068
1065
branch_table : self . branch_table . as_ref ( ) . unwrap ( ) . next_index ( ) ,
1069
1066
stack : self . immutable_label ( ) . prev_stack ,
1070
- result : 0 ,
1067
+ values : 0 ,
1071
1068
}
1072
1069
}
1073
1070
@@ -1137,27 +1134,10 @@ impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
1137
1134
fn delta (
1138
1135
source : SideTableBranch , target : SideTableBranch , field : fn ( SideTableBranch ) -> isize ,
1139
1136
) -> MResult < i32 , Check > {
1140
- let source = field ( source) ;
1141
- let target = field ( target) ;
1142
- let Some ( delta) = target. checked_sub ( source) else {
1143
- #[ cfg( feature = "debug" ) ]
1144
- eprintln ! ( "side-table subtraction overflow {target} - {source}" ) ;
1145
- return Err ( unsupported ( if_debug ! ( Unsupported :: SideTable ) ) ) ;
1146
- } ;
1147
- i32:: try_from ( delta) . map_err ( |_| {
1148
- #[ cfg( feature = "debug" ) ]
1149
- eprintln ! ( "side-table conversion overflow {delta}" ) ;
1150
- unsupported ( if_debug ! ( Unsupported :: SideTable ) )
1151
- } )
1137
+ let delta = field ( target) . checked_sub ( field ( source) ) . ok_or_else ( side_table_unsupported) ?;
1138
+ i32:: try_from ( delta) . map_err ( |_| side_table_unsupported ( ) )
1152
1139
}
1153
1140
1154
- fn pop_cnt ( source : SideTableBranch , target : SideTableBranch ) -> MResult < u32 , Check > {
1155
- // TODO(dev/fast-interp): Figure out why we can't simply source.stack - target.stack and
1156
- // document it. We're losing information by saturating.
1157
- let res = source. stack . saturating_sub ( target. stack ) ;
1158
- u32:: try_from ( res) . map_err ( |_| {
1159
- #[ cfg( feature = "debug" ) ]
1160
- eprintln ! ( "side-table pop_cnt overflow {res}" ) ;
1161
- unsupported ( if_debug ! ( Unsupported :: SideTable ) )
1162
- } )
1141
+ fn side_table_unsupported ( ) -> Error {
1142
+ unsupported ( if_debug ! ( Unsupported :: SideTable ) )
1163
1143
}
0 commit comments