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