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 "platform/assert.h"
9#include "platform/utils.h"
10#include "vm/class_id.h"
11#include "vm/pointer_tagging.h"
12
13namespace dart {
14
15class IsolateGroup;
16class ObjectLayout;
17
18class ObjectPtr {
19 public:
20 ObjectPtr* operator->() { return this; }
21 const ObjectPtr* operator->() const { return this; }
22 ObjectLayout* ptr() const {
23 return reinterpret_cast<ObjectLayout*>(UntaggedPointer());
24 }
25
26 bool IsWellFormed() const {
27 uword value = tagged_pointer_;
28 return (value & kSmiTagMask) == 0 ||
29 Utils::IsAligned(value - kHeapObjectTag, kWordSize);
30 }
31 bool IsHeapObject() const {
32 ASSERT(IsWellFormed());
33 uword value = tagged_pointer_;
34 return (value & kSmiTagMask) == kHeapObjectTag;
35 }
36 // Assumes this is a heap object.
37 bool IsNewObject() const {
38 ASSERT(IsHeapObject());
39 uword addr = tagged_pointer_;
40 return (addr & kNewObjectAlignmentOffset) == kNewObjectAlignmentOffset;
41 }
42 bool IsNewObjectMayBeSmi() const {
43 static const uword kNewObjectBits =
44 (kNewObjectAlignmentOffset | kHeapObjectTag);
45 const uword addr = tagged_pointer_;
46 return (addr & kObjectAlignmentMask) == kNewObjectBits;
47 }
48 // Assumes this is a heap object.
49 bool IsOldObject() const {
50 ASSERT(IsHeapObject());
51 uword addr = tagged_pointer_;
52 return (addr & kNewObjectAlignmentOffset) == kOldObjectAlignmentOffset;
53 }
54
55 // Like !IsHeapObject() || IsOldObject(), but compiles to a single branch.
56 bool IsSmiOrOldObject() const {
57 ASSERT(IsWellFormed());
58 static const uword kNewObjectBits =
59 (kNewObjectAlignmentOffset | kHeapObjectTag);
60 const uword addr = tagged_pointer_;
61 return (addr & kObjectAlignmentMask) != kNewObjectBits;
62 }
63
64 // Like !IsHeapObject() || IsNewObject(), but compiles to a single branch.
65 bool IsSmiOrNewObject() const {
66 ASSERT(IsWellFormed());
67 static const uword kOldObjectBits =
68 (kOldObjectAlignmentOffset | kHeapObjectTag);
69 const uword addr = tagged_pointer_;
70 return (addr & kObjectAlignmentMask) != kOldObjectBits;
71 }
72
73#define DEFINE_IS_CID(clazz) \
74 bool Is##clazz() const { return ((GetClassId() == k##clazz##Cid)); }
75 CLASS_LIST(DEFINE_IS_CID)
76#undef DEFINE_IS_CID
77
78#define DEFINE_IS_CID(clazz) \
79 bool IsTypedData##clazz() const { \
80 return ((GetClassId() == kTypedData##clazz##Cid)); \
81 } \
82 bool IsTypedDataView##clazz() const { \
83 return ((GetClassId() == kTypedData##clazz##ViewCid)); \
84 } \
85 bool IsExternalTypedData##clazz() const { \
86 return ((GetClassId() == kExternalTypedData##clazz##Cid)); \
87 }
88 CLASS_LIST_TYPED_DATA(DEFINE_IS_CID)
89#undef DEFINE_IS_CID
90
91#define DEFINE_IS_CID(clazz) \
92 bool IsFfi##clazz() const { return ((GetClassId() == kFfi##clazz##Cid)); }
93 CLASS_LIST_FFI(DEFINE_IS_CID)
94#undef DEFINE_IS_CID
95
96 bool IsStringInstance() const { return IsStringClassId(GetClassId()); }
97 bool IsRawNull() const { return GetClassId() == kNullCid; }
98 bool IsDartInstance() const {
99 return (!IsHeapObject() || (GetClassId() >= kInstanceCid));
100 }
101 bool IsFreeListElement() const {
102 return ((GetClassId() == kFreeListElement));
103 }
104 bool IsForwardingCorpse() const {
105 return ((GetClassId() == kForwardingCorpse));
106 }
107 bool IsPseudoObject() const {
108 return IsFreeListElement() || IsForwardingCorpse();
109 }
110
111 intptr_t GetClassId() const;
112 intptr_t GetClassIdMayBeSmi() const {
113 return IsHeapObject() ? GetClassId() : static_cast<intptr_t>(kSmiCid);
114 }
115
116 void Validate(IsolateGroup* isolate_group) const;
117
118 bool operator==(const ObjectPtr& other) {
119 return tagged_pointer_ == other.tagged_pointer_;
120 }
121 bool operator!=(const ObjectPtr& other) {
122 return tagged_pointer_ != other.tagged_pointer_;
123 }
124 constexpr bool operator==(const ObjectPtr& other) const {
125 return tagged_pointer_ == other.tagged_pointer_;
126 }
127 constexpr bool operator!=(const ObjectPtr& other) const {
128 return tagged_pointer_ != other.tagged_pointer_;
129 }
130 bool operator==(const nullptr_t& other) { return tagged_pointer_ == 0; }
131 bool operator!=(const nullptr_t& other) { return tagged_pointer_ != 0; }
132 constexpr bool operator==(const nullptr_t& other) const {
133 return tagged_pointer_ == 0;
134 }
135 constexpr bool operator!=(const nullptr_t& other) const {
136 return tagged_pointer_ != 0;
137 }
138
139 // Use explicit null comparisons instead.
140 operator bool() const = delete;
141
142 // The underlying types of int32_t/int64_t and intptr_t are sometimes
143 // different and sometimes the same, depending on the platform. With
144 // only a conversion operator for intptr_t, on 64-bit Mac a static_cast
145 // to int64_t fails because it tries conversion to bool (!) rather than
146 // intptr_t. So we exhaustive define all the valid conversions based on
147 // the underlying types.
148#if INT_MAX == INTPTR_MAX
149 explicit operator int() const { // NOLINT
150 return static_cast<int>(tagged_pointer_); // NOLINT
151 }
152#endif
153#if LONG_MAX == INTPTR_MAX
154 explicit operator long() const { // NOLINT
155 return static_cast<long>(tagged_pointer_); // NOLINT
156 }
157#endif
158#if LLONG_MAX == INTPTR_MAX
159 explicit operator long long() const { // NOLINT
160 return static_cast<long long>(tagged_pointer_); // NOLINT
161 }
162#endif
163#if UINT_MAX == UINTPTR_MAX
164 explicit operator unsigned int() const { // NOLINT
165 return static_cast<unsigned int>(tagged_pointer_); // NOLINT
166 }
167#endif
168#if ULONG_MAX == UINTPTR_MAX
169 explicit operator unsigned long() const { // NOLINT
170 return static_cast<unsigned long>(tagged_pointer_); // NOLINT
171 }
172#endif
173#if ULLONG_MAX == UINTPTR_MAX
174 explicit operator unsigned long long() const { // NOLINT
175 return static_cast<unsigned long long>(tagged_pointer_); // NOLINT
176 }
177#endif
178
179 // Must be trivially copyable for std::atomic.
180 ObjectPtr& operator=(const ObjectPtr& other) = default;
181 constexpr ObjectPtr(const ObjectPtr& other) = default;
182
183 ObjectPtr() : tagged_pointer_(0) {}
184 explicit constexpr ObjectPtr(uword tagged) : tagged_pointer_(tagged) {}
185 explicit constexpr ObjectPtr(intptr_t tagged) : tagged_pointer_(tagged) {}
186 constexpr ObjectPtr(nullptr_t) : tagged_pointer_(0) {} // NOLINT
187 explicit ObjectPtr(ObjectLayout* heap_object)
188 : tagged_pointer_(reinterpret_cast<uword>(heap_object) + kHeapObjectTag) {
189 }
190
191 protected:
192 uword UntaggedPointer() const {
193 ASSERT(IsHeapObject());
194 return tagged_pointer_ - kHeapObjectTag;
195 }
196
197 uword tagged_pointer_;
198};
199
200// Needed by the printing in the EXPECT macros.
201#if defined(DEBUG) || defined(TESTING)
202inline std::ostream& operator<<(std::ostream& os, const ObjectPtr& obj) {
203 os << reinterpret_cast<void*>(static_cast<uword>(obj));
204 return os;
205}
206#endif
207
208#define DEFINE_TAGGED_POINTER(klass, base) \
209 class klass##Layout; \
210 class klass##Ptr : public base##Ptr { \
211 public: \
212 klass##Ptr* operator->() { return this; } \
213 const klass##Ptr* operator->() const { return this; } \
214 klass##Layout* ptr() { \
215 return reinterpret_cast<klass##Layout*>(UntaggedPointer()); \
216 } \
217 /* TODO: Return const pointer */ \
218 klass##Layout* ptr() const { \
219 return reinterpret_cast<klass##Layout*>(UntaggedPointer()); \
220 } \
221 klass##Ptr& operator=(const klass##Ptr& other) = default; \
222 constexpr klass##Ptr(const klass##Ptr& other) = default; \
223 explicit constexpr klass##Ptr(const ObjectPtr& other) \
224 : base##Ptr(other) {} \
225 klass##Ptr() : base##Ptr() {} \
226 explicit constexpr klass##Ptr(uword tagged) : base##Ptr(tagged) {} \
227 explicit constexpr klass##Ptr(intptr_t tagged) : base##Ptr(tagged) {} \
228 constexpr klass##Ptr(nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \
229 explicit klass##Ptr(const ObjectLayout* untagged) \
230 : base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {} \
231 };
232
233DEFINE_TAGGED_POINTER(Class, Object)
234DEFINE_TAGGED_POINTER(PatchClass, Object)
235DEFINE_TAGGED_POINTER(Function, Object)
236DEFINE_TAGGED_POINTER(ClosureData, Object)
237DEFINE_TAGGED_POINTER(SignatureData, Object)
238DEFINE_TAGGED_POINTER(RedirectionData, Object)
239DEFINE_TAGGED_POINTER(FfiTrampolineData, Object)
240DEFINE_TAGGED_POINTER(Field, Object)
241DEFINE_TAGGED_POINTER(Script, Object)
242DEFINE_TAGGED_POINTER(Library, Object)
243DEFINE_TAGGED_POINTER(Namespace, Object)
244DEFINE_TAGGED_POINTER(KernelProgramInfo, Object)
245DEFINE_TAGGED_POINTER(WeakSerializationReference, Object)
246DEFINE_TAGGED_POINTER(Code, Object)
247DEFINE_TAGGED_POINTER(Bytecode, Object)
248DEFINE_TAGGED_POINTER(ObjectPool, Object)
249DEFINE_TAGGED_POINTER(Instructions, Object)
250DEFINE_TAGGED_POINTER(InstructionsSection, Object)
251DEFINE_TAGGED_POINTER(PcDescriptors, Object)
252DEFINE_TAGGED_POINTER(CodeSourceMap, Object)
253DEFINE_TAGGED_POINTER(CompressedStackMaps, Object)
254DEFINE_TAGGED_POINTER(LocalVarDescriptors, Object)
255DEFINE_TAGGED_POINTER(ExceptionHandlers, Object)
256DEFINE_TAGGED_POINTER(Context, Object)
257DEFINE_TAGGED_POINTER(ContextScope, Object)
258DEFINE_TAGGED_POINTER(ParameterTypeCheck, Object)
259DEFINE_TAGGED_POINTER(SingleTargetCache, Object)
260DEFINE_TAGGED_POINTER(UnlinkedCall, Object)
261DEFINE_TAGGED_POINTER(MonomorphicSmiableCall, Object)
262DEFINE_TAGGED_POINTER(CallSiteData, Object)
263DEFINE_TAGGED_POINTER(ICData, CallSiteData)
264DEFINE_TAGGED_POINTER(MegamorphicCache, CallSiteData)
265DEFINE_TAGGED_POINTER(SubtypeTestCache, Object)
266DEFINE_TAGGED_POINTER(LoadingUnit, Object)
267DEFINE_TAGGED_POINTER(Error, Object)
268DEFINE_TAGGED_POINTER(ApiError, Error)
269DEFINE_TAGGED_POINTER(LanguageError, Error)
270DEFINE_TAGGED_POINTER(UnhandledException, Error)
271DEFINE_TAGGED_POINTER(UnwindError, Error)
272DEFINE_TAGGED_POINTER(Instance, Object)
273DEFINE_TAGGED_POINTER(LibraryPrefix, Instance)
274DEFINE_TAGGED_POINTER(TypeArguments, Instance)
275DEFINE_TAGGED_POINTER(AbstractType, Instance)
276DEFINE_TAGGED_POINTER(Type, AbstractType)
277DEFINE_TAGGED_POINTER(TypeRef, AbstractType)
278DEFINE_TAGGED_POINTER(TypeParameter, AbstractType)
279DEFINE_TAGGED_POINTER(Closure, Instance)
280DEFINE_TAGGED_POINTER(Number, Instance)
281DEFINE_TAGGED_POINTER(Integer, Number)
282DEFINE_TAGGED_POINTER(Smi, Integer)
283DEFINE_TAGGED_POINTER(Mint, Integer)
284DEFINE_TAGGED_POINTER(Double, Number)
285DEFINE_TAGGED_POINTER(String, Instance)
286DEFINE_TAGGED_POINTER(OneByteString, String)
287DEFINE_TAGGED_POINTER(TwoByteString, String)
288DEFINE_TAGGED_POINTER(PointerBase, Instance)
289DEFINE_TAGGED_POINTER(TypedDataBase, PointerBase)
290DEFINE_TAGGED_POINTER(TypedData, TypedDataBase)
291DEFINE_TAGGED_POINTER(TypedDataView, TypedDataBase)
292DEFINE_TAGGED_POINTER(ExternalOneByteString, String)
293DEFINE_TAGGED_POINTER(ExternalTwoByteString, String)
294DEFINE_TAGGED_POINTER(Bool, Instance)
295DEFINE_TAGGED_POINTER(Array, Instance)
296DEFINE_TAGGED_POINTER(ImmutableArray, Array)
297DEFINE_TAGGED_POINTER(GrowableObjectArray, Instance)
298DEFINE_TAGGED_POINTER(LinkedHashMap, Instance)
299DEFINE_TAGGED_POINTER(Float32x4, Instance)
300DEFINE_TAGGED_POINTER(Int32x4, Instance)
301DEFINE_TAGGED_POINTER(Float64x2, Instance)
302DEFINE_TAGGED_POINTER(ExternalTypedData, TypedDataBase)
303DEFINE_TAGGED_POINTER(Pointer, PointerBase)
304DEFINE_TAGGED_POINTER(DynamicLibrary, Instance)
305DEFINE_TAGGED_POINTER(Capability, Instance)
306DEFINE_TAGGED_POINTER(SendPort, Instance)
307DEFINE_TAGGED_POINTER(ReceivePort, Instance)
308DEFINE_TAGGED_POINTER(TransferableTypedData, Instance)
309DEFINE_TAGGED_POINTER(StackTrace, Instance)
310DEFINE_TAGGED_POINTER(RegExp, Instance)
311DEFINE_TAGGED_POINTER(WeakProperty, Instance)
312DEFINE_TAGGED_POINTER(MirrorReference, Instance)
313DEFINE_TAGGED_POINTER(UserTag, Instance)
314DEFINE_TAGGED_POINTER(FutureOr, Instance)
315#undef DEFINE_TAGGED_POINTER
316
317inline intptr_t RawSmiValue(const SmiPtr raw_value) {
318 const intptr_t value = static_cast<intptr_t>(raw_value);
319 ASSERT((value & kSmiTagMask) == kSmiTag);
320 return (value >> kSmiTagShift);
321}
322
323} // namespace dart
324
325#endif // RUNTIME_VM_TAGGED_POINTER_H_
326