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