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
FunctionBodyFunctionBody40 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
BodyLocalDeclsBodyLocalDecls76 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.
NON_EXPORTED_BASE(Decoder)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