function-body-decoder-impl.h 9.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright 2017 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_FUNCTION_BODY_DECODER_IMPL_H_
#define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_

#include "src/wasm/decoder.h"
#include "src/wasm/wasm-opcodes.h"

namespace v8 {
namespace internal {
namespace wasm {

struct WasmGlobal;

17 18 19 20 21 22 23 24
// Use this macro to check a condition if checked == true, and DCHECK the
// condition otherwise.
#define CHECKED_COND(cond)   \
  (checked ? (cond) : ([&] { \
    DCHECK(cond);            \
    return true;             \
  })())

25
// Helpers for decoding different kinds of operands which follow bytecodes.
26
template <bool checked>
27 28
struct LocalIndexOperand {
  uint32_t index;
29
  ValueType type = kWasmStmt;
30 31 32
  unsigned length;

  inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
33
    index = decoder->read_u32v<checked>(pc + 1, &length, "local index");
34 35 36
  }
};

37
template <bool checked>
38 39 40 41
struct ImmI32Operand {
  int32_t value;
  unsigned length;
  inline ImmI32Operand(Decoder* decoder, const byte* pc) {
42
    value = decoder->read_i32v<checked>(pc + 1, &length, "immi32");
43 44 45
  }
};

46
template <bool checked>
47 48 49 50
struct ImmI64Operand {
  int64_t value;
  unsigned length;
  inline ImmI64Operand(Decoder* decoder, const byte* pc) {
51
    value = decoder->read_i64v<checked>(pc + 1, &length, "immi64");
52 53 54
  }
};

55
template <bool checked>
56 57
struct ImmF32Operand {
  float value;
58
  unsigned length = 4;
59 60
  inline ImmF32Operand(Decoder* decoder, const byte* pc) {
    // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
61
    uint32_t tmp = decoder->read_u32<checked>(pc + 1, "immf32");
62 63 64 65
    memcpy(&value, &tmp, sizeof(value));
  }
};

66
template <bool checked>
67 68
struct ImmF64Operand {
  double value;
69
  unsigned length = 8;
70 71
  inline ImmF64Operand(Decoder* decoder, const byte* pc) {
    // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
72
    uint64_t tmp = decoder->read_u64<checked>(pc + 1, "immf64");
73 74 75 76
    memcpy(&value, &tmp, sizeof(value));
  }
};

77
template <bool checked>
78 79
struct GlobalIndexOperand {
  uint32_t index;
80 81
  ValueType type = kWasmStmt;
  const WasmGlobal* global = nullptr;
82 83 84
  unsigned length;

  inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
85
    index = decoder->read_u32v<checked>(pc + 1, &length, "global index");
86 87 88
  }
};

89
template <bool checked>
90
struct BlockTypeOperand {
91 92 93
  uint32_t arity = 0;
  const byte* types = nullptr;  // pointer to encoded types for the block.
  unsigned length = 1;
94 95

  inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
96
    uint8_t val = decoder->read_u8<checked>(pc + 1, "block type");
97 98 99 100 101 102
    ValueType type = kWasmStmt;
    if (decode_local_type(val, &type)) {
      arity = type == kWasmStmt ? 0 : 1;
      types = pc + 1;
    } else {
      // Handle multi-value blocks.
103
      if (!CHECKED_COND(FLAG_experimental_wasm_mv)) {
104
        decoder->error(pc + 1, "invalid block arity > 1");
105 106
        return;
      }
107
      if (!CHECKED_COND(val == kMultivalBlock)) {
108
        decoder->error(pc + 1, "invalid block type");
109 110 111 112
        return;
      }
      // Decode and check the types vector of the block.
      unsigned len = 0;
113
      uint32_t count = decoder->read_u32v<checked>(pc + 2, &len, "block arity");
114 115 116 117 118 119 120 121 122
      // {count} is encoded as {arity-2}, so that a {0} count here corresponds
      // to a block with 2 values. This makes invalid/redundant encodings
      // impossible.
      arity = count + 2;
      length = 1 + len + arity;
      types = pc + 1 + 1 + len;

      for (uint32_t i = 0; i < arity; i++) {
        uint32_t offset = 1 + 1 + len + i;
123
        val = decoder->read_u8<checked>(pc + offset, "block type");
124
        decode_local_type(val, &type);
125
        if (!CHECKED_COND(type != kWasmStmt)) {
126
          decoder->error(pc + offset, "invalid block type");
127 128 129 130 131
          return;
        }
      }
    }
  }
132

133 134
  // Decode a byte representing a local type. Return {false} if the encoded
  // byte was invalid or {kMultivalBlock}.
135
  inline bool decode_local_type(uint8_t val, ValueType* result) {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    switch (static_cast<ValueTypeCode>(val)) {
      case kLocalVoid:
        *result = kWasmStmt;
        return true;
      case kLocalI32:
        *result = kWasmI32;
        return true;
      case kLocalI64:
        *result = kWasmI64;
        return true;
      case kLocalF32:
        *result = kWasmF32;
        return true;
      case kLocalF64:
        *result = kWasmF64;
        return true;
      case kLocalS128:
        *result = kWasmS128;
        return true;
      default:
        *result = kWasmStmt;
        return false;
    }
  }
  ValueType read_entry(unsigned index) {
    DCHECK_LT(index, arity);
    ValueType result;
    CHECK(decode_local_type(types[index], &result));
    return result;
  }
};

