function-body-decoder-impl.h 9.52 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_wasm_mv_prototype)) {
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
    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;
155 156 157 158 159 160 161 162 163
      case kLocalS1x4:
        *result = kWasmS1x4;
        return true;
      case kLocalS1x8:
        *result = kWasmS1x8;
        return true;
      case kLocalS1x16:
        *result = kWasmS1x16;
        return true;
164 165 166 167 168 169 170 171 172 173 174 175 176 177
      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;
178
template <bool checked>
179 180
struct BreakDepthOperand {
  uint32_t depth;
181
  Control* target = nullptr;
182 183
  unsigned length;
  inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
184
    depth = decoder->read_u32v<checked>(pc + 1, &length, "break depth");
185 186 187
  }
};

188
template <bool checked>
189 190 191
struct CallIndirectOperand {
  uint32_t table_index;
  uint32_t index;
192
  FunctionSig* sig = nullptr;
193 194 195
  unsigned length;
  inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
    unsigned len = 0;
196 197 198
    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)) {
199 200
      decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
                      table_index);
201 202 203 204 205
    }
    length = 1 + len;
  }
};

206
template <bool checked>
207 208
struct CallFunctionOperand {
  uint32_t index;
209
  FunctionSig* sig = nullptr;
210 211
  unsigned length;
  inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
212
    index = decoder->read_u32v<checked>(pc + 1, &length, "function index");
213 214 215
  }
};

216
template <bool checked>
217 218
struct MemoryIndexOperand {
  uint32_t index;
219
  unsigned length = 1;
220
  inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
221 222
    index = decoder->read_u8<checked>(pc + 1, "memory index");
    if (!CHECKED_COND(index == 0)) {
223
      decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
224 225 226 227
    }
  }
};

228
template <bool checked>
229 230 231 232 233
struct BranchTableOperand {
  uint32_t table_count;
  const byte* start;
  const byte* table;
  inline BranchTableOperand(Decoder* decoder, const byte* pc) {
234
    DCHECK_EQ(kExprBrTable, decoder->read_u8<checked>(pc, "opcode"));
235
    start = pc + 1;
236 237 238
    unsigned len = 0;
    table_count = decoder->read_u32v<checked>(pc + 1, &len, "table count");
    table = pc + 1 + len;
239 240 241 242
  }
};

// A helper to iterate over a branch table.
243
template <bool checked>
244 245 246 247 248 249 250
class BranchTableIterator {
 public:
  unsigned cur_index() { return index_; }
  bool has_next() { return decoder_->ok() && index_ <= table_count_; }
  uint32_t next() {
    DCHECK(has_next());
    index_++;
251
    unsigned length;
252
    uint32_t result =
253
        decoder_->read_u32v<checked>(pc_, &length, "branch table entry");
254 255 256 257 258 259 260 261 262 263 264
    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_; }

265
  BranchTableIterator(Decoder* decoder, BranchTableOperand<checked>& operand)
266 267 268 269 270 271 272 273 274 275 276 277 278 279
      : 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.
};

280
template <bool checked>
281 282 283 284 285 286 287 288
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 =
289 290
        decoder->read_u32v<checked>(pc + 1, &alignment_length, "alignment");
    if (!CHECKED_COND(alignment <= max_alignment)) {
291 292 293 294
      decoder->errorf(pc + 1,
                      "invalid alignment; expected maximum alignment is %u, "
                      "actual alignment is %u",
                      max_alignment, alignment);
295 296
    }
    unsigned offset_length;
297 298
    offset = decoder->read_u32v<checked>(pc + 1 + alignment_length,
                                         &offset_length, "offset");
299 300 301 302 303
    length = alignment_length + offset_length;
  }
};

// Operand for SIMD lane operations.
304
template <bool checked>
305 306
struct SimdLaneOperand {
  uint8_t lane;
307
  unsigned length = 1;
308 309

  inline SimdLaneOperand(Decoder* decoder, const byte* pc) {
310
    lane = decoder->read_u8<checked>(pc + 2, "lane");
311 312 313 314
  }
};

// Operand for SIMD shift operations.
315
template <bool checked>
316 317
struct SimdShiftOperand {
  uint8_t shift;
318
  unsigned length = 1;
319 320

  inline SimdShiftOperand(Decoder* decoder, const byte* pc) {
321
    shift = decoder->read_u8<checked>(pc + 2, "shift");
322 323 324
  }
};

325 326 327 328 329 330 331 332 333 334 335 336
// Operand for SIMD concatenation operations.
template <bool checked>
struct SimdConcatOperand {
  uint8_t bytes;
  unsigned length;

  inline SimdConcatOperand(Decoder* decoder, const byte* pc) {
    bytes = decoder->read_u8<checked>(pc + 2, "bytes");
    length = 1;
  }
};

337 338
#undef CHECKED_COND

339 340 341 342 343
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_