function-body-decoder.h 6.59 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif  // !V8_ENABLE_WEBASSEMBLY

9 10
#ifndef V8_WASM_FUNCTION_BODY_DECODER_H_
#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 17
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"
18
#include "src/zone/zone-containers.h"
19 20 21 22

namespace v8 {
namespace internal {

23
class AccountingAllocator;
24 25
class BitVector;  // forward declaration

26 27
namespace wasm {

28
class WasmFeatures;
29
struct WasmModule;  // forward declaration of module interface.
30

31
// A wrapper around the signature and bytes of a function.
32
struct FunctionBody {
33 34 35 36
  const FunctionSig* sig;  // function signature
  uint32_t offset;         // offset in the module bytes, for error reporting
  const byte* start;       // start of the function body
  const byte* end;         // end of the function body
37

38
  FunctionBody(const FunctionSig* sig, uint32_t offset, const byte* start,
39 40 41
               const byte* end)
      : sig(sig), offset(offset), start(start), end(end) {}
};
42

43
enum class LoadTransformationKind : uint8_t { kSplat, kExtend, kZeroExtend };
44

45 46 47 48 49
V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
                                              const WasmFeatures& enabled,
                                              const WasmModule* module,
                                              WasmFeatures* detected,
                                              const FunctionBody& body);
50

51 52
enum PrintLocals { kPrintLocals, kOmitLocals };
V8_EXPORT_PRIVATE
53
bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
54
                      const WasmModule* module, PrintLocals print_locals);
55

56 57
V8_EXPORT_PRIVATE
bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
58
                      const WasmModule* module, PrintLocals print_locals,
59 60
                      std::ostream& out,
                      std::vector<int>* line_numbers = nullptr);
61

62
// A simplified form of AST printing, e.g. from a debugger.
63
void PrintRawWasmCode(const byte* start, const byte* end);
64

65
struct BodyLocalDecls {
66
  // The size of the encoded declarations.
67
  uint32_t encoded_size = 0;  // size of encoded declarations
68

69
  ZoneVector<ValueType> type_list;
70

71
  explicit BodyLocalDecls(Zone* zone) : type_list(zone) {}
72 73
};

74 75
V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled,
                                        BodyLocalDecls* decls,
76
                                        const WasmModule* module,
77
                                        const byte* start, const byte* end);
78

79 80
V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(
    Zone* zone, uint32_t num_locals, const byte* start, const byte* end);
81

82
// Computes the length of the opcode at the given address.
83
V8_EXPORT_PRIVATE unsigned OpcodeLength(const byte* pc, const byte* end);
84

85 86 87 88 89
// Computes the stack effect of the opcode at the given address.
// Returns <pop count, push count>.
// Be cautious with control opcodes: This function only covers their immediate,
// local stack effect (e.g. BrIf pops 1, Br pops 0). Those opcodes can have
// non-local stack effect though, which are not covered here.
90 91 92 93
// TODO(clemensb): This is only used by the interpreter; move there.
V8_EXPORT_PRIVATE std::pair<uint32_t, uint32_t> StackEffect(
    const WasmModule* module, const FunctionSig* sig, const byte* pc,
    const byte* end);
94

95 96 97
// Checks if the underlying hardware supports the Wasm SIMD proposal.
V8_EXPORT_PRIVATE bool CheckHardwareSupportsSimd();

98
// A simple forward iterator for bytecodes.
99
class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
100 101
  // Base class for both iterators defined below.
  class iterator_base {
102
   public:
103
    iterator_base& operator++() {
104 105 106 107
      DCHECK_LT(ptr_, end_);
      ptr_ += OpcodeLength(ptr_, end_);
      return *this;
    }
108
    bool operator==(const iterator_base& that) const {
109 110
      return this->ptr_ == that.ptr_;
    }
111
    bool operator!=(const iterator_base& that) const {
112 113 114 115 116 117 118 119 120 121 122 123 124
      return this->ptr_ != that.ptr_;
    }

   protected:
    const byte* ptr_;
    const byte* end_;
    iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
  };

 public:
  // If one wants to iterate over the bytecode without looking at {pc_offset()}.
  class opcode_iterator
      : public iterator_base,
125
        public base::iterator<std::input_iterator_tag, WasmOpcode> {
126
   public:
127
    WasmOpcode operator*() {
128 129 130
      DCHECK_LT(ptr_, end_);
      return static_cast<WasmOpcode>(*ptr_);
    }
131 132 133 134 135 136 137 138 139 140

   private:
    friend class BytecodeIterator;
    opcode_iterator(const byte* ptr, const byte* end)
        : iterator_base(ptr, end) {}
  };
  // If one wants to iterate over the instruction offsets without looking at
  // opcodes.
  class offset_iterator
      : public iterator_base,
141
        public base::iterator<std::input_iterator_tag, uint32_t> {
142
   public:
143
    uint32_t operator*() {
144 145
      DCHECK_LT(ptr_, end_);
      return static_cast<uint32_t>(ptr_ - start_);
146 147 148
    }

   private:
149
    const byte* start_;
150
    friend class BytecodeIterator;
151 152
    offset_iterator(const byte* start, const byte* ptr, const byte* end)
        : iterator_base(ptr, end), start_(start) {}
153 154 155 156 157 158
  };

  // Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
  // assume the bytecode starts with local declarations and decode them.
  // Otherwise, do not decode local decls.
  BytecodeIterator(const byte* start, const byte* end,
159
                   BodyLocalDecls* decls = nullptr);
160

161 162 163 164 165 166 167 168 169 170
  base::iterator_range<opcode_iterator> opcodes() {
    return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_),
                                                 opcode_iterator(end_, end_));
  }

  base::iterator_range<offset_iterator> offsets() {
    return base::iterator_range<offset_iterator>(
        offset_iterator(start_, pc_, end_),
        offset_iterator(start_, end_, end_));
  }
171 172

  WasmOpcode current() {
173
    return static_cast<WasmOpcode>(
174
        read_u8<Decoder::kNoValidation>(pc_, "expected bytecode"));
175 176 177 178 179 180 181 182 183 184
  }

  void next() {
    if (pc_ < end_) {
      pc_ += OpcodeLength(pc_, end_);
      if (pc_ >= end_) pc_ = end_;
    }
  }

  bool has_next() { return pc_ < end_; }
185 186

  WasmOpcode prefixed_opcode() {
187
    return read_prefixed_opcode<Decoder::kNoValidation>(pc_);
188
  }
189 190
};

191 192 193 194
}  // namespace wasm
}  // namespace internal
}  // namespace v8

195
#endif  // V8_WASM_FUNCTION_BODY_DECODER_H_