summaryrefslogtreecommitdiff
path: root/src/passes/Print.cpp
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2022-10-07 08:02:09 -0500
committerGitHub <noreply@github.com>2022-10-07 06:02:09 -0700
commit7fc26f3e78f72ecaa5b79ebe042b95a0be422327 (patch)
treef87c84fc691aaf311fbd71c176ee37723c76ae20 /src/passes/Print.cpp
parente8884de3c880a7de4bb1f8eae3df5f00f4164b4d (diff)
downloadbinaryen-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.cpp55
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) {