Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How handle the THIS parameter of virtual methods? #144

Closed
Horcrux7 opened this issue Sep 26, 2020 · 8 comments
Closed

How handle the THIS parameter of virtual methods? #144

Horcrux7 opened this issue Sep 26, 2020 · 8 comments

Comments

@Horcrux7
Copy link

What is the best practice with the current MVP to implements the THIS parameter of virtual methods which type is different depending the real method implementation. The follow example compiled with WASP and run with V8 produce a function signature mismatch

  • In this sample there are 2 types (classes) Abc and Abc2.
  • Abc represent the super class and Abc2 represent the extended class.
  • Both have a method bar ( the functions Abc.bar and Abc2.bar).
  • Now it create an instance of Abc2 and assign it to a variable of the super type Abc
  • Now it call the method with a signature of Abc.bar. In real it is via dynamic dispatch the function of Abc2.bar
  • This result in the error.
(module
  (type $t0 (func(result i32)))
  (type $t1 (func(param (ref null $Abc))))
  (type $t2 (func(param (ref null $Abc2))))

  (type $Abc (struct
    (field $a (mut i32))
  ))
  (type $Abc2 (struct
    (field $a (mut i32))
  ))

  (export "test" (func $test))
  (func $test(result i32)(local $val (ref null $Abc))
    rtt.canon $Abc2
    struct.new_default_with_rtt $Abc2
    local.tee 0

    i32.const 2 ;; Abc2.bar(this)
    call_indirect (type $t1)  ;; <-- function signature mismatch because signature of THIS of $t1 different from $t2

    local.get 0
    struct.get $Abc 0
    return
  )

  (func $Abc.bar(param $this (ref null $Abc))
    local.get $this
    i32.const 2
    struct.set $Abc 0
    return
  )

  (func $Abc2.bar(param $this (ref null $Abc2))
    local.get $this
    i32.const 3
    struct.set $Abc2 0
    return
  )

  (table $functions 3 funcref)
  (elem (i32.const 0) 0 1 2 )
)

The only solution I see right now is to implement all THIS parameters with the same type. And, if necessary, assign a new local variable with the real type via cast if needed. Is this the right solution for the current MVP? This can look like:

  (func $Abc2.bar(param $this (ref null $Abc2))(local $this2 (ref null $Abc2))
    local.get $this
    local.tee $this2
    i32.const 3
    struct.set $Abc2 0
    return
  )
@conrad-watt
Copy link
Contributor

Yes, this sounds correct. Currently the expectation is that this parameters must be anyref in general (or a least a uniform supertype). There are ongoing discussions on improving this situation through post-MVP features (e.g. here).

For fairness I should also point out that @RossTate has a different take on the issue (here).

@Horcrux7
Copy link
Author

A possible solution seams to use function references. If I add the follow function:

  (func $getBarMethod(result (ref $t1))
    ref.func $Abc2.bar
    return
  )

then I can replace the calling lines:

    i32.const 2 ;; Abc2.bar(this)
    call_indirect (type $t1)  ;; <-- function signature mismatch because signature of THIS of $t1 different from $t2

with:

    call $getBarMethod
    call_ref

This work with current V8. Functions references seems to check fewer strong. The disadvantages is that it required an extra function for every virtual method now. I think this must be combined with tables to simplified.

@conrad-watt
Copy link
Contributor

@Horcrux7 I'm sorry, I didn't look closely enough at your example. In your code, $Abc and $Abc2 are structurally the exact same type (and therefore so are $t1 and $t2), so even your first example should work. V8's implementation of the type system isn't complete, so it's likely that the types aren't being fully canonicalised. It's likely that your second example works because $t1 and $t2 are (correctly) being compared for structural equality when typing $getBarMethod.

In general though, $Abc2 could be a strict subtype of $Abc (e.g. it could have an extra field). In this case, I'd expect your second example to error as well.

@RossTate

This comment has been minimized.

@conrad-watt

This comment has been minimized.

@RossTate

This comment has been minimized.

@Horcrux7
Copy link
Author

@conrad-watt Thanks for the hint. I simplify the sample. Of course can have the type Abc2 extra fields.

@tlively
Copy link
Member

tlively commented Feb 23, 2022

I'll close this issue because the original question has been answered. Feel free to reopen it if there are follow-on questions!

@tlively tlively closed this as completed Feb 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants