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
FunctionBodyForTesting(const byte * start,const byte * end)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
VerifyWasmCode(AccountingAllocator * allocator,const WasmModule * module,FunctionSig * sig,const byte * start,const byte * end)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
BuildTFGraph(AccountingAllocator * allocator,TFBuilder * builder,FunctionSig * sig,const byte * start,const byte * end)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.
BodyLocalDeclsBodyLocalDecls85 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.
NON_EXPORTED_BASE(Decoder)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