@@ -66,13 +66,9 @@ namespace wasm {
66
66
// two non-reference children of `select` must have the same type because that
67
67
// would require inspecting the types of those children.
68
68
//
69
- // The skipUnreachable() hook function determines the behavior on code that
70
- // we cannot process due to unreachability. For example, an unreachable
71
- // StructNew has no struct type defined, so we cannot apply its heap type. By
72
- // default we do not skip such unreachable code, and error in such such cases if
73
- // the type is not provided (by passing the heap type as mentioned above, as a
74
- // parameter to the visit* method). Optimization passes can often skip
75
- // unreachable code (leaving it for DCE), while other operations might not.
69
+ // The noteUnknown() hook is called whenever there is insufficient type
70
+ // information to generate constraints for all the children. Some users may wish
71
+ // to ignore this situation and others may want to assert that it never occurs.
76
72
template <typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
77
73
Module& wasm;
78
74
Function* func;
@@ -105,8 +101,6 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
105
101
106
102
Type getLabelType (Name label) { return self ().getLabelType (label); }
107
103
108
- bool skipUnreachable () { return false ; }
109
-
110
104
void visitNop (Nop* curr) {}
111
105
112
106
void visitBlock (Block* curr) {
@@ -195,7 +189,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
195
189
}
196
190
197
191
void visitAtomicRMW (AtomicRMW* curr) {
198
- if (self ().skipUnreachable () && curr->type == Type::unreachable) {
192
+ if (curr->type == Type::unreachable) {
193
+ self ().noteUnknown ();
199
194
return ;
200
195
}
201
196
assert (curr->type == Type::i32 || curr->type == Type::i64 );
@@ -828,7 +823,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
828
823
void visitTupleExtract (TupleExtract* curr,
829
824
std::optional<size_t > arity = std::nullopt) {
830
825
if (!arity) {
831
- if (self ().skipUnreachable () && !curr->tuple ->type .isTuple ()) {
826
+ if (!curr->tuple ->type .isTuple ()) {
827
+ self ().noteUnknown ();
832
828
return ;
833
829
}
834
830
assert (curr->tuple ->type .isTuple ());
@@ -845,7 +841,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
845
841
846
842
void visitCallRef (CallRef* curr, std::optional<HeapType> ht = std::nullopt) {
847
843
if (!ht) {
848
- if (self ().skipUnreachable () && !curr->target ->type .isRef ()) {
844
+ if (!curr->target ->type .isRef ()) {
845
+ self ().noteUnknown ();
849
846
return ;
850
847
}
851
848
ht = curr->target ->type .getHeapType ().getSignature ();
@@ -859,36 +856,32 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
859
856
}
860
857
861
858
void visitRefTest (RefTest* curr) {
862
- if (self ().skipUnreachable () && !curr->castType .isRef ()) {
863
- return ;
864
- }
865
859
auto top = curr->castType .getHeapType ().getTop ();
866
860
note (&curr->ref , Type (top, Nullable));
867
861
}
868
862
869
863
void visitRefCast (RefCast* curr, std::optional<Type> target = std::nullopt) {
870
- if (self ().skipUnreachable () && !curr->type .isRef ()) {
871
- return ;
864
+ if (!target) {
865
+ if (!curr->type .isRef ()) {
866
+ self ().noteUnknown ();
867
+ return ;
868
+ }
869
+ target = curr->type ;
872
870
}
873
- auto top = curr-> type . getHeapType ().getTop ();
871
+ auto top = target-> getHeapType ().getTop ();
874
872
note (&curr->ref , Type (top, Nullable));
875
873
if (curr->desc ) {
876
- if (!target) {
877
- target = curr->type ;
878
- }
879
- if (self ().skipUnreachable () && !target->isRef ()) {
880
- return ;
881
- }
882
874
auto desc = target->getHeapType ().getDescriptorType ();
883
875
assert (desc);
884
- note (&curr->desc , Type (*desc, Nullable, curr-> type . getExactness ()));
876
+ note (&curr->desc , Type (*desc, Nullable, target-> getExactness ()));
885
877
}
886
878
}
887
879
888
880
void visitRefGetDesc (RefGetDesc* curr,
889
881
std::optional<HeapType> ht = std::nullopt) {
890
882
if (!ht) {
891
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
883
+ if (!curr->ref ->type .isRef ()) {
884
+ self ().noteUnknown ();
892
885
return ;
893
886
}
894
887
ht = curr->ref ->type .getHeapType ();
@@ -900,18 +893,19 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
900
893
switch (curr->op ) {
901
894
case BrOnNull:
902
895
case BrOnNonNull:
896
+ // br_on(_non)_null is polymorphic over reference types and does not
897
+ // take a type immediate.
898
+ assert (!target);
903
899
noteAnyReference (&curr->ref );
904
900
return ;
905
901
case BrOnCast:
906
902
case BrOnCastFail:
907
903
case BrOnCastDesc:
908
904
case BrOnCastDescFail: {
909
905
if (!target) {
906
+ assert (curr->castType .isRef ());
910
907
target = curr->castType ;
911
908
}
912
- if (self ().skipUnreachable () && !target->isRef ()) {
913
- return ;
914
- }
915
909
auto top = target->getHeapType ().getTop ();
916
910
note (&curr->ref , Type (top, Nullable));
917
911
if (curr->op == BrOnCastDesc || curr->op == BrOnCastDescFail) {
@@ -926,7 +920,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
926
920
}
927
921
928
922
void visitStructNew (StructNew* curr) {
929
- if (self ().skipUnreachable () && !curr->type .isRef ()) {
923
+ if (!curr->type .isRef ()) {
924
+ self ().noteUnknown ();
930
925
return ;
931
926
}
932
927
if (!curr->isWithDefault ()) {
@@ -945,7 +940,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
945
940
void visitStructGet (StructGet* curr,
946
941
std::optional<HeapType> ht = std::nullopt) {
947
942
if (!ht) {
948
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
943
+ if (!curr->ref ->type .isRef ()) {
944
+ self ().noteUnknown ();
949
945
return ;
950
946
}
951
947
ht = curr->ref ->type .getHeapType ();
@@ -956,7 +952,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
956
952
void visitStructSet (StructSet* curr,
957
953
std::optional<HeapType> ht = std::nullopt) {
958
954
if (!ht) {
959
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
955
+ if (!curr->ref ->type .isRef ()) {
956
+ self ().noteUnknown ();
960
957
return ;
961
958
}
962
959
ht = curr->ref ->type .getHeapType ();
@@ -970,7 +967,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
970
967
void visitStructRMW (StructRMW* curr,
971
968
std::optional<HeapType> ht = std::nullopt) {
972
969
if (!ht) {
973
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
970
+ if (!curr->ref ->type .isRef ()) {
971
+ self ().noteUnknown ();
974
972
return ;
975
973
}
976
974
ht = curr->ref ->type .getHeapType ();
@@ -984,7 +982,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
984
982
void visitStructCmpxchg (StructCmpxchg* curr,
985
983
std::optional<HeapType> ht = std::nullopt) {
986
984
if (!ht) {
987
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
985
+ if (!curr->ref ->type .isRef ()) {
986
+ self ().noteUnknown ();
988
987
return ;
989
988
}
990
989
ht = curr->ref ->type .getHeapType ();
@@ -999,7 +998,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
999
998
1000
999
void visitArrayNew (ArrayNew* curr) {
1001
1000
if (!curr->isWithDefault ()) {
1002
- if (self ().skipUnreachable () && !curr->type .isRef ()) {
1001
+ if (!curr->type .isRef ()) {
1002
+ self ().noteUnknown ();
1003
1003
return ;
1004
1004
}
1005
1005
note (&curr->init , curr->type .getHeapType ().getArray ().element .type );
@@ -1018,7 +1018,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1018
1018
}
1019
1019
1020
1020
void visitArrayNewFixed (ArrayNewFixed* curr) {
1021
- if (self ().skipUnreachable () && !curr->type .isRef ()) {
1021
+ if (!curr->type .isRef ()) {
1022
+ self ().noteUnknown ();
1022
1023
return ;
1023
1024
}
1024
1025
auto type = curr->type .getHeapType ().getArray ().element .type ;
@@ -1030,7 +1031,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1030
1031
void visitArrayGet (ArrayGet* curr,
1031
1032
std::optional<HeapType> ht = std::nullopt) {
1032
1033
if (!ht) {
1033
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1034
+ if (!curr->ref ->type .isRef ()) {
1035
+ self ().noteUnknown ();
1034
1036
return ;
1035
1037
}
1036
1038
ht = curr->ref ->type .getHeapType ();
@@ -1042,7 +1044,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1042
1044
void visitArraySet (ArraySet* curr,
1043
1045
std::optional<HeapType> ht = std::nullopt) {
1044
1046
if (!ht) {
1045
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1047
+ if (!curr->ref ->type .isRef ()) {
1048
+ self ().noteUnknown ();
1046
1049
return ;
1047
1050
}
1048
1051
ht = curr->ref ->type .getHeapType ();
@@ -1061,13 +1064,15 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1061
1064
std::optional<HeapType> dest = std::nullopt,
1062
1065
std::optional<HeapType> src = std::nullopt) {
1063
1066
if (!dest) {
1064
- if (self ().skipUnreachable () && !curr->destRef ->type .isRef ()) {
1067
+ if (!curr->destRef ->type .isRef ()) {
1068
+ self ().noteUnknown ();
1065
1069
return ;
1066
1070
}
1067
1071
dest = curr->destRef ->type .getHeapType ();
1068
1072
}
1069
1073
if (!src) {
1070
- if (self ().skipUnreachable () && !curr->srcRef ->type .isRef ()) {
1074
+ if (!curr->srcRef ->type .isRef ()) {
1075
+ self ().noteUnknown ();
1071
1076
return ;
1072
1077
}
1073
1078
src = curr->srcRef ->type .getHeapType ();
@@ -1082,7 +1087,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1082
1087
void visitArrayFill (ArrayFill* curr,
1083
1088
std::optional<HeapType> ht = std::nullopt) {
1084
1089
if (!ht) {
1085
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1090
+ if (!curr->ref ->type .isRef ()) {
1091
+ self ().noteUnknown ();
1086
1092
return ;
1087
1093
}
1088
1094
ht = curr->ref ->type .getHeapType ();
@@ -1097,7 +1103,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1097
1103
void visitArrayInitData (ArrayInitData* curr,
1098
1104
std::optional<HeapType> ht = std::nullopt) {
1099
1105
if (!ht) {
1100
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1106
+ if (!curr->ref ->type .isRef ()) {
1107
+ self ().noteUnknown ();
1101
1108
return ;
1102
1109
}
1103
1110
ht = curr->ref ->type .getHeapType ();
@@ -1111,7 +1118,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1111
1118
void visitArrayInitElem (ArrayInitElem* curr,
1112
1119
std::optional<HeapType> ht = std::nullopt) {
1113
1120
if (!ht) {
1114
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1121
+ if (!curr->ref ->type .isRef ()) {
1122
+ self ().noteUnknown ();
1115
1123
return ;
1116
1124
}
1117
1125
ht = curr->ref ->type .getHeapType ();
@@ -1125,7 +1133,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1125
1133
void visitArrayRMW (ArrayRMW* curr,
1126
1134
std::optional<HeapType> ht = std::nullopt) {
1127
1135
if (!ht) {
1128
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1136
+ if (!curr->ref ->type .isRef ()) {
1137
+ self ().noteUnknown ();
1129
1138
return ;
1130
1139
}
1131
1140
ht = curr->ref ->type .getHeapType ();
@@ -1139,7 +1148,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1139
1148
void visitArrayCmpxchg (ArrayCmpxchg* curr,
1140
1149
std::optional<HeapType> ht = std::nullopt) {
1141
1150
if (!ht) {
1142
- if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1151
+ if (!curr->ref ->type .isRef ()) {
1152
+ self ().noteUnknown ();
1143
1153
return ;
1144
1154
}
1145
1155
ht = curr->ref ->type .getHeapType ();
@@ -1241,14 +1251,16 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1241
1251
void visitContBind (ContBind* curr,
1242
1252
std::optional<HeapType> src = std::nullopt,
1243
1253
std::optional<HeapType> dest = std::nullopt) {
1244
- if (!src.has_value ()) {
1245
- if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1254
+ if (!src) {
1255
+ if (!curr->cont ->type .isRef ()) {
1256
+ self ().noteUnknown ();
1246
1257
return ;
1247
1258
}
1248
1259
src = curr->cont ->type .getHeapType ();
1249
1260
}
1250
- if (!dest.has_value ()) {
1251
- if (self ().skipUnreachable () && !curr->type .isRef ()) {
1261
+ if (!dest) {
1262
+ if (!curr->type .isRef ()) {
1263
+ self ().noteUnknown ();
1252
1264
return ;
1253
1265
}
1254
1266
dest = curr->type .getHeapType ();
@@ -1273,8 +1285,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1273
1285
}
1274
1286
1275
1287
void visitResume (Resume* curr, std::optional<HeapType> ct = std::nullopt) {
1276
- if (!ct.has_value ()) {
1277
- if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1288
+ if (!ct) {
1289
+ if (!curr->cont ->type .isRef ()) {
1290
+ self ().noteUnknown ();
1278
1291
return ;
1279
1292
}
1280
1293
ct = curr->cont ->type .getHeapType ();
@@ -1290,8 +1303,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1290
1303
1291
1304
void visitResumeThrow (ResumeThrow* curr,
1292
1305
std::optional<HeapType> ct = std::nullopt) {
1293
- if (!ct.has_value ()) {
1294
- if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1306
+ if (!ct) {
1307
+ if (!curr->cont ->type .isRef ()) {
1308
+ self ().noteUnknown ();
1295
1309
return ;
1296
1310
}
1297
1311
ct = curr->cont ->type .getHeapType ();
@@ -1307,8 +1321,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1307
1321
1308
1322
void visitStackSwitch (StackSwitch* curr,
1309
1323
std::optional<HeapType> ct = std::nullopt) {
1310
- if (!ct.has_value ()) {
1311
- if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1324
+ if (!ct) {
1325
+ if (!curr->cont ->type .isRef ()) {
1326
+ self ().noteUnknown ();
1312
1327
return ;
1313
1328
}
1314
1329
ct = curr->cont ->type .getHeapType ();
0 commit comments