Closed poorna2152 closed 2 years ago
1.
the code fails.
What is the error?
2.
See: https://github.com/WebAssembly/gc/blob/main/proposals/gc/MVP.md#runtime-types
Can we use (ref.cast (ref.as_data (local.get $0)) (global.get $rttAny))
like shown in above?
(global $rttA (rtt $Any) (rtt.canon $Any))
(global $rttB (rtt $BoxedInt) (rtt.canon $BoxedInt))
(func $get_type_code (param $0 eqref) (result i32) (struct.get $Any $type (ref.cast (ref.as_data (local.get $0)) (global.get $rttA))))
(module
(type $BoxedInt (struct (field $type i32) (field $val i64)))
(type $Any (struct (field $type i32)))
(import "console" "log" (func $println (param i32)))
(export "main" (func $main))
(export "get_type" (func $get_type))
(func $main
(local $0 eqref)
(local.set $0
(call $int_to_tagged
(i64.const 21)))
(call $println
(call $get_type
(local.get $0))))
(func $int_to_tagged (param $0 i64) (result (ref $BoxedInt))
(return
(struct.new_with_rtt $BoxedInt
(i32.const 7)
(local.get $0)
(rtt.canon $BoxedInt))))
(func $tagged_to_int (param $0 (ref $BoxedInt)) (result i64)
(return
(struct.get $BoxedInt $val
(local.get $0))))
(func $get_type (param $0 eqref) (result i32)
(if
(ref.is_i31
(local.get $0))
(return
(i32.const 1)) ;; TYPE_BOOLEAN
(if
(ref.is_null
(local.get $0))
(return
(i32.const 0)) ;; TYPE_NIL
(return
(struct.get $Any $type
(ref.cast
(ref.as_data
(local.get $0))
(rtt.canon $Any))))))))
When defining a global
(global $rttBoxedInt (rtt $BoxedInt) (rtt.canon $BoxedInt ))
Three arguments are $rttBoxedInt -> name (rtt $BoxedInt) -> type of the variable (rtt.canon $BoxedInt ) -> Initial value
This program gets compiled but doesn't work when run in nodeJS (version v17.9.0). https://github.com/WebAssembly/binaryen/blob/main/test/spec/ref_cast.wast
In the below link they use a instruction sub
which is not there in Binaryen.
(type $B (sub $A (struct (field i32))))
https://github.com/WebAssembly/gc/blob/main/proposals/gc/MVP.md#runtime-types
From what I found out I think you can cast a supertype to a subtype but you cant do vice versa.
That is why our code is failing with an illegal cast. For example, we can cast an $Any to a $BoxedInt. But we cant cast an $BoxedInt to $Any.
Consider following get_type()
functions. Assumefor cases 1 and 2 it is called with a $BoxedInt initialized as following
(struct.new_with_rtt $BoxedInt
(i32.const 0)
(local.get $0)
(rtt.canon $BoxedInt))))
(func $get_type (param $0 (ref $Any)) (result i32)
(return
(struct.get $Any $type
(local.get $0)))))
(func $get_type (param $0 eqref) (result i32)
(return
(struct.get $Any $type
(ref.cast
(ref.as_data
(local.get $0))
(rtt.canon $Any))))))
What I was doing previously was the following and it works but is considerably slow. Now assume that for that $BoxedInt is initialized as following.
(struct.new_with_rtt $BoxedInt
(i32.const 0)
(i64.const 21)
(rtt.sub $BoxedInt
(rtt.canon $Any)))
(func $get_type (param $0 eqref) (result i32)
(return
(struct.get $Any $type
(ref.cast
(ref.as_data
(local.get $0))
(rtt.canon $Any)))))
Working example:
(module
(type $BoxedInt (struct (field $type i32) (field $val i64)))
(type $Any (struct (field $type i32)))
(global $rttAny (rtt $Any) (rtt.canon $Any))
(global $rttBoxedInt (rtt $BoxedInt) (rtt.sub $BoxedInt (global.get $rttAny)))
(import "console" "log" (func $println (param i32)))
(export "main" (func $main))
(export "get_type" (func $get_type))
(export "int_to_tagged" (func $int_to_tagged))
(func $main
(call $println
(call $get_type
(call $int_to_tagged
(i64.const 21)))))
(func $int_to_tagged (param $0 i64) (result (ref $BoxedInt))
(return
(struct.new_with_rtt $BoxedInt
(i32.const 0)
(local.get $0)
(rtt.canon $BoxedInt))))
(func $get_type (param $0 (ref $Any)) (result i32)
(return
(struct.get $Any $type
(local.get $0)))))
This was what I was using to represent subtype supertype relationship.
But apparently use of extend and using
rtt.sub
is not needed. Since both$BoxedInt
and$Any
struct definition start with a i32 field$Any
is implicitly going to be a supertype of$BoxedInt
. https://github.com/WebAssembly/gc/blob/main/proposals/gc/Overview.md#subtypingThus when we pass a
$BoxedInt
to below function it works.But, when we change the parameter of the above function to
eqref
and cast the struct to$Any
within the function, the code fails.If this failure is an intentional one then I think we cant rely on this subtype supertype representation. Then we might have to go back to my initial implementation where I used the type of the struct to get the type of a variable.