v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
tagged.h
Go to the documentation of this file.
1// Copyright 2023 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_OBJECTS_TAGGED_H_
6#define V8_OBJECTS_TAGGED_H_
7
8#include <type_traits>
9
10#include "src/common/globals.h"
12#include "src/objects/union.h"
13
14namespace v8 {
15namespace internal {
16
17class BigInt;
18class FieldType;
19class HeapObject;
20class HeapNumber;
21class HeapObjectLayout;
22class TrustedObject;
23class TrustedObjectLayout;
24class Object;
25class TaggedIndex;
26class Smi;
27
28// Tagged<T> represents an uncompressed V8 tagged pointer.
29//
30// The tagged pointer is a pointer-sized value with a tag in the LSB. The value
31// is either:
32//
33// * A small integer (Smi), shifted right, with the tag set to 0
34// * A strong pointer to an object on the V8 heap, with the tag set to 01
35// * A weak pointer to an object on the V8 heap, with the tag set to 11
36// * A cleared weak pointer, with the value 11
37//
38// The exact encoding differs depending on 32- vs 64-bit architectures, and in
39// the latter case, whether or not pointer compression is enabled.
40//
41// On 32-bit architectures, this is:
42// |----- 32 bits -----|
43// Pointer: |______address____w1|
44// Smi: |____int31_value___0|
45//
46// On 64-bit architectures with pointer compression:
47// |----- 32 bits -----|----- 32 bits -----|
48// Pointer: |________base_______|______offset_____w1|
49// Smi: |......garbage......|____int31_value___0|
50//
51// On 64-bit architectures without pointer compression:
52// |----- 32 bits -----|----- 32 bits -----|
53// Pointer: |________________address______________w1|
54// Smi: |____int32_value____|00...............00|
55//
56// where `w` is the "weak" bit.
57//
58// We specialise Tagged separately for Object, Smi and HeapObject, and then all
59// other types T, so that:
60//
61// Tagged<Object> -> StrongTaggedBase
62// Tagged<Smi> -> StrongTaggedBase
63// Tagged<T> -> Tagged<HeapObject> -> StrongTaggedBase
64//
65// We also specialize it separately for MaybeWeak types, with a parallel
66// hierarchy:
67//
68// Tagged<MaybeWeak<Object>> -> WeakTaggedBase
69// Tagged<MaybeWeak<Smi>> -> WeakTaggedBase
70// Tagged<MaybeWeak<T>> -> Tagged<MaybeWeak<HeapObject>> -> WeakTaggedBase
71template <typename T>
72class Tagged;
73
74// MaybeWeak<T> represents a reference to T that may be either a strong or weak.
75//
76// MaybeWeak doesn't really exist by itself, but is rather a sentinel type for
77// templates on tagged interfaces (like Tagged). For example, where Tagged<T>
78// represents a strong reference to T, Tagged<MaybeWeak<T>> represents a
79// potentially weak reference to T, and it is the responsibility of the Tagged
80// interface to provide some mechanism (likely template specialization) to
81// distinguish between the two and provide accessors to the T reference itself
82// (which will always be strong).
83template <typename T>
84class MaybeWeak {};
85
86template <typename T>
87struct is_maybe_weak : public std::false_type {};
88template <typename T>
89struct is_maybe_weak<MaybeWeak<T>> : public std::true_type {};
90template <typename... T>
91struct is_maybe_weak<Union<T...>>
92 : public std::disjunction<is_maybe_weak<T>...> {};
93template <typename T>
95
96// ClearedWeakValue is a sentinel type for cleared weak values.
98
99// Convert a strong reference to T into a weak reference to T.
100template <typename T>
102template <typename T>
104
105// Convert a weak reference to T into a strong reference to T.
106template <typename T>
107inline Tagged<T> MakeStrong(Tagged<T> value);
108template <typename T>
110
111// Base class for all Tagged<T> classes.
114
115// `is_subtype<Derived, Base>::value` is true when Derived is a subtype of Base
116// according to our object hierarchy. In particular, Smi is considered a
117// subtype of Object.
118template <typename Derived, typename Base, typename Enabled = void>
119struct is_subtype;
120template <typename Derived, typename Base>
122
123namespace detail {
124template <typename Derived, typename Base, typename Enabled = void>
125struct is_simple_subtype;
126template <typename Derived, typename Base, typename Enabled = void>
127struct is_complex_subtype;
128} // namespace detail
129
130// `is_subtype<Derived, Base>` tries is_simple_subtype first, and if that fails,
131// is_complex_subtype. This is to prevent instantiating the is_complex_subtype
132// template when is_simple_subtype, to avoid trying std::is_base_of. This allows
133// subtype checks to pass, for simple subtypes, with forward declarations.
134template <typename Derived, typename Base, typename Enabled>
136 : public std::disjunction<detail::is_simple_subtype<Derived, Base>,
137 detail::is_complex_subtype<Derived, Base>> {};
138
139// Forward declarations for is_simple_subtype hack, remove once those
140// specializations are removed.
141class FixedArrayBase;
142class FixedArray;
143class FixedDoubleArray;
144class ByteArray;
145class NameDictionary;
146class NumberDictionary;
147class OrderedHashMap;
148class OrderedHashSet;
151class ArrayList;
153
154namespace detail {
155// `is_simple_subtype<Derived, Base>::value` is true when Derived is a simple
156// subtype of Base according to our object hierarchy, in a way that doesn't
157// require object definitions (in particular, we don't need to known anything
158// about C++ base classes). False, in this case, doesn't mean "not a subtype",
159// it just means "not a _simple_ subtype".
160template <typename Derived, typename Base, typename Enabled>
161struct is_simple_subtype : public std::false_type {};
162template <typename Derived, typename Base>
163static constexpr bool is_simple_subtype_v =
165
166template <typename T>
167struct is_simple_subtype<T, T> : public std::true_type {};
168template <>
169struct is_simple_subtype<Object, Object> : public std::true_type {};
170template <>
171struct is_simple_subtype<Smi, Object> : public std::true_type {};
172template <>
173struct is_simple_subtype<TaggedIndex, Object> : public std::true_type {};
174template <>
175struct is_simple_subtype<FieldType, Object> : public std::true_type {};
176template <>
177struct is_simple_subtype<HeapObject, Object> : public std::true_type {};
178template <>
179struct is_simple_subtype<HeapObjectLayout, Object> : public std::true_type {};
180template <typename T>
181struct is_simple_subtype<T, MaybeWeak<T>> : public std::true_type {};
182template <typename T>
183struct is_simple_subtype<MaybeWeak<T>, MaybeWeak<T>> : public std::true_type {};
184template <typename T>
186 : public std::true_type {};
187template <>
188struct is_simple_subtype<Smi, MaybeWeak<Object>> : public std::true_type {};
189
190// Special case to match Torque's idea of Object/MaybeObject against the C++
191// one.
192// TODO(leszeks): Clean up what types torque and C++ consider to be unions of
193// other types.
194template <>
197 : public std::true_type {};
198template <>
200 : public std::true_type {};
201template <>
203 : public std::true_type {};
204
205// Specializations of is_simple_subtype for Union, which allows for trivial
206// subtype checks of Unions without recursing into the full is_subtype trait,
207// which might require object definitions.
208//
209// A couple of redundant looking specializations are necessary to disambiguate
210// specializations when there are two Unions.
211template <typename Derived, typename... BaseTs>
212struct is_simple_subtype<Derived, Union<BaseTs...>>
213 : public std::disjunction<is_simple_subtype<Derived, BaseTs>...> {};
214template <typename... DerivedTs, typename Base>
215struct is_simple_subtype<Union<DerivedTs...>, Base>
216 : public std::conjunction<is_simple_subtype<DerivedTs, Base>...> {};
217template <typename... DerivedTs, typename... BaseTs>
218struct is_simple_subtype<Union<DerivedTs...>, Union<BaseTs...>>
219 : public std::conjunction<
220 is_simple_subtype<DerivedTs, Union<BaseTs...>>...> {};
221template <typename... Ts>
222struct is_simple_subtype<Union<Ts...>, Union<Ts...>> : public std::true_type {};
223
224// TODO(jgruber): Clean up this artificial FixedArrayBase hierarchy. Only types
225// that can be used as elements should be in it.
226// TODO(jgruber): Replace FixedArrayBase with a union type, once they exist.
227#define DEF_FIXED_ARRAY_SUBTYPE(Subtype) \
228 template <> \
229 struct is_simple_subtype<Subtype, FixedArrayBase> : public std::true_type { \
230 };
231DEF_FIXED_ARRAY_SUBTYPE(FixedArray)
232DEF_FIXED_ARRAY_SUBTYPE(FixedDoubleArray)
234DEF_FIXED_ARRAY_SUBTYPE(NameDictionary)
235DEF_FIXED_ARRAY_SUBTYPE(NumberDictionary)
236DEF_FIXED_ARRAY_SUBTYPE(OrderedHashMap)
237DEF_FIXED_ARRAY_SUBTYPE(OrderedHashSet)
238DEF_FIXED_ARRAY_SUBTYPE(OrderedNameDictionary)
239DEF_FIXED_ARRAY_SUBTYPE(ScriptContextTable)
241DEF_FIXED_ARRAY_SUBTYPE(SloppyArgumentsElements)
242#undef DEF_FIXED_ARRAY_SUBTYPE
243
244// `is_complex_subtype<Derived, Base>::value` is true when Derived is a
245// non-simple subtype of Base according to our object hierarchy, in a way that
246// might require object definitions or recursion into is_subtype (in particular,
247// we do need to know about C++ base classes).
248//
249// This doesn't check the simple cases, so should not be used directly, but
250// only via is_subtype.
251template <typename Derived, typename Base, typename Enabled>
252struct is_complex_subtype : public std::is_base_of<Base, Derived> {};
253template <typename Derived, typename Base>
254static constexpr bool is_complex_subtype_v =
256
257template <typename Derived>
259 Derived, Object,
260 std::enable_if_t<std::conjunction_v<std::negation<is_union<Derived>>,
261 is_subtype<Derived, HeapObject>>>>
262 : public std::true_type {};
263template <typename Derived>
265 std::enable_if_t<std::disjunction_v<
266 std::is_base_of<HeapObject, Derived>,
267 std::is_base_of<HeapObjectLayout, Derived>>>>
268 : public std::true_type {};
269
270template <typename Derived>
272 std::enable_if_t<std::disjunction_v<
273 std::is_base_of<TrustedObject, Derived>,
274 std::is_base_of<TrustedObjectLayout, Derived>>>>
275 : public std::true_type {};
276
277class StructLayout;
278template <typename Derived>
280 std::enable_if_t<std::disjunction_v<
281 std::is_base_of<Struct, Derived>,
282 std::is_base_of<StructLayout, Derived>>>>
283 : public std::true_type {};
284
285template <typename Derived, typename... BaseTs>
286struct is_complex_subtype<Derived, Union<BaseTs...>>
287 : public std::disjunction<is_subtype<Derived, BaseTs>...> {};
288template <typename... DerivedTs, typename Base>
289struct is_complex_subtype<Union<DerivedTs...>, Base>
290 : public std::conjunction<is_subtype<DerivedTs, Base>...> {};
291template <typename... DerivedTs, typename... BaseTs>
292struct is_complex_subtype<Union<DerivedTs...>, Union<BaseTs...>>
293 : public std::conjunction<is_subtype<DerivedTs, Union<BaseTs...>>...> {};
294template <typename Derived, typename Base>
296 Derived, MaybeWeak<Base>,
297 std::enable_if_t<!is_union_v<Derived> && !is_maybe_weak_v<Derived>>>
298 : public is_subtype<Derived, Base> {};
299template <typename Derived, typename Base>
301 : public is_subtype<Derived, Base> {};
302} // namespace detail
303
304static_assert(is_subtype_v<Smi, Object>);
310
311// `is_taggable<T>::value` is true when T is a valid type for Tagged. This means
312// de-facto being a subtype of Object.
313template <typename T>
315template <typename T>
316static constexpr bool is_taggable_v = is_taggable<T>::value;
317
318// `is_castable<From, To>::value` is true when you can use `::cast` to cast from
319// From to To. This means an upcast or downcast, which in practice means
320// checking `is_subtype` symmetrically.
321template <typename From, typename To>
323 std::disjunction<is_subtype<To, From>, is_subtype<From, To>>;
324template <typename From, typename To>
326
327// TODO(leszeks): Remove this once there are no more conversions between
328// Tagged<Foo> and Foo.
329static constexpr bool kTaggedCanConvertToRawObjects = true;
330
331namespace detail {
332
333// {TaggedOperatorArrowRef} is returned by {Tagged::operator->}. It should never
334// be stored anywhere or used in any other code; no one should ever have to
335// spell out {TaggedOperatorArrowRef} in code. Its only purpose is to be
336// dereferenced immediately by "operator-> chaining". Returning the address of
337// the field is valid because this objects lifetime only ends at the end of the
338// full statement.
339template <typename T>
341 public:
342 V8_INLINE constexpr T* operator->() { return &object_; }
343
344 private:
345 friend class Tagged<T>;
346 V8_INLINE constexpr explicit TaggedOperatorArrowRef(T object)
347 : object_(object) {}
349};
350
351template <typename T>
355
356template <typename T>
360
361template <typename... T>
362struct BaseForTagged<Union<T...>> {
363 template <typename U>
365 std::disjunction<std::is_same<U, Smi>, std::is_same<U, Object>,
366 std::is_same<U, TaggedIndex>,
367 std::is_same<U, FieldType>>;
368
369 using type = std::conditional_t<
370 std::disjunction_v<is_maybe_weak<T>...>, WeakTaggedBase,
371 std::conditional_t<std::disjunction_v<is_non_heap_object<T>...>,
373};
374
375// FieldType is special, since it can be Smi or Map. It could probably even be
376// its own specialization, to avoid exposing an operator->.
377template <>
381
382} // namespace detail
383
384// Specialization for Object, where it's unknown whether this is a Smi or a
385// HeapObject.
386template <>
388 public:
389 // Allow Tagged<Object> to be created from any address.
390 V8_INLINE constexpr explicit Tagged(Address o) : StrongTaggedBase(o) {}
391
392 // Allow explicit uninitialized initialization.
393 // TODO(leszeks): Consider zapping this instead, since it's odd that
394 // Tagged<Object> implicitly initialises to Smi::zero().
396
397 // Allow implicit conversion from const HeapObjectLayout* to Tagged<Object>.
398 // TODO(leszeks): Make this more const-correct.
399 // TODO(leszeks): Consider making this an explicit conversion.
400 // NOLINTNEXTLINE
402 : Tagged(reinterpret_cast<Address>(ptr) + kHeapObjectTag) {}
403
404 // Implicit conversion for subclasses -- all classes are subclasses of Object,
405 // so allow all tagged pointers.
406 // NOLINTNEXTLINE
408 : StrongTaggedBase(other.ptr()) {}
410 return *this = Tagged(other);
411 }
412};
413
414// Specialization for Smi disallowing any implicit creation or access via ->,
415// but offering instead a cast from Object and an int32_t value() method.
416template <>
417class Tagged<Smi> : public StrongTaggedBase {
418 public:
419 V8_INLINE constexpr Tagged() = default;
420 V8_INLINE constexpr explicit Tagged(Address ptr) : StrongTaggedBase(ptr) {}
421
422 // No implicit conversions from other tagged pointers.
423
424 V8_INLINE constexpr bool IsHeapObject() const { return false; }
425 V8_INLINE constexpr bool IsSmi() const { return true; }
426
427 V8_INLINE constexpr int32_t value() const {
428 return Internals::SmiValue(ptr());
429 }
430};
431
432// Specialization for TaggedIndex disallowing any implicit creation or access
433// via ->, but offering instead a cast from Object and an intptr_t value()
434// method.
435template <>
437 public:
438 V8_INLINE constexpr Tagged() = default;
439 V8_INLINE constexpr explicit Tagged(Address ptr) : StrongTaggedBase(ptr) {}
440
441 // No implicit conversions from other tagged pointers.
442
443 V8_INLINE constexpr bool IsHeapObject() const { return false; }
444 V8_INLINE constexpr bool IsSmi() const { return true; }
445
446 // Returns the integer value.
447 V8_INLINE constexpr intptr_t value() const {
448 // Truncate and shift down (requires >> to be sign extending).
449 return static_cast<intptr_t>(ptr()) >> kSmiTagSize;
450 }
451
452 // Implicit conversions to/from raw pointers
453 // TODO(leszeks): Remove once we're using Tagged everywhere.
454 // NOLINTNEXTLINE
456
457 private:
458 // Handles of the same type are allowed to access the Address constructor.
459 friend class Handle<TaggedIndex>;
460#ifdef V8_ENABLE_DIRECT_HANDLE
461 friend class DirectHandle<TaggedIndex>;
462#endif
463 template <typename TFieldType, int kFieldOffset, typename CompressionScheme>
464 friend class TaggedField;
465};
466
467// Specialization for HeapObject, to group together functions shared between all
468// HeapObjects
469template <>
472
473 public:
474 V8_INLINE constexpr Tagged() = default;
475 // Allow implicit conversion from const HeapObjectLayout* to
476 // Tagged<HeapObject>.
477 // TODO(leszeks): Make this more const-correct.
478 // TODO(leszeks): Consider making this an explicit conversion.
479 // NOLINTNEXTLINE
481 : Tagged(reinterpret_cast<Address>(ptr) + kHeapObjectTag) {}
482
483 // Implicit conversion for subclasses.
484 template <typename U>
487 {
488 return *this = Tagged(other);
489 }
490
491 // Implicit conversion for subclasses.
492 template <typename U>
493 // NOLINTNEXTLINE
494 V8_INLINE constexpr Tagged(Tagged<U> other)
496 : Base(other) {}
497
498 V8_INLINE constexpr HeapObject operator*() const;
500 const;
501
502 V8_INLINE constexpr bool is_null() const {
503 return static_cast<Tagged_t>(this->ptr()) ==
504 static_cast<Tagged_t>(kNullAddress);
505 }
506
507 constexpr V8_INLINE bool IsHeapObject() const { return true; }
508 constexpr V8_INLINE bool IsSmi() const { return false; }
509
510 // Implicit conversions and explicit casts to/from raw pointers
511 // TODO(leszeks): Remove once we're using Tagged everywhere.
512 template <typename U>
513 // NOLINTNEXTLINE
514 constexpr Tagged(U raw)
515 requires(std::is_base_of_v<HeapObject, U>)
516 : Base(raw.ptr()) {
517 static_assert(kTaggedCanConvertToRawObjects);
518 }
519 template <typename U>
520 static constexpr Tagged<HeapObject> cast(U other) {
521 static_assert(kTaggedCanConvertToRawObjects);
522 return Cast<HeapObject>(Tagged<U>(other));
523 }
524
525 Address address() const { return this->ptr() - kHeapObjectTag; }
526
527 protected:
528 V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {}
529
530 private:
531 friend class HeapObject;
532 // Handles of the same type are allowed to access the Address constructor.
533 friend class Handle<HeapObject>;
534#ifdef V8_ENABLE_DIRECT_HANDLE
535 friend class DirectHandle<HeapObject>;
536#endif
537 template <typename TFieldType, int kFieldOffset, typename CompressionScheme>
538 friend class TaggedField;
539 template <typename To, typename From>
540 friend inline Tagged<To> UncheckedCast(Tagged<From> value);
541
544
545 V8_INLINE constexpr HeapObject ToRawPtr() const;
546};
547
548static_assert(Tagged<HeapObject>().is_null());
549
550// Specialization for MaybeWeak<Object>, where it's unknown whether this is a
551// Smi, a strong HeapObject, or a weak HeapObject
552template <>
554 public:
555 // Allow Tagged<MaybeWeak<Object>> to be created from any address.
556 V8_INLINE constexpr explicit Tagged(Address o) : WeakTaggedBase(o) {}
557
558 // Allow explicit uninitialized initialization.
559 // TODO(leszeks): Consider zapping this instead, since it's odd that
560 // Tagged<MaybeWeak<Object>> implicitly initialises to Smi::zero().
562
563 // Allow implicit conversion from const HeapObjectLayout* to
564 // Tagged<MaybeWeak<Object>>.
565 // TODO(leszeks): Make this more const-correct.
566 // TODO(leszeks): Consider making this an explicit conversion.
567 // NOLINTNEXTLINE
569 : Tagged(reinterpret_cast<Address>(ptr) + kHeapObjectTag) {}
570
571 // Implicit conversion for subclasses -- all classes are subclasses of Object,
572 // so allow all tagged pointers, both weak and strong.
573 // NOLINTNEXTLINE
575 : WeakTaggedBase(other.ptr()) {}
576 // NOLINTNEXTLINE
578 : WeakTaggedBase(other.ptr()) {}
580 return *this = Tagged(other);
581 }
583 return *this = Tagged(other);
584 }
585};
586
587// Specialization for MaybeWeak<HeapObject>, to group together functions shared
588// between all HeapObjects
589template <>
592
593 public:
594 V8_INLINE constexpr Tagged() = default;
595 // Allow implicit conversion from const HeapObjectLayout* to
596 // Tagged<HeapObject>.
597 // TODO(leszeks): Make this more const-correct.
598 // TODO(leszeks): Consider making this an explicit conversion.
599 // NOLINTNEXTLINE
601 : Tagged(reinterpret_cast<Address>(ptr) + kHeapObjectTag) {}
602
603 // Implicit conversion for subclasses.
604 template <typename U>
607 {
608 return *this = Tagged(other);
609 }
610
611 // Implicit conversion for subclasses.
612 template <typename U>
613 // NOLINTNEXTLINE
614 V8_INLINE constexpr Tagged(Tagged<U> other)
616 : Base(other.ptr()) {}
617
618 template <typename U>
619 V8_INLINE explicit constexpr Tagged(Tagged<U> other,
620 HeapObjectReferenceType type)
622 : Base(type == HeapObjectReferenceType::WEAK ? MakeWeak(other)
623 : MakeStrong(other)) {}
624
625 V8_INLINE constexpr bool is_null() const {
626 return static_cast<Tagged_t>(this->ptr()) ==
627 static_cast<Tagged_t>(kNullAddress);
628 }
629
630 constexpr V8_INLINE bool IsSmi() const { return false; }
631
632 protected:
633 V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {}
634
635 private:
636 // Handles of the same type are allowed to access the Address constructor.
637 friend class Handle<MaybeWeak<HeapObject>>;
638#ifdef V8_ENABLE_DIRECT_HANDLE
639 friend class DirectHandle<MaybeWeak<HeapObject>>;
640#endif
641 template <typename TFieldType, int kFieldOffset, typename CompressionScheme>
642 friend class TaggedField;
643 template <typename To, typename From>
644 friend inline Tagged<To> UncheckedCast(Tagged<From> value);
645
649};
650
651// Generic Tagged<T> for Unions. This doesn't allow direct access to the object,
652// aside from casting.
653template <typename... Ts>
654class Tagged<Union<Ts...>> : public detail::BaseForTagged<Union<Ts...>>::type {
655 using This = Union<Ts...>;
657
658 public:
659 V8_INLINE constexpr Tagged() = default;
660
661 // Implicit conversion for subclasses.
662 template <typename U>
664 requires(is_subtype_v<U, This>)
665 {
666 *this = Tagged(other);
667 return *this;
668 }
669
670 // Implicit conversion for subclasses.
671 template <typename U>
672 // NOLINTNEXTLINE
673 V8_INLINE constexpr Tagged(Tagged<U> other)
674 requires(is_subtype_v<U, This>)
675 : Base(other.ptr()) {}
676
677 // Implicit conversions and explicit casts to/from raw pointers
678 // TODO(leszeks): Remove once we're using Tagged everywhere.
679 template <typename U>
680 // NOLINTNEXTLINE
681 V8_INLINE constexpr Tagged(U raw)
682 requires(is_subtype_v<U, This> && std::is_base_of_v<HeapObject, U>)
683 : Base(raw.ptr()) {
684 static_assert(kTaggedCanConvertToRawObjects);
685 }
686
687 private:
688 // Handles of the same type are allowed to access the Address constructor.
689 friend class Handle<This>;
690#ifdef V8_ENABLE_DIRECT_HANDLE
691 friend class DirectHandle<This>;
692#endif
693 template <typename TFieldType, int kFieldOffset, typename CompressionScheme>
694 friend class TaggedField;
695 template <typename TFieldType, typename CompressionScheme>
696 friend class TaggedMember;
697 template <typename To, typename From>
698 friend inline Tagged<To> UncheckedCast(Tagged<From> value);
699
700 V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {}
701};
702
703// Generic Tagged<T> for any T that is a subclass of HeapObject. There are
704// separate Tagged<T> specialaizations for T==Smi and T==Object, so we know that
705// all other Tagged<T> are definitely pointers and not Smis.
706template <typename T>
707class Tagged : public detail::BaseForTagged<T>::type {
709
710 public:
711 V8_INLINE constexpr Tagged() = default;
712 template <typename U = T>
713 // Allow implicit conversion from const T* to Tagged<T>.
714 // TODO(leszeks): Make this more const-correct.
715 // TODO(leszeks): Consider making this an explicit conversion.
716 // NOLINTNEXTLINE
718 : Tagged(reinterpret_cast<Address>(ptr) + kHeapObjectTag) {
719 static_assert(std::is_base_of_v<HeapObjectLayout, U>);
720 }
721
722 // Implicit conversion for subclasses.
723 template <typename U>
725 requires(is_subtype_v<U, T>)
726 {
727 *this = Tagged(other);
728 return *this;
729 }
730
731 // Implicit conversion for subclasses.
732 template <typename U>
733 // NOLINTNEXTLINE
734 V8_INLINE constexpr Tagged(Tagged<U> other)
735 requires(is_subtype_v<U, T>)
736 : Base(other) {}
737
738 V8_INLINE constexpr decltype(auto) operator*() const {
739 // Indirect operator* through a helper, which has a couple of
740 // implementations for old- and new-layout objects, so that gdb only sees
741 // this single operator* overload.
742 return operator_star_impl();
743 }
744 V8_INLINE constexpr decltype(auto) operator->() const {
745 // Indirect operator-> through a helper, which has a couple of
746 // implementations for old- and new-layout objects, so that gdb only sees
747 // this single operator-> overload.
748 return operator_arrow_impl();
749 }
750
751 // Implicit conversions and explicit casts to/from raw pointers
752 // TODO(leszeks): Remove once we're using Tagged everywhere.
753 template <typename U>
754 // NOLINTNEXTLINE
755 V8_INLINE constexpr Tagged(U raw)
756 requires(is_subtype_v<U, T>)
757 : Base(raw.ptr()) {
758 static_assert(kTaggedCanConvertToRawObjects);
759 }
760 template <typename U>
761 static constexpr Tagged<T> cast(U other) {
762 static_assert(kTaggedCanConvertToRawObjects);
763 return Cast<T>(Tagged<U>(other));
764 }
765
766 private:
767 friend T;
768 // Handles of the same type are allowed to access the Address constructor.
769 friend class Handle<T>;
770#ifdef V8_ENABLE_DIRECT_HANDLE
771 friend class DirectHandle<T>;
772#endif
773 template <typename TFieldType, int kFieldOffset, typename CompressionScheme>
774 friend class TaggedField;
775 template <typename TFieldType, typename CompressionScheme>
776 friend class TaggedMember;
777 template <typename To, typename From>
778 friend inline Tagged<To> UncheckedCast(Tagged<From> value);
779
782
783 V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {}
784
786 requires(std::is_base_of_v<HeapObjectLayout, T>)
787 {
788 return *ToRawPtr();
789 }
791 requires(std::is_base_of_v<HeapObjectLayout, T>)
792 {
793 return ToRawPtr();
794 }
795
796 V8_INLINE constexpr T operator_star_impl() const
797 requires(!std::is_base_of_v<HeapObjectLayout, T>)
798 {
799 return ToRawPtr();
800 }
802 const
803 requires(!std::is_base_of_v<HeapObjectLayout, T>)
804 {
806 }
807
808 template <typename U = T>
810 requires(std::is_base_of_v<HeapObjectLayout, U>)
811 {
812 // Check whether T is taggable on raw ptr access rather than top-level, to
813 // allow forward declarations.
814 static_assert(is_taggable_v<T>);
815 return reinterpret_cast<T*>(this->ptr() - kHeapObjectTag);
816 }
817
818 template <typename U = T>
819 V8_INLINE constexpr T ToRawPtr() const
820 requires(!std::is_base_of_v<HeapObjectLayout, U>)
821 {
822 // Check whether T is taggable on raw ptr access rather than top-level, to
823 // allow forward declarations.
824 static_assert(is_taggable_v<T>);
825 return T(this->ptr(), typename T::SkipTypeCheckTag{});
826 }
827};
828
829// Specialized Tagged<T> for cleared weak values. This is only used, in
830// practice, for conversions from Tagged<ClearedWeakValue> to a
831// Tagged<MaybeWeak<T>>, where subtyping rules mean that this works for
832// aribitrary T.
833template <>
835 public:
837};
838
839// Generic Tagged<T> for any T that is a subclass of HeapObject. There are
840// separate Tagged<T> specializations for T==Smi and T==Object, so we know that
841// all other Tagged<T> are definitely pointers and not Smis.
842template <typename T>
843class Tagged<MaybeWeak<T>> : public detail::BaseForTagged<MaybeWeak<T>>::type {
845
846 public:
847 V8_INLINE constexpr Tagged() = default;
848 template <typename U = T>
849 // Allow implicit conversion from const T* to Tagged<MaybeWeak<T>>.
850 // TODO(leszeks): Make this more const-correct.
851 // TODO(leszeks): Consider making this an explicit conversion.
852 // NOLINTNEXTLINE
854 : Tagged(reinterpret_cast<Address>(ptr) + kHeapObjectTag) {
855 static_assert(std::is_base_of_v<HeapObjectLayout, U>);
856 }
857
858 // Implicit conversion for subclasses.
859 template <typename U>
861 requires(is_subtype_v<U, T>)
862 {
863 *this = Tagged(other);
864 return *this;
865 }
866
867 // Implicit conversion for subclasses.
868 template <typename U>
869 // NOLINTNEXTLINE
870 V8_INLINE constexpr Tagged(Tagged<U> other)
871 requires(is_subtype_v<U, T>)
872 : Base(other) {}
873
874 private:
875 V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {}
876
877 friend T;
878 // Handles of the same type are allowed to access the Address constructor.
879 friend class Handle<MaybeWeak<T>>;
880#ifdef V8_ENABLE_DIRECT_HANDLE
881 friend class DirectHandle<MaybeWeak<T>>;
882#endif
885 template <typename To, typename From>
886 friend inline Tagged<To> UncheckedCast(Tagged<From> value);
887};
888
891
892template <typename T>
894 return Tagged<MaybeWeak<T>>(value.ptr() | kWeakHeapObjectTag);
895}
896
897template <typename T>
901
902template <typename T>
904 return Tagged<T>(value.ptr() & (~kWeakHeapObjectTag | kHeapObjectTag));
905}
906
907template <typename T>
909 return Tagged<T>(value.ptr() & (~kWeakHeapObjectTag | kHeapObjectTag));
910}
911
912// Deduction guide to simplify Foo->Tagged<Foo> transition.
913// TODO(leszeks): Remove once we're using Tagged everywhere.
914static_assert(kTaggedCanConvertToRawObjects);
915template <class T>
916Tagged(T object) -> Tagged<T>;
917
919
920template <class T>
921Tagged(const T* object) -> Tagged<T>;
922template <class T>
923Tagged(T* object) -> Tagged<T>;
924
925template <typename T>
927 using type = T;
928};
929
930template <typename T>
932 using type = T;
933};
934
935} // namespace internal
936} // namespace v8
937
938namespace std {
939
940// Template specialize std::common_type to always return Object when compared
941// against a subtype of Object.
942//
943// This is an incomplete specialization for objects and common_type, but
944// sufficient for existing use-cases. A proper specialization would need to be
945// conditionally enabled via `requires`, which is C++20, or with `enable_if`,
946// which would require a custom common_type implementation.
947template <class T>
948struct common_type<T, i::Object> {
949 static_assert(i::is_subtype_v<T, i::Object>,
950 "common_type with Object is only partially specialized.");
952};
953
954} // namespace std
955
956#endif // V8_OBJECTS_TAGGED_H_
#define T
static V8_INLINE constexpr int SmiValue(Address value)
V8_INLINE Tagged(Address ptr)
Definition tagged.h:836
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
constexpr V8_INLINE bool IsHeapObject() const
Definition tagged.h:507
static constexpr Tagged< HeapObject > cast(U other)
Definition tagged.h:520
V8_INLINE constexpr Tagged(Tagged< U > other)
Definition tagged.h:494
constexpr V8_INLINE bool IsSmi() const
Definition tagged.h:508
V8_INLINE constexpr Tagged(Address ptr)
Definition tagged.h:528
V8_INLINE constexpr Tagged & operator=(Tagged< U > other)
Definition tagged.h:485
V8_INLINE Tagged(const HeapObjectLayout *ptr)
Definition tagged.h:480
V8_INLINE constexpr Tagged()=default
V8_INLINE constexpr Tagged & operator=(Tagged< U > other)
Definition tagged.h:605
constexpr V8_INLINE bool IsSmi() const
Definition tagged.h:630
V8_INLINE Tagged(const HeapObjectLayout *ptr)
Definition tagged.h:600
V8_INLINE constexpr bool is_null() const
Definition tagged.h:625
V8_INLINE constexpr Tagged(Tagged< U > other)
Definition tagged.h:614
V8_INLINE constexpr Tagged(Tagged< U > other, HeapObjectReferenceType type)
Definition tagged.h:619
V8_INLINE Tagged(const HeapObjectLayout *ptr)
Definition tagged.h:568
V8_INLINE constexpr Tagged(StrongTaggedBase other)
Definition tagged.h:577
V8_INLINE constexpr Tagged & operator=(StrongTaggedBase other)
Definition tagged.h:582
V8_INLINE constexpr Tagged & operator=(WeakTaggedBase other)
Definition tagged.h:579
V8_INLINE constexpr Tagged(Address o)
Definition tagged.h:556
V8_INLINE constexpr Tagged(WeakTaggedBase other)
Definition tagged.h:574
typename detail::BaseForTagged< MaybeWeak< T > >::type Base
Definition tagged.h:844
V8_INLINE constexpr Tagged(Address ptr)
Definition tagged.h:875
V8_INLINE constexpr Tagged(Tagged< U > other)
Definition tagged.h:870
V8_INLINE Tagged(const T *ptr)
Definition tagged.h:853
V8_INLINE constexpr Tagged & operator=(Tagged< U > other)
Definition tagged.h:860
V8_INLINE constexpr Tagged()=default
V8_INLINE constexpr Tagged()
Definition tagged.h:395
V8_INLINE constexpr Tagged(StrongTaggedBase other)
Definition tagged.h:407
V8_INLINE Tagged(const HeapObjectLayout *ptr)
Definition tagged.h:401
V8_INLINE constexpr Tagged(Address o)
Definition tagged.h:390
V8_INLINE constexpr Tagged & operator=(StrongTaggedBase other)
Definition tagged.h:409
V8_INLINE constexpr bool IsHeapObject() const
Definition tagged.h:424
V8_INLINE constexpr Tagged(Address ptr)
Definition tagged.h:420
V8_INLINE constexpr Tagged()=default
V8_INLINE constexpr bool IsSmi() const
Definition tagged.h:425
V8_INLINE constexpr int32_t value() const
Definition tagged.h:427
V8_INLINE constexpr intptr_t value() const
Definition tagged.h:447
V8_INLINE constexpr bool IsHeapObject() const
Definition tagged.h:443
V8_INLINE constexpr Tagged()=default
V8_INLINE constexpr Tagged(Address ptr)
Definition tagged.h:439
V8_INLINE constexpr bool IsSmi() const
Definition tagged.h:444
V8_INLINE constexpr Tagged(Tagged< U > other)
Definition tagged.h:673
typename detail::BaseForTagged< This >::type Base
Definition tagged.h:656
V8_INLINE constexpr Tagged()=default
V8_INLINE constexpr Tagged(Address ptr)
Definition tagged.h:700
V8_INLINE constexpr Tagged & operator=(Tagged< U > other)
Definition tagged.h:663
friend Tagged< T > MakeStrong(Tagged< T > value)
Definition tagged.h:903
V8_INLINE constexpr detail::TaggedOperatorArrowRef< T > operator_arrow_impl() const
Definition tagged.h:801
V8_INLINE constexpr Tagged(Address ptr)
Definition tagged.h:783
V8_INLINE constexpr T operator_star_impl() const
Definition tagged.h:796
V8_INLINE constexpr Tagged(U raw)
Definition tagged.h:755
V8_INLINE T * operator_arrow_impl() const
Definition tagged.h:790
V8_INLINE T * ToRawPtr() const
Definition tagged.h:809
static constexpr Tagged< T > cast(U other)
Definition tagged.h:761
V8_INLINE constexpr Tagged(Tagged< U > other)
Definition tagged.h:734
V8_INLINE T & operator_star_impl() const
Definition tagged.h:785
V8_INLINE constexpr decltype(auto) operator*() const
Definition tagged.h:738
friend Tagged< To > UncheckedCast(Tagged< From > value)
Definition casting.h:61
V8_INLINE constexpr Tagged & operator=(Tagged< U > other)
Definition tagged.h:724
V8_INLINE constexpr decltype(auto) operator->() const
Definition tagged.h:744
V8_INLINE constexpr T ToRawPtr() const
Definition tagged.h:819
V8_INLINE constexpr Tagged()=default
V8_INLINE Tagged(const T *ptr)
Definition tagged.h:717
typename detail::BaseForTagged< T >::type Base
Definition tagged.h:708
V8_INLINE constexpr T * operator->()
Definition tagged.h:342
V8_INLINE constexpr TaggedOperatorArrowRef(T object)
Definition tagged.h:346
WEAK
Definition globals.h:1032
STL namespace.
static constexpr bool is_complex_subtype_v
Definition tagged.h:254
static constexpr bool is_simple_subtype_v
Definition tagged.h:163
std::disjunction< is_subtype< To, From >, is_subtype< From, To > > is_castable
Definition tagged.h:322
Tagged< T > MakeStrong(Tagged< T > value)
Definition tagged.h:903
static constexpr bool is_maybe_weak_v
Definition tagged.h:94
TaggedImpl< HeapObjectReferenceType::WEAK, Address > WeakTaggedBase
Definition tagged.h:113
const int kSmiTagSize
Definition v8-internal.h:87
Tagged(T object) -> Tagged< T >
static constexpr bool kTaggedCanConvertToRawObjects
Definition tagged.h:329
kInterpreterTrampolineOffset Tagged< HeapObject >
Address Tagged_t
Definition globals.h:547
static constexpr bool is_taggable_v
Definition tagged.h:316
static constexpr bool is_subtype_v
Definition tagged.h:121
static constexpr bool is_castable_v
Definition tagged.h:325
constexpr int U
const int kWeakHeapObjectTag
Definition v8-internal.h:73
TaggedImpl< HeapObjectReferenceType::STRONG, Address > StrongTaggedBase
Definition tagged.h:112
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
const int kHeapObjectTag
Definition v8-internal.h:72
static constexpr Address kNullAddress
Definition v8-internal.h:53
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
std::conditional_t< std::disjunction_v< is_maybe_weak< T >... >, WeakTaggedBase, std::conditional_t< std::disjunction_v< is_non_heap_object< T >... >, Tagged< Object >, Tagged< HeapObject > > > type
Definition tagged.h:369
std::disjunction< std::is_same< U, Smi >, std::is_same< U, Object >, std::is_same< U, TaggedIndex >, std::is_same< U, FieldType > > is_non_heap_object
Definition tagged.h:364
#define DEF_FIXED_ARRAY_SUBTYPE(Subtype)
Definition tagged.h:227
#define V8_INLINE
Definition v8config.h:500
wasm::ValueType type