Line data Source code
1 : // Copyright 2017 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_FUNCTION_BODY_DECODER_IMPL_H_
6 : #define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
7 :
8 : #include "src/wasm/decoder.h"
9 : #include "src/wasm/wasm-opcodes.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 : namespace wasm {
14 :
15 : struct WasmGlobal;
16 :
17 : // Use this macro to check a condition if checked == true, and DCHECK the
18 : // condition otherwise.
19 : #define CHECKED_COND(cond) \
20 : (checked ? (cond) : ([&] { \
21 : DCHECK(cond); \
22 : return true; \
23 : })())
24 :
25 : // Helpers for decoding different kinds of operands which follow bytecodes.
26 : template <bool checked>
27 : struct LocalIndexOperand {
28 : uint32_t index;
29 : ValueType type = kWasmStmt;
30 : unsigned length;
31 :
32 7019012 : inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
33 8161725 : index = decoder->read_u32v<checked>(pc + 1, &length, "local index");
34 : }
35 : };
36 :
37 : template <bool checked>
38 : struct ImmI32Operand {
39 : int32_t value;
40 : unsigned length;
41 571633 : inline ImmI32Operand(Decoder* decoder, const byte* pc) {
42 2863600 : value = decoder->read_i32v<checked>(pc + 1, &length, "immi32");
43 571633 : }
44 : };
45 :
46 : template <bool checked>
47 : struct ImmI64Operand {
48 : int64_t value;
49 : unsigned length;
50 11585 : inline ImmI64Operand(Decoder* decoder, const byte* pc) {
51 43884 : value = decoder->read_i64v<checked>(pc + 1, &length, "immi64");
52 11585 : }
53 : };
54 :
55 : template <bool checked>
56 : struct ImmF32Operand {
57 : float value;
58 : unsigned length = 4;
59 442092 : inline ImmF32Operand(Decoder* decoder, const byte* pc) {
60 : // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
61 884184 : uint32_t tmp = decoder->read_u32<checked>(pc + 1, "immf32");
62 442092 : memcpy(&value, &tmp, sizeof(value));
63 442092 : }
64 : };
65 :
66 : template <bool checked>
67 : struct ImmF64Operand {
68 : double value;
69 : unsigned length = 8;
70 11307 : inline ImmF64Operand(Decoder* decoder, const byte* pc) {
71 : // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
72 22614 : uint64_t tmp = decoder->read_u64<checked>(pc + 1, "immf64");
73 11307 : memcpy(&value, &tmp, sizeof(value));
74 11307 : }
75 : };
76 :
77 : template <bool checked>
78 : struct GlobalIndexOperand {
79 : uint32_t index;
80 : ValueType type = kWasmStmt;
81 : const WasmGlobal* global = nullptr;
82 : unsigned length;
83 :
84 22571 : inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
85 44214 : index = decoder->read_u32v<checked>(pc + 1, &length, "global index");
86 : }
87 : };
88 :
89 : template <bool checked>
90 : struct BlockTypeOperand {
91 : uint32_t arity = 0;
92 : const byte* types = nullptr; // pointer to encoded types for the block.
93 : unsigned length = 1;
94 :
95 2521128 : inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
96 2521128 : uint8_t val = decoder->read_u8<checked>(pc + 1, "block type");
97 2521128 : ValueType type = kWasmStmt;
98 2521128 : if (decode_local_type(val, &type)) {
99 2459771 : arity = type == kWasmStmt ? 0 : 1;
100 2459771 : types = pc + 1;
101 : } else {
102 : // Handle multi-value blocks.
103 100 : if (!CHECKED_COND(FLAG_wasm_mv_prototype)) {
104 : decoder->error(pc + 1, "invalid block arity > 1");
105 51 : return;
106 : }
107 49 : if (!CHECKED_COND(val == kMultivalBlock)) {
108 : decoder->error(pc + 1, "invalid block type");
109 : return;
110 : }
111 : // Decode and check the types vector of the block.
112 49 : unsigned len = 0;
113 61306 : uint32_t count = decoder->read_u32v<checked>(pc + 2, &len, "block arity");
114 : // {count} is encoded as {arity-2}, so that a {0} count here corresponds
115 : // to a block with 2 values. This makes invalid/redundant encodings
116 : // impossible.
117 61306 : arity = count + 2;
118 61306 : length = 1 + len + arity;
119 61306 : types = pc + 1 + 1 + len;
120 :
121 183918 : for (uint32_t i = 0; i < arity; i++) {
122 122612 : uint32_t offset = 1 + 1 + len + i;
123 122612 : val = decoder->read_u8<checked>(pc + offset, "block type");
124 122612 : decode_local_type(val, &type);
125 98 : if (!CHECKED_COND(type != kWasmStmt)) {
126 : decoder->error(pc + offset, "invalid block type");
127 : return;
128 : }
129 : }
130 : }
131 : }
132 :
133 : // Decode a byte representing a local type. Return {false} if the encoded
134 : // byte was invalid or {kMultivalBlock}.
135 2650504 : inline bool decode_local_type(uint8_t val, ValueType* result) {
136 2650504 : switch (static_cast<ValueTypeCode>(val)) {
137 : case kLocalVoid:
138 2438485 : *result = kWasmStmt;
139 : return true;
140 : case kLocalI32:
141 145794 : *result = kWasmI32;
142 : return true;
143 : case kLocalI64:
144 68 : *result = kWasmI64;
145 : return true;
146 : case kLocalF32:
147 1823 : *result = kWasmF32;
148 : return true;
149 : case kLocalF64:
150 2977 : *result = kWasmF64;
151 : return true;
152 : case kLocalS128:
153 0 : *result = kWasmS128;
154 : return true;
155 : case kLocalS1x4:
156 0 : *result = kWasmS1x4;
157 : return true;
158 : case kLocalS1x8:
159 0 : *result = kWasmS1x8;
160 : return true;
161 : case kLocalS1x16:
162 0 : *result = kWasmS1x16;
163 : return true;
164 : default:
165 61357 : *result = kWasmStmt;
166 : return false;
167 : }
168 : }
169 6764 : ValueType read_entry(unsigned index) {
170 : DCHECK_LT(index, arity);
171 : ValueType result;
172 6764 : CHECK(decode_local_type(types[index], &result));
173 6764 : return result;
174 : }
175 : };
176 :
177 : struct Control;
178 : template <bool checked>
179 : struct BreakDepthOperand {
180 : uint32_t depth;
181 : Control* target = nullptr;
182 : unsigned length;
183 161179 : inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
184 323158 : depth = decoder->read_u32v<checked>(pc + 1, &length, "break depth");
185 : }
186 : };
187 :
188 : template <bool checked>
189 : struct CallIndirectOperand {
190 : uint32_t table_index;
191 : uint32_t index;
192 : FunctionSig* sig = nullptr;
193 : unsigned length;
194 3630 : inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
195 3195 : unsigned len = 0;
196 7260 : index = decoder->read_u32v<checked>(pc + 1, &len, "signature index");
197 6825 : table_index = decoder->read_u8<checked>(pc + 1 + len, "table index");
198 3195 : if (!CHECKED_COND(table_index == 0)) {
199 0 : decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
200 0 : table_index);
201 : }
202 3630 : length = 1 + len;
203 3630 : }
204 : };
205 :
206 : template <bool checked>
207 : struct CallFunctionOperand {
208 : uint32_t index;
209 : FunctionSig* sig = nullptr;
210 : unsigned length;
211 1210777 : inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
212 1429232 : index = decoder->read_u32v<checked>(pc + 1, &length, "function index");
213 : }
214 : };
215 :
216 : template <bool checked>
217 : struct MemoryIndexOperand {
218 : uint32_t index;
219 : unsigned length = 1;
220 1547 : inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
221 3189 : index = decoder->read_u8<checked>(pc + 1, "memory index");
222 1547 : if (!CHECKED_COND(index == 0)) {
223 15 : decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
224 : }
225 1547 : }
226 : };
227 :
228 : template <bool checked>
229 : struct BranchTableOperand {
230 : uint32_t table_count;
231 : const byte* start;
232 : const byte* table;
233 15428 : inline BranchTableOperand(Decoder* decoder, const byte* pc) {
234 : DCHECK_EQ(kExprBrTable, decoder->read_u8<checked>(pc, "opcode"));
235 411038 : start = pc + 1;
236 15428 : unsigned len = 0;
237 15428 : table_count = decoder->read_u32v<checked>(pc + 1, &len, "table count");
238 22783 : table = pc + 1 + len;
239 15428 : }
240 : };
241 :
242 : // A helper to iterate over a branch table.
243 : template <bool checked>
244 : class BranchTableIterator {
245 : public:
246 : unsigned cur_index() { return index_; }
247 258664 : bool has_next() { return decoder_->ok() && index_ <= table_count_; }
248 88158 : uint32_t next() {
249 : DCHECK(has_next());
250 117447 : index_++;
251 : unsigned length;
252 : uint32_t result =
253 88158 : decoder_->read_u32v<checked>(pc_, &length, "branch table entry");
254 117447 : pc_ += length;
255 88158 : return result;
256 : }
257 : // length, including the length of the {BranchTableOperand}, but not the
258 : // opcode.
259 15337 : unsigned length() {
260 62479 : while (has_next()) next();
261 15337 : return static_cast<unsigned>(pc_ - start_);
262 : }
263 : const byte* pc() { return pc_; }
264 :
265 : BranchTableIterator(Decoder* decoder, BranchTableOperand<checked>& operand)
266 : : decoder_(decoder),
267 : start_(operand.start),
268 : pc_(operand.table),
269 : index_(0),
270 403683 : table_count_(operand.table_count) {}
271 :
272 : private:
273 : Decoder* decoder_;
274 : const byte* start_;
275 : const byte* pc_;
276 : uint32_t index_; // the current index.
277 : uint32_t table_count_; // the count of entries, not including default.
278 : };
279 :
280 : template <bool checked>
281 : struct MemoryAccessOperand {
282 : uint32_t alignment;
283 : uint32_t offset;
284 : unsigned length;
285 168199 : inline MemoryAccessOperand(Decoder* decoder, const byte* pc,
286 : uint32_t max_alignment) {
287 : unsigned alignment_length;
288 336398 : alignment =
289 : decoder->read_u32v<checked>(pc + 1, &alignment_length, "alignment");
290 28869 : if (!CHECKED_COND(alignment <= max_alignment)) {
291 38 : decoder->errorf(pc + 1,
292 : "invalid alignment; expected maximum alignment is %u, "
293 : "actual alignment is %u",
294 : max_alignment, alignment);
295 : }
296 : unsigned offset_length;
297 336398 : offset = decoder->read_u32v<checked>(pc + 1 + alignment_length,
298 : &offset_length, "offset");
299 168199 : length = alignment_length + offset_length;
300 168199 : }
301 : };
302 :
303 : // Operand for SIMD lane operations.
304 : template <bool checked>
305 : struct SimdLaneOperand {
306 : uint8_t lane;
307 : unsigned length = 1;
308 :
309 5390 : inline SimdLaneOperand(Decoder* decoder, const byte* pc) {
310 10780 : lane = decoder->read_u8<checked>(pc + 2, "lane");
311 : }
312 : };
313 :
314 : // Operand for SIMD shift operations.
315 : template <bool checked>
316 : struct SimdShiftOperand {
317 : uint8_t shift;
318 : unsigned length = 1;
319 :
320 42 : inline SimdShiftOperand(Decoder* decoder, const byte* pc) {
321 84 : shift = decoder->read_u8<checked>(pc + 2, "shift");
322 : }
323 : };
324 :
325 : // Operand for SIMD concatenation operations.
326 : template <bool checked>
327 : struct SimdConcatOperand {
328 : uint8_t bytes;
329 : unsigned length;
330 :
331 : inline SimdConcatOperand(Decoder* decoder, const byte* pc) {
332 0 : bytes = decoder->read_u8<checked>(pc + 2, "bytes");
333 : length = 1;
334 : }
335 : };
336 :
337 : #undef CHECKED_COND
338 :
339 : } // namespace wasm
340 : } // namespace internal
341 : } // namespace v8
342 :
343 : #endif // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
|