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 "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 : class Counters;
21 :
22 : namespace compiler { // external declarations from compiler.
23 : class WasmGraphBuilder;
24 : }
25 :
26 : namespace wasm {
27 :
28 : typedef compiler::WasmGraphBuilder TFBuilder;
29 : struct WasmModule; // forward declaration of module interface.
30 :
31 : // A wrapper around the signature and bytes of a function.
32 : struct FunctionBody {
33 : FunctionSig* sig; // function signature
34 : uint32_t offset; // offset in the module bytes, for error reporting
35 : const byte* start; // start of the function body
36 : const byte* end; // end of the function body
37 : };
38 :
39 : static inline FunctionBody FunctionBodyForTesting(const byte* start,
40 : const byte* end) {
41 0 : return {nullptr, 0, start, end};
42 : }
43 :
44 : V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
45 : const wasm::WasmModule* module,
46 : FunctionBody& body);
47 :
48 : // Note: If run in the background thread, must follow protocol using
49 : // isolate::async_counters() to guarantee usability of counters argument.
50 : DecodeResult VerifyWasmCodeWithStats(AccountingAllocator* allocator,
51 : const wasm::WasmModule* module,
52 : FunctionBody& body, bool is_wasm,
53 : Counters* counters);
54 :
55 : DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
56 : FunctionBody& body);
57 : bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
58 : const wasm::WasmModule* module);
59 :
60 : // A simplified form of AST printing, e.g. from a debugger.
61 : void PrintRawWasmCode(const byte* start, const byte* end);
62 :
63 13697 : inline DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
64 : const WasmModule* module, FunctionSig* sig,
65 : const byte* start, const byte* end) {
66 13697 : FunctionBody body = {sig, 0, start, end};
67 27394 : return VerifyWasmCode(allocator, module, body);
68 : }
69 :
70 738 : inline DecodeResult BuildTFGraph(AccountingAllocator* allocator,
71 : TFBuilder* builder, FunctionSig* sig,
72 : const byte* start, const byte* end) {
73 738 : FunctionBody body = {sig, 0, start, end};
74 1476 : return BuildTFGraph(allocator, builder, body);
75 : }
76 :
77 29593 : struct BodyLocalDecls {
78 : // The size of the encoded declarations.
79 : uint32_t encoded_size; // size of encoded declarations
80 :
81 : ZoneVector<ValueType> type_list;
82 :
83 248 : explicit BodyLocalDecls(Zone* zone) : encoded_size(0), type_list(zone) {}
84 : };
85 :
86 : V8_EXPORT_PRIVATE bool DecodeLocalDecls(BodyLocalDecls* decls,
87 : const byte* start, const byte* end);
88 :
89 : V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone,
90 : size_t num_locals,
91 : const byte* start,
92 : const byte* end);
93 :
94 : // Computes the length of the opcode at the given address.
95 : V8_EXPORT_PRIVATE unsigned OpcodeLength(const byte* pc, const byte* end);
96 :
97 : // Computes the stack effect of the opcode at the given address.
98 : // Returns <pop count, push count>.
99 : // Be cautious with control opcodes: This function only covers their immediate,
100 : // local stack effect (e.g. BrIf pops 1, Br pops 0). Those opcodes can have
101 : // non-local stack effect though, which are not covered here.
102 : std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
103 : FunctionSig* sig, const byte* pc,
104 : const byte* end);
105 :
106 : // A simple forward iterator for bytecodes.
107 20432 : class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
108 : // Base class for both iterators defined below.
109 : class iterator_base {
110 : public:
111 : inline iterator_base& operator++() {
112 : DCHECK_LT(ptr_, end_);
113 295 : ptr_ += OpcodeLength(ptr_, end_);
114 : return *this;
115 : }
116 : inline bool operator==(const iterator_base& that) {
117 : return this->ptr_ == that.ptr_;
118 : }
119 : inline bool operator!=(const iterator_base& that) {
120 : return this->ptr_ != that.ptr_;
121 : }
122 :
123 : protected:
124 : const byte* ptr_;
125 : const byte* end_;
126 : iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
127 : };
128 :
129 : public:
130 : // If one wants to iterate over the bytecode without looking at {pc_offset()}.
131 : class opcode_iterator
132 : : public iterator_base,
133 : public base::iterator<std::input_iterator_tag, WasmOpcode> {
134 : public:
135 : inline WasmOpcode operator*() {
136 : DCHECK_LT(ptr_, end_);
137 6 : return static_cast<WasmOpcode>(*ptr_);
138 : }
139 :
140 : private:
141 : friend class BytecodeIterator;
142 : opcode_iterator(const byte* ptr, const byte* end)
143 : : iterator_base(ptr, end) {}
144 : };
145 : // If one wants to iterate over the instruction offsets without looking at
146 : // opcodes.
147 : class offset_iterator
148 : : public iterator_base,
149 : public base::iterator<std::input_iterator_tag, uint32_t> {
150 : public:
151 : inline uint32_t operator*() {
152 : DCHECK_LT(ptr_, end_);
153 292 : return static_cast<uint32_t>(ptr_ - start_);
154 : }
155 :
156 : private:
157 : const byte* start_;
158 : friend class BytecodeIterator;
159 : offset_iterator(const byte* start, const byte* ptr, const byte* end)
160 : : iterator_base(ptr, end), start_(start) {}
161 : };
162 :
163 : // Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
164 : // assume the bytecode starts with local declarations and decode them.
165 : // Otherwise, do not decode local decls.
166 : BytecodeIterator(const byte* start, const byte* end,
167 : BodyLocalDecls* decls = nullptr);
168 :
169 : base::iterator_range<opcode_iterator> opcodes() {
170 : return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_),
171 : opcode_iterator(end_, end_));
172 : }
173 :
174 : base::iterator_range<offset_iterator> offsets() {
175 : return base::iterator_range<offset_iterator>(
176 : offset_iterator(start_, pc_, end_),
177 68 : offset_iterator(start_, end_, end_));
178 : }
179 :
180 : WasmOpcode current() {
181 : return static_cast<WasmOpcode>(
182 213699 : read_u8<Decoder::kNoValidate>(pc_, "expected bytecode"));
183 : }
184 :
185 213699 : void next() {
186 213699 : if (pc_ < end_) {
187 213699 : pc_ += OpcodeLength(pc_, end_);
188 213699 : if (pc_ >= end_) pc_ = end_;
189 : }
190 213699 : }
191 :
192 2 : bool has_next() { return pc_ < end_; }
193 :
194 : WasmOpcode prefixed_opcode() {
195 12 : byte prefix = read_u8<Decoder::kNoValidate>(pc_, "expected prefix");
196 12 : byte index = read_u8<Decoder::kNoValidate>(pc_ + 1, "expected index");
197 12 : return static_cast<WasmOpcode>(prefix << 8 | index);
198 : }
199 : };
200 :
201 : } // namespace wasm
202 : } // namespace internal
203 : } // namespace v8
204 :
205 : #endif // V8_WASM_FUNCTION_BODY_DECODER_H_
|