1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/wasm/wasm-opcodes.h" 6 #include "src/messages.h" 7 #include "src/runtime/runtime.h" 8 #include "src/signature.h" 9 10 namespace v8 { 11 namespace internal { 12 namespace wasm { 13 14 typedef Signature<ValueType> FunctionSig; 15 16 #define CASE_OP(name, str) \ 17 case kExpr##name: \ 18 return str; 19 #define CASE_I32_OP(name, str) CASE_OP(I32##name, "i32." str) 20 #define CASE_I64_OP(name, str) CASE_OP(I64##name, "i64." str) 21 #define CASE_F32_OP(name, str) CASE_OP(F32##name, "f32." str) 22 #define CASE_F64_OP(name, str) CASE_OP(F64##name, "f64." str) 23 #define CASE_S128_OP(name, str) CASE_OP(S128##name, "s128." str) 24 #define CASE_F32x4_OP(name, str) CASE_OP(F32x4##name, "f32x4." str) 25 #define CASE_I32x4_OP(name, str) CASE_OP(I32x4##name, "i32x4." str) 26 #define CASE_I16x8_OP(name, str) CASE_OP(I16x8##name, "i16x8." str) 27 #define CASE_I8x16_OP(name, str) CASE_OP(I8x16##name, "i8x16." str) 28 #define CASE_S32x4_OP(name, str) CASE_OP(S32x4##name, "s32x4." str) 29 #define CASE_S16x8_OP(name, str) CASE_OP(S16x8##name, "s16x8." str) 30 #define CASE_S8x16_OP(name, str) CASE_OP(S8x16##name, "s8x16." str) 31 #define CASE_INT_OP(name, str) CASE_I32_OP(name, str) CASE_I64_OP(name, str) 32 #define CASE_FLOAT_OP(name, str) CASE_F32_OP(name, str) CASE_F64_OP(name, str) 33 #define CASE_ALL_OP(name, str) CASE_FLOAT_OP(name, str) CASE_INT_OP(name, str) 34 #define CASE_SIMD_OP(name, str) \ 35 CASE_F32x4_OP(name, str) CASE_I32x4_OP(name, str) CASE_I16x8_OP(name, str) \ 36 CASE_I8x16_OP(name, str) 37 #define CASE_SIMDI_OP(name, str) \ 38 CASE_I32x4_OP(name, str) CASE_I16x8_OP(name, str) CASE_I8x16_OP(name, str) 39 #define CASE_SIGN_OP(TYPE, name, str) \ 40 CASE_##TYPE##_OP(name##S, str "_s") CASE_##TYPE##_OP(name##U, str "_u") 41 #define CASE_ALL_SIGN_OP(name, str) \ 42 CASE_FLOAT_OP(name, str) CASE_SIGN_OP(INT, name, str) 43 #define CASE_CONVERT_OP(name, RES, SRC, src_suffix, str) \ 44 CASE_##RES##_OP(U##name##SRC, str "_u/" src_suffix) \ 45 CASE_##RES##_OP(S##name##SRC, str "_s/" src_suffix) 46 #define CASE_L32_OP(name, str) \ 47 CASE_SIGN_OP(I32, name##8, str "8") \ 48 CASE_SIGN_OP(I32, name##16, str "16") \ 49 CASE_I32_OP(name, str "32") 50 51 const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) { 52 switch (opcode) { 53 // clang-format off 54 55 // Standard opcodes 56 CASE_INT_OP(Eqz, "eqz") 57 CASE_ALL_OP(Eq, "eq") 58 CASE_ALL_OP(Ne, "ne") 59 CASE_ALL_OP(Add, "add") 60 CASE_ALL_OP(Sub, "sub") 61 CASE_ALL_OP(Mul, "mul") 62 CASE_ALL_SIGN_OP(Lt, "lt") 63 CASE_ALL_SIGN_OP(Gt, "gt") 64 CASE_ALL_SIGN_OP(Le, "le") 65 CASE_ALL_SIGN_OP(Ge, "ge") 66 CASE_INT_OP(Clz, "clz") 67 CASE_INT_OP(Ctz, "ctz") 68 CASE_INT_OP(Popcnt, "popcnt") 69 CASE_ALL_SIGN_OP(Div, "div") 70 CASE_SIGN_OP(INT, Rem, "rem") 71 CASE_INT_OP(And, "and") 72 CASE_INT_OP(Ior, "or") 73 CASE_INT_OP(Xor, "xor") 74 CASE_INT_OP(Shl, "shl") 75 CASE_SIGN_OP(INT, Shr, "shr") 76 CASE_INT_OP(Rol, "rol") 77 CASE_INT_OP(Ror, "ror") 78 CASE_FLOAT_OP(Abs, "abs") 79 CASE_FLOAT_OP(Neg, "neg") 80 CASE_FLOAT_OP(Ceil, "ceil") 81 CASE_FLOAT_OP(Floor, "floor") 82 CASE_FLOAT_OP(Trunc, "trunc") 83 CASE_FLOAT_OP(NearestInt, "nearest") 84 CASE_FLOAT_OP(Sqrt, "sqrt") 85 CASE_FLOAT_OP(Min, "min") 86 CASE_FLOAT_OP(Max, "max") 87 CASE_FLOAT_OP(CopySign, "copysign") 88 CASE_I32_OP(ConvertI64, "wrap/i64") 89 CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc") 90 CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc") 91 CASE_CONVERT_OP(Convert, I64, I32, "i32", "extend") 92 CASE_CONVERT_OP(Convert, F32, I32, "i32", "convert") 93 CASE_CONVERT_OP(Convert, F32, I64, "i64", "convert") 94 CASE_F32_OP(ConvertF64, "demote/f64") 95 CASE_CONVERT_OP(Convert, F64, I32, "i32", "convert") 96 CASE_CONVERT_OP(Convert, F64, I64, "i64", "convert") 97 CASE_F64_OP(ConvertF32, "promote/f32") 98 CASE_I32_OP(ReinterpretF32, "reinterpret/f32") 99 CASE_I64_OP(ReinterpretF64, "reinterpret/f64") 100 CASE_F32_OP(ReinterpretI32, "reinterpret/i32") 101 CASE_F64_OP(ReinterpretI64, "reinterpret/i64") 102 CASE_OP(Unreachable, "unreachable") 103 CASE_OP(Nop, "nop") 104 CASE_OP(Block, "block") 105 CASE_OP(Loop, "loop") 106 CASE_OP(If, "if") 107 CASE_OP(Else, "else") 108 CASE_OP(End, "end") 109 CASE_OP(Br, "br") 110 CASE_OP(BrIf, "br_if") 111 CASE_OP(BrTable, "br_table") 112 CASE_OP(Return, "return") 113 CASE_OP(CallFunction, "call") 114 CASE_OP(CallIndirect, "call_indirect") 115 CASE_OP(Drop, "drop") 116 CASE_OP(Select, "select") 117 CASE_OP(GetLocal, "get_local") 118 CASE_OP(SetLocal, "set_local") 119 CASE_OP(TeeLocal, "tee_local") 120 CASE_OP(GetGlobal, "get_global") 121 CASE_OP(SetGlobal, "set_global") 122 CASE_ALL_OP(Const, "const") 123 CASE_OP(MemorySize, "current_memory") 124 CASE_OP(GrowMemory, "grow_memory") 125 CASE_ALL_OP(LoadMem, "load") 126 CASE_SIGN_OP(INT, LoadMem8, "load8") 127 CASE_SIGN_OP(INT, LoadMem16, "load16") 128 CASE_SIGN_OP(I64, LoadMem32, "load32") 129 CASE_ALL_OP(StoreMem, "store") 130 CASE_INT_OP(StoreMem8, "store8") 131 CASE_INT_OP(StoreMem16, "store16") 132 CASE_I64_OP(StoreMem32, "store32") 133 134 // Non-standard opcodes. 135 CASE_OP(Try, "try") 136 CASE_OP(Throw, "throw") 137 CASE_OP(Catch, "catch") 138 139 // asm.js-only opcodes. 140 CASE_F64_OP(Acos, "acos") 141 CASE_F64_OP(Asin, "asin") 142 CASE_F64_OP(Atan, "atan") 143 CASE_F64_OP(Cos, "cos") 144 CASE_F64_OP(Sin, "sin") 145 CASE_F64_OP(Tan, "tan") 146 CASE_F64_OP(Exp, "exp") 147 CASE_F64_OP(Log, "log") 148 CASE_F64_OP(Atan2, "atan2") 149 CASE_F64_OP(Pow, "pow") 150 CASE_F64_OP(Mod, "mod") 151 CASE_F32_OP(AsmjsLoadMem, "asmjs_load") 152 CASE_F64_OP(AsmjsLoadMem, "asmjs_load") 153 CASE_L32_OP(AsmjsLoadMem, "asmjs_load") 154 CASE_I32_OP(AsmjsStoreMem, "asmjs_store") 155 CASE_F32_OP(AsmjsStoreMem, "asmjs_store") 156 CASE_F64_OP(AsmjsStoreMem, "asmjs_store") 157 CASE_I32_OP(AsmjsStoreMem8, "asmjs_store8") 158 CASE_I32_OP(AsmjsStoreMem16, "asmjs_store16") 159 CASE_SIGN_OP(I32, AsmjsDiv, "asmjs_div") 160 CASE_SIGN_OP(I32, AsmjsRem, "asmjs_rem") 161 CASE_I32_OP(AsmjsSConvertF32, "asmjs_convert_s/f32") 162 CASE_I32_OP(AsmjsUConvertF32, "asmjs_convert_u/f32") 163 CASE_I32_OP(AsmjsSConvertF64, "asmjs_convert_s/f64") 164 CASE_I32_OP(AsmjsUConvertF64, "asmjs_convert_u/f64") 165 166 // SIMD opcodes. 167 CASE_SIMD_OP(Splat, "splat") 168 CASE_SIMD_OP(Neg, "neg") 169 CASE_SIMD_OP(Eq, "eq") 170 CASE_SIMD_OP(Ne, "ne") 171 CASE_SIMD_OP(Add, "add") 172 CASE_SIMD_OP(Sub, "sub") 173 CASE_SIMD_OP(Mul, "mul") 174 CASE_F32x4_OP(Abs, "abs") 175 CASE_F32x4_OP(Sqrt, "sqrt") 176 CASE_F32x4_OP(Div, "div") 177 CASE_F32x4_OP(RecipApprox, "recip_approx") 178 CASE_F32x4_OP(SqrtApprox, "sqrt_approx") 179 CASE_F32x4_OP(Min, "min") 180 CASE_F32x4_OP(Max, "max") 181 CASE_F32x4_OP(MinNum, "min_num") 182 CASE_F32x4_OP(MaxNum, "max_num") 183 CASE_F32x4_OP(Lt, "lt") 184 CASE_F32x4_OP(Le, "le") 185 CASE_F32x4_OP(Gt, "gt") 186 CASE_F32x4_OP(Ge, "ge") 187 CASE_CONVERT_OP(Convert, F32x4, I32x4, "i32", "convert") 188 CASE_CONVERT_OP(Convert, I32x4, F32x4, "f32", "convert") 189 CASE_F32x4_OP(ExtractLane, "extract_lane") 190 CASE_F32x4_OP(ReplaceLane, "replace_lane") 191 CASE_SIMDI_OP(ExtractLane, "extract_lane") 192 CASE_SIMDI_OP(ReplaceLane, "replace_lane") 193 CASE_SIGN_OP(SIMDI, Min, "min") 194 CASE_SIGN_OP(SIMDI, Max, "max") 195 CASE_SIGN_OP(SIMDI, Lt, "lt") 196 CASE_SIGN_OP(SIMDI, Le, "le") 197 CASE_SIGN_OP(SIMDI, Gt, "gt") 198 CASE_SIGN_OP(SIMDI, Ge, "ge") 199 CASE_SIGN_OP(SIMDI, Shr, "shr") 200 CASE_SIMDI_OP(Shl, "shl") 201 CASE_SIGN_OP(I16x8, AddSaturate, "add_saturate") 202 CASE_SIGN_OP(I8x16, AddSaturate, "add_saturate") 203 CASE_SIGN_OP(I16x8, SubSaturate, "sub_saturate") 204 CASE_SIGN_OP(I8x16, SubSaturate, "sub_saturate") 205 CASE_S128_OP(Or, "or") 206 CASE_S128_OP(Xor, "xor") 207 CASE_S128_OP(And, "and") 208 CASE_S128_OP(Not, "not") 209 CASE_S32x4_OP(Select, "select") 210 CASE_S32x4_OP(Swizzle, "swizzle") 211 CASE_S32x4_OP(Shuffle, "shuffle") 212 CASE_S16x8_OP(Select, "select") 213 CASE_S16x8_OP(Swizzle, "swizzle") 214 CASE_S16x8_OP(Shuffle, "shuffle") 215 CASE_S8x16_OP(Select, "select") 216 CASE_S8x16_OP(Swizzle, "swizzle") 217 CASE_S8x16_OP(Shuffle, "shuffle") 218 219 // Atomic operations. 220 CASE_L32_OP(AtomicAdd, "atomic_add") 221 CASE_L32_OP(AtomicAnd, "atomic_and") 222 CASE_L32_OP(AtomicCompareExchange, "atomic_cmpxchng") 223 CASE_L32_OP(AtomicExchange, "atomic_xchng") 224 CASE_L32_OP(AtomicOr, "atomic_or") 225 CASE_L32_OP(AtomicSub, "atomic_sub") 226 CASE_L32_OP(AtomicXor, "atomic_xor") 227 228 default : return "unknown"; 229 // clang-format on 230 } 231 } 232 233 bool WasmOpcodes::IsPrefixOpcode(WasmOpcode opcode) { 234 switch (opcode) { 235 #define CHECK_PREFIX(name, opcode) \ 236 case k##name##Prefix: \ 237 return true; 238 FOREACH_PREFIX(CHECK_PREFIX) 239 #undef CHECK_PREFIX 240 default: 241 return false; 242 } 243 } 244 245 std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) { 246 if (sig.return_count() == 0) os << "v"; 247 for (size_t i = 0; i < sig.return_count(); ++i) { 248 os << WasmOpcodes::ShortNameOf(sig.GetReturn(i)); 249 } 250 os << "_"; 251 if (sig.parameter_count() == 0) os << "v"; 252 for (size_t i = 0; i < sig.parameter_count(); ++i) { 253 os << WasmOpcodes::ShortNameOf(sig.GetParam(i)); 254 } 255 return os; 256 } 257 258 #define DECLARE_SIG_ENUM(name, ...) kSigEnum_##name, 259 260 enum WasmOpcodeSig { FOREACH_SIGNATURE(DECLARE_SIG_ENUM) }; 261 262 // TODO(titzer): not static-initializer safe. Wrap in LazyInstance. 263 #define DECLARE_SIG(name, ...) \ 264 static ValueType kTypes_##name[] = {__VA_ARGS__}; \ 265 static const FunctionSig kSig_##name( \ 266 1, static_cast<int>(arraysize(kTypes_##name)) - 1, kTypes_##name); 267 268 FOREACH_SIGNATURE(DECLARE_SIG) 269 270 #define DECLARE_SIG_ENTRY(name, ...) &kSig_##name, 271 272 static const FunctionSig* kSimpleExprSigs[] = { 273 nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)}; 274 275 #define DECLARE_SIMD_SIG_ENTRY(name, ...) &kSig_##name, 276 277 static const FunctionSig* kSimdExprSigs[] = { 278 nullptr, FOREACH_SIMD_SIGNATURE(DECLARE_SIMD_SIG_ENTRY)}; 279 280 static byte kSimpleExprSigTable[256]; 281 static byte kSimpleAsmjsExprSigTable[256]; 282 static byte kSimdExprSigTable[256]; 283 static byte kAtomicExprSigTable[256]; 284 285 // Initialize the signature table. 286 static void InitSigTables() { 287 #define SET_SIG_TABLE(name, opcode, sig) \ 288 kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1; 289 FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE); 290 #undef SET_SIG_TABLE 291 #define SET_ASMJS_SIG_TABLE(name, opcode, sig) \ 292 kSimpleAsmjsExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1; 293 FOREACH_ASMJS_COMPAT_OPCODE(SET_ASMJS_SIG_TABLE); 294 #undef SET_ASMJS_SIG_TABLE 295 byte simd_index; 296 #define SET_SIG_TABLE(name, opcode, sig) \ 297 simd_index = opcode & 0xff; \ 298 kSimdExprSigTable[simd_index] = static_cast<int>(kSigEnum_##sig) + 1; 299 FOREACH_SIMD_0_OPERAND_OPCODE(SET_SIG_TABLE) 300 #undef SET_SIG_TABLE 301 byte atomic_index; 302 #define SET_ATOMIC_SIG_TABLE(name, opcode, sig) \ 303 atomic_index = opcode & 0xff; \ 304 kAtomicExprSigTable[atomic_index] = static_cast<int>(kSigEnum_##sig) + 1; 305 FOREACH_ATOMIC_OPCODE(SET_ATOMIC_SIG_TABLE) 306 #undef SET_ATOMIC_SIG_TABLE 307 } 308 309 class SigTable { 310 public: 311 SigTable() { 312 // TODO(ahaas): Move {InitSigTable} into the class. 313 InitSigTables(); 314 } 315 FunctionSig* Signature(WasmOpcode opcode) const { 316 return const_cast<FunctionSig*>( 317 kSimpleExprSigs[kSimpleExprSigTable[static_cast<byte>(opcode)]]); 318 } 319 FunctionSig* AsmjsSignature(WasmOpcode opcode) const { 320 return const_cast<FunctionSig*>( 321 kSimpleExprSigs[kSimpleAsmjsExprSigTable[static_cast<byte>(opcode)]]); 322 } 323 FunctionSig* SimdSignature(WasmOpcode opcode) const { 324 return const_cast<FunctionSig*>( 325 kSimdExprSigs[kSimdExprSigTable[static_cast<byte>(opcode & 0xff)]]); 326 } 327 FunctionSig* AtomicSignature(WasmOpcode opcode) const { 328 return const_cast<FunctionSig*>( 329 kSimpleExprSigs[kAtomicExprSigTable[static_cast<byte>(opcode & 0xff)]]); 330 } 331 }; 332 333 static base::LazyInstance<SigTable>::type sig_table = LAZY_INSTANCE_INITIALIZER; 334 335 FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) { 336 if (opcode >> 8 == kSimdPrefix) { 337 return sig_table.Get().SimdSignature(opcode); 338 } else { 339 return sig_table.Get().Signature(opcode); 340 } 341 } 342 343 FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) { 344 return sig_table.Get().AsmjsSignature(opcode); 345 } 346 347 FunctionSig* WasmOpcodes::AtomicSignature(WasmOpcode opcode) { 348 return sig_table.Get().AtomicSignature(opcode); 349 } 350 351 // TODO(titzer): pull WASM_64 up to a common header. 352 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 353 #define WASM_64 1 354 #else 355 #define WASM_64 0 356 #endif 357 358 int WasmOpcodes::TrapReasonToMessageId(TrapReason reason) { 359 switch (reason) { 360 #define TRAPREASON_TO_MESSAGE(name) \ 361 case k##name: \ 362 return MessageTemplate::kWasm##name; 363 FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE) 364 #undef TRAPREASON_TO_MESSAGE 365 default: 366 return MessageTemplate::kNone; 367 } 368 } 369 370 const char* WasmOpcodes::TrapReasonMessage(TrapReason reason) { 371 return MessageTemplate::TemplateString(TrapReasonToMessageId(reason)); 372 } 373 } // namespace wasm 374 } // namespace internal 375 } // namespace v8 376