1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 *
4 * Copyright 2021 Mozilla Foundation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #ifndef wasm_valtype_h
20 #define wasm_valtype_h
21
22 #include "mozilla/Maybe.h"
23
24 #include <type_traits>
25
26 #include "jit/IonTypes.h"
27 #include "wasm/WasmConstants.h"
28 #include "wasm/WasmTypeDecls.h"
29
30 namespace js {
31 namespace wasm {
32
33 using mozilla::Maybe;
34
35 // A PackedTypeCode represents any value type in an compact POD format.
36 union PackedTypeCode {
37 public:
38 using PackedRepr = uintptr_t;
39
40 private:
41 #ifdef JS_64BIT
42 static constexpr size_t PointerTagBits = 2;
43 static constexpr size_t TypeCodeBits = 8;
44 static constexpr size_t TypeIndexBits = 21;
45 static constexpr size_t NullableBits = 1;
46 static constexpr size_t RttDepthBits = 10;
47 #else
48 static constexpr size_t PointerTagBits = 2;
49 static constexpr size_t TypeCodeBits = 8;
50 static constexpr size_t TypeIndexBits = 14;
51 static constexpr size_t NullableBits = 1;
52 static constexpr size_t RttDepthBits = 7;
53 #endif
54
55 static_assert(PointerTagBits + TypeCodeBits + TypeIndexBits + NullableBits +
56 RttDepthBits <=
57 (sizeof(PackedRepr) * 8),
58 "enough bits");
59 static_assert(MaxTypeIndex < (1 << TypeIndexBits), "enough bits");
60 static_assert(MaxRttDepth < (1 << RttDepthBits), "enough bits");
61
62 PackedRepr bits_;
63 struct {
64 PackedRepr pointerTag_ : PointerTagBits;
65 PackedRepr typeCode_ : TypeCodeBits;
66 PackedRepr typeIndex_ : TypeIndexBits;
67 PackedRepr nullable_ : NullableBits;
68 PackedRepr rttDepth_ : RttDepthBits;
69 };
70
71 public:
72 static constexpr uint32_t NoTypeCode = (1 << TypeCodeBits) - 1;
73 static constexpr uint32_t NoTypeIndex = (1 << TypeIndexBits) - 1;
74
invalid()75 static PackedTypeCode invalid() {
76 PackedTypeCode ptc = {};
77 ptc.typeCode_ = NoTypeCode;
78 return ptc;
79 }
80
fromBits(PackedRepr bits)81 static constexpr PackedTypeCode fromBits(PackedRepr bits) {
82 PackedTypeCode ptc = {};
83 ptc.bits_ = bits;
84 return ptc;
85 }
86
pack(TypeCode tc,uint32_t refTypeIndex,bool isNullable,uint32_t rttDepth)87 static constexpr PackedTypeCode pack(TypeCode tc, uint32_t refTypeIndex,
88 bool isNullable, uint32_t rttDepth) {
89 MOZ_ASSERT(uint32_t(tc) <= ((1 << TypeCodeBits) - 1));
90 MOZ_ASSERT_IF(tc != AbstractReferenceTypeIndexCode && tc != TypeCode::Rtt,
91 refTypeIndex == NoTypeIndex);
92 MOZ_ASSERT_IF(tc == AbstractReferenceTypeIndexCode || tc == TypeCode::Rtt,
93 refTypeIndex <= MaxTypeIndex);
94 MOZ_ASSERT_IF(tc != TypeCode::Rtt, rttDepth == 0);
95 MOZ_ASSERT_IF(tc == TypeCode::Rtt, rttDepth <= MaxRttDepth);
96 PackedTypeCode ptc = {};
97 ptc.typeCode_ = PackedRepr(tc);
98 ptc.typeIndex_ = refTypeIndex;
99 ptc.nullable_ = isNullable;
100 ptc.rttDepth_ = rttDepth;
101 return ptc;
102 }
103
pack(TypeCode tc,bool nullable)104 static constexpr PackedTypeCode pack(TypeCode tc, bool nullable) {
105 return pack(tc, PackedTypeCode::NoTypeIndex, nullable, 0);
106 }
107
pack(TypeCode tc)108 static constexpr PackedTypeCode pack(TypeCode tc) {
109 return pack(tc, PackedTypeCode::NoTypeIndex, false, 0);
110 }
111
isValid()112 bool isValid() const { return typeCode_ != NoTypeCode; }
113
isReference()114 bool isReference() const {
115 return typeCodeAbstracted() == AbstractReferenceTypeCode;
116 }
117
bits()118 PackedRepr bits() const { return bits_; }
119
typeCode()120 TypeCode typeCode() const {
121 MOZ_ASSERT(isValid());
122 return TypeCode(typeCode_);
123 }
124
125 // Return the TypeCode, but return AbstractReferenceTypeCode for any reference
126 // type.
127 //
128 // This function is very, very hot, hence what would normally be a switch on
129 // the value `c` to map the reference types to AbstractReferenceTypeCode has
130 // been distilled into a simple comparison; this is fastest. Should type
131 // codes become too complicated for this to work then a lookup table also has
132 // better performance than a switch.
133 //
134 // An alternative is for the PackedTypeCode to represent something closer to
135 // what ValType needs, so that this decoding step is not necessary, but that
136 // moves complexity elsewhere, and the perf gain here would be only about 1%
137 // for baseline compilation throughput.
138 //
139 // TODO: with rtt types this is no longer a simple comparison, we should
140 // re-evaluate the performance of this function.
typeCodeAbstracted()141 TypeCode typeCodeAbstracted() const {
142 MOZ_ASSERT(isValid());
143 TypeCode tc = TypeCode(typeCode_);
144 return (tc < LowestPrimitiveTypeCode && tc != TypeCode::Rtt)
145 ? AbstractReferenceTypeCode
146 : tc;
147 }
148
typeIndex()149 uint32_t typeIndex() const {
150 MOZ_ASSERT(isValid());
151 return uint32_t(typeIndex_);
152 }
153
typeIndexUnchecked()154 uint32_t typeIndexUnchecked() const {
155 MOZ_ASSERT(isValid());
156 return uint32_t(typeIndex_);
157 }
158
isNullable()159 bool isNullable() const {
160 MOZ_ASSERT(isValid());
161 return bool(nullable_);
162 }
163
rttDepth()164 uint32_t rttDepth() const {
165 MOZ_ASSERT(isValid());
166 return uint32_t(rttDepth_);
167 }
168
asNonNullable()169 PackedTypeCode asNonNullable() const {
170 MOZ_ASSERT(isReference());
171 PackedTypeCode mutated = *this;
172 mutated.nullable_ = 0;
173 return mutated;
174 }
175
176 bool operator==(const PackedTypeCode& rhs) const {
177 return bits_ == rhs.bits_;
178 }
179 bool operator!=(const PackedTypeCode& rhs) const {
180 return bits_ != rhs.bits_;
181 }
182 };
183
184 static_assert(sizeof(PackedTypeCode) == sizeof(uintptr_t), "packed");
185 static_assert(std::is_pod_v<PackedTypeCode>,
186 "must be POD to be simply serialized/deserialized");
187
188 // An enum that describes the representation classes for tables; The table
189 // element type is mapped into this by Table::repr().
190
191 enum class TableRepr { Ref, Func };
192
193 // The RefType carries more information about types t for which t.isReference()
194 // is true.
195
196 class RefType {
197 public:
198 enum Kind {
199 Func = uint8_t(TypeCode::FuncRef),
200 Extern = uint8_t(TypeCode::ExternRef),
201 Eq = uint8_t(TypeCode::EqRef),
202 TypeIndex = uint8_t(AbstractReferenceTypeIndexCode)
203 };
204
205 private:
206 PackedTypeCode ptc_;
207
208 #ifdef DEBUG
isValid()209 bool isValid() const {
210 switch (ptc_.typeCode()) {
211 case TypeCode::FuncRef:
212 case TypeCode::ExternRef:
213 case TypeCode::EqRef:
214 MOZ_ASSERT(ptc_.typeIndex() == PackedTypeCode::NoTypeIndex);
215 return true;
216 case AbstractReferenceTypeIndexCode:
217 MOZ_ASSERT(ptc_.typeIndex() != PackedTypeCode::NoTypeIndex);
218 return true;
219 default:
220 return false;
221 }
222 }
223 #endif
RefType(Kind kind,bool nullable)224 RefType(Kind kind, bool nullable)
225 : ptc_(PackedTypeCode::pack(TypeCode(kind), nullable)) {
226 MOZ_ASSERT(isValid());
227 }
228
RefType(uint32_t refTypeIndex,bool nullable)229 RefType(uint32_t refTypeIndex, bool nullable)
230 : ptc_(PackedTypeCode::pack(AbstractReferenceTypeIndexCode, refTypeIndex,
231 nullable, 0)) {
232 MOZ_ASSERT(isValid());
233 }
234
235 public:
RefType()236 RefType() : ptc_(PackedTypeCode::invalid()) {}
RefType(PackedTypeCode ptc)237 explicit RefType(PackedTypeCode ptc) : ptc_(ptc) { MOZ_ASSERT(isValid()); }
238
fromTypeCode(TypeCode tc,bool nullable)239 static RefType fromTypeCode(TypeCode tc, bool nullable) {
240 MOZ_ASSERT(tc != AbstractReferenceTypeIndexCode);
241 return RefType(Kind(tc), nullable);
242 }
243
fromTypeIndex(uint32_t refTypeIndex,bool nullable)244 static RefType fromTypeIndex(uint32_t refTypeIndex, bool nullable) {
245 return RefType(refTypeIndex, nullable);
246 }
247
kind()248 Kind kind() const { return Kind(ptc_.typeCode()); }
249
typeIndex()250 uint32_t typeIndex() const { return ptc_.typeIndex(); }
251
packed()252 PackedTypeCode packed() const { return ptc_; }
253
func()254 static RefType func() { return RefType(Func, true); }
extern_()255 static RefType extern_() { return RefType(Extern, true); }
eq()256 static RefType eq() { return RefType(Eq, true); }
257
isFunc()258 bool isFunc() const { return kind() == RefType::Func; }
isExtern()259 bool isExtern() const { return kind() == RefType::Extern; }
isEq()260 bool isEq() const { return kind() == RefType::Eq; }
isTypeIndex()261 bool isTypeIndex() const { return kind() == RefType::TypeIndex; }
262
isNullable()263 bool isNullable() const { return bool(ptc_.isNullable()); }
asNonNullable()264 RefType asNonNullable() const { return RefType(ptc_.asNonNullable()); }
265
tableRepr()266 TableRepr tableRepr() const {
267 switch (kind()) {
268 case RefType::Func:
269 return TableRepr::Func;
270 case RefType::Extern:
271 case RefType::Eq:
272 return TableRepr::Ref;
273 case RefType::TypeIndex:
274 MOZ_CRASH("NYI");
275 }
276 MOZ_CRASH("switch is exhaustive");
277 }
278
279 bool operator==(const RefType& that) const { return ptc_ == that.ptc_; }
280 bool operator!=(const RefType& that) const { return ptc_ != that.ptc_; }
281 };
282
283 class FieldTypeTraits {
284 public:
285 enum Kind {
286 I8 = uint8_t(TypeCode::I8),
287 I16 = uint8_t(TypeCode::I16),
288 I32 = uint8_t(TypeCode::I32),
289 I64 = uint8_t(TypeCode::I64),
290 F32 = uint8_t(TypeCode::F32),
291 F64 = uint8_t(TypeCode::F64),
292 V128 = uint8_t(TypeCode::V128),
293 Rtt = uint8_t(TypeCode::Rtt),
294 Ref = uint8_t(AbstractReferenceTypeCode),
295 };
296
isValidTypeCode(TypeCode tc)297 static bool isValidTypeCode(TypeCode tc) {
298 switch (tc) {
299 #ifdef ENABLE_WASM_GC
300 case TypeCode::I8:
301 case TypeCode::I16:
302 #endif
303 case TypeCode::I32:
304 case TypeCode::I64:
305 case TypeCode::F32:
306 case TypeCode::F64:
307 #ifdef ENABLE_WASM_SIMD
308 case TypeCode::V128:
309 #endif
310 case TypeCode::FuncRef:
311 case TypeCode::ExternRef:
312 #ifdef ENABLE_WASM_GC
313 case TypeCode::EqRef:
314 case TypeCode::Rtt:
315 #endif
316 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
317 case AbstractReferenceTypeIndexCode:
318 #endif
319 return true;
320 default:
321 return false;
322 }
323 }
324 };
325
326 class ValTypeTraits {
327 public:
328 enum Kind {
329 I32 = uint8_t(TypeCode::I32),
330 I64 = uint8_t(TypeCode::I64),
331 F32 = uint8_t(TypeCode::F32),
332 F64 = uint8_t(TypeCode::F64),
333 V128 = uint8_t(TypeCode::V128),
334 Rtt = uint8_t(TypeCode::Rtt),
335 Ref = uint8_t(AbstractReferenceTypeCode),
336 };
337
isValidTypeCode(TypeCode tc)338 static bool isValidTypeCode(TypeCode tc) {
339 switch (tc) {
340 case TypeCode::I32:
341 case TypeCode::I64:
342 case TypeCode::F32:
343 case TypeCode::F64:
344 #ifdef ENABLE_WASM_SIMD
345 case TypeCode::V128:
346 #endif
347 case TypeCode::FuncRef:
348 case TypeCode::ExternRef:
349 #ifdef ENABLE_WASM_GC
350 case TypeCode::EqRef:
351 case TypeCode::Rtt:
352 #endif
353 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
354 case AbstractReferenceTypeIndexCode:
355 #endif
356 return true;
357 default:
358 return false;
359 }
360 }
361 };
362
363 // The PackedType represents the storage type of a WebAssembly location, whether
364 // parameter, local, field, or global. See specializations below for ValType and
365 // FieldType.
366
367 template <class T>
368 class PackedType : public T {
369 public:
370 using Kind = typename T::Kind;
371
372 protected:
373 PackedTypeCode tc_;
374
PackedType(TypeCode c)375 explicit PackedType(TypeCode c) : tc_(PackedTypeCode::pack(c)) {
376 MOZ_ASSERT(c != AbstractReferenceTypeIndexCode);
377 MOZ_ASSERT(isValid());
378 }
379
typeCode()380 TypeCode typeCode() const {
381 MOZ_ASSERT(isValid());
382 return tc_.typeCode();
383 }
384
385 public:
PackedType()386 PackedType() : tc_(PackedTypeCode::invalid()) {}
387
PackedType(Kind c)388 MOZ_IMPLICIT PackedType(Kind c) : tc_(PackedTypeCode::pack(TypeCode(c))) {
389 MOZ_ASSERT(c != Kind::Ref);
390 MOZ_ASSERT(isValid());
391 }
392
PackedType(RefType rt)393 MOZ_IMPLICIT PackedType(RefType rt) : tc_(rt.packed()) {
394 MOZ_ASSERT(isValid());
395 }
396
PackedType(PackedTypeCode ptc)397 explicit PackedType(PackedTypeCode ptc) : tc_(ptc) { MOZ_ASSERT(isValid()); }
398
PackedType(jit::MIRType mty)399 explicit PackedType(jit::MIRType mty) {
400 switch (mty) {
401 case jit::MIRType::Int32:
402 tc_ = PackedTypeCode::pack(TypeCode::I32);
403 break;
404 case jit::MIRType::Int64:
405 tc_ = PackedTypeCode::pack(TypeCode::I64);
406 break;
407 case jit::MIRType::Float32:
408 tc_ = PackedTypeCode::pack(TypeCode::F32);
409 break;
410 case jit::MIRType::Double:
411 tc_ = PackedTypeCode::pack(TypeCode::F64);
412 break;
413 case jit::MIRType::Simd128:
414 tc_ = PackedTypeCode::pack(TypeCode::V128);
415 break;
416 default:
417 MOZ_CRASH("PackedType(MIRType): unexpected type");
418 }
419 }
420
fromNonRefTypeCode(TypeCode tc)421 static PackedType fromNonRefTypeCode(TypeCode tc) {
422 #ifdef DEBUG
423 switch (tc) {
424 case TypeCode::I8:
425 case TypeCode::I16:
426 case TypeCode::I32:
427 case TypeCode::I64:
428 case TypeCode::F32:
429 case TypeCode::F64:
430 case TypeCode::V128:
431 break;
432 default:
433 MOZ_CRASH("Bad type code");
434 }
435 #endif
436 return PackedType(tc);
437 }
438
fromRtt(uint32_t typeIndex,uint32_t rttDepth)439 static PackedType fromRtt(uint32_t typeIndex, uint32_t rttDepth) {
440 return PackedType(
441 PackedTypeCode::pack(TypeCode::Rtt, typeIndex, false, rttDepth));
442 }
443
fromBitsUnsafe(uint64_t bits)444 static PackedType fromBitsUnsafe(uint64_t bits) {
445 return PackedType(PackedTypeCode::fromBits(bits));
446 }
447
hostPtr()448 static constexpr PackedType hostPtr() {
449 #ifdef JS_64BIT
450 return PackedType::I64;
451 #else
452 return PackedType::I32;
453 #endif
454 }
455
isValid()456 bool isValid() const {
457 if (!tc_.isValid()) {
458 return false;
459 }
460 return T::isValidTypeCode(tc_.typeCode());
461 }
462
packed()463 PackedTypeCode packed() const {
464 MOZ_ASSERT(isValid());
465 return tc_;
466 }
467
bitsUnsafe()468 uint64_t bitsUnsafe() const {
469 MOZ_ASSERT(isValid());
470 return tc_.bits();
471 }
472
isFuncRef()473 bool isFuncRef() const { return tc_.typeCode() == TypeCode::FuncRef; }
474
isExternRef()475 bool isExternRef() const { return tc_.typeCode() == TypeCode::ExternRef; }
476
isEqRef()477 bool isEqRef() const { return tc_.typeCode() == TypeCode::EqRef; }
478
isTypeIndex()479 bool isTypeIndex() const {
480 MOZ_ASSERT(isValid());
481 return tc_.typeCode() == AbstractReferenceTypeIndexCode;
482 }
483
isReference()484 bool isReference() const {
485 MOZ_ASSERT(isValid());
486 return tc_.isReference();
487 }
488
isRtt()489 bool isRtt() const { return tc_.typeCode() == TypeCode::Rtt; }
490
491 // Returns whether the type has a default value.
isDefaultable()492 bool isDefaultable() const {
493 MOZ_ASSERT(isValid());
494 return !(isRtt() || (isReference() && !isNullable()));
495 }
496
497 // Returns whether the type has a representation in JS.
isExposable()498 bool isExposable() const {
499 MOZ_ASSERT(isValid());
500 #if defined(ENABLE_WASM_SIMD) || defined(ENABLE_WASM_GC)
501 return !(kind() == Kind::V128 || isRtt() || isTypeIndex());
502 #else
503 return true;
504 #endif
505 }
506
isNullable()507 bool isNullable() const {
508 MOZ_ASSERT(isValid());
509 return tc_.isNullable();
510 }
511
typeIndex()512 uint32_t typeIndex() const {
513 MOZ_ASSERT(isValid());
514 return tc_.typeIndex();
515 }
516
rttDepth()517 uint32_t rttDepth() const {
518 MOZ_ASSERT(isValid());
519 return tc_.rttDepth();
520 }
521
kind()522 Kind kind() const {
523 MOZ_ASSERT(isValid());
524 return Kind(tc_.typeCodeAbstracted());
525 }
526
refType()527 RefType refType() const {
528 MOZ_ASSERT(isReference());
529 return RefType(tc_);
530 }
531
refTypeKind()532 RefType::Kind refTypeKind() const {
533 MOZ_ASSERT(isReference());
534 return RefType(tc_).kind();
535 }
536
renumber(const RenumberMap & map)537 void renumber(const RenumberMap& map) {
538 if (!isTypeIndex()) {
539 return;
540 }
541
542 if (RenumberMap::Ptr p = map.lookup(refType().typeIndex())) {
543 *this = RefType::fromTypeIndex(p->value(), isNullable());
544 }
545 }
546
offsetTypeIndex(uint32_t offsetBy)547 void offsetTypeIndex(uint32_t offsetBy) {
548 if (!isTypeIndex()) {
549 return;
550 }
551 *this =
552 RefType::fromTypeIndex(refType().typeIndex() + offsetBy, isNullable());
553 }
554
555 // Some types are encoded as JS::Value when they escape from Wasm (when passed
556 // as parameters to imports or returned from exports). For ExternRef the
557 // Value encoding is pretty much a requirement. For other types it's a choice
558 // that may (temporarily) simplify some code.
isEncodedAsJSValueOnEscape()559 bool isEncodedAsJSValueOnEscape() const {
560 switch (typeCode()) {
561 case TypeCode::FuncRef:
562 case TypeCode::ExternRef:
563 case TypeCode::EqRef:
564 return true;
565 default:
566 return false;
567 }
568 }
569
size()570 uint32_t size() const {
571 switch (tc_.typeCodeAbstracted()) {
572 case TypeCode::I8:
573 return 1;
574 case TypeCode::I16:
575 return 2;
576 case TypeCode::I32:
577 return 4;
578 case TypeCode::I64:
579 return 8;
580 case TypeCode::F32:
581 return 4;
582 case TypeCode::F64:
583 return 8;
584 case TypeCode::V128:
585 return 16;
586 case TypeCode::Rtt:
587 case AbstractReferenceTypeCode:
588 return sizeof(void*);
589 default:
590 MOZ_ASSERT_UNREACHABLE();
591 return 0;
592 }
593 }
alignmentInStruct()594 uint32_t alignmentInStruct() const { return size(); }
indexingShift()595 uint32_t indexingShift() const {
596 switch (size()) {
597 case 1:
598 return 0;
599 case 2:
600 return 1;
601 case 4:
602 return 2;
603 case 8:
604 return 3;
605 case 16:
606 return 4;
607 default:
608 MOZ_ASSERT_UNREACHABLE();
609 return 0;
610 }
611 }
612
widenToValType()613 PackedType<ValTypeTraits> widenToValType() const {
614 switch (tc_.typeCodeAbstracted()) {
615 case TypeCode::I8:
616 case TypeCode::I16:
617 return PackedType<ValTypeTraits>::I32;
618 default:
619 return PackedType<ValTypeTraits>(tc_);
620 }
621 }
622
valType()623 PackedType<ValTypeTraits> valType() const {
624 MOZ_ASSERT(isValType());
625 return PackedType<ValTypeTraits>(tc_);
626 }
627
isValType()628 bool isValType() const {
629 switch (tc_.typeCode()) {
630 case TypeCode::I8:
631 case TypeCode::I16:
632 return false;
633 default:
634 return true;
635 }
636 }
637
638 bool operator==(const PackedType& that) const {
639 MOZ_ASSERT(isValid() && that.isValid());
640 return tc_ == that.tc_;
641 }
642
643 bool operator!=(const PackedType& that) const {
644 MOZ_ASSERT(isValid() && that.isValid());
645 return tc_ != that.tc_;
646 }
647
648 bool operator==(Kind that) const {
649 MOZ_ASSERT(isValid());
650 MOZ_ASSERT(that != Kind::Ref);
651 return Kind(typeCode()) == that;
652 }
653
654 bool operator!=(Kind that) const { return !(*this == that); }
655 };
656
657 using ValType = PackedType<ValTypeTraits>;
658 using FieldType = PackedType<FieldTypeTraits>;
659
660 // The dominant use of this data type is for locals and args, and profiling
661 // with ZenGarden and Tanks suggests an initial size of 16 minimises heap
662 // allocation, both in terms of blocks and bytes.
663 using ValTypeVector = Vector<ValType, 16, SystemAllocPolicy>;
664
665 // ValType utilities
666
SizeOf(ValType vt)667 static inline unsigned SizeOf(ValType vt) {
668 switch (vt.kind()) {
669 case ValType::I32:
670 case ValType::F32:
671 return 4;
672 case ValType::I64:
673 case ValType::F64:
674 return 8;
675 case ValType::V128:
676 return 16;
677 case ValType::Rtt:
678 case ValType::Ref:
679 return sizeof(intptr_t);
680 }
681 MOZ_CRASH("Invalid ValType");
682 }
683
684 // Note, ToMIRType is only correct within Wasm, where an AnyRef is represented
685 // as a pointer. At the JS/wasm boundary, an AnyRef can be represented as a
686 // JS::Value, and the type translation may have to be handled specially and on a
687 // case-by-case basis.
688
ToMIRType(ValType vt)689 static inline jit::MIRType ToMIRType(ValType vt) {
690 switch (vt.kind()) {
691 case ValType::I32:
692 return jit::MIRType::Int32;
693 case ValType::I64:
694 return jit::MIRType::Int64;
695 case ValType::F32:
696 return jit::MIRType::Float32;
697 case ValType::F64:
698 return jit::MIRType::Double;
699 case ValType::V128:
700 return jit::MIRType::Simd128;
701 case ValType::Rtt:
702 case ValType::Ref:
703 return jit::MIRType::RefOrNull;
704 }
705 MOZ_CRASH("bad type");
706 }
707
IsNumberType(ValType vt)708 static inline bool IsNumberType(ValType vt) { return !vt.isReference(); }
709
ToMIRType(const Maybe<ValType> & t)710 static inline jit::MIRType ToMIRType(const Maybe<ValType>& t) {
711 return t ? ToMIRType(ValType(t.ref())) : jit::MIRType::None;
712 }
713
714 extern bool ToValType(JSContext* cx, HandleValue v, ValType* out);
715
716 extern UniqueChars ToString(ValType type);
717
718 extern UniqueChars ToString(const Maybe<ValType>& type);
719
720 } // namespace wasm
721 } // namespace js
722
723 #endif // wasm_valtype_h
724