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 "src/base/compiler-specific.h" 9 #include "src/base/iterator.h" 10 #include "src/globals.h" 11 #include "src/signature.h" 12 #include "src/wasm/decoder.h" 13 #include "src/wasm/wasm-opcodes.h" 14 #include "src/wasm/wasm-result.h" 15 16 namespace v8 { 17 namespace internal { 18 19 class BitVector; // forward declaration 20 21 namespace compiler { // external declarations from compiler. 22 class NodeOriginTable; 23 class WasmGraphBuilder; 24 } 25 26 namespace wasm { 27 28 struct WasmModule; // forward declaration of module interface. 29 struct WasmFeatures; 30 31 typedef compiler::WasmGraphBuilder TFBuilder; 32 33 // A wrapper around the signature and bytes of a function. 34 struct FunctionBody { 35 FunctionSig* sig; // function signature 36 uint32_t offset; // offset in the module bytes, for error reporting 37 const byte* start; // start of the function body 38 const byte* end; // end of the function body 39 40 FunctionBody(FunctionSig* sig, uint32_t offset, const byte* start, 41 const byte* end) 42 : sig(sig), offset(offset), start(start), end(end) {} 43 }; 44 45 V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator, 46 const WasmFeatures& enabled, 47 const WasmModule* module, 48 WasmFeatures* detected, 49 FunctionBody& body); 50 51 DecodeResult BuildTFGraph(AccountingAllocator* allocator, 52 const WasmFeatures& enabled, const WasmModule* module, 53 TFBuilder* builder, WasmFeatures* detected, 54 FunctionBody& body, 55 compiler::NodeOriginTable* node_origins); 56 enum PrintLocals { kPrintLocals, kOmitLocals }; 57 V8_EXPORT_PRIVATE 58 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, 59 const WasmModule* module, PrintLocals print_locals); 60 61 V8_EXPORT_PRIVATE 62 bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, 63 const WasmModule* module, PrintLocals print_locals, 64 std::ostream& out, 65 std::vector<int>* line_numbers = nullptr); 66 67 // A simplified form of AST printing, e.g. from a debugger. 68 void PrintRawWasmCode(const byte* start, const byte* end); 69 70 struct BodyLocalDecls { 71 // The size of the encoded declarations. 72 uint32_t encoded_size = 0; // size of encoded declarations 73 74 ZoneVector<ValueType> type_list; 75 76 explicit BodyLocalDecls(Zone* zone) : type_list(zone) {} 77 }; 78 79 V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled, 80 BodyLocalDecls* decls, 81 const byte* start, const byte* end); 82 83 V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, 84 size_t num_locals, 85 const byte* start, 86 const byte* end); 87 88 // Computes the length of the opcode at the given address. 89 V8_EXPORT_PRIVATE unsigned OpcodeLength(const byte* pc, const byte* end); 90 91 // Computes the stack effect of the opcode at the given address. 92 // Returns <pop count, push count>. 93 // Be cautious with control opcodes: This function only covers their immediate, 94 // local stack effect (e.g. BrIf pops 1, Br pops 0). Those opcodes can have 95 // non-local stack effect though, which are not covered here. 96 std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module, 97 FunctionSig* sig, const byte* pc, 98 const byte* end); 99 100 // A simple forward iterator for bytecodes. 101 class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) { 102 // Base class for both iterators defined below. 103 class iterator_base { 104 public: 105 inline iterator_base& operator++() { 106 DCHECK_LT(ptr_, end_); 107 ptr_ += OpcodeLength(ptr_, end_); 108 return *this; 109 } 110 inline bool operator==(const iterator_base& that) { 111 return this->ptr_ == that.ptr_; 112 } 113 inline bool operator!=(const iterator_base& that) { 114 return this->ptr_ != that.ptr_; 115 } 116 117 protected: 118 const byte* ptr_; 119 const byte* end_; 120 iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {} 121 }; 122 123 public: 124 // If one wants to iterate over the bytecode without looking at {pc_offset()}. 125 class opcode_iterator 126 : public iterator_base, 127 public base::iterator<std::input_iterator_tag, WasmOpcode> { 128 public: 129 inline WasmOpcode operator*() { 130 DCHECK_LT(ptr_, end_); 131 return static_cast<WasmOpcode>(*ptr_); 132 } 133 134 private: 135 friend class BytecodeIterator; 136 opcode_iterator(const byte* ptr, const byte* end) 137 : iterator_base(ptr, end) {} 138 }; 139 // If one wants to iterate over the instruction offsets without looking at 140 // opcodes. 141 class offset_iterator 142 : public iterator_base, 143 public base::iterator<std::input_iterator_tag, uint32_t> { 144 public: 145 inline uint32_t operator*() { 146 DCHECK_LT(ptr_, end_); 147 return static_cast<uint32_t>(ptr_ - start_); 148 } 149 150 private: 151 const byte* start_; 152 friend class BytecodeIterator; 153 offset_iterator(const byte* start, const byte* ptr, const byte* end) 154 : iterator_base(ptr, end), start_(start) {} 155 }; 156 157 // Create a new {BytecodeIterator}. If the {decls} pointer is non-null, 158 // assume the bytecode starts with local declarations and decode them. 159 // Otherwise, do not decode local decls. 160 BytecodeIterator(const byte* start, const byte* end, 161 BodyLocalDecls* decls = nullptr); 162 163 base::iterator_range<opcode_iterator> opcodes() { 164 return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_), 165 opcode_iterator(end_, end_)); 166 } 167 168 base::iterator_range<offset_iterator> offsets() { 169 return base::iterator_range<offset_iterator>( 170 offset_iterator(start_, pc_, end_), 171 offset_iterator(start_, end_, end_)); 172 } 173 174 WasmOpcode current() { 175 return static_cast<WasmOpcode>( 176 read_u8<Decoder::kNoValidate>(pc_, "expected bytecode")); 177 } 178 179 void next() { 180 if (pc_ < end_) { 181 pc_ += OpcodeLength(pc_, end_); 182 if (pc_ >= end_) pc_ = end_; 183 } 184 } 185 186 bool has_next() { return pc_ < end_; } 187 188 WasmOpcode prefixed_opcode() { 189 byte prefix = read_u8<Decoder::kNoValidate>(pc_, "expected prefix"); 190 byte index = read_u8<Decoder::kNoValidate>(pc_ + 1, "expected index"); 191 return static_cast<WasmOpcode>(prefix << 8 | index); 192 } 193 }; 194 195 } // namespace wasm 196 } // namespace internal 197 } // namespace v8 198 199 #endif // V8_WASM_FUNCTION_BODY_DECODER_H_ 200