signature.go

  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}