@@ -65,6 +65,14 @@ namespace wasm {
65
65
// the types of children. For example, it does not report the constraint that
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
+ //
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.
68
76
template <typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
69
77
Module& wasm;
70
78
Function* func;
@@ -109,6 +117,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
109
117
110
118
Type getLabelType (Name label) { return self ().getLabelType (label); }
111
119
120
+ bool skipUnreachable () { return false ; }
121
+
112
122
void visitNop (Nop* curr) {}
113
123
114
124
void visitBlock (Block* curr) {
@@ -197,6 +207,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
197
207
}
198
208
199
209
void visitAtomicRMW (AtomicRMW* curr) {
210
+ if (self ().skipUnreachable () && curr->type == Type::unreachable) {
211
+ return ;
212
+ }
200
213
assert (curr->type == Type::i32 || curr->type == Type::i64 );
201
214
notePointer (&curr->ptr , curr->memory );
202
215
note (&curr->value , curr->type );
@@ -823,6 +836,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
823
836
void visitTupleExtract (TupleExtract* curr,
824
837
std::optional<size_t > arity = std::nullopt) {
825
838
if (!arity) {
839
+ if (self ().skipUnreachable () && !curr->tuple ->type .isTuple ()) {
840
+ return ;
841
+ }
826
842
assert (curr->tuple ->type .isTuple ());
827
843
arity = curr->tuple ->type .size ();
828
844
}
@@ -837,6 +853,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
837
853
838
854
void visitCallRef (CallRef* curr, std::optional<HeapType> ht = std::nullopt) {
839
855
if (!ht) {
856
+ if (self ().skipUnreachable () && !curr->target ->type .isRef ()) {
857
+ return ;
858
+ }
840
859
ht = curr->target ->type .getHeapType ().getSignature ();
841
860
}
842
861
auto params = ht->getSignature ().params ;
@@ -848,17 +867,26 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
848
867
}
849
868
850
869
void visitRefTest (RefTest* curr) {
870
+ if (self ().skipUnreachable () && !curr->castType .isRef ()) {
871
+ return ;
872
+ }
851
873
auto top = curr->castType .getHeapType ().getTop ();
852
874
note (&curr->ref , Type (top, Nullable));
853
875
}
854
876
855
877
void visitRefCast (RefCast* curr, std::optional<Type> target = std::nullopt) {
878
+ if (self ().skipUnreachable () && !curr->type .isRef ()) {
879
+ return ;
880
+ }
856
881
auto top = curr->type .getHeapType ().getTop ();
857
882
note (&curr->ref , Type (top, Nullable));
858
883
if (curr->desc ) {
859
884
if (!target) {
860
885
target = curr->type ;
861
886
}
887
+ if (self ().skipUnreachable () && !target->isRef ()) {
888
+ return ;
889
+ }
862
890
auto desc = target->getHeapType ().getDescriptorType ();
863
891
assert (desc);
864
892
note (&curr->desc , Type (*desc, Nullable, curr->type .getExactness ()));
@@ -868,6 +896,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
868
896
void visitRefGetDesc (RefGetDesc* curr,
869
897
std::optional<HeapType> ht = std::nullopt) {
870
898
if (!ht) {
899
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
900
+ return ;
901
+ }
871
902
ht = curr->ref ->type .getHeapType ();
872
903
}
873
904
note (&curr->ref , Type (*ht, Nullable));
@@ -886,6 +917,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
886
917
if (!target) {
887
918
target = curr->castType ;
888
919
}
920
+ if (self ().skipUnreachable () && !target->isRef ()) {
921
+ return ;
922
+ }
889
923
auto top = target->getHeapType ().getTop ();
890
924
note (&curr->ref , Type (top, Nullable));
891
925
if (curr->op == BrOnCastDesc || curr->op == BrOnCastDescFail) {
@@ -903,6 +937,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
903
937
if (curr->isWithDefault ()) {
904
938
return ;
905
939
}
940
+ if (self ().skipUnreachable () && !curr->type .isRef ()) {
941
+ return ;
942
+ }
906
943
const auto & fields = curr->type .getHeapType ().getStruct ().fields ;
907
944
assert (fields.size () == curr->operands .size ());
908
945
for (size_t i = 0 ; i < fields.size (); ++i) {
@@ -913,6 +950,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
913
950
void visitStructGet (StructGet* curr,
914
951
std::optional<HeapType> ht = std::nullopt) {
915
952
if (!ht) {
953
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
954
+ return ;
955
+ }
916
956
ht = curr->ref ->type .getHeapType ();
917
957
}
918
958
note (&curr->ref , Type (*ht, Nullable));
@@ -921,6 +961,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
921
961
void visitStructSet (StructSet* curr,
922
962
std::optional<HeapType> ht = std::nullopt) {
923
963
if (!ht) {
964
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
965
+ return ;
966
+ }
924
967
ht = curr->ref ->type .getHeapType ();
925
968
}
926
969
const auto & fields = ht->getStruct ().fields ;
@@ -932,6 +975,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
932
975
void visitStructRMW (StructRMW* curr,
933
976
std::optional<HeapType> ht = std::nullopt) {
934
977
if (!ht) {
978
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
979
+ return ;
980
+ }
935
981
ht = curr->ref ->type .getHeapType ();
936
982
}
937
983
const auto & fields = ht->getStruct ().fields ;
@@ -943,6 +989,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
943
989
void visitStructCmpxchg (StructCmpxchg* curr,
944
990
std::optional<HeapType> ht = std::nullopt) {
945
991
if (!ht) {
992
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
993
+ return ;
994
+ }
946
995
ht = curr->ref ->type .getHeapType ();
947
996
}
948
997
const auto & fields = ht->getStruct ().fields ;
@@ -954,6 +1003,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
954
1003
955
1004
void visitArrayNew (ArrayNew* curr) {
956
1005
if (!curr->isWithDefault ()) {
1006
+ if (self ().skipUnreachable () && !curr->type .isRef ()) {
1007
+ return ;
1008
+ }
957
1009
note (&curr->init , curr->type .getHeapType ().getArray ().element .type );
958
1010
}
959
1011
note (&curr->size , Type::i32 );
@@ -970,6 +1022,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
970
1022
}
971
1023
972
1024
void visitArrayNewFixed (ArrayNewFixed* curr) {
1025
+ if (self ().skipUnreachable () && !curr->type .isRef ()) {
1026
+ return ;
1027
+ }
973
1028
auto type = curr->type .getHeapType ().getArray ().element .type ;
974
1029
for (auto & expr : curr->values ) {
975
1030
note (&expr, type);
@@ -979,6 +1034,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
979
1034
void visitArrayGet (ArrayGet* curr,
980
1035
std::optional<HeapType> ht = std::nullopt) {
981
1036
if (!ht) {
1037
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1038
+ return ;
1039
+ }
982
1040
ht = curr->ref ->type .getHeapType ();
983
1041
}
984
1042
note (&curr->ref , Type (*ht, Nullable));
@@ -988,6 +1046,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
988
1046
void visitArraySet (ArraySet* curr,
989
1047
std::optional<HeapType> ht = std::nullopt) {
990
1048
if (!ht) {
1049
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1050
+ return ;
1051
+ }
991
1052
ht = curr->ref ->type .getHeapType ();
992
1053
}
993
1054
auto type = ht->getArray ().element .type ;
@@ -1004,9 +1065,15 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1004
1065
std::optional<HeapType> dest = std::nullopt,
1005
1066
std::optional<HeapType> src = std::nullopt) {
1006
1067
if (!dest) {
1068
+ if (self ().skipUnreachable () && !curr->destRef ->type .isRef ()) {
1069
+ return ;
1070
+ }
1007
1071
dest = curr->destRef ->type .getHeapType ();
1008
1072
}
1009
1073
if (!src) {
1074
+ if (self ().skipUnreachable () && !curr->srcRef ->type .isRef ()) {
1075
+ return ;
1076
+ }
1010
1077
src = curr->srcRef ->type .getHeapType ();
1011
1078
}
1012
1079
note (&curr->destRef , Type (*dest, Nullable));
@@ -1019,6 +1086,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1019
1086
void visitArrayFill (ArrayFill* curr,
1020
1087
std::optional<HeapType> ht = std::nullopt) {
1021
1088
if (!ht) {
1089
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1090
+ return ;
1091
+ }
1022
1092
ht = curr->ref ->type .getHeapType ();
1023
1093
}
1024
1094
auto type = ht->getArray ().element .type ;
@@ -1031,6 +1101,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1031
1101
void visitArrayInitData (ArrayInitData* curr,
1032
1102
std::optional<HeapType> ht = std::nullopt) {
1033
1103
if (!ht) {
1104
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1105
+ return ;
1106
+ }
1034
1107
ht = curr->ref ->type .getHeapType ();
1035
1108
}
1036
1109
note (&curr->ref , Type (*ht, Nullable));
@@ -1042,6 +1115,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1042
1115
void visitArrayInitElem (ArrayInitElem* curr,
1043
1116
std::optional<HeapType> ht = std::nullopt) {
1044
1117
if (!ht) {
1118
+ if (self ().skipUnreachable () && !curr->ref ->type .isRef ()) {
1119
+ return ;
1120
+ }
1045
1121
ht = curr->ref ->type .getHeapType ();
1046
1122
}
1047
1123
note (&curr->ref , Type (*ht, Nullable));
@@ -1093,6 +1169,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1093
1169
void visitStringEncode (StringEncode* curr,
1094
1170
std::optional<HeapType> ht = std::nullopt) {
1095
1171
if (!ht) {
1172
+ if (self ().skipUnreachable () && !curr->array ->type .isRef ()) {
1173
+ return ;
1174
+ }
1096
1175
ht = curr->array ->type .getHeapType ();
1097
1176
}
1098
1177
note (&curr->str , Type (HeapType::string, Nullable));
@@ -1129,9 +1208,15 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1129
1208
std::optional<HeapType> src = std::nullopt,
1130
1209
std::optional<HeapType> dest = std::nullopt) {
1131
1210
if (!src.has_value ()) {
1211
+ if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1212
+ return ;
1213
+ }
1132
1214
src = curr->cont ->type .getHeapType ();
1133
1215
}
1134
1216
if (!dest.has_value ()) {
1217
+ if (self ().skipUnreachable () && !curr->type .isRef ()) {
1218
+ return ;
1219
+ }
1135
1220
dest = curr->type .getHeapType ();
1136
1221
}
1137
1222
auto sourceParams = src->getContinuation ().type .getSignature ().params ;
@@ -1155,6 +1240,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1155
1240
1156
1241
void visitResume (Resume* curr, std::optional<HeapType> ct = std::nullopt) {
1157
1242
if (!ct.has_value ()) {
1243
+ if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1244
+ return ;
1245
+ }
1158
1246
ct = curr->cont ->type .getHeapType ();
1159
1247
}
1160
1248
assert (ct->isContinuation ());
@@ -1169,6 +1257,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1169
1257
void visitResumeThrow (ResumeThrow* curr,
1170
1258
std::optional<HeapType> ct = std::nullopt) {
1171
1259
if (!ct.has_value ()) {
1260
+ if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1261
+ return ;
1262
+ }
1172
1263
ct = curr->cont ->type .getHeapType ();
1173
1264
}
1174
1265
assert (ct->isContinuation ());
@@ -1183,6 +1274,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
1183
1274
void visitStackSwitch (StackSwitch* curr,
1184
1275
std::optional<HeapType> ct = std::nullopt) {
1185
1276
if (!ct.has_value ()) {
1277
+ if (self ().skipUnreachable () && !curr->cont ->type .isRef ()) {
1278
+ return ;
1279
+ }
1186
1280
ct = curr->cont ->type .getHeapType ();
1187
1281
}
1188
1282
assert (ct->isContinuation ());
0 commit comments