blob: 8c2c2c47345579e918cda5db21ae601ed0fa90b8 [file] [log] [blame]
Ben Murdoch014dc512016-03-22 12:00:34 +00001// 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 "src/signature.h"
Ben Murdoch109988c2016-05-18 11:27:45 +01009#include "src/wasm/decoder.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000010#include "src/wasm/wasm-opcodes.h"
11#include "src/wasm/wasm-result.h"
12
13namespace v8 {
14namespace internal {
15
Ben Murdoch109988c2016-05-18 11:27:45 +010016class BitVector; // forward declaration
17
Ben Murdoch014dc512016-03-22 12:00:34 +000018namespace compiler { // external declarations from compiler.
19class WasmGraphBuilder;
20}
21
22namespace wasm {
23
Ben Murdochf3b273f2017-01-17 12:11:28 +000024const uint32_t kMaxNumWasmLocals = 8000000;
25struct WasmGlobal;
26
Ben Murdoch109988c2016-05-18 11:27:45 +010027// Helpers for decoding different kinds of operands which follow bytecodes.
28struct LocalIndexOperand {
29 uint32_t index;
30 LocalType type;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010031 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010032
33 inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
34 index = decoder->checked_read_u32v(pc, 1, &length, "local index");
35 type = kAstStmt;
36 }
37};
38
39struct ImmI8Operand {
40 int8_t value;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010041 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010042 inline ImmI8Operand(Decoder* decoder, const byte* pc) {
43 value = bit_cast<int8_t>(decoder->checked_read_u8(pc, 1, "immi8"));
44 length = 1;
45 }
46};
47
48struct ImmI32Operand {
49 int32_t value;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010050 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010051 inline ImmI32Operand(Decoder* decoder, const byte* pc) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +010052 value = decoder->checked_read_i32v(pc, 1, &length, "immi32");
Ben Murdoch109988c2016-05-18 11:27:45 +010053 }
54};
55
56struct ImmI64Operand {
57 int64_t value;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010058 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010059 inline ImmI64Operand(Decoder* decoder, const byte* pc) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +010060 value = decoder->checked_read_i64v(pc, 1, &length, "immi64");
Ben Murdoch109988c2016-05-18 11:27:45 +010061 }
62};
63
64struct ImmF32Operand {
65 float value;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010066 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010067 inline ImmF32Operand(Decoder* decoder, const byte* pc) {
68 value = bit_cast<float>(decoder->checked_read_u32(pc, 1, "immf32"));
69 length = 4;
70 }
71};
72
73struct ImmF64Operand {
74 double value;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010075 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010076 inline ImmF64Operand(Decoder* decoder, const byte* pc) {
77 value = bit_cast<double>(decoder->checked_read_u64(pc, 1, "immf64"));
78 length = 8;
79 }
80};
81
82struct GlobalIndexOperand {
83 uint32_t index;
84 LocalType type;
Ben Murdochf3b273f2017-01-17 12:11:28 +000085 const WasmGlobal* global;
Ben Murdoch13e2dad2016-09-16 13:49:30 +010086 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +010087
88 inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
89 index = decoder->checked_read_u32v(pc, 1, &length, "global index");
Ben Murdochf3b273f2017-01-17 12:11:28 +000090 global = nullptr;
Ben Murdoch109988c2016-05-18 11:27:45 +010091 type = kAstStmt;
Ben Murdoch109988c2016-05-18 11:27:45 +010092 }
93};
94
Ben Murdochf3b273f2017-01-17 12:11:28 +000095struct BlockTypeOperand {
96 uint32_t arity;
97 const byte* types; // pointer to encoded types for the block.
98 unsigned length;
99
100 inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
101 uint8_t val = decoder->checked_read_u8(pc, 1, "block type");
102 LocalType type = kAstStmt;
103 length = 1;
104 arity = 0;
105 types = nullptr;
106 if (decode_local_type(val, &type)) {
107 arity = type == kAstStmt ? 0 : 1;
108 types = pc + 1;
109 } else {
110 // Handle multi-value blocks.
111 if (!FLAG_wasm_mv_prototype) {
112 decoder->error(pc, pc + 1, "invalid block arity > 1");
113 return;
114 }
115 if (val != kMultivalBlock) {
116 decoder->error(pc, pc + 1, "invalid block type");
117 return;
118 }
119 // Decode and check the types vector of the block.
120 unsigned len = 0;
121 uint32_t count = decoder->checked_read_u32v(pc, 2, &len, "block arity");
122 // {count} is encoded as {arity-2}, so that a {0} count here corresponds
123 // to a block with 2 values. This makes invalid/redundant encodings
124 // impossible.
125 arity = count + 2;
126 length = 1 + len + arity;
127 types = pc + 1 + 1 + len;
128
129 for (uint32_t i = 0; i < arity; i++) {
130 uint32_t offset = 1 + 1 + len + i;
131 val = decoder->checked_read_u8(pc, offset, "block type");
132 decode_local_type(val, &type);
133 if (type == kAstStmt) {
134 decoder->error(pc, pc + offset, "invalid block type");
135 return;
136 }
137 }
138 }
139 }
140 // Decode a byte representing a local type. Return {false} if the encoded
141 // byte was invalid or {kMultivalBlock}.
142 bool decode_local_type(uint8_t val, LocalType* result) {
143 switch (static_cast<LocalTypeCode>(val)) {
144 case kLocalVoid:
145 *result = kAstStmt;
146 return true;
147 case kLocalI32:
148 *result = kAstI32;
149 return true;
150 case kLocalI64:
151 *result = kAstI64;
152 return true;
153 case kLocalF32:
154 *result = kAstF32;
155 return true;
156 case kLocalF64:
157 *result = kAstF64;
158 return true;
159 default:
160 *result = kAstStmt;
161 return false;
162 }
163 }
164 LocalType read_entry(unsigned index) {
165 DCHECK_LT(index, arity);
166 LocalType result;
167 CHECK(decode_local_type(types[index], &result));
168 return result;
169 }
170};
171
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100172struct Control;
Ben Murdoch109988c2016-05-18 11:27:45 +0100173struct BreakDepthOperand {
174 uint32_t depth;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100175 Control* target;
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100176 unsigned length;
Ben Murdoch109988c2016-05-18 11:27:45 +0100177 inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000178 depth = decoder->checked_read_u32v(pc, 1, &length, "break depth");
Ben Murdoch109988c2016-05-18 11:27:45 +0100179 target = nullptr;
180 }
181};
182
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100183struct CallIndirectOperand {
Ben Murdoch109988c2016-05-18 11:27:45 +0100184 uint32_t index;
185 FunctionSig* sig;
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100186 unsigned length;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100187 inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100188 unsigned len1 = 0;
189 unsigned len2 = 0;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100190 index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "signature index");
191 length = len1 + len2;
Ben Murdoch109988c2016-05-18 11:27:45 +0100192 sig = nullptr;
193 }
194};
195
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100196struct CallFunctionOperand {
Ben Murdoch109988c2016-05-18 11:27:45 +0100197 uint32_t index;
198 FunctionSig* sig;
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100199 unsigned length;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100200 inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100201 unsigned len1 = 0;
202 unsigned len2 = 0;
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100203 index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index");
204 length = len1 + len2;
Ben Murdoch109988c2016-05-18 11:27:45 +0100205 sig = nullptr;
206 }
207};
208
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100209struct BranchTableOperand {
Ben Murdoch109988c2016-05-18 11:27:45 +0100210 uint32_t table_count;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000211 const byte* start;
Ben Murdoch109988c2016-05-18 11:27:45 +0100212 const byte* table;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100213 inline BranchTableOperand(Decoder* decoder, const byte* pc) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000214 DCHECK_EQ(kExprBrTable, decoder->checked_read_u8(pc, 0, "opcode"));
215 start = pc + 1;
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100216 unsigned len1 = 0;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000217 table_count = decoder->checked_read_u32v(pc, 1, &len1, "table count");
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100218 if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 ||
Ben Murdochf3b273f2017-01-17 12:11:28 +0000219 len1 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100220 decoder->error(pc, "branch table size overflow");
221 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000222 table = pc + 1 + len1;
Ben Murdoch109988c2016-05-18 11:27:45 +0100223 }
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100224 inline uint32_t read_entry(Decoder* decoder, unsigned i) {
225 DCHECK(i <= table_count);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100226 return table ? decoder->read_u32(table + i * sizeof(uint32_t)) : 0;
Ben Murdoch109988c2016-05-18 11:27:45 +0100227 }
228};
229
Ben Murdochf3b273f2017-01-17 12:11:28 +0000230// A helper to iterate over a branch table.
231class BranchTableIterator {
232 public:
233 unsigned cur_index() { return index_; }
234 bool has_next() { return index_ <= table_count_; }
235 uint32_t next() {
236 DCHECK(has_next());
237 index_++;
238 unsigned length = 0;
239 uint32_t result =
240 decoder_->checked_read_u32v(pc_, 0, &length, "branch table entry");
241 pc_ += length;
242 return result;
243 }
244 // length, including the length of the {BranchTableOperand}, but not the
245 // opcode.
246 unsigned length() {
247 while (has_next()) next();
248 return static_cast<unsigned>(pc_ - start_);
249 }
250 const byte* pc() { return pc_; }
251
252 BranchTableIterator(Decoder* decoder, BranchTableOperand& operand)
253 : decoder_(decoder),
254 start_(operand.start),
255 pc_(operand.table),
256 index_(0),
257 table_count_(operand.table_count) {}
258
259 private:
260 Decoder* decoder_;
261 const byte* start_;
262 const byte* pc_;
263 uint32_t index_; // the current index.
264 uint32_t table_count_; // the count of entries, not including default.
265};
266
Ben Murdoch109988c2016-05-18 11:27:45 +0100267struct MemoryAccessOperand {
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100268 uint32_t alignment;
Ben Murdoch109988c2016-05-18 11:27:45 +0100269 uint32_t offset;
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100270 unsigned length;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000271 inline MemoryAccessOperand(Decoder* decoder, const byte* pc,
272 uint32_t max_alignment) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100273 unsigned alignment_length;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100274 alignment =
275 decoder->checked_read_u32v(pc, 1, &alignment_length, "alignment");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000276 if (max_alignment < alignment) {
277 decoder->error(pc, pc + 1,
278 "invalid alignment; expected maximum alignment is %u, "
279 "actual alignment is %u",
280 max_alignment, alignment);
281 }
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100282 unsigned offset_length;
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100283 offset = decoder->checked_read_u32v(pc, 1 + alignment_length,
284 &offset_length, "offset");
285 length = alignment_length + offset_length;
Ben Murdoch109988c2016-05-18 11:27:45 +0100286 }
287};
288
Ben Murdoch014dc512016-03-22 12:00:34 +0000289typedef compiler::WasmGraphBuilder TFBuilder;
290struct ModuleEnv; // forward declaration of module interface.
291
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100292// All of the various data structures necessary to decode a function body.
293struct FunctionBody {
294 ModuleEnv* module; // module environment
295 FunctionSig* sig; // function signature
296 const byte* base; // base of the module bytes, for error reporting
297 const byte* start; // start of the function body
298 const byte* end; // end of the function body
Ben Murdoch014dc512016-03-22 12:00:34 +0000299};
300
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100301static inline FunctionBody FunctionBodyForTesting(const byte* start,
302 const byte* end) {
303 return {nullptr, nullptr, start, start, end};
304}
305
Ben Murdochf91f0612016-11-29 16:50:11 +0000306struct DecodeStruct {
307 int unused;
308};
309typedef Result<DecodeStruct*> DecodeResult;
310inline std::ostream& operator<<(std::ostream& os, const DecodeStruct& tree) {
311 return os;
312}
Ben Murdoch014dc512016-03-22 12:00:34 +0000313
Ben Murdochf3b273f2017-01-17 12:11:28 +0000314V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
315 FunctionBody& body);
316DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
317 FunctionBody& body);
318bool PrintAst(AccountingAllocator* allocator, const FunctionBody& body,
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100319 std::ostream& os,
320 std::vector<std::tuple<uint32_t, int, int>>* offset_table);
Ben Murdoch014dc512016-03-22 12:00:34 +0000321
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100322// A simplified form of AST printing, e.g. from a debugger.
323void PrintAstForDebugging(const byte* start, const byte* end);
324
Ben Murdochf3b273f2017-01-17 12:11:28 +0000325inline DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
Ben Murdochf91f0612016-11-29 16:50:11 +0000326 ModuleEnv* module, FunctionSig* sig,
327 const byte* start, const byte* end) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100328 FunctionBody body = {module, sig, nullptr, start, end};
329 return VerifyWasmCode(allocator, body);
Ben Murdoch014dc512016-03-22 12:00:34 +0000330}
331
Ben Murdochf3b273f2017-01-17 12:11:28 +0000332inline DecodeResult BuildTFGraph(AccountingAllocator* allocator,
Ben Murdochf91f0612016-11-29 16:50:11 +0000333 TFBuilder* builder, ModuleEnv* module,
334 FunctionSig* sig, const byte* start,
335 const byte* end) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100336 FunctionBody body = {module, sig, nullptr, start, end};
337 return BuildTFGraph(allocator, builder, body);
Ben Murdoch014dc512016-03-22 12:00:34 +0000338}
339
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100340struct AstLocalDecls {
341 // The size of the encoded declarations.
342 uint32_t decls_encoded_size; // size of encoded declarations
343
344 // Total number of locals.
345 uint32_t total_local_count;
346
347 // List of {local type, count} pairs.
348 ZoneVector<std::pair<LocalType, uint32_t>> local_types;
349
350 // Constructor initializes the vector.
351 explicit AstLocalDecls(Zone* zone)
352 : decls_encoded_size(0), total_local_count(0), local_types(zone) {}
353};
354
355bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, const byte* end);
356BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
Ben Murdoch109988c2016-05-18 11:27:45 +0100357 const byte* start, const byte* end);
358
Ben Murdoch014dc512016-03-22 12:00:34 +0000359// Computes the length of the opcode at the given address.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100360unsigned OpcodeLength(const byte* pc, const byte* end);
Ben Murdoch014dc512016-03-22 12:00:34 +0000361
Ben Murdochf91f0612016-11-29 16:50:11 +0000362// A simple forward iterator for bytecodes.
363class BytecodeIterator : public Decoder {
364 public:
365 // If one wants to iterate over the bytecode without looking at {pc_offset()}.
366 class iterator {
367 public:
368 inline iterator& operator++() {
369 DCHECK_LT(ptr_, end_);
370 ptr_ += OpcodeLength(ptr_, end_);
371 return *this;
372 }
373 inline WasmOpcode operator*() {
374 DCHECK_LT(ptr_, end_);
375 return static_cast<WasmOpcode>(*ptr_);
376 }
377 inline bool operator==(const iterator& that) {
378 return this->ptr_ == that.ptr_;
379 }
380 inline bool operator!=(const iterator& that) {
381 return this->ptr_ != that.ptr_;
382 }
383
384 private:
385 friend class BytecodeIterator;
386 const byte* ptr_;
387 const byte* end_;
388 iterator(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
389 };
390
391 // Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
392 // assume the bytecode starts with local declarations and decode them.
393 // Otherwise, do not decode local decls.
394 BytecodeIterator(const byte* start, const byte* end,
395 AstLocalDecls* decls = nullptr);
396
397 inline iterator begin() const { return iterator(pc_, end_); }
398 inline iterator end() const { return iterator(end_, end_); }
399
400 WasmOpcode current() {
401 return static_cast<WasmOpcode>(
402 checked_read_u8(pc_, 0, "expected bytecode"));
403 }
404
405 void next() {
406 if (pc_ < end_) {
407 pc_ += OpcodeLength(pc_, end_);
408 if (pc_ >= end_) pc_ = end_;
409 }
410 }
411
412 bool has_next() { return pc_ < end_; }
413};
414
Ben Murdoch014dc512016-03-22 12:00:34 +0000415} // namespace wasm
416} // namespace internal
417} // namespace v8
418
419#endif // V8_WASM_AST_DECODER_H_