Line data Source code
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 :
40 : static inline FunctionBody FunctionBodyForTesting(const byte* start,
41 : const byte* end) {
42 0 : 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 :
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 :
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 24193 : 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 178 : explicit BodyLocalDecls(Zone* zone) : encoded_size(0), type_list(zone) {}
85 : };
86 :
87 : V8_EXPORT_PRIVATE bool DecodeLocalDecls(BodyLocalDecls* decls,
88 : const byte* start, const byte* end);
89 :
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 : // Computes the stack effect of the opcode at the given address.
99 : // Returns <pop count, push count>.
100 : // Be cautious with control opcodes: This function only covers their immediate,
101 : // local stack effect (e.g. BrIf pops 1, Br pops 0). Those opcodes can have
102 : // non-local stack effect though, which are not covered here.
103 : std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
104 : FunctionSig* sig, const byte* pc,
105 : const byte* end);
106 :
107 : // A simple forward iterator for bytecodes.
108 21492 : class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
109 : // Base class for both iterators defined below.
110 : class iterator_base {
111 : public:
112 : inline iterator_base& operator++() {
113 : DCHECK_LT(ptr_, end_);
114 313 : ptr_ += OpcodeLength(ptr_, end_);
115 : return *this;
116 : }
117 : inline bool operator==(const iterator_base& that) {
118 : return this->ptr_ == that.ptr_;
119 : }
120 : inline bool operator!=(const iterator_base& that) {
121 : return this->ptr_ != that.ptr_;
122 : }
123 :
124 : protected:
125 : const byte* ptr_;
126 : const byte* end_;
127 : iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
128 : };
129 :
130 : public:
131 : // If one wants to iterate over the bytecode without looking at {pc_offset()}.
132 : class opcode_iterator
133 : : public iterator_base,
134 : public std::iterator<std::input_iterator_tag, WasmOpcode> {
135 : public:
136 : inline WasmOpcode operator*() {
137 : DCHECK_LT(ptr_, end_);
138 : return static_cast<WasmOpcode>(*ptr_);
139 : }
140 :
141 : private:
142 : friend class BytecodeIterator;
143 : opcode_iterator(const byte* ptr, const byte* end)
144 : : iterator_base(ptr, end) {}
145 : };
146 : // If one wants to iterate over the instruction offsets without looking at
147 : // opcodes.
148 : class offset_iterator
149 : : public iterator_base,
150 : public std::iterator<std::input_iterator_tag, uint32_t> {
151 : public:
152 : inline uint32_t operator*() {
153 : DCHECK_LT(ptr_, end_);
154 345 : return static_cast<uint32_t>(ptr_ - start_);
155 : }
156 :
157 : private:
158 : const byte* start_;
159 : friend class BytecodeIterator;
160 : offset_iterator(const byte* start, const byte* ptr, const byte* end)
161 : : iterator_base(ptr, end), start_(start) {}
162 : };
163 :
164 : // Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
165 : // assume the bytecode starts with local declarations and decode them.
166 : // Otherwise, do not decode local decls.
167 : BytecodeIterator(const byte* start, const byte* end,
168 : BodyLocalDecls* decls = nullptr);
169 :
170 : base::iterator_range<opcode_iterator> opcodes() {
171 : return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_),
172 : opcode_iterator(end_, end_));
173 : }
174 :
175 : base::iterator_range<offset_iterator> offsets() {
176 : return base::iterator_range<offset_iterator>(
177 : offset_iterator(start_, pc_, end_),
178 78 : offset_iterator(start_, end_, end_));
179 : }
180 :
181 : WasmOpcode current() {
182 236971 : return static_cast<WasmOpcode>(read_u8<false>(pc_, "expected bytecode"));
183 : }
184 :
185 236971 : void next() {
186 236971 : if (pc_ < end_) {
187 236971 : pc_ += OpcodeLength(pc_, end_);
188 236971 : if (pc_ >= end_) pc_ = end_;
189 : }
190 236971 : }
191 :
192 : bool has_next() { return pc_ < end_; }
193 : };
194 :
195 : } // namespace wasm
196 : } // namespace internal
197 : } // namespace v8
198 :
199 : #endif // V8_WASM_FUNCTION_BODY_DECODER_H_
|