blob: 60fb2f43380703ae7e59642ba9c324eef2f4938d [file]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: wasm-opt %s -all --closed-world --preserve-type-order \
;; RUN: --unsubtyping --remove-unused-types -all -S -o - | filecheck %s
(module
(rec
;; We must maintain this descriptor relationship so that when $struct flows
;; out to JS it still has the prototype configured on its descriptor.
;; CHECK: (rec
;; CHECK-NEXT: (type $struct-proto (descriptor $desc-proto) (struct))
(type $struct-proto (descriptor $desc-proto) (struct))
;; CHECK: (type $desc-proto (describes $struct-proto) (struct (field externref)))
(type $desc-proto (describes $struct-proto) (struct (field externref)))
;; But this descriptor cannot have a configured prototype, so we do not need
;; to maintain the relationship.
;; CHECK: (type $struct-no-proto (struct))
(type $struct-no-proto (descriptor $desc-no-proto) (struct))
(type $desc-no-proto (describes $struct-no-proto) (struct (field (mut externref))))
;; This descriptor has a valid prototype field, but is not sent to JS. It
;; can be optimized out.
;; CHECK: (type $struct-not-sent (struct))
(type $struct-not-sent (descriptor $desc-not-sent) (struct))
(type $desc-not-sent (describes $struct-not-sent) (struct (field externref)))
;; Receiving a type from JS as means it is implicitly cast from any, which
;; can cause the subtype relationship to be kept.
;; CHECK: (type $super-param (sub (struct)))
(type $super-param (sub (struct)))
;; CHECK: (type $sub-param (sub $super-param (struct)))
(type $sub-param (sub $super-param (struct)))
;; Returning a type to JS means it flows into an anyref posistion, which
;; can cause the subytpe relationship to be kept.
;; CHECK: (type $super-result (sub (struct)))
(type $super-result (sub (struct)))
;; CHECK: (type $sub-result (sub $super-result (struct)))
(type $sub-result (sub $super-result (struct)))
)
;; CHECK: (type $8 (func))
;; CHECK: (type $9 (func (result (ref $struct-proto))))
;; CHECK: (type $10 (func (result (ref $struct-no-proto))))
;; CHECK: (type $11 (func (param (ref $struct-not-sent))))
;; CHECK: (type $12 (func (param (ref null $super-param))))
;; CHECK: (type $13 (func (result (ref null $sub-result))))
;; CHECK: (type $prototypes (array (mut externref)))
(type $prototypes (array (mut externref)))
;; CHECK: (type $funcs (array (mut funcref)))
(type $funcs (array (mut funcref)))
;; CHECK: (type $data (array (mut i8)))
(type $data (array (mut i8)))
;; CHECK: (type $configureAll (func (param (ref null $prototypes) (ref null $funcs) (ref null $data) externref)))
(type $configureAll (func (param (ref null $prototypes)) (param (ref null $funcs)) (param (ref null $data)) (param externref)))
;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $prototypes) (ref null $funcs) (ref null $data) externref)))
(import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll)))
;; CHECK: (data $data "12345678")
(data $data "12345678")
;; CHECK: (elem $prototypes externref (item (ref.null noextern)))
(elem $prototypes externref (ref.null extern))
;; CHECK: (elem $funcs func $return-struct-proto $return-struct-no-proto $receive-proto $receive $return)
(elem $funcs funcref (ref.func $return-struct-proto) (ref.func $return-struct-no-proto) (ref.func $receive-proto) (ref.func $receive) (ref.func $return))
;; CHECK: (start $start)
(start $start)
;; CHECK: (func $start (type $8)
;; CHECK-NEXT: (call $configureAll
;; CHECK-NEXT: (array.new_elem $prototypes $prototypes
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (array.new_elem $funcs $funcs
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 5)
;; CHECK-NEXT: )
;; CHECK-NEXT: (array.new_data $data $data
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 8)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $start
(call $configureAll
(array.new_elem $prototypes $prototypes (i32.const 0) (i32.const 1))
(array.new_elem $funcs $funcs (i32.const 0) (i32.const 5))
(array.new_data $data $data (i32.const 0) (i32.const 8))
(ref.null extern)
)
)
;; CHECK: (func $return-struct-proto (type $9) (result (ref $struct-proto))
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $return-struct-proto (result (ref $struct-proto))
;; Looking at the function signature, $struct-proto flows out to JS. Since
;; its descriptor can have a configured prototype, it must be kept. It
;; doesn't matter that the function actually traps.
(unreachable)
)
;; CHECK: (func $return-struct-no-proto (type $10) (result (ref $struct-no-proto))
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $return-struct-no-proto (result (ref $struct-no-proto))
;; No need to keep a descriptor that cannot hold a configured prototype.
(unreachable)
)
;; CHECK: (func $receive-proto (type $11) (param $0 (ref $struct-not-sent))
;; CHECK-NEXT: )
(func $receive-proto (param (ref $struct-not-sent))
;; Since we are not passing $struct-not-sent to JS, we do not need to
;; preserve its descriptor, even though that descriptor could hold a
;; prototype.
)
;; CHECK: (func $receive (type $12) (param $0 (ref null $super-param))
;; CHECK-NEXT: (local $any anyref)
;; CHECK-NEXT: (local $sub-param (ref null $sub-param))
;; CHECK-NEXT: (local.set $any
;; CHECK-NEXT: (local.get $sub-param)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $receive (param (ref null $super-param))
;; There is an implicit cast from any to $super-param on the boundary. This
;; combined with $sub-param flowing into any here means that the subtyping
;; must be maintained.
(local $any anyref)
(local $sub-param (ref null $sub-param))
(local.set $any
(local.get $sub-param)
)
)
;; CHECK: (func $return (type $13) (result (ref null $sub-result))
;; CHECK-NEXT: (local $any anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.test (ref null $super-result)
;; CHECK-NEXT: (local.get $any)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $return (result (ref null $sub-result))
;; $sub-result implicitly flows into any on the boundary. This combined with
;; the cast from any to $super-result here means that the subtyping must be
;; maintained.
(local $any anyref)
(drop
(ref.test (ref null $super-result)
(local.get $any)
)
)
(unreachable)
)
)