Flutter Engine
The Flutter Engine
tagged_pointer.h
Go to the documentation of this file.
1// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_TAGGED_POINTER_H_
6#define RUNTIME_VM_TAGGED_POINTER_H_
7
8#include <type_traits>
9#include "platform/assert.h"
10#include "platform/utils.h"
11#include "vm/class_id.h"
12#include "vm/globals.h"
13#include "vm/pointer_tagging.h"
14
15namespace dart {
16
17class IsolateGroup;
18class UntaggedObject;
19
20#define OBJECT_POINTER_CORE_FUNCTIONS(type, ptr) \
21 type* operator->() { \
22 return this; \
23 } \
24 const type* operator->() const { \
25 return this; \
26 } \
27 bool IsWellFormed() const { \
28 const uword value = ptr; \
29 return (value & kSmiTagMask) == 0 || \
30 Utils::IsAligned(value - kHeapObjectTag, kWordSize); \
31 } \
32 bool IsImmediateObject() const { \
33 ASSERT(IsWellFormed()); \
34 const uword value = ptr; \
35 return (value & kSmiTagMask) != kHeapObjectTag; \
36 } \
37 bool IsHeapObject() const { \
38 ASSERT(IsWellFormed()); \
39 const uword value = ptr; \
40 return (value & kSmiTagMask) == kHeapObjectTag; \
41 } \
42 /* Assumes this is a heap object. */ \
43 bool IsNewObject() const { \
44 ASSERT(IsHeapObject()); \
45 const uword addr = ptr; \
46 return (addr & kNewObjectAlignmentOffset) == kNewObjectAlignmentOffset; \
47 } \
48 bool IsNewObjectMayBeSmi() const { \
49 const uword kNewObjectBits = (kNewObjectAlignmentOffset | kHeapObjectTag); \
50 const uword addr = ptr; \
51 return (addr & kObjectAlignmentMask) == kNewObjectBits; \
52 } \
53 /* Assumes this is a heap object. */ \
54 bool IsOldObject() const { \
55 ASSERT(IsHeapObject()); \
56 const uword addr = ptr; \
57 return (addr & kNewObjectAlignmentOffset) == kOldObjectAlignmentOffset; \
58 } \
59 \
60 /* Like !IsHeapObject() || IsOldObject() but compiles to a single branch. */ \
61 bool IsImmediateOrOldObject() const { \
62 ASSERT(IsWellFormed()); \
63 const uword kNewObjectBits = (kNewObjectAlignmentOffset | kHeapObjectTag); \
64 const uword addr = ptr; \
65 return (addr & kObjectAlignmentMask) != kNewObjectBits; \
66 } \
67 \
68 /* Like !IsHeapObject() || IsNewObject() but compiles to a single branch. */ \
69 bool IsImmediateOrNewObject() const { \
70 ASSERT(IsWellFormed()); \
71 const uword kOldObjectBits = (kOldObjectAlignmentOffset | kHeapObjectTag); \
72 const uword addr = ptr; \
73 return (addr & kObjectAlignmentMask) != kOldObjectBits; \
74 } \
75 \
76 bool operator==(const type& other) { \
77 return (ptr & kSmiTagMask) == kHeapObjectTag \
78 ? ptr == other.ptr \
79 : static_cast<compressed_uword>(ptr) == \
80 static_cast<compressed_uword>(other.ptr); \
81 } \
82 bool operator!=(const type& other) { \
83 return (ptr & kSmiTagMask) == kHeapObjectTag \
84 ? ptr != other.ptr \
85 : static_cast<compressed_uword>(ptr) != \
86 static_cast<compressed_uword>(other.ptr); \
87 } \
88 constexpr bool operator==(const type& other) const { \
89 return (ptr & kSmiTagMask) == kHeapObjectTag \
90 ? ptr == other.ptr \
91 : static_cast<compressed_uword>(ptr) == \
92 static_cast<compressed_uword>(other.ptr); \
93 } \
94 constexpr bool operator!=(const type& other) const { \
95 return (ptr & kSmiTagMask) == kHeapObjectTag \
96 ? ptr != other.ptr \
97 : static_cast<compressed_uword>(ptr) != \
98 static_cast<compressed_uword>(other.ptr); \
99 }
100
102 public:
104
106 return reinterpret_cast<UntaggedObject*>(untagged_pointer());
107 }
108
109#define DEFINE_IS_CID(clazz) \
110 bool Is##clazz() const { return ((GetClassId() == k##clazz##Cid)); }
112#undef DEFINE_IS_CID
113
114#define DEFINE_IS_CID(clazz) \
115 bool IsTypedData##clazz() const { \
116 return ((GetClassId() == kTypedData##clazz##Cid)); \
117 } \
118 bool IsTypedDataView##clazz() const { \
119 return ((GetClassId() == kTypedData##clazz##ViewCid)); \
120 } \
121 bool IsUnmodifiableTypedDataView##clazz() const { \
122 return ((GetClassId() == kUnmodifiableTypedData##clazz##ViewCid)); \
123 } \
124 bool IsExternalTypedData##clazz() const { \
125 return ((GetClassId() == kExternalTypedData##clazz##Cid)); \
126 }
128#undef DEFINE_IS_CID
129
130#define DEFINE_IS_CID(clazz) \
131 bool IsFfi##clazz() const { return ((GetClassId() == kFfi##clazz##Cid)); }
133#undef DEFINE_IS_CID
134
135 bool IsStringInstance() const { return IsStringClassId(GetClassId()); }
136 bool IsRawNull() const { return GetClassId() == kNullCid; }
137 bool IsDartInstance() const {
138 return (!IsHeapObject() || !IsInternalOnlyClassId(GetClassId()));
139 }
140 bool IsFreeListElement() const {
141 return ((GetClassId() == kFreeListElement));
142 }
143 bool IsForwardingCorpse() const {
144 return ((GetClassId() == kForwardingCorpse));
145 }
146 bool IsPseudoObject() const {
148 }
149
150 intptr_t GetClassId() const;
151 intptr_t GetClassIdMayBeSmi() const {
152 return IsHeapObject() ? GetClassId() : static_cast<intptr_t>(kSmiCid);
153 }
154
155 void Validate(IsolateGroup* isolate_group) const;
156
157 bool operator==(const std::nullptr_t& other) { return tagged_pointer_ == 0; }
158 bool operator!=(const std::nullptr_t& other) { return tagged_pointer_ != 0; }
159 constexpr bool operator==(const std::nullptr_t& other) const {
160 return tagged_pointer_ == 0;
161 }
162 constexpr bool operator!=(const std::nullptr_t& other) const {
163 return tagged_pointer_ != 0;
164 }
165
166 // Use explicit null comparisons instead.
167 operator bool() const = delete;
168
169 // The underlying types of int32_t/int64_t and intptr_t are sometimes
170 // different and sometimes the same, depending on the platform. With
171 // only a conversion operator for intptr_t, on 64-bit Mac a static_cast
172 // to int64_t fails because it tries conversion to bool (!) rather than
173 // intptr_t. So we exhaustive define all the valid conversions based on
174 // the underlying types.
175#if INT_MAX == INTPTR_MAX
176 explicit operator int() const { // NOLINT
177 return static_cast<int>(tagged_pointer_); // NOLINT
178 }
179#endif
180#if LONG_MAX == INTPTR_MAX
181 explicit operator long() const { // NOLINT
182 return static_cast<long>(tagged_pointer_); // NOLINT
183 }
184#endif
185#if LLONG_MAX == INTPTR_MAX
186 explicit operator long long() const { // NOLINT
187 return static_cast<long long>(tagged_pointer_); // NOLINT
188 }
189#endif
190#if UINT_MAX == UINTPTR_MAX
191 explicit operator unsigned int() const { // NOLINT
192 return static_cast<unsigned int>(tagged_pointer_); // NOLINT
193 }
194#endif
195#if ULONG_MAX == UINTPTR_MAX
196 explicit operator unsigned long() const { // NOLINT
197 return static_cast<unsigned long>(tagged_pointer_); // NOLINT
198 }
199#endif
200#if ULLONG_MAX == UINTPTR_MAX
201 explicit operator unsigned long long() const { // NOLINT
202 return static_cast<unsigned long long>(tagged_pointer_); // NOLINT
203 }
204#endif
205
206 // Must be trivially copyable for std::atomic.
207 ObjectPtr& operator=(const ObjectPtr& other) = default;
208 constexpr ObjectPtr(const ObjectPtr& other) = default;
209
211 explicit constexpr ObjectPtr(uword tagged) : tagged_pointer_(tagged) {}
212 explicit constexpr ObjectPtr(intptr_t tagged) : tagged_pointer_(tagged) {}
213 constexpr ObjectPtr(std::nullptr_t) : tagged_pointer_(0) {} // NOLINT
214 explicit ObjectPtr(UntaggedObject* heap_object)
215 : tagged_pointer_(reinterpret_cast<uword>(heap_object) + kHeapObjectTag) {
216 }
217
218 ObjectPtr Decompress(uword heap_base) const { return *this; }
219 ObjectPtr DecompressSmi() const { return *this; }
220 uword heap_base() const {
221 // TODO(rmacnak): Why does Windows have trouble linking GetClassId used
222 // here?
223#if !defined(DART_HOST_OS_WINDOWS)
224 ASSERT(IsHeapObject());
225 ASSERT(!IsInstructions());
226 ASSERT(!IsInstructionsSection());
227#endif
229 }
230
231 protected:
233 ASSERT(IsHeapObject());
235 }
236
238};
239
240// Needed by the printing in the EXPECT macros.
241#if defined(DEBUG) || defined(TESTING)
242inline std::ostream& operator<<(std::ostream& os, const ObjectPtr& obj) {
243 os << reinterpret_cast<void*>(static_cast<uword>(obj));
244 return os;
245}
246#endif
247
248template <typename T, typename Enable = void>
249struct is_uncompressed_ptr : std::false_type {};
250template <typename T>
252 T,
253 typename std::enable_if<std::is_base_of<ObjectPtr, T>::value, void>::type>
254 : std::true_type{};
255template <typename T, typename Enable = void>
256struct is_compressed_ptr : std::false_type {};
257
258template <typename T, typename Enable = void>
260 using type =
262};
263
264#if !defined(DART_COMPRESSED_POINTERS)
266#define DEFINE_COMPRESSED_POINTER(klass, base) \
267 typedef klass##Ptr Compressed##klass##Ptr;
268#else
270 public:
272
273 explicit CompressedObjectPtr(ObjectPtr uncompressed)
274 : compressed_pointer_(
275 static_cast<uint32_t>(static_cast<uword>(uncompressed))) {}
276 explicit constexpr CompressedObjectPtr(uword tagged)
277 : compressed_pointer_(static_cast<uint32_t>(tagged)) {}
278
280 return static_cast<ObjectPtr>(static_cast<uword>(compressed_pointer_) +
281 heap_base);
282 }
283
284 ObjectPtr DecompressSmi() const {
285 ASSERT((compressed_pointer_ & kSmiTagMask) != kHeapObjectTag);
286 return static_cast<ObjectPtr>(static_cast<uword>(compressed_pointer_));
287 }
288
289 const ObjectPtr& operator=(const ObjectPtr& other) {
290 compressed_pointer_ = static_cast<uint32_t>(static_cast<uword>(other));
291 return other;
292 }
293
294 protected:
295 uint32_t compressed_pointer_;
296};
297
298template <typename T>
299struct is_compressed_ptr<
300 T,
301 typename std::enable_if<std::is_base_of<CompressedObjectPtr, T>::value,
302 void>::type> : std::true_type{};
303template <typename T>
304struct base_ptr_type<
305 T,
306 typename std::enable_if<std::is_base_of<CompressedObjectPtr, T>::value,
307 void>::type> {
309};
310
311#define DEFINE_COMPRESSED_POINTER(klass, base) \
312 class Compressed##klass##Ptr : public Compressed##base##Ptr { \
313 public: \
314 Compressed##klass##Ptr* operator->() { \
315 return this; \
316 } \
317 const Compressed##klass##Ptr* operator->() const { \
318 return this; \
319 } \
320 explicit Compressed##klass##Ptr(klass##Ptr uncompressed) \
321 : Compressed##base##Ptr(uncompressed) {} \
322 const klass##Ptr& operator=(const klass##Ptr& other) { \
323 compressed_pointer_ = static_cast<uint32_t>(static_cast<uword>(other)); \
324 return other; \
325 } \
326 klass##Ptr Decompress(uword heap_base) const { \
327 return klass##Ptr(CompressedObjectPtr::Decompress(heap_base)); \
328 } \
329 };
330#endif
331
332#define DEFINE_TAGGED_POINTER(klass, base) \
333 class Untagged##klass; \
334 class klass##Ptr : public base##Ptr { \
335 public: \
336 klass##Ptr* operator->() { \
337 return this; \
338 } \
339 const klass##Ptr* operator->() const { \
340 return this; \
341 } \
342 Untagged##klass* untag() { \
343 return reinterpret_cast<Untagged##klass*>(untagged_pointer()); \
344 } \
345 /* TODO: Return const pointer */ \
346 Untagged##klass* untag() const { \
347 return reinterpret_cast<Untagged##klass*>(untagged_pointer()); \
348 } \
349 klass##Ptr& operator=(const klass##Ptr& other) = default; \
350 constexpr klass##Ptr(const klass##Ptr& other) = default; \
351 explicit constexpr klass##Ptr(const ObjectPtr& other) \
352 : base##Ptr(other) {} \
353 klass##Ptr() : base##Ptr() {} \
354 explicit constexpr klass##Ptr(uword tagged) : base##Ptr(tagged) {} \
355 explicit constexpr klass##Ptr(intptr_t tagged) : base##Ptr(tagged) {} \
356 constexpr klass##Ptr(std::nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \
357 explicit klass##Ptr(const UntaggedObject* untagged) \
358 : base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {} \
359 klass##Ptr Decompress(uword heap_base) const { \
360 return *this; \
361 } \
362 }; \
363 DEFINE_COMPRESSED_POINTER(klass, base)
364
365DEFINE_TAGGED_POINTER(Class, Object)
366DEFINE_TAGGED_POINTER(PatchClass, Object)
367DEFINE_TAGGED_POINTER(Function, Object)
368DEFINE_TAGGED_POINTER(ClosureData, Object)
369DEFINE_TAGGED_POINTER(FfiTrampolineData, Object)
370DEFINE_TAGGED_POINTER(Field, Object)
371DEFINE_TAGGED_POINTER(Script, Object)
372DEFINE_TAGGED_POINTER(Library, Object)
373DEFINE_TAGGED_POINTER(Namespace, Object)
374DEFINE_TAGGED_POINTER(KernelProgramInfo, Object)
375DEFINE_TAGGED_POINTER(WeakSerializationReference, Object)
376DEFINE_TAGGED_POINTER(WeakArray, Object)
377DEFINE_TAGGED_POINTER(Code, Object)
378DEFINE_TAGGED_POINTER(ObjectPool, Object)
379DEFINE_TAGGED_POINTER(Instructions, Object)
380DEFINE_TAGGED_POINTER(InstructionsSection, Object)
381DEFINE_TAGGED_POINTER(InstructionsTable, Object)
382DEFINE_TAGGED_POINTER(PcDescriptors, Object)
383DEFINE_TAGGED_POINTER(CodeSourceMap, Object)
384DEFINE_TAGGED_POINTER(CompressedStackMaps, Object)
385DEFINE_TAGGED_POINTER(LocalVarDescriptors, Object)
386DEFINE_TAGGED_POINTER(ExceptionHandlers, Object)
388DEFINE_TAGGED_POINTER(ContextScope, Object)
389DEFINE_TAGGED_POINTER(Sentinel, Object)
390DEFINE_TAGGED_POINTER(SingleTargetCache, Object)
391DEFINE_TAGGED_POINTER(UnlinkedCall, Object)
392DEFINE_TAGGED_POINTER(MonomorphicSmiableCall, Object)
393DEFINE_TAGGED_POINTER(CallSiteData, Object)
394DEFINE_TAGGED_POINTER(ICData, CallSiteData)
395DEFINE_TAGGED_POINTER(MegamorphicCache, CallSiteData)
396DEFINE_TAGGED_POINTER(SubtypeTestCache, Object)
397DEFINE_TAGGED_POINTER(LoadingUnit, Object)
398DEFINE_TAGGED_POINTER(Error, Object)
399DEFINE_TAGGED_POINTER(ApiError, Error)
400DEFINE_TAGGED_POINTER(LanguageError, Error)
401DEFINE_TAGGED_POINTER(UnhandledException, Error)
402DEFINE_TAGGED_POINTER(UnwindError, Error)
403DEFINE_TAGGED_POINTER(Instance, Object)
404DEFINE_TAGGED_POINTER(LibraryPrefix, Instance)
405DEFINE_TAGGED_POINTER(TypeArguments, Instance)
406DEFINE_TAGGED_POINTER(TypeParameters, Object)
407DEFINE_TAGGED_POINTER(AbstractType, Instance)
408DEFINE_TAGGED_POINTER(Type, AbstractType)
409DEFINE_TAGGED_POINTER(FunctionType, AbstractType)
410DEFINE_TAGGED_POINTER(RecordType, AbstractType)
411DEFINE_TAGGED_POINTER(TypeParameter, AbstractType)
412DEFINE_TAGGED_POINTER(Closure, Instance)
413DEFINE_TAGGED_POINTER(Number, Instance)
414DEFINE_TAGGED_POINTER(Integer, Number)
415DEFINE_TAGGED_POINTER(Smi, Integer)
416DEFINE_TAGGED_POINTER(Mint, Integer)
417DEFINE_TAGGED_POINTER(Double, Number)
418DEFINE_TAGGED_POINTER(String, Instance)
419DEFINE_TAGGED_POINTER(OneByteString, String)
420DEFINE_TAGGED_POINTER(TwoByteString, String)
421DEFINE_TAGGED_POINTER(Record, Instance)
422DEFINE_TAGGED_POINTER(PointerBase, Instance)
423DEFINE_TAGGED_POINTER(TypedDataBase, PointerBase)
424DEFINE_TAGGED_POINTER(TypedData, TypedDataBase)
425DEFINE_TAGGED_POINTER(TypedDataView, TypedDataBase)
426DEFINE_TAGGED_POINTER(Bool, Instance)
427DEFINE_TAGGED_POINTER(Array, Instance)
428DEFINE_TAGGED_POINTER(ImmutableArray, Array)
429DEFINE_TAGGED_POINTER(GrowableObjectArray, Instance)
430DEFINE_TAGGED_POINTER(LinkedHashBase, Instance)
431DEFINE_TAGGED_POINTER(Map, LinkedHashBase)
432DEFINE_TAGGED_POINTER(Set, LinkedHashBase)
433DEFINE_TAGGED_POINTER(ConstMap, Map)
434DEFINE_TAGGED_POINTER(ConstSet, Set)
435DEFINE_TAGGED_POINTER(Float32x4, Instance)
436DEFINE_TAGGED_POINTER(Int32x4, Instance)
437DEFINE_TAGGED_POINTER(Float64x2, Instance)
438DEFINE_TAGGED_POINTER(ExternalTypedData, TypedDataBase)
439DEFINE_TAGGED_POINTER(Pointer, PointerBase)
440DEFINE_TAGGED_POINTER(DynamicLibrary, Instance)
441DEFINE_TAGGED_POINTER(Capability, Instance)
442DEFINE_TAGGED_POINTER(SendPort, Instance)
443DEFINE_TAGGED_POINTER(ReceivePort, Instance)
444DEFINE_TAGGED_POINTER(TransferableTypedData, Instance)
445DEFINE_TAGGED_POINTER(StackTrace, Instance)
446DEFINE_TAGGED_POINTER(SuspendState, Instance)
447DEFINE_TAGGED_POINTER(RegExp, Instance)
448DEFINE_TAGGED_POINTER(WeakProperty, Instance)
449DEFINE_TAGGED_POINTER(WeakReference, Instance)
450DEFINE_TAGGED_POINTER(FinalizerBase, Instance)
452DEFINE_TAGGED_POINTER(FinalizerEntry, Instance)
453DEFINE_TAGGED_POINTER(NativeFinalizer, Instance)
454DEFINE_TAGGED_POINTER(MirrorReference, Instance)
455DEFINE_TAGGED_POINTER(UserTag, Instance)
456DEFINE_TAGGED_POINTER(FutureOr, Instance)
457#undef DEFINE_TAGGED_POINTER
458
459inline intptr_t RawSmiValue(const SmiPtr raw_value) {
460#if !defined(DART_COMPRESSED_POINTERS)
461 const intptr_t value = static_cast<intptr_t>(raw_value);
462#else
463 const intptr_t value = static_cast<intptr_t>(static_cast<int32_t>(
464 static_cast<uint32_t>(static_cast<uintptr_t>(raw_value))));
465#endif
467 return (value >> kSmiTagShift);
468}
469
470} // namespace dart
471
472#endif // RUNTIME_VM_TAGGED_POINTER_H_
GLenum type
#define CLASS_LIST_FFI(V)
Definition: class_id.h:171
#define CLASS_LIST_TYPED_DATA(V)
Definition: class_id.h:137
#define CLASS_LIST(V)
Definition: class_id.h:208
constexpr ObjectPtr(std::nullptr_t)
constexpr bool operator!=(const std::nullptr_t &other) const
ObjectPtr(UntaggedObject *heap_object)
ObjectPtr DecompressSmi() const
bool IsDartInstance() const
void Validate(IsolateGroup *isolate_group) const
Definition: raw_object.cc:30
bool IsFreeListElement() const
constexpr ObjectPtr(uword tagged)
ObjectPtr Decompress(uword heap_base) const
constexpr ObjectPtr(const ObjectPtr &other)=default
bool operator==(const std::nullptr_t &other)
constexpr bool operator==(const std::nullptr_t &other) const
bool operator!=(const std::nullptr_t &other)
UntaggedObject * untag() const
bool IsStringInstance() const
uword heap_base() const
bool IsForwardingCorpse() const
intptr_t GetClassId() const
Definition: raw_object.h:885
uword untagged_pointer() const
intptr_t GetClassIdMayBeSmi() const
ObjectPtr & operator=(const ObjectPtr &other)=default
constexpr ObjectPtr(intptr_t tagged)
bool IsRawNull() const
bool IsPseudoObject() const
#define ASSERT(E)
uint8_t value
Definition: dart_vm.cc:33
static constexpr uintptr_t kHeapBaseMask
intptr_t RawSmiValue(const SmiPtr raw_value)
@ kForwardingCorpse
Definition: class_id.h:225
@ kNullCid
Definition: class_id.h:252
@ kFreeListElement
Definition: class_id.h:224
uintptr_t uword
Definition: globals.h:501
static void Finalizer(void *isolate_callback_data, void *buffer)
Definition: json_stream.cc:192
bool IsInternalOnlyClassId(intptr_t index)
Definition: class_id.h:299
@ kHeapObjectTag
@ kSmiTagMask
@ kSmiTagShift
bool IsStringClassId(intptr_t index)
Definition: class_id.h:350
ObjectPtr CompressedObjectPtr
Definition: ref_ptr.h:256
std::ostream & operator<<(std::ostream &out, const impeller::Color &c)
Definition: color.h:961
#define T
Definition: precompiler.cc:65
typename std::enable_if< is_uncompressed_ptr< T >::value, ObjectPtr >::type type
#define DEFINE_TAGGED_POINTER(klass, base)
#define OBJECT_POINTER_CORE_FUNCTIONS(type, ptr)
#define DEFINE_IS_CID(clazz)