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
|
wasmFullPass(`
(module
(import "env" "f" (func $f (result i32 i32 i32)))
(func (export "run") (result i32)
(call $f)
i32.sub
i32.sub))`,
42,
{ env: { f: () => [52, 10, 0] } });
wasmFullPass(`
(module
(import "env" "f" (func $f (result i64 i64 i64)))
(func (export "run") (result i64)
(call $f)
i64.sub
i64.sub))`,
42n,
{ env: { f: () => [52n, 10n, 0n] } });
wasmFullPass(`
(module
(import "env" "f" (func $f (result f32 f32 f32)))
(func (export "run") (result i32)
(call $f)
f32.sub
f32.sub
i32.trunc_f32_s))`,
42,
{ env: { f: () => [52.25, 10.5, 0.25] } });
wasmFullPass(`
(module
(import "env" "f" (func $f (result f64 f64 f64)))
(func (export "run") (result i32)
(call $f)
f64.sub
f64.sub
i32.trunc_f64_s))`,
42,
{ env: { f: () => [52.25, 10.5, 0.25] } });
// Multiple values are returned as an iterable; it doesn't have to be an array.
function expectMultiValuePass(f) {
wasmFullPass(`
(module
(import "env" "f" (func $f (result i32 i32 i32)))
(func (export "run") (result i32)
(call $f)
i32.sub
i32.sub))`,
42,
{ env: { f } });
}
function expectMultiValueError(f, type, pattern) {
let module = new WebAssembly.Module(wasmTextToBinary(`
(module
(import "env" "f" (func $f (result i32 i32 i32)))
(func (export "run") (result i32)
(call $f)
i32.sub
i32.sub))`));
let instance = new WebAssembly.Instance(module, { env: { f } } );
assertErrorMessage(() => instance.exports.run(), type, pattern);
}
expectMultiValuePass(() => [52, 10, 0]);
expectMultiValuePass(() => [32, -10, 0]);
expectMultiValuePass(() => [52.75, 10, 0.5]); // Values converted to i32 via ToInt32.
expectMultiValuePass(() => [42, undefined, undefined]);
expectMultiValuePass(() => (function*() { yield 52; yield 10; yield 0; })());
expectMultiValuePass(() => (function*() { yield '52'; yield '10'; yield 0; })());
// Multi-value result must be iterable.
expectMultiValueError(() => 1, TypeError, /iterable/);
expectMultiValueError(() => 1n, TypeError, /iterable/);
// Check that the iterator's values are collected first, and that the
// length of the result is correct.
expectMultiValueError(() => [1], TypeError, /expected 3, got 1/);
expectMultiValueError(() => [1n], TypeError, /expected 3, got 1/);
expectMultiValueError(() => [52, 10, 0, 0], TypeError, /expected 3, got 4/);
expectMultiValueError(() => (function*() { yield 52; yield 10; yield 0; yield 0; })(),
TypeError, /expected 3, got 4/);
// Check that side effects from conversions are done in order.
{
let calls = [];
function log(x) { calls.push(x); return x; }
function logged(x) { return { valueOf: () => log(x) } }
expectMultiValuePass(() => [logged(52), logged(10), logged(0)]);
assertEq(calls.join(','), '52,10,0');
}
function expectMultiValueResult(text, expected) {
let instance = wasmEvalText(text);
assertDeepEq(instance.exports.run(), expected);
}
expectMultiValueResult(`
(module
(func (export "run") (result i32 i32 i32)
(i32.const 0)
(i32.const 52)
(i32.const 10)))`, [0, 52, 10]);
expectMultiValueResult(`
(module
(func (export "run") (result f32 f32 f32)
(f32.const 0.5)
(f32.const 52.5)
(f32.const 10.5)))`, [0.5, 52.5, 10.5]);
expectMultiValueResult(`
(module
(func (export "run") (result f64 f64 f64)
(f64.const 0.5)
(f64.const 52.5)
(f64.const 10.5)))`, [0.5, 52.5, 10.5]);
expectMultiValueResult(`
(module
(func (export "run") (result i32 i64 i32)
(i32.const 0)
(i64.const 52)
(i32.const 10)))`, [0, 52n, 10]);
expectMultiValueResult(`
(module
(func (export "run") (result i64 i32 i64)
(i64.const 0)
(i32.const 52)
(i64.const 10)))`, [0n, 52, 10n]);
expectMultiValueResult(`
(module
(func (export "run") (result i64 i64 i64)
(i64.const 0)
(i64.const 52)
(i64.const 10)))`, [0n, 52n, 10n]);
|