1package interpreter
2
3import (
4 "fmt"
5
6 "github.com/tetratelabs/wazero/internal/wasm"
7)
8
9// signature represents how a Wasm opcode
10// manipulates the value stacks in terms of value types.
11type signature struct {
12 in, out []unsignedType
13}
14
15var (
16 signature_None_None = &signature{}
17 signature_Unknown_None = &signature{
18 in: []unsignedType{unsignedTypeUnknown},
19 }
20 signature_None_I32 = &signature{
21 out: []unsignedType{unsignedTypeI32},
22 }
23 signature_None_I64 = &signature{
24 out: []unsignedType{unsignedTypeI64},
25 }
26 signature_None_V128 = &signature{
27 out: []unsignedType{unsignedTypeV128},
28 }
29 signature_None_F32 = &signature{
30 out: []unsignedType{unsignedTypeF32},
31 }
32 signature_None_F64 = &signature{
33 out: []unsignedType{unsignedTypeF64},
34 }
35 signature_I32_None = &signature{
36 in: []unsignedType{unsignedTypeI32},
37 }
38 signature_I64_None = &signature{
39 in: []unsignedType{unsignedTypeI64},
40 }
41 signature_F32_None = &signature{
42 in: []unsignedType{unsignedTypeF32},
43 }
44 signature_F64_None = &signature{
45 in: []unsignedType{unsignedTypeF64},
46 }
47 signature_V128_None = &signature{
48 in: []unsignedType{unsignedTypeV128},
49 }
50 signature_I32_I32 = &signature{
51 in: []unsignedType{unsignedTypeI32},
52 out: []unsignedType{unsignedTypeI32},
53 }
54 signature_I32_I64 = &signature{
55 in: []unsignedType{unsignedTypeI32},
56 out: []unsignedType{unsignedTypeI64},
57 }
58 signature_I64_I64 = &signature{
59 in: []unsignedType{unsignedTypeI64},
60 out: []unsignedType{unsignedTypeI64},
61 }
62 signature_I32_F32 = &signature{
63 in: []unsignedType{unsignedTypeI32},
64 out: []unsignedType{unsignedTypeF32},
65 }
66 signature_I32_F64 = &signature{
67 in: []unsignedType{unsignedTypeI32},
68 out: []unsignedType{unsignedTypeF64},
69 }
70 signature_I64_I32 = &signature{
71 in: []unsignedType{unsignedTypeI64},
72 out: []unsignedType{unsignedTypeI32},
73 }
74 signature_I64_F32 = &signature{
75 in: []unsignedType{unsignedTypeI64},
76 out: []unsignedType{unsignedTypeF32},
77 }
78 signature_I64_F64 = &signature{
79 in: []unsignedType{unsignedTypeI64},
80 out: []unsignedType{unsignedTypeF64},
81 }
82 signature_F32_I32 = &signature{
83 in: []unsignedType{unsignedTypeF32},
84 out: []unsignedType{unsignedTypeI32},
85 }
86 signature_F32_I64 = &signature{
87 in: []unsignedType{unsignedTypeF32},
88 out: []unsignedType{unsignedTypeI64},
89 }
90 signature_F32_F64 = &signature{
91 in: []unsignedType{unsignedTypeF32},
92 out: []unsignedType{unsignedTypeF64},
93 }
94 signature_F32_F32 = &signature{
95 in: []unsignedType{unsignedTypeF32},
96 out: []unsignedType{unsignedTypeF32},
97 }
98 signature_F64_I32 = &signature{
99 in: []unsignedType{unsignedTypeF64},
100 out: []unsignedType{unsignedTypeI32},
101 }
102 signature_F64_F32 = &signature{
103 in: []unsignedType{unsignedTypeF64},
104 out: []unsignedType{unsignedTypeF32},
105 }
106 signature_F64_I64 = &signature{
107 in: []unsignedType{unsignedTypeF64},
108 out: []unsignedType{unsignedTypeI64},
109 }
110 signature_F64_F64 = &signature{
111 in: []unsignedType{unsignedTypeF64},
112 out: []unsignedType{unsignedTypeF64},
113 }
114 signature_I32I32_None = &signature{
115 in: []unsignedType{unsignedTypeI32, unsignedTypeI32},
116 }
117
118 signature_I32I32_I32 = &signature{
119 in: []unsignedType{unsignedTypeI32, unsignedTypeI32},
120 out: []unsignedType{unsignedTypeI32},
121 }
122 signature_I32I64_None = &signature{
123 in: []unsignedType{unsignedTypeI32, unsignedTypeI64},
124 }
125 signature_I32F32_None = &signature{
126 in: []unsignedType{unsignedTypeI32, unsignedTypeF32},
127 }
128 signature_I32F64_None = &signature{
129 in: []unsignedType{unsignedTypeI32, unsignedTypeF64},
130 }
131 signature_I64I32_I32 = &signature{
132 in: []unsignedType{unsignedTypeI64, unsignedTypeI32},
133 out: []unsignedType{unsignedTypeI32},
134 }
135 signature_I64I64_I32 = &signature{
136 in: []unsignedType{unsignedTypeI64, unsignedTypeI64},
137 out: []unsignedType{unsignedTypeI32},
138 }
139 signature_I64I64_I64 = &signature{
140 in: []unsignedType{unsignedTypeI64, unsignedTypeI64},
141 out: []unsignedType{unsignedTypeI64},
142 }
143 signature_F32F32_I32 = &signature{
144 in: []unsignedType{unsignedTypeF32, unsignedTypeF32},
145 out: []unsignedType{unsignedTypeI32},
146 }
147 signature_F32F32_F32 = &signature{
148 in: []unsignedType{unsignedTypeF32, unsignedTypeF32},
149 out: []unsignedType{unsignedTypeF32},
150 }
151 signature_F64F64_I32 = &signature{
152 in: []unsignedType{unsignedTypeF64, unsignedTypeF64},
153 out: []unsignedType{unsignedTypeI32},
154 }
155 signature_F64F64_F64 = &signature{
156 in: []unsignedType{unsignedTypeF64, unsignedTypeF64},
157 out: []unsignedType{unsignedTypeF64},
158 }
159 signature_I32I32I32_None = &signature{
160 in: []unsignedType{unsignedTypeI32, unsignedTypeI32, unsignedTypeI32},
161 }
162 signature_I32I64I32_None = &signature{
163 in: []unsignedType{unsignedTypeI32, unsignedTypeI64, unsignedTypeI32},
164 }
165 signature_UnknownUnknownI32_Unknown = &signature{
166 in: []unsignedType{unsignedTypeUnknown, unsignedTypeUnknown, unsignedTypeI32},
167 out: []unsignedType{unsignedTypeUnknown},
168 }
169 signature_V128V128_V128 = &signature{
170 in: []unsignedType{unsignedTypeV128, unsignedTypeV128},
171 out: []unsignedType{unsignedTypeV128},
172 }
173 signature_V128V128V128_V32 = &signature{
174 in: []unsignedType{unsignedTypeV128, unsignedTypeV128, unsignedTypeV128},
175 out: []unsignedType{unsignedTypeV128},
176 }
177 signature_I32_V128 = &signature{
178 in: []unsignedType{unsignedTypeI32},
179 out: []unsignedType{unsignedTypeV128},
180 }
181 signature_I32V128_None = &signature{
182 in: []unsignedType{unsignedTypeI32, unsignedTypeV128},
183 }
184 signature_I32V128_V128 = &signature{
185 in: []unsignedType{unsignedTypeI32, unsignedTypeV128},
186 out: []unsignedType{unsignedTypeV128},
187 }
188 signature_V128I32_V128 = &signature{
189 in: []unsignedType{unsignedTypeV128, unsignedTypeI32},
190 out: []unsignedType{unsignedTypeV128},
191 }
192 signature_V128I64_V128 = &signature{
193 in: []unsignedType{unsignedTypeV128, unsignedTypeI64},
194 out: []unsignedType{unsignedTypeV128},
195 }
196 signature_V128F32_V128 = &signature{
197 in: []unsignedType{unsignedTypeV128, unsignedTypeF32},
198 out: []unsignedType{unsignedTypeV128},
199 }
200 signature_V128F64_V128 = &signature{
201 in: []unsignedType{unsignedTypeV128, unsignedTypeF64},
202 out: []unsignedType{unsignedTypeV128},
203 }
204 signature_V128_I32 = &signature{
205 in: []unsignedType{unsignedTypeV128},
206 out: []unsignedType{unsignedTypeI32},
207 }
208 signature_V128_I64 = &signature{
209 in: []unsignedType{unsignedTypeV128},
210 out: []unsignedType{unsignedTypeI64},
211 }
212 signature_V128_F32 = &signature{
213 in: []unsignedType{unsignedTypeV128},
214 out: []unsignedType{unsignedTypeF32},
215 }
216 signature_V128_F64 = &signature{
217 in: []unsignedType{unsignedTypeV128},
218 out: []unsignedType{unsignedTypeF64},
219 }
220 signature_V128_V128 = &signature{
221 in: []unsignedType{unsignedTypeV128},
222 out: []unsignedType{unsignedTypeV128},
223 }
224 signature_I64_V128 = &signature{
225 in: []unsignedType{unsignedTypeI64},
226 out: []unsignedType{unsignedTypeV128},
227 }
228 signature_F32_V128 = &signature{
229 in: []unsignedType{unsignedTypeF32},
230 out: []unsignedType{unsignedTypeV128},
231 }
232 signature_F64_V128 = &signature{
233 in: []unsignedType{unsignedTypeF64},
234 out: []unsignedType{unsignedTypeV128},
235 }
236 signature_I32I64_I64 = &signature{
237 in: []unsignedType{unsignedTypeI32, unsignedTypeI64},
238 out: []unsignedType{unsignedTypeI64},
239 }
240 signature_I32I32I64_I32 = &signature{
241 in: []unsignedType{unsignedTypeI32, unsignedTypeI32, unsignedTypeI64},
242 out: []unsignedType{unsignedTypeI32},
243 }
244 signature_I32I64I64_I32 = &signature{
245 in: []unsignedType{unsignedTypeI32, unsignedTypeI64, unsignedTypeI64},
246 out: []unsignedType{unsignedTypeI32},
247 }
248 signature_I32I32I32_I32 = &signature{
249 in: []unsignedType{unsignedTypeI32, unsignedTypeI32, unsignedTypeI32},
250 out: []unsignedType{unsignedTypeI32},
251 }
252 signature_I32I64I64_I64 = &signature{
253 in: []unsignedType{unsignedTypeI32, unsignedTypeI64, unsignedTypeI64},
254 out: []unsignedType{unsignedTypeI64},
255 }
256)
257
258// wasmOpcodeSignature returns the signature of given Wasm opcode.
259// Note that some of opcodes' signature vary depending on
260// the function instance (for example, local types).
261// "index" parameter is not used by most of opcodes.
262// The returned signature is used for stack validation when lowering Wasm's opcodes to interpreterir.
263func (c *compiler) wasmOpcodeSignature(op wasm.Opcode, index uint32) (*signature, error) {
264 switch op {
265 case wasm.OpcodeUnreachable, wasm.OpcodeNop, wasm.OpcodeBlock, wasm.OpcodeLoop:
266 return signature_None_None, nil
267 case wasm.OpcodeIf:
268 return signature_I32_None, nil
269 case wasm.OpcodeElse, wasm.OpcodeEnd, wasm.OpcodeBr:
270 return signature_None_None, nil
271 case wasm.OpcodeBrIf, wasm.OpcodeBrTable:
272 return signature_I32_None, nil
273 case wasm.OpcodeReturn:
274 return signature_None_None, nil
275 case wasm.OpcodeCall:
276 return c.funcTypeToSigs.get(c.funcs[index], false /* direct */), nil
277 case wasm.OpcodeCallIndirect:
278 return c.funcTypeToSigs.get(index, true /* call_indirect */), nil
279 case wasm.OpcodeDrop:
280 return signature_Unknown_None, nil
281 case wasm.OpcodeSelect, wasm.OpcodeTypedSelect:
282 return signature_UnknownUnknownI32_Unknown, nil
283 case wasm.OpcodeLocalGet:
284 inputLen := uint32(len(c.sig.Params))
285 if l := uint32(len(c.localTypes)) + inputLen; index >= l {
286 return nil, fmt.Errorf("invalid local index for local.get %d >= %d", index, l)
287 }
288 var t wasm.ValueType
289 if index < inputLen {
290 t = c.sig.Params[index]
291 } else {
292 t = c.localTypes[index-inputLen]
293 }
294 return wasmValueTypeToUnsignedOutSignature(t), nil
295 case wasm.OpcodeLocalSet:
296 inputLen := uint32(len(c.sig.Params))
297 if l := uint32(len(c.localTypes)) + inputLen; index >= l {
298 return nil, fmt.Errorf("invalid local index for local.get %d >= %d", index, l)
299 }
300 var t wasm.ValueType
301 if index < inputLen {
302 t = c.sig.Params[index]
303 } else {
304 t = c.localTypes[index-inputLen]
305 }
306 return wasmValueTypeToUnsignedInSignature(t), nil
307 case wasm.OpcodeLocalTee:
308 inputLen := uint32(len(c.sig.Params))
309 if l := uint32(len(c.localTypes)) + inputLen; index >= l {
310 return nil, fmt.Errorf("invalid local index for local.get %d >= %d", index, l)
311 }
312 var t wasm.ValueType
313 if index < inputLen {
314 t = c.sig.Params[index]
315 } else {
316 t = c.localTypes[index-inputLen]
317 }
318 return wasmValueTypeToUnsignedInOutSignature(t), nil
319 case wasm.OpcodeGlobalGet:
320 if len(c.globals) <= int(index) {
321 return nil, fmt.Errorf("invalid global index for global.get %d >= %d", index, len(c.globals))
322 }
323 return wasmValueTypeToUnsignedOutSignature(c.globals[index].ValType), nil
324 case wasm.OpcodeGlobalSet:
325 if len(c.globals) <= int(index) {
326 return nil, fmt.Errorf("invalid global index for global.get %d >= %d", index, len(c.globals))
327 }
328 return wasmValueTypeToUnsignedInSignature(c.globals[index].ValType), nil
329 case wasm.OpcodeI32Load:
330 return signature_I32_I32, nil
331 case wasm.OpcodeI64Load:
332 return signature_I32_I64, nil
333 case wasm.OpcodeF32Load:
334 return signature_I32_F32, nil
335 case wasm.OpcodeF64Load:
336 return signature_I32_F64, nil
337 case wasm.OpcodeI32Load8S, wasm.OpcodeI32Load8U, wasm.OpcodeI32Load16S, wasm.OpcodeI32Load16U:
338 return signature_I32_I32, nil
339 case wasm.OpcodeI64Load8S, wasm.OpcodeI64Load8U, wasm.OpcodeI64Load16S, wasm.OpcodeI64Load16U,
340 wasm.OpcodeI64Load32S, wasm.OpcodeI64Load32U:
341 return signature_I32_I64, nil
342 case wasm.OpcodeI32Store:
343 return signature_I32I32_None, nil
344 case wasm.OpcodeI64Store:
345 return signature_I32I64_None, nil
346 case wasm.OpcodeF32Store:
347 return signature_I32F32_None, nil
348 case wasm.OpcodeF64Store:
349 return signature_I32F64_None, nil
350 case wasm.OpcodeI32Store8:
351 return signature_I32I32_None, nil
352 case wasm.OpcodeI32Store16:
353 return signature_I32I32_None, nil
354 case wasm.OpcodeI64Store8:
355 return signature_I32I64_None, nil
356 case wasm.OpcodeI64Store16:
357 return signature_I32I64_None, nil
358 case wasm.OpcodeI64Store32:
359 return signature_I32I64_None, nil
360 case wasm.OpcodeMemorySize:
361 return signature_None_I32, nil
362 case wasm.OpcodeMemoryGrow:
363 return signature_I32_I32, nil
364 case wasm.OpcodeI32Const:
365 return signature_None_I32, nil
366 case wasm.OpcodeI64Const:
367 return signature_None_I64, nil
368 case wasm.OpcodeF32Const:
369 return signature_None_F32, nil
370 case wasm.OpcodeF64Const:
371 return signature_None_F64, nil
372 case wasm.OpcodeI32Eqz:
373 return signature_I32_I32, nil
374 case wasm.OpcodeI32Eq, wasm.OpcodeI32Ne, wasm.OpcodeI32LtS,
375 wasm.OpcodeI32LtU, wasm.OpcodeI32GtS, wasm.OpcodeI32GtU,
376 wasm.OpcodeI32LeS, wasm.OpcodeI32LeU, wasm.OpcodeI32GeS,
377 wasm.OpcodeI32GeU:
378 return signature_I32I32_I32, nil
379 case wasm.OpcodeI64Eqz:
380 return signature_I64_I32, nil
381 case wasm.OpcodeI64Eq, wasm.OpcodeI64Ne, wasm.OpcodeI64LtS,
382 wasm.OpcodeI64LtU, wasm.OpcodeI64GtS, wasm.OpcodeI64GtU,
383 wasm.OpcodeI64LeS, wasm.OpcodeI64LeU, wasm.OpcodeI64GeS,
384 wasm.OpcodeI64GeU:
385 return signature_I64I64_I32, nil
386 case wasm.OpcodeF32Eq, wasm.OpcodeF32Ne, wasm.OpcodeF32Lt,
387 wasm.OpcodeF32Gt, wasm.OpcodeF32Le, wasm.OpcodeF32Ge:
388 return signature_F32F32_I32, nil
389 case wasm.OpcodeF64Eq, wasm.OpcodeF64Ne, wasm.OpcodeF64Lt,
390 wasm.OpcodeF64Gt, wasm.OpcodeF64Le, wasm.OpcodeF64Ge:
391 return signature_F64F64_I32, nil
392 case wasm.OpcodeI32Clz, wasm.OpcodeI32Ctz, wasm.OpcodeI32Popcnt:
393 return signature_I32_I32, nil
394 case wasm.OpcodeI32Add, wasm.OpcodeI32Sub, wasm.OpcodeI32Mul,
395 wasm.OpcodeI32DivS, wasm.OpcodeI32DivU, wasm.OpcodeI32RemS,
396 wasm.OpcodeI32RemU, wasm.OpcodeI32And, wasm.OpcodeI32Or,
397 wasm.OpcodeI32Xor, wasm.OpcodeI32Shl, wasm.OpcodeI32ShrS,
398 wasm.OpcodeI32ShrU, wasm.OpcodeI32Rotl, wasm.OpcodeI32Rotr:
399 return signature_I32I32_I32, nil
400 case wasm.OpcodeI64Clz, wasm.OpcodeI64Ctz, wasm.OpcodeI64Popcnt:
401 return signature_I64_I64, nil
402 case wasm.OpcodeI64Add, wasm.OpcodeI64Sub, wasm.OpcodeI64Mul,
403 wasm.OpcodeI64DivS, wasm.OpcodeI64DivU, wasm.OpcodeI64RemS,
404 wasm.OpcodeI64RemU, wasm.OpcodeI64And, wasm.OpcodeI64Or,
405 wasm.OpcodeI64Xor, wasm.OpcodeI64Shl, wasm.OpcodeI64ShrS,
406 wasm.OpcodeI64ShrU, wasm.OpcodeI64Rotl, wasm.OpcodeI64Rotr:
407 return signature_I64I64_I64, nil
408 case wasm.OpcodeF32Abs, wasm.OpcodeF32Neg, wasm.OpcodeF32Ceil,
409 wasm.OpcodeF32Floor, wasm.OpcodeF32Trunc, wasm.OpcodeF32Nearest,
410 wasm.OpcodeF32Sqrt:
411 return signature_F32_F32, nil
412 case wasm.OpcodeF32Add, wasm.OpcodeF32Sub, wasm.OpcodeF32Mul,
413 wasm.OpcodeF32Div, wasm.OpcodeF32Min, wasm.OpcodeF32Max,
414 wasm.OpcodeF32Copysign:
415 return signature_F32F32_F32, nil
416 case wasm.OpcodeF64Abs, wasm.OpcodeF64Neg, wasm.OpcodeF64Ceil,
417 wasm.OpcodeF64Floor, wasm.OpcodeF64Trunc, wasm.OpcodeF64Nearest,
418 wasm.OpcodeF64Sqrt:
419 return signature_F64_F64, nil
420 case wasm.OpcodeF64Add, wasm.OpcodeF64Sub, wasm.OpcodeF64Mul,
421 wasm.OpcodeF64Div, wasm.OpcodeF64Min, wasm.OpcodeF64Max,
422 wasm.OpcodeF64Copysign:
423 return signature_F64F64_F64, nil
424 case wasm.OpcodeI32WrapI64:
425 return signature_I64_I32, nil
426 case wasm.OpcodeI32TruncF32S, wasm.OpcodeI32TruncF32U:
427 return signature_F32_I32, nil
428 case wasm.OpcodeI32TruncF64S, wasm.OpcodeI32TruncF64U:
429 return signature_F64_I32, nil
430 case wasm.OpcodeI64ExtendI32S, wasm.OpcodeI64ExtendI32U:
431 return signature_I32_I64, nil
432 case wasm.OpcodeI64TruncF32S, wasm.OpcodeI64TruncF32U:
433 return signature_F32_I64, nil
434 case wasm.OpcodeI64TruncF64S, wasm.OpcodeI64TruncF64U:
435 return signature_F64_I64, nil
436 case wasm.OpcodeF32ConvertI32S, wasm.OpcodeF32ConvertI32U:
437 return signature_I32_F32, nil
438 case wasm.OpcodeF32ConvertI64S, wasm.OpcodeF32ConvertI64U:
439 return signature_I64_F32, nil
440 case wasm.OpcodeF32DemoteF64:
441 return signature_F64_F32, nil
442 case wasm.OpcodeF64ConvertI32S, wasm.OpcodeF64ConvertI32U:
443 return signature_I32_F64, nil
444 case wasm.OpcodeF64ConvertI64S, wasm.OpcodeF64ConvertI64U:
445 return signature_I64_F64, nil
446 case wasm.OpcodeF64PromoteF32:
447 return signature_F32_F64, nil
448 case wasm.OpcodeI32ReinterpretF32:
449 return signature_F32_I32, nil
450 case wasm.OpcodeI64ReinterpretF64:
451 return signature_F64_I64, nil
452 case wasm.OpcodeF32ReinterpretI32:
453 return signature_I32_F32, nil
454 case wasm.OpcodeF64ReinterpretI64:
455 return signature_I64_F64, nil
456 case wasm.OpcodeI32Extend8S, wasm.OpcodeI32Extend16S:
457 return signature_I32_I32, nil
458 case wasm.OpcodeI64Extend8S, wasm.OpcodeI64Extend16S, wasm.OpcodeI64Extend32S:
459 return signature_I64_I64, nil
460 case wasm.OpcodeTableGet:
461 // table.get takes table's offset and pushes the ref type value of opaque pointer as i64 value onto the stack.
462 return signature_I32_I64, nil
463 case wasm.OpcodeTableSet:
464 // table.set takes table's offset and the ref type value of opaque pointer as i64 value.
465 return signature_I32I64_None, nil
466 case wasm.OpcodeRefFunc:
467 // ref.func is translated as pushing the compiled function's opaque pointer (uint64) at interpreterir layer.
468 return signature_None_I64, nil
469 case wasm.OpcodeRefIsNull:
470 // ref.is_null is translated as checking if the uint64 on the top of the stack (opaque pointer) is zero or not.
471 return signature_I64_I32, nil
472 case wasm.OpcodeRefNull:
473 // ref.null is translated as i64.const 0.
474 return signature_None_I64, nil
475 case wasm.OpcodeMiscPrefix:
476 switch miscOp := c.body[c.pc+1]; miscOp {
477 case wasm.OpcodeMiscI32TruncSatF32S, wasm.OpcodeMiscI32TruncSatF32U:
478 return signature_F32_I32, nil
479 case wasm.OpcodeMiscI32TruncSatF64S, wasm.OpcodeMiscI32TruncSatF64U:
480 return signature_F64_I32, nil
481 case wasm.OpcodeMiscI64TruncSatF32S, wasm.OpcodeMiscI64TruncSatF32U:
482 return signature_F32_I64, nil
483 case wasm.OpcodeMiscI64TruncSatF64S, wasm.OpcodeMiscI64TruncSatF64U:
484 return signature_F64_I64, nil
485 case wasm.OpcodeMiscMemoryInit, wasm.OpcodeMiscMemoryCopy, wasm.OpcodeMiscMemoryFill,
486 wasm.OpcodeMiscTableInit, wasm.OpcodeMiscTableCopy:
487 return signature_I32I32I32_None, nil
488 case wasm.OpcodeMiscDataDrop, wasm.OpcodeMiscElemDrop:
489 return signature_None_None, nil
490 case wasm.OpcodeMiscTableGrow:
491 return signature_I64I32_I32, nil
492 case wasm.OpcodeMiscTableSize:
493 return signature_None_I32, nil
494 case wasm.OpcodeMiscTableFill:
495 return signature_I32I64I32_None, nil
496 default:
497 return nil, fmt.Errorf("unsupported misc instruction in interpreterir: 0x%x", op)
498 }
499 case wasm.OpcodeVecPrefix:
500 switch vecOp := c.body[c.pc+1]; vecOp {
501 case wasm.OpcodeVecV128Const:
502 return signature_None_V128, nil
503 case wasm.OpcodeVecV128Load, wasm.OpcodeVecV128Load8x8s, wasm.OpcodeVecV128Load8x8u,
504 wasm.OpcodeVecV128Load16x4s, wasm.OpcodeVecV128Load16x4u, wasm.OpcodeVecV128Load32x2s,
505 wasm.OpcodeVecV128Load32x2u, wasm.OpcodeVecV128Load8Splat, wasm.OpcodeVecV128Load16Splat,
506 wasm.OpcodeVecV128Load32Splat, wasm.OpcodeVecV128Load64Splat, wasm.OpcodeVecV128Load32zero,
507 wasm.OpcodeVecV128Load64zero:
508 return signature_I32_V128, nil
509 case wasm.OpcodeVecV128Load8Lane, wasm.OpcodeVecV128Load16Lane,
510 wasm.OpcodeVecV128Load32Lane, wasm.OpcodeVecV128Load64Lane:
511 return signature_I32V128_V128, nil
512 case wasm.OpcodeVecV128Store,
513 wasm.OpcodeVecV128Store8Lane,
514 wasm.OpcodeVecV128Store16Lane,
515 wasm.OpcodeVecV128Store32Lane,
516 wasm.OpcodeVecV128Store64Lane:
517 return signature_I32V128_None, nil
518 case wasm.OpcodeVecI8x16ExtractLaneS,
519 wasm.OpcodeVecI8x16ExtractLaneU,
520 wasm.OpcodeVecI16x8ExtractLaneS,
521 wasm.OpcodeVecI16x8ExtractLaneU,
522 wasm.OpcodeVecI32x4ExtractLane:
523 return signature_V128_I32, nil
524 case wasm.OpcodeVecI64x2ExtractLane:
525 return signature_V128_I64, nil
526 case wasm.OpcodeVecF32x4ExtractLane:
527 return signature_V128_F32, nil
528 case wasm.OpcodeVecF64x2ExtractLane:
529 return signature_V128_F64, nil
530 case wasm.OpcodeVecI8x16ReplaceLane, wasm.OpcodeVecI16x8ReplaceLane, wasm.OpcodeVecI32x4ReplaceLane,
531 wasm.OpcodeVecI8x16Shl, wasm.OpcodeVecI8x16ShrS, wasm.OpcodeVecI8x16ShrU,
532 wasm.OpcodeVecI16x8Shl, wasm.OpcodeVecI16x8ShrS, wasm.OpcodeVecI16x8ShrU,
533 wasm.OpcodeVecI32x4Shl, wasm.OpcodeVecI32x4ShrS, wasm.OpcodeVecI32x4ShrU,
534 wasm.OpcodeVecI64x2Shl, wasm.OpcodeVecI64x2ShrS, wasm.OpcodeVecI64x2ShrU:
535 return signature_V128I32_V128, nil
536 case wasm.OpcodeVecI64x2ReplaceLane:
537 return signature_V128I64_V128, nil
538 case wasm.OpcodeVecF32x4ReplaceLane:
539 return signature_V128F32_V128, nil
540 case wasm.OpcodeVecF64x2ReplaceLane:
541 return signature_V128F64_V128, nil
542 case wasm.OpcodeVecI8x16Splat,
543 wasm.OpcodeVecI16x8Splat,
544 wasm.OpcodeVecI32x4Splat:
545 return signature_I32_V128, nil
546 case wasm.OpcodeVecI64x2Splat:
547 return signature_I64_V128, nil
548 case wasm.OpcodeVecF32x4Splat:
549 return signature_F32_V128, nil
550 case wasm.OpcodeVecF64x2Splat:
551 return signature_F64_V128, nil
552 case wasm.OpcodeVecV128i8x16Shuffle, wasm.OpcodeVecI8x16Swizzle, wasm.OpcodeVecV128And, wasm.OpcodeVecV128Or, wasm.OpcodeVecV128Xor, wasm.OpcodeVecV128AndNot:
553 return signature_V128V128_V128, nil
554 case wasm.OpcodeVecI8x16AllTrue, wasm.OpcodeVecI16x8AllTrue, wasm.OpcodeVecI32x4AllTrue, wasm.OpcodeVecI64x2AllTrue,
555 wasm.OpcodeVecV128AnyTrue,
556 wasm.OpcodeVecI8x16BitMask, wasm.OpcodeVecI16x8BitMask, wasm.OpcodeVecI32x4BitMask, wasm.OpcodeVecI64x2BitMask:
557 return signature_V128_I32, nil
558 case wasm.OpcodeVecV128Not, wasm.OpcodeVecI8x16Neg, wasm.OpcodeVecI16x8Neg, wasm.OpcodeVecI32x4Neg, wasm.OpcodeVecI64x2Neg,
559 wasm.OpcodeVecF32x4Neg, wasm.OpcodeVecF64x2Neg, wasm.OpcodeVecF32x4Sqrt, wasm.OpcodeVecF64x2Sqrt,
560 wasm.OpcodeVecI8x16Abs, wasm.OpcodeVecI8x16Popcnt, wasm.OpcodeVecI16x8Abs, wasm.OpcodeVecI32x4Abs, wasm.OpcodeVecI64x2Abs,
561 wasm.OpcodeVecF32x4Abs, wasm.OpcodeVecF64x2Abs,
562 wasm.OpcodeVecF32x4Ceil, wasm.OpcodeVecF32x4Floor, wasm.OpcodeVecF32x4Trunc, wasm.OpcodeVecF32x4Nearest,
563 wasm.OpcodeVecF64x2Ceil, wasm.OpcodeVecF64x2Floor, wasm.OpcodeVecF64x2Trunc, wasm.OpcodeVecF64x2Nearest,
564 wasm.OpcodeVecI16x8ExtendLowI8x16S, wasm.OpcodeVecI16x8ExtendHighI8x16S, wasm.OpcodeVecI16x8ExtendLowI8x16U, wasm.OpcodeVecI16x8ExtendHighI8x16U,
565 wasm.OpcodeVecI32x4ExtendLowI16x8S, wasm.OpcodeVecI32x4ExtendHighI16x8S, wasm.OpcodeVecI32x4ExtendLowI16x8U, wasm.OpcodeVecI32x4ExtendHighI16x8U,
566 wasm.OpcodeVecI64x2ExtendLowI32x4S, wasm.OpcodeVecI64x2ExtendHighI32x4S, wasm.OpcodeVecI64x2ExtendLowI32x4U, wasm.OpcodeVecI64x2ExtendHighI32x4U,
567 wasm.OpcodeVecI16x8ExtaddPairwiseI8x16S, wasm.OpcodeVecI16x8ExtaddPairwiseI8x16U, wasm.OpcodeVecI32x4ExtaddPairwiseI16x8S, wasm.OpcodeVecI32x4ExtaddPairwiseI16x8U,
568 wasm.OpcodeVecF64x2PromoteLowF32x4Zero, wasm.OpcodeVecF32x4DemoteF64x2Zero,
569 wasm.OpcodeVecF32x4ConvertI32x4S, wasm.OpcodeVecF32x4ConvertI32x4U,
570 wasm.OpcodeVecF64x2ConvertLowI32x4S, wasm.OpcodeVecF64x2ConvertLowI32x4U,
571 wasm.OpcodeVecI32x4TruncSatF32x4S, wasm.OpcodeVecI32x4TruncSatF32x4U,
572 wasm.OpcodeVecI32x4TruncSatF64x2SZero, wasm.OpcodeVecI32x4TruncSatF64x2UZero:
573 return signature_V128_V128, nil
574 case wasm.OpcodeVecV128Bitselect:
575 return signature_V128V128V128_V32, nil
576 case wasm.OpcodeVecI8x16Eq, wasm.OpcodeVecI8x16Ne, wasm.OpcodeVecI8x16LtS, wasm.OpcodeVecI8x16LtU, wasm.OpcodeVecI8x16GtS,
577 wasm.OpcodeVecI8x16GtU, wasm.OpcodeVecI8x16LeS, wasm.OpcodeVecI8x16LeU, wasm.OpcodeVecI8x16GeS, wasm.OpcodeVecI8x16GeU,
578 wasm.OpcodeVecI16x8Eq, wasm.OpcodeVecI16x8Ne, wasm.OpcodeVecI16x8LtS, wasm.OpcodeVecI16x8LtU, wasm.OpcodeVecI16x8GtS,
579 wasm.OpcodeVecI16x8GtU, wasm.OpcodeVecI16x8LeS, wasm.OpcodeVecI16x8LeU, wasm.OpcodeVecI16x8GeS, wasm.OpcodeVecI16x8GeU,
580 wasm.OpcodeVecI32x4Eq, wasm.OpcodeVecI32x4Ne, wasm.OpcodeVecI32x4LtS, wasm.OpcodeVecI32x4LtU, wasm.OpcodeVecI32x4GtS,
581 wasm.OpcodeVecI32x4GtU, wasm.OpcodeVecI32x4LeS, wasm.OpcodeVecI32x4LeU, wasm.OpcodeVecI32x4GeS, wasm.OpcodeVecI32x4GeU,
582 wasm.OpcodeVecI64x2Eq, wasm.OpcodeVecI64x2Ne, wasm.OpcodeVecI64x2LtS, wasm.OpcodeVecI64x2GtS, wasm.OpcodeVecI64x2LeS,
583 wasm.OpcodeVecI64x2GeS, wasm.OpcodeVecF32x4Eq, wasm.OpcodeVecF32x4Ne, wasm.OpcodeVecF32x4Lt, wasm.OpcodeVecF32x4Gt,
584 wasm.OpcodeVecF32x4Le, wasm.OpcodeVecF32x4Ge, wasm.OpcodeVecF64x2Eq, wasm.OpcodeVecF64x2Ne, wasm.OpcodeVecF64x2Lt,
585 wasm.OpcodeVecF64x2Gt, wasm.OpcodeVecF64x2Le, wasm.OpcodeVecF64x2Ge,
586 wasm.OpcodeVecI8x16Add, wasm.OpcodeVecI8x16AddSatS, wasm.OpcodeVecI8x16AddSatU, wasm.OpcodeVecI8x16Sub,
587 wasm.OpcodeVecI8x16SubSatS, wasm.OpcodeVecI8x16SubSatU,
588 wasm.OpcodeVecI16x8Add, wasm.OpcodeVecI16x8AddSatS, wasm.OpcodeVecI16x8AddSatU, wasm.OpcodeVecI16x8Sub,
589 wasm.OpcodeVecI16x8SubSatS, wasm.OpcodeVecI16x8SubSatU, wasm.OpcodeVecI16x8Mul,
590 wasm.OpcodeVecI32x4Add, wasm.OpcodeVecI32x4Sub, wasm.OpcodeVecI32x4Mul,
591 wasm.OpcodeVecI64x2Add, wasm.OpcodeVecI64x2Sub, wasm.OpcodeVecI64x2Mul,
592 wasm.OpcodeVecF32x4Add, wasm.OpcodeVecF32x4Sub, wasm.OpcodeVecF32x4Mul, wasm.OpcodeVecF32x4Div,
593 wasm.OpcodeVecF64x2Add, wasm.OpcodeVecF64x2Sub, wasm.OpcodeVecF64x2Mul, wasm.OpcodeVecF64x2Div,
594 wasm.OpcodeVecI8x16MinS, wasm.OpcodeVecI8x16MinU, wasm.OpcodeVecI8x16MaxS, wasm.OpcodeVecI8x16MaxU, wasm.OpcodeVecI8x16AvgrU,
595 wasm.OpcodeVecI16x8MinS, wasm.OpcodeVecI16x8MinU, wasm.OpcodeVecI16x8MaxS, wasm.OpcodeVecI16x8MaxU, wasm.OpcodeVecI16x8AvgrU,
596 wasm.OpcodeVecI32x4MinS, wasm.OpcodeVecI32x4MinU, wasm.OpcodeVecI32x4MaxS, wasm.OpcodeVecI32x4MaxU,
597 wasm.OpcodeVecF32x4Min, wasm.OpcodeVecF32x4Max, wasm.OpcodeVecF64x2Min, wasm.OpcodeVecF64x2Max,
598 wasm.OpcodeVecF32x4Pmin, wasm.OpcodeVecF32x4Pmax, wasm.OpcodeVecF64x2Pmin, wasm.OpcodeVecF64x2Pmax,
599 wasm.OpcodeVecI16x8Q15mulrSatS,
600 wasm.OpcodeVecI16x8ExtMulLowI8x16S, wasm.OpcodeVecI16x8ExtMulHighI8x16S, wasm.OpcodeVecI16x8ExtMulLowI8x16U, wasm.OpcodeVecI16x8ExtMulHighI8x16U,
601 wasm.OpcodeVecI32x4ExtMulLowI16x8S, wasm.OpcodeVecI32x4ExtMulHighI16x8S, wasm.OpcodeVecI32x4ExtMulLowI16x8U, wasm.OpcodeVecI32x4ExtMulHighI16x8U,
602 wasm.OpcodeVecI64x2ExtMulLowI32x4S, wasm.OpcodeVecI64x2ExtMulHighI32x4S, wasm.OpcodeVecI64x2ExtMulLowI32x4U, wasm.OpcodeVecI64x2ExtMulHighI32x4U,
603 wasm.OpcodeVecI32x4DotI16x8S,
604 wasm.OpcodeVecI8x16NarrowI16x8S, wasm.OpcodeVecI8x16NarrowI16x8U, wasm.OpcodeVecI16x8NarrowI32x4S, wasm.OpcodeVecI16x8NarrowI32x4U:
605 return signature_V128V128_V128, nil
606 default:
607 return nil, fmt.Errorf("unsupported vector instruction in interpreterir: %s", wasm.VectorInstructionName(vecOp))
608 }
609 case wasm.OpcodeAtomicPrefix:
610 switch atomicOp := c.body[c.pc+1]; atomicOp {
611 case wasm.OpcodeAtomicMemoryNotify:
612 return signature_I32I32_I32, nil
613 case wasm.OpcodeAtomicMemoryWait32:
614 return signature_I32I32I64_I32, nil
615 case wasm.OpcodeAtomicMemoryWait64:
616 return signature_I32I64I64_I32, nil
617 case wasm.OpcodeAtomicFence:
618 return signature_None_None, nil
619 case wasm.OpcodeAtomicI32Load, wasm.OpcodeAtomicI32Load8U, wasm.OpcodeAtomicI32Load16U:
620 return signature_I32_I32, nil
621 case wasm.OpcodeAtomicI64Load, wasm.OpcodeAtomicI64Load8U, wasm.OpcodeAtomicI64Load16U, wasm.OpcodeAtomicI64Load32U:
622 return signature_I32_I64, nil
623 case wasm.OpcodeAtomicI32Store, wasm.OpcodeAtomicI32Store8, wasm.OpcodeAtomicI32Store16:
624 return signature_I32I32_None, nil
625 case wasm.OpcodeAtomicI64Store, wasm.OpcodeAtomicI64Store8, wasm.OpcodeAtomicI64Store16, wasm.OpcodeAtomicI64Store32:
626 return signature_I32I64_None, nil
627 case wasm.OpcodeAtomicI32RmwAdd, wasm.OpcodeAtomicI32RmwSub, wasm.OpcodeAtomicI32RmwAnd, wasm.OpcodeAtomicI32RmwOr, wasm.OpcodeAtomicI32RmwXor, wasm.OpcodeAtomicI32RmwXchg,
628 wasm.OpcodeAtomicI32Rmw8AddU, wasm.OpcodeAtomicI32Rmw8SubU, wasm.OpcodeAtomicI32Rmw8AndU, wasm.OpcodeAtomicI32Rmw8OrU, wasm.OpcodeAtomicI32Rmw8XorU, wasm.OpcodeAtomicI32Rmw8XchgU,
629 wasm.OpcodeAtomicI32Rmw16AddU, wasm.OpcodeAtomicI32Rmw16SubU, wasm.OpcodeAtomicI32Rmw16AndU, wasm.OpcodeAtomicI32Rmw16OrU, wasm.OpcodeAtomicI32Rmw16XorU, wasm.OpcodeAtomicI32Rmw16XchgU:
630 return signature_I32I32_I32, nil
631 case wasm.OpcodeAtomicI64RmwAdd, wasm.OpcodeAtomicI64RmwSub, wasm.OpcodeAtomicI64RmwAnd, wasm.OpcodeAtomicI64RmwOr, wasm.OpcodeAtomicI64RmwXor, wasm.OpcodeAtomicI64RmwXchg,
632 wasm.OpcodeAtomicI64Rmw8AddU, wasm.OpcodeAtomicI64Rmw8SubU, wasm.OpcodeAtomicI64Rmw8AndU, wasm.OpcodeAtomicI64Rmw8OrU, wasm.OpcodeAtomicI64Rmw8XorU, wasm.OpcodeAtomicI64Rmw8XchgU,
633 wasm.OpcodeAtomicI64Rmw16AddU, wasm.OpcodeAtomicI64Rmw16SubU, wasm.OpcodeAtomicI64Rmw16AndU, wasm.OpcodeAtomicI64Rmw16OrU, wasm.OpcodeAtomicI64Rmw16XorU, wasm.OpcodeAtomicI64Rmw16XchgU,
634 wasm.OpcodeAtomicI64Rmw32AddU, wasm.OpcodeAtomicI64Rmw32SubU, wasm.OpcodeAtomicI64Rmw32AndU, wasm.OpcodeAtomicI64Rmw32OrU, wasm.OpcodeAtomicI64Rmw32XorU, wasm.OpcodeAtomicI64Rmw32XchgU:
635 return signature_I32I64_I64, nil
636 case wasm.OpcodeAtomicI32RmwCmpxchg, wasm.OpcodeAtomicI32Rmw8CmpxchgU, wasm.OpcodeAtomicI32Rmw16CmpxchgU:
637 return signature_I32I32I32_I32, nil
638 case wasm.OpcodeAtomicI64RmwCmpxchg, wasm.OpcodeAtomicI64Rmw8CmpxchgU, wasm.OpcodeAtomicI64Rmw16CmpxchgU, wasm.OpcodeAtomicI64Rmw32CmpxchgU:
639 return signature_I32I64I64_I64, nil
640 default:
641 return nil, fmt.Errorf("unsupported atomic instruction in interpreterir: %s", wasm.AtomicInstructionName(atomicOp))
642 }
643 default:
644 return nil, fmt.Errorf("unsupported instruction in interpreterir: 0x%x", op)
645 }
646}
647
648// funcTypeToIRSignatures is the central cache for a module to get the *signature
649// for function calls.
650type funcTypeToIRSignatures struct {
651 directCalls []*signature
652 indirectCalls []*signature
653 wasmTypes []wasm.FunctionType
654}
655
656// get returns the *signature for the direct or indirect function call against functions whose type is at `typeIndex`.
657func (f *funcTypeToIRSignatures) get(typeIndex wasm.Index, indirect bool) *signature {
658 var sig *signature
659 if indirect {
660 sig = f.indirectCalls[typeIndex]
661 } else {
662 sig = f.directCalls[typeIndex]
663 }
664 if sig != nil {
665 return sig
666 }
667
668 tp := &f.wasmTypes[typeIndex]
669 if indirect {
670 sig = &signature{
671 in: make([]unsignedType, 0, len(tp.Params)+1), // +1 to reserve space for call indirect index.
672 out: make([]unsignedType, 0, len(tp.Results)),
673 }
674 } else {
675 sig = &signature{
676 in: make([]unsignedType, 0, len(tp.Params)),
677 out: make([]unsignedType, 0, len(tp.Results)),
678 }
679 }
680
681 for _, vt := range tp.Params {
682 sig.in = append(sig.in, wasmValueTypeTounsignedType(vt))
683 }
684 for _, vt := range tp.Results {
685 sig.out = append(sig.out, wasmValueTypeTounsignedType(vt))
686 }
687
688 if indirect {
689 sig.in = append(sig.in, unsignedTypeI32)
690 f.indirectCalls[typeIndex] = sig
691 } else {
692 f.directCalls[typeIndex] = sig
693 }
694 return sig
695}
696
697func wasmValueTypeTounsignedType(vt wasm.ValueType) unsignedType {
698 switch vt {
699 case wasm.ValueTypeI32:
700 return unsignedTypeI32
701 case wasm.ValueTypeI64,
702 // From interpreterir layer, ref type values are opaque 64-bit pointers.
703 wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
704 return unsignedTypeI64
705 case wasm.ValueTypeF32:
706 return unsignedTypeF32
707 case wasm.ValueTypeF64:
708 return unsignedTypeF64
709 case wasm.ValueTypeV128:
710 return unsignedTypeV128
711 }
712 panic("unreachable")
713}
714
715func wasmValueTypeToUnsignedOutSignature(vt wasm.ValueType) *signature {
716 switch vt {
717 case wasm.ValueTypeI32:
718 return signature_None_I32
719 case wasm.ValueTypeI64,
720 // From interpreterir layer, ref type values are opaque 64-bit pointers.
721 wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
722 return signature_None_I64
723 case wasm.ValueTypeF32:
724 return signature_None_F32
725 case wasm.ValueTypeF64:
726 return signature_None_F64
727 case wasm.ValueTypeV128:
728 return signature_None_V128
729 }
730 panic("unreachable")
731}
732
733func wasmValueTypeToUnsignedInSignature(vt wasm.ValueType) *signature {
734 switch vt {
735 case wasm.ValueTypeI32:
736 return signature_I32_None
737 case wasm.ValueTypeI64,
738 // From interpreterir layer, ref type values are opaque 64-bit pointers.
739 wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
740 return signature_I64_None
741 case wasm.ValueTypeF32:
742 return signature_F32_None
743 case wasm.ValueTypeF64:
744 return signature_F64_None
745 case wasm.ValueTypeV128:
746 return signature_V128_None
747 }
748 panic("unreachable")
749}
750
751func wasmValueTypeToUnsignedInOutSignature(vt wasm.ValueType) *signature {
752 switch vt {
753 case wasm.ValueTypeI32:
754 return signature_I32_I32
755 case wasm.ValueTypeI64,
756 // At interpreterir layer, ref type values are opaque 64-bit pointers.
757 wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
758 return signature_I64_I64
759 case wasm.ValueTypeF32:
760 return signature_F32_F32
761 case wasm.ValueTypeF64:
762 return signature_F64_F64
763 case wasm.ValueTypeV128:
764 return signature_V128_V128
765 }
766 panic("unreachable")
767}