value-type.h 24.4 KB
Newer Older
1 2 3 4
// Copyright 2018 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 11
#ifndef V8_WASM_VALUE_TYPE_H_
#define V8_WASM_VALUE_TYPE_H_

12
#include "src/base/bit-field.h"
13
#include "src/base/optional.h"
14
#include "src/codegen/machine-type.h"
15
#include "src/wasm/wasm-constants.h"
16
#include "src/wasm/wasm-limits.h"
17 18 19

namespace v8 {
namespace internal {
20 21 22 23

template <typename T>
class Signature;

24 25
namespace wasm {

26 27 28
// Type for holding simd values, defined in wasm-value.h.
class Simd128;

29
// Format: kind, log2Size, code, machineType, shortName, typeName
30 31
//
// Some of these types are from proposals that are not standardized yet:
32 33 34
// - "ref"/"optref" (a.k.a. "ref null") per
//   https://github.com/WebAssembly/function-references
// - "rtt" per https://github.com/WebAssembly/gc
35 36 37 38 39 40 41 42 43
#define FOREACH_NUMERIC_VALUE_TYPE(V)    \
  V(I32, 2, I32, Int32, 'i', "i32")      \
  V(I64, 3, I64, Int64, 'l', "i64")      \
  V(F32, 2, F32, Float32, 'f', "f32")    \
  V(F64, 3, F64, Float64, 'd', "f64")    \
  V(S128, 4, S128, Simd128, 's', "s128") \
  V(I8, 0, I8, Int8, 'b', "i8")          \
  V(I16, 1, I16, Int16, 'h', "i16")

44
#define FOREACH_VALUE_TYPE(V)                                               \
45
  V(Void, -1, Void, None, 'v', "<void>")                                    \
46 47 48 49 50
  FOREACH_NUMERIC_VALUE_TYPE(V)                                             \
  V(Rtt, kTaggedSizeLog2, Rtt, TaggedPointer, 't', "rtt")                   \
  V(RttWithDepth, kTaggedSizeLog2, RttWithDepth, TaggedPointer, 'k', "rtt") \
  V(Ref, kTaggedSizeLog2, Ref, AnyTagged, 'r', "ref")                       \
  V(OptRef, kTaggedSizeLog2, OptRef, AnyTagged, 'n', "ref null")            \
51 52
  V(Bottom, -1, Void, None, '*', "<bot>")

53 54
constexpr int kMaxValueTypeSize = 16;  // bytes

55 56 57 58 59 60
// Represents a WebAssembly heap type, as per the typed-funcref and gc
// proposals.
// The underlying Representation enumeration encodes heap types as follows:
// a number t < kV8MaxWasmTypes represents the type defined in the module at
// index t. Numbers directly beyond that represent the generic heap types. The
// next number represents the bottom heap type (internal use).
61 62
class HeapType {
 public:
63 64 65 66 67
  enum Representation : uint32_t {
    kFunc = kV8MaxWasmTypes,  // shorthand: c
    kExtern,                  // shorthand: e
    kEq,                      // shorthand: q
    kI31,                     // shorthand: j
68
    kData,                    // shorthand: o
69
    kAny,                     // shorthand: a
70
    // This value is used to represent failures in the parsing of heap types and
71 72 73
    // does not correspond to a wasm heap type.
    kBottom
  };
74 75
  // Internal use only; defined in the public section to make it easy to
  // check that they are defined correctly:
76
  static constexpr Representation kFirstSentinel = kFunc;
77
  static constexpr Representation kLastSentinel = kAny;
78 79 80

  static constexpr HeapType from_code(uint8_t code) {
    switch (code) {
81
      case ValueTypeCode::kFuncRefCode:
82
        return HeapType(kFunc);
83
      case ValueTypeCode::kExternRefCode:
84
        return HeapType(kExtern);
85
      case ValueTypeCode::kEqRefCode:
86
        return HeapType(kEq);
87
      case ValueTypeCode::kI31RefCode:
88
        return HeapType(kI31);
89 90
      case ValueTypeCode::kAnyRefCode:
        return HeapType(kAny);
91 92
      case ValueTypeCode::kDataRefCode:
        return HeapType(kData);
93 94 95 96
      default:
        return HeapType(kBottom);
    }
  }
97

98
  explicit constexpr HeapType(Representation repr) : representation_(repr) {
99
    DCHECK(is_bottom() || is_valid());
100
  }
101 102
  explicit constexpr HeapType(uint32_t repr)
      : HeapType(static_cast<Representation>(repr)) {}
103 104

