ast-decoder.h 10 KB
Newer Older
1 2 3 4 5 6 7 8
// 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.

#ifndef V8_WASM_AST_DECODER_H_
#define V8_WASM_AST_DECODER_H_

#include "src/signature.h"
9
#include "src/wasm/decoder.h"
10 11 12 13 14 15
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"

namespace v8 {
namespace internal {

16 17
class BitVector;  // forward declaration

18 19 20 21 22 23
namespace compiler {  // external declarations from compiler.
class WasmGraphBuilder;
}

namespace wasm {

24 25
const uint32_t kMaxNumWasmLocals = 8000000;

26 27 28 29
// Helpers for decoding different kinds of operands which follow bytecodes.
struct LocalIndexOperand {
  uint32_t index;
  LocalType type;
30
  unsigned length;
31 32 33 34 35 36 37 38 39

  inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
    index = decoder->checked_read_u32v(pc, 1, &length, "local index");
    type = kAstStmt;
  }
};

struct ImmI8Operand {
  int8_t value;
40
  unsigned length;
41 42 43 44 45 46 47 48
  inline ImmI8Operand(Decoder* decoder, const byte* pc) {
    value = bit_cast<int8_t>(decoder->checked_read_u8(pc, 1, "immi8"));
    length = 1;
  }
};

struct ImmI32Operand {
  int32_t value;
49
  unsigned length;
50
  inline ImmI32Operand(Decoder* decoder, const byte* pc) {
51
    value = decoder->checked_read_i32v(pc, 1, &length, "immi32");
52 53 54 55 56
  }
};

struct ImmI64Operand {
  int64_t value;
57
  unsigned length;
58
  inline ImmI64Operand(Decoder* decoder, const byte* pc) {
59
    value = decoder->checked_read_i64v(pc, 1, &length, "immi64");
60 61 62 63 64
  }
};

struct ImmF32Operand {
  float value;
65
  unsigned length;
66 67 68 69 70 71 72 73
  inline ImmF32Operand(Decoder* decoder, const byte* pc) {
    value = bit_cast<float>(decoder->checked_read_u32(pc, 1, "immf32"));
    length = 4;
  }
};

struct ImmF64Operand {
  double value;
74
  unsigned length;
75 76 77 78 79 80 81 82 83
  inline ImmF64Operand(Decoder* decoder, const byte* pc) {
    value = bit_cast<double>(decoder->checked_read_u64(pc, 1, "immf64"));
    length = 8;
  }
};

struct GlobalIndexOperand {
  uint32_t index;
  LocalType type;
84
  unsigned length;
85 86 87 88 89 90 91

  inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
    index = decoder->checked_read_u32v(pc, 1, &length, "global index");
    type = kAstStmt;
  }
};

92
struct Control;
93
struct BreakDepthOperand {
94
  uint32_t arity;
95
  uint32_t depth;
96
  Control* target;
97
  unsigned length;
98
  inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
99 100
    unsigned len1 = 0;
    unsigned len2 = 0;
101 102 103
    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
    depth = decoder->checked_read_u32v(pc, 1 + len1, &len2, "break depth");
    length = len1 + len2;
104 105 106 107
    target = nullptr;
  }
};

108 109
struct CallIndirectOperand {
  uint32_t arity;
110 111
  uint32_t index;
  FunctionSig* sig;
112
  unsigned length;
113
  inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
114 115
    unsigned len1 = 0;
    unsigned len2 = 0;
116 117 118
    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
    index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "signature index");
    length = len1 + len2;
119 120 121 122
    sig = nullptr;
  }
};

123 124
struct CallFunctionOperand {
  uint32_t arity;
125 126
  uint32_t index;
  FunctionSig* sig;
127
  unsigned length;
128
  inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
129 130
    unsigned len1 = 0;
    unsigned len2 = 0;
131 132 133
    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
    index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index");
    length = len1 + len2;
134 135 136 137
    sig = nullptr;
  }
};

138 139
struct CallImportOperand {
  uint32_t arity;
140 141
  uint32_t index;
  FunctionSig* sig;
142
  unsigned length;
143
  inline CallImportOperand(Decoder* decoder, const byte* pc) {
144 145
    unsigned len1 = 0;
    unsigned len2 = 0;
146 147 148
    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
    index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "import index");
    length = len1 + len2;
149 150 151 152
    sig = nullptr;
  }
};

153
struct BranchTableOperand {
154
  uint32_t arity;
155 156
  uint32_t table_count;
  const byte* table;
157
  unsigned length;
158
  inline BranchTableOperand(Decoder* decoder, const byte* pc) {
159 160
    unsigned len1 = 0;
    unsigned len2 = 0;
161
    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
162
    table_count =
163
        decoder->checked_read_u32v(pc, 1 + len1, &len2, "table count");
164 165 166 167
    if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 ||
        len1 + len2 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
      decoder->error(pc, "branch table size overflow");
    }
168
    length = len1 + len2 + (table_count + 1) * sizeof(uint32_t);
169

170
    uint32_t table_start = 1 + len1 + len2;
171
    if (decoder->check(pc, table_start, (table_count + 1) * sizeof(uint32_t),
172
                       "expected <table entries>")) {
173
      table = pc + table_start;
174 175 176 177
    } else {
      table = nullptr;
    }
  }
