diff options
author | Alon Zakai <azakai@google.com> | 2023-03-03 14:10:02 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-03 22:10:02 +0000 |
commit | c891c01ca5813172775ae859126a0ec3857ad8b7 (patch) | |
tree | 396b4b1bd9bc66e155d96111c6a42f0217ffb212 /src | |
parent | dea234b50fac389605209e818bbab39777984f36 (diff) | |
download | binaryen-c891c01ca5813172775ae859126a0ec3857ad8b7.tar.gz binaryen-c891c01ca5813172775ae859126a0ec3857ad8b7.tar.bz2 binaryen-c891c01ca5813172775ae859126a0ec3857ad8b7.zip |
Note function signature param/result features for validation (#5542)
As with #5535, this was not noticed because it can only happen on very
small modules where the param/result type appears nowhere else but
in a function signature.
Use generic heap type scanning, which also scans into struct and array
types etc.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm/wasm-type.cpp | 111 |
1 files changed, 69 insertions, 42 deletions
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 2c7c3e232..8b1dfb0af 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -1007,49 +1007,76 @@ Type Type::reinterpret() const { FeatureSet Type::getFeatures() const { auto getSingleFeatures = [](Type t) -> FeatureSet { if (t.isRef()) { - // A reference type implies we need that feature. Some also require more, - // such as GC or exceptions. - auto heapType = t.getHeapType(); - if (heapType.isBasic()) { - switch (heapType.getBasic()) { - case HeapType::ext: - case HeapType::func: - return FeatureSet::ReferenceTypes; - case HeapType::any: - case HeapType::eq: - case HeapType::i31: - case HeapType::struct_: - case HeapType::array: - return FeatureSet::ReferenceTypes | FeatureSet::GC; - case HeapType::string: - case HeapType::stringview_wtf8: - case HeapType::stringview_wtf16: - case HeapType::stringview_iter: - return FeatureSet::ReferenceTypes | FeatureSet::Strings; - case HeapType::none: - case HeapType::noext: - case HeapType::nofunc: - // Technically introduced in GC, but used internally as part of - // ref.null with just reference types. - return FeatureSet::ReferenceTypes; + // A reference type implies we need that feature. Some also require + // more, such as GC or exceptions, and may require us to look into child + // types. + struct ReferenceFeatureCollector + : HeapTypeChildWalker<ReferenceFeatureCollector> { + FeatureSet feats = FeatureSet::None; + + void noteChild(HeapType* heapType) { + if (heapType->isBasic()) { + switch (heapType->getBasic()) { + case HeapType::ext: + case HeapType::func: + feats |= FeatureSet::ReferenceTypes; + return; + case HeapType::any: + case HeapType::eq: + case HeapType::i31: + case HeapType::struct_: + case HeapType::array: + feats |= FeatureSet::ReferenceTypes | FeatureSet::GC; + return; + case HeapType::string: + case HeapType::stringview_wtf8: + case HeapType::stringview_wtf16: + case HeapType::stringview_iter: + feats |= FeatureSet::ReferenceTypes | FeatureSet::Strings; + return; + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + // Technically introduced in GC, but used internally as part of + // ref.null with just reference types. + feats |= FeatureSet::ReferenceTypes; + return; + } + } + + if (heapType->isStruct() || heapType->isArray() || + heapType->getRecGroup().size() > 1 || heapType->getSuperType()) { + feats |= FeatureSet::ReferenceTypes | FeatureSet::GC; + } else if (heapType->isSignature()) { + // This is a function reference, which requires reference types and + // possibly also multivalue (if it has multiple returns). Note that + // technically typed function references also require GC, however, + // we use these types internally regardless of the presence of GC + // (in particular, since during load of the wasm we don't know the + // features yet, so we apply the more refined types), so we don't + // add that in any case here. + feats |= FeatureSet::ReferenceTypes; + auto sig = heapType->getSignature(); + if (sig.results.isTuple()) { + feats |= FeatureSet::Multivalue; + } + } + + // In addition, scan their non-ref children, to add dependencies on + // things like SIMD. + for (auto child : heapType->getTypeChildren()) { + if (!child.isRef()) { + feats |= child.getFeatures(); + } + } } - } - if (heapType.isStruct() || heapType.isArray() || - heapType.getRecGroup().size() > 1 || heapType.getSuperType()) { - return FeatureSet::ReferenceTypes | FeatureSet::GC; - } - // Otherwise, this is a function reference, which requires reference types - // and possibly also multivalue (if it has multiple returns). - // Note: Technically typed function references also require GC, however, - // we use these types internally regardless of the presence of GC (in - // particular, since during load of the wasm we don't know the features - // yet, so we apply the more refined types), so we don't add that in any - // case here. - FeatureSet feats = FeatureSet::ReferenceTypes; - if (heapType.getSignature().results.isTuple()) { - feats |= FeatureSet::Multivalue; - } - return feats; + }; + + ReferenceFeatureCollector collector; + auto heapType = t.getHeapType(); + collector.walkRoot(&heapType); + collector.noteChild(&heapType); + return collector.feats; } TODO_SINGLE_COMPOUND(t); switch (t.getBasic()) { |