  constexpr bool operator==(HeapType other) const {
105
    return representation_ == other.representation_;
106 107
  }
  constexpr bool operator!=(HeapType other) const {
108
    return representation_ != other.representation_;
109 110
  }

111 112 113 114 115 116 117 118
  constexpr bool operator==(Representation other) const {
    return representation_ == other;
  }

  constexpr bool operator!=(Representation other) const {
    return representation_ != other;
  }

119
  constexpr Representation representation() const { return representation_; }
120
  constexpr uint32_t ref_index() const {
121
    DCHECK(is_index());
122 123 124 125
    return representation_;
  }

  constexpr bool is_generic() const {
126
    return !is_bottom() && representation_ >= kFirstSentinel;
127 128
  }

129
  constexpr bool is_index() const { return representation_ < kFirstSentinel; }
130

131
  constexpr bool is_bottom() const { return representation_ == kBottom; }
132

133 134
  std::string name() const {
    switch (representation_) {
135 136 137 138 139 140
      case kFunc:
        return std::string("func");
      case kExtern:
        return std::string("extern");
      case kEq:
        return std::string("eq");
141 142
      case kI31:
        return std::string("i31");
143 144
      case kData:
        return std::string("data");
145 146
      case kAny:
        return std::string("any");
147
      default:
148
        return std::to_string(representation_);
149 150 151
    }
  }

152
  // Returns the code that represents this heap type in the wasm binary format.
153
  constexpr int32_t code() const {
154
    // Type codes represent the first byte of the LEB128 encoding. To get the
155 156 157
    // int32 represented by a code, we need to sign-extend it from 7 to 32 bits.
    int32_t mask = 0xFFFFFF80;
    switch (representation_) {
158
      case kFunc:
159
        return mask | kFuncRefCode;
160
      case kExtern:
161
        return mask | kExternRefCode;
162
      case kEq:
163
        return mask | kEqRefCode;
164
      case kI31:
165
        return mask | kI31RefCode;
166 167
      case kData:
        return mask | kDataRefCode;
168 169
      case kAny:
        return mask | kAnyRefCode;
170
      default:
171
        return static_cast<int32_t>(representation_);
172 173 174 175 176
    }
  }

