Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Unify externref and anyref #271

Merged
merged 1 commit into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,7 @@ let heap_type s =
| Some i when i land 0xc0 = 0x40 ->
(match vs7 s with
| -0x10 -> FuncHeapType
| -0x11 -> ExternHeapType
| -0x12 -> AnyHeapType
| -0x11 -> AnyHeapType
| -0x13 -> EqHeapType
| -0x16 -> I31HeapType
| -0x17 -> let n = vu32 s in RttHeapType (var_type s, Some n)
Expand All @@ -180,8 +179,7 @@ let ref_type s =
let pos = pos s in
match vs7 s with
| -0x10 -> (Nullable, FuncHeapType)
| -0x11 -> (Nullable, ExternHeapType)
| -0x12 -> (Nullable, AnyHeapType)
| -0x11 -> (Nullable, AnyHeapType)
| -0x13 -> (Nullable, EqHeapType)
| -0x14 -> (Nullable, heap_type s)
| -0x15 -> (NonNullable, heap_type s)
Expand Down
9 changes: 6 additions & 3 deletions interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,24 @@ struct
| F64Type -> vs7 (-0x04)

let heap_type = function
| AnyHeapType -> vs7 (-0x12)
| AnyHeapType -> vs7 (-0x11)
| EqHeapType -> vs7 (-0x13)
| I31HeapType -> vs7 (-0x16)
| DataHeapType -> vs7 (-0x19)
| ArrayHeapType -> vs7 (-0x1a)
| FuncHeapType -> vs7 (-0x10)
| ExternHeapType -> vs7 (-0x11)
| DefHeapType x -> var_type vs33 x
| RttHeapType (x, None) -> vs7 (-0x18); var_type vu32 x
| RttHeapType (x, Some n) -> vs7 (-0x17); vs32 n; var_type vu32 x
| BotHeapType -> assert false

let ref_type = function
| (Nullable, AnyHeapType) -> vs7 (-0x11)
| (Nullable, EqHeapType) -> vs7 (-0x13)
| (NonNullable, I31HeapType) -> vs7 (-0x16)
| (NonNullable, DataHeapType) -> vs7 (-0x19)
| (NonNullable, ArrayHeapType) -> vs7 (-0x1a)
| (Nullable, FuncHeapType) -> vs7 (-0x10)
| (Nullable, ExternHeapType) -> vs7 (-0x11)
| (Nullable, t) -> vs7 (-0x14); heap_type t
| (NonNullable, t) -> vs7 (-0x15); heap_type t

Expand Down
13 changes: 4 additions & 9 deletions interpreter/script/js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,9 @@ let lookup (mods : modules) x_opt name at =

let subject_idx = 0l
let externref_idx = 1l
let is_externref_idx = 2l
let is_eqref_idx = 3l
let eq_ref_idx = 4l
let subject_type_idx = 5l
let is_eqref_idx = 2l
let eq_ref_idx = 3l
let subject_type_idx = 4l

let eq_of = function
| I32Type -> I32 I32Op.Eq
Expand Down Expand Up @@ -345,7 +344,6 @@ let assert_return ress ts at =
| DataHeapType -> RefTest DataOp
| ArrayHeapType -> RefTest ArrayOp
| FuncHeapType -> RefTest FuncOp
| ExternHeapType -> Call (is_externref_idx @@ at)
| DefHeapType _ -> Const (I32 1l @@ at) (* TODO *)
| RttHeapType _ -> Const (I32 1l @@ at) (* TODO *)
| BotHeapType -> assert false
Expand All @@ -365,15 +363,14 @@ let assert_return ress ts at =
let i32_type = NumType I32Type
let anyref_type = RefType (Nullable, AnyHeapType)
let eqref_type = RefType (Nullable, EqHeapType)
let externref_type = RefType (Nullable, ExternHeapType)
let func_def_type ins out at = FuncDefType (FuncType (ins, out)) @@ at

let wrap item_name wrap_action wrap_assertion at =
let itypes, idesc, action = wrap_action at in
let locals, assertion = wrap_assertion at in
let types =
func_def_type [] [] at ::
func_def_type [i32_type] [externref_type] at ::
func_def_type [i32_type] [anyref_type] at ::
func_def_type [anyref_type] [i32_type] at ::
func_def_type [eqref_type; eqref_type] [i32_type] at ::
itypes
Expand All @@ -382,8 +379,6 @@ let wrap item_name wrap_action wrap_assertion at =
[ {module_name = Utf8.decode "module"; item_name; idesc} @@ at;
{module_name = Utf8.decode "spectest"; item_name = Utf8.decode "externref";
idesc = FuncImport (1l @@ at) @@ at} @@ at;
{module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_externref";
idesc = FuncImport (2l @@ at) @@ at} @@ at;
{module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_eqref";
idesc = FuncImport (2l @@ at) @@ at} @@ at;
{module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_ref";
Expand Down
5 changes: 2 additions & 3 deletions interpreter/script/run.ml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ let type_of_result r =
| LitResult v -> Value.type_of_value v.it
| NanResult n -> Types.NumType (Value.type_of_num n.it)
| RefResult t -> Types.(RefType (NonNullable, t))
| NullResult -> Types.(RefType (Nullable, ExternHeapType))
| NullResult -> Types.(RefType (Nullable, AnyHeapType))

let string_of_result r =
match r with
Expand Down Expand Up @@ -357,8 +357,7 @@ let assert_result at got expect =
| Types.I31HeapType, Ref (I31.I31Ref _)
| Types.DataHeapType, Ref (Data.DataRef _)
| Types.ArrayHeapType, Ref (Data.DataRef (Data.Array _))
| Types.FuncHeapType, Ref (Instance.FuncRef _)
| Types.ExternHeapType, Ref (ExternRef _) -> false
| Types.FuncHeapType, Ref (Instance.FuncRef _) -> false
| _ -> true
)
| NullResult ->
Expand Down
2 changes: 1 addition & 1 deletion interpreter/script/script.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exception Syntax of Source.region * string
let () =
let type_of_ref' = !Value.type_of_ref' in
Value.type_of_ref' := function
| ExternRef _ -> Types.ExternHeapType
| ExternRef _ -> Types.AnyHeapType
| r -> type_of_ref' r

let () =
Expand Down
2 changes: 1 addition & 1 deletion interpreter/syntax/free.ml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ let num_type = function

let heap_type = function
| AnyHeapType | EqHeapType | I31HeapType | DataHeapType | ArrayHeapType
| FuncHeapType | ExternHeapType | BotHeapType -> empty
| FuncHeapType | BotHeapType -> empty
| DefHeapType x | RttHeapType (x, _) -> var_type x

let ref_type = function
Expand Down
3 changes: 0 additions & 3 deletions interpreter/syntax/types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ and heap_type =
| DataHeapType
| ArrayHeapType
| FuncHeapType
| ExternHeapType
| DefHeapType of var
| RttHeapType of var * int32 option
| BotHeapType
Expand Down Expand Up @@ -167,7 +166,6 @@ let sem_heap_type c = function
| DataHeapType -> DataHeapType
| ArrayHeapType -> ArrayHeapType
| FuncHeapType -> FuncHeapType
| ExternHeapType -> ExternHeapType
| DefHeapType x -> DefHeapType (sem_var_type c x)
| RttHeapType (x, no) -> RttHeapType (sem_var_type c x, no)
| BotHeapType -> BotHeapType
Expand Down Expand Up @@ -288,7 +286,6 @@ and string_of_heap_type = function
| DataHeapType -> "data"
| ArrayHeapType -> "array"
| FuncHeapType -> "func"
| ExternHeapType -> "extern"
| DefHeapType x -> string_of_var x
| RttHeapType (x, None) -> "(rtt " ^ string_of_var x ^ ")"
| RttHeapType (x, Some n) ->
Expand Down
5 changes: 2 additions & 3 deletions interpreter/text/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ heap_type :
| DATA { fun c -> DataHeapType }
| ARRAY { fun c -> ArrayHeapType }
| FUNC { fun c -> FuncHeapType }
| EXTERN { fun c -> ExternHeapType }
| EXTERN { fun c -> AnyHeapType }
| var { fun c -> DefHeapType (SynVar ($1 c type_).it) }
| LPAR RTT var RPAR /* Sugar */
{ fun c -> RttHeapType (SynVar ($3 c type_).it, None) }
Expand All @@ -318,7 +318,7 @@ ref_type :
| DATAREF { fun c -> (NonNullable, DataHeapType) } /* Sugar */
| ARRAYREF { fun c -> (NonNullable, ArrayHeapType) } /* Sugar */
| FUNCREF { fun c -> (Nullable, FuncHeapType) } /* Sugar */
| EXTERNREF { fun c -> (Nullable, ExternHeapType) } /* Sugar */
| EXTERNREF { fun c -> (Nullable, AnyHeapType) } /* Sugar */
| LPAR RTT var RPAR /* Sugar */
{ fun c -> (NonNullable, RttHeapType (SynVar ($3 c type_).it, None)) }
| LPAR RTT NAT var RPAR /* Sugar */
Expand Down Expand Up @@ -1284,7 +1284,6 @@ result :
| LPAR REF_DATA RPAR { RefResult DataHeapType @@ at () }
| LPAR REF_ARRAY RPAR { RefResult ArrayHeapType @@ at () }
| LPAR REF_FUNC RPAR { RefResult FuncHeapType @@ at () }
| LPAR REF_EXTERN RPAR { RefResult ExternHeapType @@ at () }
| LPAR REF_NULL RPAR { NullResult @@ at () }

result_list :
Expand Down
2 changes: 1 addition & 1 deletion interpreter/valid/valid.ml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ let check_num_type (c : context) (t : num_type) at =
let check_heap_type (c : context) (t : heap_type) at =
match t with
| AnyHeapType | EqHeapType | I31HeapType | DataHeapType | ArrayHeapType
| FuncHeapType | ExternHeapType -> ()
| FuncHeapType -> ()
| DefHeapType (SynVar x) -> ignore (type_ c (x @@ at))
| RttHeapType (SynVar x, _) -> ignore (type_ c (x @@ at))
| DefHeapType (SemVar _) | RttHeapType (SemVar _, _) | BotHeapType ->
Expand Down
33 changes: 13 additions & 20 deletions proposals/gc/MVP.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ All three proposals are prerequisites.

[Heap types](https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md#types) classify reference types and are extended:

* `any` is a new heap type
- `heaptype ::= ... | any`
- the common supertype of all referenceable types

* `eq` is a new heap type
- `heaptype ::= ... | eq`
- the common supertype of all referenceable types on which comparison (`ref.eq`) is allowed
Expand All @@ -56,6 +52,10 @@ All three proposals are prerequisites.
- `rtt n? t ok` iff `t ok`
- the constant `n`, if present, encodes the static knowledge that this type has `n` dynamic supertypes (see [Runtime types](#runtime-types))

* `extern` is renamed back to `any`
- the common supertype of all referenceable types
- the name `extern` is kept as an alias in the text format for backwards compatibility

* Note: heap types `func` and `extern` already exist via [reference types proposal](https://github.com/WebAssembly/reference-types), and `(ref null? $t)` via [typed references](https://github.com/WebAssembly/function-references)

We distinguish these *abstract* heap types from *concrete* heap types `(type $t)`.
Expand All @@ -67,9 +67,6 @@ Moreover, they form a small [subtype hierarchy](#subtyping).

New abbreviations are introduced for reference types in binary and text format, corresponding to `funcref` and `externref`:

* `anyref` is a new reference type
- `anyref == (ref null any)`

* `eqref` is a new reference type
- `eqref == (ref null eq)`

Expand All @@ -85,6 +82,10 @@ New abbreviations are introduced for reference types in binary and text format,
* `rtt <n>? <typeidx>` is a new reference type
- `(rtt <n>? $t) == (ref (rtt <n>? $t))`

* `externref` is renamed to `anyref`
- `anyref == (ref null any)`
- the name `externref` is kept as an alias in the text format for backwards compatibility


#### Type Definitions

Expand Down Expand Up @@ -166,14 +167,10 @@ i31 data
All *concrete* heap types (of the form `(type $t)`) are situated below either `data` or `func`.
RTTs are below `eq`.

In addition, the abstract heap type `extern` is also a subtype of `any`.
Its interpretation is defined by the host environment.
It may contain additional host-defined types that are neither of the above three leaf type categories.
It may also overlap with some or all of these categories, as would be observable by applying a classification instruction like `ref.is_func` to a value of type `externref`.
The possible outcomes of such an operation hence depend on the host environment.
(For example, in a JavaScript embedding, `externref` could be inhabited by all JS values -- which is a natural choice, because JavaScript is untyped; but some of its values are JS-side representations of Wasm values per the JS API, and those can also be observed as `data` or `func` references. Another possible interpretation could be that `data` is disjoint from `extern`, which would be determined by the coercions allowed by the JS API at the JS/Wasm boundary. While such an interpretation is probably not attractive for JavaScript, it would be natural in other embeddings such as the C/C++ API, where different references are represented with different host types.)
In addition, a host environment may introduce additional inhabitants of type `any` that are are in neither of the above three leaf type categories.
The interpretation of such values is defined by the host environment.

Note: In the future, this hierarchy could be refined to distinguish compound data types that are not subtypes of `eq`.
Note: In the future, this hierarchy could be refined, e.g., to distinguish compound data types that are not subtypes of `eq`.


##### Defined Types
Expand Down Expand Up @@ -397,8 +394,6 @@ Tentatively, support a type of guaranteed unboxed scalars.

Note: The [reference types](https://github.com/WebAssembly/reference-types) and [typed function references](https://github.com/WebAssembly/function-references)already introduce similar `ref.is_null`, `br_on_null`, and `br_on_non_null` instructions.

Note: There are no instructions to check for `externref`, since that can consist of a diverse set of different object representations that would be costly to check for exhaustively.

Note: The `br_on_*` instructions allow an operand of unrelated reference type, even though this cannot possibly succeed. That's because subtyping allows to forget that information, so by the subtype substitutibility property, it would be accepted in any case. The given typing rules merely allow this type to also propagate to the result, which avoids the need to compute a least upper bound between the operand type and the target type in the typing algorithm.


Expand Down Expand Up @@ -480,8 +475,7 @@ This extends the [encodings](https://github.com/WebAssembly/function-references/
| Opcode | Type | Parameters | Note |
| ------ | --------------- | ---------- | ---- |
| -0x10 | `funcref` | | shorthand, from reftype proposal |
| -0x11 | `externref` | | shorthand, from reftype proposal |
| -0x12 | `anyref` | | shorthand |
| -0x11 | `anyref` | | shorthand, from reftype proposal |
| -0x13 | `eqref` | | shorthand |
| -0x14 | `(ref null ht)` | `ht : heaptype (s33)` | from funcref proposal |
| -0x15 | `(ref ht)` | `ht : heaptype (s33)` | from funcref proposal |
Expand All @@ -499,8 +493,7 @@ The opcode for heap types is encoded as an `s33`.
| ------ | --------------- | ---------- | ---- |
| i >= 0 | `(type i)` | | from funcref proposal |
| -0x10 | `func` | | from funcref proposal |
| -0x11 | `extern` | | from funcref proposal |
| -0x12 | `any` | | |
| -0x11 | `any` | | from funcref proposal |
| -0x13 | `eq` | | |
| -0x16 | `i31` | | |
| -0x17 | `(rtt n i)` | `n : u32`, `i : typeidx` | |
Expand Down
17 changes: 0 additions & 17 deletions test/core/linking.wast
Original file line number Diff line number Diff line change
Expand Up @@ -177,23 +177,6 @@
"incompatible import type"
)

(assert_unlinkable
(module (global (import "Mref_ex" "g-const-funcnull") externref))
"incompatible import type"
)
(assert_unlinkable
(module (global (import "Mref_ex" "g-const-func") externref))
"incompatible import type"
)
(assert_unlinkable
(module (global (import "Mref_ex" "g-const-refnull") externref))
"incompatible import type"
)
(assert_unlinkable
(module (global (import "Mref_ex" "g-const-ref") externref))
"incompatible import type"
)


(assert_unlinkable
(module (global (import "Mref_ex" "g-var-func") (mut (ref null func))))
Expand Down