WebAssembly / gc

Branch of the spec repo scoped to discussion of GC integration in WebAssembly
https://webassembly.github.io/gc/
Other
982 stars 70 forks source link

Are functions still required to be pre-declared as referable? #499

Closed titzer closed 8 months ago

titzer commented 8 months ago

The current reference interpreter passes this test (excerpted from type-equivalence.wast):

(module
  (type $s0 (func (param i32)))
  (type $s1 (func (param i32 (ref $s0))))
  (type $s2 (func (param i32 (ref $s0))))
  (type $t1 (func (param (ref $s1))))
  (type $t2 (func (param (ref $s2))))

  (func $s1 (type $s1))
  (func $s2 (type $s2))
  (func $f1 (type $t1))
  (func $f2 (type $t2))
  (table funcref (elem $f1 $f2 $s1 $s2))

  (func (export "run")
    (call_indirect (type $t1) (ref.func $s1) (i32.const 0))
    (call_indirect (type $t1) (ref.func $s1) (i32.const 1))
    (call_indirect (type $t1) (ref.func $s2) (i32.const 0))
    (call_indirect (type $t1) (ref.func $s2) (i32.const 1))
    (call_indirect (type $t2) (ref.func $s1) (i32.const 0))
    (call_indirect (type $t2) (ref.func $s1) (i32.const 1))
    (call_indirect (type $t2) (ref.func $s2) (i32.const 0))
    (call_indirect (type $t2) (ref.func $s2) (i32.const 1))
  )
)
(assert_return (invoke "run"))

However, when translating it to .bin.wast, it does not pre-refer to the functions in the table. IIUC this is a change from previous behavior. Do we still require functions to be pre-declared (in elements) to be used with ref.func?

titzer commented 8 months ago

Update: it appears that the reference interpreter has just changed to use constant initializers (ref.func in init expressions). I guess this is intended as having been "referenced" since all such element sections can appear before bodies? If so, I'll close this issue.

tlively commented 8 months ago

I don't know what the intention is here. I don't recall ever having discussed it 😅

conrad-watt commented 8 months ago

IIRC we explicitly decided that the occurrence of a function index in a global/table initialiser, active/passive elem segment, or export would also (in addition to the "normal" declarative elem segment case) count as "referencing" for the purposes of allowing ref.func in code. This is reflected in the live spec, but I'll try to dig up a meeting or issue where this decision was recorded.

I remember @rossberg being against this relaxing at the time :)

conrad-watt commented 8 months ago

https://github.com/WebAssembly/reference-types/issues/31 https://github.com/WebAssembly/reference-types/issues/76

See @lukewagner's comment towards the end, which I think pretty much sums up the eventual decision

@rossberg What I proposed is that, in your example, since the ref.global is outside the code section, it doesn't need to have been declared. Implementation-wise, everything before the code section is effectively one big declaration for the code section, so there's no practical benefit in your example requiring the ref.global to have already been declared.

titzer commented 8 months ago

@conrad-watt Thanks for doing the legwork to dig this up. It seems the most consistent that all element segments behave the same (counting as a reference), regardless of whether they were function indexes or ref.funcs. Looks like we just didn't have a test for that case yet until recently here.

conrad-watt commented 8 months ago

It seems the most consistent that all element segments behave the same (counting as a reference), regardless of whether they were function indexes or ref.funcs

agree - especially since we previously said that occurrences of ref.func $i in global initialisers should cause $i to be counted as "declared".

rossberg commented 8 months ago

Right, IIRC, it was the group's sentiment to count every occurrence of a function reference outside a function body to be sufficient as a "forward declaration". That's what spec and interpreter implement. (This forward declaration thing probably is one of Wasm's biggest hacks.)

Legacy element segments with just function indices are desugared into reference instructions by the spec, so they naturally behave consistently.

FWIW re the OP: the text format never implies hidden forward declarations. What you see is what you get when converting to binary.

titzer commented 8 months ago

@rossberg Thanks, I think we can close this now.