;; 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 -o /dev/null 2>&1 | filecheck %s

;; Test the fuzzing-support module imports.

(module
 (import "fuzzing-support" "log-i32" (func $log-i32 (param i32)))
 (import "fuzzing-support" "log-f64" (func $log-f64 (param f64)))

 (import "fuzzing-support" "throw" (func $throw))

 (import "fuzzing-support" "table-set" (func $table.set (param i32 funcref)))
 (import "fuzzing-support" "table-get" (func $table.get (param i32) (result funcref)))

 (import "fuzzing-support" "call-export" (func $call.export (param i32)))
 (import "fuzzing-support" "call-export-catch" (func $call.export.catch (param i32) (result i32)))

 (import "fuzzing-support" "call-ref" (func $call.ref (param funcref)))
 (import "fuzzing-support" "call-ref-catch" (func $call.ref.catch (param funcref) (result i32)))

 (import "fuzzing-support" "sleep" (func $sleep (param i32 i32) (result i32)))

 (table $table 10 20 funcref)

 ;; Note that the exported table appears first here, but in the binary and in
 ;; the IR it is actually last, as we always add function exports first.
 (export "table" (table $table))

 ;; CHECK:      [fuzz-exec] calling logging
 ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
 (func $logging (export "logging")
  (call $log-i32
   (i32.const 42)
  )
  (call $log-f64
   (f64.const 3.14159)
  )
 )

 ;; CHECK:      [fuzz-exec] calling throwing
 ;; CHECK-NEXT: [exception thrown: __private ()]
 (func $throwing (export "throwing")
  (call $throw)
 )

 ;; CHECK:      [fuzz-exec] calling table.setting
 ;; CHECK-NEXT: [exception thrown: __private ()]
 (func $table.setting (export "table.setting")
  (call $table.set
   (i32.const 5)
   (ref.func $table.setting)
  )
  ;; Out of bounds sets will throw.
  (call $table.set
   (i32.const 9999)
   (ref.func $table.setting)
  )
 )

 ;; CHECK:      [fuzz-exec] calling table.getting
 ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 ;; CHECK-NEXT: [exception thrown: __private ()]
 (func $table.getting (export "table.getting")
  ;; There is a non-null value at 5, and a null at 6.
  (call $log-i32
   (ref.is_null
    (call $table.get
     (i32.const 5)
    )
   )
  )
  (call $log-i32
   (ref.is_null
    (call $table.get
     (i32.const 6)
    )
   )
  )
  ;; Out of bounds gets will throw.
  (drop
   (call $table.get
    (i32.const 9999)
   )
  )
 )

 ;; CHECK:      [fuzz-exec] calling export.calling
 ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
 ;; CHECK-NEXT: [exception thrown: __private ()]
 (func $export.calling (export "export.calling")
  ;; At index 0 in the exports we have $logging, so we will do those loggings.
  (call $call.export
   (i32.const 0)
  )
  ;; At index 999 we have nothing, so we'll error.
  (call $call.export
   (i32.const 999)
  )
 )

 ;; CHECK:      [fuzz-exec] calling export.calling.catching
 ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 (func $export.calling.catching (export "export.calling.catching")
  ;; At index 0 in the exports we have $logging, so we will do those loggings,
  ;; then log a 0 as no exception happens.
  (call $log-i32
   (call $call.export.catch
    (i32.const 0)
   )
  )
  ;; At index 999 we have nothing, so we'll error, catch it, and log 1.
  (call $log-i32
   (call $call.export.catch
    (i32.const 999)
   )
  )
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling
 ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
 ;; CHECK-NEXT: [exception thrown: __private ()]
 (func $ref.calling (export "ref.calling")
  ;; This will emit some logging.
  (call $call.ref
   (ref.func $logging)
  )
  ;; This will throw.
  (call $call.ref
   (ref.null func)
  )
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.catching
 ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 (func $ref.calling.catching (export "ref.calling.catching")
  ;; This will emit some logging, then log 0 as we do not error.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $logging)
   )
  )
  ;; The exception here is caught, and we'll log 1.
  (call $log-i32
   (call $call.ref.catch
    (ref.null func)
   )
  )
 )

 (func $legal (param $x i32) (result i32)
  ;; Helper for the function below. All types here are legal for JS.
  (call $log-i32
   (i32.const 12)
  )
  ;; Also log the param to show it is 0, which is what $call.ref does for all
  ;; params.
  (call $log-i32
   (local.get $x)
  )
  (i32.const 34)
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.legal
 ;; CHECK-NEXT: [LoggingExternalInterface logging 12]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
 (func $ref.calling.legal (export "ref.calling.legal")
  ;; It is fine to call-ref a function with params and results. The params get
  ;; default values, and the results are ignored. All we will see here is the
  ;; logging from the function, "12".
  (call $call.ref
   (ref.func $legal)
  )
 )

 (func $illegal (param $x i64)
  ;; Helper for the function below. The param, an i64, causes a problem: when we
  ;; call from JS we provide 0, but 0 throws when it tries to convert to BigInt.
  (call $log-i32
   (i32.const 56)
  )
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.illegal
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 (func $ref.calling.illegal (export "ref.calling.illegal")
  ;; The i64 param causes an error here, so we will only log 1 because we catch an exception.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $illegal)
   )
  )
 )

 (func $illegal-v128 (param $x v128)
  ;; Helper for the function below.
  (call $log-i32
   (i32.const 56)
  )
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.illegal-v128
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 (func $ref.calling.illegal-v128 (export "ref.calling.illegal-v128")
  ;; As above, we throw on the v128 param, and log 1.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $illegal-v128)
   )
  )
 )

 (func $illegal-exnref (param $x exnref)
  ;; Helper for the function below.
  (call $log-i32
   (i32.const 57)
  )
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.illegal-exnref
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 (func $ref.calling.illegal-exnref (export "ref.calling.illegal-exnref")
  ;; As above, we throw on the exnref param, and log 1.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $illegal-exnref)
   )
  )
 )

 (func $illegal-result (result v128)
  ;; Helper for the function below. The result is illegal for JS.
  (call $log-i32
   (i32.const 910)
  )
  (v128.const i32x4 1 2 3 4)
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.illegal-result
 ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
 (func $ref.calling.illegal-result (export "ref.calling.illegal-result")
  ;; The v128 result causes an error here, so we will log 1 as an exception. The JS
  ;; semantics determine that we do that check *before* the call, so the logging
  ;; of 910 does not go through.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $illegal-result)
   )
  )
 )

 (func $legal-result (result i64)
  ;; Helper for the function below.
  (call $log-i32
   (i32.const 910)
  )
  (i64.const 90)
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.legal-result
 ;; CHECK-NEXT: [LoggingExternalInterface logging 910]
 ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
 (func $ref.calling.legal-result (export "ref.calling.legal-result")
  ;; Unlike v128, i64 is legal in a result. The JS VM just returns a BigInt.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $legal-result)
   )
  )
 )

 (func $trap
  ;; Helper for the function below.
  (unreachable)
 )

 ;; CHECK:      [fuzz-exec] calling ref.calling.trap
 ;; CHECK-NEXT: [trap unreachable]
 (func $ref.calling.trap (export "ref.calling.trap")
  ;; We try to catch an exception here, but the target function traps, which is
  ;; not something we can catch. We will trap here, and not log at all.
  (call $log-i32
   (call $call.ref.catch
    (ref.func $trap)
   )
  )
 )

 ;; CHECK:      [fuzz-exec] calling do-sleep
 ;; CHECK-NEXT: [fuzz-exec] note result: do-sleep => 42
 ;; CHECK-NEXT: warning: no passes specified, not doing any work
 (func $do-sleep (export "do-sleep") (result i32)
  (call $sleep
   ;; A ridiculous amount of ms, but in the interpreter it is ignored anyhow.
   (i32.const -1)
   ;; An id, that is returned back to us.
   (i32.const 42)
  )
 )
)
;; CHECK:      [fuzz-exec] calling logging
;; CHECK-NEXT: [LoggingExternalInterface logging 42]
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]

