• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_WASM_VALUE_TYPE_H_
6 #define V8_WASM_VALUE_TYPE_H_
7 
8 #include "src/base/bit-field.h"
9 #include "src/codegen/machine-type.h"
10 #include "src/wasm/wasm-constants.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 template <typename T>
16 class Signature;
17 
18 namespace wasm {
19 
20 // Type for holding simd values, defined in wasm-value.h.
21 class Simd128;
22 
23 // Format: kind, log2Size, code, machineType, shortName, typeName
24 //
25 // Some of these types are from proposals that are not standardized yet:
26 // - "ref"/"optref" (a.k.a. "ref null") per
27 //   https://github.com/WebAssembly/function-references
28 // - "rtt" per https://github.com/WebAssembly/gc
29 #define FOREACH_NUMERIC_VALUE_TYPE(V)    \
30   V(I32, 2, I32, Int32, 'i', "i32")      \
31   V(I64, 3, I64, Int64, 'l', "i64")      \
32   V(F32, 2, F32, Float32, 'f', "f32")    \
33   V(F64, 3, F64, Float64, 'd', "f64")    \
34   V(S128, 4, S128, Simd128, 's', "s128") \
35   V(I8, 0, I8, Int8, 'b', "i8")          \
36   V(I16, 1, I16, Int16, 'h', "i16")
37 
38 #define FOREACH_VALUE_TYPE(V)                                               \
39   V(Stmt, -1, Void, None, 'v', "<stmt>")                                    \
40   FOREACH_NUMERIC_VALUE_TYPE(V)                                             \
41   V(Rtt, kSystemPointerSizeLog2, Rtt, TaggedPointer, 't', "rtt")            \
42   V(Ref, kSystemPointerSizeLog2, Ref, TaggedPointer, 'r', "ref")            \
43   V(OptRef, kSystemPointerSizeLog2, OptRef, TaggedPointer, 'n', "ref null") \
44   V(Bottom, -1, Void, None, '*', "<bot>")
45 
46 // Represents a WebAssembly heap type, as per the typed-funcref and gc
47 // proposals.
48 // The underlying Representation enumeration encodes heap types as follows:
49 // a number t < kV8MaxWasmTypes represents the type defined in the module at
50 // index t. Numbers directly beyond that represent the generic heap types. The
51 // next number represents the bottom heap type (internal use).
52 class HeapType {
53  public:
54   enum Representation : uint32_t {
55     kFunc = kV8MaxWasmTypes,  // shorthand: c
56     kExtern,                  // shorthand: e
57     kEq,                      // shorthand: q
58     kExn,                     // shorthand: x
59     kI31,                     // shorthand: j
60     // This value is used to represent failures in the parsing of heap types and
61     // does not correspond to a wasm heap type.
62     kBottom
63   };
64   // Internal use only; defined in the public section to make it easy to
65   // check that they are defined correctly:
66   static constexpr Representation kFirstSentinel = kFunc;
67   static constexpr Representation kLastSentinel = kI31;
68 
from_code(uint8_t code)69   static constexpr HeapType from_code(uint8_t code) {
70     switch (code) {
71       case ValueTypeCode::kFuncRefCode:
72         return HeapType(kFunc);
73       case ValueTypeCode::kExternRefCode:
74         return HeapType(kExtern);
75       case ValueTypeCode::kEqRefCode:
76         return HeapType(kEq);
77       case ValueTypeCode::kExnRefCode:
78         return HeapType(kExn);
79       case ValueTypeCode::kI31RefCode:
80         return HeapType(kI31);
81       default:
82         return HeapType(kBottom);
83     }
84   }
85 
HeapType(Representation repr)86   explicit constexpr HeapType(Representation repr) : representation_(repr) {
87     CONSTEXPR_DCHECK(is_bottom() || is_valid());
88   }
HeapType(uint32_t repr)89   explicit constexpr HeapType(uint32_t repr)
90       : HeapType(static_cast<Representation>(repr)) {}
91 
92   constexpr bool operator==(HeapType other) const {
93     return representation_ == other.representation_;
94   }
95   constexpr bool operator!=(HeapType other) const {
96     return representation_ != other.representation_;
97   }
98 
99   constexpr bool operator==(Representation other) const {
100     return representation_ == other;
101   }
102 
103   constexpr bool operator!=(Representation other) const {
104     return representation_ != other;
105   }
106 
representation()107   constexpr Representation representation() const { return representation_; }
ref_index()108   constexpr uint32_t ref_index() const {
109     CONSTEXPR_DCHECK(is_index());
110     return representation_;
111   }
112 
is_generic()113   constexpr bool is_generic() const {
114     return !is_bottom() && representation_ >= kFirstSentinel;
115   }
116 
is_index()117   constexpr bool is_index() const { return representation_ < kFirstSentinel; }
118 
is_bottom()119   constexpr bool is_bottom() const { return representation_ == kBottom; }
120 
name()121   std::string name() const {
122     switch (representation_) {
123       case kFunc:
124         return std::string("func");
125       case kExtern:
126         return std::string("extern");
127       case kEq:
128         return std::string("eq");
129       case kExn:
130         return std::string("exn");
131       case kI31:
132         return std::string("i31");
133       default:
134         return std::to_string(representation_);
135     }
136   }
137 
138   // Returns the code that represents this heap type in the wasm binary format.
code()139   constexpr int32_t code() const {
140     // Type codes represent the first byte of the LEB128 encoding. To get the
141     // int32 represented by a code, we need to sign-extend it from 7 to 32 bits.
142     int32_t mask = 0xFFFFFF80;
143     switch (representation_) {
144       case kFunc:
145         return mask | kFuncRefCode;
146       case kExn:
147         return mask | kExnRefCode;
148       case kExtern:
149         return mask | kExternRefCode;
150       case kEq:
151         return mask | kEqRefCode;
152       case kI31:
153         return mask | kI31RefCode;
154       default:
155         return static_cast<int32_t>(representation_);
156     }
157   }
158 
159  private:
160   friend class ValueType;
161   Representation representation_;
is_valid()162   constexpr bool is_valid() const { return representation_ <= kLastSentinel; }
163 };
164 
165 enum Nullability : bool { kNonNullable, kNullable };
166 
167 // A ValueType is encoded by three components: A Kind, a heap representation
168 // (for reference types), and an inheritance depth (for rtts only). Those are
169 // encoded into 32 bits using base::BitField. The underlying Kind enumeration
170 // includes four elements which do not strictly correspond to value types: the
171 // two packed types i8 and i16, the type of void blocks (stmt), and a bottom
172 // value (for internal use).
173 class ValueType {
174  public:
175   enum Kind : uint8_t {
176 #define DEF_ENUM(kind, ...) k##kind,
177     FOREACH_VALUE_TYPE(DEF_ENUM)
178 #undef DEF_ENUM
179   };
180 
181   /******************************* Constructors *******************************/
ValueType()182   constexpr ValueType() : bit_field_(KindField::encode(kStmt)) {}
Primitive(Kind kind)183   static constexpr ValueType Primitive(Kind kind) {
184     CONSTEXPR_DCHECK(kind == kBottom || kind <= kI16);
185     return ValueType(KindField::encode(kind));
186   }
Ref(uint32_t heap_type,Nullability nullability)187   static constexpr ValueType Ref(uint32_t heap_type, Nullability nullability) {
188     CONSTEXPR_DCHECK(HeapType(heap_type).is_valid());
189     return ValueType(
190         KindField::encode(nullability == kNullable ? kOptRef : kRef) |
191         HeapTypeField::encode(heap_type));
192   }
Ref(HeapType heap_type,Nullability nullability)193   static constexpr ValueType Ref(HeapType heap_type, Nullability nullability) {
194     return Ref(heap_type.representation(), nullability);
195   }
196 
Rtt(uint32_t heap_type,uint8_t inheritance_depth)197   static constexpr ValueType Rtt(uint32_t heap_type,
198                                  uint8_t inheritance_depth) {
199     CONSTEXPR_DCHECK(HeapType(heap_type).is_valid());
200     return ValueType(KindField::encode(kRtt) |
201                      HeapTypeField::encode(heap_type) |
202                      DepthField::encode(inheritance_depth));
203   }
Rtt(HeapType heap_type,uint8_t inheritance_depth)204   static constexpr ValueType Rtt(HeapType heap_type,
205                                  uint8_t inheritance_depth) {
206     return Rtt(heap_type.representation(), inheritance_depth);
207   }
208 
209   // Useful when deserializing a type stored in a runtime object.
FromRawBitField(uint32_t bit_field)210   static constexpr ValueType FromRawBitField(uint32_t bit_field) {
211     return ValueType(bit_field);
212   }
213 
214   /******************************** Type checks *******************************/
is_reference_type()215   constexpr bool is_reference_type() const {
216     return kind() == kRef || kind() == kOptRef || kind() == kRtt;
217   }
218 
is_object_reference_type()219   constexpr bool is_object_reference_type() const {
220     return kind() == kRef || kind() == kOptRef;
221   }
222 
is_nullable()223   constexpr bool is_nullable() const { return kind() == kOptRef; }
224 
is_reference_to(uint32_t htype)225   constexpr bool is_reference_to(uint32_t htype) const {
226     return (kind() == kRef || kind() == kOptRef) &&
227            heap_representation() == htype;
228   }
229 
is_rtt()230   constexpr bool is_rtt() const { return kind() == kRtt; }
has_depth()231   constexpr bool has_depth() const { return is_rtt(); }
232 
has_index()233   constexpr bool has_index() const {
234     return is_reference_type() && heap_type().is_index();
235   }
236 
is_defaultable()237   constexpr bool is_defaultable() const {
238     CONSTEXPR_DCHECK(kind() != kBottom && kind() != kStmt);
239     return kind() != kRef && kind() != kRtt;
240   }
241 
is_bottom()242   constexpr bool is_bottom() const { return kind() == kBottom; }
243 
is_packed()244   constexpr bool is_packed() const { return kind() == kI8 || kind() == kI16; }
245 
Unpacked()246   constexpr ValueType Unpacked() const {
247     return is_packed() ? Primitive(kI32) : *this;
248   }
249 
250   /***************************** Field Accessors ******************************/
kind()251   constexpr Kind kind() const { return KindField::decode(bit_field_); }
heap_representation()252   constexpr HeapType::Representation heap_representation() const {
253     CONSTEXPR_DCHECK(is_reference_type());
254     return static_cast<HeapType::Representation>(
255         HeapTypeField::decode(bit_field_));
256   }
heap_type()257   constexpr HeapType heap_type() const {
258     return HeapType(heap_representation());
259   }
depth()260   constexpr uint8_t depth() const {
261     CONSTEXPR_DCHECK(has_depth());
262     return DepthField::decode(bit_field_);
263   }
ref_index()264   constexpr uint32_t ref_index() const {
265     CONSTEXPR_DCHECK(has_index());
266     return heap_type().ref_index();
267   }
268 
269   // Useful when serializing this type to store it into a runtime object.
raw_bit_field()270   constexpr uint32_t raw_bit_field() const { return bit_field_; }
271 
272   /*************************** Other utility methods **************************/
273   constexpr bool operator==(ValueType other) const {
274     return bit_field_ == other.bit_field_;
275   }
276   constexpr bool operator!=(ValueType other) const {
277     return bit_field_ != other.bit_field_;
278   }
279 
bit_field_offset()280   static constexpr size_t bit_field_offset() {
281     return offsetof(ValueType, bit_field_);
282   }
283 
element_size_log2()284   constexpr int element_size_log2() const {
285     constexpr int8_t kElementSizeLog2[] = {
286 #define ELEM_SIZE_LOG2(kind, log2Size, ...) log2Size,
287         FOREACH_VALUE_TYPE(ELEM_SIZE_LOG2)
288 #undef ELEM_SIZE_LOG2
289     };
290 
291     int size_log_2 = kElementSizeLog2[kind()];
292     CONSTEXPR_DCHECK(size_log_2 >= 0);
293     return size_log_2;
294   }
295 
element_size_bytes()296   constexpr int element_size_bytes() const {
297     constexpr int8_t kElementSize[] = {
298 #define ELEM_SIZE_LOG2(kind, log2Size, ...) \
299   log2Size == -1 ? -1 : (1 << std::max(0, log2Size)),
300         FOREACH_VALUE_TYPE(ELEM_SIZE_LOG2)
301 #undef ELEM_SIZE_LOG2
302     };
303 
304     int size = kElementSize[kind()];
305     CONSTEXPR_DCHECK(size > 0);
306     return size;
307   }
308 
309   /*************************** Machine-type related ***************************/
machine_type()310   constexpr MachineType machine_type() const {
311     CONSTEXPR_DCHECK(kBottom != kind());
312 
313     constexpr MachineType kMachineType[] = {
314 #define MACH_TYPE(kind, log2Size, code, machineType, ...) \
315   MachineType::machineType(),
316         FOREACH_VALUE_TYPE(MACH_TYPE)
317 #undef MACH_TYPE
318     };
319 
320     return kMachineType[kind()];
321   }
322 
machine_representation()323   constexpr MachineRepresentation machine_representation() const {
324     return machine_type().representation();
325   }
326 
For(MachineType type)327   static ValueType For(MachineType type) {
328     switch (type.representation()) {
329       case MachineRepresentation::kWord8:
330       case MachineRepresentation::kWord16:
331       case MachineRepresentation::kWord32:
332         return Primitive(kI32);
333       case MachineRepresentation::kWord64:
334         return Primitive(kI64);
335       case MachineRepresentation::kFloat32:
336         return Primitive(kF32);
337       case MachineRepresentation::kFloat64:
338         return Primitive(kF64);
339       case MachineRepresentation::kTaggedPointer:
340         return Ref(HeapType::kExtern, kNullable);
341       case MachineRepresentation::kSimd128:
342         return Primitive(kS128);
343       default:
344         UNREACHABLE();
345     }
346   }
347 
348   /********************************* Encoding *********************************/
349 
350   // Returns the first byte of this type's representation in the wasm binary
351   // format.
352   // For compatibility with the reftypes and exception-handling proposals, this
353   // function prioritizes shorthand encodings
354   // (e.g., Ref(HeapType::kFunc, kNullable).value_type_code will return
355   // kFuncrefCode and not kOptRefCode).
value_type_code()356   constexpr ValueTypeCode value_type_code() const {
357     CONSTEXPR_DCHECK(kind() != kBottom);
358     switch (kind()) {
359       case kOptRef:
360         switch (heap_representation()) {
361           case HeapType::kFunc:
362             return kFuncRefCode;
363           case HeapType::kExtern:
364             return kExternRefCode;
365           case HeapType::kEq:
366             return kEqRefCode;
367           case HeapType::kExn:
368             return kExnRefCode;
369           default:
370             return kOptRefCode;
371         }
372       case kRef:
373         if (heap_representation() == HeapType::kI31) return kI31RefCode;
374         return kRefCode;
375       case kStmt:
376         return kVoidCode;
377       case kRtt:
378         return kRttCode;
379 #define NUMERIC_TYPE_CASE(kind, ...) \
380   case k##kind:                      \
381     return k##kind##Code;
382         FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_TYPE_CASE)
383 #undef NUMERIC_TYPE_CASE
384       case kBottom:
385         // Unreachable code
386         return kVoidCode;
387     }
388   }
389 
390   // Returns true iff the heap type is needed to encode this type in the wasm
391   // binary format, taking into account available type shorthands.
encoding_needs_heap_type()392   constexpr bool encoding_needs_heap_type() const {
393     return (kind() == kRef && heap_representation() != HeapType::kI31) ||
394            kind() == kRtt ||
395            (kind() == kOptRef && (!heap_type().is_generic() ||
396                                   heap_representation() == HeapType::kI31));
397   }
398 
399   static constexpr int kLastUsedBit = 30;
400 
401   /****************************** Pretty-printing *****************************/
short_name()402   constexpr char short_name() const {
403     constexpr char kShortName[] = {
404 #define SHORT_NAME(kind, log2Size, code, machineType, shortName, ...) shortName,
405         FOREACH_VALUE_TYPE(SHORT_NAME)
406 #undef SHORT_NAME
407     };
408 
409     return kShortName[kind()];
410   }
411 
name()412   std::string name() const {
413     std::ostringstream buf;
414     switch (kind()) {
415       case kRef:
416         if (heap_representation() == HeapType::kI31) {
417           buf << "i31ref";
418         } else {
419           buf << "(ref " << heap_type().name() << ")";
420         }
421         break;
422       case kOptRef:
423         if (heap_type().is_generic() &&
424             heap_representation() != HeapType::kI31) {
425           // We use shorthands to be compatible with the 'reftypes' proposal.
426           buf << heap_type().name() << "ref";
427         } else {
428           buf << "(ref null " << heap_type().name() << ")";
429         }
430         break;
431       case kRtt:
432         buf << "(rtt " << static_cast<uint32_t>(depth()) << " "
433             << heap_type().name() << ")";
434         break;
435       default:
436         buf << kind_name();
437     }
438     return buf.str();
439   }
440 
441  private:
442   // We only use 31 bits so ValueType fits in a Smi. This can be changed if
443   // needed.
444   static constexpr int kKindBits = 5;
445   static constexpr int kHeapTypeBits = 20;
446   static constexpr int kDepthBits = 6;
447   STATIC_ASSERT(kV8MaxWasmTypes < (1u << kHeapTypeBits));
448   // Note: we currently conservatively allow only 5 bits, but have room to
449   // store 6, so we can raise the limit if needed.
450   STATIC_ASSERT(kV8MaxRttSubtypingDepth < (1u << kDepthBits));
451   using KindField = base::BitField<Kind, 0, kKindBits>;
452   using HeapTypeField = KindField::Next<uint32_t, kHeapTypeBits>;
453   using DepthField = HeapTypeField::Next<uint8_t, kDepthBits>;
454 
455   // This is implemented defensively against field order changes.
456   STATIC_ASSERT(kLastUsedBit == std::max(KindField::kLastUsedBit,
457                                          std::max(HeapTypeField::kLastUsedBit,
458                                                   DepthField::kLastUsedBit)));
459 
ValueType(uint32_t bit_field)460   constexpr explicit ValueType(uint32_t bit_field) : bit_field_(bit_field) {}
461 
kind_name()462   constexpr const char* kind_name() const {
463     constexpr const char* kTypeName[] = {
464 #define KIND_NAME(kind, log2Size, code, machineType, shortName, typeName, ...) \
465   typeName,
466         FOREACH_VALUE_TYPE(KIND_NAME)
467 #undef TYPE_NAME
468     };
469 
470     CONSTEXPR_DCHECK(kind() < arraysize(kTypeName));
471     return kTypeName[kind()];
472   }
473 
474   uint32_t bit_field_;
475 };
476 
477 static_assert(sizeof(ValueType) <= kUInt32Size,
478               "ValueType is small and can be passed by value");
479 
hash_value(ValueType type)480 inline size_t hash_value(ValueType type) {
481   return static_cast<size_t>(type.kind());
482 }
483 
484 // Output operator, useful for DCHECKS and others.
485 inline std::ostream& operator<<(std::ostream& oss, ValueType type) {
486   return oss << type.name();
487 }
488 
489 // Precomputed primitive types.
490 constexpr ValueType kWasmI32 = ValueType::Primitive(ValueType::kI32);
491 constexpr ValueType kWasmI64 = ValueType::Primitive(ValueType::kI64);
492 constexpr ValueType kWasmF32 = ValueType::Primitive(ValueType::kF32);
493 constexpr ValueType kWasmF64 = ValueType::Primitive(ValueType::kF64);
494 constexpr ValueType kWasmS128 = ValueType::Primitive(ValueType::kS128);
495 constexpr ValueType kWasmI8 = ValueType::Primitive(ValueType::kI8);
496 constexpr ValueType kWasmI16 = ValueType::Primitive(ValueType::kI16);
497 constexpr ValueType kWasmStmt = ValueType::Primitive(ValueType::kStmt);
498 constexpr ValueType kWasmBottom = ValueType::Primitive(ValueType::kBottom);
499 // Established wasm shorthands:
500 constexpr ValueType kWasmFuncRef = ValueType::Ref(HeapType::kFunc, kNullable);
501 constexpr ValueType kWasmExnRef = ValueType::Ref(HeapType::kExn, kNullable);
502 constexpr ValueType kWasmExternRef =
503     ValueType::Ref(HeapType::kExtern, kNullable);
504 constexpr ValueType kWasmEqRef = ValueType::Ref(HeapType::kEq, kNullable);
505 constexpr ValueType kWasmI31Ref = ValueType::Ref(HeapType::kI31, kNonNullable);
506 
507 #define FOREACH_WASMVALUE_CTYPES(V) \
508   V(kI32, int32_t)                  \
509   V(kI64, int64_t)                  \
510   V(kF32, float)                    \
511   V(kF64, double)                   \
512   V(kS128, Simd128)
513 
514 using FunctionSig = Signature<ValueType>;
515 
516 #define FOREACH_LOAD_TYPE(V) \
517   V(I32, , Int32)            \
518   V(I32, 8S, Int8)           \
519   V(I32, 8U, Uint8)          \
520   V(I32, 16S, Int16)         \
521   V(I32, 16U, Uint16)        \
522   V(I64, , Int64)            \
523   V(I64, 8S, Int8)           \
524   V(I64, 8U, Uint8)          \
525   V(I64, 16S, Int16)         \
526   V(I64, 16U, Uint16)        \
527   V(I64, 32S, Int32)         \
528   V(I64, 32U, Uint32)        \
529   V(F32, , Float32)          \
530   V(F64, , Float64)          \
531   V(S128, , Simd128)
532 
533 class LoadType {
534  public:
535   enum LoadTypeValue : uint8_t {
536 #define DEF_ENUM(type, suffix, ...) k##type##Load##suffix,
537     FOREACH_LOAD_TYPE(DEF_ENUM)
538 #undef DEF_ENUM
539   };
540 
541   // Allow implicit conversion of the enum value to this wrapper.
LoadType(LoadTypeValue val)542   constexpr LoadType(LoadTypeValue val)  // NOLINT(runtime/explicit)
543       : val_(val) {}
544 
value()545   constexpr LoadTypeValue value() const { return val_; }
size_log_2()546   constexpr unsigned size_log_2() const { return kLoadSizeLog2[val_]; }
size()547   constexpr unsigned size() const { return 1 << size_log_2(); }
value_type()548   constexpr ValueType value_type() const { return kValueType[val_]; }
mem_type()549   constexpr MachineType mem_type() const { return kMemType[val_]; }
550 
ForValueType(ValueType type)551   static LoadType ForValueType(ValueType type) {
552     switch (type.kind()) {
553       case ValueType::kI32:
554         return kI32Load;
555       case ValueType::kI64:
556         return kI64Load;
557       case ValueType::kF32:
558         return kF32Load;
559       case ValueType::kF64:
560         return kF64Load;
561       case ValueType::kS128:
562         return kS128Load;
563       default:
564         UNREACHABLE();
565     }
566   }
567 
568  private:
569   const LoadTypeValue val_;
570 
571   static constexpr uint8_t kLoadSizeLog2[] = {
572   // MSVC wants a static_cast here.
573 #define LOAD_SIZE(_, __, memtype) \
574   static_cast<uint8_t>(           \
575       ElementSizeLog2Of(MachineType::memtype().representation())),
576       FOREACH_LOAD_TYPE(LOAD_SIZE)
577 #undef LOAD_SIZE
578   };
579 
580   static constexpr ValueType kValueType[] = {
581 #define VALUE_TYPE(type, ...) ValueType::Primitive(ValueType::k##type),
582       FOREACH_LOAD_TYPE(VALUE_TYPE)
583 #undef VALUE_TYPE
584   };
585 
586   static constexpr MachineType kMemType[] = {
587 #define MEMTYPE(_, __, memtype) MachineType::memtype(),
588       FOREACH_LOAD_TYPE(MEMTYPE)
589 #undef MEMTYPE
590   };
591 };
592 
593 #define FOREACH_STORE_TYPE(V) \
594   V(I32, , Word32)            \
595   V(I32, 8, Word8)            \
596   V(I32, 16, Word16)          \
597   V(I64, , Word64)            \
598   V(I64, 8, Word8)            \
599   V(I64, 16, Word16)          \
600   V(I64, 32, Word32)          \
601   V(F32, , Float32)           \
602   V(F64, , Float64)           \
603   V(S128, , Simd128)
604 
605 class StoreType {
606  public:
607   enum StoreTypeValue : uint8_t {
608 #define DEF_ENUM(type, suffix, ...) k##type##Store##suffix,
609     FOREACH_STORE_TYPE(DEF_ENUM)
610 #undef DEF_ENUM
611   };
612 
613   // Allow implicit convertion of the enum value to this wrapper.
StoreType(StoreTypeValue val)614   constexpr StoreType(StoreTypeValue val)  // NOLINT(runtime/explicit)
615       : val_(val) {}
616 
value()617   constexpr StoreTypeValue value() const { return val_; }
size_log_2()618   constexpr unsigned size_log_2() const { return kStoreSizeLog2[val_]; }
size()619   constexpr unsigned size() const { return 1 << size_log_2(); }
value_type()620   constexpr ValueType value_type() const { return kValueType[val_]; }
mem_rep()621   constexpr MachineRepresentation mem_rep() const { return kMemRep[val_]; }
622 
ForValueType(ValueType type)623   static StoreType ForValueType(ValueType type) {
624     switch (type.kind()) {
625       case ValueType::kI32:
626         return kI32Store;
627       case ValueType::kI64:
628         return kI64Store;
629       case ValueType::kF32:
630         return kF32Store;
631       case ValueType::kF64:
632         return kF64Store;
633       case ValueType::kS128:
634         return kS128Store;
635       default:
636         UNREACHABLE();
637     }
638   }
639 
640  private:
641   const StoreTypeValue val_;
642 
643   static constexpr uint8_t kStoreSizeLog2[] = {
644   // MSVC wants a static_cast here.
645 #define STORE_SIZE(_, __, memrep) \
646   static_cast<uint8_t>(ElementSizeLog2Of(MachineRepresentation::k##memrep)),
647       FOREACH_STORE_TYPE(STORE_SIZE)
648 #undef STORE_SIZE
649   };
650 
651   static constexpr ValueType kValueType[] = {
652 #define VALUE_TYPE(type, ...) ValueType::Primitive(ValueType::k##type),
653       FOREACH_STORE_TYPE(VALUE_TYPE)
654 #undef VALUE_TYPE
655   };
656 
657   static constexpr MachineRepresentation kMemRep[] = {
658 #define MEMREP(_, __, memrep) MachineRepresentation::k##memrep,
659       FOREACH_STORE_TYPE(MEMREP)
660 #undef MEMREP
661   };
662 };
663 
664 }  // namespace wasm
665 }  // namespace internal
666 }  // namespace v8
667 
668 #endif  // V8_WASM_VALUE_TYPE_H_
669