github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wazeroir/signature.go (about) 1 package wazeroir 2 3 import ( 4 "fmt" 5 6 "github.com/wasilibs/wazerox/internal/wasm" 7 ) 8 9 // signature represents how a Wasm opcode 10 // manipulates the value stacks in terms of value types. 11 type signature struct { 12 in, out []UnsignedType 13 } 14 15 var ( 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 wazeroir. 263 func (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 wazeroir 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 wazeroir: 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 wazeroir: %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 wazeroir: %s", wasm.AtomicInstructionName(atomicOp)) 642 } 643 default: 644 return nil, fmt.Errorf("unsupported instruction in wazeroir: 0x%x", op) 645 } 646 } 647 648 // funcTypeToIRSignatures is the central cache for a module to get the *signature 649 // for function calls. 650 type 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`. 657 func (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 697 func wasmValueTypeToUnsignedType(vt wasm.ValueType) UnsignedType { 698 switch vt { 699 case wasm.ValueTypeI32: 700 return UnsignedTypeI32 701 case wasm.ValueTypeI64, 702 // From wazeroir 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 715 func wasmValueTypeToUnsignedOutSignature(vt wasm.ValueType) *signature { 716 switch vt { 717 case wasm.ValueTypeI32: 718 return signature_None_I32 719 case wasm.ValueTypeI64, 720 // From wazeroir 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 733 func wasmValueTypeToUnsignedInSignature(vt wasm.ValueType) *signature { 734 switch vt { 735 case wasm.ValueTypeI32: 736 return signature_I32_None 737 case wasm.ValueTypeI64, 738 // From wazeroir 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 751 func wasmValueTypeToUnsignedInOutSignature(vt wasm.ValueType) *signature { 752 switch vt { 753 case wasm.ValueTypeI32: 754 return signature_I32_I32 755 case wasm.ValueTypeI64, 756 // From wazeroir 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 }