;; CHECK:      [fuzz-exec] calling throwing
;; CHECK-NEXT: [exception thrown: __private ()]

;; CHECK:      [fuzz-exec] calling table.setting
;; CHECK-NEXT: [exception thrown: __private ()]

;; CHECK:      [fuzz-exec] calling table.getting
;; CHECK-NEXT: [LoggingExternalInterface logging 0]
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
;; CHECK-NEXT: [exception thrown: __private ()]

;; CHECK:      [fuzz-exec] calling export.calling
;; CHECK-NEXT: [LoggingExternalInterface logging 42]
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
;; CHECK-NEXT: [exception thrown: __private ()]

;; CHECK:      [fuzz-exec] calling export.calling.catching
;; CHECK-NEXT: [LoggingExternalInterface logging 42]
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
;; CHECK-NEXT: [LoggingExternalInterface logging 0]
;; CHECK-NEXT: [LoggingExternalInterface logging 1]

;; CHECK:      [fuzz-exec] calling ref.calling
;; CHECK-NEXT: [LoggingExternalInterface logging 42]
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
;; CHECK-NEXT: [exception thrown: __private ()]

;; CHECK:      [fuzz-exec] calling ref.calling.catching
;; CHECK-NEXT: [LoggingExternalInterface logging 42]
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
;; CHECK-NEXT: [LoggingExternalInterface logging 0]
;; CHECK-NEXT: [LoggingExternalInterface logging 1]

;; CHECK:      [fuzz-exec] calling ref.calling.legal
;; CHECK-NEXT: [LoggingExternalInterface logging 12]
;; CHECK-NEXT: [LoggingExternalInterface logging 0]

;; CHECK:      [fuzz-exec] calling ref.calling.illegal
;; CHECK-NEXT: [LoggingExternalInterface logging 1]

;; CHECK:      [fuzz-exec] calling ref.calling.illegal-v128
;; CHECK-NEXT: [LoggingExternalInterface logging 1]

;; CHECK:      [fuzz-exec] calling ref.calling.illegal-exnref
;; CHECK-NEXT: [LoggingExternalInterface logging 1]

;; CHECK:      [fuzz-exec] calling ref.calling.illegal-result
;; CHECK-NEXT: [LoggingExternalInterface logging 1]

;; CHECK:      [fuzz-exec] calling ref.calling.legal-result
;; CHECK-NEXT: [LoggingExternalInterface logging 910]
;; CHECK-NEXT: [LoggingExternalInterface logging 0]

;; CHECK:      [fuzz-exec] calling ref.calling.trap
;; CHECK-NEXT: [trap unreachable]

;; CHECK:      [fuzz-exec] calling do-sleep
;; CHECK-NEXT: [fuzz-exec] note result: do-sleep => 42
;; CHECK-NEXT: [fuzz-exec] comparing do-sleep
;; CHECK-NEXT: [fuzz-exec] comparing export.calling
;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching
;; CHECK-NEXT: [fuzz-exec] comparing logging
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-exnref
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-result
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-v128
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal-result
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.trap
;; CHECK-NEXT: [fuzz-exec] comparing table.getting
;; CHECK-NEXT: [fuzz-exec] comparing table.setting
;; CHECK-NEXT: [fuzz-exec] comparing throwing