v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-opcodes-inl.h
Go to the documentation of this file.
1// Copyright 2020 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#ifndef V8_WASM_WASM_OPCODES_INL_H_
6#define V8_WASM_WASM_OPCODES_INL_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
13// Include the non-inl header before the rest of the headers.
14
15#include <array>
16
20
21namespace v8 {
22namespace internal {
23namespace wasm {
24
25// static
26constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
27 switch (opcode) {
28#define CASE(opcode, binary, sig, name, ...) \
29 case kExpr##opcode: \
30 return name;
32#undef CASE
33
34 case kNumericPrefix:
35 case kSimdPrefix:
36 case kAtomicPrefix:
37 case kGCPrefix:
38 case kAsmJsPrefix:
39 return "unknown";
40 }
41 // Even though the switch above handles all well-defined enum values,
42 // random modules (e.g. fuzzer generated) can call this function with
43 // random (invalid) opcodes. Handle those here:
44 return "invalid opcode";
45}
46
47// static
49 switch (opcode) {
50#define CHECK_PREFIX(name, opcode) case k##name##Prefix:
52#undef CHECK_PREFIX
53 return true;
54 default:
55 return false;
56 }
57}
58
59// static
61 switch (opcode) {
62#define CHECK_OPCODE(name, ...) case kExpr##name:
64#undef CHECK_OPCODE
65 return true;
66 default:
67 return false;
68 }
69}
70
71// static
73 switch (opcode) {
74 case kExprUnreachable:
75 case kExprBr:
76 case kExprBrTable:
77 case kExprReturn:
78 case kExprReturnCall:
79 case kExprReturnCallIndirect:
80 case kExprThrow:
81 case kExprRethrow:
82 return true;
83 default:
84 return false;
85 }
86}
87
88// static
89constexpr bool WasmOpcodes::IsBreakable(WasmOpcode opcode) {
90 switch (opcode) {
91 case kExprBlock:
92 case kExprTry:
93 case kExprCatch:
94 case kExprLoop:
95 case kExprElse:
96 return false;
97 default:
98 return true;
99 }
100}
101
102// static
104 switch (opcode) {
105 case kExprRefNull:
106 case kExprRefIsNull:
107 case kExprRefFunc:
108 case kExprRefAsNonNull:
109 return true;
110 default:
111 return false;
112 }
113}
114
115// static
117 // TODO(8729): Trapping opcodes are not yet considered to be throwing.
118 switch (opcode) {
119 case kExprThrow:
120 case kExprRethrow:
121 case kExprCallFunction:
122 case kExprCallIndirect:
123 return true;
124 default:
125 return false;
126 }
127}
128
129// static
131 // Relaxed SIMD opcodes have the SIMD prefix (0xfd) shifted by 12 bits, and
132 // nibble 3 must be 0x1. I.e. their encoded opcode is in [0xfd100, 0xfd1ff].
133 static_assert(kSimdPrefix == 0xfd);
134#define CHECK_OPCODE(name, opcode, ...) \
135 static_assert((opcode & 0xfff00) == 0xfd100);
137#undef CHECK_OPCODE
138
139 return (opcode & 0xfff00) == 0xfd100;
140}
141
143 return (opcode >= kExprF16x8Splat && opcode <= kExprF16x8ReplaceLane) ||
144 (opcode >= kExprF16x8Abs && opcode <= kExprF16x8Qfms);
145}
146
147#if DEBUG
148// static
149constexpr bool WasmOpcodes::IsMemoryAccessOpcode(WasmOpcode opcode) {
150 switch (opcode) {
151#define MEM_OPCODE(name, ...) case WasmOpcode::kExpr##name:
152 FOREACH_LOAD_MEM_OPCODE(MEM_OPCODE)
153 FOREACH_STORE_MEM_OPCODE(MEM_OPCODE)
154 FOREACH_ATOMIC_OPCODE(MEM_OPCODE)
155 FOREACH_SIMD_MEM_OPCODE(MEM_OPCODE)
157 return true;
158 default:
159 return false;
160 }
161}
162#endif // DEBUG
163
164constexpr uint8_t WasmOpcodes::ExtractPrefix(WasmOpcode opcode) {
165 // See comment on {WasmOpcode} for the encoding.
166 return (opcode > 0xffff) ? opcode >> 12 : opcode >> 8;
167}
168
169namespace impl {
170
171#define DECLARE_SIG_ENUM(name, ...) kSigEnum_##name,
176#undef DECLARE_SIG_ENUM
177#define DECLARE_SIG(name, ...) \
178 constexpr inline ValueType kTypes_##name[] = {__VA_ARGS__}; \
179 constexpr inline int kReturnsCount_##name = \
180 kTypes_##name[0] == kWasmVoid ? 0 : 1; \
181 constexpr inline FunctionSig kSig_##name( \
182 kReturnsCount_##name, static_cast<int>(arraysize(kTypes_##name)) - 1, \
183 kTypes_##name + (1 - kReturnsCount_##name));
185#undef DECLARE_SIG
186
187#define DECLARE_SIG_ENTRY(name, ...) &kSig_##name,
188constexpr inline const FunctionSig* kCachedSigs[] = {
190#undef DECLARE_SIG_ENTRY
191
192constexpr WasmOpcodeSig GetShortOpcodeSigIndex(uint8_t opcode) {
193#define CASE(name, opc, sig, ...) opcode == opc ? kSigEnum_##sig:
196#undef CASE
197}
198
199constexpr WasmOpcodeSig GetAsmJsOpcodeSigIndex(uint8_t opcode) {
200#define CASE(name, opc, sig, ...) opcode == (opc & 0xFF) ? kSigEnum_##sig:
202#undef CASE
203}
204
205constexpr WasmOpcodeSig GetSimdOpcodeSigIndex(uint8_t opcode) {
206#define CASE(name, opc, sig, ...) opcode == (opc & 0xFF) ? kSigEnum_##sig:
209#undef CASE
210}
211
213#define CASE(name, opc, sig, ...) opcode == (opc & 0xFF) ? kSigEnum_##sig:
215#undef CASE
216}
217
219#define CASE(name, opc, sig, ...) opcode == (opc & 0xFF) ? kSigEnum_##sig:
222#undef CASE
223}
224
226#define CASE(name, opc, sig32, text, sig64) \
227 opcode == (opc & 0xFF) ? kSigEnum_##sig64:
230#undef CASE
231}
232
233constexpr WasmOpcodeSig GetNumericOpcodeSigIndex(uint8_t opcode) {
234#define CASE(name, opc, sig, ...) opcode == (opc & 0xFF) ? kSigEnum_##sig:
236#undef CASE
237}
238
239constexpr std::array<WasmOpcodeSig, 256> kShortSigTable =
241constexpr std::array<WasmOpcodeSig, 256> kSimpleAsmjsExprSigTable =
243constexpr std::array<WasmOpcodeSig, 256> kSimdExprSigTable =
245constexpr std::array<WasmOpcodeSig, 256> kRelaxedSimdExprSigTable =
247constexpr std::array<WasmOpcodeSig, 256> kAtomicExprSigTableMem32 =
249constexpr std::array<WasmOpcodeSig, 256> kAtomicExprSigTableMem64 =
251constexpr std::array<WasmOpcodeSig, 256> kNumericExprSigTable =
253
254} // namespace impl
255
257 switch (ExtractPrefix(opcode)) {
258 case 0:
261 case kSimdPrefix: {
262 // Handle SIMD MVP opcodes (in [0xfd00, 0xfdff]).
263 if (opcode <= 0xfdff) {
264 DCHECK_LE(0xfd00, opcode);
265 return impl::kCachedSigs[impl::kSimdExprSigTable[opcode & 0xff]];
266 }
267 // Handle relaxed SIMD opcodes (in [0xfd100, 0xfd1ff]).
268 if (IsRelaxedSimdOpcode(opcode)) {
270 }
271 return nullptr;
272 }
273 case kNumericPrefix:
274 return impl::kCachedSigs[impl::kNumericExprSigTable[opcode & 0xff]];
275 case kAsmJsPrefix:
277 default:
278 UNREACHABLE(); // invalid prefix.
279 }
280}
281
283 WasmOpcode opcode, bool is_memory64) {
284 if (is_memory64) {
286 } else {
288 }
289}
290
295
297 TrapReason reason) {
298 switch (reason) {
299#define TRAPREASON_TO_MESSAGE(name) \
300 case k##name: \
301 return MessageTemplate::kWasm##name;
303#undef TRAPREASON_TO_MESSAGE
304 case kTrapCount:
305 UNREACHABLE();
306 }
307}
308
310 MessageTemplate message) {
311 switch (message) {
312#define MESSAGE_TO_TRAPREASON(name) \
313 case MessageTemplate::kWasm##name: \
314 return k##name;
316#undef MESSAGE_TO_TRAPREASON
317 default:
318 UNREACHABLE();
319 }
320}
321
325
326} // namespace wasm
327} // namespace internal
328} // namespace v8
329
330#endif // V8_WASM_WASM_OPCODES_INL_H_
static V8_EXPORT_PRIVATE const char * TemplateString(MessageTemplate index)
Definition messages.cc:425
static constexpr const FunctionSig * Signature(WasmOpcode)
static constexpr bool IsBreakable(WasmOpcode)
static constexpr bool IsRelaxedSimdOpcode(WasmOpcode)
static constexpr bool IsExternRefOpcode(WasmOpcode)
static constexpr uint8_t ExtractPrefix(WasmOpcode)
static constexpr bool IsFP16SimdOpcode(WasmOpcode)
static constexpr const FunctionSig * SignatureForAtomicOp(WasmOpcode opcode, bool is_memory64)
static const char * TrapReasonMessage(TrapReason)
static constexpr const FunctionSig * AsmjsSignature(WasmOpcode)
static constexpr TrapReason MessageIdToTrapReason(MessageTemplate message)
static constexpr bool IsThrowingOpcode(WasmOpcode)
static constexpr const char * OpcodeName(WasmOpcode)
static constexpr bool IsUnconditionalJump(WasmOpcode)
static constexpr MessageTemplate TrapReasonToMessageId(TrapReason)
static constexpr bool IsControlOpcode(WasmOpcode)
static constexpr bool IsPrefixOpcode(WasmOpcode)
#define FOREACH_WASM_TRAPREASON(V)
Definition globals.h:2650
constexpr auto make_array(Function f)
constexpr WasmOpcodeSig GetAtomicOpcodeMem64SigIndex(uint8_t opcode)
constexpr WasmOpcodeSig GetSimdOpcodeSigIndex(uint8_t opcode)
constexpr const FunctionSig * kCachedSigs[]
constexpr WasmOpcodeSig GetRelaxedSimdOpcodeSigIndex(uint8_t opcode)
constexpr std::array< WasmOpcodeSig, 256 > kRelaxedSimdExprSigTable
constexpr std::array< WasmOpcodeSig, 256 > kShortSigTable
constexpr std::array< WasmOpcodeSig, 256 > kAtomicExprSigTableMem32
constexpr std::array< WasmOpcodeSig, 256 > kSimpleAsmjsExprSigTable
constexpr WasmOpcodeSig GetAtomicOpcodeMem32SigIndex(uint8_t opcode)
constexpr WasmOpcodeSig GetNumericOpcodeSigIndex(uint8_t opcode)
constexpr std::array< WasmOpcodeSig, 256 > kNumericExprSigTable
constexpr WasmOpcodeSig GetShortOpcodeSigIndex(uint8_t opcode)
constexpr WasmOpcodeSig GetAsmJsOpcodeSigIndex(uint8_t opcode)
constexpr std::array< WasmOpcodeSig, 256 > kSimdExprSigTable
constexpr std::array< WasmOpcodeSig, 256 > kAtomicExprSigTableMem64
Definition c-api.cc:87
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define DECLARE_SIG_ENTRY(name,...)
#define DECLARE_SIG(name,...)
#define CHECK_OPCODE(name,...)
#define TRAPREASON_TO_MESSAGE(name)
#define MESSAGE_TO_TRAPREASON(name)
#define CHECK_PREFIX(name, opcode)
#define DECLARE_SIG_ENUM(name,...)
#define FOREACH_CONTROL_OPCODE(V)
#define FOREACH_PREFIX(V)
#define FOREACH_ATOMIC_OPCODE(V)
#define FOREACH_OPCODE(V)
#define FOREACH_SIMD_MEM_OPCODE(V)
#define FOREACH_LOAD_MEM_OPCODE(V)
#define FOREACH_SIMD_MEM_1_OPERAND_OPCODE(V)
#define FOREACH_SIMD_MVP_0_OPERAND_OPCODE(V)
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V)
#define FOREACH_ASMJS_COMPAT_OPCODE(V)
#define FOREACH_STORE_MEM_OPCODE(V)
#define FOREACH_RELAXED_SIMD_OPCODE(V)
#define FOREACH_ATOMIC_0_OPERAND_OPCODE(V)
#define FOREACH_NUMERIC_OPCODE_WITH_SIG(V)
#define FOREACH_SIGNATURE(V)
#define FOREACH_SIMPLE_OPCODE(V)