 private:
  friend class ValueType;
177
  Representation representation_;
178
  constexpr bool is_valid() const { return representation_ <= kLastSentinel; }
179
};
180

181 182
enum Nullability : bool { kNonNullable, kNullable };

183 184 185 186 187 188
enum ValueKind : uint8_t {
#define DEF_ENUM(kind, ...) k##kind,
  FOREACH_VALUE_TYPE(DEF_ENUM)
#undef DEF_ENUM
};

189 190 191 192 193 194 195 196 197 198 199 200
constexpr bool is_numeric(ValueKind kind) {
  switch (kind) {
#define NUMERIC_CASE(kind, ...) \
  case k##kind:                 \
    return true;
    FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_CASE)
#undef NUMERIC_CASE
    default:
      return false;
  }
}

201
constexpr bool is_reference(ValueKind kind) {
202 203 204 205
  return kind == kRef || kind == kOptRef || kind == kRtt ||
         kind == kRttWithDepth;
}

206
constexpr bool is_object_reference(ValueKind kind) {
207 208 209 210 211 212 213 214 215 216 217
  return kind == kRef || kind == kOptRef;
}

constexpr int element_size_log2(ValueKind kind) {
  constexpr int8_t kElementSizeLog2[] = {
#define ELEM_SIZE_LOG2(kind, log2Size, ...) log2Size,
      FOREACH_VALUE_TYPE(ELEM_SIZE_LOG2)
#undef ELEM_SIZE_LOG2
  };

  int size_log_2 = kElementSizeLog2[kind];
218
  DCHECK_LE(0, size_log_2);
219 220 221 222 223 224 225 226 227 228 229 230
  return size_log_2;
}

constexpr int element_size_bytes(ValueKind kind) {
  constexpr int8_t kElementSize[] = {
#define ELEM_SIZE_LOG2(kind, log2Size, ...) \
  log2Size == -1 ? -1 : (1 << std::max(0, log2Size)),
      FOREACH_VALUE_TYPE(ELEM_SIZE_LOG2)
#undef ELEM_SIZE_LOG2
  };

  int size = kElementSize[kind];
231
  DCHECK_LT(0, size);
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  return size;
}

constexpr char short_name(ValueKind kind) {
  constexpr char kShortName[] = {
#define SHORT_NAME(kind, log2Size, code, machineType, shortName, ...) shortName,
      FOREACH_VALUE_TYPE(SHORT_NAME)
#undef SHORT_NAME
  };

  return kShortName[kind];
}

constexpr const char* name(ValueKind kind) {
  constexpr const char* kKindName[] = {
#define KIND_NAME(kind, log2Size, code, machineType, shortName, kindName, ...) \
  kindName,
      FOREACH_VALUE_TYPE(KIND_NAME)
#undef TYPE_NAME
  };

  return kKindName[kind];
}

constexpr MachineType machine_type(ValueKind kind) {
257
  DCHECK_NE(kBottom, kind);
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

  constexpr MachineType kMachineType[] = {
#define MACH_TYPE(kind, log2Size, code, machineType, ...) \
  MachineType::machineType(),
      FOREACH_VALUE_TYPE(MACH_TYPE)
#undef MACH_TYPE
  };

  return kMachineType[kind];
}

constexpr bool is_packed(ValueKind kind) { return kind == kI8 || kind == kI16; }
constexpr ValueKind unpacked(ValueKind kind) {
  return is_packed(kind) ? kI32 : kind;
}

constexpr bool is_rtt(ValueKind kind) {
  return kind == kRtt || kind == kRttWithDepth;
}

constexpr bool is_defaultable(ValueKind kind) {
279
  DCHECK(kind != kBottom && kind != kVoid);
280 281 282 283 284 285 286 287 288
  return kind != kRef && !is_rtt(kind);
}

// A ValueType is encoded by three components: A ValueKind, a heap
// representation (for reference types), and an inheritance depth (for rtts
// only). Those are encoded into 32 bits using base::BitField. The underlying
// ValueKind enumeration includes four elements which do not strictly correspond
// to value types: the two packed types i8 and i16, the type of void blocks
// (stmt), and a bottom value (for internal use).
289 290
class ValueType {
 public:
291
  /******************************* Constructors *******************************/
292
  constexpr ValueType() : bit_field_(KindField::encode(kVoid)) {}
293
  static constexpr ValueType Primitive(ValueKind kind) {
294
    DCHECK(kind == kBottom || kind <= kI16);
295
    return ValueType(KindField::encode(kind));
296
  }
297
  static constexpr ValueType Ref(uint32_t heap_type, Nullability nullability) {
298
    DCHECK(HeapType(heap_type).is_valid());
299 300 301 302
    return ValueType(
        KindField::encode(nullability == kNullable ? kOptRef : kRef) |
        HeapTypeField::encode(heap_type));
  }
303
  static constexpr ValueType Ref(HeapType heap_type, Nullability nullability) {
304
    return Ref(heap_type.representation(), nullability);
305
  }
306

307
  static constexpr ValueType Rtt(uint32_t type_index) {
308
    DCHECK(HeapType(type_index).is_index());
309 310 311 312
    return ValueType(KindField::encode(kRtt) |
                     HeapTypeField::encode(type_index));
  }

313
  static constexpr ValueType Rtt(uint32_t type_index,
314
                                 uint8_t inheritance_depth) {
315
    DCHECK(HeapType(type_index).is_index());
316
    return ValueType(KindField::encode(kRttWithDepth) |
317
                     HeapTypeField::encode(type_index) |
318 319 320
                     DepthField::encode(inheritance_depth));
  }

321
  // Useful when deserializing a type stored in a runtime object.
322 323
  static constexpr ValueType FromRawBitField(uint32_t bit_field) {
    return ValueType(bit_field);
324
  }
325

326
  /******************************** Type checks *******************************/
327 328
  constexpr bool is_numeric() const { return wasm::is_numeric(kind()); }

329
  constexpr bool is_reference() const { return wasm::is_reference(kind()); }
330

331 332
  constexpr bool is_object_reference() const {
    return wasm::is_object_reference(kind());
333 334 335 336 337 338 339 340 341
  }

  constexpr bool is_nullable() const { return kind() == kOptRef; }