178 179
  inline uint32_t read_entry(Decoder* decoder, unsigned i) {
    DCHECK(i <= table_count);
180
    return table ? decoder->read_u32(table + i * sizeof(uint32_t)) : 0;
181 182 183 184
  }
};

struct MemoryAccessOperand {
185
  uint32_t alignment;
186
  uint32_t offset;
187
  unsigned length;
188
  inline MemoryAccessOperand(Decoder* decoder, const byte* pc) {
189
    unsigned alignment_length;
190 191
    alignment =
        decoder->checked_read_u32v(pc, 1, &alignment_length, "alignment");
192
    unsigned offset_length;
193 194 195
    offset = decoder->checked_read_u32v(pc, 1 + alignment_length,
                                        &offset_length, "offset");
    length = alignment_length + offset_length;
196 197 198
  }
};

199 200
struct ReturnArityOperand {
  uint32_t arity;
201
  unsigned length;
202 203 204 205 206 207

  inline ReturnArityOperand(Decoder* decoder, const byte* pc) {
    arity = decoder->checked_read_u32v(pc, 1, &length, "return count");
  }
};

208 209 210
typedef compiler::WasmGraphBuilder TFBuilder;
struct ModuleEnv;  // forward declaration of module interface.

211 212 213 214 215 216 217
// All of the various data structures necessary to decode a function body.
struct FunctionBody {
  ModuleEnv* module;  // module environment
  FunctionSig* sig;   // function signature
  const byte* base;   // base of the module bytes, for error reporting
  const byte* start;  // start of the function body
  const byte* end;    // end of the function body
218 219
};

220 221 222 223 224
static inline FunctionBody FunctionBodyForTesting(const byte* start,
                                                  const byte* end) {
  return {nullptr, nullptr, start, start, end};
}

225 226 227 228 229 230 231
struct DecodeStruct {
  int unused;
};
typedef Result<DecodeStruct*> DecodeResult;
inline std::ostream& operator<<(std::ostream& os, const DecodeStruct& tree) {
  return os;
}
232

233 234 235 236
DecodeResult VerifyWasmCode(base::AccountingAllocator* allocator,
                            FunctionBody& body);
DecodeResult BuildTFGraph(base::AccountingAllocator* allocator,
                          TFBuilder* builder, FunctionBody& body);
237 238 239
bool PrintAst(base::AccountingAllocator* allocator, const FunctionBody& body,
              std::ostream& os,
              std::vector<std::tuple<uint32_t, int, int>>* offset_table);
240

241 242 243
// A simplified form of AST printing, e.g. from a debugger.
void PrintAstForDebugging(const byte* start, const byte* end);

244 245 246
inline DecodeResult VerifyWasmCode(base::AccountingAllocator* allocator,
                                   ModuleEnv* module, FunctionSig* sig,
                                   const byte* start, const byte* end) {
247
  FunctionBody body = {module, sig, nullptr, start, end};
248
  return VerifyWasmCode(allocator, body);
249 250
}

251 252 253 254
inline DecodeResult BuildTFGraph(base::AccountingAllocator* allocator,
                                 TFBuilder* builder, ModuleEnv* module,
                                 FunctionSig* sig, const byte* start,
                                 const byte* end) {
255
  FunctionBody body = {module, sig, nullptr, start, end};
256
  return BuildTFGraph(allocator, builder, body);
257 258
}

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
struct AstLocalDecls {
  // The size of the encoded declarations.
  uint32_t decls_encoded_size;  // size of encoded declarations

  // Total number of locals.
  uint32_t total_local_count;

  // List of {local type, count} pairs.
  ZoneVector<std::pair<LocalType, uint32_t>> local_types;

  // Constructor initializes the vector.
  explicit AstLocalDecls(Zone* zone)
      : decls_encoded_size(0), total_local_count(0), local_types(zone) {}
};

bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, const byte* end);
275
BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
276 277
                                           const byte* start, const byte* end);

278
// Computes the length of the opcode at the given address.
279
unsigned OpcodeLength(const byte* pc, const byte* end);
280 281

// Computes the arity (number of sub-nodes) of the opcode at the given address.
282
unsigned OpcodeArity(const byte* pc, const byte* end);
283

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
// A simple forward iterator for bytecodes.
class BytecodeIterator : public Decoder {
 public:
  // If one wants to iterate over the bytecode without looking at {pc_offset()}.
  class iterator {
   public:
    inline iterator& operator++() {
      DCHECK_LT(ptr_, end_);
      ptr_ += OpcodeLength(ptr_, end_);
      return *this;
    }
    inline WasmOpcode operator*() {
      DCHECK_LT(ptr_, end_);
      return static_cast<WasmOpcode>(*ptr_);
    }
    inline bool operator==(const iterator& that) {
      return this->ptr_ == that.ptr_;
    }
    inline bool operator!=(const iterator& that) {
      return this->ptr_ != that.ptr_;
    }

   private:
    friend class BytecodeIterator;
    const byte* ptr_;
    const byte* end_;
    iterator(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
  };

  // 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,
                   AstLocalDecls* decls = nullptr);

  inline iterator begin() const { return iterator(pc_, end_); }
  inline iterator end() const { return iterator(end_, end_); }

  WasmOpcode current() {
    return static_cast<WasmOpcode>(
        checked_read_u8(pc_, 0, "expected bytecode"));
  }

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

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

337 338 339 340 341
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_AST_DECODER_H_