[WASM-References] Rename anyfunc to funcref
[WebKit-https.git] / JSTests / wasm / function-tests / context-switch.js
1 import Builder from '../Builder.js'
2 import * as assert from '../assert.js'
3
4 {
5     function makeInstance() {
6         const tableDescription = {initial: 1, element: "funcref"};
7         const builder = new Builder()
8             .Type()
9                 .Func([], "void")
10             .End()
11             .Import()
12                 .Table("imp", "table", tableDescription)
13             .End()
14             .Function().End()
15             .Export()
16                 .Function("foo")
17             .End()
18             .Code()
19                 .Function("foo", {params:["i32"], ret:"void"})
20                     .GetLocal(0) // parameter to call
21                     .GetLocal(0) // call index
22                     .CallIndirect(0, 0) // calling function of type [] => 'void'
23                     .Return()
24                 .End()
25             .End();
26
27
28         const bin = builder.WebAssembly().get();
29         const module = new WebAssembly.Module(bin);
30         const table = new WebAssembly.Table(tableDescription);
31         return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
32     }
33
34     function makeInstance2(f) {
35         const builder = new Builder()
36             .Type()
37             .End()
38             .Import()
39                 .Function("imp", "f", {params:[], ret:"void"})
40             .End()
41             .Function().End()
42             .Export()
43                 .Function("foo")
44             .End()
45             .Code()
46                 .Function("foo", {params: [], ret: "void" })
47                     .Call(0)
48                     .Return()
49                 .End()
50             .End();
51
52
53         const bin = builder.WebAssembly().get();
54         const module = new WebAssembly.Module(bin);
55         return new WebAssembly.Instance(module, {imp: {f}});
56     }
57
58     const {instance: i1, table: t1} = makeInstance();
59     const foo = i1.exports.foo;
60
61     let called = false;
62     let shouldThrow = false;
63     const i2 = makeInstance2(function() {
64         called = true;
65         if (shouldThrow)
66             throw new Error("Threw");
67     });
68
69     t1.set(0, i2.exports.foo);
70     for (let i = 0; i < 1000; ++i) {
71         foo(0);
72         assert.eq(called, true);
73         called = false;
74     }
75     shouldThrow = true;
76     for (let i = 0; i < 1000; ++i) {
77         assert.throws(() => foo(0), Error, "Threw");
78         assert.eq(called, true);
79         called = false;
80     }
81 }
82
83 {
84     function makeInstance() {
85         const tableDescription = {initial: 1, element: "funcref"};
86         const builder = new Builder()
87             .Type()
88                 .Func(["i32"], "void")
89             .End()
90             .Import()
91                 .Table("imp", "table", tableDescription)
92             .End()
93             .Function().End()
94             .Export()
95                 .Function("foo")
96             .End()
97             .Code()
98                 .Function("foo", {params:["i32", "i32"], ret:"void"})
99                     .GetLocal(1) // parameter to call
100                     .GetLocal(0) // call index
101                     .CallIndirect(0, 0) // calling function of type ['i32'] => 'void'
102                     .Return()
103                 .End()
104             .End();
105
106         const bin = builder.WebAssembly().get();
107         const module = new WebAssembly.Module(bin);
108         const table = new WebAssembly.Table(tableDescription);
109         return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
110     }
111
112     function makeInstance2(memory, f) {
113         const builder = new Builder()
114             .Type()
115             .End()
116             .Import()
117                 .Function("imp", "f", {params:['i32', 'i32'], ret:"void"})
118                 .Memory("imp", "memory", memoryDescription)
119             .End()
120             .Function().End()
121             .Export()
122                 .Function("foo")
123             .End()
124             .Code()
125                 .Function("foo", {params: ["i32"], ret: "void" })
126                     .GetLocal(0)
127                     .GetLocal(0)
128                     .I32Load(2, 0)
129                     .Call(0)
130                     .Return()
131                 .End()
132             .End();
133
134
135         const bin = builder.WebAssembly().get();
136         const module = new WebAssembly.Module(bin);
137         return new WebAssembly.Instance(module, {imp: {f, memory}});
138     }
139
140     const {instance: i1, table: t1} = makeInstance();
141     const foo = (memOffset) => i1.exports.foo(0, memOffset);
142
143     const memoryDescription = {initial:1};
144     const mem = new WebAssembly.Memory(memoryDescription);
145     let called = false;
146
147     const pageSize = 64 * 1024;
148     let buf = new Uint32Array(mem.buffer);
149     const i2 = makeInstance2(mem, function(i, value) {
150         assert.eq(i & 3, 0);
151         assert.eq(buf[i/4], value);
152         called = true;
153     });
154     t1.set(0, i2.exports.foo);
155     
156     for (let i = 0; i < pageSize/4; ++i) {
157         buf[i] = i+1;
158     }
159
160     for (let i = 0; i < pageSize/4; ++i) {
161         foo(i*4);
162         assert.eq(called, true);
163         called = false;
164     }
165
166     for (let i = pageSize/4; i < 2*pageSize/4; ++i) {
167         assert.throws(() => foo(i*4), WebAssembly.RuntimeError, "Out of bounds memory access");
168         assert.eq(called, false);
169     }
170 }
171
172 {
173     function makeInstance() {
174         const tableDescription = {initial: 1, element: "funcref"};
175         const builder = new Builder()
176             .Type()
177                 .Func(["i32"], "void")
178             .End()
179             .Import()
180                 .Table("imp", "table", tableDescription)
181             .End()
182             .Function().End()
183             .Export()
184                 .Function("foo")
185             .End()
186             .Code()
187                 .Function("foo", {params:["i32", "i32"], ret:"void"})
188                     .GetLocal(1) // parameter to call
189                     .GetLocal(0) // call index
190                     .CallIndirect(0, 0) // calling function of type ['i32'] => 'void'
191                     .Return()
192                 .End()
193             .End();
194
195         const bin = builder.WebAssembly().get();
196         const module = new WebAssembly.Module(bin);
197         const table = new WebAssembly.Table(tableDescription);
198         return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
199     }
200
201     function makeInstance2(memory, f) {
202         const builder = new Builder()
203             .Type()
204             .End()
205             .Import()
206                 .Function("imp", "f", {params:['i32', 'i32'], ret:"void"})
207                 .Memory("imp", "memory", memoryDescription)
208             .End()
209             .Function().End()
210             .Export()
211                 .Function("foo")
212             .End()
213             .Code()
214                 .Function("foo", {params: ["i32"], ret: "void" })
215                     .GetLocal(0)
216                     .GetLocal(0)
217                     .I32Load(2, 0)
218                     .Call(0)
219                     .Return()
220                 .End()
221             .End();
222
223
224         const bin = builder.WebAssembly().get();
225         const module = new WebAssembly.Module(bin);
226         return new WebAssembly.Instance(module, {imp: {f, memory}});
227     }
228
229     function exportImport(f) {
230         let builder = (new Builder())
231             .Type().End()
232             .Import()
233                 .Function("imp", "f", {params: ['i32'], ret:"void"})
234             .End()
235             .Function().End()
236             .Export()
237                 .Function("func", {module: "imp", field: "f"})
238             .End()
239             .Code().End();
240         return (new WebAssembly.Instance(new WebAssembly.Module(builder.WebAssembly().get()), {imp: {f}})).exports.func;
241     }
242
243     const {instance: i1, table: t1} = makeInstance();
244     const foo = (memOffset) => i1.exports.foo(0, memOffset);
245
246     const memoryDescription = {initial:1};
247     const mem = new WebAssembly.Memory(memoryDescription);
248     let called = false;
249
250     const pageSize = 64 * 1024;
251     let buf = new Uint32Array(mem.buffer);
252     const i2 = makeInstance2(mem, function(i, value) {
253         assert.eq(i & 3, 0);
254         assert.eq(buf[i/4], value);
255         called = true;
256     });
257
258     const exportedImport = exportImport(function(offset) {
259         i2.exports.foo(offset);
260     });
261     t1.set(0, exportedImport);
262     
263     for (let i = 0; i < pageSize/4; ++i) {
264         buf[i] = i+1;
265     }
266
267     for (let i = 0; i < pageSize/4; ++i) {
268         foo(i*4);
269         assert.eq(called, true);
270         called = false;
271     }
272
273     for (let i = pageSize/4; i < 2*pageSize/4; ++i) {
274         assert.throws(() => foo(i*4), WebAssembly.RuntimeError, "Out of bounds memory access");
275         assert.eq(called, false);
276     }
277 }