  constexpr bool is_reference_to(uint32_t htype) const {
    return (kind() == kRef || kind() == kOptRef) &&
           heap_representation() == htype;
  }

342
  constexpr bool is_rtt() const { return wasm::is_rtt(kind()); }
343
  constexpr bool has_depth() const { return kind() == kRttWithDepth; }
344 345

  constexpr bool has_index() const {
346
    return is_rtt() || (is_object_reference() && heap_type().is_index());
347 348
  }

349
  constexpr bool is_defaultable() const { return wasm::is_defaultable(kind()); }
350 351 352

  constexpr bool is_bottom() const { return kind() == kBottom; }

353
  constexpr bool is_packed() const { return wasm::is_packed(kind()); }
354 355 356 357 358

  constexpr ValueType Unpacked() const {
    return is_packed() ? Primitive(kI32) : *this;
  }

359 360 361 362 363 364 365
  // Returns the version of this type that does not allow null values. Handles
  // bottom.
  constexpr ValueType AsNonNull() const {
    DCHECK(is_object_reference() || is_bottom());
    return is_nullable() ? Ref(heap_type(), kNonNullable) : *this;
  }

366
  /***************************** Field Accessors ******************************/
367
  constexpr ValueKind kind() const { return KindField::decode(bit_field_); }
368
  constexpr HeapType::Representation heap_representation() const {
369
    DCHECK(is_object_reference());
370 371
    return static_cast<HeapType::Representation>(
        HeapTypeField::decode(bit_field_));
372
  }
373
  constexpr HeapType heap_type() const {
374
    DCHECK(is_object_reference());
375 376
    return HeapType(heap_representation());
  }
377
  constexpr uint8_t depth() const {
378
    DCHECK(has_depth());
379 380
    return DepthField::decode(bit_field_);
  }
381
  constexpr uint32_t ref_index() const {
382
    DCHECK(has_index());
383
    return HeapTypeField::decode(bit_field_);
384
  }
385
  constexpr Nullability nullability() const {
386
    DCHECK(is_object_reference());
387 388
    return kind() == kOptRef ? kNullable : kNonNullable;
  }
389

390
  // Useful when serializing this type to store it into a runtime object.
391 392
  constexpr uint32_t raw_bit_field() const { return bit_field_; }

393 394 395 396 397 398 399 400
  /*************************** Other utility methods **************************/
  constexpr bool operator==(ValueType other) const {
    return bit_field_ == other.bit_field_;
  }
  constexpr bool operator!=(ValueType other) const {
    return bit_field_ != other.bit_field_;
  }

401 402 403 404
  static constexpr size_t bit_field_offset() {
    return offsetof(ValueType, bit_field_);
  }

405
  constexpr int element_size_log2() const {
406
    return wasm::element_size_log2(kind());
407 408
  }

409
  constexpr int element_size_bytes() const {
410
    return wasm::element_size_bytes(kind());
411
  }
412

413
  /*************************** Machine-type related ***************************/
414
  constexpr MachineType machine_type() const {
415
    return wasm::machine_type(kind());
416 417
  }

418
  constexpr MachineRepresentation machine_representation() const {
419 420 421
    return machine_type().representation();
  }

422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
  static ValueType For(MachineType type) {
    switch (type.representation()) {
      case MachineRepresentation::kWord8:
      case MachineRepresentation::kWord16:
      case MachineRepresentation::kWord32:
        return Primitive(kI32);
      case MachineRepresentation::kWord64:
        return Primitive(kI64);
      case MachineRepresentation::kFloat32:
        return Primitive(kF32);
      case MachineRepresentation::kFloat64:
        return Primitive(kF64);
      case MachineRepresentation::kTaggedPointer:
        return Ref(HeapType::kExtern, kNullable);
      case MachineRepresentation::kSimd128:
        return Primitive(kS128);
      default:
        UNREACHABLE();
    }
  }

