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_FUNCTION_BODY_DECODER_H_ 6 #define V8_WASM_FUNCTION_BODY_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 typedef compiler::WasmGraphBuilder TFBuilder; 30 struct WasmModule; // forward declaration of module interface. 31 32 // A wrapper around the signature and bytes of a function. 33 struct FunctionBody { 34 FunctionSig* sig; // function signature 35 const byte* base; // base of the module bytes, for error reporting 36 const byte* start; // start of the function body 37 const byte* end; // end of the function body 38 }; 39 40 static inline FunctionBody FunctionBodyForTesting(const byte* start, 41 const byte* end) { 42 return {nullptr, start, start, end}; 43 } 44 45 struct DecodeStruct { 46 int unused; 47 }; 48 typedef Result<DecodeStruct*> DecodeResult; 49 inline std::ostream& operator<<(std::ostream& os, const DecodeStruct& tree) { 50 return os; 51 } 52 53 V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator, 54 const wasm::WasmModule* module, 55 FunctionBody& body); 56 DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder, 57 FunctionBody& body); 58 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, 59 const wasm::WasmModule* module); 60 61 // A simplified form of AST printing, e.g. from a debugger. 62 void PrintRawWasmCode(const byte* start, const byte* end); 63 64 inline DecodeResult VerifyWasmCode(AccountingAllocator* allocator, 65 const WasmModule* module, FunctionSig* sig, 66 const byte* start, const byte* end) { 67 FunctionBody body = {sig, nullptr, start, end}; 68 return VerifyWasmCode(allocator, module, body); 69 } 70 71 inline DecodeResult BuildTFGraph(AccountingAllocator* allocator, 72 TFBuilder* builder, FunctionSig* sig, 73 const byte* start, const byte* end) { 74 FunctionBody body = {sig, nullptr, start, end}; 75 return BuildTFGraph(allocator, builder, body); 76 } 77 78 struct BodyLocalDecls { 79 // The size of the encoded declarations. 80 uint32_t encoded_size; // size of encoded declarations 81 82 ZoneVector<ValueType> type_list; 83 84 // Constructor initializes the vector. 85 explicit BodyLocalDecls(Zone* zone) : encoded_size(0), type_list(zone) {} 86 }; 87 88 V8_EXPORT_PRIVATE bool DecodeLocalDecls(BodyLocalDecls* decls, 89 const byte* start, const byte* end); 90 V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, 91 size_t num_locals, 92 const byte* start, 93 const byte* end); 94 95 // Computes the length of the opcode at the given address. 96 V8_EXPORT_PRIVATE unsigned OpcodeLength(const byte* pc, const byte* end); 97 98 // A simple forward iterator for bytecodes. 99 class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) { 100 // Base class for both iterators defined below. 101 class iterator_base { 102 public: 103 inline iterator_base& operator++() { 104 DCHECK_LT(ptr_, end_); 105 ptr_ += OpcodeLength(ptr_, end_); 106 return *this; 107 } 108 inline bool operator==(const iterator_base& that) { 109 return this->ptr_ == that.ptr_; 110 } 111 inline bool operator!=(const iterator_base& that) { 112 return this->ptr_ != that.ptr_; 113 } 114 115 protected: 116 const byte* ptr_; 117 const byte* end_; 118 iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {} 119 }; 120 121 public: 122 // If one wants to iterate over the bytecode without looking at {pc_offset()}. 123 class opcode_iterator 124 : public iterator_base, 125 public std::iterator<std::input_iterator_tag, WasmOpcode> { 126 public: 127 inline WasmOpcode operator*() { 128 DCHECK_LT(ptr_, end_); 129 return static_cast<WasmOpcode>(*ptr_); 130 } 131 132 private: 133 friend class BytecodeIterator; 134 opcode_iterator(const byte* ptr, const byte* end) 135 : iterator_base(ptr, end) {} 136 }; 137 // If one wants to iterate over the instruction offsets without looking at 138 // opcodes. 139 class offset_iterator 140 : public iterator_base, 141 public std::iterator<std::input_iterator_tag, uint32_t> { 142 public: 143 inline uint32_t operator*() { 144 DCHECK_LT(ptr_, end_); 145 return static_cast<uint32_t>(ptr_ - start_); 146 } 147 148 private: 149 const byte* start_; 150 friend class BytecodeIterator; 151 offset_iterator(const byte* start, const byte* ptr, const byte* end) 152 : iterator_base(ptr, end), start_(start) {} 153 }; 154 155 // Create a new {BytecodeIterator}. If the {decls} pointer is non-null, 156 // assume the bytecode starts with local declarations and decode them. 157 // Otherwise, do not decode local decls. 158 BytecodeIterator(const byte* start, const byte* end, 159 BodyLocalDecls* decls = nullptr); 160 161 base::iterator_range<opcode_iterator> opcodes() { 162 return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_), 163 opcode_iterator(end_, end_)); 164 } 165 166 base::iterator_range<offset_iterator> offsets() { 167 return base::iterator_range<offset_iterator>( 168 offset_iterator(start_, pc_, end_), 169 offset_iterator(start_, end_, end_)); 170 } 171 172 WasmOpcode current() { 173 return static_cast<WasmOpcode>( 174 checked_read_u8(pc_, 0, "expected bytecode")); 175 } 176 177 void next() { 178 if (pc_ < end_) { 179 pc_ += OpcodeLength(pc_, end_); 180 if (pc_ >= end_) pc_ = end_; 181 } 182 } 183 184 bool has_next() { return pc_ < end_; } 185 }; 186 187 } // namespace wasm 188 } // namespace internal 189 } // namespace v8 190 191 #endif // V8_WASM_FUNCTION_BODY_DECODER_H_ 192