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
OpcodeName(WasmOpcode opcode)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
IsPrefixOpcode(WasmOpcode opcode)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
operator <<(std::ostream & os,const FunctionSig & sig)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.
InitSigTables()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:
SigTable()311 SigTable() {
312 // TODO(ahaas): Move {InitSigTable} into the class.
313 InitSigTables();
314 }
Signature(WasmOpcode opcode) const315 FunctionSig* Signature(WasmOpcode opcode) const {
316 return const_cast<FunctionSig*>(
317 kSimpleExprSigs[kSimpleExprSigTable[static_cast<byte>(opcode)]]);
318 }
AsmjsSignature(WasmOpcode opcode) const319 FunctionSig* AsmjsSignature(WasmOpcode opcode) const {
320 return const_cast<FunctionSig*>(
321 kSimpleExprSigs[kSimpleAsmjsExprSigTable[static_cast<byte>(opcode)]]);
322 }
SimdSignature(WasmOpcode opcode) const323 FunctionSig* SimdSignature(WasmOpcode opcode) const {
324 return const_cast<FunctionSig*>(
325 kSimdExprSigs[kSimdExprSigTable[static_cast<byte>(opcode & 0xff)]]);
326 }
AtomicSignature(WasmOpcode opcode) const327 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
Signature(WasmOpcode opcode)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
AsmjsSignature(WasmOpcode opcode)343 FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) {
344 return sig_table.Get().AsmjsSignature(opcode);
345 }
346
AtomicSignature(WasmOpcode opcode)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
TrapReasonToMessageId(TrapReason reason)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
TrapReasonMessage(TrapReason reason)370 const char* WasmOpcodes::TrapReasonMessage(TrapReason reason) {
371 return MessageTemplate::TemplateString(TrapReasonToMessageId(reason));
372 }
373 } // namespace wasm
374 } // namespace internal
375 } // namespace v8
376