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