  /********************************* Encoding *********************************/

445 446 447 448 449
  // Returns the first byte of this type's representation in the wasm binary
  // format.
  // For compatibility with the reftypes and exception-handling proposals, this
  // function prioritizes shorthand encodings
  // (e.g., Ref(HeapType::kFunc, kNullable).value_type_code will return
450
  // kFuncrefCode and not kOptRefCode).
451
  constexpr ValueTypeCode value_type_code() const {
452
    DCHECK_NE(kBottom, kind());
453 454
    switch (kind()) {
      case kOptRef:
455
        switch (heap_representation()) {
456
          case HeapType::kFunc:
457
            return kFuncRefCode;
458
          case HeapType::kExtern:
459
            return kExternRefCode;
460
          case HeapType::kEq:
461
            return kEqRefCode;
462 463
          case HeapType::kAny:
            return kAnyRefCode;
464
          default:
465
            return kOptRefCode;
466 467
        }
      case kRef:
468 469 470 471 472 473 474 475
        switch (heap_representation()) {
          case HeapType::kI31:
            return kI31RefCode;
          case HeapType::kData:
            return kDataRefCode;
          default:
            return kRefCode;
        }
476
      case kVoid:
477
        return kVoidCode;
478
      case kRtt:
479
        return kRttCode;
480 481
      case kRttWithDepth:
        return kRttWithDepthCode;
482 483
#define NUMERIC_TYPE_CASE(kind, ...) \
  case k##kind:                      \
484
    return k##kind##Code;
485 486 487 488
        FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_TYPE_CASE)
#undef NUMERIC_TYPE_CASE
      case kBottom:
        // Unreachable code
489
        return kVoidCode;
490 491 492
    }
  }

493 494
  // Returns true iff the heap type is needed to encode this type in the wasm
  // binary format, taking into account available type shorthands.
495
  constexpr bool encoding_needs_heap_type() const {
496 497 498 499 500
    return (kind() == kRef && heap_representation() != HeapType::kI31 &&
            heap_representation() != HeapType::kData) ||
           (kind() == kOptRef && (heap_type().is_index() ||
                                  heap_representation() == HeapType::kI31 ||
                                  heap_representation() == HeapType::kData));
501 502
  }

503
  static constexpr int kLastUsedBit = 30;
504

505
  /****************************** Pretty-printing *****************************/
506
  constexpr char short_name() const { return wasm::short_name(kind()); }
507

508
  std::string name() const {
509 510 511 512
    std::ostringstream buf;
    switch (kind()) {
      case kRef:
      case kOptRef:
513 514 515
        if (encoding_needs_heap_type()) {
          buf << "(ref " << (kind() == kOptRef ? "null " : "")
              << heap_type().name() << ")";
516
        } else {
517
          buf << heap_type().name() << "ref";
518 519
        }
        break;
520
      case kRttWithDepth:
521 522
        buf << "(rtt " << static_cast<uint32_t>(depth()) << " " << ref_index()
            << ")";
523
        break;
524 525 526
      case kRtt:
        buf << "(rtt " << ref_index() << ")";
        break;
527 528 529 530 531 532 533
      default:
        buf << kind_name();
    }
    return buf.str();
  }

