diff options
author | Thomas Lively <tlively@google.com> | 2022-10-07 08:02:09 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-07 06:02:09 -0700 |
commit | 7fc26f3e78f72ecaa5b79ebe042b95a0be422327 (patch) | |
tree | f87c84fc691aaf311fbd71c176ee37723c76ae20 /src/passes/Print.cpp | |
parent | e8884de3c880a7de4bb1f8eae3df5f00f4164b4d (diff) | |
download | binaryen-7fc26f3e78f72ecaa5b79ebe042b95a0be422327.tar.gz binaryen-7fc26f3e78f72ecaa5b79ebe042b95a0be422327.tar.bz2 binaryen-7fc26f3e78f72ecaa5b79ebe042b95a0be422327.zip |
Implement bottom heap types (#5115)
These types, `none`, `nofunc`, and `noextern` are uninhabited, so references to
them can only possibly be null. To simplify the IR and increase type precision,
introduce new invariants that all `ref.null` instructions must be typed with one
of these new bottom types and that `Literals` have a bottom type iff they
represent null values. These new invariants requires several additional changes.
First, it is now possible that the `ref` or `target` child of a `StructGet`,
`StructSet`, `ArrayGet`, `ArraySet`, or `CallRef` instruction has a bottom
reference type, so it is not possible to determine what heap type annotation to
emit in the binary or text formats. (The bottom types are not valid type
annotations since they do not have indices in the type section.)
To fix that problem, update the printer and binary emitter to emit unreachables
instead of the instruction with undetermined type annotation. This is a valid
transformation because the only possible value that could flow into those
instructions in that case is null, and all of those instructions trap on nulls.
That fix uncovered a latent bug in the binary parser in which new unreachables
within unreachable code were handled incorrectly. This bug was not previously
found by the fuzzer because we generally stop emitting code once we encounter an
instruction with type `unreachable`. Now, however, it is possible to emit an
`unreachable` for instructions that do not have type `unreachable` (but are
known to trap at runtime), so we will continue emitting code. See the new
test/lit/parse-double-unreachable.wast for details.
Update other miscellaneous code that creates `RefNull` expressions and null
`Literals` to maintain the new invariants as well.
Diffstat (limited to 'src/passes/Print.cpp')
-rw-r--r-- | src/passes/Print.cpp | 55 |
1 files changed, 42 insertions, 13 deletions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 01b004d97..7ebad3322 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -115,6 +115,15 @@ bool maybePrintRefShorthand(std::ostream& o, Type type) { case HeapType::stringview_iter: o << "stringview_iter"; return true; + case HeapType::none: + o << "nullref"; + return true; + case HeapType::noext: + o << "nullexternref"; + return true; + case HeapType::nofunc: + o << "nullfuncref"; + return true; } } return false; @@ -2058,10 +2067,17 @@ struct PrintExpressionContents } return false; } + bool printUnreachableOrNullReplacement(Expression* curr) { + if (curr->type == Type::unreachable || curr->type.isNull()) { + printMedium(o, "block"); + return true; + } + return false; + } void visitCallRef(CallRef* curr) { // TODO: Workaround if target has bottom type. - if (printUnreachableReplacement(curr->target)) { + if (printUnreachableOrNullReplacement(curr->target)) { return; } printMedium(o, curr->isReturn ? "return_call_ref " : "call_ref "); @@ -2144,7 +2160,7 @@ struct PrintExpressionContents }); } void visitStructGet(StructGet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } auto heapType = curr->ref->type.getHeapType(); @@ -2163,7 +2179,7 @@ struct PrintExpressionContents printFieldName(heapType, curr->index); } void visitStructSet(StructSet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } printMedium(o, "struct.set "); @@ -2192,7 +2208,7 @@ struct PrintExpressionContents TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); } void visitArrayGet(ArrayGet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } const auto& element = curr->ref->type.getHeapType().getArray().element; @@ -2208,22 +2224,22 @@ struct PrintExpressionContents TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } void visitArraySet(ArraySet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } printMedium(o, "array.set "); TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } void visitArrayLen(ArrayLen* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } printMedium(o, "array.len "); TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } void visitArrayCopy(ArrayCopy* curr) { - if (printUnreachableReplacement(curr->srcRef) || - printUnreachableReplacement(curr->destRef)) { + if (printUnreachableOrNullReplacement(curr->srcRef) || + printUnreachableOrNullReplacement(curr->destRef)) { return; } printMedium(o, "array.copy "); @@ -2746,19 +2762,29 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { drop.value = child; printFullLine(&drop); } + Unreachable unreachable; + printFullLine(&unreachable); decIndent(); } + // This must be used for the same Expressions that use + // PrintExpressionContents::printUnreachableOrNullReplacement. + void maybePrintUnreachableOrNullReplacement(Expression* curr, Type type) { + if (type.isNull()) { + type = Type::unreachable; + } + maybePrintUnreachableReplacement(curr, type); + } void visitCallRef(CallRef* curr) { - maybePrintUnreachableReplacement(curr, curr->target->type); + maybePrintUnreachableOrNullReplacement(curr, curr->target->type); } void visitStructNew(StructNew* curr) { maybePrintUnreachableReplacement(curr, curr->type); } void visitStructSet(StructSet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } void visitStructGet(StructGet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } void visitArrayNew(ArrayNew* curr) { maybePrintUnreachableReplacement(curr, curr->type); @@ -2767,10 +2793,13 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { maybePrintUnreachableReplacement(curr, curr->type); } void visitArraySet(ArraySet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } void visitArrayGet(ArrayGet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); + } + void visitArrayLen(ArrayLen* curr) { + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } // Module-level visitors void printSupertypeOr(HeapType curr, std::string noSuper) { |