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
19namespace v8 {
20namespace internal {
21
22class BitVector;  // forward declaration
23
24namespace wasm {
25
26class WasmFeatures;
27struct WasmModule;  // forward declaration of module interface.
28
29// A wrapper around the signature and bytes of a function.
30struct 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
36  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
41enum class LoadTransformationKind : uint8_t { kSplat, kExtend, kZeroExtend };
42
43V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
44                                              const WasmFeatures& enabled,
45                                              const WasmModule* module,
46                                              WasmFeatures* detected,
47                                              const FunctionBody& body);
48
49enum PrintLocals { kPrintLocals, kOmitLocals };
50V8_EXPORT_PRIVATE
51bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
52                      const WasmModule* module, PrintLocals print_locals);
53
54V8_EXPORT_PRIVATE
55bool 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.
61void PrintRawWasmCode(const byte* start, const byte* end);
62
63struct 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
69  explicit BodyLocalDecls(Zone* zone) : type_list(zone) {}
70};
71
72V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled,
73                                        BodyLocalDecls* decls,
74                                        const WasmModule* module,
75                                        const byte* start, const byte* end);
76
77V8_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.
81V8_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.
89V8_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.
94V8_EXPORT_PRIVATE bool CheckHardwareSupportsSimd();
95
96// A simple forward iterator for bytecodes.
97class 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