summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/literal.cpp65
-rw-r--r--test/lit/exec/eh-print.wast43
2 files changed, 92 insertions, 16 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index a0e3d2bf6..075028127 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -540,7 +540,36 @@ void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) {
o << std::dec;
}
+// Printing literals is mainly for debugging purposes, and they can be of
+// massive size or even infinitely recursive, so abbreviate past some point.
+// We do so by tracking how much we've printed so far, and whether we are the
+// "toplevel" call (the entry point from somewhere else), and we reset the
+// count when we leave the toplevel call.
+namespace {
+struct PrintLimiter {
+ static const size_t PRINT_LIMIT = 100;
+ static thread_local size_t printed;
+
+ bool isTopLevel;
+
+ PrintLimiter() : isTopLevel(printed == 0) { printed++; }
+
+ ~PrintLimiter() {
+ if (isTopLevel) {
+ printed = 0;
+ }
+ }
+
+ bool stop() { return printed >= PRINT_LIMIT; }
+};
+
+thread_local size_t PrintLimiter::printed = 0;
+
+} // namespace
+
std::ostream& operator<<(std::ostream& o, Literal literal) {
+ PrintLimiter limiter;
+
prepareMinorColor(o);
assert(literal.type.isSingle());
if (literal.type.isBasic()) {
@@ -618,7 +647,6 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
assert(literal.isData());
auto data = literal.getGCData();
assert(data);
- // TODO: infinite recursion is possible here, if the data is cyclic
o << "[ref " << data->type << ' ' << data->values << ']';
}
}
@@ -626,27 +654,32 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
return o;
}
-// Printing literals is mainly for debugging purposes, and they can be of
-// massive size, so abbreviate past some point.
-static size_t LITERALS_PRINT_LIMIT = 20;
-
std::ostream& operator<<(std::ostream& o, wasm::Literals literals) {
+ PrintLimiter limiter;
+
+ if (limiter.stop()) {
+ return o << "[..]";
+ }
+
if (literals.size() == 1) {
return o << literals[0];
- } else {
- o << '(';
- if (literals.size() > 0) {
- o << literals[0];
+ }
+
+ o << '(';
+ bool first = true;
+ for (auto& literal : literals) {
+ if (limiter.stop()) {
+ o << "[..]";
+ break;
}
- for (size_t i = 1; i < literals.size(); ++i) {
- o << ", " << literals[i];
- if (i == LITERALS_PRINT_LIMIT) {
- o << "[..]";
- break;
- }
+ if (first) {
+ first = false;
+ } else {
+ o << ", ";
}
- return o << ')';
+ o << literal;
}
+ return o << ')';
}
Literal Literal::countLeadingZeroes() const {
diff --git a/test/lit/exec/eh-print.wast b/test/lit/exec/eh-print.wast
new file mode 100644
index 000000000..8f9520e75
--- /dev/null
+++ b/test/lit/exec/eh-print.wast
@@ -0,0 +1,43 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --output=fuzz-exec and should not be edited.
+
+;; RUN: wasm-opt %s -all --fuzz-exec-before -q -o /dev/null 2>&1 | filecheck %s
+
+(module
+ (tag $A (param (ref $A)))
+ (tag $B (param (ref $B)))
+
+ (type $A (array (field (mut i32))))
+
+ (type $B (struct (field (mut anyref))))
+
+ ;; CHECK: [fuzz-exec] calling array
+ ;; CHECK-NEXT: [exception thrown: A [ref (type $array.0 (array (mut i32))) (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0[..])]]
+ (func "array" (result (ref $A))
+ ;; Throw a very large array. We should not print all 12K items in it, as that
+ ;; would be very verbose. Instead we stop after a reasonable amount and
+ ;; print [..] for the rest.
+ (throw $A
+ (array.new_default $A
+ (i32.const 12345)
+ )
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling struct
+ ;; CHECK-NEXT: [exception thrown: B [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [..]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+ (func "struct" (result (ref $B))
+ (local $x (ref $B))
+ ;; As above, but now with a recursive struct.
+ (local.set $x
+ (struct.new_default $B)
+ )
+ (struct.set $B 0
+ (local.get $x)
+ (local.get $x)
+ )
+ (throw $B
+ (local.get $x)
+ )
+ )
+)
+