struct Control;
169
template <bool checked>
170 171
struct BreakDepthOperand {
  uint32_t depth;
172
  Control* target = nullptr;
173 174
  unsigned length;
  inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
175
    depth = decoder->read_u32v<checked>(pc + 1, &length, "break depth");
176 177 178
  }
};

179
template <bool checked>
180 181 182
struct CallIndirectOperand {
  uint32_t table_index;
  uint32_t index;
183
  FunctionSig* sig = nullptr;
184 185 186
  unsigned length;
  inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
    unsigned len = 0;
187 188 189
    index = decoder->read_u32v<checked>(pc + 1, &len, "signature index");
    table_index = decoder->read_u8<checked>(pc + 1 + len, "table index");
    if (!CHECKED_COND(table_index == 0)) {
190 191
      decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
                      table_index);
192 193 194 195 196
    }
    length = 1 + len;
  }
};

197
template <bool checked>
198 199
struct CallFunctionOperand {
  uint32_t index;
200
  FunctionSig* sig = nullptr;
201 202
  unsigned length;
  inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
203
    index = decoder->read_u32v<checked>(pc + 1, &length, "function index");
204 205 206
  }
};

207
template <bool checked>
208 209
struct MemoryIndexOperand {
  uint32_t index;
210
  unsigned length = 1;
211
  inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
212 213
    index = decoder->read_u8<checked>(pc + 1, "memory index");
    if (!CHECKED_COND(index == 0)) {
214
      decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
215 216 217 218
    }
  }
};

219
template <bool checked>
220 221 222 223 224
struct BranchTableOperand {
  uint32_t table_count;
  const byte* start;
  const byte* table;
  inline BranchTableOperand(Decoder* decoder, const byte* pc) {
225
    DCHECK_EQ(kExprBrTable, decoder->read_u8<checked>(pc, "opcode"));
226
    start = pc + 1;
227 228 229
    unsigned len = 0;
    table_count = decoder->read_u32v<checked>(pc + 1, &len, "table count");
    table = pc + 1 + len;
230 231 232 233
  }
};

// A helper to iterate over a branch table.
234
template <bool checked>
235 236 237 238 239 240 241
class BranchTableIterator {
 public:
  unsigned cur_index() { return index_; }
  bool has_next() { return decoder_->ok() && index_ <= table_count_; }
  uint32_t next() {
    DCHECK(has_next());
    index_++;
242
    unsigned length;
243
    uint32_t result =
244
        decoder_->read_u32v<checked>(pc_, &length, "branch table entry");
245 246 247 248 249 250 251 252 253 254 255
    pc_ += length;
    return result;
  }
  // length, including the length of the {BranchTableOperand}, but not the
  // opcode.
  unsigned length() {
    while (has_next()) next();
    return static_cast<unsigned>(pc_ - start_);
  }
  const byte* pc() { return pc_; }

256
  BranchTableIterator(Decoder* decoder, BranchTableOperand<checked>& operand)
257 258 259 260 261 262 263 264 265 266 267 268 269 270
      : decoder_(decoder),
        start_(operand.start),
        pc_(operand.table),
        index_(0),
        table_count_(operand.table_count) {}

 private:
  Decoder* decoder_;
  const byte* start_;
  const byte* pc_;
  uint32_t index_;        // the current index.
  uint32_t table_count_;  // the count of entries, not including default.
};

271
template <bool checked>
272 273 274 275 276 277 278 279
struct MemoryAccessOperand {
  uint32_t alignment;
  uint32_t offset;
  unsigned length;
  inline MemoryAccessOperand(Decoder* decoder, const byte* pc,
                             uint32_t max_alignment) {
    unsigned alignment_length;
    alignment =
280 281
        decoder->read_u32v<checked>(pc + 1, &alignment_length, "alignment");
    if (!CHECKED_COND(alignment <= max_alignment)) {
282 283 284 285
      decoder->errorf(pc + 1,
                      "invalid alignment; expected maximum alignment is %u, "
                      "actual alignment is %u",
                      max_alignment, alignment);
286 287
    }
    unsigned offset_length;
288 289
    offset = decoder->read_u32v<checked>(pc + 1 + alignment_length,
                                         &offset_length, "offset");
290 291 292 293 294
    length = alignment_length + offset_length;
  }
};

// Operand for SIMD lane operations.
295
template <bool checked>
296 297
struct SimdLaneOperand {
  uint8_t lane;
298
  unsigned length = 1;
299 300

  inline SimdLaneOperand(Decoder* decoder, const byte* pc) {
301
    lane = decoder->read_u8<checked>(pc + 2, "lane");
302 303 304 305
  }
};

// Operand for SIMD shift operations.
306
template <bool checked>
307 308
struct SimdShiftOperand {
  uint8_t shift;
309
  unsigned length = 1;
310 311

  inline SimdShiftOperand(Decoder* decoder, const byte* pc) {
312
    shift = decoder->read_u8<checked>(pc + 2, "shift");
313 314 315
  }
};

316
// Operand for SIMD S8x16 shuffle operations.
317
template <bool checked>
318 319
struct Simd8x16ShuffleOperand {
  uint8_t shuffle[kSimd128Size];
320

321 322
  inline Simd8x16ShuffleOperand(Decoder* decoder, const byte* pc) {
    for (uint32_t i = 0; i < kSimd128Size; ++i) {
323 324
      shuffle[i] = decoder->read_u8<checked>(pc + 2 + i, "shuffle");
    }
325 326 327
  }
};

328 329
#undef CHECKED_COND

330 331 332 333 334
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_