 private:
534 535
  // We only use 31 bits so ValueType fits in a Smi. This can be changed if
  // needed.
536 537
  static constexpr int kKindBits = 5;
  static constexpr int kHeapTypeBits = 20;
538
  static constexpr int kDepthBits = 6;
539 540
  STATIC_ASSERT(kV8MaxWasmTypes < (1u << kHeapTypeBits));
  // Note: we currently conservatively allow only 5 bits, but have room to
541
  // store 6, so we can raise the limit if needed.
542
  STATIC_ASSERT(kV8MaxRttSubtypingDepth < (1u << kDepthBits));
543
  using KindField = base::BitField<ValueKind, 0, kKindBits>;
544 545
  using HeapTypeField = KindField::Next<uint32_t, kHeapTypeBits>;
  using DepthField = HeapTypeField::Next<uint8_t, kDepthBits>;
546

547 548 549 550 551
  // This is implemented defensively against field order changes.
  STATIC_ASSERT(kLastUsedBit == std::max(KindField::kLastUsedBit,
                                         std::max(HeapTypeField::kLastUsedBit,
                                                  DepthField::kLastUsedBit)));

552 553
  constexpr explicit ValueType(uint32_t bit_field) : bit_field_(bit_field) {}

554
  constexpr const char* kind_name() const { return wasm::name(kind()); }
555

556
  uint32_t bit_field_;
557
};
558

559 560
static_assert(sizeof(ValueType) <= kUInt32Size,
              "ValueType is small and can be passed by value");
561 562
static_assert(ValueType::kLastUsedBit < 8 * sizeof(ValueType) - kSmiTagSize,
              "ValueType has space to be encoded in a Smi");
563 564 565 566 567

inline size_t hash_value(ValueType type) {
  return static_cast<size_t>(type.kind());
}

568 569
// Output operator, useful for DCHECKS and others.
inline std::ostream& operator<<(std::ostream& oss, ValueType type) {
570
  return oss << type.name();
571 572
}

573
// Precomputed primitive types.
574 575 576 577 578 579 580
constexpr ValueType kWasmI32 = ValueType::Primitive(kI32);
constexpr ValueType kWasmI64 = ValueType::Primitive(kI64);
constexpr ValueType kWasmF32 = ValueType::Primitive(kF32);
constexpr ValueType kWasmF64 = ValueType::Primitive(kF64);
constexpr ValueType kWasmS128 = ValueType::Primitive(kS128);
constexpr ValueType kWasmI8 = ValueType::Primitive(kI8);
constexpr ValueType kWasmI16 = ValueType::Primitive(kI16);
581
constexpr ValueType kWasmVoid = ValueType::Primitive(kVoid);
582
constexpr ValueType kWasmBottom = ValueType::Primitive(kBottom);
583
// Established reference-type proposal shorthands.
584 585 586 587
constexpr ValueType kWasmFuncRef = ValueType::Ref(HeapType::kFunc, kNullable);
constexpr ValueType kWasmExternRef =
    ValueType::Ref(HeapType::kExtern, kNullable);
constexpr ValueType kWasmEqRef = ValueType::Ref(HeapType::kEq, kNullable);
588
constexpr ValueType kWasmI31Ref = ValueType::Ref(HeapType::kI31, kNonNullable);
589 590
constexpr ValueType kWasmDataRef =
    ValueType::Ref(HeapType::kData, kNonNullable);
591
constexpr ValueType kWasmAnyRef = ValueType::Ref(HeapType::kAny, kNullable);
592

593 594 595 596
// This is used in wasm.tq.
constexpr ValueType kWasmExternNonNullableRef =
    ValueType::Ref(HeapType::kExtern, kNonNullable);

597
#define FOREACH_WASMVALUE_CTYPES(V) \
598 599 600 601 602
  V(kI32, int32_t)                  \
  V(kI64, int64_t)                  \
  V(kF32, float)                    \
  V(kF64, double)                   \
  V(kS128, Simd128)
603

604 605
using FunctionSig = Signature<ValueType>;

606
#define FOREACH_LOAD_TYPE(V) \
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
  V(I32, , Int32)            \
  V(I32, 8S, Int8)           \
  V(I32, 8U, Uint8)          \
  V(I32, 16S, Int16)         \
  V(I32, 16U, Uint16)        \
  V(I64, , Int64)            \
  V(I64, 8S, Int8)           \
  V(I64, 8U, Uint8)          \
  V(I64, 16S, Int16)         \
  V(I64, 16U, Uint16)        \
  V(I64, 32S, Int32)         \
  V(I64, 32U, Uint32)        \
  V(F32, , Float32)          \
  V(F64, , Float64)          \
  V(S128, , Simd128)
622 623 624 625 626 627 628 629 630

class LoadType {
 public:
  enum LoadTypeValue : uint8_t {
#define DEF_ENUM(type, suffix, ...) k##type##Load##suffix,
    FOREACH_LOAD_TYPE(DEF_ENUM)
#undef DEF_ENUM
  };

631
  // Allow implicit conversion of the enum value to this wrapper.
632 633 634 635 636 637 638 639 640
  constexpr LoadType(LoadTypeValue val)  // NOLINT(runtime/explicit)
      : val_(val) {}

  constexpr LoadTypeValue value() const { return val_; }
  constexpr unsigned size_log_2() const { return kLoadSizeLog2[val_]; }
  constexpr unsigned size() const { return 1 << size_log_2(); }
  constexpr ValueType value_type() const { return kValueType[val_]; }
  constexpr MachineType mem_type() const { return kMemType[val_]; }

641 642
  static LoadType ForValueKind(ValueKind kind, bool is_signed = false) {
    switch (kind) {
643
      case kI32:
644
        return kI32Load;
645
      case kI64:
646
        return kI64Load;
647
      case kF32:
648
        return kF32Load;
649
      case kF64:
650
        return kF64Load;
651
      case kS128:
652
        return kS128Load;
653
      case kI8:
654
        return is_signed ? kI32Load8S : kI32Load8U;
655
      case kI16:
656
        return is_signed ? kI32Load16S : kI32Load16U;
657 658 659 660 661 662 663 664 665
      default:
        UNREACHABLE();
    }
  }

