19
19
20
20
#include " ir/properties.h"
21
21
#include " ir/subtypes.h"
22
+ #include " wasm-type.h"
22
23
#include " wasm.h"
23
24
24
25
namespace wasm {
@@ -83,20 +84,23 @@ template<typename T> struct StructValues : public std::vector<T> {
83
84
T desc;
84
85
};
85
86
86
- // Maps heap types to a StructValues for that heap type.
87
+ // Maps heap types to a StructValues for that heap type. Includes exactness in
88
+ // the key to allow differentiating between values for exact and inexact
89
+ // references to each type.
87
90
//
88
91
// Also provides a combineInto() helper that combines one map into another. This
89
92
// depends on the underlying T defining a combine() method.
90
93
template <typename T>
91
- struct StructValuesMap : public std ::unordered_map<HeapType, StructValues<T>> {
94
+ struct StructValuesMap
95
+ : public std::unordered_map<std::pair<HeapType, Exactness>, StructValues<T>> {
92
96
// When we access an item, if it does not already exist, create it with a
93
97
// vector of the right length for that type.
94
- StructValues<T>& operator [](HeapType type) {
95
- assert (type.isStruct ());
98
+ StructValues<T>& operator [](std::pair< HeapType, Exactness> type) {
99
+ assert (type.first . isStruct ());
96
100
auto inserted = this ->insert ({type, {}});
97
101
auto & values = inserted.first ->second ;
98
102
if (inserted.second ) {
99
- values.resize (type.getStruct ().fields .size ());
103
+ values.resize (type.first . getStruct ().fields .size ());
100
104
}
101
105
return values;
102
106
}
@@ -113,7 +117,8 @@ struct StructValuesMap : public std::unordered_map<HeapType, StructValues<T>> {
113
117
void dump (std::ostream& o) {
114
118
o << " dump " << this << ' \n ' ;
115
119
for (auto & [type, vec] : (*this )) {
116
- o << " dump " << type << " " << &vec << ' ' ;
120
+ o << " dump " << type.first << (type.second == Exact ? " exact " : " " )
121
+ << &vec << ' ' ;
117
122
for (auto x : vec) {
118
123
x.dump (o);
119
124
o << " " ;
@@ -203,7 +208,8 @@ struct StructScanner
203
208
// Note writes to all the fields of the struct.
204
209
auto heapType = type.getHeapType ();
205
210
auto & fields = heapType.getStruct ().fields ;
206
- auto & infos = functionNewInfos[this ->getFunction ()][heapType];
211
+ auto ht = std::make_pair (heapType, Exact);
212
+ auto & infos = functionNewInfos[this ->getFunction ()][ht];
207
213
for (Index i = 0 ; i < fields.size (); i++) {
208
214
if (curr->isWithDefault ()) {
209
215
self ().noteDefault (fields[i].type , heapType, i, infos[i]);
@@ -224,11 +230,12 @@ struct StructScanner
224
230
}
225
231
226
232
// Note a write to this field of the struct.
227
- noteExpressionOrCopy (curr->value ,
228
- type.getHeapType (),
229
- curr->index ,
230
- functionSetGetInfos[this ->getFunction ()]
231
- [type.getHeapType ()][curr->index ]);
233
+ auto ht = std::make_pair (type.getHeapType (), type.getExactness ());
234
+ noteExpressionOrCopy (
235
+ curr->value ,
236
+ type.getHeapType (),
237
+ curr->index ,
238
+ functionSetGetInfos[this ->getFunction ()][ht][curr->index ]);
232
239
}
233
240
234
241
void visitStructGet (StructGet* curr) {
@@ -237,11 +244,11 @@ struct StructScanner
237
244
return ;
238
245
}
239
246
240
- auto heapType = type.getHeapType ();
247
+ auto ht = std::make_pair ( type.getHeapType (), type. getExactness () );
241
248
auto index = curr->index ;
242
- self ().noteRead (heapType ,
249
+ self ().noteRead (type. getHeapType () ,
243
250
index,
244
- functionSetGetInfos[this ->getFunction ()][heapType ][index]);
251
+ functionSetGetInfos[this ->getFunction ()][ht ][index]);
245
252
}
246
253
247
254
void visitStructRMW (StructRMW* curr) {
@@ -251,9 +258,9 @@ struct StructScanner
251
258
}
252
259
253
260
auto heapType = type.getHeapType ();
261
+ auto ht = std::make_pair (heapType, type.getExactness ());
254
262
auto index = curr->index ;
255
- auto & info =
256
- functionSetGetInfos[this ->getFunction ()][type.getHeapType ()][index];
263
+ auto & info = functionSetGetInfos[this ->getFunction ()][ht][index];
257
264
258
265
if (curr->op == RMWXchg) {
259
266
// An xchg is really like a read and write combined.
@@ -274,9 +281,9 @@ struct StructScanner
274
281
}
275
282
276
283
auto heapType = type.getHeapType ();
284
+ auto ht = std::make_pair (heapType, type.getExactness ());
277
285
auto index = curr->index ;
278
- auto & info =
279
- functionSetGetInfos[this ->getFunction ()][type.getHeapType ()][curr->index ];
286
+ auto & info = functionSetGetInfos[this ->getFunction ()][ht][index];
280
287
281
288
// A cmpxchg is like a read and conditional write.
282
289
self ().noteRead (heapType, index, info);
@@ -310,11 +317,12 @@ struct StructScanner
310
317
return ;
311
318
}
312
319
auto heapType = type.getHeapType ();
320
+ auto ht = std::make_pair (heapType, type.getExactness ());
313
321
if (heapType.isStruct ()) {
314
322
// Any subtype of the reference here may be read from.
315
323
self ().noteRead (heapType,
316
324
DescriptorIndex,
317
- functionSetGetInfos[this ->getFunction ()][heapType ].desc );
325
+ functionSetGetInfos[this ->getFunction ()][ht ].desc );
318
326
return ;
319
327
}
320
328
}
@@ -399,46 +407,58 @@ template<typename T> class TypeHierarchyPropagator {
399
407
void propagate (StructValuesMap<T>& combinedInfos,
400
408
bool toSubTypes,
401
409
bool toSuperTypes) {
402
- UniqueDeferredQueue<HeapType> work;
403
- for (auto & [type , _] : combinedInfos) {
404
- work.push (type );
410
+ UniqueDeferredQueue<std::pair< HeapType, Exactness> > work;
411
+ for (auto & [ht , _] : combinedInfos) {
412
+ work.push (ht );
405
413
}
406
414
while (!work.empty ()) {
407
- auto type = work.pop ();
408
- auto & infos = combinedInfos[type];
415
+ auto [ type, exactness] = work.pop ();
416
+ auto & infos = combinedInfos[{ type, exactness} ];
409
417
410
418
if (toSuperTypes) {
411
- // Propagate shared fields to the supertype.
412
- if (auto superType = type.getDeclaredSuperType ()) {
413
- auto & superInfos = combinedInfos[*superType];
414
- auto & superFields = superType->getStruct ().fields ;
415
- for (Index i = 0 ; i < superFields.size (); i++) {
419
+ // Propagate shared fields to the supertype, which may be the inexact
420
+ // version of the same type.
421
+ std::optional<std::pair<HeapType, Exactness>> super;
422
+ if (exactness == Exact) {
423
+ super = {type, Inexact};
424
+ } else if (auto superType = type.getDeclaredSuperType ()) {
425
+ super = {*superType, Inexact};
426
+ }
427
+ if (super) {
428
+ auto & superInfos = combinedInfos[*super];
429
+ const auto & superFields = &super->first .getStruct ().fields ;
430
+ for (Index i = 0 ; i < superFields->size (); i++) {
416
431
if (superInfos[i].combine (infos[i])) {
417
- work.push (*superType );
432
+ work.push (*super );
418
433
}
419
434
}
420
435
// Propagate the descriptor to the super, if the super has one.
421
- if (superType-> getDescriptorType () &&
436
+ if (super-> first . getDescriptorType () &&
422
437
superInfos.desc .combine (infos.desc )) {
423
- work.push (*superType );
438
+ work.push (*super );
424
439
}
425
440
}
426
441
}
427
442
428
- if (toSubTypes) {
429
- // Propagate shared fields to the subtypes.
443
+ if (toSubTypes && exactness == Inexact) {
444
+ // Propagate shared fields to the subtypes, which may just be the exact
445
+ // version of the same type.
430
446
auto numFields = type.getStruct ().fields .size ();
431
- for ( auto subType : subTypes. getImmediateSubTypes (type) ) {
432
- auto & subInfos = combinedInfos[subType ];
447
+ auto handleSubtype = [&](std::pair<HeapType, Exactness> sub ) {
448
+ auto & subInfos = combinedInfos[sub ];
433
449
for (Index i = 0 ; i < numFields; i++) {
434
450
if (subInfos[i].combine (infos[i])) {
435
- work.push (subType );
451
+ work.push (sub );
436
452
}
437
453
}
438
454
// Propagate the descriptor.
439
455
if (subInfos.desc .combine (infos.desc )) {
440
- work.push (subType );
456
+ work.push (sub );
441
457
}
458
+ };
459
+ handleSubtype ({type, Exact});
460
+ for (auto subType : subTypes.getImmediateSubTypes (type)) {
461
+ handleSubtype ({subType, Inexact});
442
462
}
443
463
}
444
464
}
0 commit comments