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 "src/signature.h"
9 #include "src/wasm/decoder.h"
10 #include "src/wasm/wasm-opcodes.h"
11 #include "src/wasm/wasm-result.h"
12
13 namespace v8 {
14 namespace internal {
15
16 class BitVector; // forward declaration
17
18 namespace compiler { // external declarations from compiler.
19 class WasmGraphBuilder;
20 }
21
22 namespace wasm {
23
24 // Helpers for decoding different kinds of operands which follow bytecodes.
25 struct LocalIndexOperand {
26 uint32_t index;
27 LocalType type;
28 unsigned length;
29
LocalIndexOperandLocalIndexOperand30 inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
31 index = decoder->checked_read_u32v(pc, 1, &length, "local index");
32 type = kAstStmt;
33 }
34 };
35
36 struct ImmI8Operand {
37 int8_t value;
38 unsigned length;
ImmI8OperandImmI8Operand39 inline ImmI8Operand(Decoder* decoder, const byte* pc) {
40 value = bit_cast<int8_t>(decoder->checked_read_u8(pc, 1, "immi8"));
41 length = 1;
42 }
43 };
44
45 struct ImmI32Operand {
46 int32_t value;
47 unsigned length;
ImmI32OperandImmI32Operand48 inline ImmI32Operand(Decoder* decoder, const byte* pc) {
49 value = decoder->checked_read_i32v(pc, 1, &length, "immi32");
50 }
51 };
52
53 struct ImmI64Operand {
54 int64_t value;
55 unsigned length;
ImmI64OperandImmI64Operand56 inline ImmI64Operand(Decoder* decoder, const byte* pc) {
57 value = decoder->checked_read_i64v(pc, 1, &length, "immi64");
58 }
59 };
60
61 struct ImmF32Operand {
62 float value;
63 unsigned length;
ImmF32OperandImmF32Operand64 inline ImmF32Operand(Decoder* decoder, const byte* pc) {
65 value = bit_cast<float>(decoder->checked_read_u32(pc, 1, "immf32"));
66 length = 4;
67 }
68 };
69
70 struct ImmF64Operand {
71 double value;
72 unsigned length;
ImmF64OperandImmF64Operand73 inline ImmF64Operand(Decoder* decoder, const byte* pc) {
74 value = bit_cast<double>(decoder->checked_read_u64(pc, 1, "immf64"));
75 length = 8;
76 }
77 };
78
79 struct GlobalIndexOperand {
80 uint32_t index;
81 LocalType type;
82 MachineType machine_type;
83 unsigned length;
84
GlobalIndexOperandGlobalIndexOperand85 inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
86 index = decoder->checked_read_u32v(pc, 1, &length, "global index");
87 type = kAstStmt;
88 machine_type = MachineType::None();
89 }
90 };
91
92 struct Control;
93 struct BreakDepthOperand {
94 uint32_t arity;
95 uint32_t depth;
96 Control* target;
97 unsigned length;
BreakDepthOperandBreakDepthOperand98 inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
99 unsigned len1 = 0;
100 unsigned len2 = 0;
101 arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
102 depth = decoder->checked_read_u32v(pc, 1 + len1, &len2, "break depth");
103 length = len1 + len2;
104 target = nullptr;
105 }
106 };
107
108 struct CallIndirectOperand {
109 uint32_t arity;
110 uint32_t index;
111 FunctionSig* sig;
112 unsigned length;
CallIndirectOperandCallIndirectOperand113 inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
114 unsigned len1 = 0;
115 unsigned len2 = 0;
116 arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
117 index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "signature index");
118 length = len1 + len2;
119 sig = nullptr;
120 }
121 };
122
123 struct CallFunctionOperand {
124 uint32_t arity;
125 uint32_t index;
126 FunctionSig* sig;
127 unsigned length;
CallFunctionOperandCallFunctionOperand128 inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
129 unsigned len1 = 0;
130 unsigned len2 = 0;
131 arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
132 index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index");
133 length = len1 + len2;
134 sig = nullptr;
135 }
136 };
137
138 struct CallImportOperand {
139 uint32_t arity;
140 uint32_t index;
141 FunctionSig* sig;
142 unsigned length;
CallImportOperandCallImportOperand143 inline CallImportOperand(Decoder* decoder, const byte* pc) {
144 unsigned len1 = 0;
145 unsigned len2 = 0;
146 arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
147 index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "import index");
148 length = len1 + len2;
149 sig = nullptr;
150 }
151 };
152
153 struct BranchTableOperand {
154 uint32_t arity;
155 uint32_t table_count;
156 const byte* table;
157 unsigned length;
BranchTableOperandBranchTableOperand158 inline BranchTableOperand(Decoder* decoder, const byte* pc) {
159 unsigned len1 = 0;
160 unsigned len2 = 0;
161 arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
162 table_count =
163 decoder->checked_read_u32v(pc, 1 + len1, &len2, "table count");
164 if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 ||
165 len1 + len2 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
166 decoder->error(pc, "branch table size overflow");
167 }
168 length = len1 + len2 + (table_count + 1) * sizeof(uint32_t);
169
170 uint32_t table_start = 1 + len1 + len2;
171 if (decoder->check(pc, table_start, (table_count + 1) * sizeof(uint32_t),
172 "expected <table entries>")) {
173 table = pc + table_start;
174 } else {
175 table = nullptr;
176 }
177 }
read_entryBranchTableOperand178 inline uint32_t read_entry(Decoder* decoder, unsigned i) {
179 DCHECK(i <= table_count);
180 return table ? decoder->read_u32(table + i * sizeof(uint32_t)) : 0;
181 }
182 };
183
184 struct MemoryAccessOperand {
185 uint32_t alignment;
186 uint32_t offset;
187 unsigned length;
MemoryAccessOperandMemoryAccessOperand188 inline MemoryAccessOperand(Decoder* decoder, const byte* pc) {
189 unsigned alignment_length;
190 alignment =
191 decoder->checked_read_u32v(pc, 1, &alignment_length, "alignment");
192 unsigned offset_length;
193 offset = decoder->checked_read_u32v(pc, 1 + alignment_length,
194 &offset_length, "offset");
195 length = alignment_length + offset_length;
196 }
197 };
198
199 struct ReturnArityOperand {
200 uint32_t arity;
201 unsigned length;
202
ReturnArityOperandReturnArityOperand203 inline ReturnArityOperand(Decoder* decoder, const byte* pc) {
204 arity = decoder->checked_read_u32v(pc, 1, &length, "return count");
205 }
206 };
207
208 typedef compiler::WasmGraphBuilder TFBuilder;
209 struct ModuleEnv; // forward declaration of module interface.
210
211 // All of the various data structures necessary to decode a function body.
212 struct FunctionBody {
213 ModuleEnv* module; // module environment
214 FunctionSig* sig; // function signature
215 const byte* base; // base of the module bytes, for error reporting
216 const byte* start; // start of the function body
217 const byte* end; // end of the function body
218 };
219
FunctionBodyForTesting(const byte * start,const byte * end)220 static inline FunctionBody FunctionBodyForTesting(const byte* start,
221 const byte* end) {
222 return {nullptr, nullptr, start, start, end};
223 }
224
225 struct Tree;
226 typedef Result<Tree*> TreeResult;
227
228 std::ostream& operator<<(std::ostream& os, const Tree& tree);
229
230 TreeResult VerifyWasmCode(base::AccountingAllocator* allocator,
231 FunctionBody& body);
232 TreeResult BuildTFGraph(base::AccountingAllocator* allocator,
233 TFBuilder* builder, FunctionBody& body);
234 bool PrintAst(base::AccountingAllocator* allocator, const FunctionBody& body,
235 std::ostream& os,
236 std::vector<std::tuple<uint32_t, int, int>>* offset_table);
237
238 // A simplified form of AST printing, e.g. from a debugger.
239 void PrintAstForDebugging(const byte* start, const byte* end);
240
VerifyWasmCode(base::AccountingAllocator * allocator,ModuleEnv * module,FunctionSig * sig,const byte * start,const byte * end)241 inline TreeResult VerifyWasmCode(base::AccountingAllocator* allocator,
242 ModuleEnv* module, FunctionSig* sig,
243 const byte* start, const byte* end) {
244 FunctionBody body = {module, sig, nullptr, start, end};
245 return VerifyWasmCode(allocator, body);
246 }
247
BuildTFGraph(base::AccountingAllocator * allocator,TFBuilder * builder,ModuleEnv * module,FunctionSig * sig,const byte * start,const byte * end)248 inline TreeResult BuildTFGraph(base::AccountingAllocator* allocator,
249 TFBuilder* builder, ModuleEnv* module,
250 FunctionSig* sig, const byte* start,
251 const byte* end) {
252 FunctionBody body = {module, sig, nullptr, start, end};
253 return BuildTFGraph(allocator, builder, body);
254 }
255
256 struct AstLocalDecls {
257 // The size of the encoded declarations.
258 uint32_t decls_encoded_size; // size of encoded declarations
259
260 // Total number of locals.
261 uint32_t total_local_count;
262
263 // List of {local type, count} pairs.
264 ZoneVector<std::pair<LocalType, uint32_t>> local_types;
265
266 // Constructor initializes the vector.
AstLocalDeclsAstLocalDecls267 explicit AstLocalDecls(Zone* zone)
268 : decls_encoded_size(0), total_local_count(0), local_types(zone) {}
269 };
270
271 bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, const byte* end);
272 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
273 const byte* start, const byte* end);
274
275 // Computes the length of the opcode at the given address.
276 unsigned OpcodeLength(const byte* pc, const byte* end);
277
278 // Computes the arity (number of sub-nodes) of the opcode at the given address.
279 unsigned OpcodeArity(const byte* pc, const byte* end);
280
281 } // namespace wasm
282 } // namespace internal
283 } // namespace v8
284
285 #endif // V8_WASM_AST_DECODER_H_
286