 private:
  const LoadTypeValue val_;

  static constexpr uint8_t kLoadSizeLog2[] = {
666
  // MSVC wants a static_cast here.
667
#define LOAD_SIZE(_, __, memtype) \
668 669
  static_cast<uint8_t>(           \
      ElementSizeLog2Of(MachineType::memtype().representation())),
670 671 672 673 674
      FOREACH_LOAD_TYPE(LOAD_SIZE)
#undef LOAD_SIZE
  };

  static constexpr ValueType kValueType[] = {
675
#define VALUE_TYPE(type, ...) ValueType::Primitive(k##type),
676 677 678 679 680
      FOREACH_LOAD_TYPE(VALUE_TYPE)
#undef VALUE_TYPE
  };

  static constexpr MachineType kMemType[] = {
681
#define MEMTYPE(_, __, memtype) MachineType::memtype(),
682 683 684 685 686 687
      FOREACH_LOAD_TYPE(MEMTYPE)
#undef MEMTYPE
  };
};

#define FOREACH_STORE_TYPE(V) \
688 689 690 691 692 693 694 695 696 697
  V(I32, , Word32)            \
  V(I32, 8, Word8)            \
  V(I32, 16, Word16)          \
  V(I64, , Word64)            \
  V(I64, 8, Word8)            \
  V(I64, 16, Word16)          \
  V(I64, 32, Word32)          \
  V(F32, , Float32)           \
  V(F64, , Float64)           \
  V(S128, , Simd128)
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714

class StoreType {
 public:
  enum StoreTypeValue : uint8_t {
#define DEF_ENUM(type, suffix, ...) k##type##Store##suffix,
    FOREACH_STORE_TYPE(DEF_ENUM)
#undef DEF_ENUM
  };

  // Allow implicit convertion of the enum value to this wrapper.
  constexpr StoreType(StoreTypeValue val)  // NOLINT(runtime/explicit)
      : val_(val) {}

  constexpr StoreTypeValue value() const { return val_; }
  constexpr unsigned size_log_2() const { return kStoreSizeLog2[val_]; }
  constexpr unsigned size() const { return 1 << size_log_2(); }
  constexpr ValueType value_type() const { return kValueType[val_]; }
715
  constexpr MachineRepresentation mem_rep() const { return kMemRep[val_]; }
716

717 718
  static StoreType ForValueKind(ValueKind kind) {
    switch (kind) {
719
      case kI32:
720
        return kI32Store;
721
      case kI64:
722
        return kI64Store;
723
      case kF32:
724
        return kF32Store;
725
      case kF64:
726
        return kF64Store;
727
      case kS128:
728
        return kS128Store;
729
      case kI8:
730
        return kI32Store8;
731
      case kI16:
732
        return kI32Store16;
733 734 735 736 737 738 739 740 741
      default:
        UNREACHABLE();
    }
  }

 private:
  const StoreTypeValue val_;

  static constexpr uint8_t kStoreSizeLog2[] = {
742
  // MSVC wants a static_cast here.
743
#define STORE_SIZE(_, __, memrep) \
744
  static_cast<uint8_t>(ElementSizeLog2Of(MachineRepresentation::k##memrep)),
745 746 747 748 749
      FOREACH_STORE_TYPE(STORE_SIZE)
#undef STORE_SIZE
  };

  static constexpr ValueType kValueType[] = {
750
#define VALUE_TYPE(type, ...) ValueType::Primitive(k##type),
751 752 753 754 755
      FOREACH_STORE_TYPE(VALUE_TYPE)
#undef VALUE_TYPE
  };

  static constexpr MachineRepresentation kMemRep[] = {
756
#define MEMREP(_, __, memrep) MachineRepresentation::k##memrep,
757 758 759 760 761
      FOREACH_STORE_TYPE(MEMREP)
#undef MEMREP
  };
};

762
base::Optional<wasm::ValueKind> WasmReturnTypeFromSignature(
763 764
    const FunctionSig* wasm_signature);

765 766 767 768 769
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_VALUE_TYPE_H_