Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/wasm/ast-decoder.h

Issue 2594973003: [wasm] Rename ast-decoder.* to function-body-decoder.* (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #ifndef V8_WASM_AST_DECODER_H_
6 #define V8_WASM_AST_DECODER_H_
7
8 #include <iterator>
9
10 #include "src/base/compiler-specific.h"
11 #include "src/base/iterator.h"
12 #include "src/globals.h"
13 #include "src/signature.h"
14 #include "src/wasm/decoder.h"
15 #include "src/wasm/wasm-opcodes.h"
16 #include "src/wasm/wasm-result.h"
17
18 namespace v8 {
19 namespace internal {
20
21 class BitVector; // forward declaration
22
23 namespace compiler { // external declarations from compiler.
24 class WasmGraphBuilder;
25 }
26
27 namespace wasm {
28
29 const uint32_t kMaxNumWasmLocals = 8000000;
30 struct WasmGlobal;
31
32 // Helpers for decoding different kinds of operands which follow bytecodes.
33 struct LocalIndexOperand {
34 uint32_t index;
35 LocalType type;
36 unsigned length;
37
38 inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
39 index = decoder->checked_read_u32v(pc, 1, &length, "local index");
40 type = kAstStmt;
41 }
42 };
43
44 struct ImmI8Operand {
45 int8_t value;
46 unsigned length;
47 inline ImmI8Operand(Decoder* decoder, const byte* pc) {
48 value = bit_cast<int8_t>(decoder->checked_read_u8(pc, 1, "immi8"));
49 length = 1;
50 }
51 };
52
53 struct ImmI32Operand {
54 int32_t value;
55 unsigned length;
56 inline ImmI32Operand(Decoder* decoder, const byte* pc) {
57 value = decoder->checked_read_i32v(pc, 1, &length, "immi32");
58 }
59 };
60
61 struct ImmI64Operand {
62 int64_t value;
63 unsigned length;
64 inline ImmI64Operand(Decoder* decoder, const byte* pc) {
65 value = decoder->checked_read_i64v(pc, 1, &length, "immi64");
66 }
67 };
68
69 struct ImmF32Operand {
70 float value;
71 unsigned length;
72 inline ImmF32Operand(Decoder* decoder, const byte* pc) {
73 value = bit_cast<float>(decoder->checked_read_u32(pc, 1, "immf32"));
74 length = 4;
75 }
76 };
77
78 struct ImmF64Operand {
79 double value;
80 unsigned length;
81 inline ImmF64Operand(Decoder* decoder, const byte* pc) {
82 value = bit_cast<double>(decoder->checked_read_u64(pc, 1, "immf64"));
83 length = 8;
84 }
85 };
86
87 struct GlobalIndexOperand {
88 uint32_t index;
89 LocalType type;
90 const WasmGlobal* global;
91 unsigned length;
92
93 inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
94 index = decoder->checked_read_u32v(pc, 1, &length, "global index");
95 global = nullptr;
96 type = kAstStmt;
97 }
98 };
99
100 struct BlockTypeOperand {
101 uint32_t arity;
102 const byte* types; // pointer to encoded types for the block.
103 unsigned length;
104
105 inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
106 uint8_t val = decoder->checked_read_u8(pc, 1, "block type");
107 LocalType type = kAstStmt;
108 length = 1;
109 arity = 0;
110 types = nullptr;
111 if (decode_local_type(val, &type)) {
112 arity = type == kAstStmt ? 0 : 1;
113 types = pc + 1;
114 } else {
115 // Handle multi-value blocks.
116 if (!FLAG_wasm_mv_prototype) {
117 decoder->error(pc, pc + 1, "invalid block arity > 1");
118 return;
119 }
120 if (val != kMultivalBlock) {
121 decoder->error(pc, pc + 1, "invalid block type");
122 return;
123 }
124 // Decode and check the types vector of the block.
125 unsigned len = 0;
126 uint32_t count = decoder->checked_read_u32v(pc, 2, &len, "block arity");
127 // {count} is encoded as {arity-2}, so that a {0} count here corresponds
128 // to a block with 2 values. This makes invalid/redundant encodings
129 // impossible.
130 arity = count + 2;
131 length = 1 + len + arity;
132 types = pc + 1 + 1 + len;
133
134 for (uint32_t i = 0; i < arity; i++) {
135 uint32_t offset = 1 + 1 + len + i;
136 val = decoder->checked_read_u8(pc, offset, "block type");
137 decode_local_type(val, &type);
138 if (type == kAstStmt) {
139 decoder->error(pc, pc + offset, "invalid block type");
140 return;
141 }
142 }
143 }
144 }
145 // Decode a byte representing a local type. Return {false} if the encoded
146 // byte was invalid or {kMultivalBlock}.
147 bool decode_local_type(uint8_t val, LocalType* result) {
148 switch (static_cast<LocalTypeCode>(val)) {
149 case kLocalVoid:
150 *result = kAstStmt;
151 return true;
152 case kLocalI32:
153 *result = kAstI32;
154 return true;
155 case kLocalI64:
156 *result = kAstI64;
157 return true;
158 case kLocalF32:
159 *result = kAstF32;
160 return true;
161 case kLocalF64:
162 *result = kAstF64;
163 return true;
164 case kLocalS128:
165 *result = kAstS128;
166 return true;
167 default:
168 *result = kAstStmt;
169 return false;
170 }
171 }
172 LocalType read_entry(unsigned index) {
173 DCHECK_LT(index, arity);
174 LocalType result;
175 CHECK(decode_local_type(types[index], &result));
176 return result;
177 }
178 };
179
180 struct Control;
181 struct BreakDepthOperand {
182 uint32_t depth;
183 Control* target;
184 unsigned length;
185 inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
186 depth = decoder->checked_read_u32v(pc, 1, &length, "break depth");
187 target = nullptr;
188 }
189 };
190
191 struct CallIndirectOperand {
192 uint32_t table_index;
193 uint32_t index;
194 FunctionSig* sig;
195 unsigned length;
196 inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
197 unsigned len = 0;
198 index = decoder->checked_read_u32v(pc, 1, &len, "signature index");
199 table_index = decoder->checked_read_u8(pc, 1 + len, "table index");
200 if (table_index != 0) {
201 decoder->error(pc, pc + 1 + len, "expected table index 0, found %u",
202 table_index);
203 }
204 length = 1 + len;
205 sig = nullptr;
206 }
207 };
208
209 struct CallFunctionOperand {
210 uint32_t index;
211 FunctionSig* sig;
212 unsigned length;
213 inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
214 unsigned len1 = 0;
215 unsigned len2 = 0;
216 index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index");
217 length = len1 + len2;
218 sig = nullptr;
219 }
220 };
221
222 struct MemoryIndexOperand {
223 uint32_t index;
224 unsigned length;
225 inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
226 index = decoder->checked_read_u8(pc, 1, "memory index");
227 if (index != 0) {
228 decoder->error(pc, pc + 1, "expected memory index 0, found %u", index);
229 }
230 length = 1;
231 }
232 };
233
234 struct BranchTableOperand {
235 uint32_t table_count;
236 const byte* start;
237 const byte* table;
238 inline BranchTableOperand(Decoder* decoder, const byte* pc) {
239 DCHECK_EQ(kExprBrTable, decoder->checked_read_u8(pc, 0, "opcode"));
240 start = pc + 1;
241 unsigned len1 = 0;
242 table_count = decoder->checked_read_u32v(pc, 1, &len1, "table count");
243 if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 ||
244 len1 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
245 decoder->error(pc, "branch table size overflow");
246 }
247 table = pc + 1 + len1;
248 }
249 };
250
251 // A helper to iterate over a branch table.
252 class BranchTableIterator {
253 public:
254 unsigned cur_index() { return index_; }
255 bool has_next() { return decoder_->ok() && index_ <= table_count_; }
256 uint32_t next() {
257 DCHECK(has_next());
258 index_++;
259 unsigned length = 0;
260 uint32_t result =
261 decoder_->checked_read_u32v(pc_, 0, &length, "branch table entry");
262 pc_ += length;
263 return result;
264 }
265 // length, including the length of the {BranchTableOperand}, but not the
266 // opcode.
267 unsigned length() {
268 while (has_next()) next();
269 return static_cast<unsigned>(pc_ - start_);
270 }
271 const byte* pc() { return pc_; }
272
273 BranchTableIterator(Decoder* decoder, BranchTableOperand& operand)
274 : decoder_(decoder),
275 start_(operand.start),
276 pc_(operand.table),
277 index_(0),
278 table_count_(operand.table_count) {}
279
280 private:
281 Decoder* decoder_;
282 const byte* start_;
283 const byte* pc_;
284 uint32_t index_; // the current index.
285 uint32_t table_count_; // the count of entries, not including default.
286 };
287
288 struct MemoryAccessOperand {
289 uint32_t alignment;
290 uint32_t offset;
291 unsigned length;
292 inline MemoryAccessOperand(Decoder* decoder, const byte* pc,
293 uint32_t max_alignment) {
294 unsigned alignment_length;
295 alignment =
296 decoder->checked_read_u32v(pc, 1, &alignment_length, "alignment");
297 if (max_alignment < alignment) {
298 decoder->error(pc, pc + 1,
299 "invalid alignment; expected maximum alignment is %u, "
300 "actual alignment is %u",
301 max_alignment, alignment);
302 }
303 unsigned offset_length;
304 offset = decoder->checked_read_u32v(pc, 1 + alignment_length,
305 &offset_length, "offset");
306 length = alignment_length + offset_length;
307 }
308 };
309
310 typedef compiler::WasmGraphBuilder TFBuilder;
311 struct ModuleEnv; // forward declaration of module interface.
312
313 // All of the various data structures necessary to decode a function body.
314 struct FunctionBody {
315 ModuleEnv* module; // module environment
316 FunctionSig* sig; // function signature
317 const byte* base; // base of the module bytes, for error reporting
318 const byte* start; // start of the function body
319 const byte* end; // end of the function body
320 };
321
322 static inline FunctionBody FunctionBodyForTesting(const byte* start,
323 const byte* end) {
324 return {nullptr, nullptr, start, start, end};
325 }
326
327 struct DecodeStruct {
328 int unused;
329 };
330 typedef Result<DecodeStruct*> DecodeResult;
331 inline std::ostream& operator<<(std::ostream& os, const DecodeStruct& tree) {
332 return os;
333 }
334
335 V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
336 FunctionBody& body);
337 DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
338 FunctionBody& body);
339 bool PrintAst(AccountingAllocator* allocator, const FunctionBody& body,
340 std::ostream& os,
341 std::vector<std::tuple<uint32_t, int, int>>* offset_table);
342
343 // A simplified form of AST printing, e.g. from a debugger.
344 void PrintAstForDebugging(const byte* start, const byte* end);
345
346 inline DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
347 ModuleEnv* module, FunctionSig* sig,
348 const byte* start, const byte* end) {
349 FunctionBody body = {module, sig, nullptr, start, end};
350 return VerifyWasmCode(allocator, body);
351 }
352
353 inline DecodeResult BuildTFGraph(AccountingAllocator* allocator,
354 TFBuilder* builder, ModuleEnv* module,
355 FunctionSig* sig, const byte* start,
356 const byte* end) {
357 FunctionBody body = {module, sig, nullptr, start, end};
358 return BuildTFGraph(allocator, builder, body);
359 }
360
361 struct AstLocalDecls {
362 // The size of the encoded declarations.
363 uint32_t decls_encoded_size; // size of encoded declarations
364
365 // Total number of locals.
366 uint32_t total_local_count;
367
368 // List of {local type, count} pairs.
369 ZoneVector<std::pair<LocalType, uint32_t>> local_types;
370
371 // Constructor initializes the vector.
372 explicit AstLocalDecls(Zone* zone)
373 : decls_encoded_size(0), total_local_count(0), local_types(zone) {}
374 };
375
376 V8_EXPORT_PRIVATE bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start,
377 const byte* end);
378 V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone,
379 size_t num_locals,
380 const byte* start,
381 const byte* end);
382
383 // Computes the length of the opcode at the given address.
384 V8_EXPORT_PRIVATE unsigned OpcodeLength(const byte* pc, const byte* end);
385
386 // A simple forward iterator for bytecodes.
387 class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
388 // Base class for both iterators defined below.
389 class iterator_base {
390 public:
391 inline iterator_base& operator++() {
392 DCHECK_LT(ptr_, end_);
393 ptr_ += OpcodeLength(ptr_, end_);
394 return *this;
395 }
396 inline bool operator==(const iterator_base& that) {
397 return this->ptr_ == that.ptr_;
398 }
399 inline bool operator!=(const iterator_base& that) {
400 return this->ptr_ != that.ptr_;
401 }
402
403 protected:
404 const byte* ptr_;
405 const byte* end_;
406 iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
407 };
408
409 public:
410 // If one wants to iterate over the bytecode without looking at {pc_offset()}.
411 class opcode_iterator
412 : public iterator_base,
413 public std::iterator<std::input_iterator_tag, WasmOpcode> {
414 public:
415 inline WasmOpcode operator*() {
416 DCHECK_LT(ptr_, end_);
417 return static_cast<WasmOpcode>(*ptr_);
418 }
419
420 private:
421 friend class BytecodeIterator;
422 opcode_iterator(const byte* ptr, const byte* end)
423 : iterator_base(ptr, end) {}
424 };
425 // If one wants to iterate over the instruction offsets without looking at
426 // opcodes.
427 class offset_iterator
428 : public iterator_base,
429 public std::iterator<std::input_iterator_tag, uint32_t> {
430 public:
431 inline uint32_t operator*() {
432 DCHECK_LT(ptr_, end_);
433 return static_cast<uint32_t>(ptr_ - start_);
434 }
435
436 private:
437 const byte* start_;
438 friend class BytecodeIterator;
439 offset_iterator(const byte* start, const byte* ptr, const byte* end)
440 : iterator_base(ptr, end), start_(start) {}
441 };
442
443 // Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
444 // assume the bytecode starts with local declarations and decode them.
445 // Otherwise, do not decode local decls.
446 BytecodeIterator(const byte* start, const byte* end,
447 AstLocalDecls* decls = nullptr);
448
449 base::iterator_range<opcode_iterator> opcodes() {
450 return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_),
451 opcode_iterator(end_, end_));
452 }
453
454 base::iterator_range<offset_iterator> offsets() {
455 return base::iterator_range<offset_iterator>(
456 offset_iterator(start_, pc_, end_),
457 offset_iterator(start_, end_, end_));
458 }
459
460 WasmOpcode current() {
461 return static_cast<WasmOpcode>(
462 checked_read_u8(pc_, 0, "expected bytecode"));
463 }
464
465 void next() {
466 if (pc_ < end_) {
467 pc_ += OpcodeLength(pc_, end_);
468 if (pc_ >= end_) pc_ = end_;
469 }
470 }
471
472 bool has_next() { return pc_ < end_; }
473 };
474
475 } // namespace wasm
476 } // namespace internal
477 } // namespace v8
478
479 #endif // V8_WASM_AST_DECODER_H_
OLDNEW
« no previous file with comments | « src/v8.gyp ('k') | src/wasm/ast-decoder.cc » ('j') | src/wasm/function-body-decoder.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698