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