summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/ref-types/externref-boxing.js
blob: 854f3e781500c932feb3306c775840fa48eea590 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Moving a JS value through a wasm externref is a pair of boxing/unboxing
// conversions that leaves the value unchanged.  There are many cases,
// along these axes:
//
//  - global variables
//  - tables
//  - function parameters and returns
//  - struct fields [for the gc feature], see externref-boxing-struct.js

// Global variables can receive values via several mechanisms:
//
// - on initialization when created from JS
// - on initialization when created in Wasm, from an imported global
// - through the "value" property if the value is mutable
// - through the global.set wasm instruction, ditto
//
// Their values can be obtained in several ways:
//
// - through the "value" property
// - through the global.get wasm instruction
// - read when other globals are initialized from them

// Set via initialization and read via 'value'

for (let v of WasmExternrefValues)
{
    let g = new WebAssembly.Global({value: "externref"}, v);
    assertEq(g.value, v);
}

// Set via 'value' and read via 'value'

for (let v of WasmExternrefValues)
{
    let g = new WebAssembly.Global({value: "externref", mutable: true});
    g.value = v;
    assertEq(g.value, v);
}

// Set via initialization, then read via global.get and returned

for (let v of WasmExternrefValues)
{
    let g = new WebAssembly.Global({value: "externref"}, v);
    let ins = wasmEvalText(
        `(module
           (import "m" "g" (global $glob externref))
           (func (export "f") (result externref)
             (global.get $glob)))`,
        {m:{g}});
    assertEq(ins.exports.f(), v);
}

// Set via global.set, then read via 'value'

for (let v of WasmExternrefValues)
{
    let g = new WebAssembly.Global({value: "externref", mutable: true});
    let ins = wasmEvalText(
        `(module
           (import "m" "g" (global $glob (mut externref)))
           (func (export "f") (param $v externref)
             (global.set $glob (local.get $v))))`,
        {m:{g}});
    ins.exports.f(v);
    assertEq(g.value, v);
}

// Tables of externref can receive values via several mechanisms:
//
// - through WebAssembly.Table.prototype.set()
// - through the table.set, table.copy, and table.grow instructions
// - through table.fill
// - through WebAssembly.Table.prototype.grow()
//
// Their values can be read in several ways:
//
// - through WebAssembly.Table.prototype.get()
// - through the table.get and table.copy instructions
//
// (Note, tables are always initialized to null when created from JS)

// .set() and .get()

for (let v of WasmExternrefValues)
{
    let t = new WebAssembly.Table({element: "externref", initial: 10});
    t.set(3, v);
    assertEq(t.get(3), v);
}

// write with table.set, read with .get()

for (let v of WasmExternrefValues)
{
    let t = new WebAssembly.Table({element: "externref", initial: 10});
    let ins = wasmEvalText(
        `(module
           (import "m" "t" (table $t 10 externref))
           (func (export "f") (param $v externref)
             (table.set $t (i32.const 3) (local.get $v))))`,
        {m:{t}});
    ins.exports.f(v);
    assertEq(t.get(3), v);
}

// write with .set(), read with table.get

for (let v of WasmExternrefValues)
{
    let t = new WebAssembly.Table({element: "externref", initial: 10});
    let ins = wasmEvalText(
        `(module
           (import "m" "t" (table $t 10 externref))
           (func (export "f") (result externref)
             (table.get $t (i32.const 3))))`,
        {m:{t}});
    t.set(3, v);
    assertEq(ins.exports.f(), v);
}

// Imported JS functions can receive externref values as parameters and return
// them.

for (let v of WasmExternrefValues)
{
    let returner = function () { return v; };
    let receiver = function (w) { assertEq(w, v); };
    let ins = wasmEvalText(
        `(module
           (import "m" "returner" (func $returner (result externref)))
           (import "m" "receiver" (func $receiver (param externref)))
           (func (export "test_returner") (result externref)
             (call $returner))
           (func (export "test_receiver") (param $v externref)
             (call $receiver (local.get $v))))`,
        {m:{returner, receiver}});
    assertEq(ins.exports.test_returner(), v);
    ins.exports.test_receiver(v);
}