summaryrefslogtreecommitdiff
path: root/test/lit/exec/read-nn-null.wast
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-08-31 08:21:51 -0700
committerGitHub <noreply@github.com>2022-08-31 08:21:51 -0700
commit8e1abd1eff79fa25f0dda7ccb529f672f0d90388 (patch)
treed8ccab7a8d7a01a4bbddef273952f028b8a87d0e /test/lit/exec/read-nn-null.wast
parentda24ef6ed7055f64299fce22a051ba0e85284c23 (diff)
downloadbinaryen-8e1abd1eff79fa25f0dda7ccb529f672f0d90388.tar.gz
binaryen-8e1abd1eff79fa25f0dda7ccb529f672f0d90388.tar.bz2
binaryen-8e1abd1eff79fa25f0dda7ccb529f672f0d90388.zip
[Wasm GC] Support non-nullable locals in the "1a" form (#4959)
An overview of this is in the README in the diff here (conveniently, it is near the top of the diff). Basically, we fix up nn locals after each pass, by default. This keeps things easy to reason about - what validates is what is valid wasm - but there are some minor nuances as mentioned there, in particular, we ignore nameless blocks (which are commonly added by various passes; ignoring them means we can keep more locals non-nullable). The key addition here is LocalStructuralDominance which checks which local indexes have the "structural dominance" property of 1a, that is, that each get has a set in its block or an outer block that precedes it. I optimized that function quite a lot to reduce the overhead of running that logic after each pass. The overhead is something like 2% on J2Wasm and 0% on Dart (0%, because in this mode we shrink code size, so there is less work actually, and it balances out). Since we run fixups after each pass, this PR removes logic to manually call the fixup code from various places we used to call it (like eh-utils and various passes). Various passes are now marked as requiresNonNullableLocalFixups => false. That lets us skip running the fixups after them, which we normally do automatically. This helps avoid overhead. Most passes still need the fixups, though - any pass that adds a local, or a named block, or moves code around, likely does. This removes a hack in SimplifyLocals that is no longer needed. Before we worked to avoid moving a set into a try, as it might not validate. Now, we just do it and let fixups happen automatically if they need to: in the common code they probably don't, so the extra complexity seems not worth it. Also removes a hack from StackIR. That hack tried to avoid roundtrip adding a nondefaultable local. But we have the logic to fix that up now, and opts will likely keep it non-nullable as well. Various tests end up updated here because now a local can be non-nullable - previous fixups are no longer needed. Note that this doesn't remove the gc-nn-locals feature. That has been useful for testing, and may still be useful in the future - it basically just allows nn locals in all positions (that can't read the null default value at the entry). We can consider removing it separately. Fixes #4824
Diffstat (limited to 'test/lit/exec/read-nn-null.wast')
-rw-r--r--test/lit/exec/read-nn-null.wast74
1 files changed, 74 insertions, 0 deletions
diff --git a/test/lit/exec/read-nn-null.wast b/test/lit/exec/read-nn-null.wast
new file mode 100644
index 000000000..d72688969
--- /dev/null
+++ b/test/lit/exec/read-nn-null.wast
@@ -0,0 +1,74 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items --output=fuzz-exec and should not be edited.
+
+;; RUN: wasm-opt %s -all --coalesce-locals --optimize-instructions --fuzz-exec -q -o /dev/null 2>&1 | filecheck %s --check-prefix=NORMAL
+;; RUN: wasm-opt %s -tnh -all --coalesce-locals --optimize-instructions --fuzz-exec -q -o /dev/null 2>&1 | filecheck %s --check-prefix=TNH
+
+;; The sequence of passes here will do the following:
+;;
+;; * coalesce-locals will remove the local.set. That does not reach any
+;; local.get due to the unreachable, so it is a dead store that we can
+;; remove.
+;; * optimize-instructions will reorder the select's arms (to get rid of the
+;; i32.eqz). It looks ok to reorder them because the local.get on one arm has
+;; no side effects at all.
+;;
+;; After those, if we did not fix up non-nullable locals in between, then we'd
+;; end up executing a local.get of a non-nullable local that has no local.set,
+;; which means we are reading a null by a non-nullable local - an internal
+;; error. We avoid this situation by fixing up non-nullable locals in between
+;; these passes, which adds a ref.as_non_null on the local.get, and that
+;; possibly-trapping instruction will prevent dangerous reordering. In
+;; particular, --fuzz-exec result should be identical before and after: always
+;; log 42 and then trap on that unreachable.
+;;
+;; This also tests traps-never-happen mode. Atm that mode changes nothing here,
+;; but that may change in the future as tnh starts to optimize more things. In
+;; particular, tnh can in principle remove the ref.as_non_null that is added on
+;; the local.get, which would then let optimize-instructions reorder - but that
+;; will still not affect observable behavior, so it is fine.
+
+(module
+ (import "fuzzing-support" "log-i32" (func $log (param i32)))
+
+ (func $foo (export "foo") (param $i i32) (result funcref)
+ (local $ref (ref func))
+ (local.set $ref
+ (ref.func $foo)
+ )
+ (select (result funcref)
+ (block $trap (result funcref)
+ (call $log
+ (i32.const 42)
+ )
+ ;; We never reach the br, but its existence makes the block's type none
+ ;; instead of unreachable (optimization passes may ignore such
+ ;; obviously-unreachable code, so we make it less obvious this way).
+ (unreachable)
+ (br $trap
+ (ref.func $foo)
+ )
+ )
+ (local.get $ref)
+ (i32.eqz
+ (local.get $i)
+ )
+ )
+ )
+)
+;; NORMAL: [fuzz-exec] calling foo
+;; NORMAL-NEXT: [LoggingExternalInterface logging 42]
+;; NORMAL-NEXT: [trap unreachable]
+
+;; NORMAL: [fuzz-exec] calling foo
+;; NORMAL-NEXT: [LoggingExternalInterface logging 42]
+;; NORMAL-NEXT: [trap unreachable]
+;; NORMAL-NEXT: [fuzz-exec] comparing foo
+
+;; TNH: [fuzz-exec] calling foo
+;; TNH-NEXT: [LoggingExternalInterface logging 42]
+;; TNH-NEXT: [trap unreachable]
+
+;; TNH: [fuzz-exec] calling foo
+;; TNH-NEXT: [LoggingExternalInterface logging 42]
+;; TNH-NEXT: [trap unreachable]
+;; TNH-NEXT: [fuzz-exec] comparing foo