1import Builder from '../Builder.js'
2import * as assert from '../assert.js'
3
4{
5 function makeInstance() {
6 const tableDescription = {initial: 1, element: "anyfunc"};
7 const builder = new Builder()
8 .Type()
9 .Func(["i32"], "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", 0 /*['i32'] => 'void'*/)
20 .GetLocal(0) // parameter to call
21 .GetLocal(0) // call index
22 .CallIndirect(0, 0) // calling function of type ['i32'] => 'i32'
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 const {instance: i1, table: t1} = makeInstance();
35 const {instance: i2, table: t2} = makeInstance();
36 t2.set(0, i1.exports.foo);
37 t1.set(0, i2.exports.foo);
38
39 // FIXME: asssert some stack size
40 function assertOverflows(instance) {
41 let stack;
42 try {
43 instance.exports.foo(0)
44 } catch(e) {
45 stack = e.stack;
46 }
47 stack = stack.split("\n");
48 assert.truthy(stack.length > 50);
49 for (let i = 0; i < 50; ++i) {
50 let item = stack[stack.length - i - 1];
51 assert.eq(item, "wasm function: 0@[wasm code]");
52 }
53 }
54 assertOverflows(i1);
55 assertOverflows(i2);
56
57}
58
59{
60 function makeInstance() {
61 const tableDescription = {initial: 1, element: "anyfunc"};
62 const builder = new Builder()
63 .Type()
64 .Func([], "void")
65 .End()
66 .Import()
67 .Table("imp", "table", tableDescription)
68 .End()
69 .Function().End()
70 .Export()
71 .Function("foo")
72 .End()
73 .Code()
74 .Function("foo", {params:["i32"], ret:"void"})
75 .GetLocal(0) // parameter to call
76 .GetLocal(0) // call index
77 .CallIndirect(0, 0) // calling function of type [] => 'void'
78 .Return()
79 .End()
80 .End();
81
82
83 const bin = builder.WebAssembly().get();
84 const module = new WebAssembly.Module(bin);
85 const table = new WebAssembly.Table(tableDescription);
86 return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
87 }
88
89 function makeInstance2(f) {
90 const builder = new Builder()
91 .Type()
92 .End()
93 .Import()
94 .Function("imp", "f", {params:['i32'], ret:"void"})
95 .End()
96 .Function().End()
97 .Export()
98 .Function("foo")
99 .End()
100 .Code()
101 .Function("foo", {params: [], ret: "void" })
102 .I32Const(0)
103 .Call(0)
104 .Return()
105 .End()
106 .End();
107
108
109 const bin = builder.WebAssembly().get();
110 const module = new WebAssembly.Module(bin);
111 return new WebAssembly.Instance(module, {imp: {f}});
112 }
113
114 const {instance: i1, table: t1} = makeInstance();
115 const foo = i1.exports.foo;
116 const i2 = makeInstance2(i1.exports.foo);
117 t1.set(0, i2.exports.foo);
118
119 function assertThrows(instance) {
120 let stack;
121 try {
122 instance.exports.foo();
123 } catch(e) {
124 stack = e.stack;
125 }
126 assert.truthy(stack);
127
128 stack = stack.split("\n");
129 assert.truthy(stack.length > 50);
130 const oneString = "wasm function: 1@[wasm code]";
131 const zeroString = "wasm function: 0@[wasm code]";
132 let currentIndex = stack[stack.length - 1] === oneString ? 1 : 0;
133 for (let i = 0; i < 50; ++i) {
134 let item = stack[stack.length - 1 - i];
135 if (currentIndex === 1) {
136 assert.eq(item, oneString);
137 currentIndex = 0;
138 } else {
139 assert.eq(currentIndex, 0);
140 assert.eq(item, zeroString);
141 currentIndex = 1;
142 }
143 }
144 }
145
146 for (let i = 0; i < 20; ++i) {
147 assertThrows(i2);
148 assertThrows(i1);
149 }
150
151 for (let i = 0; i < 20; ++i) {
152 assertThrows(i1);
153 assertThrows(i2);
154 }
155}
156
157{
158 function test(numArgs) {
159 function makeSignature() {
160 let args = [];
161 for (let i = 0; i < numArgs; ++i) {
162 args.push("i32");
163 }
164 return {params: args};
165 }
166 function makeInstance(f) {
167 let builder = new Builder()
168 .Type()
169 .Func([], "void")
170 .End()
171 .Import()
172 .Function("imp", "f", makeSignature())
173 .End()
174 .Function().End()
175 .Export()
176 .Function("foo")
177 .End()
178 .Code()
179 .Function("foo", {params:[], ret:"void"});
180 for (let i = 0; i < numArgs; ++i) {
181 builder = builder.I32Const(i);
182 }
183
184 builder = builder.Call(0).Return().End().End();
185 const bin = builder.WebAssembly().get();
186 const module = new WebAssembly.Module(bin);
187 return new WebAssembly.Instance(module, {imp: {f}});
188 }
189
190 function f(...args) {
191 assert.eq(args.length, numArgs);
192 for (let i = 0; i < args.length; ++i)
193 assert.eq(args[i], i);
194
195 instance.exports.foo();
196 }
197 let instance = makeInstance(f);
198
199 let stack;
200 try {
201 instance.exports.foo();
202 } catch(e) {
203 stack = e.stack;
204 }
205 assert.truthy(stack.split("\n").length > 25);
206 }
207
208 test(20);
209 test(20);
210 test(1000);
211 test(2);
212 test(1);
213 test(0);
214 test(700);
215 test(433);
216 test(42);
217}